AWSのECS環境を構築してみる
概要
AWS にてコンテナ環境(ECS)環境を構築してみます。
ECS には EC2 タイプと Fargate がありますが、ここではまず EC2 タイプで構築します。
※Fargate にする場合、設定・管理する必要がある内容が減りますが、まず EC2 タイプで理解を深めます。
また、キャパシティプロバイダーやスポットインスタンスといった機能を使用することで、価格を抑えながら柔軟にスケールするといった機能がありますが、今回は基本の学習のため使用しません。
手順
コンテナリポジトリ(ECR)を作成する
まず、コンテナイメージを格納するための ECR を作成します。
-
Elastic Container Service
-リポジトリ
を開きます。 -
リポジトリを作成
を押下し、設定を行います。- 可視性設定は
プライベート
のままとします。 - リポジトリ名に任意の名前(例:
samplerepo
)を設定します。 -
リポジトリを作成
を押下します。
- 可視性設定は
プッシュコマンドを確認する
AWS コンソールから以下の方法でプッシュコマンドを確認します。
- 作成したリポジトリを選択します。
-
プッシュコマンドの表示
を押下します。
以降、記載のコマンドに沿って操作していきます。
ECR にログインする
PC 環境から AWS CLI を用いて、以下のコマンドを実行し docker で ECR にログインします。(docker コマンド側が AWS ECR に対して、ログイン状態になります。)
aws ecr get-login-password | docker login --username AWS --password-stdin https://<aws_account_id>.dkr.ecr.<region>.amazonaws.com
ローカルで Docker 環境を作る
次のような内容で、Docker の簡単な環境を作ります。
.
├ src
│ └ index.html
└ Dockerfile
HTML ページを用意する
<h1>Hello World!</h1>
Dockerfile を作成する
FROM 'nginx:latest'
RUN service nginx start
COPY src /usr/share/nginx/html
VOLUME /usr/share/nginx/html
Docker イメージを構築する
docker build -t samplerepo .
リポジトリにイメージをプッシュできるようタグをつける
docker tag samplerepo:latest <aws_account_id>.dkr.ecr.ap-northeast-1.amazonaws.com/samplerepo:latest
プッシュを実行する
docker push <aws_account_id>.dkr.ecr.ap-northeast-1.amazonaws.com/samplerepo:latest
ECR にプッシュされたことを確認する
AWS コンソールから対象のリポジトリを選択し、イメージがプッシュされたことを確認します。
補足:コマンドラインで、リポジトリの一覧を確認する。
aws ecr describe-repositories --region ap-northeast-1
補足:ECR に格納されたイメージを PULL する
docker pull <aws_account_id>.dkr.ecr.ap-northeast-1.amazonaws.com/samplerepo:latest
ECS クラスターを作成する
ECS クラスターは、コンテナを配置するマシンリソースプールの設定になります。
- AWS コンソールで、
ECS
-クラスター
-クラスターの作成
を押下します。 -
EC2 Linux + ネットワーキング
を選択し、次のステップ
を押下します。 -
クラスター名
を任意の名前で設定します。(例:cluster01
) -
EC2 インスタンスタイプ
を選択します。ここでは、今回は動作確認用なので、手動入力としてt2.small
を選択します。 -
インスタンス数
を2
に設定します。 -
キーペア
は既存のものを選択します。(設定しない場合、直接 EC2 に入って調査ができなくなります) - ECS を配置する VPC とサブネットを設定します。ここでは既存の VPC と既存のサブネット(-1a、-1c)を選択します。
-
Tags
を設定します(例:キー
:Name
、値
:ECSInstance01
) -
作成
ボタンを押下します。しばらく待つと完了します。 -
クラスターの表示
を押下します。 -
ECSインスタンス
タブを選択し、インスタンスが起動していることを確認します。
タスク定義を設定する
タスクは、ECS 上に配置される、コンテナの設計図になります。
- AWS コンソールで、
ECS
-タスク定義
-新しいタスクの作成
を押下します。 - 起動タイプの互換性の設定で、
EC2
を選択し次のステップ
を押下します。 - タスクとコンテナ定義の設定を行います。
-
タスク定義名
:任意の名前を設定します。(例:testtask01
) -
タスクロール
:他の AWS リソースにアクセスする権限(例:RDS)を付与したロールを選択します。※実際には、あらかじめロールを作っておく必要があります。今回はなしにします。 -
ネットワークモード
:bridge
、host
、awsvpc
、なし
から選択できます。今回はbridge
を選択します。 -
タスクメモリ
:タスクに割り当てるメモリを設定します。(例:256
) -
タスクCPU
:タスクに割り当てる CPU を設定します。(例:0.5 vcpu
) -
コンテナの追加
を押下し、コンテナの設定を行います。-
コンテナ名
:任意のコンテナ名を設定します。(例:container01
) -
イメージ
:ECR のリポジトリの URL を設定します。(例:<aws_account_id>.dkr.ecr.ap-northeast-1.amazonaws.com/samplerepo
-
メモリ制限
:使用するメモリの制限を設定します。これはdocker run
の--memory
、--memory-reservation
に対応しています。ハード制限の値を超えるとプロセスが強制終了されます。ソフト制限はコンテナ用にメモリが予約されます。ハード制限>ソフト制限である必要があります。タスクレベルで設定を行っている場合は、オプションになります。(もう少し調べる必要がありますが、タスクレベルかコンテナレベルかどちらかの設定に寄せる形になるのかと思います)今回は設定なしにしておきます。 -
ポートマッピング
:ホスト側のポートとコンテナ側のポートを紐づけます。今回は、80
と80
を設定しておきます。 -
ヘルスチェック
:docker run
の--health-cmd
に対応しています。例えば、特定の web ページが正常か一定間隔で確認する際に使用します。今回は設定なしとします。 -
環境 CPUユニット数
:docker run
の--cpus
に対応しています。 -
エントリポイント
、コマンド
、作業ディレクトリ
:Dockerfile の定義を上書きする場合設定できます。今回は設定なしにしておきます。 -
環境変数
:docker run
の-e
あるいは--env
に対応しています。今回は設定なしにしておきます。 -
コンテナタイムアウト
:1 つのタスク定義に複数のコンテナを設定している場合、コンテナ間の起動順序に依存関係がある場合、起動順序を設定できます。今回は設定なしにしておきます。 -
ネットワーク設定 リンク
:docker run
の--link
に対応しています。 -
ネットワーク設定 ホスト名
:docker run
の--hostname
に対応しています。 -
ネットワーク設定 DNS
:docker run
の--dns
に対応しています。 -
ログ設定
:チェックを入れることで CloudWatchLogs に自動出力できます。 -
セキュリティ 特権付与
:チェックを入れるとコンテナにroot
の特権が与えられる。 -
セキュリティ ユーザー
:コンテナ内で使用するユーザを設定できる。
-
-
-
制約
:タスクの配置戦略について設定します。配置戦略とは、AMI の種類や AZ など特定の条件のインスタンスでフィルタして、そのタスクを配置するといった制御を行うことができます。今回は設定なしにしておきます。 -
作成
を押下し、タスク定義の設定を完了します。
備考:ネットワークモード
設定項目 | 説明 |
---|---|
bridge | コンテナ内外で任意のポート番号で紐づける。そのためコンテナ側のポート番号が重複してもマッピングして使用できるが外部から使用できるポート番号は重複できない。 |
host | コンテナ内外で同じポート番号で待ち受ける。1 つのホストで同じポートで待ち受けることはできない。 |
awsvpc | EC2 の eni(ネットワークインターフェース)を複数利用して、タスクごとに eni を割り当て、外部からの待ち受けポートも重複することができる。※インスタンスタイプによって使える eni の数に制限がある。 |
なし | 外部に接続できない。 |
タスクを実行する
- 対象のタスクを選択し、
アクション
からタスクの実行
を選択して実行します。 - 起動タイプ:
EC2
を選択します。 - クラスター:起動対象のクラスターを選択します。ここでは、事前に作成した
cluster01
を選択します。 - タスクの数:起動するタスクの数を設定します。
1
を設定します。 - タスクグループ:任意のグループ名を設定します。設定なしにします。(例:
ecsgroup01
) -
タスクの実行
を押下します。 -
タスクが正常に作成されました
が表示されれば OK です。
ECS の比較的新しい機能であるキャパシティプロバイダー
を用いて、より柔軟にコンピューティングリソースの割り当てができるようですが、今回は使用せずそのまま実行します。(いずれやってみます)
また、タスク実行時に、タスク定義で設定したタスクロールやコマンド、環境設定などの上書きをしての起動ができるようになっています。(今回は使用しません)
動作確認:ボリュームマウントの設定(タスク定義の更新)
続いて、EC2 側のフォルダとコンテナ内のフォルダをマウントで接続してファイルをを操作できるようにしてみます。
ボリュームのマウントの設定をして、更新を反映していきます。
設定を更新する場合は、タスク定義を更新して新しいリビジョンの定義を作成し、それを実行することで反映できます。
-
タスク定義
-タスク定義名:Revion
を選択して、新しいリビジョンの作成
を押下します。 -
ボリューム
からボリュームの追加
を選択します。- 名前:任意の名前を設定します。(例:
testvolume
) - ボリュームタイプを
Docker
に設定します。 -
追加
を押下します。
- 名前:任意の名前を設定します。(例:
- 一旦、タスク定義(親画面)の
作成
ボタンを押下しリビジョンを作成します。(ボリューム作成後、一度リビジョンを作成しないと、ボリュームを使用したマウント設定が反映できないためです) - 再度、
新しいリビジョンの作成
を押下します。 -
コンテナの定義
から設定済みのコンテナ定義を選択します。 -
ストレージとログ
の、マウントポイント
-コンテナパス
にマウントしたいポイントを定義します。(例:/usr/share/nginx/html/
) - コンテナの定義の
更新
を押下します。 - タスク定義(親画面)の
作成
ボタンを押下します。 - タスク定義の新しいリビジョンが作成されます。
- 作成したりビジョンの
アクション
から、タスクの実行
を選択します。 - 起動タイプ
EC2
を選択します。 -
タスクの実行
を押下します。 - 起動タイプを
EC2
を選択して、タスクの実行
を押下します。 -
クラスター
からタスク
を選択し、古いリビジョンのタスクを選択して停止しておきます。 -
コンテナインスタンス
からパブリック IP を確認して、SSH 接続します。(例:ssh -i key.pem ec2-user@[IPアドレス]
) - ディレクトリを
/var/lib/docker/volumes/
に移動します。ここにecs-
から始まるフォルダがあり、これが、ボリュームの追加
で追加したボリュームになります。 - さらにそのフォルダ内に入っていくと、
_data
ディレクトリがあり、その下にindex.html
ファイルがあります。このファイルを更新すると、Web ブラウザから表示される画面にも反映されることが分かります。
サービスの設定
サービスを設定することで、タスクの実行数を定義でき、タスクの起動や運用を自動化できます。
サービスとタスクは 1:1 の関係になります。
また、複数コンテナを立ち上げ、ロードバランサ(ALB)でバランシングするため、固定のポート番号ではなく、動的に割り当てられるポート番号を使用できるようにポートマッピングの設定を変更します。
80
と設定していたホスト側のポート番号を0
とすることで、一時的なポート番号が使用できるようになります。
タスク定義の変更
-
タスク定義
から作成したタスクを選択します。 - 最新リビジョンのタスクを選択し、
新しいリビジョンのタスクを作成
を押下します。 -
コンテナの定義
から対象のコンテナを選択し、ポートマッピング
でホストポート
を0
に設定します。 - タスク定義(親画面)の
作成
ボタンを押下します。
ロードバランサの作成
- AWS コンソールから
EC2
-ロードバランシング
-ロードバランサー
を選択します。 -
ロードバランサーの作成
を押下します。 -
Application Load Balancer
の作成
を押下します。 -
ロードバランサ名(Load balancer name)
に任意の名前を設定します。(例:loadBalancer01
) - アベイラビリティゾーンは、クラスタを作成した
VPC
、サブネット
に合わせて設定します。 - セキュリティグループは新たに作成します。
- セキュリティグループ名:任意の名前を設定します。(例:
ecsALBSecurityGroup
) -
80
番ポートですべての通信0.0.0.0/0
を受け付けるように設定します。 - 作成したセキュリティグループのみを紐づけます。
- セキュリティグループ名:任意の名前を設定します。(例:
- ターゲットグループは新たに作成します。
- ターゲットタイプは
instances
のままで、80
ポートが解放されていることを確認します。 - ターゲットグループ名(
Target group name
)に任意の名称を設定します(例:ecsALBTargetGroup
) - 次へ(
Next
)を押下します。 - ターゲットインスタンスは指定せずそのまま作成します。
- 作成したターゲットグループを、ロードバランサ作成画面側から紐づけます。
- ターゲットタイプは
- ロードバランサの作成(
Create load balancer
)を実行します。 - ロードバランサが作成されたことを確認します。
ECS 用の AutoScalling グループに設定されたセキュリティグループの変更
上記の通り、1サーバに複数コンテナ立ち上げた状態でうまくバランシングるために、コンテナは固定のポート番号ではなくランダムで割り振られたポート番号で待ち受けます。そのため、セキュリティグループが80
しか許可していないと通信ができません。
そのため、ECS インスタンスが属するセキュリティグループ(AutoScalling グループに適用されたセキュリティグループ)にて、インバウンドですべての TCP 通信を、ALB のセキュリティグループからのみ受け付けるように変更します。
-
クラスター
-ECSインスタンス
からいずれかのECSインスタンス
を選択します。 - そのインスタンス(EC2)に適用されているセキュリティグループを確認し、セキュリティグループ更新に進みます。
- インバウンドルール設定で、
すべてのTCP
で、ソースを、セキュリティグループ
の中から、ALB 用のセキュリティグループ(例:ecsALBSecurityGroup)を選択して許可します。
サービスの作成
- 対象のクラスターの
サービス
から作成
を押下します。 - 起動タイプは
EC2
を選択します。 - タスク定義は事前に作成した最新リビジョン(
latest
)の定義を参照します。 - サービス名を任意の名前で設定します。(例:
service01
) - タスクの数を設定します。今回は
4
を設定します。 -
次のステップ
を押下します。 -
ロードバランサの種類
でApplication Load Balancer
を選択します。 -
サービス用の IAM ロールの選択
であらかじめ用意されているAWSServiceRoleForECS
を選択します。 -
ロードバランサー名
で先ほど作成したロードバランサーを選択します。(例:loadBalancer01
) -
ロードバランス用のコンテナ
で、対象のコンテナ(例:container01
)を選択し、ロードバランサに追加
を押下します。 -
プロダクションリスナーポート
で80:HTTP
を選択します。(ロードバランサ側の既存リスナーポートから選択するか、新たに作成できます) -
ターゲットグループ名
で先ほど作成したターゲットグループecsALBTargetGroup
を選択します。 -
次のステップ
を押下します。 - AutoScalling 画面に進みます。そのまま
次のステップ
を押下します。 -
確認
画面で、サービスの作成
を押下します。 -
サービスの表示
を押下して、4つのタスクが起動したことを確認します。 - ロードバランサーの画面から
DNS名
を確認してブラウザでアクセスします。画面が表示されれば OK です。
コンテナイメージを差し替える場合
- タスクを新しいリビジョンで作成し、
コンテナの定義
で対象コンテナのイメージ
を新しいリポジトリのパスに差し替えます。 -
クラスター
からサービス
を開き、チェックを入れて更新
を押下します。 -
サービスの設定
のリビジョン
をlatest
のリビジョンに変更します。 -
最小ヘルス率
:サービスの更新中に稼働しているコンテナを減らさない場合は100
とします。 -
最大率
:サービスの更新中に最大で入れ替え前のコンテナ、入れ替え後のコンテナを完全に同時に稼働した状態(2倍の状態)とする場合には、200
を設定します。
サービスの AutoScalling を設定する
- 対象のクラスターを選択し、サービスの更新に進みます。
- 基本設定及びネットワーク構成は変えず、次へ進みます。
-
AutoScalling(オプション)
画面で、Service Auto Scaling の設定を変更することで、サービスの必要数を調整する
を選択します。 - タスクの最小値を 1、必要数を 2、最大数を 4 と設定します。
-
スケーリングポリシーの追加
を押下します。 -
スケーリングポリシータイプ
をターゲットの追跡
にします。(ターゲットの追跡は規定した値に合わせるように上下します。ステップスケーリングはメトリクスの閾値に応じてスケーリングします。) -
ポリシー名
を任意の名前に設定します。(例:tracking
) -
ECSサービスメトリクス
をECSServiceAverageCPUUtilization
を選択します。CPU の平均使用率を使用します。 -
ターゲット値
に基準とする値を設定します。(例:1
と設定すると CPU 使用率が 1%になるように調整する動きになります)今回は動きを見るために1
を設定してみます。 -
スケールアウトクールダウン間隔
、スケールインクールダウン間隔
にスケーリングアクション毎の間隔を定義します。今回はすぐ動きが分かるように10
を設定します。 -
次のステップ
を押下します。 -
サービスの更新
を押下します。
補足:ステップスケーリングについて
ステップスケーリングを使用すると、メモリの使用率などの閾値でアラームを設定して、その条件を満たしたときにコンテナ数を増減させられます。
補足:EC2 側の AutoScalling 設定について
EC2 インスタンス数のスケーリングに関しては、EC2 の AutoScalling グループ側の設定が必要になります。AutoScalling を設定する際には、アラームで閾値を設定しますが、その際に、ECS クラスターの Reservation 系のメトリクス(CPU やメモリをどの程度予約しているか)でスケーリングを行うことができます(例:メモリを 70%以上予約したら EC2 の台数を増やす、など)
補足:インスタンス数を手動スケールする場合
紐づけられている AutoScalling グループの設定に移動し、グループの詳細
-編集
で希望する容量
および最大キャパシティ
を増やすことで増加させることができます。
Discussion