QCon全球软件开发大会8折优惠倒计时,购票立减¥1760!了解详情 >>> 了解详情
写点什么

使用 AWS CodePipeline 部署 Docker 容器实现 DevOps

2019 年 8 月 28 日

使用AWS CodePipeline部署Docker容器实现DevOps

本文要点

  • AWS CodePipeline 是一项 DevOps 服务,用来对各种 AWS 平台上托管的应用进行持续集成、持续交付和持续部署。

  • Amazon Elastic Container Service(ECS)是 AWS 托管的一项服务,它能够使用 Docker 容器实现应用的容器化。

  • Amazon Fargate 是 Amazon Elastic Container Service(ECS)的一种无服务器(serverless)启动形式。

  • 对于部署到 ECS 的示例应用来说,AWS CodePipeline 由一个源码仓库(如 GitHub repo)、用于进行构建的 AWS CodeBuild 以及用于 Staging 环境的 AWS ECS(Fargate)服务组成。

  • 将 AWS CodePipeline 用于 AWS ECS 服务的好处在于在新 Docker 镜像构建和部署的过程中,ECS 服务能够继续运行。


Docker 容器可以使用多种云平台进行部署,而 Amazon Elastic Container Service(ECS)就是其中之一。ECS 提供了 Fargate 运行类型,这是一个 serverless 平台,借助它容器服务能够运行在 Docker 容器中,而不是运行在 EC2 实例中。


问题

由于 Docker 镜像源码或代码构建的变更,Docker 容器的部署可能需要更新或修改。Docker 镜像中任何的代码修改都需要重新构建 Docker 镜像,Docker 服务也需要重新部署。当某个 AWS ECS 正在运行时,如果没有集成、构建、交付和部署源码的机制,那么就会涉及到停止 ECS 服务任务,这样的后果就是 ECS 服务的停机。ECS 服务的高可用性具有很高的优先级,所以停止服务重新进行部署并不是合适的可选方案。


解决方案

AWS CodePipeline 是一个用于持续集成、持续交付和持续部署的 DevOps 服务,它适用于各种 AWS 平台上的应用,其中也包括 Amazon ECS 和 Fargate 平台。ECS 在更新和修改时,可以不用停止 ECS 服务任务。AWS CodePipeline 在一个动态环境中提供了 ECS 服务的高可用性,在这种环境中,Docker 镜像的源码变更是非常常见的。CodePipeline 由三个阶段组成:源代码集成、源代码构建和部署,如图 1 所示。



图 1:CodePipeline 的不同阶段


在源码方面,我们会使用 Github 仓库。在源码构建方面,我们会使用 AWS CodeBuild 项目。在部署方面,我们会使用 ECS 服务的 Fargate 启动形式。


创建和部署 CodePipeline 应用到 ECS Fargate 涉及到如下的步骤:


  1. 为服务创建 ECS Fargate Task Definition

  2. 配置 Task Subnet/s 的连接

  3. 创建或配置 S3 Bucket,用于存放 CodePipeline Build 阶段的输出制件(Output Artifact)。

  4. 创建 CodePipeline,用来在 ECS Fargate 上部署 Docker 容器应用(镜像)。

  5. 为 Stage 制件修改输入/输出设置。

  6. 运行 CodePipeline

  7. 修改代码并重新运行 CodePipeline。


搭建环境

唯一的先决条件是要有一个 AWS 帐户。CodePipeline 部署在 ECS Fargate 上的应用程序是一个 Docker 应用。任何具有源码仓库的 Docker 镜像都可以使用,我们所使用的是dvohra/node-server Docker 镜像。Docker 镜像dvohra/node-server的源码存放在GitHub仓库中


创建 GitHub 代码仓库

