--- title: AWS CI/CD勉強メモ①:ECR/ECS Dockerコンテナ起動 tags: ECR ECS cloud9 Docker CICD author: suo-takefumi slide: false --- ## やること Cloud9でDockerイメージをビルドして ECRにDockerイメージをpushして ECSでDockerコンテナを起動する ## 参考リンク - [AWS Cloud9環境でdocker-composeをできるようにする](https://qiita.com/okenak/items/51d2fc2e6a4b8adace2a) - [今から追いつくDocker講座!AWS ECSとFargateで目指せコンテナマスター!](https://www.youtube.com/watch?v=DS5HBTMG1RI&list=PLtpYHR4V8Mg-jbuk4yoXhXwJtreodnvzg) - [Capacity Providerとは?ECSの次世代スケーリング戦略を解説する](https://dev.classmethod.jp/articles/regrwoth-capacity-provider/) ## 構成 今回つくる環境 ![構成図](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/3ae6375c-d3b7-b3d3-55a3-18f90286be04.png) - ECSは、クラスターをEC2(linux)で構成 - クラスターを構成するEC2はCloud9と同じVPCに配置 - クラスターを構成するEC2とCloud9は通信可 各IAMロールの概要 |No|Name|概要| |---|---|---| | IAM-1 | ecsrole | Cloud9からECS,ECRにアクセス | | IAM-2 | ー | ← これ無いわ、間違えた | | IAM-3 | ー | クラスターとしてEC2が機能するためのアクセス権
今回はクラスター作成時に自動生成する | | IAM-4 | ecsTaskExecutionRole | Dockerコンテナのアクセス権
RDS接続許可、みたいな権限 | ![line.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/06917eca-093b-ea99-5681-5423b5bd8387.png) - 用語説明 - ECR(Amazon Elastic Container Registry) - Dockerコンテナレジストリ - Dockerイメージの保存と取得 - マネージドサービス - ECS(Amazon Elastic Container Service) - コンテナオーケストレーションサービス - マネージドサービス - クラスターをFargateで構成するとクラスター部分の管理もAWSお任せにできる やっていきます ## 1.Dockerイメージを作成する ECSで起動するDockerコンテナのため、Dockerイメージを作成 ![図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/ce417f8d-dc46-9cbc-32b3-822b95223921.png) #### 1-1.準備(環境構築) cloud9の作成の詳細は省略(デフォルトVPCに作成するだけ)。 cloud9には、Dockerがインストールされている。 ec2-user をdockerグループに配属させる。 ```bash:Cloud9-Terminal $ sudo usermod -a -G docker ec2-user ``` Docker Composeをインストールする。 ```bash:Cloud9-Terminal $ sudo curl -L "https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose $ sudo chmod +x /usr/local/bin/docker-compose ``` IAMロール作成し、Cloud9 のEC2インスタンスにアタッチする。 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/5469de4a-ef4a-b3a1-dc39-2fe50b6acd8b.png) IAMロール名 `ecsrole` (図の`IAM-1`)に適用したポリシー - `AmazonEC2ContainerRegistryFullAccess` - `AmazonECS_FullAccess` #### 1-2.Dockerイメージをビルドする cloud9上でDockerイメージをビルドする。ビルドイメージ名 `volumedemo` ```bash:Cloud9-Terminal $ mkdir docker $ mkdir docker/volumes $ touch docker/volumes/Dockerfile $ nano docker/volumes/Dockerfile # -> 編集内容は後に記載してある $ touch docker/volumes/index.html $ nano docker/volumes/index.html # -> 編集内容は後に記載してある ``` ```dockerfile:Dockerfile FROM centos:latest RUN yum install -y httpd COPY ./index.html /var/www/html/index.html VOLUME /var/www/html EXPOSE 80 443 CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"] ``` ```html:index.html test

TEST

