如何将 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
目录的新目录:
- 如果
deploy.rb
定义了需要在容器内执行的命令(比如 docker-compose exec php composer install
对应 PHP),Docker 表示容器还不存在(因为现有的是在以前的版本文件夹中创建的)。
- 如果在Capistrano部署过程中执行
docker-compose up -d
命令,由于端口冲突(之前的容器仍然存在),我会得到一些错误。
你知道如何解决这个问题吗?我应该离开 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。例如,工具将是。
- 领事
consul watch
+ consul-template
或 tiller 在代理上更新代理配置
- Registator for centralized registration or consul agent client mode with a service-configuration.json(取决于你的选择)
-
我认为 Capistrano 不是完成这项工作的合适工具。最近在 SSHKit 的 PR 中讨论了这一点,它是 Capistrano 的基础。
https://github.com/capistrano/sshkit/pull/368
@EugenMayer 更好地解释了 "normal" 使用 Docker 的方式。
我不确定我的问题是否相关,因为我可能会尝试混合不应混合使用的工具(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
目录的新目录:
- 如果
deploy.rb
定义了需要在容器内执行的命令(比如docker-compose exec php composer install
对应 PHP),Docker 表示容器还不存在(因为现有的是在以前的版本文件夹中创建的)。 - 如果在Capistrano部署过程中执行
docker-compose up -d
命令,由于端口冲突(之前的容器仍然存在),我会得到一些错误。
你知道如何解决这个问题吗?我应该离开 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。例如,工具将是。
- 领事
consul watch
+consul-template
或 tiller 在代理上更新代理配置- Registator for centralized registration or consul agent client mode with a service-configuration.json(取决于你的选择) -
我认为 Capistrano 不是完成这项工作的合适工具。最近在 SSHKit 的 PR 中讨论了这一点,它是 Capistrano 的基础。
https://github.com/capistrano/sshkit/pull/368
@EugenMayer 更好地解释了 "normal" 使用 Docker 的方式。