如果要使用新的 GitHub 源码仓库的话,它必须要包含一个 Dockerfile 文件,据此来构建 Docker 镜像。dvohra/node-server镜像的 Dockerfile 是基于node:4.6 Docker 镜像的。Dockerfile声明要复制server.js文件到当前目录下(这个文件用来创建一个 Node 服务器)、暴露 Node 服务器所监听的 8080 端口并为 server.js 脚本运行一个 node 命令。server.js文件会创建一个 Node 服务器并处理 HTTP 请求/响应。


为 CodeBuild 项目添加构建规范

构建规范(build spec)是具有 build 命令和设置的 YAML 语法的文件,CodeBuild 项目会使用它来运行构建过程。构建规范文件必须叫做“buildspec.yml”并且必须要复制到源码仓库的根路径下。buildspec.yml 文件包含了描述各个构建阶段的键/值对。构建文件中的phases表述了阶段序列,这是buildspec.yml中需要的一个映射。versionbuildspec.yml需要的另外一个映射。buildspec.yml文件位于 GitHub 的仓库中。


添加镜像定义文件

要部署基于容器的应用,比如部署到 ECS 上的应用,AWS CodePipeline 需要有一个 JSON 格式的镜像定义文件。镜像定义文件默认名为imagedefinitions.json,但是可以使用其他的名称。镜像定义文件描述了容器应用,它包含两个属性:nameimageURIname指明了 Docker 容器的名称,容器必须要在运行 CodePipeline 之前运行。imageURI指定了要在 Docker 容器中运行的 Docker 镜像。Docker 镜像一般情况下会与 ECS 容器中已经运行的镜像相同。镜像可以是不同的,变种形式一般会通过镜像标签来设置。Node 服务器应用所用的imagedefinitions.json文件可以在 GitHub 上看到,该应用将会部署到 ECS Fargate 上。


创建任务定义

ECS 应用中的任务定义(task definition)描述了 ECS 部署环境中的容器。在本节中,我们会为 Node 服务器容器创建任务定义,以便于将其部署到 ECS Fargate 中。如果你没有登录的话,请访问该地址并登录。点击 Get started 访问 ECS 控制台。然后,点击导航区域的 Task Definitions。在 Task Definitions 中点击 Create new Task Definition。在 Create new Task Definition 中选择 Fargate 启动类型。点击 Next step,我们要配置任务和容器定义。在 Add container 对话框中,指定 Container name(node-server)并指定 Image 为_dvohra/node-server_。任务定义如图 2 所示。



图 2:任务定义


在任务子网中配置连接性

在创建服务之前,我们需要在 Subnets 中配置到 Internet 的连接性,在配置服务的时候,我们需要用的这个子网。Route Table 列出了路由,我们使用默认的 Internet gateway 添加一个新的路由。添加路由时,将 Destination 设置为 0.0.0.0/0,这是一个 IP 地址。将 Target 选择为 internet gateway.


创建和测试容器服务

接下来,在默认集群中创建一个 ECS 容器,如图 3 所示。



图 3:具有一个服务的集群


按照 Fargate 启动类型,每个任务都会有一个 Elastic Network Interface(ENI)。复制该任务的 Public IP,它与 Elastic Network Interface 的 Public IP 相同,我们可以从任务 Details 页的 Network 区域,也可以从 ENI 控制台找到它。在浏览器中打开_<Public IP of Task>:8080_ 这个 URL 地址并调用 Node 服务应用。Node 服务器会返回如图 4 所示的一条信息。



图 4:Node 服务器的响应


创建和配置 S3 Bucket

CodePipeline 在构建 Node 服务器应用的源码并将其以 Docker 镜像的形式部署为 ECS 服务时,需要 CodeBuild 项目生成“输出制件(Output Artifacts)”。输出制件会保存在 S3 bucket 中,在创建 CodePipeline 的时候要选择这个 bucket。在 S3 控制台中创建一个新的 S3 Bucket,或者选择之前运行 CodePipeline 时所创建的 S3 bucket。


创建 CodeBuild 项目

