追記
ecs_deploy.sh
の実行権限がなかったので、chmod 500 ./ci/ecs_deploy.sh
を追記しました
背景
趣味のwebアプリ開発環境を一通り整えたが、最後のCIの部分を全く実装していかなった
GitHubを使っていたらCodePipelineを使って楽々ECSにデプロイできたのだが、今回はGitlabで作成してしまった
そしてGitHubに移す気力はない
対象読者
- ECS/ECRでの継続デプロイを理解している人
目的
理想は、masterにプッシュしたら、自動でgitlab runnerが走って自動でecrを更新しecsのサービスも更新してほしい(贅沢)
今回の僕のweb環境は以下のようになっています。
RESTfulなので、フロントエンドとAPIサイドに分かれています。
├── Dockerfile
├── README.md
├── docker-compose.yml
├── front <=フロントエンド側の開発ディレクトリ
├── nginx.conf
└── phalcon <= webアプリケーションのディレクトリ
├── (略)
├── public <= nginxのrootディレクトリ
これを踏まえて、CIサーバーでやらせたいことを掘り下げると、、、
-
docker
コマンドで、ビルドしたイメージをECRにプッシュしたい -
aws
コマンドで、ECSの操作を行いたい - frontディレクトリ内で、webpackのビルドを行い、その出力ファイル(index.htmlとその他staticファイル)をphalcon(webアプリケーション)ディレクトリ内の
public
ディレクトリ内にブッコミたい
これを実現するには、以下の課題をクリアする必要がある
- npmのインストール
- dockerのインストール
- awsコマンドのインストール
調査
gitlabCIについて一つ勘違いしていた。てっきりprivateなサーバーでのみ動かすことしかできないと思っていたが、どうやらGitlabが用意しているCIサーバーも制限があるが存在しているようである。自前サーバーで動かすのをSpecific Runners
というのに対しShared Runners
というらしい。1ヶ月1グループあたり2000回まで無料のようである。太っ腹。参考元
さらにさらに、どうやらimageを指定して、その中で動作するらしい。Dockerは新世界の神ではないか。
細かいCIの設定は.gitlab-ci.yml
に以下のようなフォーマットでかく。以下は最小構成である、
script
以下に、複数のコマンドを書くことができる。また、stageは複数定義可能であるが、コンテナの状態が引き継がれないので、基本的に1stageで行なっている
image: python:2.7
stages:
- deploy
deploy_job:
stage: deploy
script:
- XXXXXXXXXXXX
awsコマンド
先ほどの、npm,docker,awsの中でインストールがめんどくさそうなのはaws
という直感を元にpython:2.7
イメージを使用。デフォルトでawsコマンドが使えるので。python:2.7はDebianのjessieがベースになっているとのこと。
ここで、みんな大好きAWS_ACCESS_KEY_ID
とAWS_SECRET_ACCESS_KEY
を環境変数に登録する。.gitlab-ci.yml
に書くと、gitに追跡されてしまうので、ここはgitlabの設定であらかじめ登録しておくこと

ここまでで.gitlab-ci.yml
は以下のようになった
image: python:2.7
stages:
- deploy
deploy_job:
stage: deploy
script:
- pip install --upgrade pip
- pip install --upgrade awscli
npm
フロントエンドには、vue
を使っているが、webpackでビルドする必要がある。
無論python:2.7
に入っていないので自力で導入。
以下を、install_npm.shとして作成
curl -sL https://deb.nodesource.com/setup_10.x | bash -
apt-get install -y nodejs
これを踏まえて、gitlab-ci.yml
は以下のようになる
image: python:2.7
stages:
- deploy
deploy_job:
stage: deploy
script:
- pip install --upgrade pip
- pip install --upgrade awscli
- sh ./ci/install_npm.sh
- cd ./front
- npm install
- npm run build
docker
ECSで動かすタスクで動くDockerイメージを更新するには、ECSというdockerリポジトリに、新たにプッシュする必要がある。
ぐぐるとよく出てくる方法はめっちゃ長かった。
- 古いdockerをアンインストール
- 周辺パッケージをインストール
- GPG鍵の取得
- .......以降省略
ダメ元でdocker公式読んだら、もっと簡単な方法があった。やはり公式が正義
curl -fsSL get.docker.com -o get-docker.sh
sh get-docker.sh
これだけでいいとのこと。あっさり。
しかし、これだけでは、プロセスが停止したままなので、service docker start
を加えて以下が最終形。install_docker.sh
としてファイル作成
curl -fsSL get.docker.com -o get-docker.sh
sh get-docker.sh
service docker start
これでdockerがすぐに動かせる状況になった
ECRにプッシュ
プッシュするタグ名は、複数箇所で使用するので、以下のように環境変数として定義。これはシークレットレベルは低いので、.gitlab-ci.yml
に定義
deploy_job:
stage: deploy
variables:
TAG_NAME: XXXXXXXXXXXX
script:
(略)
- aws_var=`aws ecr get-login --no-include-email --region ap-northeast-1 `
- $aws_var
- docker build -t kyujin .
- docker tag kyujin:latest $TAG_NAME
- docker push $TAG_NAME
ECSを更新
最後にして最難関。愚直にやろうと思うと以下の手順でやる必要がある
- タスク定義を先ほどプッシュしたイメージを含んで更新(リビジョン)
- クラスター内のサービスを更新
非常にめんどくさい。CodePipelineならGUIでサクッとできたのでこちらは地獄のように感じる
以下のスクリプトを使わせてもらった。
ecs_deploy.sh
としてファイルを作成し、以下で実行。
sh ./ci/ecs_deploy.sh -r $REGION -c $CLUSTER -n $SERVICE -i $TAG_NAME -t 1800
これだけで1
も2
も自動でやってくれる。幸せ。
しかし、shでやってると怒られた
./ci/ecs_deploy.sh: Syntax error: "(" unexpected
どうやら、Debian
でshをすると、dash
が起動する影響らしい。微修正
./ci/ecs_deploy.sh -r $REGION -c $CLUSTER -n $SERVICE -i $TAG_NAME -t 1800
jsonのパーサーのjq
も必要なのでサクッとインストール
apt-get install jq
結論
最終形は以下のようになった。めでたしめでたし。
image: python:2.7
stages:
- deploy
deploy_job:
stage: deploy
variables:
TAG_NAME: XXXXXXXXX
REGION: YYYYYYYY
CLUSTER: ZZZZZZZZZZZZZZZZ
SERVICE: WWWWWWWWWWWWW
script:
- pip install --upgrade pip
- pip install --upgrade awscli
- sh ./ci/install_docker.sh
- sh ./ci/install_npm.sh
- cd ./front
- npm install
- npm run build
- cd ./../
- apt-get install jq
- aws_var=`aws ecr get-login --no-include-email --region ap-northeast-1 `
- $aws_var
- docker build -t kyujin .
- docker tag kyujin:latest $TAG_NAME
- docker push $TAG_NAME
- chmod 777 ./ci/ecs_deploy.sh
- ./ci/ecs_deploy.sh -r $REGION -c $CLUSTER -n $SERVICE -i $TAG_NAME -t 1800
所管
- 日曜の午前3時には、masterプッシュして30秒後にはCIが走ってたが、月曜の今現在、masterプッシュして30分経っても走らずにPending状態。。。。やっぱり共有している以上、しかたないのか。。、。
- 趣味でやるぶんにはCI用意してくれるだけで御の字
- gitlabのドキュメント、日本語対応してくれんかなあ