如何将 Capistrano 与 Docker 集成以进行部署?

How to integrate Capistrano with Docker for deployment?

我不确定我的问题是否相关,因为我可能会尝试混合不应混合使用的工具(Capistrano 和 Docker)。

我最近对一个使用 Capistrano 部署的应用程序进行了 docker 化。 Docker compose 用于开发和暂存环境。

这是我的项目的样子(未显示应用程序文件):

Capfile
docker-compose.yml
docker-compose.staging.yml
config/
    deploy.rb
    deploy
        staging.rb

Docker Compose 文件会创建所有必要的容器(Nginx、PHP、MongoDB、Elasticsearch 等)以运行 正在开发或暂存的应用程序环境(因此在 docker-compose.staging.yml 中定义了一些特定参数)。

使用此命令将应用部署到暂存环境:

cap staging deploy

服务器上的文件夹架构是 Capistrano 之一:

current
releases
    20160912150720
    20160912151003
    20160912153905
shared

以下命令已 运行 在登台服务器的 current 目录中,以将所有必要的容器实例化到 运行 应用程序:

docker-compose -f docker-compose.yml -f docker-compose.staging.yml up -d

到目前为止一切顺利。下一次部署时事情变得更加复杂:current 符号链接将指向 releases 目录的新目录:

你知道如何解决这个问题吗?我应该离开 Capistrano 并做一些不同的事情吗?

我们的想法是保持 Capistrano 提供的(接近)零停机时间部署以及 Docker 容器的灵活性(例如,为同一服务器上的各种应用程序提供多个 PHP 版本).

据我了解,您在主机上使用 capistrano 来重新部署整个应用程序堆栈,即容器。因此,您正在使用 Capistrano 来编排构建、容器创建以及部署。

当你这样做时,基本上,当 运行ning cap deploy

  • 构建应用程序(基于您在主机上拉取的当前基础)- 甚至可能包括 gulp/grunt/build 任务
  • 然后你 "package" 使用 "volume mounts"
  • 将它添加到你的图像中
  • 在此期间您启动/更换容器

您这样做是为了获得 'nearly' 零停机部署。

如果您真的非常关心停机时间和正式化部署过程,您应该通过为

使用适当的管道实现来正确地做到这一点
  • 包装/ci
  • 部署/分发

我不认为 capistrano can/should 是您可以在此策略中使用的工具之一。 Capistrano 旨在使用 ssh 和 git 作为传输直接在服务器上部署应用程序。使用 cap 在目标服务器上构建整个图像,然后将它们作为容器启动,真是太过分了,恕我直言。

包装/建筑

要么使用像 jenkins/bamboo/gocd 这样的 CI/CD 服务器为您的应用程序构建发布映像。假设只有应用程序是根据 'release' 定制的,假设您的数据库和应用程序为 containers/services,应用程序将包含您的源代码,并且会在发布期间定期更改..

因此,它是一个 CD/CI 在您的 CI 服务器上异地构建新应用程序图像(发布)的过程。使用 COPY 提取应用程序的源代码并将其打包到您的图像中,然后使用任何 RUN 语句来编译您的资产(npm / gulp / g运行t whatever) .这一切都不是发生在生产服务器上,而是发生在 CI/CD 代理上。鼓励对超薄图像使用多阶段构建。

然后您推送此发布映像,让我们将此映像 yourregistry.com/yourapp 调用到您的 private registry 中作为新的 'version' 进行部署。

部署

有停机时间(简单)

要在停机的情况下部署到您的生产或暂存服务器,您只需执行 docker-composer pull && docker-composer up - 这将拉取较新的图像,然后在您的堆栈中启动它 - 您的应用已升级。在发布阶段使用标记图像需要更改 docker-compose.yml

服务器当然应该能够从您的私有存储库中提取数据。

无需停机(更努力)

要实现零停机部署,您应该使用 blue-green deployment concept。因此,您将代理添加到您的设置中,不再从应用程序公开 public 端口,而是使用此代理 public 端口。您当前的实时系统可能 运行 在随机端口 21231 上连接,代理正在从 443 转发到 21231。

我们正在使用随机端口来避免在部署 "second" 系统期间发生冲突,涵盖您提到的问题之一。

重新部署时,您只会启动一个基于新应用映像的 "new" 容器(除了旧应用映像),它会获得一个新的随机端口 12312 - 如果您愿意,运行 您的集成测试直接针对 12312(不要使用代理)。如果您完成并感到高兴,请重新配置代理以现在转发到 12312 - 然后删除旧容器 (21231)。

如果您想自动执行代理重新配置,详细超出了这个问题的范围,您可以使用服务发现和注册器,它可以使随机端口更多更实用,并且可以轻松地重新配置您的代理,当它们处于 运行 时,让它成为 nginx/haproxy。例如,工具将是。

我认为 Capistrano 不是完成这项工作的合适工具。最近在 SSHKit 的 PR 中讨论了这一点,它是 Capistrano 的基础。

https://github.com/capistrano/sshkit/pull/368

@EugenMayer 更好地解释了 "normal" 使用 Docker 的方式。