LoginSignup
22
23

More than 3 years have passed since last update.

CircleCI+Code4兄弟でFargateで動くGoプログラムをデプロイする

Last updated at Posted at 2019-10-23

はじめに

Go言語で書かれたプログラムをFargateでサービス実行していて、そこにCI/CDを設定する
手順の紹介記事です。
構成は以下の通り

  • GitHub
  • CircleCI
  • CodePipeline(CodeCommit/CodeBuild/CodeDeploy)
  • ECS(Fargate)

CircleCIを経由しないフローでもいいですが、CircleCI 2.1での新しい書き方を試したかった
のもあり、こんな構成にしました。 参考:CircleCI2.1 Qiita検索結果
なお、手順の紹介に重点を置いたので、各種設定ファイルについては概要説明に止めます。

前提

環境

  • QA/Production環境それぞれ別のAWSアカウントで利用
  • 東京リージョン(ap-northeast-1)を利用
  • FargateでサービスとしてGoプログラムを実行している
  • CirceCIのconfig.ymlはversion2.1を使用
    • executors/commands/parametersを使いたいので
  • Golangのバージョンは1.13~
    • Go Modulesを使っているので

デプロイフロー

GitHubでは3種類のブランチを使います。
それを、以下のように動作するよう設定します。

  • masterブランチ
    • developブランチのマージ先
    • PRマージされるとProduction環境のCodeCommitへPushされる
    • CodeCommitへのPushをトリガにCodePipelineによりECSへデプロイされる
  • developブランチ
    • 開発用ブランチのマージ先
    • 開発を始める場合はここから新しい開発用ブランチを作成
    • PRマージされるとQA環境のCodeCommitへPushされる
    • CodeCommitへのPushをトリガにCodePipelineによりECSへデプロイされる
  • 開発用ブランチ(ここではfeature_hogeブランチ)
    • GitHubにPushされるとLint/Testが実行される

なので、マージの流れは、 feature_hoge -> develop -> master の順

イメージ図

スクリーンショット 2019-10-23 19.18.36.png

今回利用するGoプログラム

sample-go
プログラムの内容は適当(個人的な検証プログラム)です。
ECSにサービス登録して実行する前提なので、デーモンとして動く実装であればどんなコードでもOK。

ファイル構成

sample-go
├── .circleci
│   └── config.yml   # CircleCI設定ファイル
├── Dockerfile       # Goプログラム実行用コンテナ作るやつ(マルチステージビルド!!)
├── Makefile         # Goプログラムのビルドに使う
├── bin              # リポジトリには含まれません
│   └── sample-go    # make bin/sample-go を実行して生成されるバイナリ
├── buildspec.yml    # CodeBuildが実行するコマンドを記述したファイル
├── main.go
├── main_test.go
├── go.mod
└── go.sum

CI設定に関わる下記ファイルの概要説明

  • .circleci/config.yml
    • GitHubへのPushをトリガに動くCircleCIワークフローの設定ファイル
  • buildspec.yml
    • CodeBuildが実行するコマンドなどを指定したファイル
    • docker build してイメージをECRへPushするという内容
  • Dockerfile
    • Goプログラムのビルド、及び実行バイナリを格納したコンテナイメージを作成するDockerfile
    • buildspec.yml内で指定されている

手順

GitHub - CircleCI 連携設定

https://circleci.com/ にアクセス

まだGitHub - CircleCI 連携設定していない場合は下記手順を実施

GitHubアカウントでログイン

下記ボタンをクリック
スクリーンショット 2019-10-21 15.30.29.png

CircleCIからGitHubへのアクセスを許可

下記のような確認画面が表示されるので画面下の Authorize circleciボタンをクリック

スクリーンショット 2019-10-21 15.30.29.png

CIをセットアップするリポジトリを指定

https://circleci.com/add-projects/gh/{GitHubアカウント名} にアクセス

スクリーンショット 2019-10-21 15.35.18.png
対象リポジトリのSet Up Projectボタンを押す

Set Up Project 画面からビルドを一度実行する

  • Operating System -> Linux
  • Language -> Go
    を選択し、Next Stepsセクションの Start building をクリック
    スクリーンショット 2019-10-21 15.58.17.png

初回はエラーになるがこのまま進めます

CI(Lint/Test)動作確認

feature_hogeブランチを作成してPush

git checkout -b feature_hoge
git push origin feature_hoge

https://circleci.com/gh/{GitHubアカウント名}
にアクセスして上記のPushをトリガに最新Job(一番上)が動いていることを確認します。

スクリーンショット 2019-10-23 10.59.59.png

SUCCESSであれば、Lint/Testにパスしたということになります。
もし、FAILEDであれば、対象のJobをクリックして、Lint/Test結果を確認し、必要な修正を行ってください。

以降の設定は、QA/Productionの両方のAWSアカウントで実施する必要があります。
QA用AWSアカウントの手順のみ記載しますが、Productionにも同様に設定する必要があります

Fargate設定

ECRにリポジトリを作成してコンテナイメージをPush

# awsクレデンシャルのプロファイルを指定
export AWS_PROFILE={プロファイル名}

