如何在Amazon Elastic Beanstalk单容器Docker环境中运行Rails迁移和种子设定

时间:2015-07-22 20:05:31

标签: ruby-on-rails docker elastic-beanstalk

我正在使用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"。您可以按照那里的对话进行操作,但它们很有用。

4 个答案:

答案 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)

解决方案1:启动服务器时运行迁移

在我工作的公司中,我们在这条线上实际上相当于启动生产服务器:

 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而言 应用程序团队不希望在部署后运行迁移,而其他人(如我们的团队)则需要运行迁移 我想在部署后直接运行它们。

解决方案2:后台工作人员Enviromnet运行迁移

如果你有工作人员喜欢延迟工作,Sidekiq,Rescue在自己的EB环境中你可以配置他们运行 迁移:

bundle exec rake db:migrate && bundle exec sidekiq

首先,您将部署工作人员,一旦部署了工作人员,然后部署不会运行迁移的Web服务器

例如:bundle exec puma

解决方案3挂钩

我同意使用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是否存在,并仅在这种情况下执行它们。