gpt4 book ai didi

amazon-web-services - 如何设置 Dockerized 应用程序到 Elastic Beanstalk 的持续集成?

转载 作者:行者123 更新时间:2023-12-04 08:11:14 25 4
gpt4 key购买 nike

我是 Docker 的新手,我之前的经验是将 Java Web 应用程序(在 Tomcat 容器中运行)部署到 Elastic Beanstalk。我习惯使用的管道是这样的:提交被检入 git,这会触发 Jenkins 作业,该作业构建应用程序 JAR(或 WAR)文件,将其发布到 Artifactory,然后将相同的 JAR 部署到应用程序在 Elastic Beanstalk 中使用 eb deploy 。 (抱歉,如果“管道”是一个保留术语;我是在概念上使用它。)

顺便说一句,我还将使用 Gitlab 进行 CI/CD 而不是 Jenkins(由于我无法控制的组织原因),但是从 Jenkins 到 Gitlab 的跳转对我来说似乎很简单——当然比从直接部署 WAR 以部署 Dockerized 容器。

进入 Docker 世界,我想管道会像这样:提交被检入 git,这会触发 Gitlab CI,然后构建 JAR 或 WAR 文件,将其发布到 Artifactory,然后使用 Dockerfile 到构建 Docker 镜像,将该 Docker 镜像发布到 Amazon ECR(也许?)...然后老实说,我不确定 Elastic Beanstalk 集成将如何从那里进行。我知道它与 Dockerrun.aws.json 文件有关,大概需要调用 AWS CLI。

我刚刚看完了来自 Amazon 的名为 Running Microservices and Docker on AWS Elastic Beanstalk 的网络研讨会,其中指出在我的 repo 的根目录中应该有一个 Dockerrun.aws.json 文件,它基本上定义了与 EB 的集成。但是,JSON 文件似乎包含指向 ECR 中单个 Docker 镜像的链接,这让我很不爽。每次构建新图像时,该链接不会更改吗?我想象 CI 需要动态更新 repo 中的 JSON 文件......这对我来说几乎感觉像是一种反模式。

在我上面链接的网络研讨会中,主持人创建了他的 Docker 镜像并使用 CLI 手动推送了 ECR。然后他手动将Dockerrun.aws.json文件上传到EB。然而,他不需要上传应用程序,因为它已经包含在 Docker 镜像中。这一切对我来说似乎很奇怪,我怀疑我是否正确理解了事情。 Dockerrun.aws.json 文件是否需要在每次构建时更改?还是我想错了?

最佳答案

在我发布这个问题后的 8 个月里,我学到了很多东西,我们已经转向了不同的更好的技术。但我会发布我学到的东西来回答我原来的问题。

Dockerrun.aws.json 文件几乎与 ECS 任务定义完全相同。使用 Beanstalk 的 Multi-Docker 容器部署版本(相对于单个容器)很重要,即使您只部署单个容器。 IMO 他们应该摆脱 Beanstalk 的单容器平台,因为它非常无用。但假设您已将 Beanstalk 设置为多容器 Docker 平台,则 Dockerrun.aws.json 文件如下所示:

{
"AWSEBDockerrunVersion": 2,
"containerDefinitions": [
{
"name": "my-container-name-this-can-be-whatever-you-want",
"image": "my.artifactory.com/docker/my-image:latest",
"environment": [],
"essential": true,
"cpu": 10,
"memory": 2048,
"mountPoints": [],
"volumesFrom": [],
"portMappings": [
{
"hostPort": 80,
"containerPort": 80
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/aws/elasticbeanstalk/my-image/var/log/stdouterr.log",
"awslogs-region": "us-east-1",
"awslogs-datetime-format": "%Y-%m-%d %H:%M:%S.%L"
}
}
}
]
}

如果您以后决定将整个事物转换为 ECS 服务而不是使用 Beanstalk,这将变得非常容易,因为上面的示例 JSON 通过提取“containerDefinitions”部分直接转换为 ECS 任务定义。因此等效的 ECS 任务定义可能如下所示:
[
{
"name": "my-container-name-this-can-be-whatever-you-want",
"image": "my.artifactory.com/docker/my-image:latest",
"environment": [
{
"name": "VARIABLE1",
"value": "value1"
}
],
"essential": true,
"cpu": 10,
"memory": 2048,
"mountPoints": [],
"volumesFrom": [],
"portMappings": [
{
"hostPort": 0,
"containerPort": 80
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/aws/ecs/my-image/var/log/stdouterr.log",
"awslogs-region": "us-east-1",
"awslogs-datetime-format": "%Y-%m-%d %H:%M:%S.%L"
}
}
}
]