``` ビルドする ```bash:Cloud9-Terminal $ cd docker/volumes $ docker build -t volumedemo ./ # -> Successfully tagged volumedemo:latest となれば成功 ``` ビルドが成功し、Dockerイメージがつくれたか確認 ```bash:Cloud9-Terminal docker images # -> REPOSITORY名 `centos`, `volumedemo` の2つが追加されてれば成功 ``` Dockerコンテナを起動 ```bash:cloud9-Terminal $ docker run --name volumedemo -d -p 8080:80 volumedemo:latest $ docker container ls # -> NAMES `volumedemo` の STATUS が `UP xxx` となれば成功 ``` Webが開くか動作確認 ```bash:Cloud9-Terminal $ curl http://localhost:8080/index.html # -> `test

TEST

`と出力されたら成功 ``` #### 1-3.ホスト側からDockerコンテナ内のファイル(html)を更新する Dockerコンテナのマウントボリュームを確認 ```bash:Cloud9-Terminal $ docker inspect {CONTAINER ID} # -> 出力結果から Mounts の情報を確認 ``` `Mounts` の `Source` がホストのパス ```json "Mounts": [ { "Type": "volume", "Name": "951214538382d48c336a02bcd34d5d61e2cb88654587ec45f14996a2cda43024", "Source": "/var/lib/docker/volumes/a02b1214538382d48c336c45fcd34d5d61e2cb88654587e9514996a2cda43024/_data", "Destination": "/var/www/html", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ``` ホスト側からindex.htmlを編集し、Webサイトが更新されたことを確認 ```bash:Cloud9-Terminal sudo nano /var/lib/docker/volumes/a02b1214538382d48c336c45fcd34d5d61e2cb88654587e9514996a2cda43024/_data/index.html ``` ``` [更新前] test

TEST

[更新後] test

TEST123456789

``` ↑の手法はパス探し面倒(Cloud9はアクセス権も絡み更に面倒) なのでホスト側の格納パスを指定してバインドマウントする ```bash:Cloud9-Terminal $ mkdir /home/ec2-user/environment/docker/bindmount $ touch /home/ec2-user/environment/docker/bindmount/index.html $ nano /home/ec2-user/environment/docker/bindmount/index.html # 中身 test

TEST-ABCDEFG

$ docker container run --name bindmount1 -d -p 80:80 -v /home/ec2-user/environment/docker/bindmount:/var/www/html volumedemo:latest ``` 動作確認 Webサイトにアクセスして `test

TEST-ABCDEFG

