【チュートリアル】 AmazonEC2で作業して作る、ECSで動かすwebサーバー
はじめに
いきなりチュートリアル記事
ローカルマシンで全てを構築してもよいが、EC2で簡単に真っサラな環境が作れる昨今であれば、これを使って構築する解説をした方が環境が同じになりハンズオン型式ドキュメントとしての間違いが起き辛いだろうから、あえてここではEC2を1つ起動してイメージの作成を行う記事を書いていく事にする。最終的にはbookにしたい断片的な記事公開。
EC2の起動
ここではdebian12のARM版を選択する。
debianでは無く、ubuntuとかでもそれほど操作は変わらないはずだが筆者は何年もdebianを利用しているため。
スペックはt4g.nano
を選択した。ディスクは8Gもあれば十分かとは思う。
適切にキーペアを設定した後、ポート80を開放する。
以上の設定を施し起動し、sshで接続してみる。
ここではwt.exeで接続した
初期設定
aptを最新に整えて、パッケージをアップデートしておく
sudo apt update && sudo apt upgrade -y
git
docker-compose
の2つをinstallしておく。docker-compose
をインストールすると自動的にdocker.io
(すなわちdocker
の本体)が入る
sudo apt update && sudo apt install -y git docker-compose
バージョンを確認しておく
git --version
docker --version
docker-compose --version
それぞれのバージョンを確認している
また、adduser
コマンドにてadmin
ユーザーをdocker
グループに所属させる。
sudo adduser admin docker
この後一度ログアウト後、再度ログインし、idコマンドで確認しておく
id
dockerグループに所属している事が確認できる
初歩の構築作業
作業ディレクトリの作成
名前は何でもいいのでディレクトリを作成しておく。ここではmy-ecs-project
とする
mkdir my-ecs-project
cd my-ecs-project
適当なindex.htmlの作成とdockerから確認
htmlの作成
ここで以下のような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>
Dockerfileの作成
続いて以下のようなファイルを作成する
# 使用するベースイメージ
FROM nginx:alpine
# ホストのHTMLファイルをコンテナ内のnginxサーバーのドキュメントルートにコピー
COPY ./index.html /usr/share/nginx/html/index.html
# 80番ポートを開放
EXPOSE 80
ここでは軽量で汎用性の高いnginx
を選択。apache2を選ぶ方法も勿論あるが、ここでは割愛する。
ただ、少なくともこの記事の中では設定を変更しないので実際には何でもいいのかもしれない。
dockerコマンドにてタグ付けとビルド
ここでは my-ecs-project
というリポジトリ名にてタグを付けるものとする。
docker build -t my-ecs-project .
-
docker
- Docker CLIツールの実行コマンド。
-
build
- イメージを作成するためのサブコマンド。
-
-t my-ecs-project
- 作成するDockerイメージに「名前(リポジトリ名)」と「タグ」を付けるオプション。
-
my-ecs-project
はイメージの名前(リポジトリ名)。 - デフォルトタグは
latest
になる。
-
.
- 現在のディレクトリを「ビルドコンテキスト」として指定。
Dockerは、ビルドコンテキスト以下のディレクトリ内のファイルを参照し、Dockerfile を基にイメージを作成する。
コマンドを実行すると以下のようになるだろう
docker build -t my-ecs-project
$ docker build -t my-ecs-project .
Sending build context to Docker daemon 45.57kB
Step 1/3 : FROM nginx:alpine
alpine: Pulling from library/nginx
0152682790bb: Pull complete
34f4f67366d7: Pull complete
bb6bc1d08cd9: Pull complete
9b12d344c7bc: Pull complete
5d89794bca8f: Pull complete
685f57786a72: Pull complete
876850e427bb: Pull complete
57520d670e0d: Pull complete
Digest: sha256:814a8e88df978ade80e584cc5b333144b9372a8e3c98872d07137dbf3b44d0e4
Status: Downloaded newer image for nginx:alpine
---> f9d642c42f7b
Step 2/3 : COPY ./index.html /usr/share/nginx/html/index.html
---> 30a45935b50a
Step 3/3 : EXPOSE 80
---> Running in 24e38b2b03e2
Removing intermediate container 24e38b2b03e2
---> 50a2e5ef01b2
Successfully built 50a2e5ef01b2
Successfully tagged my-ecs-project:latest
作成されたイメージは、以下のコマンドで確認できる
docker image ls
実行すると以下のようになるはずだ。ここでは元になっているnginxのイメージも取得されている点に注目する。
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
my-ecs-project latest 50a2e5ef01b2 2 minutes ago 50.9MB
nginx alpine f9d642c42f7b 8 weeks ago 50.9MB
これを以下のようにポート80で起動する
docker run -d -p 80:80 my-ecs-project
すると以下のようになる
$ docker run -d -p 80:80 my-ecs-project
d1110e1259bc546142fb109a5db249db93bd75b19ce628a0f80985d05a015f26
コマンドの解説
-
docker
- Docker CLIツールの実行コマンド。
-
run
- 新しいコンテナを作成して実行するためのサブコマンド。
-
-d
*「デタッチドモード(Detached Mode)」を指定するオプション。- コンテナをバックグラウンドで実行
-
-p 80:80
- ホスト(ローカルマシン)のポート 80 を、コンテナのポート 80 にマッピング
-
my-ecs-project
- 実行するDockerイメージ名。
- デフォルトではリビジョンlatestが自動的に指定される
- 必要に応じてリビジョンを含むタグ(例:my-ecs-project:rev)を付けて特定のバージョンを指定
Dockerにより当該のEC2のグローバルIPアドレス:80が解放されるので、これに実際にアクセスしてhtmlの内容を確認しておく
ECRリポジトリを作成し、ローカルのイメージを送りこむ(push)
ECRリポジトリの作成
これは最初はwebから作成する事にする。
今、ローカルにmy-ecs-project
という名前にて管理しているため、ECRリポジトリも余程特殊な理由が無い限り同名で作成しておくとよいだろう。
ここからリポジトリを作成
my-ecs-project
そのものでも別段構わないのであるが、namespaceをスラッシュで与える事ができるということで、ここでは practice/my-ecs-projectとした
以上の手順でECRリポジトリが作成される
ECRリポジトリにアクセスするためのユーザーおよびキー
実際には、EC2で作業している場合、あえてユーザーを作成する必要は一切なく、EC2に適切なロールを割り当てれば済む話なのであるが、それはいずれやるかもしれないし、やらないかもしれないとして、ここではより汎用的な作業であるAWSキーを使ったイメージ転送作業を行ってみよう。
ここではecs-practice
という名前のユーザーを作成している
ここでAmazonEC2ContainerRegistryFullAccess
を割り当てている。
ユーザーが作成できたらアクセスキーを作成する
ユースケースはその他とする
ここでこのようにキーが生成されるので、冒頭SSHしてdockerイメージを作成したホストで
aws configure
し
- AWS Access Key ID
- AWS Secret Access Key
- Default region name
をそれぞれ書き込む。Default region name
はap-northeast-1
でいいと思う
- Default output format
はnone(default)でいい
ECRへのpushを行ってみる
以下の手順を用いてECRにローカルのdockerイメージをプッシュする
ECRにログイン
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
(結構コマンドが長い)
転送用のタグ付け
ここでは practice/ というnamespaceを与えてECRリポジトリを作成した為、タグ付けもそのように行う。すなわち practice/my-ecs-project:latest となる
docker tag my-ecs-project:latest <aws_account_id>.dkr.ecr.ap-northeast-1.amazonaws.com/practice/my-ecs-project:latest
プッシュ
docker push
にてプッシュする
docker push <aws_account_id>.dkr.ecr.ap-northeast-1.amazonaws.com/practice/my-ecs-project:latest
ここでも practice/ というnamespaceを与える。すなわち /practice/my-ecs-project:latest
するとこのようにpushされる
確認
この状態でpushされているはずなので確認してみよう
なお、このコマンドは何度でも実行する事はできる。ただし
変更点が無いと以上のようにLayer already exists
となり、実質アップロードされない。
以上の操作でECRにイメージをpushできた。
このイメージをAWS上で起動できればそれでokということになる。
タスク定義の設定
ここからAWS上でdockerイメージを実際に起動していく作業となる
ECSと入力して
タスク定義
を探して選択する
ここから「新しいタスク定義」を選ぶ。初回なのでJSONでは無い方を選択してみよう
すると以下のような画面になる(AWSは画面UIも割と頻繁に変更されるが...)
以下のように項目を設定していく
また、タスク実行ロール
にecsTaskExecutionRole
が指定されており、タスクロール
には何も指定されていない 事を 一応気にしておくこと。
続いてコンテナの設定を行う
ここでECRリポジトリのURIはGUIで選択できないので
ここからコピーするのが確実であろう
それ意外はほぼほぼdefaultで行う。今回port80のdockerイメージをAWS側でもport80で動作させるため、設定の変更が必要な箇所はほとんど無い。あったとしても後から行う。ここでは起動を優先させる。
クラスターの作成
ここでトップに戻ってまず「クラスター」を作成する
クラスターとは、ECSでタスクやサービスを実行するための基本単位であり、一種の枠みたいなもので、これが無いとECSは一切使えない。つまり、問答無用でとにかく作成する。ここではmy-ecs-project-cluster
という名前にする
AWS Fargate (サーバーレス)
はdefaultで選択されているはずなのだが一応確認しておく
これを実行すると割と時間がかかった後にクラスターが作成される
サービスの作成
サービスの概念は、ECSでdockerイメージを起動すのに慣れていない人は戸惑う概念かもしれない。
サービスとは常に
docker run -d -p 80:80 my-ecs-project
のような状態を維持するものであり、例えばタスクの数を1としていてタスクが強制終了したりした場合は強制的に自動再起動を行うものである。
実は、使い捨てタスクなど、サービスを使わなくとも利用できるものもあるのではあるが、サーバーとしてサービスを維持し続ける場合のタスクに関しては基本的にサービスを作成しておくのが基本である。
慣れるまでやや難解な概念かもしれないが、初心者の場合は手を動かして覚えていこう。
というわけで作成する
このセクションは基本的にdefaultでよい。キャパシティープロバイダー戦略になっていないことを確認すれば後は大丈夫なはず。
キャパシティープロバイダー戦略ではなく「起動タイプ」になっている
先程作成したタスク定義を指定しリビジョン1(最新)になっている事を確認する
サービス名はmy-ecs-project-service
とした。必要なタスクが1になっている事も確認しておく
もし、タスク定義を修正していたりとかするとリビジョン2とかになっているかもしれない。これは基本的に戻せる数値ではないためだが、重要なのは(最新)になっている事。
その他の項目はデフォルトでok。
後学の為にネットワーキング
を確認するとdefaultのVPCを利用して起動する設定になっている事を確認しておくといいかもしれない。
VPCがデフォルトになっている。これはAWSが用意したネットワークを使うという意味
以上の設定で作成する。ちょっと時間がかかった後サービスが作成される
サービスが開始された時点で「タスク」が起動する
正常にサービスが開始されると、このようにタスクが起動している。
タスクのIDをクリックしてみると
すると、このようにタスクにパブリックIP(グローバルIP)が割り当てられている事が確認できるので、これにアクセスしてみよう(このIPの環境は当然それぞれで異なるはずだ)
そうすると、このようにローカルで作成したHTMLが表示されているのがわかる。
タスクを停止してみる
ECSサービスがECSタスクを自動的に起動しているため、この間課金が続いている。デモなので作業を終了させたい場合はタスクを停止するのであるが、個々のタスクを停止してもサービスによって再起動される。
例えば
ここではタスク 05643e8837684302a754ba9f7f9852ac
を停止する
するとタスクは停止する、ただし、先に書いたようにサービスは自動的にタスクの数を維持しようとする(ここまでの手順だとタスクの数は「 1 」に設定したはずだ。)
従って
新しいタスクが自動的に起動されている
このように止めても止めても次々に新しいIPが割り当てられて起動してくる。
課金を抑えるために
作業終了後はタスクの数を0にする
必要なタスクの数を0にセットしている
暫くするとタスクは消滅する。手動で停止してもいいが
次回は
ECSにてphpの起動を行う解説
まとめ
-
Dockerイメージの作成
-
index.html
とDockerfile
を作成して、Nginxベースのイメージをビルド: - docker ruをローカルで確認
-
-
ECRへのプッシュ
- AWS Management Consoleから
practice/my-ecs-project
リポジトリを作成。 - aws ecr get-login-password, docker tag, docker push を用いて Docker イメージを ECR にプッシュ:
- AWS Management Consoleから
-
ECSでのデプロイ
- ECS管理画面からタスク定義を作成。
- クラスターを作成
- サービスを作成してタスクを起動
- タスクに割り当てられたグローバルIPでアクセスし、HTMLが表示されることを確認。
Discussion