如何在不丢失数据的情况下更新Docker容器内服务端应用代码
问题场景
我有一个Docker Compose项目,文件结构如下:
. |-- .dockerignore |-- Dockerfile |-- docker-compose.yml |-- messages |-- 20221120-010625.txt |-- 20221120-010630.txt `-- 20221120-010641.txt |-- package.json `-- server.js
执行docker-compose up -d启动后,能通过http://localhost/?message=<message>在服务器上记录消息。现在需要更新源码(比如给页面里的Created file ...文本加###前缀),但绝对不能丢失已有的消息数据。
之前试过docker-compose down --volumes && docker-compose up -d --force-recreate --build,源码是更新了,但所有消息全没了;后来尝试在docker-compose.yml里给/var/www/html/messages挂载命名卷,结果卷目录归root所有,node用户没权限写入,直接报错。
解决方案
1. 搞定命名卷的权限问题
Docker创建命名卷时默认用root权限初始化目录,导致node用户写不了,解决方法有两种:
方法一:修改Dockerfile,启动时自动调权限
把Dockerfile里的CMD改成下面这样,启动服务前先确保messages目录权限正确:
FROM node:16-alpine RUN mkdir -p /var/www/html && chown -R node:node /var/www/html WORKDIR /var/www/html COPY --chown=node:node . . USER node RUN npm i EXPOSE 8080 # 替换原来的CMD,先创建目录并改权限再启动服务 CMD ["sh", "-c", "mkdir -p /var/www/html/messages && chown -R node:node /var/www/html/messages && npm run start"]
方法二:手动调整已有命名卷的权限
如果已经创建了命名卷,先跑个临时容器把权限改好:
docker run --rm -v messages:/var/www/html/messages node:16-alpine chown -R node:node /var/www/html/messages
改完再启动应用容器,就能正常写入消息了。
2. 正确的源码更新流程
挂载好命名卷后,更新源码根本不用删卷,直接重新构建镜像并重启容器就行:
# 构建新镜像 docker-compose build # 用新镜像重启容器,保留卷数据 docker-compose up -d --force-recreate
或者合并成一条命令:
docker-compose up -d --force-recreate --build
⚠️ 重点:别加--volumes参数,加了就会删掉卷里的所有消息!
3. 完善docker-compose.yml配置
确保docker-compose.yml里正确配置命名卷:
version: '3' services: serverapp: build: dockerfile: Dockerfile container_name: serverapp restart: unless-stopped ports: - "80:80" volumes: - messages:/var/www/html/messages # 把命名卷挂载到消息存储目录 volumes: messages: # 定义命名卷
4. 验证效果
修改server.js里的响应内容,比如把:
res.send(`<pre>${filesListStr}\nCreated file: "${filePathMessage}" with content: "${message}".</pre>`);
改成:
res.send(`<pre>${filesListStr}\n### Created file: "${filePathMessage}" with content: "${message}".</pre>`);
然后执行更新命令,刷新页面就能看到新的格式,之前的消息文件也都还在。
内容的提问来源于stack exchange,提问作者davidesp
相关产品推荐
相关产品推荐

