AWS Copilot で nginx を使ったサイドカーパターンを試す

前回からの続きで Express の前段に nginx を配置する構成を Copilot のサイドカーパターンを使って構築する方法を紹介します。

サイドカーパターンとは

コンテナのデザインパターンの 1 つで、メインとなるコンテナを拡張・補完する目的で別のコンテナを配置することです。 その名の通りバイクの横についてるサイドカーが由来になっているそうです。

参考1: Sidecars - AWS Copilot CLI

参考2: https://dl.acm.org/doi/10.5555/3027041.3027059

前提

前回の記事からの続きとして AWS Copilot で Express がデプロイされている状態から始めます。

blog.morugu.com

nginx の準備

前回のディレクトリ構造に nginx を追加して以下のようにしていきます。

copilot-express
 ┣ copilot
 ┃ ┣ api
 ┃ ┃ ┗ manifest.yml
 ┃ ┗ .workspace
 ┣ nginx ←これから作成
 ┃ ┣ Dockerfile
 ┃ ┗ nginx.conf
 ┣ Dockerfile
 ┣ index.ts
 ┣ package.json
 ┗ tsconfig.json

nginx の作業用ディレクトリを作成

$ mkdir nginx && cd nginx

nginx.conf の作成

$ touch nginx.conf
server {
  listen 80;

  location / {
    proxy_pass http://localhost:3000;
  }
}

ここで localhost:3000 を指定する理由は Fargate タスクはawsvpc networking modeと呼ばれる通信方式で動作しており、同一タスクに属するコンテナ間は localhost でのアクセスが可能なためです。

参考 1: Task Networking in AWS Fargate | AWS Compute Blog

参考 2: More detailed example for the nginx sidecar use case · Discussion #2674 · aws/copilot-cli · GitHub

Dockerfile の作成

$ touch Dockerfile
FROM nginx:alpine

RUN rm -f /etc/nginx/conf.d/*

ADD nginx.conf /etc/nginx/conf.d/nginx.conf

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

Docker イメージの作成

$ docker buildx build --platform=linux/amd64 -t copilot-express/nginx .

$ docker images | grep copilot-express/nginx

docker buildxを使う理由は、M1 Mac 上でdocker buildで作成したイメージだとデプロイ時にstandard_init_linux.go:228: exec user process caused: exec format errorが発生してタスクの起動に失敗するためです。

具体的には M1 Mac (arm64)と Fargate(Linux のデフォルトは x86_64) の CPU アーキテクチャが異なるため発生しており、対策として docker buildx を使用してビルドしています。

参考: node.js - 'exec user process caused: exec format error' in AWS Fargate Service - Stack Overflow

ECR リポジトリの作成 & プッシュ

前回copilot initで作成された ECR リポジトリ名がcopilot-express/apiだったので、 今回はcopilot-express/nginxという名前で ECR リポジトリを作成します。

$ aws ecr create-repository --repository-name copilot-express/nginx

タグをつけてプッシュします。

$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin xxxxx.dkr.ecr.ap-northeast-1.amazonaws.com

$ docker tag copilot-express/nginx:latest xxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/copilot-express/nginx:latest

$ docker push xxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/copilot-express/nginx:latest

これで nginx の準備が完了です。

Copilot Manifest の修正 & デプロイ

./copilot/api/manifest.yml の修正

前回copilot initで作成された ./copilot/api/manifest.yml に 以下のように追記します。

http:
  # 追加
  targetContainer: nginx

# 追加
sidecars:
  nginx:
    port: 80
    # ECR にプッシュした nginx イメージの URI を指定
    image: xxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/copilot-express/nginx:latest

ECS デプロイ

./copilot/api/manifest.ymlへの追記が完了したらデプロイを実行します。

$ copilot svc deploy

~~~~~
✔ Deployed service api.
Recommended follow-up action:
  - You can access your service at http://xxxxx.ap-northeast-1.elb.amazonaws.com over the internet.

表示された URL にアクセスして前回同様 Express app works! が表示されたらサイドカーパターンでのデプロイ完了です。

構成の確認

マネジメントコンソールの ECS > クラスター > copilot-express-test-Cluster-xxxxx(copilot initで作成されたクラスター) > タスクから、apinginxのコンテナがRUNNINGになっていることが確認できます。

f:id:morugu:20220107191546p:plain


また EC2 > ロードバランサー > 対象のロードバランサー > リスナータブ > 転送先からポートが 3000 だったのが 80 に変わっていることが確認できます。

f:id:morugu:20220107192310p:plain

リソースの削除

各種構成や動作確認ができたので、Copilot で作成したリソースを削除します。

$ copilot app delete

ECR の copilot-express/nginx リポジトリは AWS CLI から作成したので個別で削除します。

$ aws ecr delete-repository --repository-name copilot-express/nginx --force

まとめ

we are planning to support using local images or Dockerfiles.

と、公式ドキュメントにあるのでローカルのコンテナ環境をそのまま Copilot で ECS にデプロイできる日も近そうです!