| No. | タイトル |
|---|---|
| 1 | Dockerで開発環境を構築する |
| 2 | ログイン認証を機能を実装する |
| 3 | 記事投稿機能を実装する |
| 4 | AWS ECSを使ってデプロイする |
| 5 | Circle CIを使って自動テスト•デプロイをする |
はじめに
Rails & Nuxtでポートフォリオを作成するシリーズの第4弾になります。
全5部構成でDocker,CircleCI,AWS等のモダンな技術を組み込んだ作品を完成させる予定です。
本章ではAWSのECSを利用してアプリのデプロイを行います。
事前学習
↓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レコードの値/トラフィックのルーティング先をコピーして下さい。

お名前.comのネームサーバにNSレコードの値を登録
先ほどコピーしたNSレコードをお名前.comのDNSサーバーに登録します。

$: 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の修正
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 #設定したパスワード
エンドポイントは↓の値をコピーしてください。
ロードバランサーの作成
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など環境毎に分けて作成すると良いかもです。
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"]
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"]
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}
docker ps
で、現在起動しているコンテナが表示されます。
railsを起動しているコンテナのCONTAINER IDを指定して、以下コマンドを打つと、Dockerコンテナ内部に入れます。
docker exec -it {CONTAINER ID} sh
ここで、環境を指定してdb:migrateします。
rails db:migrate RAILS_ENV=production
起動確認
https://sample.comにアクセスすると、ホーム画面が表示されると思います!
うまくいかない場合...
- 記入ミス等、ケアレスミスしてないか見直す
- 英語の記事がないか調べてみる
-
docker logs {コンテナid}でエラー原因を探る - タスク詳細画面でエラー原因を見てみる
などなど...



