16
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

AWS ECS(Fargate), ALB, RDSの構成でRailsデプロイしてみた

Last updated at Posted at 2023-09-11

概要

RailsアプリケーションをECS on Fargate + RDS にデプロイする手順について説明します。
今回は説明のため、全てのリソースをマネジメントコール画面(2023.9.10)で入力しています。
ECSやALB、RDSなど、複数のAWSサービスを使用しますが、それぞれのサービスに対して説明はしないです。

誰に向けて?

  • AWSの知識は豊富だが、経験が浅い人
  • マネジメントコンソールからサクッと作成したい人
  • 環境構築滅多にしないから、すぐに忘れちゃう人

AWSリソースの構成

基本的にAWS公式のベストプラクティスに則った構成で作成しています。
下記参照ください。

参考: Amazon Elastic Container Service
参考: Task Networking in AWS Fargate

迷いやすい点、少し構成を考えた点があるので、それらも後ほど紹介します。

アーキテクチャー図

diagramsで作成しています。
github Actionsは、自動デプロイ処理をしようと思っていましたが、結構長くなったので、別記事にしました。

マルチAZ構成で、ECSはFargateにしています。
image.png

必要なリソース

必要なリソースと、ほんの少しの説明だけを書き上 げてみました。
アーキテクチャー図と、下記の情報で、ぽちぽちすれば大体できると思います。

  • VPC: 10.1.0.0/16
    • subnet
      • public: 10.1.0.0/24
      • public: 10.1.1.0/24
      • private: 10.1.2.0/24
      • private: 10.1.3.0/24
    • NAT gateway
    • セキュリティグループ
      • ALB用
        • インバウンドルール: port 443/80
      • ECS用
        • インバウンドルール: port 3000(railsのデフォルト)
      • RDS用
        • インバウンドルール: port 3306, source: ECSのアクセス
  • RDS(PostgreSQL14)
  • ドメイン
    • お名前.com(ドメイン取得)
    • Route53(ドメイン管理)
    • ACM(SSL/TLS証明書の取得)
  • ALB
  • ECR
  • ECS
    • クラスター
    • サービス
    • タスク定義

迷いやすい点、少し構成を考えた点

個人的に、いつも迷いやすい点、またECSの構成で少し考えた点を紹介します。

VPCやサブネットのIPアドレス構成について

VPCは、サブネットマスクを/16にすることで、65536のIPアドレスが取得できることになります。拡張性を考慮していると言えます。
サブネットは、サブネットマスクを/24にすると、第3オクテットを0,1,2,3で取得した時に、256のIPアドレスに分割できます。管理がしやすく、IPアドレスも十分取得できます。
なので、この構成にしています。

ECSをプライベートサブネットかパブリックサブネットのどちらに配置するか?

今回は、プライベートサブネットにしましたが、AWSのベストプラクティスにはどちらも紹介されています。
ALB経由するなら、プライベートサブネット1択でしょ。という方が多いかもしれません。

ただ、プライベートサブネットにすると、後述のNATゲートウェイ(もしくはVPCエンドポイント)に結構費用がかかります(月に5000円ほどはかかる)。 大規模アプリなら無視できるかもしれませんが、中小規模のアプリケーションでは5000円の差は重要です。

下記の記事が参考になりますが、
AWSによると、プライバシーやセキュアな環境である必要があればプライベートサブネットを、インターネットアクセスを簡単にするためにパブリックサブネットを使用するといいんじゃないか
というふうな感じらしいです。

パブリックサブネットにした場合、下記のような問題が出てきますが、
セキュリティグループを適切に設定していれば、ほとんどのセキュリティリスクは緩和されるはずです。
ただ、人為的ミスが命取りになるので、やはりパブリック層とプライベート層とレイヤー分ける意味でも、ECSをプライベートサブネットにしておくのが、良さそうです。

  1. 直接の外部アクセス
  2. DoS/DDoS攻撃のリスク
  3. データのエクスフィルトレーション
  4. 設定ミスの影響

(指摘があれば欲しいです。)

参考: AWS ECS の配置は、プライベートサブネットとパブリックサブネットのどっちがいいの?

NATゲートウェイ か VPCエンドポイントか

ECS実行環境をプライベートサブネットに配置した場合、ECSコントロールプレーンやECR,Cloud watch logsなどの通信するために、NATゲートウェイ か VPCエンドポイントを設置する必要があります。

今回は、NATゲートウェイを選定しました。
VPCエンドポイントにした場合、約5個のリソースが必要になり、さらにマルチAZだとその倍のリソースが必要になります。

