Docker Compose 配置容器的工作目录(working_dir)

文章目录

    使用 Docker Compose 配置文件,新建了一个 alpine 镜像的容器。
    里面运行了一个 golang gin 开发的 web 应用。没想到,又踩了一个 docker 配置的坑 🥲 我感觉踩的 docker 坑多得数不过来啦

    相对目录问题

    我发现了一个线上的 bug,线上服务器中,使用 golang 创建的相对路径的目录,结果发现目录创建在了根目录 / 下,而不是预期的 /app 目录下。

    • 本地开发机,没有使用 docker,目录位置都是正常的
    • 线上服务器,使用 docker 部署的,目录位置不对。全部到了根目录下。
    • 线上服务器,不使用 docker,使用 systemd 直接运行的,目录位置也是正常的。(后来发现是我设置了 systemd WorkingDirectory 参数)

    查了一下,原来 docker 也是需要设置工作目录的。至少 alpine 镜像是这样的。

    原 docker-compose.yml 配置

    sunzhongwei.com:
      image: alpine:3.20.3
      restart: always
      ports:
        - "9000:9000"
      volumes:
        - /var/www/sunzhongwei.com:/app
      command: /app/main
    

    确认当前的工作目录:

    > docker compose exec sunzhongwei.com pwd
    /
    

    可以看到当前目录是 / 根目录,而不是 /app 目录。

    修改后的 docker-compose.yml 配置

    增加了 working_dir 参数:

    sunzhongwei.com:
      image: alpine:3.20.3
      restart: always
      ports:
        - "9000:9000"
      volumes:
        - /var/www/sunzhongwei.com:/app
      working_dir: /app
      command: /app/main
    

    数据目录备份

    修改完配置,不要着急使配置生效。因为如果重新构建容器,容器内的数据目录会丢失。
    即,没有映射到宿主机的目录数据,会丢失。例如,如果有两个目录 upload 和 sitemap,需要先备份出来。

    docker compose exec sunzhongwei.com sh
    
    # cp -R upload app/upload
    # cp -R sitemap app/sitemap
    

    因为原配置里,已经把 /var/www/sunzhongwei.com 映射到了 /app 目录下,所以备份到 /app/upload 和 /app/sitemap 下即可。

    备份完成后,从宿主机的目录里就能看到 upload 和 sitemap 两个目录了。

    如何使 working_dir 的配置生效

    执行:

    docker compose up -d <容器名>
    

    即可。不需要先 stop,因为当你对正在运行的服务执行 docker compose up -d 时,Docker Compose 会自动按顺序执行以下操作:

    1. 构建上下文:检查镜像等依赖(如果配置了build)。
    2. 停止容器:自动停止指定服务(例如 sunzhongwei.com)当前正在运行的容器。
    3. 删除容器:移除刚才停止的旧容器。
    4. 创建新容器:根据 docker-compose.yml 中的最新配置(包含你新加的 working_dir)创建一个全新的容器。
    5. 启动容器:启动这个新容器。

    所以只需执行一条命令即可。

    需要注意的是:

    docker compose restart <容器名>
    

    只是重启现有容器,不会重新加载 docker-compose.yml 的变更。所以,如果只是执行 restart,新配置是不会生效的。

    操作流程总结

    完整且正确的操作步骤:

    1. 备份数据目录(如果有需要保留的数据目录)。
    2. 修改配置:在 docker-compose.yml 中为指定服务添加 working_dir: /app。
    3. 执行一条命令:在 docker-compose.yml 目录下运行 docker compose up -d <容器名>

    验证

    # docker compose exec sunzhongwei.com pwd
    /app
    

    或者进入容器:

    docker compose exec sunzhongwei.com sh
    

    会发现默认的目录已经不是 / 而变成了 /app.

    并且之前存在 docker 中的那两个目录也消失了。

    关于作者 🌱

    我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊,或者关注我的个人公众号“大象工具”, 查看更多联系方式