ちょっと話題の記事

GitHub ActionでDockerコンテナをビルドしてAmazon ECRに保存する

2019.11.15

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

おはようございます、加藤です。下記のブログで、AWS認証情報の設定とAmazon ECRにログインするGitHub Actionが公開されている事を知りました。
これらを使って、GitHubで管理しているDockerイメージをビルドして、ECRに保存する方法を紹介します。タグが付けられて時にのみ動作し、そのタグをイメージに引き継ぐ仕様で作りました。

Continuous delivery of container applications to AWS Fargate with GitHub Actions | AWS Open Source Blog

AWS IAM ユーザーの作成

GitHub ActionからAmazon ECRへアクセスする為の、IAMユーザーを発行します。マネジメントコンソールへのアクセスは必要無いので、アクセスの種類はプログラムによるアクセスのみを設定します。
今回は、AWS管理ポリシー AmazonEC2ContainerRegistryPowerUser を関連付けします。権限を最小化したい場合は、独自でIAMポリシーを作成してください。

発行されたアクセスキー、シークレットアクセスキーは後ほど使用するのでメモして置きます。

Amazon ECRの作成

任意の名前でコンテナリポジトリを作成してください。今回は sample-nginx という名前で作成しました。

GitHub Action ワークフローの作成

以下の3ステップで実行します。

  1. AWS認証情報を設定
  2. Amazon ECRにログイン
  3. ビルドとプッシュ

v* のタグが設定された時だけ、動作します。実ワークロードでは、ビルド後にテストの実施や、タグが設定されなくても、テストまでは行うなど、変更が必要です。

.github/workflows/main.yml

name: Build and Push

on:
  push:
    tags:
      - v*

jobs:
  build-and-push:

    runs-on: ubuntu-18.04
    timeout-minutes: 300

    steps:
    - uses: actions/checkout@v1    

    - name: Configure AWS Credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ap-northeast-1

    - name: Login to Amazon ECR
      id: login-ecr
      uses: aws-actions/amazon-ecr-login@v1

    - name: Build, tag, and push image to Amazon ECR
      env:
        ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
        ECR_REPOSITORY: ${{ secrets.AWS_ECR_REPO_NAME }}
      run: |
        IMAGE_TAG=$(echo ${{ github.ref }} | sed -e "s#refs/tags/##g")
        docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
        docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG

GitHubリポジトリにSecretsを設定

GitHubリポジトリを開き、 Settings → Secrets からSecretsを設定します。ここで設定した値は、GitHub Action ワークフロー内で ${{ secrets.AWS_ECR_REPO_NAME }} という記法で取り出しができます。
以下の3つを設定してください。

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • AWS_ECR_REPO_NAME

サンプルコンテナの準備

nginxをベースに作成します。
Hello World!と表示されるだけのシンプルな静的Webサイトです。

directory layout

.
├── Dockerfile
└── html
    └── index.html

Dockerfile

FROM nginx:1.17.5

COPY ./html /usr/share/nginx/html

html/index.html

<html>

<body>
    <h1>Hello World!</h1>
</body>

</html>

これら、2つのファイルを作成します。

実行

まず、リポジトリにプッシュします。

git add -A
git commit -m 'initial commit'
git push

次に、タグを付けてプッシュします。

git tag v1.0.0
git push --tags

GitHub Action ワークフローのログを確認します。

今回、下記の2つのGitHub Actionを使用しましたが、アカウント番号やリポジトリ名などまで、マスクしてくれるので、Publicなリポジトリでも安心して使えますね!!(これらの情報が見えたからといって直接的に危険は無いですが)

Amazon ECRにImageが登録されていれば、成功です。

※ 画像はタグ名が v1.0.3 となっていますが、手順通りなら v1.0.0 となります。

あとがき

GitHub Actionを初めて使ってみました。リポジトリのタグ名を ${{ github.ref }} という記法で取得できるのですが、 refs/tags/v1.0.0 という感じで取り出されます。
このままだと、イメージのタグ名に使用できないので、 sedIMAGE_TAG=$(echo ${{ github.ref }} | sed -e "s#refs/tags/##g") と書いて v1.0.0 を抽出しています。
社内で相談し、 奥さん和田さん に教えて貰いましたが、良い方法は無いみたいです...

今回は、タグの設定をトリガーとしていますが、リリースをトリガーにする事もできます。コンテナのビルドからデプロイまで一気通貫のパイプラインをよく見ますが、アプリ担当者とインフラ担当がチームとして別れている様な場合は、パイプラインも合わせて分割した方が良いかなと個人的には思っています。
後続の処理としては、以下の2パターンがあると思っています。

  • Amazon ECRへのプッシュをトリガーとしてAmazon ECS/EKSへのデプロイするパイプラインを動かす
  • コンテナのバージョンも含めてInfrastructure as Codeで管理しているので、コードのバージョン指定部分を変更する

以上です!