接下来,我们要创建一个 CodeBuild 项目,它用来将源码构建到 Docker 镜像中。关于 Docker 镜像dvohra/node-server的源码以及用于将源码构建到 Docke 镜像中的buildspec.yml文件,我们在前文中已经讨论过了。在 Docker 镜像构建完成之后,CodeBuild 会将其上传至 Docker hub。要创建 CodeBuild 项目,我们需要在 Web 浏览器中打开这个URL。选择 Build projects 并点击 Create project,如图 5 所示。



图 5:Build projects>Create project


这样会启动 Create project 向导。在 Configure project 中指定项目名称(node-server),在 Source>Source Provider 中选择 GitHub。对于仓库,使用 Use a repository in my account 并选择_dvohra/docker-node-server _仓库。Git clone depth 使用默认的设置,即值为 1。


选中 Webhook、Insecure SSL 和 Build Badge 选项。选择 Webhook 能够让 GitHub 仓库在每次代码变更的时候都会重新构建代码。Insecure SSL 选项能够在连接项目源时,生成源码构建的 SSL 告警。Build Badge 能够让项目的状态可见并且可嵌入。在 Environment: How to build 中的 Environment image 部分,选择 Use an image managed by AWS CodeBuild。将 Operating System 选择为 Ubuntu。对于 Runtime,选择 Docker,如图 6 所示。



图 6:将运行时选择为 Docker


对于 Runtime version,请选择 aws:codebuild/docker:17.09.0,它代表了 Docker 的 17.9 版本。如果有新的可用版本的话,请选择更新的版本。对于 Docker 运行时环境,Privileged 选项会自动选中,因为它是构建 Docker 镜像所需要的。对于 Build specification,请选择 Use the buildspec.yml in the source code root directory,如图 7 所示。默认情况下,Buildspec name 的值为 buildspec.yml。



图 7 配置环境:如何构建


对于 Certificate,选择 Do not install any certificate。CodePipeline 并不需要证书,但是如果要实现更安全 CodeBuild,我们可以安装来自 S3 的自签名证书。接下来,在 Artifacts 中配置输出制件。CodePipeline 需要输出制件。这里,我们将 Type 选择为 Amazon S3,并指明要使用的 S3 bucket 文件夹名。将 Path 设置为“/”,这样它将会在 bucket 根路径下创建文件夹。将 Namespace type 选择为 Node。将 Bucket name 选择为我们之前配置的 Bucket,如图 8 所示,同时,将 Cache 设置为 No cache



图 8 为制件配置 S3 Bucket


如果是第一次创建 CodeBuild 项目的话,在 Service role 中选择 Create a service role in your account 选项。如果之前创建过 CodeBuild 项目,那么选择 Choose an existing service role from your account。选中 Allow AWS CodeBuild to modify this service role,这样它才能够和本构建项目一起使用,如图 9 所示。对于 VPC,请选择 No VPC,然后点击 Continue。



图 9 配置 Service Role 和 Service Role 的设置


Review 页面,我们可以检查 Source Build 环境。向下滑动并点击 Create 就可以创建 CodeBuild 项目了。CodeBuild 项目创建成功后会列到 Build projects 中,如图 10 所示。



图 10 CodeBuild 项目


CodeBuild 默认创建的 service role 并不包含一些所需的权限。我们需要修改 service role 以便于包含内联的策略,添加s3:GetObjects3:PutObject权限。要添加的内联策略如下所示:


{   "Version":"2012-10-17",   "Statement":[     {       "Effect":"Allow",       "Action":["s3:PutObject","s3:GetObject"],       "Resource":"arn:aws:s3:::*"     }   ]}
复制代码


测试 CodeBuild 项目

在 CodePipeline 中创建和配置 CodeBuild 之前,我们可以测试一下 CodeBuild 项目,这样如果有错误的话,我们可以立即修正。如图 11 所示,点击 Start build 将会开始构建。



图 11 开始构建


