bash - 使用Bash脚本进行Docker构建/部署

标签 bash docker docker-compose

我有一个试图用于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/

相关文章:

javascript - 使用 Nodejs + docker 来自 nginx 反向代理的 504 响应

docker - haproxy 没有路由到服务

linux - 可以编写脚本在本地机器上打开多个终端并通过 ssh 连接到不同的服务器吗?

mysql - 为什么 "which mysql"没有显示 .bash_profile 中定义的路径的其余部分?

docker - 在GCE上通过jenkins作业尝试时无法部署k8s pod

.net - 与容器上RabbitMQ的连接问题

amazon-web-services - 使用 docker-compose 在本地挂载 AWS EFS

bash - 棘手的 bash 尝试使用不同的参数运行程序

arrays - 使用多字符分隔符将字符串拆分为数组

docker - Travis 无法停止 Docker 容器