在 AWS Elastic Beanstalk 上使用 Docker 进行 Django 迁移

Posted

技术标签:

【中文标题】在 AWS Elastic Beanstalk 上使用 Docker 进行 Django 迁移【英文标题】:Django migrations with Docker on AWS Elastic Beanstalk 【发布时间】:2015-11-05 20:58:29 【问题描述】:

我有一个 django 应用程序在 AWS Elastic Beanstalk 上的单个 docker 容器中运行。我无法让它正确运行迁移,它总是看到旧的 docker 映像并尝试从中运行迁移(但它没有最新的文件)。

我用我的 EBS 源包(一个包含 Dockerrun.aws.json 文件和 .ebextensions 目录的 zip)打包了一个 .ebextensions 目录。它有一个 setup.config 文件,如下所示:

container_commands:
  01_migrate:
    command: "CONTAINER=`docker ps -a --no-trunc | grep aws_beanstalk | cut -d' ' -f1 | head -1` && docker exec $CONTAINER python3 manage.py migrate"
    leader_only: true

这部分模仿了this SO question 上的 cmets。

如果我再次重新部署应用程序,我已经验证它可以工作,因为这次之前运行的映像将具有更新的迁移文件。

有人知道如何在.ebextensions 脚本中访问最新的 docker 镜像或最新运行的容器吗?

【问题讨论】:

【参考方案1】:

我正在使用另一种方法。我所做的是基于新构建的映像运行一个容器,然后从 Elastic Beanstalk 传入环境变量并在该容器中运行自定义命令。完成该命令后,它将自行删除并继续部署。

这是我放在.ebextensions/scripts/container_command.sh 中的脚本(确保替换 中的所有内容):

#!/bin/bash

COMMAND=$1

EB_CONFIG_DOCKER_IMAGE_STAGING=$(/opt/elasticbeanstalk/bin/get-config container -k <environment_name>_image)
EB_SUPPORT_FILES=$(/opt/elasticbeanstalk/bin/get-config container -k support_files_dir)

# build --env arguments for docker from env var settings
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)

docker run --name=shopblender_pre_deploy -d \
    "$EB_CONFIG_DOCKER_ENV_ARGS[@]" \
    "$EB_CONFIG_DOCKER_IMAGE_STAGING"

docker exec shopblender_pre_deploy $COMMAND

# clean up
docker stop shopblender_pre_deploy
docker rm shopblender_pre_deploy

现在,您可以使用此脚本对稍后部署的容器执行任何自定义命令。

类似.ebextensions/container_commands.config:

container_commands:
    01-command:
        command: bash .ebextensions/scripts/container_command.sh "php app/console doctrine:schema:update --force --no-interaction" &>> /var/log/database.log
        leader_only: true
    02-command:
        command: bash .ebextensions/scripts/container_command.sh "php app/console fos:elastica:reset --no-interaction" &>> /var/log/database.log
        leader_only: true
    03-command:
        command: bash .ebextensions/scripts/container_command.sh "php app/console doctrine:fixtures:load --no-interaction" &>> /var/log/database.log
        leader_only: true

这样你也不必担心你最近启动的容器是什么,这是上述解决方案的问题。

【讨论】:

【参考方案2】:

根据Customizing Software on Linux Servers 上的 AWS 文档,container_commands 将在部署您的应用程序之前执行。

您可以使用container_commands 键为您的容器执行命令。 container_commands 中的命令按名称按字母顺序处理。 它们在应用程序和网络服务器设置完成后运行并且应用程序版本文件已提取,但在应用程序版本部署之前。他们还可以访问环境变量,例如您的 AWS 安全凭证。此外,您可以使用leader_only。一个实例被选为 Auto Scaling 组中的领导者。如果leader_only 值设置为true,则该命令仅在标记为领导者的实例上运行。

看看我在here 中的回答。它在不同的应用部署状态下运行一些命令并给出命令结果。

因此,您的问题解决方案可能是创建应用后部署挂钩

.ebextensions/00_post_migrate.config

files:
  "/opt/elasticbeanstalk/hooks/appdeploy/post/10_post_migrate.sh":
    mode: "000755"
    owner: root
    group: root
    content: |
      #!/usr/bin/env bash
      if [ -f /tmp/leader_only ]
      then
        rm /tmp/leader_only
        docker exec `docker ps --no-trunc -q | head -n 1` python3 manage.py migrate
      fi

container_commands:
  01_migrate:
    command: "touch /tmp/leader_only"
    leader_only: true

【讨论】:

谢谢 - 我会试一试并报告。如果命令返回非零状态,您是否还知道这是否会停止部署? 我不确定。需要先尝试一下。 在启动 django 之前创建一个运行迁移的入口点脚本不是更简单吗? @elssar 您的意思是在 Dockerfile 本身中?那我怎么才能让它只在leader_only 上运行呢? @EdwardSamuel 刚刚试了一下,然后开始工作!感谢您的提示。我在 EB 机器上的 /opt/elasticbeanstalk/hooks/appdeploy/ 目录中窥探,并从那里的其他脚本中获取了一些其他队列,例如,它们获取了一个 common.sh 文件,该文件公开了一些允许您在事件中插入跟踪、警告或错误的函数部署过程。似乎工作得很好,唯一担心的是它似乎没有被 AWS 正式记录或批准,亚马逊可能会在没有通知的情况下改变一切:O

以上是关于在 AWS Elastic Beanstalk 上使用 Docker 进行 Django 迁移的主要内容,如果未能解决你的问题,请参考以下文章

在 AWS Elastic Beanstalk 上扩展 Magento

如何在 AWS Elastic Beanstalk 上设置 HTTPS

如何在 AWS Elastic Beanstalk 上设置 HTTPS

在 AWS Elastic Beanstalk 上运行节点和反应

如何使用 aws cli 在 Elastic Beanstalk 上上传和部署?

在aws elastic beanstalk上上传文件?