
AWS ECS Fargateをわからせる
初心者向けドキュメントってことでスクショ多めのdefault vpcを使って構成。構成プログラムとか使わずに解説。スクショ多めの奴は鮮度が悪くなるのも早いんだけどもなっていう。
ECS Fargetとは何か
こういうのはもうAIに丸投げしときますわ

ここでの説明はdockerの事が書いてないけどdockerは必須というかecsは基本的にdockerイメージを勝手に走らせてくれるものという理解でokと思う
この記事で出来ること
ECSとロードバランサーを使ってdockerイメージをAWS内で動かす事ができるようになる(ただし、初歩中の初歩)
nginxを使ったカスタムイメージの作成
単純にhtmlを供出できればいいので、nginxでなくてもapache2でもいいし、何ならgo言語で自作したようなプログラムでもいい。要するに何でもいいんだけど、とりあえずnginxが最近よく使われるから何となくそれにしているというだけの話。
最初にまずinstallされているコマンドを確認する
先述したようにdockerが使えない場合は何とかしてdockerをつかえるようにする。また、当然ながらawsの契約とawsコマンド(awscli)も必要であーる。
ここではdockerやawscliのinstallは行わないから(ただでさえ文章が長い)、このコマンドが使えない人は何とか調べてきてほしい。
% docker --version
Docker version 20.10.5+dfsg1, build 55c4c88
% aws --version
aws-cli/2.13.3 Python/3.11.4 Linux/5.10.0-27-cloud-arm64 exe/aarch64.debian.11 prompt/off
なお、現状これでもちょっとバージョン古い
イメージの作成
これはまず作業用のディレクトリーを何でもいいから切った方がよい
% mkdir works
% cd works
何でもいいよ。そしたら以下のようなものを書いたDockerfileというファイルを作る
# 使用するベースイメージ
FROM nginx:alpine
# ホストのHTMLファイルをコンテナ内のnginxサーバーのドキュメントルートにコピー
COPY ./index.html /usr/share/nginx/html/index.html
# 80番ポートを開放
EXPOSE 80
そしたらそしたら表示テストのためのindex.htmlを作る。
<!DOCTYPE html>
<html>
<head>
<title>My First Web Page</title>
</head>
<body>
<h1>Hello, ECS Fargate!</h1>
<p>This is my first containerized web page.</p>
</body>
</html>
そしたらば、これを元にイメージを作る。その際にdockerイメージタグというのを取り決めておく必要がある。タグ名は何でもいいんだけど今回は
ecs-practice-webserver
とでもしますか。
docker build -t ecs-practice-webserver .
を入力。-tはタグ。 「.(カレント)」は現在のディレクトリを基準にしてDockerfileを探すとかそういう話だが、まあ手順通りに何も考えずにやってokである。
以下作業ログ
% docker build -t ecs-practice-webserver .
Sending build context to Docker daemon 3.072kB
Step 1/3 : FROM nginx:alpine
alpine: Pulling from library/nginx
c6b39de5b339: Pull complete
9c27a1903544: Pull complete
ea4e582a9368: Pull complete
7efe8030585d: Pull complete
f2f0a331a0f0: Pull complete
680f7dc6d450: Pull complete
4ed9732a112b: Pull complete
d244ccf97067: Pull complete
Digest: sha256:bb193a04d4f2026c6342fc142741d8036a27ea89674830a0fd0569d58bb2ca77
Status: Downloaded newer image for nginx:alpine
---> d315ef79be32
Step 2/3 : COPY ./index.html /usr/share/nginx/html/index.html
---> 7d317d8e0c42
Step 3/3 : EXPOSE 80
---> Running in ddfa49ef548e
Removing intermediate container ddfa49ef548e
---> bc7881aaef32
Successfully built bc7881aaef32
Successfully tagged ecs-practice-webserver:latest
このようにイメージの作成の成功している。これはシステムの裏で格納されており、docker imagesコマンドで作成されたことの確認はできる、が、割愛。興味あったらコマンド打ってみて。
イメージの確認
ここで作成されたイメージを一度手元で確認しておこう。
% docker run -p 8000:80 ecs-practice-webserver
このようにやって当該ホストの8000 portにアクセスすると

とかいうwebページが表示されるだろう。これで準備はokである。はず。
ECRの準備とIAMアカウント
ECRプライベートレポジトリの作成
これはaws webコンソールから行う、といってもそうムズくはない。ただ、ecrとかで検索してもピンズトで出てこないのでそこだけ注意

なおここではプライベートリポジトリを選択すること

リポジトリの作成で名前をecs-practice-webserverとした。ローカルに合わせる必要はないが、合わせない必要もないなら合わせといた方が管理はしやすいんじゃないかな?

そうするとURIが発行される。これをコピーしてメモっといた方が後々、楽とは思う
メモっとけよ〜w
ECRへpushするIAMアカウント
ローカルのイメージをECRにpushするには専用のAWSアカウントを作る方がよい。これはECRだけに限定する方法とか、ECS全般をメンテナンスするアカウントとかポリシーをいろいろ自分で決めていいと思うが、ここではECR専用とする。何故ならそれが一番わかりやすくセキュアでありまたECSに関してはここではwebから全て設定するからである。そもそも、ここでごちゃごちゃ言ってる事の意味がわからないなら手順通りにやってみて。
まずIAMを探し「ユーザー」を選ぶ

