クソ雑魚エンジニアのメモ帳

学んだことを書くところ

GitlabのCIでnpm+docker+git+awscliの実行環境構築

追記

ecs_deploy.shの実行権限がなかったので、chmod 777 ./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回まで無料のようである。太っ腹。

GitLab.com settings | GitLab

さらにさらに、どうやらimageを指定して、その中で動作するらしい。Dockerは新世界の神ではないか。 細かいCIの設定は.gitlab-ci.ymlに以下のようなフォーマットでかく。以下は最小構成である、

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_IDAWS_SECRET_ACCESS_KEY環境変数に登録する。.gitlab-ci.ymlに書くと、gitに追跡されてしまうので、ここはgitlabの設定であらかじめ登録しておくこと

f:id:Kouchannel55:20180515005519p:plain

ここまでで.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リポジトリに、新たにプッシュする必要がある。

ぐぐるとよく出てくる方法はめっちゃ長かった。

  1. 古いdockerをアンインストール
  2. 周辺パッケージをインストール
  3. GPG鍵の取得
  4. .......以降省略

ダメ元でdocker公式読んだら、もっと簡単な方法があった。やはり公式が正義

docs.docker.com

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を更新

最後にして最難関。愚直にやろうと思うと以下の手順でやる必要がある

  1. タスク定義を先ほどプッシュしたイメージを含んで更新(リビジョン)
  2. クラスター内のサービスを更新

非常にめんどくさい。CodePipelineならGUIでサクッとできたのでこちらは地獄のように感じる

以下のスクリプトを使わせてもらった。

github.com

ecs_deploy.shとしてファイルを作成し、以下で実行。

sh ./ci/ecs_deploy.sh -r $REGION -c $CLUSTER -n $SERVICE -i $TAG_NAME -t 1800

これだけで12も自動でやってくれる。幸せ。

しかし、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のドキュメント、日本語対応してくれんかなあ