CircleCI からECSへ自動デプロイ
三部作の最終回。
前回ほぼほぼECRの方の話しかしてない気がする。
大事な部分、コードペタッと貼っただけじゃねーか!と言われても仕方ない。
そして残念、たぶん今回も。。。
- CircleCI で docker build するまで
- CircleCI からECRへ自動push
- CircleCI からECSへ自動デプロイ ← イマココ
ECS準備
初めに断っておくのですが、AWSのチュートリアルを見ながら進めようと思っていたのですが
書いてあることがマジで分からなくなったので、その通りではありません。
認証のあるECRをIAMロールのを活用してタスク実行しようとか、
そういうのほんと……よく分かんない……学習コスト高くない……?
と言うわけで、
ちょっと強引だけど前回作ったCLIユーザーを利用する形にしました。
VPC
最初にサーバにネットワークのセキュリティ設定を進めて行きたいと思います。
この先webサーバを用意するのですが、
何も設定していないとそこまで到達しないので設定します。
AWSマネジメントコンソールからVPCを選択します。
VPCの利用に限っては料金が発生しないっぽいです。
VPCの作成をクリックして、各項目を埋めて作成です。
カラム | 設定値 |
---|---|
名前タグ | my-web-vpc 任意ではありますが自分が何のためのVPCか識別できるよう付けておくのが良いかと |
IPv4 CIDR ブロック | 192.168.0.0/16 利用するプライベートIPv4のアドレス空間 |
IPv6 CIDR ブロック | なし |
テナンシー | デフォルト |
サブネット
VPCができたら次はサブネットからサブネットの作成を行います。
すごくざっくり言うと、VPCで定義したアドレス空間を更に分ける感じのはず。
ここら辺のネットワーク周りはよりセキュリティを強固にしたり、
IP空間毎に役割を持たせたい時にじっくり設定しましょう。
単純な個人webサイト程度だとあまりここにコストをかけ過ぎるのも……って感じです。
なので、サブネットマスクも収まっていれば割と何でも良いかと。
/32とはか……そもそも設定できるのかな?
カラム | 設定値 |
---|---|
名前タグ | my-web-vpc |
VPC | 作ったVPC |
アベイラビリティーゾーン | 指定なし |
IPv4 CIDR ブロック | 192.168.0.0/20 |
セキュリティグループ
さて、ネットワークが出来たのでそこにアクセスコントロールしていきます。
たぶんセキュリティグループが自動的に作成されていると思います。
名前とか付けておくと今後も分かりやすくなると思います。
作成されたセキュリティグループを選択したら
インバウンドのルールってタブがあると思いますので、
そこでルールの編集をクリックします。
インバウンドというのは、
外からAWSの方に行くリクエストですね。
HTTPリクエストを受け付けるため、以下のルールを追加します。
カラム | 設定値 |
---|---|
タイプ | HTTP |
プロトコル | TCP |
ポート範囲 | 80 |
ソース | カスタム 0.0.0.0/0 |
説明 | http request |
今回はIPv4のHTTPのみなのでこれだけですが、
v6対応したら::/0
を追加したり、
HTTPS対応したら443で受け付けるルールを追加します。
これでネットワークとセキュリティは一旦お終いです。
クラスター作成
ECS自体の構成はそんなに言及しませんが、
クラスターがサービスを束ね、
サービスが個々のタスクを管理するといった感じでしょうか。
このクラスターもCLIから作成することもできるのですが、
一度作ればそれでいいのでわざわざCLIから作るってことはしません。
あまりそれが求められる場面も少ないと思います。
話を戻して、
AWSマネジメントコンソールからECSを選択し、
クラスターからクラスター作成します。
今回はEC2 を利用してみようと思います。
各設定値は以下の通り。
なるべく無料枠で収めちゃう戦略です。
カラム | 設定値 |
---|---|
クラスタテンプレート | EC2 Linux + ネットワーキング |
クラスター名 | 任意 hogehoge-cluster |
プロビジョニングモデル | オンデマンドインスタンス |
EC2 インスタンスタイプ | t2.micro 12ヶ月無料枠 |
インスタンス数 | 1 |
EC2 Ami Id | Amazon Linux 2 AMI |
EBS ストレージ | 30GB 12ヶ月無料枠 |
キーペア | なし |
VPC | 先ほど作成したVPC |
サブネット | 先ほど作成したVPCのサブネット |
セキュリティグループ | 先ほど作成したセキュリティグループ |
コンテナインスタンスの IAM ロール | ecsInstanceRole 無ければ自動生成される |
ポリシーのアタッチ
またポリシーですか?
またポリシーです。ごめんなさいね。
今回はECS側のポリシー設定です。
クラスターは既に作成しているので、
タスク定義やクラスターで動かすサービス作成などの権限を扱うポリシーをアタッチします。
前回は既存のポリシーをアタッチしたのですが、
今回は自分でポリシーを作ってみます。
AWSマネジメントコンソールからIAMを選択し、ポリシーの画面まで遷移します。
ポリシーの作成から、以下の内容でポリシーを作成します。
カラム | 設定値 |
---|---|
サービス | Elastic Container Service |
アクション | リスト - ListAccountSettings 読み込み - DescribeServices - CreateService - UpdateService - RegisterTaskDefinition |
リソース | すべてのリソース |
リクエスト条件 | なし |
名前 | my-ecs-policy 任意です |
説明 | 任意 |
次にグループから前回作成したグループを選択し、
アクセス許可のタブから今作ったポリシーをアタッチします。
Elastic IPの設定
最後に固定IPアドレスを取得します。
EC2インスタンスとか立て直しをするとIPアドレスが変わってしまうので、
EC2と固定IPアドレスの紐付けを行います。
Elastic IPの取得自体はVPCダッシュボードのElastic IP、
新しいアドレスの割り当てから取得出来ます。
Elastic IPはインスタンスに紐付いていないとお金が掛かるそうです。
取得したIPを選択して、アクション→アドレスの関連付けから行います。
インスタンスを選択すると自動で他の項目を埋めてくれると思います。
再関連付けもとりあえずチェックしておいて良いと思います。
これでAWS側の設定が終わりました。
長かった……。
CircleCIからpush
たぶん本題となるはずのcircleciです。。。
まず前回同様環境変数の追加を行います。
今回追加するのはクラスター名です。
それ以外の必要な変数は前回セットしています。
環境変数名 | 概要 |
---|---|
ECS_CLUSTER | 作成したクラスター名 |
そして定義したジョブがこちらになります。
.circleci/config.yml
version: 2 jobs: # ~~ 略 ~~ deploy: docker: - image: circleci/node:12-stretch steps: - checkout - setup_remote_docker - run: name: Setup Enviroment command: echo 'export DOCKER_IMAGE=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${AWS_RESOURCE_NAME_PREFIX}:latest' >> $BASH_ENV - run: name: Install ecs-cli command: | sudo curl -o /usr/local/bin/ecs-cli https://amazon-ecs-cli.s3.amazonaws.com/ecs-cli-linux-amd64-latest sudo chmod +x /usr/local/bin/ecs-cli - run: name: Setup ecs-cli command: | ecs-cli configure --cluster ${ECS_CLUSTER} --default-launch-type EC2 --region ${AWS_DEFAULT_REGION} --config-name ecs-config # 初回はService定義がないため、Stop Serviceをコメントアウトする必要がある。。。 - run: name: Stop Service command: | ecs-cli compose \ --file .circleci/composition.yml \ --project-name mu-web \ --ecs-params .circleci/ecs-params.yml \ --cluster-config ecs-config \ service stop - run: name: Start Service command: | ecs-cli compose \ --file .circleci/composition.yml \ --project-name mu-web \ --ecs-params .circleci/ecs-params.yml \ --cluster-config ecs-config \ service up workflows: version: 2 pipeline: jobs: - build - push: requires: - build filters: branches: only: master - deploy: requires: - push filters: branches: only: master
.circleci/composition.yml
version: "3" services: mu-web-service: image: ${DOCKER_IMAGE} ports: - "80:80"
.circleci/ecs-params.yml
version: 1 task_definition: services: mu-web-service: mem_limit: 524288000 # 500MB mem_reservation: 262144000 # 250MB
ちょっと長いですが順々にステップを見ていきます。
最初はcircleciのいつものみたいな感じなので飛ばして、
まずは本筋とは離れるんですが環境変数DOCKER_IMAGE
を用意してます。
別に用意しなくても良かったんですが、
後に参照する際に${DOCKER_IMAGE}
って書きたかったのでセットしてます。
また$BASH_ENV
に上書きすることで
後続のステップでもこの環境変数が参照できるようになります。
しないと、このステップだけ使える変数になってしまいます。
次は見たまんまCLIのインストール。
AWSのドキュメント通りに入れます。
インストールの後はCLIの設定の作成です。
使用するリージョンやクラスターを指定しています。
そして作った設定は後で使用するため、
--config-name
オプションで名前を付けています。
サービスが既に起動していたら、
既にポートが使われている状態になっていて更新出来ません。
そのためサービスの停止を入れています。
オプションは公式にあるんですが、
--project-name
はこの場合だと.circleciになっていて
familyが違うと怒られたので直接ディレクトリ名を指定しています。
他にも--file
でDocker構成ファイルを指定したり、
--ecs-params
でDocker構成ファイルでは足りないECSのパラメータを指定してあげたりしています。
そして先ほど用意した設定名を渡しています。
ただ、コメントにも書いたとおり
初回はサービスが存在しないのでstopコマンドはそんなサービス無いよって行って失敗します。
なのでもっとしっかりやるなら、
シェルスクリプトを用意してそこで終了ステータスに応じてstopを走らせるかどうか場合分けする感じでしょうか。
最後にサービスを起動のコマンドを流します。
service up
はcreate
とstart
の複合です。
こちらにも各オプションでファイルやパラメータ、設定を渡しています。
Docker構成ファイルはまんまdocker-compose.ymlだと思います。
そしてそこで環境変数が参照できるんで、
初めに用意した{DOCKER_IMAGE}
を入れてみています。
ECSパラメータのファイルでは、
ECSで利用するタスク定義になっています。
設定しているのはハード/ソフトメモリ制限程度です。
IAMロールとかも設定できるんですが、
今回CLIユーザーにやらせているのでタスク実行ロールはなしです。
さて、初回にサービス停止失敗するという残念な点がありますが
これで自動pushできるようになりました。
長かった。
もっとこうしたほうが良いんじゃない?とかありましたら、
滅茶苦茶気軽にご教示頂けると幸いでっす!