cloudpack大阪の佐々木です。
内部で開発しているGolangのWebアプリをECSで稼働させるように、CI環境をつくってみました。
パブリックのgithubとかであれば、CircleCIとかでもう少しいい感じにできるとおもうのですが、ローカルのGitリポジトリで開発しているため、パブリックアクセスできないCodeCommitを使う形にしました。
概要
動作イメージは下記のような感じです。
- CodeCommitにプッシュ
- CodePipelineでコミットを検知し、CodeBuildを起動
- CodeBuildでコンパイルし、実行ファイルをビルド、S3に保存
- S3に保存後、ECSのサービスの既存タスクを停止
- サービスが新しいタスクを起動
- 新しいコンテナがS3から実行ファイルをダウンロードし、実行
環境
アプリケーション
もとのアプリケーションのファイルは下記のような感じです。
. ├── app │ ├── model │ ├── util │ └── view ├── bindata.go ├── glide.yaml ├── server.go └── static └── js
リージョン
CodeCommitが東京リージョン未対応のため、すべてus-east-1
で作成します。
設定
CodeCommitリポジトリの作成
リポジトリの作成
リポジトリ名をgotestにします。
CodeCommitリポジトリにアクセスするユーザを作成
IAMでユーザを作成します。
AccessKeyを使ったHTTPSでのアクセスも可能ですが、SSH接続でやってみます。
ユーザを作成したら、認証情報のタブを開いて、AWS CodeCommitのSSHキー
の SSH 公開キーのアップロード
をクリックし、SSH公開鍵を貼り付けます。
アップロードすると、SSHキーID
が発行されます。
SSHのconfigに情報を追加します。
~/.ssh/config
Host git-codecommit.*.amazonaws.com User `SSH キー ID` IdentityFile ~/.ssh/秘密鍵
コードをpushしておきます。
$ git push origin master Counting objects: 41, done. Delta compression using up to 4 threads. Compressing objects: 100% (34/34), done. Writing objects: 100% (41/41), 73.27 KiB | 0 bytes/s, done. Total 41 (delta 3), reused 0 (delta 0) To ssh://git-codecommit.us-east-1.amazonaws.com/v1/repos/gotest * [new branch] master -> master
Buildしたファイル保存用のS3バケットを作成
保存用S3バケットを作成します。
CodeBuildプロジェクトを作成
下記のようなプロジェクトを作成します。
環境イメージはあらかじめ用意されているGolangのものを使用しました。
当初、自分でコンテナを作成し、ビルド+Dockerコンテナ作成+ECRにプッシュという感じでやりたかったのですが、独自コンテナでDocker on Docker はできない(下記参照)、DockerイメージにGolangをインストールするとビルドのたびに時間がかかりすぎるということで、独自コンテナはあきらめました。
https://forums.aws.amazon.com/thread.jspa?messageID=761184
ロールには自動で生成されるPolicyに、ECSのタスクをコントロールするためにAmazonEC2ContainerServiceFullAccess
を追加しています。
CodeBuild用のファイルを作成
下記の2つのファイルを作成します。
buildspec.yml
version: 0.1 phases: install: commands: - go get github.com/Masterminds/glide - go get -u github.com/jteeuwen/go-bindata/... build: commands: - ./build.sh post_build: commands: - aws s3 cp /go/src/git.local/sasaki/gotest/server s3://gotest-pkg/server - aws ecs stop-task --task `aws ecs list-tasks --cluster $ECS_CLUSTER_NAME --service-name $ECS_SERVICE_NAME --region $AWS_DEFAULT_REGION --query taskArns --output text` --cluster $ECS_CLUSTER_NAME --region $AWS_DEFAULT_REGION
build.sh
mkdir -p $GOPATH/src/git.local/sasaki/gotest cp -r app $GOPATH/src/git.local/sasaki/gotest cp -r static $GOPATH/src/git.local/sasaki/gotest cp server.go $GOPATH/src/git.local/sasaki/gotest cp bindata.go $GOPATH/src/git.local/sasaki/gotest cp glide.yaml $GOPATH/src/git.local/sasaki/gotest cd $GOPATH/src/git.local/sasaki/gotest glide up go-bindata app/view GOOS=linux GOARCH=amd64 go build server.go bindata.go
buildspec.yml
がCodeBuildの設定ファイルになります。
CodeBuildeでGolang用のコンテナを起動しますので、goコマンドは使える状態になっています。
まずinstallフェーズでgolangのglide
とgo-bindata
をインストールします。
次にbuildフェーズでbuild.sh
を実行します。
開発時はローカルにあるGitリポジトリを使っているので、glide up
でエラーになることを回避するために、ローカル環境と同じパスにソースをコピーしています。
そのあと、go build
でコンパイルしています。
post_buildフェーズでは、S3に実行ファイルをアップロードし、ECSの現在のタスクを停止しています。
artifactでもアップロードはできるのですが、post_buildのECSタスク停止後にアップロードされ、タスクに新しいファイルが反映されないため、このようにしています。
ECRにDockerイメージを作成
下記のDockerfileでDockerイメージを作成し、ECRにプッシュしておきます。
Dockerfile
FROM ubuntu:16.04 RUN apt-get -y update RUN apt-get install -y python-pip RUN yes | pip install --upgrade awscli RUN apt-get remove -y python-pip ADD start_gotest.sh / ENTRYPOINT ./start_gotest.sh
start_gotest.sh
aws s3 cp s3://gotest-pkg/server ./ chmod +x server ./server
UbuntuにS3でビルドしたファイルをダウンロードし、実行するだけです。
Alpineでやると、 ./server
がどういうわけか、not foundになるので、断念・・・
ECS設定
ECRに保存したイメージを常時稼働するように、タスク定義、サービスの設定します。
CodePipeline
CodePipelineを作成します。
ソースの場所
は作成したCodeCommitリポジトリを指定します。
ビルド
は作成したCodeBuildを指定します。
デプロイは
CodeDeploy等は使用しないので、デプロイなし
を選択します。
実行
作成したリポジトリに、buildspec.yml
と、build.sh
を追加し、プッシュすると、CodePipelineが反応し、ECSのタスクが再起動されるまで自動実行されます。
イケてないところ
- CodeBuildで使うコンテナが融通がきかない
- 独自コンテナではDocker on Dockerができないとか
- Docker + Go等 みたいなコンテナがないとか
- 本来はビルドプロセスでコンテナイメージつくってECRにプッシュするまでやりたい
- Artifactが使えてない
- そもそもあんまりよくわかってない・・・
- ECRに保存しているアプリケーションを動かすだけのコンテナのサイズがデカすぎ
- S3からダウンロードするためにubuntuにpipインストールして、aws-cliをpipインストールしただけで、こんなに・・・
ubuntu 16.04 117 MB gotest-image latest 462 MB
元記事はこちら
「GolangのWebアプリケーションをECSにデプロイするCI環境をCodeCommit、CodeBuild、CodePipelineでつくる【cloudpack大阪ブログ】」