此时将会启动 Start new build 向导,点击 Start build。CodeBuild 项目将会启动,代码会开始构建。当 CodeBuild 项目完成时,Phase details 将会与图 12 保持一致。



图 12 Phase details 和 Build logs 表明 CodeBuild 已经完成


CodeBuild 项目会生成 dvohra/node-server Docker 镜像并将其上传至 Docker Hub,如图 13 所示。



图 13 CodeBuild 生成 Docker 镜像并将其上传至 Docker Hub


创建 CodePipeline

我们已经为 CodePipeline 的每个阶段都创建了项目:源码所需的 GitHub 代码仓库、用于构建的 CodeBuild 以及用于 Staging 的 ECS Fargate 服务,接下来,我们就可以创建 CodePipeline 了。打开该地址的CodePipeline控制台,并点击图 14 中所示的 Get started。



图 14 CodePipeline>Get started


这样将会启动 Create pipeline 向导,如图 15 所示。首先,我们指定 Pipeline name(node-server-fargate),然后点击 Next step。



图 15 设置 Pipeline Name


接下来,配置 Source location。在 Source provider 中,选择 GitHub,如图 16 所示。



图 16 选择 Source provider


接下来,通过 Connect to GitHub 连接至 GitHub,如图 17 所示。



图 17 Connect to GitHub


选择 GitHub Repository,如图 18 所示。



图 18 选择 GitHub 仓库


选择仓库 Branch,如图 19 所示,然后点击 Next step。



图 19 Source location>Next step


接下来,我们要配置 Build。将 Build provider 选择为 AWS CodeBuild,如图 20 所示。



图 20 将 Build provider 选择为 AWS CodeBuild


后续展现的内容会基于所选择的 Build provider 有所差异。对于 AWS CodeBuild 来说,将会展现一个 CodeBuild 详情的区域。在 Configure your project 区域中,选择 Select an existing project,如图 21 所示。在 Project name 中,选择之前创建的名为 node-server 的项目。



图 21 选择 CodeBuild 项目


点击 Next step,接下来,我们需要配置 CodePipeline 的 Deploy 阶段,如图 22 所示。将 Deployment provider 选择为 Amazon ECS



图 22 将 Deployment provider 选择为 Amazon ECS


后续展现的内容会基于所选择的 Deployment provider 有所差异,图 23 展示了 Amazon ECS 的配置区域。在 Amazon ECS 区域中,选择 Cluster name,这将是 ECS 服务要部署到的集群,在这里选择 default



图 23 选择 ECS 集群


Service name 中要选择 ECS 要部署的服务,也就是 node-server-service,如图 24 所示。



图 24 选择 ECS 服务


Image filename 设置为imagedefinitions.json,如图 25 所示。如果忽略该值的话,默认的 Image filename 是imagedefinitions.json,并且这个文件应该位于 GitHub 仓库的源码中。然后点击 Next step。



图 25 指定 Image filename


接下来,选择 Service Role name,如图 26 所示。在 CodePipeline 第一次创建的时候,将会在 IAM 中自动创建一个 service role。在以后的操作中,将会列出 Service role 供选择。



图 26 选择 Service role


点击 Next step,检查 CodePipeline 之后点击 Create pipeline,如图 27 所示。



图 27 Create pipeline


如图 28 所示,CodePipeline 将会创建完成。CodePipeline 创建之后将会自动运行,如图 28,它会处于 Source 阶段的 In Progress 状态。



图 28 CodePipeline Source 阶段处于 in Progress 状态


Source 阶段完成之后,它的状态将会变成 Succeeded,如图 29 所示。接下来,Build 阶段将会运行,它会处于 In Progress 状态。



图 29 Source 阶段完成,Build 阶段处于 In Progress 状态


Build 完成时也会成为 Succeeded 状态,如图 30 所示。此时,Staging 阶段开始运行。



图 30 Build 阶段完成,Staging 阶段处于 In Progress 状态


