LoginSignup
15
11

More than 1 year has passed since last update.

[ Rails & Nuxt ] AWS ECSを使ってデプロイをする

Last updated at Posted at 2021-06-23
No. タイトル
1 Dockerで開発環境を構築する
2 ログイン認証を機能を実装する
3 記事投稿機能を実装する
4 AWS ECSを使ってデプロイする
5 Circle CIを使って自動テスト•デプロイをする

はじめに

Rails & Nuxtでポートフォリオを作成するシリーズの第4弾になります。
全5部構成でDocker,CircleCI,AWS等のモダンな技術を組み込んだ作品を完成させる予定です。

本章ではAWSのECSを利用してアプリのデプロイを行います。

以下、完成イメージ
AWS_インフラ.png

事前学習

↓AWSのネットワークの仕組みについて

↓ECSについて

VPC作成

最初にリージョンを東京に切り替えておいて下さい。

name CIDRブロック
sample-vpc 10.20.0.0/16

サブネット作成

後に作成するロードバランサーではサブネットが2つ必要な為、Nuxt,Rails,RDSでそれぞれ2つずつサブネットを用意します。

name CIDRブロック Region/AZ
sample-front-subnet-1a 10.20.1.0/24 ap-northeast-1a
sample-front-subnet-1c 10.20.2.0/24 ap-northeast-1c
sample-back-subnet-1a 10.20.3.0/24 ap-northeast-1a
sample-back-subnet-1c 10.20.4.0/24 ap-northeast-1c
sample-rds-subnet-1a 10.20.5.0/24 ap-northeast-1a
sample-rds-subnet-1c 10.20.6.0/24 ap-northeast-1c

IGWの作成

VPC > インターネットゲートウェイより、sample-igwという名前でIGW作成。
その後、[アクション] > [VPCにアタッチ]sample-vpcに関連づける。

ルートテーブルの作成

VPC > ルートテーブル > [ルートテーブルの作成]より作成画面に移ります。

name
sample-front-route
sample-back-route
sample-rds-route

IGW,サブネット,ルートテーブルの関連付け

  • ルートテーブル > アクション > ルートを編集 > ルートを追加より、frontとbackのルートテーブルに対して、0.0.0.0に先ほど作ったIGWを関連付ける。
  • ルートテーブル > アクション > サブネットの関連付けを編集 より以下の表のように関連付け
サブネット ルートテーブル
sample-front-subnet-1a sample-front-route
sample-front-subnet-1c sample-front-route
sample-back-subnet-1a sample-back-route
sample-back-subnet-1c sample-back-route
sample-rds-subnet-1a sample-rds-route
sample-rds-subnet-1c sample-rds-route

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

セキュリティグループ名 タイプ プロトコル ポート範囲 ソース
sample-front-sg HTTP TCP 80 0.0.0.0/0
SSH TCP 22 My IPアドレス
HTTPS TCP 443 0.0.0.0/0
カスタム TCP 3000 0.0.0.0/0
sample-back-sg カスタム TCP 8000 0.0.0.0/0
HTTPS TCP 443 0.0.0.0/0
sample-rds-sg MYSQL/Aurora TCP 3306 0.0.0.0/0

Route53

ドメインの取得

お名前.comより、ドメインの取得をします。Route53からでも取得可能ですが、値段が高いです。
あくまで練習用なので、適当に安いドメイン(.xyzとか)を取得すればOKです。

お名前.comでのドメイン取得方法については、以下を参照してください。

今回は下記を取得したという前提で進めていきます。

ドメイン名 役割
sample.com front
sample-api.com back

ホストゾーンの作成

Route53 > ホストゾーン > [ホストゾーンの作成]
ホストゾーン詳細より、NSレコードの値/トラフィックのルーティング先をコピーして下さい。
スクリーンショット 2021-06-22 16.11.13.png

お名前.comのネームサーバにNSレコードの値を登録

