8
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

ECSを高速に構築できるAWS Copilot CLIを試してみた

こんにちは、DMM WEBCAMP AdventCalender の20日目を担当します、AWSとDockerが好きな@tkt_horikoshiです。

今回はコマンドラインベースでECSを構築できるAWS Copilotを試してみたので使い心地を共有していきたいと思います。

はじめに

DMM WEBCAMPでエンジニアメンターを始めてからまだ日は浅いですが、受講生さんの中にDockerで開発環境を整えている方がいらっしゃるみたいでした。

せっかくDockerで開発してるならEC2に直接ファイルを置いたりせずにコンテナベースでアプリケーションを実行できるようにしたい。でも、何から始めたらいいかわからん。

そんな思いを抱いている人が一歩踏み出すきっかけになれば幸いです。

ECSとは

ECSはAmazon Elastic Container Serviceの略称で、Dockernizeされたアプリケーションをデプロイし、実行環境を提供するサービスです。コンピューティングリソースにEC2とFargateを選択できますが、特にFargateはコンテナ向けコンピューティングエンジンでプロビジョニングおよびメンテナンスコストが不要になるといった特徴があります。

とても魅力的なサービスで、私も本業でお世話になっているのですが、イチから構築するとなるとそこそこコストがかかるというのも事実です。

AWS Copilotを触ってみる

AWS CopilotはコマンドラインベースでコンテナアプリケーションをサクッとECSへデプロイできるというものです。コマンドラインからECS作れるなんてにわかに信じがたいですがやっていこうと思います。

基本用語

Copilotを利用するうえで理解しておきたいコンセプトについてについてまとめました。Copilotを使ってコマンドラインから下記をそれぞれ作成することができます。

コンセプト 説明
Application 例えばチャットアプリや、ブログサイトといった開発プロダクトそのものを示す概念です。ApplicationにはService, Environmentといった概念が含まれています。
Service ServiceはFrontend, Backendといったアプリケーションの構成要素を示します。
Environment Environmentはテスト環境, プロダクション環境というようなアプリケーションの動作環境の役割を示します。
Job イベント駆動で一時的に実行される処理(ECSタスク)を示します。
Pipeline ビルド、テスト、デプロイといった一連の作業を行うリリースフローを示します。

今回の記事では主にApplication, Service, Environmentについて触れていきます。

本日のゴール

Copilotを使ってアプリケーションをECSにデプロイし、Railsのウェルカム画面を表示してみたいと思います。

アプリケーションの準備

Railsの準備

Dockerfile

まずは、アプリケーションをDockerで動くように設定します。ルートディレクトリにDockerfileを配置します。

FROM ruby:2.7

RUN mkdir /app
WORKDIR /app

RUN curl https://deb.nodesource.com/setup_12.x | bash
RUN curl https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list

RUN apt-get update -qq && \
    apt-get install -y nodejs yarn

COPY Gemfile* ./
RUN bundle install
COPY . .

COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]

EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]

config.hostsの指定

ドメイン許可のためconfig/environments/development.rb, config/environments/production.rbconfig.hostsを追加してドメインを指定しておきます。

今回は、テスト環境とプロダクション環境それぞれのサブドメインも許可したいので下記のような指定となります。

Rails.application.configure do
...

  config.hosts << ".takat0-h0rikosh1.com"

...
end

Nginxの準備

Nginxも同様にDockerで動くように設定します。ルートディレクトリにnginxというディレクトリをきって各種設定ファイルを配置します。

${SERVER_HOST} を環境変数で切り替えられるようにする都合で下記通り設定ファイルのテンプレートを用意しました。

nginx/nginx.conf.template
upstream app {
  server ${SERVER_HOST}:3000;
}

server {
  listen 80;
  server_name localhost;

  root /app/public;

  client_max_body_size 100m;
  error_page 404             /404.html;
  error_page 505 502 503 504 /500.html;
  try_files  $uri/index.html $uri @app;
  keepalive_timeout 5;

  location / {
    proxy_pass http://app;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_redirect off;
    proxy_connect_timeout 30;
  }
}

続いてDockerfileです。CMDでenvsubstを使いで変数を差し替えて/etc/nginx/conf.d/nginx.confに出力します。SERVER_HOSTのデフォルトはlocalhostとしてます。

nginx/Dockerfile
FROM nginx:alpine

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

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

ENV SERVER_HOST localhost