修改输入/输出制件

我们已经配置了 CodePiepline 的所有阶段,那么为什么还需要修改输入/输出制件的设置呢?这是因为对于由 CodePipeline 部署的示例 ECS 应用程序来说,默认的输入/输出制件设置并不是运行 CodePipeline 所需要的。默认情况下,Staging 阶段的输入制件是_Build_阶段的输出制件。CodeBuild 只是构建 Docker 映像并将 Docker 映像上载到 Docker Hub 或 Amazon ECR 中,CodeBuild 阶段不会生成任何输出制件。Staging 阶段的输入制件需要设置为 Source 阶段的输出制件。如果不修改输入/输出制件的设置的话,Staging 阶段将会失败。创建后自动启动的 CodePipeline 将会失败。为了修改输入/输出制件的设置,点击 Edit,如图 31 所示。



图 31 CodePipeline>Edit


在修改完输入/输出制件后,点击 Save pipeline changes,如图 32 所示。



图 32 Save pipeline changes


运行 CodePipeline

要在修改之后运行 CodePipeline,我们需要点击 Release change,如图 33 所示。



图 33 Release change


Release change 确认对话框中,点击 Release。修改将会应用到 CodePipeline 上,CodePipeline 会从头开始运行,Source 阶段会处于 In Progress 状态,如图 34 所示。 Build Staging 阶段所显示的状态是之前运行的结果,并不代表这些阶段的当前状态。



图 34 Source 阶段处于 In Progress 状态


CodePipeline 的所有阶段都会完成,并处于 Succeeded 状态,如图 35 所示。



图 35 CodePipeline 的所有阶段都成功完成


前文所述的服务任务会停止运行,基于修改后的任务定义所生成的任务将会开始运行,如图 36 所示的 RUNNING 任务状态。



图 36 新任务正在运行


要调用新的任务,我们可以像前面那样在 Elastic Network interface 找到该任务的公开 IP,并在 Web 浏览器中打开 URL <Public IP>:8080,这样就能调用该任务了。Node 服务器应用的响应如图 37 所示。



图 37 Node 服务器应用的响应


修改源码,重新运行 CodePipeline

如果 ECS 服务的响应和没有 CodePipeline 时直接调用服务完全一样,那么运行 CodePipeline 的优势在什么地方呢?一般来讲,部署在生产环境的 ECS 的源码会定期更新,这意味着 Docker 镜像需要重新构建。在 ECS 服务任务中部署的 Docker 镜像也需要进行更新。在更新 Docker 镜像的时候,不能中断基于 ECS 的服务。借助 CodePipeline,每次修改源代码时都会自动重新运行 CodePipeline。在没有任何用户干预的情况下,每当源代码发生更改时,ECS 部署将会自动更新。


为了阐述该功能,我们对 GitHub 仓库中的代码稍微修改一下,比如让server.js中的 Hello 消息略有差异。在仓库中点击 Commit changes。CodePipeline 将会自动重新运行,如图 38 所示,图中 Source 阶段已经成功完成,而 Build 阶段正处于 in progress 状态。



图 38 CodePipeline 自动重启


在 Build 阶段成功完成之后,Staging 阶段会开始运行,其状态信息如图 39 所示。



图 39 Build 阶段完成,Staging 阶段启动


Staging 阶段也会成功完成。新的任务将会启动,使用新任务的公开 IP,在 Web 浏览器中打开<Public IP>:8080 URL。新任务将会被调用,Node 服务器的响应如图 40 所示,Node 服务器的响应反映了 server.js 的变化。



图 40 新任务中已修改的 Node 服务器响应


小结

在本文中,我们讨论了如何将 Docker 容器应用部署到 ECS Fargate 中。我们演示了如何更新 Docker 镜像的源代码,并在不停止容器服务的情况下将新的 Docker 镜像部署到正在运行的容器服务中,所有这些都使用 AWS CodePipeline 完成的。


