我正在使用docker将Rails应用程序部署到Elastic Beanstalk,到目前为止,一切都已成功。我在应用程序需要运行数据库的迁移和播种时,我无法确定我需要如何继续进行。似乎/.ebextensions
文件夹中的任何命令都在主机的上下文中运行,而不是在docker容器中运行。这是对的吗?
我可以在启动后运行命令在docker容器内执行迁移,但是如何确保迁移仅在单个实例上运行?是否有环境变量或其他方式我可以在docker容器中告诉哪个机器是领导者?
更新:我在6月6日/ 8月15日发布了a question in the Amazon Elastic Beanstalk forums asking how to run "commands from Docker host on the container"。您可以按照那里的对话进行操作,但它们很有用。
答案 0 :(得分:6)
我不确定你提出的解决方案是否有效。似乎EB Docker部署的当前进程在新的docker容器运行之前运行容器命令,这意味着您无法在其上使用docker exec
。我怀疑你的命令将针对尚未停止服务的旧容器执行。
经过多次试验和错误后,我通过使用带有shell脚本的容器命令来实现这一目的。
container_commands:
01_migrate_db:
command: ".ebextensions/scripts/migrate_db.sh"
leader_only: true
脚本:
if [ "${PROCESS}" = "WEB" ]; then
. /opt/elasticbeanstalk/hooks/common.sh
EB_SUPPORT_FILES=$(/opt/elasticbeanstalk/bin/get-config container -k support_files_dir)
EB_CONFIG_DOCKER_ENV_ARGS=()
while read -r ENV_VAR; do
EB_CONFIG_DOCKER_ENV_ARGS+=(--env "$ENV_VAR")
done < <($EB_SUPPORT_FILES/generate_env)
echo "Running migrations for aws_beanstalk/staging-app"
docker run --rm "${EB_CONFIG_DOCKER_ENV_ARGS[@]}" aws_beanstalk/staging-app bundle exec rake db:migrate || echo "The Migrations failed to run."
fi
true
我将整个脚本包装在一个检查中,以确保迁移不会在后台工作程序上运行。
然后我以与启动新容器时EB完全相同的方式构建ENV,以便为迁移提供正确的环境。
最后,我针对已创建但尚未运行的新容器运行命令 - aws_beanstalk/staging-app
。它在迁移结束时退出,--rm
自动删除容器。
答案 1 :(得分:3)
更新:此解决方案,虽然看似正确,但并不按预期工作(虽然它起初似乎是这样)。出于以下nmott&#39; answer中最佳解释的原因。将留在这里为后人。
我能够通过container_commands
目录配置文件使用.ebextensions
来实现此功能。在此处了解more about container commands。我引用了......
container_commands
中的命令按字母顺序处理 按名称排序。它们在应用程序和Web服务器之后运行 设置和应用程序版本文件已被提取,但之前 部署了应用程序版本。他们也可以访问 环境变量,例如您的AWS安全凭证。 此外,您可以使用leader_only。选择一个实例 Auto Scaling组的领导者。如果设置了leader_only值 如果为true,则该命令仅在标记为的实例上运行 领导者。
所以,应用这些知识...... container_commands.config
将是......
# .ebextensions/container_commands.config
container_commands:
01_migrate_db:
command: docker exec `docker ps -l -q -f 'status=running'` rake db:migrate RAILS_ENV=production
leader_only: true
ignoreErrors: false
02_seed_db:
command: docker exec `docker ps -l -q -f 'status=running'` rake db:seed RAILS_ENV=production
leader_only: true
ignoreErrors: false
首先运行迁移,然后为数据库播种。我们使用docker exec [OPTIONS] CONTAINER_ID COMMAND [ARG...]
在现有容器(而不是主机)的上下文中运行附加的COMMAND [ARG...]
。我们通过运行CONTAINER_ID
获得docker ps -q
。
答案 2 :(得分:2)
在我工作的公司中,我们在这条线上实际上相当于启动生产服务器:
bundle exec rake db:migrate && bundle exec puma -C /app/config/puma.rb
是的,这是负载平衡环境(3到12个实例,具体取决于负载),是的,它们都执行此脚本。 (我们通过在部署期间一次引入1个实例来实现负载平衡)
事情是第一批部署(第一批实例)将执行bundle exec rake db:migrate
并运行迁移(意味着它将运行数据库更改)
然后一旦完成,它将运行服务器bundle exec puma -C /app/config/puma.rb
第二个部署批次(第二个实例)将
也运行bundle exec rake db:migrate
但不会执行任何操作(因为没有挂起的迁移)。
它将继续到脚本bundle exec puma -C /app/config/puma.rb
o
老实说,我不认为这是一个完美的解决方案,但务实,适合我们的团队 我不相信有任何通用的&#34;最佳实践&#34;对于那些运行迁移的Rails的EB而言 应用程序团队不希望在部署后运行迁移,而其他人(如我们的团队)则需要运行迁移 我想在部署后直接运行它们。
如果你有工作人员喜欢延迟工作,Sidekiq,Rescue在自己的EB环境中你可以配置他们运行 迁移:
bundle exec rake db:migrate && bundle exec sidekiq
)
首先,您将部署工作人员,一旦部署了工作人员,然后部署不会运行迁移的Web服务器
例如:bundle exec puma
我同意使用EB hoos就可以了 说实话,我使用eb hooks只是为了更复杂 devops东西(比如拉Nginx网络服务器的ssl证书)不用于运行迁移)
无论如何,在这个SO问题中已经涵盖了钩子,所以我不会重复解决方案。我将参考这篇文章来帮助您理解它们:您需要弄清楚什么是最适合您的应用程序。但说实话,EB是一个非常简单的工具 (与Ansible或Kubernetes等工具相比)只要它工作正常就没有你实施的东西:)
EB for Rails开发人员的另一个有用链接:
答案 3 :(得分:1)
使用 .ebextensions / 01-environment.config :
container_commands:
01_write_leader_marker:
command: touch /tmp/is_leader
leader_only: true
现在将目录/ tmp添加到Dockerfile / Dockerrun.aws.json中的卷。
然后在sh脚本中检查所有初始化命令,如db migration,首先检查文件/ tmp / is_leader是否存在,并仅在这种情况下执行它们。