# ECRにリポジトリを作成
aws ecr create-repository --region ap-northeast-1 --repository-name sample-go

# コンテナイメージをECRにPush
ACCOUNT_ID=$(aws sts get-caller-identity | jq -r .Account)
$(aws ecr get-login --no-include-email --region ap-northeast-1)
docker build -t sample-go .
docker tag sample-go:latest $ACCOUNT_ID.dkr.ecr.ap-northeast-1.amazonaws.com/sample-go:latest
docker push $ACCOUNT_ID.dkr.ecr.ap-northeast-1.amazonaws.com/sample-go:latest

Fargate設定(詳細割愛)

参考記事:AWS ECRとECSの入門(Fargate編)

ここでは下記を作成した前提で進めます

  • クラスタ名:sample-go
  • サービス名:sample-go
  • タスク定義名:sample-go
    • コンテナ定義のイメージURL:123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/sample-go:latest

CodeCommit設定

CodePipelineのトリガとなる、CodeCommitの設定を行います。
CI設定時に、事前にCodeCommitにブランチを作成する必要があるのでそのセットアップも行います。

CodeCommitにPushするためのIAMユーザ作成

IAMユーザ作成

ユーザ名:codecommit-pusher(任意)
アクセスの種類:プログラムによるアクセスにチェック
アタッチポリシー:AWSCodeCommitPowerUser
※ここでは権限広めですが、適切に絞ってくださいー

後は、デフォルト値で進めてユーザ作成まで実行

CodeCommitのSSHキーを作成

注)ここで発行するSSHキーは、CodeCommitブランチ作成、及びCircleCIのSSH Permissionsでも使用します

ローカル端末でSSHキーペアを作成します
(後述するCircleCIへの鍵アップロードではPEM形式にしか対応していないので -m pemを忘れずに!)

cd ~/.ssh/
ssh-keygen -t rsa -b 2048 -f codecommit-pusher-key -m pem
ls codecommit-pusher-key*
→ codecommit-pusher-key, codecommit-pusher-key.pubが存在することを確認

(鍵ファイル名を変えて、QA/Production用に別々に発行してください)

IAMユーザ画面の認証情報タブを開き、SSHパブリックキーのアップロードボタンをクリックし
codecommit-pusher-key.pubの内容を貼り付けてアップロードする
スクリーンショット 2019-10-23 15.16.19.png

表示されたSSHキーIDを控えておいてください

CodeCommitリポジトリ作成

  • AWSマネジメントコンソールからCodeCommit画面を開き、リポジトリを作成ボタンをクリック
  • リポジトリ名に sample-go を入力して 作成ボタンをクリック

developブランチを作成する

GitHubとCodeCommitでコミット履歴が同じ状態である必要があるので、git remoteにCodeCommitリポジトリを追加
する形でブランチを追加します。

# CodeCommitにgitでアクセスできるようにssh_config設定
IAM_SSH_KEY_ID={SSHキーIDを指定}
echo -e "Host git-codecommit.*.amazonaws.com\n  User ${IAM_SSH_KEY_ID}\n  StrictHostKeyChecking no\n  UserKnownHostsFile=/dev/null\n  IdentityFile ~/.ssh/codecommit-pusher-key" >> ${HOME}/.ssh/config

# githubからcloneしたsample-goローカルリポジトリへ移動
cd sample-go
# CodeCommitのリポジトリをremote追加
git remote add codecommit ssh://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/sample-go
# developブランチをPush
git checkout develop
git pull codecommit develop
git push codecommit develop
git remote remove codecommit

(Productionの場合はmasterブランチに読み替えてください)

CodeCommitにPushするためのCircleCI設定

.circleci/config.ymlを見るとわかりますが、今回QA/ProductionでAWSアカウントが別れている関係で
CircleCIからPushするCodeCommitは2アカウント分となるため、SSHキー&秘密鍵が2つ必要になります。
今回は、環境ごとにdeploy_qaとdeploy_prodの2つのジョブに分けて、IAM_SSH_KEY_ID_QA / IAM_SSH_KEY_IDという
環境変数で使用するSSHキーを使い分ける形にしました。

.circleci/config.ymlの該当箇所抜粋
  deploy_qa:
   〜略〜
    steps:
      - checkout
      - run:
          name: deploy for qa
          command: |
            echo -e "Host git-codecommit.*.amazonaws.com\n  User ${IAM_SSH_KEY_ID_QA}\n  StrictHostKeyChecking no\n  UserKnownHostsFile=/dev/null" >> ${HOME}/.ssh/config
            git push ssh://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/sample-go develop

  deploy_prod:
   〜略〜
    steps:
      - checkout
      - run:
          name: deploy for production
          command: |
            echo -e "Host git-codecommit.*.amazonaws.com\n  User ${IAM_SSH_KEY_ID}\n  StrictHostKeyChecking no\n  UserKnownHostsFile=/dev/null" >> ${HOME}/.ssh/config
            git push ssh://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/sample-go master

CircleCIの環境変数追加

