🕌

【チュートリアル】 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を作成する

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>

Dockerfileの作成

続いて以下のようなファイルを作成する

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リポジトリも余程特殊な理由が無い限り同名で作成しておくとよいだろう。

https://ap-northeast-1.console.aws.amazon.com/ecr/private-registry/repositories?region=ap-northeast-1

ここからリポジトリを作成


my-ecs-projectそのものでも別段構わないのであるが、namespaceをスラッシュで与える事ができるということで、ここでは practice/my-ecs-projectとした

以上の手順でECRリポジトリが作成される

ECRリポジトリにアクセスするためのユーザーおよびキー

実際には、EC2で作業している場合、あえてユーザーを作成する必要は一切なく、EC2に適切なロールを割り当てれば済む話なのであるが、それはいずれやるかもしれないし、やらないかもしれないとして、ここではより汎用的な作業であるAWSキーを使ったイメージ転送作業を行ってみよう。

https://us-east-1.console.aws.amazon.com/iam/home?region=ap-northeast-1#/users

ここではecs-practiceという名前のユーザーを作成している

ここでAmazonEC2ContainerRegistryFullAccessを割り当てている。


ユーザーが作成できたらアクセスキーを作成する

ユースケースはその他とする

ここでこのようにキーが生成されるので、冒頭SSHしてdockerイメージを作成したホストで

aws configure

  • AWS Access Key ID
  • AWS Secret Access Key
  • Default region name

をそれぞれ書き込む。Default region nameap-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の起動を行う解説

https://zenn.dev/catatsumuri/articles/43aaca6a75d9d1

まとめ

  • Dockerイメージの作成
    • index.htmlDockerfile を作成して、Nginxベースのイメージをビルド:
    • docker ruをローカルで確認
  • ECRへのプッシュ
    • AWS Management Consoleから practice/my-ecs-project リポジトリを作成。
    • aws ecr get-login-password, docker tag, docker push を用いて Docker イメージを ECR にプッシュ:
  • ECSでのデプロイ
    • ECS管理画面からタスク定義を作成。
    • クラスターを作成
    • サービスを作成してタスクを起動
    • タスクに割り当てられたグローバルIPでアクセスし、HTMLが表示されることを確認。

Discussion