その後当然、ユーザーの作成を選択する

続いてユーザー名を入力していく

ここではecrというユーザーを作成している。コンソールはもちろん提供する必要などないので、チェックを付けてはいけない。

許可はまあ、あとで作るってことで、そのまま次へ、とかを押していくとユーザーが作成されるだろう
ECRとかpushするためのポリシーを作成する
左のメニュを押して

右の「ポリシーの作成」からポリシーを作る
ここでは、ポリシーエディターでジュアルを選択している。この次にECRを選択するんだけどここはElastic とかで検索しないと出てこないので注意

で、権限であるが


まあECRのごときは全て許可してもいいんじゃないかな…(諸説あり)

なんでもいいから名前を付けて保存。ここではecr-adminとした。
作成が終わったらecr-adminで検索してみよう。そうしたら

ユーザーがひっかかって作成されたポリシーを展開して確認できる。
ポリシーとユーザーを関連付ける
そしたらこのポリシーとユーザーを関連付ける。まあ、ユーザーと権限が独立して存在してても仕方ないからな。

当該ユーザーの許可ポリシーにおいて許可を追加で

ポリシーを直接アタッチする
keyとsecretを出す
そしたら「セキュリティー認証情報」で


アクセスキーを作成する

最近ではキーの漏洩が深刻化しているので他の代替え方法を提案してくるが、まーここではキーを作成しよう。今権限を絞っていることによって、万が一破られてもECRしか操作できないという程度にしておくというのは基本的には重要事項である。

ここで発行されるキーとシークレットを確実にメモる。ま、スクショのキーはボカしは必要ないかもやけど何となくな。
aws cliで認証情報をセットアップ
% aws configure
AWS Access Key ID [None]:
とかやっていってうまいことセットする。なお、defaultリージョンはap-northeast-1とする
ECRへプッシュ
これで準備が整ったのでpushしてみよう!
ログイン
まずログインをせにゃならん
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin <aws_account_id>.dkr.ecr.ap-northeast-1.amazonaws.com
<aws_account_id> は適切な値に置き換えること

うまくいくとこんな感じにLogin Succeededになると思う
続いてローカルにタグつけする
docker tag ecs-practice-webserver:latest <aws_account_id>.dkr.ecr.ap-northeast-1.amazonaws.com/ecs-practice-webserver:latest
やっぱり<aws_account_id> は適切な値に置き換えること
でここまできたら、最後にpush
docker push <aws_account_id>.dkr.ecr.ap-northeast-1.amazonaws.com/ecs-practice-webserver:latest
うまいことpushできるとこのような表示となるだろう

タスク定義
ここまででECRの問題は解決した。次にタスク定義を行う。この定義を元にサーバーが起動するのでここでの定義は名前の通りサーバーを起動するものではない。その前段の条件をセットする。
タスク定義の作成
Elastic Container Serviceから「タスク定義」にジャンプできる

そしたら作成だが、jsonは難易度がたかいので

webから新しく作る。

名前はecs-practice-webserverとかにしておくか
続いて

起動タイプは確実にAWS Fargateにチェックが付いた状態とする。アーキテクチャーはdockerイメージを作成したアーキテクチャーにする。実はここではジブンはARM64で作成していたのでここではARM64にしている。
ちなみにARMの方が安い
タスクサイズのcpuとメモリは小さいのを選択しているが、自由にしてok。ただし、スペックが高ければもちろん、コストも高くなる。
ここでイメージURIは多分前段でメモっといてくれてたんじゃないかなーと思うけど、メモを失念してた場合はECRに戻ってまたコピーしてきてください。あとは大体デフォでok

するとこんな感じの定義となりました

クラスターの作成
ここからはいよいよ本体?っぽいものの作成だ。ECS Fargateの場合
クラスター > サービス > タスク
という関係に大体なる。まあサービスをすっとばしてタスクっていうイレギュラーなのもあるが、何にせよクラスターは必要なのだ
ってことでECSはまずクラスターの下に入らないといけないからこれを作っておく。

ここでは以下のようにした

これで「作成」する。まあクラスターに関しては特に語り所がない。ただ、クラスターの作成には「まあまあ」時間がかかる

これでクラスターの作成は終わり。
サービスの作成
さて、ここでAI君にecsのサービスに関して語ってもらっとこう。

なーにを言ってんのか最初はよくわかんないかもしれないが、サービスはタスクの数を監視して自動的にタスクを起動したりするのだ。したがって、サービスが動いている場合はタスクを自分で起動したりしない(してはいけないとも言う)
ま、さらっと概要を掴んだところでサービスを定義していこう。
サービスを作成する

当該クラスターの中に入ったらサービスのリストと作成ボタンがある、ここで作成をクリックしとこう。

そうするとなんちゃら戦略とかでてくるけど、これはよくわからんのでみなかったことにして、しれっと「起動タイプ」を選択しよう