` となれば成功 次にホスト側で /home/ec2-user/environment/docker/bindmount/index.html を編集し、Webサイトにアクセスして更新されてたら成功 ## 2.DockerイメージをECRにpushする 作成したDockerイメージにECRの規則に沿ったタグを付与しECRにpushする ![2.DockerイメージをECRにpush](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/4bde8c2d-61a5-30c7-77a4-7dd721a58227.png) ECRでリポジトリを作成する ( リポジトリ名前 `blackriverrepo` ) 他の設定はデフォルト値を使用 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/e91db936-3ff7-7f61-29d7-db26e65ecee1.png) Cloud9からECSにアクセス ```bash:Cloud9-Terminal $ aws ecr get-login --no-include-email --region ap-northeast-1 # -> Dockerログインコマンドでてくる(長くてビビる) ``` 取得したDockerログインコマンドをCloud9上のターミナルで実行し、`login Succeeded` と表示でれば成功。 ECRで作成したリポジトリ `blackriverrepo` を選択し、`プッシュコマンドの通知` ボタンをクリックすると、基本コマンドでてくる ※ 手順1,2は実施済み ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/4b74d3af-2d16-b678-8191-289c3a983811.png) ECS上のリポジトリにイメージをプッシュするために、Dockerイメージにタグを付ける ```bash:Cloud9-Terminal $ docker tag volumedemo:latest xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/blackriverrepo:latest # タグが付いたか確認 $ docker image ls ``` ECRで作成したリポジトリ `blackriverrepo` にDockerイメージをpushする ```bash:Cloud9-Terminal $ docker push xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/blackriverrepo:latest ``` ECR のリポジトリを確認し、イメージURI `xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/blackriverrepo:latest` があれば成功 ```bash:Cloud9-Terminal # ECR のリポジトリはコマンドでも確認できる $ aws ecr describe-repositories --region ap-northeast-1 # コマンドでリポジトリの内容確認もできる $ aws ecr describe-repositories --region ap-northeast-1 --repository-name blackriverrepo ``` AWSコンソールで確認するとこんな感じ ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/45c53963-7d2a-5f1e-de15-35f47d7c2975.png) (おまけ)ECRからCloud9にDockerイメージをpullできるか確認 ```bash:Cloud9-Terminal # Cloud9からのDockerイメージを消す $ docker rmi xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/blackriverrepo # Cloud9でpullしてECRからDcokerイメージ取得 $ docker pull xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/blackriverrepo # -> キャッシュに残ってる場合はすぐ取得できる # -> docker images で xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/blackriverrepo があれば成功 ``` ```bash:Cloud9-Terminal # pullしたイメージでDockerコンテナ起動してみる # コンテナ起動 $ docker run --name blackriver -d -p 8080:80 xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/blackriverrepo:latest # コンテナ確認 $ docker ps -ls # Webサイト確認 $ curl http://localhost:8080/index.html ``` ## 3.クラスターを作成する ECSにクラスターを作成。今回はFargate使わずEC2(linux)にする ![3.クラスターを作成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/e7ff1a57-52e3-6dc3-f4d4-20038ddcdd9b.png) ECSでクラスターを作成する(今回は EC2(linux) で作る) ※cloud9と同じVPCにする - クラスターの構成 - クラスター名:cluster01 - プロビジョニングモデル:オンデマンドインスタンス - EC2インスタンスタイプ:t2.small - インスタンス数:2 - EC2 Ami Id:Amazon Linux 2 AMI - EBSストレージ:22 - キーペア:{既存のキーペア指定} <- コンテナに入るなら設定しておく - VPCはcloud9と同じデフォルトVPC - セキュリティグループ:`新しいセキュリティグループ` - コンテナインスタンスIAMロール:`新しいロールの作成` - Tags:`Name`, `ECSInstance01` 設定時の画面 *クリックで拡大 作成がはじまる ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/5c387d34-a037-6eee-31a9-998c1a0ecb57.png) ECSインスタンスが2つ`ACTIVE`になると成功 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/1ff25e40-b31d-215d-f167-439469d04a7e.png) ## 4.(オプション)キャパシティープロバイダーを設定する キャパシティープロバイダーは設定しなくてもDockerコンテナを起動できる なので、この章(4章) はやらなくてもよい。(←これに気が付かず苦労した) ![キャパシティープロバイダー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/f31d2f20-16b8-db4d-1bbf-281a4e3469db.png) キャパシティープロバイダーとは、ECSに作ったクラスターに対する設定 前提として、ECSに紐づくAutoScalling側でスケールイン保護が必要 #### 4-1.AutoScalling `スケールインから保護` ECSに紐づくAutoScallingを編集 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/3f1623a8-7c2d-5df9-0f1f-683ffc46cde2.png) インスタンス保護を設定 キャパシティの最小値は `0` になっているが 1 以上にすることをオススメ `0`だと、EC2インスタンスが0になる可能性がある EC2インスタンスが0の状態で、ECSでタスク実行すると『キャパシティーが無い』旨のメッセージがでる ※本記事のトラブルシュート参照 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/29f1620e-b78d-c4d7-1bcf-2c4b6512dc52.png) #### 4-2.AutoScalling `スケールイン保護の設定` 所属するEC2インスタンスを選択し、`スケールイン保護の設定`を設定する ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/45318093-7b00-2372-95d9-a9ba43523911.png) #### 4-3.ECS のクラスター `clustre01` にキャパシティー作成 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/b4f709ee-5438-8c90-402f-c9f32931649d.png) ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/2c8df0fe-663c-f9ee-1d39-ff59591ca5a6.png) ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/5123735c-c161-df75-7c32-6079f334dfe2.png) ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/499cfdeb-4a01-1e17-e71a-79ca1cec1007.png) ## 5.タスク定義を作成->実行する タスク定義を作り実行すれば、Dockerコンテナが起動する。 - タスク定義とは?を粗く理解 - json形式 - コンテナ起動の設計書 ![5.タスク定義を作成->実行](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/d2445209-5e04-9997-e2e1-baed823d162e.png) #### 5-1.タスク定義を作成 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/9ee86f66-a983-a9b5-210a-8b9e67dafc79.png) 起動タイプ EC2 を選択 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/33484b1e-0e54-fcd2-70fd-2a3af49ad5f3.png) ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/0e394e07-e69a-4c9c-da1f-7887bf5c15ea.png) ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/5fd51c06-ca44-a291-5e3c-9088a82a9e98.png) コンテナ追加 `コンテナ名`, `リポジトリのURI`, `ポートマッピング` を設定 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/66a0ee30-0791-f7a2-451c-afdc71f7b39e.png) こんな感じで登録される ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/22c28a95-2b78-67fd-2028-627315879183.png) 作成する ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/b48117f8-822d-40fb-2fff-ade1e1482d41.png) #### 5-2.タスク定義を実行 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/223df212-117d-3b3b-6729-0a2cf0385ab4.png) `4.(オプション)キャパシティープロバイダーを設定する`を実施していない場合は、このような画面になる。赤枠のメッセージは、`4`を実施していないため、その下の`起動タイプへ切り替える`をクリックし、(今回であれば)EC2を選択すればよい。 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/0976b59a-a3de-0353-1ad0-f1354e2f94cf.png) ※おまけ※ `4.(オプション)キャパシティープロバイダーを設定する`を実施した場合は、このように赤枠のメッセージが出ない。 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/ea448c55-ea83-2ac3-3d8e-f8ca6f1b1e63.png) #### 5-3.動作確認 Webサイトが開けば成功。 ※ Cloud9(Webサイトにアクセスする環境)とクラスターに所属するEC2インスタンスが通信できるようSG(セキュリティグループ)を設定する。 ![動作確認](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/e71c1921-ac13-087c-bdd6-707ac09e398d.png) Dockerコンテナが起動しているEC2インスタンスのローカルIPを確認するとアクセスするURLがわかる。 ```bash:Cloud9-Terminal $ curl http://{Dockerコンテナが起動しているEC2インスタンスのローカルIP}/index.html # -> 以下のような結果になれば成功 # test