CMD envsubst \
    '$$SERVER_HOST' \
    < /etc/nginx/conf.d/nginx.conf.template > \
    /etc/nginx/conf.d/nginx.conf \
    && nginx -g 'daemon off;'

動作確認

docker-compose.ymlを作成して動作確認してみます。

docker-compose.yml
version: "3.8"

services:
  app:
    build: .
    volumes:
      - .:/app
    ports:
      - "3000:3000"
    environment:
      RAILS_ENV: development

  proxy:
    build:
      context: nginx
    ports:
      - 80:80
    depends_on:
      - app
    environment:
      SERVER_HOST: host.docker.internal

コンテナを起動立ち上げてみましょう

$ docker-compose up
Recreating copilot-playground_app_1 ... done
Recreating copilot-playground_proxy_1 ... done
Attaching to copilot-playground_app_1, copilot-playground_proxy_1
app_1    | => Booting Puma
app_1    | => Rails 6.0.3.4 application starting in development 
app_1    | => Run `rails server --help` for more startup options
app_1    | Puma starting in single mode...
app_1    | * Version 4.3.7 (ruby 2.7.2-p137), codename: Mysterious Traveller
app_1    | * Min threads: 5, max threads: 5
app_1    | * Environment: development
app_1    | * Listening on tcp://0.0.0.0:3000
app_1    | Use Ctrl-C to stop

ひとまず手元での動作確認はできました。

スクリーンショット 2020-12-20 12.25.32.png

Copilotを使ってデプロイしてみる

Install

$ brew install aws/tap/copilot-cli

参考: https://github.com/aws/copilot-cli

Applicationを作成する

自身の所有するドメインを指定してApplicationを作成します。Applicationの名前はwelcomeにします。ルートディレクトリで copilot app init を実行します。

$ copilot app init welcome --domain takat0-h0rikosh1.com


✔ Created the infrastructure to manage services and jobs under application welcome.

✔ The directory copilot will hold service manifests for application welcome.

Recommended follow-up actions:
- Run `copilot init` to add a new service or job to your application.

なにやら copilot init を実行することを進められます。

Serviceの作成とテスト環境のプロビジョン・デプロイ

実行ログに促されるまま copilot init を実行するとステップバイステップでServiceの設定を進めていくことができます。

$ copilot init

Welcome to the Copilot CLI! We're going to walk you through some questions
to help you get set up with an application on ECS. An application is a collection of
containerized services that operate together.

はじめにServiceのワークロードタイプについて聞かれるのでここはLoad Balanced Web Serviceを選択します。名前をどうするか聞かれるのでappとしました。

  Which workload type best represents your architecture?  [Use arrows to move, type to filter, ? for more help]
  > Load Balanced Web Service
    Backend Service
    Scheduled Job

What do you want to name this Load Balanced Web Service? [? for help]
app

続いて、Dockerfileの選択を迫られます。ここではRailsのDockerfileを選択します。

for welcome?  [Use arrows to move, type to filter, ? for more help]
  > ./Dockerfile
    nginx/Dockerfile
    Enter custom path for your Dockerfile
    Use an existing image instead

最後に、テスト環境へデプロイするからどうか尋ねられるので y と入力します。

Would you like to deploy a test environment? [? for help] (y/N)
y

ここまでCLIとの対話が完了するとすごい勢いでプロビジョニングが始まり、数分後にデプロイが完了します。実行ログの最後にURLが表示されるのでブラウザで表示してみます。

スクリーンショット 2020-12-20 23.43.04.png

おー、出ました。

念の為、AWSマネジメントコンソールに入ってざっと内容を確認してみることにします。

  • ECSクラスター
    • スクリーンショット 2020-12-20 23.49.45.png
  • ECSサービス スクリーンショット 2020-12-20 23.50.25.png
  • ALB
    • スクリーンショット 2020-12-21 0.03.07.png

ネットワークの構成はどうでしょうか?

  • VPC
    • スクリーンショット 2020-12-20 23.48.12.png
  • サブネット
    • スクリーンショット 2020-12-20 23.48.58.png
  • セキュリティーブループ
    • スクリーンショット 2020-12-20 23.56.29.png

Environmentの粒度でVPCも丸ごと用意してくれちゃってるみたいです。

すごいですね、コマンドラインだけでDNSの設定を含めECSでアプリケーションを動かすところまでたどり着きました。

SidecarパターンでNginxを動かす