起動タイプがFARGATEに、プラットフォームのバージョンがLATESTになっているのを確認したらデプロイ設定で「サービス」が選択されている事を確認する。

タスク定義でファミリーに先程pushしたdockerイメージを指定していることと、必要なタスクが1になっていることを確認すること。なおこのタスクの数は非常に重要な設定である。
でサービス名には適当な名前を付けることにしよう。ここではecs-practice-webserverとした(みんな同じじゃねーか…)
全てが整ったら作成する。うまいこといくとタスクが自動的に起動してくるので、これには暫くかかるから放置しておこう。
起動されたタスクの確認
で、これまでの手順通りに滞りなくやれば、基本的には これでタスクが起動してくると思う。失敗したときのトラブルシューティングはちょっとここでは書かないというか書けない(単純に面倒くせえから)

このように1/1のタスクが実行中的なメッセージが表示されるだろう。そしたらその当該サービスのリンクをクリックする。

もう少し詳細なタスクの状態が見られる。ここで「タスク」をクリックすると

1つのタスクが実行中なのがわかる。タスクIDは適当に振られたハッシュみたいなのが付いているが気にしなくてもいい。
タスクを停止した時の挙動を予め確認しておく

ここで試しに「停止」を押してみよう。そうするとタスクは停止される。まあそうだよな。

この状態で数分放置する、、、と?

新たなタスクが勝手に起動してくるのがわかる。つまりサービスは望んだカウント、ここでは「1」のタスクをずーっと維持するために存在しているのだ。従って本当にタスクを止めたい場合はこのカウントを「0」にしなくてはいけない。まあここではしないけど

webサーバーに接続する
ではでは、今タスクが起動しているので、いよいよそのタスクにアクセスしてみよう。

起動中のタスクIDをクリックしたら…

ここにパブリックIPがある。これにアクセスすればよさそう?

でもない。これはファイヤーウォールでブロックされいるからである
セキュリティーグループの作成
もう一度、当該サービスをクリックし「設定とネットワーク」を選択する

そうすると

この辺でデフォルトのセキュリティーグループが割り当てられているのがわかる。またネットワークやサブネットもデフォルトのものが大量に割り当てられているのも確認しておいてもいい、
ここでセキュリティーグループのリンクを押すとデフォルトに移動する

このデフォルトを変更すると面倒なことになりかねないので、そのメニューの上位の「セキュリティーグループ」をクリックして

セキュリティーグループの作成でインバウンドルールを

こんな感じで作っておく。

セキュリティーグループが作成されたらECSのサービスに戻るんだけど、なんかこれは削除しないと再設定できないっぽいんだよね〜cliだとできるんだったかな?

削除を行ったら再度同じ設定で作り直し、ネットワーキングでセキュリティーグループを忘れずに付けることにする。ここは複数選択可能だ。

そしたらば

サービスを構築しなおすと、セキュリティーグループが2つになっていることを十分確認できる。そしたらここで提供されるパブリックIPで接続する。なお、パブリックIPはどんどん変わっていき、固定不可能である。(EC2と違ってElastic IPは設定不可能)

これで表示される。ここまでokなら次に進むことができる。
ALBを設定する
さて、今サービスを構築しタスクを起動しパブリックIPを割り当て当該IPの80portにアクセスしたら

と表示された。しかしIPアドレスは固定化できないため、このように適当に割りあてられたIPを訪問するのは、サーバーにおいては実験的な要素が強い。そこでALBを設定し、ALBに割り当てられたhostnameでアクセスできるよう、設定を変更していく。
サービスの削除
また削除する。サービスは結構webコンソールからだと削除生成を繰り返すね
サービスの再生成
ここでロードバランシングをみてみよう

ここでApplication Load Balancerを選ぶ

ここではフルオートでALBへの登録を行うような機能があるので使ってしまう。そしたら、まあ適当に名前入れるだけ

これで作ると

するとこのようにフルオートで作られている気配がある。なお、ALBなどの構築もあり、ここは結構時間がかかるが、このDNS名でアクセスできるようにはなる。しかしフルオートすぎてなかなかわけがわからんところだろう。
削除すると?
ALBの状態を見てみよう
これは実はEC2にある

左のロードバランサーメニューで見てみる

作る方は割とフルオートなんだけど削除してもこのようにALBが残り続けるが、そのうち消滅するようである。
まあこれ移行はフルオートでやってくれても与えられるため、そこにアクセスしたらいい。しかし事細かに設定したいオタクはこの下以降も読むとよし
ターゲットグループとかを自作する(オタク向け)
フルオートではなくある程度マニュアルで作ることもできる。ここでターゲットグループを自作るうこのときターゲットの種類はインスタンスではなくipにしなくてはいけない


としといて、これを指定しalbを作る


そしたら


このように既存のものを選択できるようになる。これで関連付けが行われる。

いすれにせよこれが表示でれば勝ち
次回
さすがにもうちょっと踏みこんでいくぜ….まあ適当な静的htmlが表示できたところで誰も特になりゃしねえからな