给网站更新功能时踩了一个比较蛋疼的坑,在这里留一个记录。
背景
首先从 0xFFFF 网站的代码部署流程说起,核心分为两步:
- 代码 push 到远程仓库后,触发的 GitHub Actions 将最新代码和 php-fpm 解析器一起,打包构建成 Docker 镜像,并推送到 Dockerhub。
- 维护人登录生产环境服务器,执行
deploy-prod.sh
,脚本会通过 docker pull zgq354/0xffff-flarum:latest
最新的 latest 的镜像,然后调用 Docker Compose 重建新的容器,替换掉原来的逻辑。
Web 网关 Nginx 需要读取镜像中的静态资源文件,在遇到 .php
的 HTTP 请求时,才将请求转发到 0xffff-flarum
镜像中启动的 php-fpm
服务。
精简后的 docker-compose.yml
编排配置如下(完整配置在 这里):
services:
nginx:
image: 0xffff-nginx:latest
build: ./nginx
container_name: 0xffff-nginx
restart: always
ports:
- ${NGINX_HTTP_PORT:-8080}:80
- ${NGINX_HTTPS_PORT:-8443}:443
volumes:
- ./logs:/var/log/nginx
- app-root:/wwwroot
php:
image: zgq354/0xffff-flarum:latest
# build: ./php-fpm
container_name: 0xffff-app
depends_on:
- redis
restart: always
expose:
- 9000
volumes:
- ./logs:/var/log
- app-root:/wwwroot
volumes:
app-root:
问题
今天又推了代码,发现网站代码未更新到最新版本,干掉所有容器和镜像再重建依然还是有问题。百思不得其解,排查半天,最后用 docker inspect
发现这里 app-root
volume 实际是绑定到了本地的 volume 目录(/var/lib/docker/volumes/0xffff-env_app-root/_data
)。
{
"Type": "volume",
"Name": "0xffff-env_app-root",
"Source": "/var/lib/docker/volumes/0xffff-env_app-root/_data",
"Destination": "/wwwroot",
"Driver": "local",
"Mode": "rw",
"RW": true,
"Propagation": ""
}
也就是说,当我们用 docker-compose
通过命名容器的方式去挂载其他容器的代码时,隐含了一个拷贝原容器代码的过程。而在容器镜像更新以后,重建容器时挂载的 volume 还是最初启动环境的那个,未自动同步最新的代码,从而导致了这里的问题。
Docker 的官方文档的描述:
Use volumes | Docker Documentation:
On the first invocation of docker-compose up the volume will be created. The same volume will be reused on following invocations.
Compose file version 3 reference | Docker Documentation
In the example below, instead of attempting to create a volume called [projectname]_data, Compose looks for an existing volume simply called data and mount it into the db service’s containers.
解决
寻找绑定其他 Docker 容器文件的手段未果,后面决定把 nginx 依赖的部分文件单独挂载到宿主机本地目录,每一次需要部署容器时候,通过启动脚本用 rsync 把文件同步出来。
rsync 可以启一个一次性容器来跑,因为 nginx 不负责动态逻辑,但又需要用 try_files
检测对应路径文件是否存在,所以同步时,把 public 目录的文件拷贝进去就足够了,更新脚本如下:
sudo docker pull zgq354/0xffff-flarum:latest \
&& cd $SCRIPTPATH/.. \
&& sudo mkdir -p data/nginx-public \
&& sudo docker run --rm -v $SCRIPTPATH/../data/nginx-public:/nginx-public zgq354/0xffff-flarum:latest rsync -av /wwwroot/public/ /nginx-public/ \
&& sudo docker-compose up -d --build --remove-orphans \
&& sudo docker exec -it 0xffff-app php flarum cache:clear
完整改动见此 commit