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}
でエラー原因を探る - タスク詳細画面でエラー原因を見てみる
などなど...