TEST

``` 今回はこれでおわり ![line.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/06917eca-093b-ea99-5681-5423b5bd8387.png) ## トラブルシュート タスク実行したときにキャパシティープロバイダー戦略のエラー発生 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/c2bfada4-7b9b-a6e3-dc02-353573d8d028.png) ↓赤枠のメッセージ↓ >キャパシティープロバイダー戦略 クラスターのデフォルト戦略 指定されたクラスターのデフォルトのキャパシティープロバイダー戦略にキャパシティープロバイダーが含まれていません。デフォルトのキャパシティープロバイダー戦略を更新して、1 つ以上のキャパシティープロバイダーを関連付けてから、もう一度お試しください。 - <考えられる原因> - (1) ECSに作成したクラスターにキャパシティープロバイダーの設定がない - (2) キャパシティープロバイダーに設定したAuto Scalling に`スケールイン保護の設定`されたEC2インスタンスがない - <考えられる対策> - (1)の対策案-1:本記事【4.(オプション)キャパシティープロバイダーを設定する】を実施しキャパシティープロバイダーを設定する - (1)の対策案-2:`キャパシティープロバイダー`を使わない。`起動タイプへ切り替える`をクリックする。本記事【5-2.タスク定義を実行】参照 - (2)の対策案:本記事【4-1.AutoScalling スケールインから保護】を参照し、Auto Scalling に最低1つ`スケールイン保護の設定`されたEC2インスタンスが含まれるようにする。