Help us understand the problem. What is going on with this article?

AWS CI/CD勉強メモ①:ECR/ECS Dockerコンテナ起動

やること

Cloud9でDockerイメージをビルドして
ECRにDockerイメージをpushして
ECSでDockerコンテナを起動する

参考リンク

構成

今回つくる環境

構成図

  • 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

  • 用語説明
  • ECR(Amazon Elastic Container Registry)
    • Dockerコンテナレジストリ
    • Dockerイメージの保存と取得
    • マネージドサービス
  • ECS(Amazon Elastic Container Service)
    • コンテナオーケストレーションサービス
    • マネージドサービス
    • クラスターをFargateで構成するとクラスター部分の管理もAWSお任せにできる

やっていきます

1.Dockerイメージを作成する

ECSで起動するDockerコンテナのため、Dockerイメージを作成

図2.png

1-1.準備(環境構築)

cloud9の作成の詳細は省略(デフォルトVPCに作成するだけ)。
cloud9には、Dockerがインストールされている。
ec2-user をdockerグループに配属させる。

Cloud9-Terminal
$ sudo usermod -a -G docker ec2-user

Docker Composeをインストールする。

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

IAMロール名 ecsrole (図のIAM-1)に適用したポリシー

  • AmazonEC2ContainerRegistryFullAccess
  • AmazonECS_FullAccess

1-2.Dockerイメージをビルドする

cloud9上でDockerイメージをビルドする。ビルドイメージ名 volumedemo

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
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"]
index.html
<html><head><title>test</title></head><body><h1>TEST</h1></body></html>

ビルドする

Cloud9-Terminal
$ cd docker/volumes
$ docker build -t volumedemo ./
# -> Successfully tagged volumedemo:latest となれば成功

ビルドが成功し、Dockerイメージがつくれたか確認

Cloud9-Terminal
docker images
# -> REPOSITORY名 `centos`, `volumedemo` の2つが追加されてれば成功

Dockerコンテナを起動

cloud9-Terminal
$ docker run --name volumedemo -d -p 8080:80 volumedemo:latest
$ docker container ls
# -> NAMES `volumedemo` の STATUS が `UP xxx` となれば成功

Webが開くか動作確認

Cloud9-Terminal
$ curl http://localhost:8080/index.html
# -> `<html><head><title>test</title></head><body><h1>TEST</h1></body></html>`と出力されたら成功

1-3.ホスト側からDockerコンテナ内のファイル(html)を更新する

Dockerコンテナのマウントボリュームを確認

Cloud9-Terminal
$ docker inspect {CONTAINER ID}
# -> 出力結果から Mounts の情報を確認

MountsSource がホストのパス

"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サイトが更新されたことを確認

Cloud9-Terminal
sudo nano /var/lib/docker/volumes/a02b1214538382d48c336c45fcd34d5d61e2cb88654587e9514996a2cda43024/_data/index.html
[更新前] <html><head><title>test</title></head><body><h1>TEST</h1></body></html>
[更新後] <html><head><title>test</title></head><body><h1>TEST123456789</h1></body></html>

↑の手法はパス探し面倒(Cloud9はアクセス権も絡み更に面倒)
なのでホスト側の格納パスを指定してバインドマウントする

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
#  中身 <html><head><title>test</title></head><body><h1>TEST-ABCDEFG</h1></body></html>
$ docker container run --name bindmount1 -d -p 80:80 -v /home/ec2-user/environment/docker/bindmount:/var/www/html volumedemo:latest

動作確認

Webサイトにアクセスして <html><head><title>test</title></head><body><h1>TEST-ABCDEFG</h1></body></html> となれば成功

次にホスト側で /home/ec2-user/environment/docker/bindmount/index.html を編集し、Webサイトにアクセスして更新されてたら成功

2.DockerイメージをECRにpushする

作成したDockerイメージにECRの規則に沿ったタグを付与しECRにpushする

2.DockerイメージをECRにpush

ECRでリポジトリを作成する ( リポジトリ名前 blackriverrepo ) 他の設定はデフォルト値を使用

image.png

Cloud9からECSにアクセス

Cloud9-Terminal
$ aws ecr get-login --no-include-email --region ap-northeast-1
# -> Dockerログインコマンドでてくる(長くてビビる)

取得したDockerログインコマンドをCloud9上のターミナルで実行し、login Succeeded と表示でれば成功。

ECRで作成したリポジトリ blackriverrepo を選択し、プッシュコマンドの通知 ボタンをクリックすると、基本コマンドでてくる ※ 手順1,2は実施済み

image.png

ECS上のリポジトリにイメージをプッシュするために、Dockerイメージにタグを付ける

Cloud9-Terminal
$ docker tag volumedemo:latest xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/blackriverrepo:latest
# タグが付いたか確認
$ docker image ls