先ほどコピーしたNSレコードをお名前.comのDNSサーバーに登録します。
スクリーンショット 2021-06-22 16.03.25.png

スクリーンショット 2021-06-22 16.05.16.png

スクリーンショット 2021-06-22 16.08.18.png

$: dig sample.com(取得したドメイン) +short NS

上記コマンドをターミナルから打ち、無事登録したNSレコードが表示されていれば反映されています。

ACMを使ってドメインに証明書を発行する

sample.comとsample-api.comについて、それぞれSSL証明書を取得します。
ACM > 証明書のリクエスト > パブリック証明書のリクエストを選択。

ドメイン名 sample.com or sample-api.com
検証方法 DNS検証
タグ なし

リクエスト後、検証画面に移るので、Route53でのレコード作成を押します。
そして、しばらくして(30分くらい)検証保留中から、発行済みステータスとなれば成功です。

RDSの作成

サブネットグループの作成

RDS > サブネットグループ > [DBサブネットグループを作成]

RDSの作成にはサブネットグループが必要なので、先に作成しておきます。
サブネットはsample-rds-subnet1aとsample-rds-subnet1cを選択
グループ名はsample-subnet-groupとします。

RDSの作成・設定

設定 備考
作成方法 標準作成
エンジンのタイプ Maria
バージョン 10.4.3
テンプレート 無料利用枠
DB インスタンス識別子 sample-rds
マスターユーザー名 sample(任意)
マスターパスワード samplepassword(任意)
DB インスタンスクラス情報 db.t2.micro
ストレージタイプ 汎用SSD
ストレージ割り当て 20
VPC 先ほど作ったVPC(sample-vpc)
サブネットグループ 先ほど作ったグループ(sample-subnet-group)
既存のVPCセキュリティグループ 先ほど作ったグループ(sample-rds-sg)
アベイラビリティゾーン 指定なし
最初のデータベース名 app_production

あとはデフォでOKです。
しばらくすると利用可能ステータスとなるので、そうしたらRDS作成完了です。

database.yml、credentials.yml.encの修正

./back/config/database.yml
production:
  <<:         *default
    database: app_production
  host:       <%= Rails.application.credentials.rds[:host] %>  
  username:   <%= Rails.application.credentials.rds[:username] %>
  password:   <%= Rails.application.credentials.rds[:password] %>

これらの値は知られたくないので、credentials.yml内に環境変数として定義します。

$: docker-compose run -e EDITOR="vi" back rails credentials:edit 
-----------------------------------
rds:
  host: エンドポイント #RDS詳細画面のエンドポイントの欄の値
  username: sample #設定したユーザーネーム
  password: samplepassword #設定したパスワード

エンドポイントは↓の値をコピーしてください。

スクリーンショット 2021-06-22 16.25.37.png

ロードバランサーの作成

EC2 > ロードバランサー > [ロードバランサーの作成]より作成画面へ移ります。

ロードバランサーの設定

front

種類の選択 Application Load Balancer
ロードバランサーの設定
名前 sample-front
スキーム インターネット向け
IPアドレスタイプ ipv4
リスナー HTTP & HTTPS
VPC sample-vpc
アベイラビリティゾーン sample-subnet-front1a & 1c
セキュリティ設定の構成
証明書タイプ ACM から証明書を選択する
証明書の名前 sample.com
セキュリティポリシー デフォルト
セキュリティグループ sample-front-sg
ターゲットグループ
名前 sample-front-tg
ターゲットの種類 インスタンス
プロトコル HTTP
ポート 8000
プロトコルバージョン HTTP 1.1
ヘルスチェック
プロトコル HTTP
パス /
ターゲットの登録 スキップ

back