作者介绍

Deepak Vohra 是 Sun 认证的 Java 程序员和 Web 组件开发人员。Vohra 在 WebLogic Developer Journal、XML Journal、ONJava、Java.net、IBM developerWorks、Java Developer Journal、Oracle 杂志和 devx 上都发表过 Java 和 Java EE 相关的技术文章。Vohra 已经出版了五本关于 Docker 的书籍,他是一位 Docker 导师。


原文链接:


Deploying Docker Containers using an AWS CodePipeline for DevOps


2019 年 8 月 28 日 08:0012223

欲了解 AWS 的更多信息,请访问【AWS 技术专区】

评论

发布
暂无评论
发现更多内容

GrowingIO 微服务 SaaS 与私有部署运行实践

GrowingIO技术专栏

大数据 微服务架构 SaaS

聊聊Serverless

kimmking

Java 编程基础

michaelliu

CDN百科 | 假如没有CDN,网络世界会变成什么样?

阿里云Edge Plus

可视化 Tekton 组件 Tekton Dashboard

郭旭东

Kubernetes cicd

我常用的在线工具清单

彭宏豪95

效率 效率工具 工具

我站在愚蠢之巅

escray

学习 CSD 认证实战营

一文看懂开源工作流引擎 Flowable

Herbert

Java spring 开源 企业中台 工作流

如何推动与影响中型前端团队的成长

堂主

前端 研发管理 团队建设

想退休,可能没机会了

池建强

读书感悟

用SpreadJS实现在线Excel的录入与展示,提升企业医保信息化服务水平

Geek_Willie

SpreadJS 医保信息化 在线excel

使用jdbcSstoragerHandler 处理mysql、oracle 、hive数据

杨飞

通过一个聊天应用学习 Deno

寇云

typescript 后端

由丰巢快递柜引发的思考

Neco.W

创业 思考 丰巢

DD 测试linux性能

HU

KubeFATE:在Kubernetes上部署联邦学习平台

亨利笔记

人工智能 学习 FATE KUBEFATE

工作两年简历写成这样,谁要你呀!

小傅哥

面试 小傅哥 Java 面试 简历优化 找工作

交易上链——中心化数字资产交易所的完美解决之道

MaxHu

区块链 智能合约 数字货币 去中心化网络 数字资产

谈谈控制感(2):怎么让我们更健康

史方远

个人成长 心理

《Linux就该这么学》笔记(二)

编程随想曲

Linux

CDN云课堂 |可编程CDN – EdgeScript应用场景、语言速览和实操演示

阿里云Edge Plus

原创 | 使用JUnit、AssertJ和Mockito编写单元测试和实践TDD (五)第一个单元测试

编程道与术

Java 编程 软件测试 TDD 单元测试

视达荣登ChinaBang Awards 2020智慧零售榜Top10

极客编

MySQL数据类型DECIMAL用法

Simon

MySQL

CDN百科 | 最近,你的APP崩了吗?

阿里云Edge Plus

CDN

多个 SSH keys 的配置,方便 Git 对不同仓库的使用与管理

与光

git GitHub SSH

延时任务的几种实现方式

郭儿的跋涉

Java 延时任务 延时消息

原创 | 使用JUnit、AssertJ和Mockito编写单元测试和实践TDD (四)关于单元测试的常见错误观念和做法

编程道与术

Java 编程 软件测试 TDD 单元测试

读懂才会用 : 瞅瞅Redis的epoll模型

小眼睛聊技术

redis 缓存 学习 开源 架构 后端

TOTO 2020再次荣获iF、红点两项国际设计大奖

极客编

CDN云课堂 | EdgeRoutine技术专家教你把JS代码跑到CDN边缘

阿里云Edge Plus

Java CDN edge

移动应用开发的下一站

移动应用开发的下一站

使用AWS CodePipeline部署Docker容器实现DevOps-InfoQ