管理のしやすさ、コストの観点から、今回はNATゲートウェイにしました。ECS用のSGのアウトバンドを適切に設定すると、セキュリティがさらに担保されます。

Railsアプリケーションについて

アプリケーションの詳細については本題から逸れるため割愛します。
Dockerfileとentrypoint.sh(コンテナ起動時コマンド)については紹介しておきます。

Dockerfile

重要なのは、ENTRYPOINT ["entrypoint.sh"]を使って、
ECS内でDokcerを起動した時に、precmpileやマイグレーション等のコマンドを実行できるようにすることです。

Dockerfile
FROM node:14.17.6 as node
FROM ruby:3.0.2
COPY --from=node /opt/yarn-* /opt/yarn
COPY --from=node /usr/local/bin/node /usr/local/bin/
COPY --from=node /usr/local/lib/node_modules/ /usr/local/lib/node_modules/
RUN ln -fs /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
  && ln -fs /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npx \
  && ln -fs /opt/yarn/bin/yarn /usr/local/bin/yarn \
  && ln -fs /opt/yarn/bin/yarnpkg /usr/local/bin/yarnpkg

RUN apt-get update -qq && \
  apt-get install -y build-essential \
  libpq-dev \
  postgresql-client \
  vim \
  && apt-get clean \
  && rm -rf /var/lib/apt/lists/*

RUN mkdir /myapp
WORKDIR /myapp

COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock

RUN bundle install

COPY package.json yarn.lock ./
RUN yarn install

COPY . /myapp

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]

entrypoint.sh

こちらがentrypoint.shです。
開発(ローカル)環境では、起動中のサーバーがあれば削除するだけです。
本番環境では、アセットのプリコンパイルと、db:create, migrateを実行するようにしています。
db:createは初回デプロイ時のみでOKなので、2回目以降はコメントアウトしてください。
seedなども必要であれば、ここに記述します。

entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# production環境の場合のみ
if [ "$RAILS_ENV" = "production" ]; then
  bundle exec rails assets:precompile
  # --------------------------------------
  # 本番環境(AWS ECS)への初回デプロイ時に利用
  # 初回デプロイ後にコメントアウトして下さい
  bundle exec rails db:create
  # --------------------------------------
  # マイグレーション処理
  bundle exec rails db:migrate
fi

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"

CSSやJSのレンダリングについて、下記が参考になりました。

【参照】

database.yml

後ほど、postgresSQLを作成などに、この辺りの設定が必要になってきます。
なので、一応載せておきます。(参考にしないでいいと思います。)

database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password: password
  pool: 5

development:
  <<: *default
  database: myapp_development


test:
  <<: *default
  database: myapp_test

production:
  <<: *default
  database: myapp_production
  username: myapp
  host: <%= ENV["DB_HOST"] %>
  password: <%= ENV["DB_PASSWORD"] %>

AWSリソースの作成手順

では、これよりAWSリソースの作成手順を説明してきます。
今回は, ProjectAというのプロジェクトの体で、ProjectAを接頭辞としてつけています。

手順ざっくり

  1. ネットワーク(VPC等)を作成
  2. セキュリティーグループを作成
  3. RDS作成
  4. ドメイン取得
  5. ALB作成
  6. ECR作成
  7. ECS作成

ドメイン取得に時間がかかるので、最初にやってもいいかもしれません。。

1.ネットワーク(VPC等)を作成

下記の通りです! VPCなどを一括作成できる機能があるので、それを使ってしまいます。
VPC -> VPC作成より、下記の画面の通りです!

image.png
image.png
image.png

上記の設定で、下記のプレビューが表示されると思います。

image.png

最後に「VPCを作成」 のボタンで一気にリソースが作成されます。

2.セキュリティグループの作成

3つのセキュリティグループを作成します。いずれも、先ほど作成したVPCを関連づけます。
ソースに関して、Anywhereにしていますが、絞った方がより良いです。

ALB用

ALBはHTTPとHTTPSを受け入れますので、下記設定が必要になります。

image.png

ECS用

ECSはRailsデフォルトポートである3000番を許可しておきます。

image.png

RDS用

RDSはECSからの通信を許可する必要があります。
ポートは5432(postgresのデフォルト)にして、ソースはECS用のセキュリティグループにします。

image.png

3.RDSの作成

今回はマルチAZ構成にしていますが、別にシングルAZで無料枠のdb.t2.microなどでも大丈夫です。

今回はPostgreSQL14を使います。
image.png
先述したdb.t2.microを使う場合は、無料枠でOKです。
image.png

ユーザー名, DB名は、先ほどのdatabe.ymlに合わせています。
パスワード、ホスト名(RDSエンドポイント)は、タスク定義のところで、環境変数として利用するのでメモを控えてください。
image.png
image.png

VPCは先ほど作成したものを、DBサブネットグループは新規でOKです。
image.png

セキュリティグループは先ほど登録したものを利用してください。
image.png

最初のデータベースを作成しておいてください。
image.png

料金がバカ高かったら、何かがおかしいので、必ず確認して、
OKだったらデータベース作成してください。
image.png

4.ドメイン取得

ここでは、ドメインを取得し、Route53と紐づけて、ACMで証明書を取得します。
ちなみに、今回取得したドメインは「atelier-sora3.com」です。

ドメイン取得

私は、お名前.comでドメインを取得しましたが、特になんでもOKと思います。
Route53でも取得できますがコストが高いです。管理は楽ですが。

【参照】

Route53でホストゾーンを作成

Route53で「ホストゾーンを作成」をクリック し、ドメイン名に、取得したドメイン名(私の場合はatelier-sora3.com)と入力します。
それ以外はそのままで、「ホストゾーンの作成」をします。
image.png

Route53のホストゾーン一覧から、作成したドメインをクリックします。
image.png

で、NSレコード(ネームサーバー)の値をメモして、次に進みます。
(画面を開いたままにするだけでOKです)
image.png

お名前.domのドメイン情報「ネームサーバー情報」を、Route53と同じにする。

ドメインを取得したサービス(お名前.com)に、先ほどメモしたネームサーバー情報を登録します。
image.png

ここまでで、Route53とお名前.comの紐付けができています。

ACMの設定

続いて、ACM(AWS Certificate Manager)の設定です。SSL/TLS証明書の取得ですね。
これによりHTTPS通信が可能になります。料金は無料です。

atelier-sora3.comを例にして、下記が設定例です。
atelier-sora3.com と *.atelier-sora3.com を登録します。
*.atelier-sora3.comはサブドメインです。

image.png

登録すると、下記のように取得中になります。30分〜半日も待てば取得できるはずです。

image.png

で、この証明書情報をRoute53に登録します。
上記の画面の「Route53でレコードを作成」をクリックすると、下記の画面になるので、そのままレコードを作成してください。
image.png

5.ELB(ALB)の作成

ALB作成に、ターゲットグループが必須なので、まずはターゲットグループ(deleteme)を作成します。
最終的には使わない、一時的なターゲットグループなので、適当に作成しちゃいます。

まず、EC2のサービス画面に来てください。
サイドバーにある、ロードバランシング>ターゲットグループ をクリック。
image.png

最終的には使わない、一時的なターゲットグループなので、適当でOKです。
私は下記のように設定しました。これで作成してください。
image.png

続いて、ロードバランサです。
ロードバランシング>ロードバランサー をクリック。

Application Load Balancer(ALB)を選択してください。
image.png

インターネット向けにしてください。
image.png

VPCを先ほど作成したものにして、
サブネットは、2つのパブリックサブネットを設定します。
image.png

セキュリティグループは、デフォルトに加えて、作成したALB用のものを設定してください。
リスナーとルーティングでは、HTTP(80)とHTTPS(443)を設定します。
デフォルトアクションは、先ほどのdeletemeを一時的に設定しておきます。

image.png
image.png

これで作成でOKです。
image.png

ポート番号80番のリスナールールを443にリダイレクトさせるように変更します。
HTTP:80を選択して、リスナーを編集から、下記のように設定してください。
image.png
下記の通りです。
image.png

6.ECRの作成

ECRは、Dokcerイメージを管理するレポジトリです。
レポジトリの作成とDockerイメージの登録をやっていきます。

ECRレポジトリ作成

ECRと検索し、レポジトリ作成をします。
image.png

名前だけ入力して、あとはそのままでレポジトリ作成します。大文字使えなかったので、小文字にしています。
image.png

作成したレポジトリの詳細ページを開いてください。
image.png

プッシュコマンド表示より、ローカルからレポジトリに登録するコマンドが記載しています。
image.png

あとはこのコマンドをローカルの開発環境で実行するだけです!
ただ、AWS CLIを使う必要があります。
未設定の人は、下記を参考にしてください。

ここまで来たらあとはECSを作成するだけです✊

7.ECSの作成

クラスターを作成し、タスク定義をして、サービス作成(タスク起動設定)という流れで進めていきます。

クラスターの作成

ECSと検索して、クラスター作成をクリックしてください。
image.png

下記の通りに入力して、作成してください。今回はFargateにします。
image.png

タスク定義の作成

タスク定義を作成から、下記の作成画面を開きます。
ここでは、コンテナの設定をしてきます。

コンテナの名前はなんでも大丈夫です。
イメージURLは、ECRから確認して、入力してください。
コンテナポートは、3000です。(Dockerfileによりますが)
スクリーンショット 2023-09-11 3.36.58.png

プロダクトによりますが、環境変数は、おそらく下記のようなものが必要になってきます。

項目 説明
DB_HOST RDSのエンドポイント database.ymlに合わせる
DB_PASSWORD RDS作成時に設定したもの database.ymlに合わせる
RAILS_ENV production 本番環境
RAILS_LOG_TO_STDOUT 1 アプリケーションのログ出力
RAILS_MASTER_KEY master.keyに記述してる値  秘匿情報
RAILS_SERVE_STATIC_FILES 1 静的ファイルの扱い

ログ記録以下の部分はそのままでOKです。作成します。
image.png
image.png

ECSサービスの作成

作成したクラスターの詳細画面より、サービスを作成できます。
image.png

起動タイプなどはデフォルトのままでOKです。
image.png

デプロイ定義のところで、サービス名とタスク定義を設定します。
タスク定義のリビジョンは、最新のものを使用するようにしてください。
(私は何度か作成したので5(最新)になっていますが、スムーズに進められた方は1(最新)になっています。)
image.png

ネットワーキングの設定は、最初に作成したVPCやサブネット、ECS用のセキュリティグループを利用してください。
サブネットは、2つのプライベートサブネットのみを登録します。
タスクは直接外部とインターネットを接続しないので、パブリックIPアドレスはオフにしておいてください。
image.png

続いて、ロードバランシングの設定です。
先ほど作成したロードバランサーを設定してください。
ターゲットグループは、サービス内のタスクに向けて、新規作成します。
image.png

上記の設定で、サービス作成をします。
すると、クラスターに、作成したサービスが表示されます。
image.png

サービス詳細画面のタスクのところで、実行中のタスクを確認できます。
image.png

数分待っていると、下記のようにデプロイが完了します。
image.png

最後に、ALBのターゲットグループを作成したターゲットグループ(ProjectA-target)に変更すると、完了です!

EC2>ロードバランシング>ロードバランサ でロードバランサのターゲットグループを変更します。
(最初に作成したターゲットグループdeletemeは編集できないので、削除するために、一度リスナールールを削除する必要があります。)

ProjectA-albの画面より、HTTP:443を選択します。
image.png

HTTP:443リスナーの詳細画面より、削除ができます。
image.png

再度、リスナーを追加します。
ここで先ほど作成したターゲットグループを選択してください。
image.png

HTTP:80リスナーは、HTTPSへリダイレクトさせます。

最終的に、下記のような設定になっていればOKです!
image.png

これで設定が完了です!!!🙆‍♂️🙆‍♂️🙆‍♂️🙆‍♂️🙆‍♂️🙆‍♂️🙆‍♂️🙆‍♂️

デプロイされたアプリケーションにアクセスしてみましょう。

取得したドメイン(atelier-sora3.com)でアクセスをすると、アプリケーションが見れるはずです!

image.png

デプロイ後、エラーになった方へ

私の説明不足かもしれません、申し訳ございません。

ECSのサービス画面からログを確認できますので、ご確認ください。
デバッグできるかと、、、😭
image.png

アプリケーションの更新(再デプロイについて)

検索すると色々な方法が出てきますが、一番簡単なのは、サービス内で起動中のタスクを削除することです。(アプリが一時的に停止するので、本番運用では控えた方がいいです。)

  1. アプリケーションのコードを修正
  2. ECRに再度プッシュ
  3. ECSサービス内で起動中のタスクを削除
  4. ECRに再度プッシュされたDockerイメージ(latestタグ付き)が、ECSサービス内に自動で起動されます。

### リソース削除について
作成した手順の逆を実施すれば、全て綺麗に削除できますので、忘れずに。🍞

自動デプロイの実装について

下記の記事にまとめました。こちらもご覧ください。

以上です。

最後までありがとうございました。
試したけど、無理だった・ここが間違っているなど、ご意見があればください。
なお、ここで作成したリソースは全て削除しています。

下記、関連記事も書いているので、よかったら見てください。

16
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?