Fargate(Nginx)->EC2を構築してみた
はじめに
EC2(Nginx)->EC2というプロキシ構成は以下記事で行ったことはありましたが、Fargate(Nginx)->EC2という構成でしてみたかったのでやってみました。
セキュリティグループ作成
事前にFargateとEC2用のセキュリティグループを作成しておきます。
- Fargate
- インバウンド:HTTP・自宅のIP許可
- アウトバウンド:フルオープン
- EC2
- インバウンド:HTTP・Fargateのセキュリティグループ許可
- アウトバウンド:フルオープン
EC2構築
以下の設定で作成しました。
- ami-0506f0f56e3a057a4(Amazon Linux2023選択したらデフォルトで選択されるAMI)
- al2023-ami-2023.3.20240108.0-kernel-6.1-x86_64
- パブリックIPアドレスあり
- 本来ならEC2はプライベートサブネットに置くと思いますが、NginxインストールにNATゲートウェイの料金がかかるのでパブリックサブネットに置きます
- 事前作成したEC2用のセキュリティグループ
- SessionManagerで接続できるIAMロールアタッチ
- t2.micro
EC2にNginxインストール・設定
まずNginxのインストールから起動確認まで行います。
$ sudo dnf -y update
$ sudo dnf -y install nginx
$ sudo systemctl start nginx
$ systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; preset: disabled)
Active: active (running) since Thu 2024-01-18 12:38:07 UTC; 19s ago
Process: 18475 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, status=0/SUCCESS)
Process: 18486 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
Process: 18489 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
Main PID: 18518 (nginx)
Tasks: 2 (limit: 1114)
Memory: 2.2M
CPU: 57ms
CGroup: /system.slice/nginx.service
├─18518 "nginx: master process /usr/sbin/nginx"
└─18519 "nginx: worker process"
起動確認ができたので、ドキュメントルートの場所を確認の上、ドキュメントを単純な内容に変更します。
なお、catの出力内容は関係箇所のみ抜粋しています。
$ cat /etc/nginx/nginx.conf
server {
listen 80;
listen [::]:80;
server_name _;
root /usr/share/nginx/html;
$ sudo vi /usr/share/nginx/html/index.html
Amazon Linux 2023 Nginx!!
これでEC2にアクセスすると、「Amazon Linux 2023 Nginx!!」が返却されます。
Fargate用のDockerイメージ作成
プロキシに利用するのもEC2と同じくNginxです。
まずは適当なディレクトリを作成し、同ディレクトリに移動した上でDockerfileを作成します。
FROM nginx
COPY ./default.conf /etc/nginx/conf.d/
Nginx用の設定ファイルdefault.confをDockerfileと同じ階層に置きます。
なお、以下の設定ファイルは事前にベースイメージのNginxコンテナにdocker execして確認した内容を流用しています。
proxy_passのコメントアウトを除外した上でEC2のプライベートアドレスを設定し、もう1箇所のlocation /
をコメントアウトしています。
もう1箇所のlocationをコメントアウトしているのは、重複してエラーが発生するからです。
server {
listen 80;
listen [::]:80;
server_name localhost;
access_log /var/log/nginx/host.access.log main;
#location / {
# root /usr/share/nginx/html;
# index index.html index.htm;
#}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy
location / {
proxy_pass http://10.0.0.120;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
階層構造は以下になります。
$ tree
.
├── Dockerfile
└── default.conf
次に、イメージを作成し、正常に作成できたかチェックしていきます。
$ docker build -t my-nginx .
$ docker container run -d --name my-nginx my-nginx
$ docker exec -it my-nginx bash
# curl localhost
<!DOCTYPE html>
<html>
<head>
<title>Error</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>An error occurred.</h1>
<p>Sorry, the page you are looking for is currently unavailable.<br/>
Please try again later.</p>
<p>If you are the system administrator of this resource then you should check
the error log for details.</p>
<p><em>Faithfully yours, nginx.</em></p>
</body>
</html>
# exit
上記ではイメージ作成後、コンテナを立ち上げコンテナに入っています。
そして、コンテナ内でcurl localhost
を実行してエラーのドキュメントが返ってきています。
この挙動は、Nginxコンテナがプロキシ先のIPアドレス10.0.0.120
に到達できないので想定通りの挙動になります。
念のため、10.0.0.120
に接続しようとしてエラーになっているかNginxコンテナのログを確認します。
$ docker logs my-nginx
2024/01/18 13:10:39 [error] 22#22: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 127.0.0.1, server: localhost, request: "GET / HTTP/1.1", upstream: "http://10.0.0.120:80/", host: "localhost"
$ docker container stop my-nginx
$ docker rm my-nginx
想定通りログからも10.0.0.120
への接続に失敗している状況がわかったので、コンテナを停止・削除します。
ECRリポジトリにプッシュ
想定通りのDockerイメージが作成できたので、今度はFargateで利用するためにECRにプッシュします。
まずはECRのプライベートリポジトリを作成します。
今回リポジトリの名前は my-nginx
としました。
リポジトリを作成するとプッシュコマンドが確認できるので、そのコマンドを参考にDockerイメージをプッシュしていきます。
必要な人はAWS CLIコマンドに --profile を設定しましょう。
xxx.dkr.ecr....
のxxxはAWSアカウントIDです。
$ aws ecr get-login-password --profile xxx | docker login --username AWS --password-stdin xxx.dkr.ecr.ap-northeast-1.amazonaws.com
Login Succeeded
Logging in with your password grants your terminal complete access to your account.
For better security, log in with a limited-privilege personal access token. Learn more at https://docs.docker.com/go/access-tokens/
$ docker tag my-nginx:latest xxx.dkr.ecr.ap-northeast-1.amazonaws.com/my-nginx:latest
$ docker image ls | grep my-nginx
xxx.dkr.ecr.ap-northeast-1.amazonaws.com/my-nginx latest 8e5447186467 21 minutes ago 187MB
my-nginx latest 8e5447186467 21 minutes ago 187MB
$ docker push xxx.dkr.ecr.ap-northeast-1.amazonaws.com/my-nginx:latest
The push refers to repository [xxx.dkr.ecr.ap-northeast-1.amazonaws.com/my-nginx]
00252c7b058e: Pushed
b074db3b55e1: Pushed
e50c68532c4a: Pushed
f6ba584ca3ec: Pushed
01aaa195cdad: Pushed
2a13e6a7cca6: Pushed
370869eba6e9: Pushed
7292cf786aa8: Pushed
latest: digest: sha256:fc8fd14e55fed8bf64f9f479aa502bad51980467870e53f48b87db7c6e09ae56 size: 1985
以上のコマンドによりECRへイメージのプッシュが完了しました。
本当にプッシュが完了したかはAWSマネジメントコンソールからECRリポジトリを確認しましょう。
Fargateタスク作成
まずはECSクラスターを作成します。
次に、タスク定義を作成します。
作成はコンソール上でぽちぽち行いましたが、JSONにすると以下の内容です。
主な設定は次のとおりです。
項目 | 値 |
---|---|
起動タイプ | Fargate |
コンテナのイメージURI | xxx.dkr.ecr.ap-northeast-1.amazonaws.com/my-nginx:latest(ECRリポジトリのイメージ) |
コンテナポート | 80 |
{
"taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:xxx:task-definition/Proxy-Nginx:1",
"containerDefinitions": [
{
"name": "Nginx",
"image": "xxx.dkr.ecr.ap-northeast-1.amazonaws.com/my-nginx:latest",
"cpu": 0,
"portMappings": [
{
"name": "nginx-80-tcp",
"containerPort": 80,
"hostPort": 80,
"protocol": "tcp",
"appProtocol": "http"
}
],
"essential": true,
"environment": [],
"environmentFiles": [],
"mountPoints": [],
"volumesFrom": [],
"ulimits": [],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-create-group": "true",
"awslogs-group": "/ecs/Proxy-Nginx",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "ecs"
},
"secretOptions": []
}
}
],
"family": "Proxy-Nginx",
"executionRoleArn": "arn:aws:iam::xxx:role/ecsTaskExecutionRole",
"networkMode": "awsvpc",
"revision": 1,
"volumes": [],
"status": "ACTIVE",
"requiresAttributes": [
{
"name": "com.amazonaws.ecs.capability.logging-driver.awslogs"
},
{
"name": "ecs.capability.execution-role-awslogs"
},
{
"name": "com.amazonaws.ecs.capability.ecr-auth"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.19"
},
{
"name": "ecs.capability.execution-role-ecr-pull"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
},
{
"name": "ecs.capability.task-eni"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.29"
}
],
"placementConstraints": [],
"compatibilities": [
"EC2",
"FARGATE"
],
"requiresCompatibilities": [
"FARGATE"
],
"cpu": "1024",
"memory": "3072",
"runtimePlatform": {
"cpuArchitecture": "X86_64",
"operatingSystemFamily": "LINUX"
},
"registeredAt": "2024-01-18T13:27:42.645Z",
"registeredBy": "arn:aws:iam::xxx:user/xxx",
"tags": []
}
最後に、ECSサービスを作成してタスクを起動します。
主な設定は次のとおりです。
項目 | 値 |
---|---|
起動タイプ | Fargate |
タスク定義 | 上記で作成したタスク定義 |
必要なタスク | 1 |
ネットワーキングのサブネット | EC2と同じVPCのパブリックサブネット |
ネットワーキングのセキュリティグループ | 事前作成しておいたFargateのセキュリティグループ |
ネットワーキングのパブリックIP | オン |
ネットワーキングの設定さえ間違えなければ問題ありません。
ECSサービスを作成すると、少し時間をおいてタスクが起動されます。
疎通確認
タスクが起動されたら、パブリックIPアドレスをメモしましょう。
そして、ローカルPCからタスクのパブリックIPアドレス宛にcurlを実行します。
ブラウザからのアクセスでも問題ありません。
$ curl 18.183.73.134
Amazon Linux 2023 Nginx!!
EC2に設定した内容が返却されたので、Fargate(Nginx)->EC2でプロキシできたことが確認できました。
続いて、EC2インスタンスのアクセスログ/var/log/nginx/access.log
も確認してみましょう。
$ cat /var/log/nginx/access.log
10.0.0.174 - - [18/Jan/2024:13:41:27 +0000] "GET / HTTP/1.0" 200 26 "-" "curl/8.1.2" "-"
実際はブラウザからもアクセスしているので上記より多くのアクセスログがありましたが、可視性を考慮し省略しています(以降同様)。
10.0.0.174
からアクセスされていますが、これはタスクのプライベートIPアドレスです。
自宅のIPアドレスではないので、絶対に自分が接続したという実感が湧きません。
実際のクライアントのIPアドレスを知りたい場合は事前にプロキシのFargateのNginxの設定を変更する必要があります。
上記記事を参考にしてイメージを作り直せばできると思いますが、今回はUserAgentを変更して自分がアクセスしたという実感を得ようと思います。
ローカルPCでcurlを実行します。
$ curl 18.183.73.134 -A "OreOre"
Amazon Linux 2023 Nginx!!
上記でUserAgentを指定したので、アクセスログにはOreOre
が残っているはずです。
EC2のアクセスログを確認します。
$ cat /var/log/nginx/access.log
10.0.0.174 - - [18/Jan/2024:13:46:47 +0000] "GET / HTTP/1.0" 200 26 "-" "OreOre" "-"
UserAgentがOreOre
になっていました。
これで自分がアクセスしたログであることが一目瞭然ですね。
おわりに
この記事が誰かのお役に立てれば幸いです。
Discussion