我有一个试图用于CD服务器的部署脚本,但是在编写bash脚本以完成一些所需的步骤(例如运行npm和迁移命令)时遇到了问题。
我将如何从该脚本进入容器bash,运行下面的命令,然后退出以完成对更改的提取?
这是我要自动化的脚本:
cd /Project
docker-compose -f docker-compose.prod.yml down
git pull
docker-compose -f docker-compose.prod.yml build
# all good until here because it opens bash and does not allow more commands to run
docker-compose -f docker-compose.prod.yml run --rm web bash
npm install # should be run inside of web bash
python manage.py migrate_all # should be run inside of web bash
exit # should be run inside of web bash
# back out of web bash
docker-compose -f docker-compose.prod.yml up -d
最佳答案
通常,Docker镜像是独立的,并且知道如何在没有任何用户干预的情况下启动自身。除了一些有限的异常(exception),您永远不需要docker-compose run
交互式shell来进行部署后设置,而docker exec
应该保留用于紧急调试。
您正在此脚本中做两件事。
首先是安装Node软件包。这些应该封装在您的镜像中;您的Dockerfile几乎总是看起来像
FROM node
WORKDIR /app
COPY package*.json .
RUN npm ci # <--- this line
COPY . .
CMD ["node", "index.js"]
由于依赖项位于镜像中,因此在镜像启动时不需要重新安装它们。相反,如果更改package.json
文件,则重新运行docker-compose build
将重新运行npm install
步骤,您将获得一个干净的程序包树。(有一种常见的设置,它会将
node_modules
目录放入一个匿名卷中,并用bind mount覆盖该镜像的代码。如果更新镜像,它将从该匿名卷中获取旧的node_modules
目录,而忽略镜像更新。删除这些volumes:
并使用图像中内置的代码。)数据库迁移有些棘手,因为您不能在镜像构建阶段运行它们。有两种好的方法。一种是始终让容器在启动时运行迁移。您可以使用以下入口点脚本:
#!/bin/sh
python manage.py migrate_all
exec "$@"
使此脚本可执行,并使其成为图像的ENTRYPOINT
,让CMD
成为实际启动应用程序的命令。每次启动容器时,它将运行迁移,然后运行main container命令,无论它是什么。如果您有多个容器副本(尤其是在集群环境(如Docker Swarm或Kubernetes)中)或需要降级时,这种方法不一定能很好地工作。在这些情况下,手动进行迁移可能更有意义。您可以通过以下方式与主容器生命周期分开进行操作:
docker-compose run web \
python manage.py migrate_all
最后,就您描述的生命周期而言,Docker镜像是不可变的:这意味着在旧镜像运行时重建新镜像是安全的。您描述的升级序列的最小停机时间方法可能类似于:git pull
# Build new images (includes `npm install`)
docker-compose build
# Run migrations (if required)
docker-compose run web python manage.py migrate_all
# Restart all containers
docker-compose up --force-recreate
关于bash - 使用Bash脚本进行Docker构建/部署,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64283027/