Amazon Linux 2 AMI 上的命令 01_migrate 失败

Posted

技术标签:

【中文标题】Amazon Linux 2 AMI 上的命令 01_migrate 失败【英文标题】:Command 01_migrate failed on Amazon Linux 2 AMI 【发布时间】:2020-10-19 06:56:57 【问题描述】:

我有一个部署到 Elastic Beanstalk Amazon Linux 2 AMI 的 Django 项目。我安装了 Pymysql 以连接到数据库,并将这些行添加到 settings.py 中,如下所示;

import pymysql

pymysql.version_info = (1, 4, 6, "final", 0)
pymysql.install_as_MySQLdb()

我还有一个用于迁移数据库的 .config 文件;

container_commands:
  01_migrate:
    command: "django-admin.py migrate"
    leader_only: true
option_settings:
  aws:elasticbeanstalk:application:environment:
    DJANGO_SETTINGS_MODULE: mysite.settings

通常,我在我的 Linux AMI 上使用 mysqlclient 和这个 .config 文件,但它在 Linux 2 AMI 上不起作用,所以我安装了 PyMySQL。现在,我正在尝试部署我的项目的更新版本,但出现如下错误;

Traceback (most recent call last):
  File "/opt/aws/bin/cfn-init", line 171, in <module>
    worklog.build(metadata, configSets)
  File "/usr/lib/python2.7/site-packages/cfnbootstrap/construction.py", line 129, in build
    Contractor(metadata).build(configSets, self)
  File "/usr/lib/python2.7/site-packages/cfnbootstrap/construction.py", line 530, in build
    self.run_config(config, worklog)
  File "/usr/lib/python2.7/site-packages/cfnbootstrap/construction.py", line 542, in run_config
    CloudFormationCarpenter(config, self._auth_config).build(worklog)
  File "/usr/lib/python2.7/site-packages/cfnbootstrap/construction.py", line 260, in build
    changes['commands'] = CommandTool().apply(self._config.commands)
  File "/usr/lib/python2.7/site-packages/cfnbootstrap/command_tool.py", line 117, in apply
    raise ToolError(u"Command %s failed" % name)
ToolError: Command 01_migrate failed

我该如何解决这个问题?

【问题讨论】:

当您从实例手动运行django-admin.py migrate 时,它是否按预期工作? 当我在我的 powershell 上运行命令时,它按预期工作。我可以将更改迁移到我的数据库。 很好,但是当您 ssh 进入 EB 实例并运行命令时,它是否可以在 EB 实例本身上工作? 我尝试运行 migrate 命令,但出现No such file or directory之类的错误 django-admin.py migrate 来自哪里?它是您的应用程序的一部分,还是某些依赖项? 【参考方案1】:

Amazon Linux 2 的设置与 AL1 完全不同,截至 2020 年 7 月 24 日的当前文档已过时。 django-admin beanstalk 安装的环境似乎不在路径上,因此您可以源环境来激活并确保它是。

我也留下了我的答案here,其中更详细地说明了我是如何得出这个答案的,但解决方案(我不喜欢)是:

container_commands:
    01_migrate:
        command: "source /var/app/venv/*/bin/activate && python3 manage.py migrate"
        leader_only: true

尽管我不喜欢它,但我已通过 AWS Support 验证这实际上是推荐的方法。您必须获取 python 环境,就像 AL2 一样,他们使用虚拟环境来保持更加一致。

【讨论】:

请注意,这会激活正确的 python(设置 PATH),但不会激活 EBS UI 设置的环境值。如果 dango 使用其中任何一个(凭证 BAD、秘密名称等),则不会为迁移命令设置它。 这个命令依赖于(至少对我而言)我在 GUI 中为一些秘密设置的环境变量,它工作得很好。我不确定你的意思@MatanDrory 这很奇怪。我刚刚在我的 EBS 创建的 EC2 机器上对其进行了测试。我运行printenv 并没有看到我的环境变量,然后运行source /var/app/venv/*/bin/activate &amp;&amp; printenv 并再次我没有看到环境变量,唯一的变化是在PATH 中。我目前有一个丑陋的解决方法,它使用一个 prebuild hook 将 env 文件复制为导出格式,我改为使用它。问题在于“/opt/elasticbeanstalk/deployment/env”中的 env 文件仅在成功部署后才创建,迫使我从示例应用程序开始【参考方案2】:

answer from @nick-brady 很棒,它提供了基本的解决方案。

但是,migrating to Amazon Linux 2 上的 AWS 文档建议我们应该使用 .platform 钩子来做这样的事情:

我们建议使用平台挂钩在您的环境实例上运行自定义代码。您仍然可以在.ebextensions 配置文件中使用命令和容器命令,但它们并不容易使用。例如,在 YAML 文件中编写命令脚本可能很麻烦且难以测试。

来自AWS Knowledge Center:

...最好使用平台挂钩,而不是在.ebextension 配置文件中提供文件和命令。

作为奖励,平台挂钩的输出被收集在一个单独的日志文件 (/var/log/eb-hooks.log) 中,默认情况下该文件包含在 bundle 和 tail 日志中。这使得调试更容易一些。

基本思想是在您的应用程序源包中创建一个 shell 脚本,例如.platform/hooks/postdeploy/01_django_migrate.sh。这在docs for extending EB linux platforms 的平台挂钩部分中有更详细的描述。

文件必须是可执行的,所以:chmod +x .platform/hooks/postdeploy/01_django_migrate.sh

文件内容可能如下所示(基于@nick-brady's answer):

#!/bin/bash

source "$PYTHONPATH/activate" && 
# log which migrations have already been applied
python manage.py showmigrations;
# migrate
python manage.py migrate --noinput;

collectstatic 等也可以这样做。

请注意,Python 虚拟环境的路径可作为环境变量PYTHONPATH 用于平台挂钩。您可以通过检查实例上的文件 /opt/elasticbeanstalk/deployment/env 来验证这一点,例如通过 ssh。另见AWS knowledge center。

对于那些想知道的人,shell 脚本中的&amp;&amp; 是一种条件执行:只有在前面成功的情况下才执行以下操作。 参见例如here.

仅限领导

在部署期间,应该有一个EB_IS_COMMAND_LEADER 环境变量,可以对其进行测试,以便在.platform 挂钩中实现leader_only 行为(基于this post):

...

if [[ $EB_IS_COMMAND_LEADER == "true" ]];
then 
  python manage.py migrate --noinput;
  python manage.py collectstatic --noinput;
else 
  echo "this instance is NOT the leader";
fi

...

【讨论】:

有没有办法像在命令中那样知道这是否是领导者?我更喜欢这个解决方案,因为环境变量是可访问的(我没有测试过,但我看到你正在使用 $PYTHONPATH)。唯一的问题是我宁愿迁移只在领导者上运行。 @MatanDrory:对此不确定。我无法在文档中找到任何明确的内容,我自己也没有尝试过。看起来您仍然可以在 .ebextensions 中使用 leader_only,或者在您的 .platform 脚本中使用测试实现类似的效果(还要注意 hooks and config-hooks 之间的区别)。 @MatanDrory:我找到了答案:在部署期间,您可以检查一个名为 EB_IS_COMMAND_LEADER 的环境属性,如this post 中所述。我会更新答案。 注意:要在登录实例时激活python(例如通过eb ssh),可以使用get_config工具获取PYTHONPATH的值:source "$(/opt/elasticbeanstalk/bin/get-config environment -k PYTHONPATH)/activate"【参考方案3】:

在我的情况下,这个 .config 工作

container_commands: 01_迁移: 命令:“django-admin.py 迁移” 仅领导者:真 02_collectstatic: 命令:“django-admin.py collectstatic --noinput”

我有这个命令:“source /var/app/venv/*/bin/activate && python3 manage.py config 直到 1 月 4 日,突然我遇到了部署错误

【讨论】:

以上是关于Amazon Linux 2 AMI 上的命令 01_migrate 失败的主要内容,如果未能解决你的问题,请参考以下文章

sh EC2上的Amazon Linux AMI 2017.09.0(HVM)上的golang,docker和docker-compose的安装脚本

Amazon Linux AMI 上的“bash: jstack: command not found”错误

如何在 AWS 上的 Amazon Linux AMI 中自动启动 node.js 应用程序?

将带有 Sinatra 2.0.0beta2 的 Rails 5 应用程序部署到 Amazon Linux AMI 时出错

Amazon linux:创建 ami 映像时更改默认 ec2-user

如何在最新的 Amazon linux AMI 中升级 docker