種類の選択 Application Load Balancer
ロードバランサーの設定
名前 sample-back
スキーム インターネット向け
IPアドレスタイプ ipv4
リスナー HTTP & HTTPS
VPC sample-vpc
アベイラビリティゾーン sample-subnet-back1a & 1c
セキュリティ設定の構成
証明書タイプ ACM から証明書を選択する
証明書の名前 sample-api.com
セキュリティポリシー デフォルト
セキュリティグループ sample-back-sg
ターゲットグループ
名前 sample-back-tg
ターゲットの種類 インスタンス
プロトコル HTTP
ポート 3000
プロトコルバージョン HTTP 1.1
ヘルスチェック
プロトコル HTTP
パス /
ターゲットの登録 スキップ

※ヘルスチェックのパスを"/"としていますが、ルートパスに何かしら200レスポンスを返すページを用意しておいて下さい。しないとエラーになります。
ターゲットはECSに登録した際に自動で追加されます。

Route53にAレコードを追加

Route53 > ホストゾーン > [レコードを作成]
- レコードタイプ: A
- 値: エイリアス
- エンドポイント: Application Load Balancer
- リージョン: 東京
- ロードバランサー: sample-front または sample-back

sample.comとsample-api.com両方のドメインで行って下さい

アプリを本番環境用に変更

AWSにデプロイするにあたり、本番環境用にいくつかファイルを変更します。
書き換えるのが面倒ならば、Dockerfile.dev,Dockerfile.proなど環境毎に分けて作成すると良いかもです。

back/Dockerfile
FROM ruby:2.6.3-alpine3.10

ENV RUNTIME_PACKAGES="linux-headers libxml2-dev make gcc libc-dev nodejs tzdata mysql-dev mysql-client yarn" \
    DEV_PACKAGES="build-base curl-dev" \
    HOME="/app" \
    LANG=C.UTF-8 \
    TZ=Asia/Tokyo