ECRで作成したリポジトリ blackriverrepo にDockerイメージをpushする

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 があれば成功

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

(おまけ)ECRからCloud9にDockerイメージをpullできるか確認

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 があれば成功
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.クラスターを作成

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

ECSインスタンスが2つACTIVEになると成功

image.png

4.(オプション)キャパシティープロバイダーを設定する

キャパシティープロバイダーは設定しなくてもDockerコンテナを起動できる
なので、この章(4章) はやらなくてもよい。(←これに気が付かず苦労した)

キャパシティープロバイダー

キャパシティープロバイダーとは、ECSに作ったクラスターに対する設定
前提として、ECSに紐づくAutoScalling側でスケールイン保護が必要

4-1.AutoScalling スケールインから保護

ECSに紐づくAutoScallingを編集

image.png

インスタンス保護を設定
キャパシティの最小値は 0 になっているが 1 以上にすることをオススメ
0だと、EC2インスタンスが0になる可能性がある
EC2インスタンスが0の状態で、ECSでタスク実行すると『キャパシティーが無い』旨のメッセージがでる ※本記事のトラブルシュート参照

image.png

4-2.AutoScalling スケールイン保護の設定

所属するEC2インスタンスを選択し、スケールイン保護の設定を設定する

image.png

4-3.ECS のクラスター clustre01 にキャパシティー作成

image.png

image.png

image.png

image.png

5.タスク定義を作成->実行する

タスク定義を作り実行すれば、Dockerコンテナが起動する。

  • タスク定義とは?を粗く理解
    • json形式
    • コンテナ起動の設計書

5.タスク定義を作成->実行

5-1.タスク定義を作成

image.png

起動タイプ EC2 を選択

image.png

image.png

image.png

コンテナ追加
コンテナ名, リポジトリのURI, ポートマッピング を設定

image.png

こんな感じで登録される

image.png

作成する

image.png

5-2.タスク定義を実行

image.png

4.(オプション)キャパシティープロバイダーを設定するを実施していない場合は、このような画面になる。赤枠のメッセージは、4を実施していないため、その下の起動タイプへ切り替えるをクリックし、(今回であれば)EC2を選択すればよい。

image.png

※おまけ※ 4.(オプション)キャパシティープロバイダーを設定するを実施した場合は、このように赤枠のメッセージが出ない。

image.png

5-3.動作確認

Webサイトが開けば成功。
※ Cloud9(Webサイトにアクセスする環境)とクラスターに所属するEC2インスタンスが通信できるようSG(セキュリティグループ)を設定する。

動作確認

Dockerコンテナが起動しているEC2インスタンスのローカルIPを確認するとアクセスするURLがわかる。

Cloud9-Terminal
$ curl http://{Dockerコンテナが起動しているEC2インスタンスのローカルIP}/index.html
# -> 以下のような結果になれば成功
# <html><head><title>test</title></head><body><h1>TEST</h1></body></html>

今回はこれでおわり

line.png

トラブルシュート

タスク実行したときにキャパシティープロバイダー戦略のエラー発生

image.png

↓赤枠のメッセージ↓

キャパシティープロバイダー戦略
クラスターのデフォルト戦略
指定されたクラスターのデフォルトのキャパシティープロバイダー戦略にキャパシティープロバイダーが含まれていません。デフォルトのキャパシティープロバイダー戦略を更新して、1 つ以上のキャパシティープロバイダーを関連付けてから、もう一度お試しください。

  • <考えられる原因>
    • (1) ECSに作成したクラスターにキャパシティープロバイダーの設定がない
    • (2) キャパシティープロバイダーに設定したAuto Scalling にスケールイン保護の設定されたEC2インスタンスがない
  • <考えられる対策>
    • (1)の対策案-1:本記事【4.(オプション)キャパシティープロバイダーを設定する】を実施しキャパシティープロバイダーを設定する
    • (1)の対策案-2:キャパシティープロバイダーを使わない。起動タイプへ切り替えるをクリックする。本記事【5-2.タスク定義を実行】参照
    • (2)の対策案:本記事【4-1.AutoScalling スケールインから保護】を参照し、Auto Scalling に最低1つスケールイン保護の設定されたEC2インスタンスが含まれるようにする。
suo-takefumi
妄想を具現化するのが好きです。/ のぞくAR #ウソ穴 開発者/ Protout Studio 2期生 / AWS Cloud9 がお気に入り
https://note.com/agw
protoout-studio
プロトアウトスタジオは日本初のプロトタイピング専門スクールです。プログラミングだけではなく、企画力と発信力を身に付けて”自分で課題を見つけて実装し、発信し続ける人”を育成しています。 圧倒的なアウトプット力を身に付けましょう。 学生募集中です。
https://protoout.studio
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away