既にお気づきの方もいらっしゃるかと思いますが、この時点ではブラウザからのアクセスがALBを通じてRailsのサーバーに向かってしまいます。

そこで、Railsサーバーのコンテナが動いているECSタスクにNginxのコンテナを動かしてALBのトラフィックをプロキシできるようにします。

ECSタスク内であるコンテナに対して補佐的な役割のコンテナを動かすアプローチをSidecarパターンと呼びます。

ECRにプッシュする

NginxのDockerイメージをECRにプッシュします。
https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/getting-started-cli.html

# リポジトリ作成
$ aws ecr create-repository --repository-name welcome/proxy

# イメージプッシュ
$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 593653836732.dkr.ecr.ap-northeast-1.amazonaws.com && \
  docker build -t welcome/proxy nginx && \
  docker tag welcome/proxy:latest 593653836732.dkr.ecr.ap-northeast-1.amazonaws.com/welcome/proxy:latest && \
  docker push 593653836732.dkr.ecr.ap-northeast-1.amazonaws.com/welcome/proxy:latest

マニフェストファイル修正

copilot init を実行した時点で設定情報が記載されたマニフェストファイルが作成されているのでこれを下記のように修正します。

copilot/app/manifest.yml
name: app
type: Load Balanced Web Service

image:
  build: ./Dockerfile
  port: 3000

http:
  path: 'app'
  # 追加
  healthcheck: '/'
  targetContainer: 'proxy'

cpu: 256
memory: 512
count: 1

# 追加
sidecars:
  proxy:
    port: 80
    image: 593653836732.dkr.ecr.ap-northeast-1.amazonaws.com/welcom/proxy:latest

デプロイ

Serviceをデプロイする copilot svc deploy コマンドを実行します。

$ copilot svc deploy

以下の通り、ECSタスクに appproxy のコンテナが実行されてることが確認できました。

スクリーンショット 2020-12-21 1.38.32.png

追加した proxy コンテナへロードバランシングできていることが確認できました。

スクリーンショット 2020-12-21 1.38.12.png

ここまでで、Nginxでプロキシできるようになりました。

Production環境のデプロイ

それでは、プロダクション環境のデプロイを試したいと思います。

環境変数の設定

今回はウェルカム画面を出したいだけなので実際には省きましたが、Production環境デプロイする場合はRAILS_ENVproductionを設定する必要があると思うのですが、その際はマニフェストファイルに下記を追記します。

copilot/app/manifest.yml
# 省略

environments:
  production:
    variables:
      RAILS_ENV: production

参考: https://aws.github.io/copilot-cli/docs/developing/environment-variables/

Environment作成

Environmentを作成する copilot env init のコマンドを--prod付きで実行します。名前はproductionとしました。

$ copilot env init \
  --name production \
  --default-config \
  --prod

ここまでで、VPCECS Clusterが作成されていることが確認できます。

  • VPC
    • スクリーンショット 2020-12-21 2.16.23.png
  • ECS Cluster スクリーンショット 2020-12-21 2.16.42.png

ご覧の通り、サービスの実行まだ行われてません。

Serviceデプロイ

copilot svc deploy を本番環境へ向けて実行してみることにします。

$ copilot svc deploy --env production

# 省略

✔ Deployed app, you can access it at https://app.production.welcome.takat0-h0rikosh1.com.

おー、出ました。

スクリーンショット 2020-12-21 2.42.31.png

コマンド2発でProductioin環境のデプロイが完了しました。

Clean up

下記のコマンドでCopilotで作成したApplicationに含まれる全てのリソースがキレイに消えてくれます。不要であれば、無駄にお金を請求されないうちに消しておきましょう。

$ copilot app delete

最後に

AWS Copilotを使ってコマンドラインからECSを構築してみました。思っていた以上にサクサクできてしまいすごい時代になったものですね。特にネットワークの構成を意識させずにアプリケーションをホスティングするところまで持っていけるところがすごいです。使いこなせたら生産性がかなり上がりそうです。

時間を掛けずに試せるし、作るも消すもコマンドラインで自由自在ですので、アプリケーションを Dockernize したいけど腰が重いなあー、と感じていた人にとてもオススメです。

興味のある方はチャレンジしてみてください。

今回のソースコードはこちらに置いておきます。
https://github.com/takat0-h0rikosh1/dmm-webcamp-advent-calender-2020

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
8
Help us understand the problem. What are the problem?