WORKDIR ${HOME}
COPY Gemfile ${HOME}/Gemfile  
COPY Gemfile.lock ${HOME}/Gemfile.lock
RUN apk update && \
    apk upgrade && \
    apk add --update --no-cache ${RUNTIME_PACKAGES} && \
    apk add --update --virtual build-dependencies --no-cache ${DEV_PACKAGES} && \
    bundle install -j4 && \
    apk del build-dependencies && \
    rm -rf /usr/local/bundle/cache/* \
    /usr/local/share/.cache/* \
    /var/cache/* \
    /tmp/* \
    /usr/lib/mysqld* \
    /usr/bin/mysql*

ADD . ${HOME}
EXPOSE 8000
CMD ["bundle", "exec", "rails", "s", "-b", "0.0.0.0", "-p", "8000", "-e", "production"]
front/Dockerfile
FROM node:16.3.0-alpine

ENV HOME="/app" \
    LANG=C.UTF-8 \
    TZ=Asia/Tokyo

ENV HOST 0.0.0.0

WORKDIR ${HOME}
RUN apk update && \
    apk upgrade && \
    npm install -g n && \
    yarn install &&\
    rm -rf /var/cache/apk/*

ADD . ${HOME}
EXPOSE 3000
RUN yarn run build
CMD ["yarn", "start"]
./front/nuxt.config.js
  axios: {
    //baseURL: "http://localhost:3000",
    //ベストプラクティスとしてはURLを環境変数で設定した方が良いですが、今回は手直しします。
      baseURL: "https://sample-api.com"
  },

ECRにリポジトリを作成・イメージのプッシュ

ECRの作成・設定

ECR > [レポジトリの作成]よりレポジトリを作成します。
可視設定はプライベート、レポジトリ名はsample-front,sample-backとします。

作成後[プッシュコマンドの表示]を押すとコマンドが表示されるので、それに従いターミナルで実行します。尚、このコマンドを実行するにはAWS-CLIの事前インストールが必要なので、やっておきましょう。

実行後、ECRレポジトリ内にイメージが追加されたのを確認して下さい。

ECSの作成・設定

以下、個人的な用語整理

  • クラスター: ECSの適用範囲を決める
  • タスク定義: docker-compose.yml
  • タスク: docker-compose.ymlによって作成されたコンテナ群
  • サービス:クラスターとタスク定義を紐付ける

ECSクラスターの作成

ECS > クラスター > [クラスターの作成]より作成画面に移ります。

クラスターテンプレート EC2 Linux + ネットワーキング
クラスター名 sample-cluster
プロビジョニングモデル オンデマンドインスタンス
EC2 インスタンスタイプ t3.small
インスタンス数 1
EC2 AMI ID* Amazon Linux2
ボリュームサイズ デフォ値
キーペア 任意 (無しにするとSSH接続でデバックできません)
VPC sample-vpc
サブネット sample-front-subnet1a & 1c
パブリック IP の自動割り当て 適用
セキュリティグループ sample-front-sg
コンテナインスタンスの IAM ロール デフォ値

タスク定義の作成

ECS > タスク定義 > [新しいタスク定義の作成]より作成画面に移ります。
front

設定 Value
起動タイプの互換性 EC2
タスク定義名 sample-front
タスクロール ecsTaskExecutionRole
ネットワークモード ホスト
タスク実行ロール ecsTaskExecutionRole
タスクメモリ (MiB) 700
タスク CPU (単位) 256
コンテナ名 sample-front
イメージURL ECR sample-frontレポジトリのURI
ポート 8000

back

設定 Value
タスク定義名 sample-back
タスクロール ecsTaskExecutionRole
ネットワークモード ホスト
タスク実行ロール ecsTaskExecutionRole
タスクメモリ (MiB) 700
タスク CPU (単位) 256
コンテナの追加
コンテナ名 sample-back
イメージURL ECR sample-backレポジトリのURI
ポート 3000

サービスの作成

ECS > クラスター > sample-service >作成より作成画面に移ります。
front

設定 Value
起動タイプ EC2
タスク定義 sample-front
サービス名 sample-front-service
サービスタイプ REPLICA
タスクの数 1
次のステップ
ロードバランシングの種類 Application Load Balancer
ヘルスチェックの猶予期間 30
サービス用の IAM ロールの選択 ecsServiceRole
ロードバランサー名 sample-front
ロードバランサーに追加
ターゲットグループ名 sample-front-tg
Service Auto Scaling サービスの必要数を直接調整しない

back

設定 備考
起動タイプ EC2
タスク定義 sample
サービス名 sample-back-service
サービスタイプ REPLICA
タスクの数 1
次のステップ
ロードバランシングの種類 Application Load Balancer
ヘルスチェックの猶予期間 30
サービス用の IAM ロールの選択 ecsServiceRole
ロードバランサー名 sample-back
ロードバランサーに追加
ターゲットグループ名 sample-back-tg
Service Auto Scaling サービスの必要数を直接調整しない

以上で完了です。最後に少しだけやることがあります。

コンテナ内に入ってdb:migrateする

EC2インスタンスの中にssh接続し、その上でdockerコンテナ内に入り込みrails db:migrateします。
RDSを作成時に初期DBとして[app_production]を設定したため、db:createの必要ありません。

ssh -i {pemファイル} ec2-user@{インスタンスのpublicIP}
EC2インスタンス内
docker ps

で、現在起動しているコンテナが表示されます。
railsを起動しているコンテナのCONTAINER IDを指定して、以下コマンドを打つと、Dockerコンテナ内部に入れます。

EC2インスタンス内
docker exec -it {CONTAINER ID} sh

ここで、環境を指定してdb:migrateします。

Dockerコンテナ内
rails db:migrate RAILS_ENV=production

起動確認

https://sample.comにアクセスすると、ホーム画面が表示されると思います!

うまくいかない場合...

  • 記入ミス等、ケアレスミスしてないか見直す
  • 英語の記事がないか調べてみる
  • docker logs {コンテナid}でエラー原因を探る
  • タスク詳細画面でエラー原因を見てみる

などなど...

15
11
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
15
11