TECHSTEP

ITインフラ関連の記事を公開してます。

【メモ】CircleCIとAmazon ECR / EKSを利用したCI/CDパイプラインの例

はじめに

今回はCircleCIとAmazon ECRを利用したCI/CDパイプラインを用意し、コンテナイメージのビルドからKubernetesクラスタへのデプロイまで実行するサンプルを作成しました。

構成

今回は以下のようなCI/CDパイプラインを作成しました。

構成図は以下のようになります。CI/CDパイプラインはCircleCI、コンテナレジストリAmazon ECR、Kubernets環境はAmazon EKSを選択しています。

f:id:FY0323:20210515172615j:plain

CircleCI

今回利用したリポジトリディレクトリ構造はこちら。.circleci/config.yml 以外は前回のGitHub Actionsの例と同じファイルを使用しています。

.
├── .circleci
│   └── config.yml
├── README.md
├── app
│   ├── dockerfile
│   ├── main.go
│   └── main_test.go
└── manifest
    ├── deployment.yaml
    └── test.sh

CI/CDパイプラインは以下のようなファイルで構成しています。CircleCIを利用するには .circleci/config.yml ファイル上にワークフローを定義する必要があります。

今回はAmazon ECRへコンテナイメージをPushするために circleci/aws-ecrというOrbを利用しています。このOrbは、サンプルなどを見る限りWorkflow上で定義することが多いのですが、今回処理結果をSlackに通知したかったためecr-pushというJob上で定義しています。本当はJobの実行基盤をDockerにしたかったのですが上手くいかなかったため、ecr-push JobはVM上で実行しています。

./circleci/config.yml

version: 2.1
 
orbs:
  slack: circleci/slack@4.4.2
  aws-ecr: circleci/aws-ecr@7.0.0
  aws-eks: circleci/aws-eks@1.1.0
  kubernetes: circleci/kubernetes@0.12.0
 
commands:
  slack_fail:
    steps:
      - slack/notify:
          event: fail
          template: basic_fail_1
  slack_success:
    steps:
      - slack/notify:
          event: pass
          template: basic_success_1
 
jobs:
  go-test:
    docker:
      - image: circleci/golang:1.15.6
    working_directory: ~/repo
    steps:
      - checkout
      - run:
          name: Run tests
          command: go test -v ./app
      - slack_fail
  ecr-push:
    machine:
      image: ubuntu-2004:202010-01
    steps:
      - aws-ecr/build-and-push-image:
          account-url: AWS_ECR_ACCOUNT_URL
          aws-access-key-id: AWS_ACCESS_KEY_ID
          aws-secret-access-key: AWS_SECRET_ACCESS_KEY
          dockerfile: dockerfile
          path: ./app
          region: AWS_REGION
          repo: <repository-name>
          tag: latest
      - slack_fail
      - slack_success
 
  k8s-validate:
    docker:
      - image: circleci/golang:1.15.6
    working_directory: ~/repo
    steps:
      - checkout
      - run:
          name: install
          command: |
            wget https://github.com/instrumenta/kubeval/releases/latest/download/kubeval-linux-amd64.tar.gz
            tar xf kubeval-linux-amd64.tar.gz
            sudo cp kubeval /usr/local/bin
      - run:
          name: validation
          command: kubeval ./manifest/*.yaml
      - slack_fail
  k8s-deployment:
    executor: aws-eks/python3
    parameters:
      cluster-name:
        default: <cluster-name>
        type: string
      aws-region:
        default: <aws-region>
        type: string
    steps:
      - checkout
      - aws-eks/update-kubeconfig-with-authenticator:
          cluster-name: << parameters.cluster-name >>
          aws-region: << parameters.aws-region >>
          install-kubectl: true
      - kubernetes/create-or-update-resource:
          resource-file-path: manifest/deployment.yaml
      - run:
          name: check resource
          command: kubectl get pods
      - run:
          name: test apps
          command: |
            chmod +x ./manifest/test.sh
            sh ./manifest/test.sh
      - slack_fail
      - slack_success
 
 
workflows:
  docker-build-and-deploy:
    jobs:
      - go-test
      - k8s-validate
      - ecr-push:
          requires:
            - go-test
          filters:
            branches:
              only:
                - main
      - k8s-deployment:
          requires:
            - k8s-validate
            - ecr-push
          filters:
            branches:
              only:
                - main


利用したOrbsはこちら。

参考ドキュメントはこちら。


利用時の前提

パイプラインを利用するうえで必要な準備なども記載します。

CircleCIの登録

CircleCIに登録していない場合は登録と利用するリポジトリの選択を済ませておきます。

※参考ドキュメント:

Slackへの通知用設定

Jobの実行結果をSlackに通知するため、Slackの設定を行います。Slack AppにてTokenの取得と投稿用チャンネルの作成をしておきます。Slackでの設定はこちらのドキュメントに書かれた通り実行すれば完了するかと思います。

CircleCIでの変数の設定

CircleCIの Environment Variables には以下の情報を登録します。

  • AWS_ACCESS_KEY_ID: AWSへのアクセスに利用するアカウントID
  • AWS_SECRET_ACCESS_KEY: AWSへのアクセスに利用するシークレットアクセスキー
  • AWS_ECR_ACCOUNT_URL: Amazon ECRへのアクセスに利用するURL
  • AWS_REGION: AWSで利用するリージョン
  • SLACK_ACCESS_TOKEN: Slack Appで取得したアクセスToken
  • SLACK_DEFAULT_CHANNEL: Slack通知に利用するチャンネル名

その他

CircleCIでは、リポジトリ上のディレクトリやファイル毎にJobを起動することができない、と認識しています。そのため、以前GitHub Actionsでつくったパイプラインと異なり、今回はひとつのワークフローの中に、イメージのビルドとクラスターへのデプロイのJobを入れています。

CIとCDのプロセスを分けようと思った場合、いくつか方法はあると考えられます。

アプリ・インフラそれぞれ専用のリポジトリを用意する

リポジトリごとに.circleci/config.ymlを作成し、ワークフローを設定すれば処理を分けることが可能になり、CIとCDを分離することができます。アプリとインフラのコードを別のリポジトリに管理する場合、こちらの方法を採用することができるでしょう。

シェルスクリプト上で処理する

こちらの記事などで紹介されていますが、シェルスクリプト上でCircleCIを実行するタイミングをコントロールする、という方法もあるようです。プロジェクトで利用するコードをmonorepoで管理する場合、こちらの方法を採用することになるでしょう。