这里的主要区别在于,在 Beanstalk 版本中,您需要将端口 80 映射到端口 80,因为在 Beanstalk 上运行 Docker 的一个限制是您不能在同一实例上复制容器,而在 ECS 中则可以。这意味着在 ECS 中,您可以将容器端口映射到主机端口“零”,这实际上只是告诉 ECS 在临时范围内选择一个随机端口,这允许您在单个实例上堆叠容器的多个副本。其次用ECS如果你想传入环境变量,你需要将它们直接注入(inject)到任务定义JSON中。在 Beanstalk 世界中,您不需要将环境变量放在 Dockerrun.aws.json 文件中,因为 Beanstalk 有一个单独的工具来管理控制台中的环境变量。

事实上,Dockerrun.aws.json 文件真的应该被认为是一个模板。因为 Beanstalk 上的 Docker 在底层使用 ECS,它只是将您的 Dockerrun.aws.json 作为模板并使用它来生成自己的任务定义 JSON,在最终将托管环境变量注入(inject)到“环境”属性中JSON。

我第一次问这个问题时遇到的一个大问题是,每次部署时是否都必须更新这个 Dockerrun.aws.json 文件。我发现这归结为您要如何部署事物的选择。你可以,但你没有必要。如果您编写 Dockerrun.aws.json 文件,以便“图像”属性引用 :latest Docker 镜像,则无需更新该文件。您需要做的就是反弹 Beanstalk 实例(即重新启动环境),它会拉取任何 :latest Docker 镜像可从 Artifactory(或 ECR,或您发布镜像的任何其他地方)获得。因此,构建管道需要做的就是发布 :latest Docker 镜像到您的 Docker 存储库,然后使用 awscli 触发 Beanstalk 环境的重新启动,命令如下:
$ aws elasticbeanstalk restart-app-server --region=us-east-1 --environment-name=myapp

但是,这种方法有很多缺点。如果你有一个 dev/unstable 分支发布了 :latest镜像到同一个存储库,如果环境碰巧自行重新启动,您将面临部署该不稳定分支的风险。因此,我建议您对 Docker 标签进行版本控制,并且只部署版本标签。所以不要指向 my-image:latest ,您会指向类似 my-image:1.2.3 的内容.这确实意味着您的构建过程必须在每次构建时更新 Dockerrun.aws.json 文件。然后你还需要做的不仅仅是一个简单的重启应用服务器。

在这种情况下,我编写了一些使用 jq utility 的 bash 脚本。以编程方式更新 JSON 中的“image”属性,用当前构建版本替换字符串“latest”。然后我将不得不调用 awsebcli 工具(请注意,这是与普通 awscli 工具不同的包)来更新环境,如下所示:
$ eb deploy myapp --label 1.2.3 --timeout 1 || true

在这里,我正在做一些 hacky: eb deploy不幸的是,命令需要 FOREVER。 (这是我们切换到纯 ECS 的另一个原因;Beanstalk 慢得令人难以置信。)该命令在整个部署时间内都挂起,在我们的例子中可能需要 30 分钟或更长时间。这对于构建过程来说是完全不合理的,因此我强制该过程在 1 分钟后超时(它实际上会继续部署;它只是断开我的 CLI 客户端的连接并向我返回一个失败代码,即使它随后可能会成功)。 || true是一种有效地告诉 Gitlab 忽略失败退出代码并假装它成功的 hack。这显然是有问题的,因为无法判断 Elastic Beanstalk 部署是否真的失败了;我们假设它永远不会。

关于使用 eb deploy 的另一件事:默认情况下,此工具将自动尝试压缩构建目录中的所有内容并将整个 ZIP 上传到 Beanstalk。你不需要那个;您只需要更新 Dockerrun.aws.json。为了做到这一点,我的构建步骤是这样的:
  • 使用 jq更新 Dockerrun.aws.json带有最新版本标签的文件
  • 使用 zip创建一个名为 deploy.zip 的新 ZIP 文件并放 Dockerrun.aws.json里面
  • 确保名为 .elasticbeanstalk/config.yml 的文件到位(如下所述)
  • 运行 eb deploy ...命令

  • 然后你需要一个位于 .elasticbeanstalk/config.yml 的构建目录中的文件。看起来像这样:
    deploy:
    artifact: deploy.zip
    global:
    application_name: myapp
    default_region: us-east-1
    workspace_type: Application

    当您调用 eb deploy 时,awsebcli 知道自动查找此文件。 .这个特定文件说的是寻找一个名为 deploy.zip 的文件,而不是尝试压缩整个目录本身。

    所以 :latest部署方法是有问题的,因为你可能会部署一些不稳定的东西;版本化的部署方法是有问题的,因为部署脚本更复杂,并且因为除非您希望构建管道花费 30 分钟以上,否则部署有可能不会成功并且真的没有办法告诉(除了自己监控每个部署)。

    无论如何,设置起来需要做更多的工作,但我建议您尽可能迁移到 ECS。 (最好还是迁移到 EKS,尽管这需要做更多的工作。)Beanstalk 有很多问题。

    关于amazon-web-services - 如何设置 Dockerized 应用程序到 Elastic Beanstalk 的持续集成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49321670/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com