Featured image of post (教程) 如何设置 AWS Codebuild+ECR

(教程) 如何设置 AWS Codebuild+ECR

写于2021年5月17日

这篇文章讲什么?

如何用 AWS Codebuild 构件出 Docker 镜像。然后把镜像推到 ECR。

本文章对谁有用?

打算部署到 AWS ECS 的程序员。

备注

以下全部是在 AWS 中国区(北京)(cn-north-1) 完成的

问题:根本目的是什么?

最终目的是把一个 Ruby on Rails 应用部署到 AWS。并且有自定义域名可访问。
本篇文章还没有达到这个目的,只是完成了一部分(Codebuild+ECR)

这俩组件的意义:

  • Codebuild:构建(build)镜像 (就是普通的 Docker 镜像)
  • ECR:存储镜像

这俩弄成功之后,后续可以用 ECS 运行镜像。

问题:用不用 CloudFormation?

不用,这一次我们全手动在网页里新建。
第一个原因:Codebuild 和 ECR 这种东西建了一次之后,几乎万年不变。
第二个原因: 我 CloudFormation 不是特别熟悉

第一步:首先你应该有个 Dockerfile(根目录下)

以下是我们的 Dockerfile,仅供参考,我们这个是 Ruby on Rails 应用,你的可能是 PHP/Java 等。

FROM ruby:2.7.1-alpine3.12

用中国区的 Alpine 镜像

COPY repositories /etc/apk/repositories

ARG APP_ENV

RUN apk update && apk add bash

RUN apk add –no-cache –update linux-headers
build-base
git
python3
# python3 is for alpine3.12 python3-dev
# python3-dev is for alpine3.12 postgresql-dev
sqlite-dev
less
nodejs
nodejs-npm
ttf-ubuntu-font-family
tzdata
ffmpeg

RUN mkdir -p /app RUN mkdir -p /usr/local/nvm WORKDIR /app

RUN node -v RUN npm -v

Copy the Gemfile as well as the Gemfile.lock and install

the RubyGems. This is a separate step so the dependencies

will be cached unless changes to one of those two files

are made.

COPY Gemfile Gemfile.lock package.json yarn.lock ./ RUN gem sources –add https://gems.ruby-china.com/ –remove https://rubygems.org/ RUN gem sources -l RUN gem install bundler -v 2.2.15 RUN gem install foreman -v 0.87.2

Install gems from the RubyGems Chinese mirror

RUN bundle config mirror.https://rubygems.org https://gems.ruby-china.com RUN bundle install –verbose –jobs 20 –retry 5

RUN npm install -g yarn –registry=https://registry.npm.taobao.org RUN yarn config set registry https://registry.npm.taobao.org RUN yarn config set sass-binary-site https://npm.taobao.org/mirrors/node-sass

RUN yarn install –registry https://registry.npm.taobao.org/ –check-files –verbose

Copy the main application.

COPY . ./

If this is a production image, precompile the assets

RUN if [ "$APP_ENV" = "production" ] ; then RAILS_ENV=production SECRET_KEY_BASE=bin/rake secret bundle exec rake assets:precompile ; fi

Expose port 80 to the Docker host, so we can access it

from the outside.

EXPOSE 80

The main command to run when the container starts. Also

tell the Rails dev server to bind to all interfaces by

default.

CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0", "-p", "80"]

Dockerfile 里第二步 repositories 文件内容(同一个层级,根目录下)

# China region mirror server for Alpine
https://mirrors.nju.edu.cn/alpine/v3.12/main
https://mirrors.nju.edu.cn/alpine/v3.12/community

第二步:你应该有个 buildspec.yml 文件(根目录下)

这个文件指名了 Codebuild 应该怎么做。

version: 0.2

官方教程文档

https://docs.aws.amazon.com/codebuild/latest/userguide/sample-docker.html

需要配置4个 Codebuild 环境变量

$AWS_DEFAULT_REGION

$AWS_ACCOUNT_ID

$IMAGE_REPO_NAME

$IMAGE_TAG

Docker caching:

https://github.com/aws/aws-codebuild-docker-images/issues/26#issuecomment-370177343