Project Settings画面(https://circleci.com/gh/{GitHubアカウント名}/sample-go/edit) にアクセス
Environment Variablesをクリック
Add Variableボタンをクリック
IAM_SSH_KEY_ID/IAM_SSH_KEY_ID_QAという環境変数として、QA/Production環境で発行したSSHキーIDを追加します

スクリーンショット 2019-10-23 16.39.08.png

CircleCIのSSH鍵追加

Project Settings画面(https://circleci.com/gh/{GitHubアカウント名}/sample-go/edit) にアクセス
SSH Permissionsをクリック
Add SSH Keyボタンをクリック
Private Key欄に codecommit-pusher-keyの内容を貼り付けます(Hostnameは空欄でOK)
Add SSH Keyボタンをクリック

QA/Production環境用に発行した2つのキーを登録します

スクリーンショット 2019-10-23 17.24.44.png

コードパイプライン設定

コードパイプライン作成

AWSマネジメントコンソールからコードパイプライン画面を開き、パイプラインを作成するボタンをクリック

パイプラインの設定を選択する

パイプライン名を入力して、次にをクリック
ロール名は自動的に入力されます(手入力は不要です)
スクリーンショット 2019-10-23 14.13.54.png

ソースステージを追加する

ソースプロバイダーにAWS CodeCommitを選択
リポジトリ名にsample-goを指定し、ブランチ名にdevelopを指定して、次にをクリック

スクリーンショット 2019-10-23 15.35.26.png

ビルドステージを追加する

プロバイダー:AWS CodeBuild
リージョン:アジアパシフィック(東京)
を選択し、プロジェクトを作成する ボタンをクリック

ビルドプロジェクトを作成する

プロジェクト名:sample-go
環境イメージ:マネージド型イメージ
オペレーティングシステム:Ubuntu
ランタイム:Standard
イメージ:aws/codebuild/standard:2.0
特権付与:チェックOn
サービスロール:新しいサービスロール
ロール名:codebuild-sample-go-service-role
※あとで権限変更するため、ロール名を控えておくこと

<追加設定>を開いて環境変数として下記入力

名前 入力
AWS_DEFAULT_REGION ap-northeast-1 プレーンテキスト
AWS_ACCOUNT_ID 123456789012 プレーンテキスト

以降、Buildspec、ログ設定はデフォルトのまま CodePipelineに進むをクリック
ビルドステージを追加する画面に戻るので、次にボタンをクリック

スクリーンショット 2019-10-23 15.56.35.png
スクリーンショット 2019-10-23 15.57.13.png
この画像には、特権付与にチェック入っていませんが必要です m(_ _)m
スクリーンショット 2019-10-23 15.57.35.png
スクリーンショット 2019-10-23 15.57.55.png
スクリーンショット 2019-10-23 15.58.14.png

デプロイステージを追加する

デプロイプロバイダーにAmazon ECSを選択
リージョン:アジアパシフィック(東京)
クラスター名:sample-go
サービス名:sample-go
次にボタンをクリック

スクリーンショット 2019-10-23 16.10.39.png

確認画面が表示されるので、パイプラインを作成するボタンをクリック
パイプラインが作成されると、最初のパイプライン処理が実行されます。
まだ設定完了ではないのでエラーになりますが、気にせずに。

ECRアクセス権限付与

CodeBuildがビルドしたイメージをECRにPushするための権限を付与します。

IAMロール[codebuild-sample-go-service-role]に権限追加

※デフォルトでは、codebuild-{プロジェクト名}-service-roleというロール名になります
IAMコンソールで、上記ロールを開きます
アクセス権限タブを開きます
AmazonEC2ContainerRegistryPowerUserポリシーをアタッチします
※ここでは権限広めですが、適切に絞ってくださいー

スクリーンショット 2019-10-23 16.21.35.png

CI/CD動作確認

feature_hogeブランチをPushした際に、golangci-lintやgo testの結果がNGであれば、その旨GitHubのプルリク上
で表示されます。CircleCIのジョブ画面でエラー詳細が確認できます。
developブランチにMergeした時には、自動的にQA環境のECS(Fargate)のサービスが更新(デプロイ)されます。
また、手順省略しましたが、Production環境用の設定も行えば、masterにMergeした時に、自動的にProductionの
ECS(Fargate)のサービスが更新(デプロイ)されるようになります。

まとめ

ビルドが早い、マルチステージビルドでコンテナイメージがコンパクトにできる、ワンバイナリで動く、ということで
もともとGoとコンテナ実行の相性はいいですが、これにCI/CDができるとさらにデリバリスピードが上がるので最高ですねー。
さらに、サーバの存在を意識しなくてよいECS(Fargate)へのデプロイも、Code4兄弟が面倒をみてくれるので、
開発者だけでなく、SREにもメリットのあるかなりよい構成なので、今後もこの構成推しでいこうと思っています。

あと、今回は長々とコンソールを操作する手順を紹介しましたが、本来こういう設定はCloudFormationでテンプレートを
作って自動でセットアップするのがいいと思います(実際に、弊社でもテンプレート化してそれを使って構築しています)
ですが、コンソールで操作してみるとAWS/GitHub/CircleCIの連携部分の理解が進むので、一度やってみるのを
オススメします!

22
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
23