phases: install: runtime-versions: docker: 18 pre_build: commands: - docker version # https://github.com/aws/aws-cli/issues/4962#issuecomment-592064025 - echo 登录 Amazon ECR… - aws ecr –region $AWS_DEFAULT_REGION get-login-password | docker login –username AWS –password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com.cn # 如果 ecr 登录这一步如果失败,可能是 role 没有权限 # An error occurred (AccessDeniedException) when calling the GetAuthorizationToken operation: User: arn:aws-cn:sts::832343096630:assumed-role/codebuild-hackernews-codebuild-staging-service-role/AWSCodeBuild-a7c26677-1ec3-4497-90e1-c94bc4abd414 is not authorized to perform: ecr:GetAuthorizationToken on resource: * # 给 Role 加一个 AmazonEC2ContainerRegistryFullAccess 就行了 build: commands: - echo Build started on date - echo Building the Docker image… # 我们这里让 Docker 使用阿里云的镜像服务 # 开发者需要开通阿里开发者帐户,再使用阿里的加速服务 # 登录后阿里开发者帐户后,在 https://cr.console.aliyun.com/undefined/instances/mirrors 查看您的专属加速器地址 - mkdir -p /etc/docker - | tee /etc/docker/daemon.json <<-‘EOF’ { "registry-mirrors": ["https://(隐去).mirror.aliyuncs.com"] } EOF - docker build –cache-from $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com.cn/$IMAGE_REPO_NAME:$IMAGE_TAG -t $IMAGE_REPO_NAME:$IMAGE_TAG –build-arg APP_ENV=production . - docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com.cn/$IMAGE_REPO_NAME:$IMAGE_TAG post_build: commands: - echo Build completed on date - echo Pushing the Docker image… - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com.cn/$IMAGE_REPO_NAME:$IMAGE_TAG

第三步:创建 ECR 存储库

先做这一步是因为这一步太简单了。

名字没什么特别要求。
我们这里用 xxx-production 以及 xxx-staging 对应2个环境下的镜像。
如果你照着做,这里先新建一个就行,反正是学习目的嘛,学会了再删掉就行。

第四步:弄 Codebuild

名字你随便写,我们这里是 xxx-codebuild-staging。
代表 xxx 项目,codebuild,staing 环境。

下拉菜单打开后如下图:

源不建议选 Github。
建议选择 Amazon S3。

意思就是:你的代码当然可以继续存在 Github 或者 Gitlab 或者随便哪里。
但是构建的时候,Codebuild 去 S3 里拿你的代码。

为什么这么干?

降低网络影响。
中国境内访问 Github 比较慢,如果选这个,每次要十几秒/几十秒/失败。
如果 Codebuild 直接从 S3 拿,速度非常快。可以在构建的"阶段详细信息"里看到 "DOWNLOAD_SOURCE" 这一步 "<1 sec"。
也就是说一秒就完成了(哪怕文件大点,2-5秒也搞定了)

怎么让 Codebuild 从 S3 拿代码?

我们上面 Codebuild 还没新建完成,
但是先讲这个话题,怎么把代码传到 S3 让 Codebuild 来获取。

我们先在 S3 新建一个 bucket,这个 bucket 不需要公开,
名字可以是 xxx-codebuild
xxx 代表项目名。

Makefile

根目录下新建一个文件叫做 Makefile

# Create a Zip archive that contains the contents of the latest commit on the current branch.
# 把当前分支最新 commit 的代码打包成 "当前分支名.zip"
# 注意: .gitattributes 文件让 git archive 命令忽略了一些文件(因为对部署没用,所以忽略)
zip-current-branch:
	git archive -o "$$(git rev-parse --abbrev-ref HEAD).zip" HEAD
	echo "成功打包文件 $$(git rev-parse --abbrev-ref HEAD).zip"

上传到 s3

upload-to-aws-s3: filename="$$(git rev-parse –abbrev-ref HEAD).zip" &&
bucket_name="xxx-codebuild" &&
echo "正在把文件: $$filename 上传到 AWS S3 的桶 $$bucket_name" &&
aws s3 cp $$filename s3://$$bucket_name/$$filename &&
rm $$filename

打包+上传

zip-current-branch-upload-to-aws-s3: make zip-current-branch make upload-to-aws-s3

注意:

  1. 缩进必须是 tab,不能是空格,否则 make 命令会失败。
  2. 你本地电脑必须登录了 aws cli,这个部分不展开讲,自行上网搜索,提示:运行 aws configure

怎么运行?

make zip-current-branch-upload-to-aws-s3

假设你当前分支是 staging,那么会打包出一个 staging.zip 文件夹。
然后上传到 S3 xxx-codebuild bucket(注意看 upload-to-aws-s3 那一段写的 bucket_name 是什么)

好的,完成,这下你就知道了怎么把本地代码打包成 zip 放到 AWS S3。
我们回到正题,继续新建 Codebuild

继续新建 Codebuild

接下来设置环境

我是这样设置的

角色这里随便写个名字。比如 xxx-codebuild-service-role 之类的。
我们需要给这个 role 新增一个权限(去 IAM 里面设置),如下图:

加一个 AmazonEC2ContainerRegistryFullAccess 权限。
原因是如果不加,Codebuild 无法运行 aws ecr 登录命令。
就没有权限把镜像 push 到 ECR 里。

下一步:设置环境变量

这里设置了4个环境变量。
注意,这些环境变量是和 buildspec.yml 对应的。
如果不设置这些环境变量,buildspec.yml 就会失败。

下一步 Buildspec

这里用默认的就行,可以不填这里,默认用 buildspec.yml 文件。

确认新建

最后

既然设置完了,此时可以在 Codebuild 中触发构建。

当然你也可以用 aws cli 触发 Codebuild,比如

aws codebuild start-build --project-name xxx-codebuild

全文完

使用 Hugo 构建
主题 StackJimmy 设计