LoginSignup
4
2

More than 1 year has passed since last update.

RailsアプリをEC2からECS/Fargate構成に移行してホストする【ECS起動編】

Last updated at Posted at 2021-12-13

はじめに

当記事はECS/Fargateインフラ構成を構築する第二部目の記事です。

第一部をまだ読まれてない方はそちらからご確認ください。

それでは、オーケストレータの構築を行なっていきます。

作業内容

  1. Blue/Greenデプロイメント用ALBの作成
  2. Railsにヘルスチェック用APIの作成
  3. CodeDeployを実行するIAMロールの作成
  4. SystemsManagerで秘匿情報の登録
  5. Railsのdatabase.ymlを編集
  6. ecsTaskExecutionRoleの作成
  7. SystemsManagerにアクセスするIAMポリシーをタスク実行ロールにアタッチ
  8. ECS(タスク定義、クラスター、サービス)の作成

※ECS起動編と題しながら、準備作業をモリモリ含んでおりすいません…

1. Blue/Greenデプロイメント用ALBの作成

前提となりますが、デプロイ方法はblue/greenデプロイメントを採用しています。

特徴は
 ・ダウンタイムなしで新旧タスクを切り替えする
 ・障害時のロールバックが高速である
 ・一定時間は2つのタスクが起動しているので料金コストがかかる
です。

Blue/Greenデプロイメントに必要になってくるALBから作成していきましょう。

では、AWSサービス一覧からEC2を選択します。

スクリーンショット 2021-12-12 12.56.05.png

左のサイドタブからロードバランサーをクリックします。

スクリーンショット 2021-12-12 12.57.05.png

ロードバランサーの作成画面に入りましょう。

スクリーンショット 2021-12-12 12.58.54.png

はじめに、各種あるロードバランサーの中からALBを選択します。

スクリーンショット 2021-12-12 12.59.52.png

スキームは
・ユーザーがALB経由でサイトアクセスできる
ようにインターネット向けにします。

そして、ネットワークを構築したVPCおよびサブネットを関連付けます。

スクリーンショット 2021-12-14 7.41.13.png

セキュリティ設定の構成は、何もせずに先に進みます。

スクリーンショット 2021-12-12 13.09.56.png

既存のセキュリティグループを選択して、
ECS用に作成したセキュリティグループを設定します。

スクリーンショット 2021-12-12 13.11.07.png

次はルーティングの設定です。

ターゲット種類は、ALBが80リスナーに対して振り分けるIPを選択しておきましょう。
(ECS起動後にタスクが生成されると、自動的にIPアドレスが割り振られます)

ヘルスチェックは
・HTTP(80)で
・Railsのapi/healthcheckパスに
行うように設定しています。

そもそもヘルスチェックとは、
ALBがコンテナに対して安全確認のために、事前に通信確認をしておくものです。

このヘルスチェックが通れば、
そのタスクがターゲットグループ内のターゲットとして配置される

イメージを持つと良いと思います。

ヘルスチェックの詳細設定はデフォルトのままでも良いですが
成功とみなす条件を緩めれば、早くパスしますので
各自で考えましょう。

スクリーンショット 2021-12-12 13.14.37.png

healthcheckプロトコルの注意
・Railsのproduction.rbでSSL通信を強制するコードをコメントインしていないか
-> ヘルスチェックはHTTP(80)のプロトコルで検証するもRailsコンテナはHTTPS(443)となっており、
  プロトコルが一致せずに失敗するかもしれない…
=> なので設定していれば、念のためコメントアウトしておく

config/environments/production.rb
require 'active_support/core_ext/integer/time'

Rails.application.configure do

  ### コメントインしてると、HTTP(80)ではなくHTTPS(443)で通信を求める?
  # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
  config.force_ssl = true

end

続いてのターゲットの登録は、ALBが自動的に上手いことしてくれるので、
何もせずにそのままクリックします。

スクリーンショット 2021-12-12 13.24.37.png

2. Railsにヘルスチェック用APIの作成

続いて、Rails側の編集になります。

まず、先ほどALBで設定したヘルスチェックのパスで
アクションが実行されるようにルーティング設定をroute.rbでします。

config/routes.rb

Rails.application.routes.draw do
 --省略--

  namespace :api do
    resources :healthcheck, only: [:index]
  end
end

更に、対象コントローラーで
200というHTTPコードがレスポンスされる処理を
indexアクションに定義します。

app/controllers/api/healthcheck_controller.rb
module Api
  class HealthcheckController < ApplicationController
    def index
      head :ok
    end
  end
end

もし、docker-composeで開発環境の構築をされているなら
上手くレスポンスされるかを検証してみましょう。

ターミナルから下記コマンドを実行します。

ターミナル
# 停止しているコンテナも含めて削除する
% docker-compose down

# バックグラウンドで開発環境を構築する(RailsコンテナとDBコンテナを起動)
% docker-compose up -d

# 念のため、コンテナが起動しているか確認する
% docker-compose ps

開発用をdocker-composeで構築していなければ、
rails sコマンドで開発用サーバーからでも確認できるはずです。

まず、ブラウザChromeでOpt+Cmd+iを押して
ディベロッパーツールを開きましょう。

その後にURLの末尾にヘルスチェック用のパスをつけて
アクセスしてみます。

すると、Statusが200と表示されているはずです。
上手く表示されていない場合はリロードしてみてください。

スクリーンショット 2021-12-12 14.53.41.png

3. CodeDeployを実行するIAMロールの作成

ECSのblue/greenデプロイメントではCodeDeployが動作します。

CodeDeploy: AWSのデプロイ処理を行うサービス

そのCodeDeployを使うには、予めIAMロールを作成しておかないといけないので
AWS公式ページに従ってロールを作成します。

では、コンソール画面で説明します。

まずAWSサービス一覧からIAMを選択します。

スクリーンショット 2021-12-12 15.15.19.png

左側のサイドバーからロールを選択します。

スクリーンショット 2021-12-12 15.16.04.png

ロールを作成を押して、作成画面に飛びます。

スクリーンショット 2021-12-12 15.16.51.png

そして、AWSサービス → CodeDeploy → CodeDeploy-ECS を選び
ユースケースを確定させます。

スクリーンショット 2021-12-12 15.18.03.png

選択したユースケースでは、どういった権限が付与されているのかを確認できます。
(ECRのイメージ保管の実態として、S3が関係しているのでS3を読取する権限もあるはずです。)

スクリーンショット 2021-12-12 15.26.10.png

次のタグの追加は、何もせずにそのままクリックします。

スクリーンショット 2021-12-12 15.28.24.png

最後にロールの作成を押して、CodeDeployを実行する権限を完成させます。

スクリーンショット 2021-12-12 15.30.06.png

4. SystemsManagerで秘匿情報の登録

続いて、RailsがDB接続する際に必要な情報をSystemsManagerに登録します。

SystemsManager: 秘匿情報を管理するサービス

Railsは、database.ymlファイルで記されている
RDSのエンドポイント/パスワード/ユーザー名をもとに
DBに接続します。

開発者/管理者以外に知られてはいけない情報を管理するために
当記事ではSystemsManagerを使います。
(本番OS上に秘匿情報を記憶させるのはNGなので注意しておきます。)

では、コンソール画面からSystemsManagerを選択します。

スクリーンショット 2021-12-12 15.45.58.png

サイドバーよりパラメーターストアを選択します。

スクリーンショット 2021-12-12 15.46.35.png

パラメータの作成をクリックします。

スクリーンショット 2021-12-12 15.47.11.png

ここで、RailsがDB接続に必要な以下3つの情報を登録します。

番号 パラメータ名称
1 /ecs-param/db-host RDSのエンドポイント(コンソールRDS画面から確認)
2 /ecs-param/db-password ログインに必要なパスワード(RDS作成時に自分で設定済み or AWS自動生成)
3 /ecs-param/db-username 使用するユーザー(編集していなければadmin)

RailsがDB接続を試みる際、database.ymlファイルを読み込みますが
本番環境はその情報をSystemsManagerから取得する訳ですね。

SystemsManagerに下記のように
host(RDSエンドポイント)に関する情報を登録できたら
続けて、password, usernameも登録して
3つの情報を登録完了してください。

スクリーンショット 2021-12-12 15.57.06.png

5. Railsのdatabase.ymlを編集

先ほど、SystemsManagerに登録した秘匿情報を
タスク定義が取得して、それをRailsが利用する流れになります。

■秘匿情報の取得の流れ
SystemsManager -> task-def -> Railsコンテナ

タスク定義がSystemsManagerから秘匿情報を取得する設定を後で行いますので
ここでは、先にRails側のdatabase.ymlの設定を行います。

それでは、database.ymlファイルのdefault情報を
production部は、database, username, password, hostを
上書きするのに記述します。

config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  socket: /tmp/mysql.sock
  username: username
  password: password
  host: db

production:
  <<: *default
  database: RDSインスタンス作成時に設定した名称
  username: <%= ENV['DB_USERNAME'] %>
  password: <%= ENV['DB_PASSWORD'] %>
  host: <%= ENV['DB_HOST'] %>

6. ecsTaskExecutionRoleの作成

次は、下記のECSで実行されるロールを作成していきます。

ecsTaskExecutionRole: タスク実行ロール

これも後の作業にはなりますが、ECSサービスを設定する際に
実行権限としてタスク実行ロールを関連付けます。

そのタスク実行ロールに様々なポリシーをアタッチすることで
実行できる権限が広がり、インフラ構築の幅も広がります。

今回の場合は、SystemsManagerから秘匿情報をタスクが取得するために、
ecsTaskExecutionRoleにSystemsManagerを読み取るポリシーをアタッチします。

なので、ecsTaskExecutionRole自体を先に作っていきます。

AWS公式ページより手順が示されておりますので、
それに従ってIAMからロールを作成しましょう。

では、IAM画面からロールを押します。

スクリーンショット 2021-12-13 9.00.32.png

ロールを作成を押します。

スクリーンショット 2021-12-13 9.01.11.png

AWSサービス -> Elastic Container Service -> Elastic Container Service
と順に押して、次のステップ:アクセス権限をクリックします。

スクリーンショット 2021-12-13 9.03.35.png

AWSが指定しているワードを検索フォームに入力した後、
チェックボックスにチェックを入れて次のステップ:タグをクリックします。

スクリーンショット 2021-12-13 9.14.56.png

タグの追加は、何もせずにそのまま進みます。

スクリーンショット 2021-12-13 9.16.38.png

最後に、AWSが指定しているロール名を入力して
ロールの作成をクリックします。

スクリーンショット 2021-12-13 9.17.40.png

7. SystemsManagerにアクセスするIAMポリシーをタスク実行ロールにアタッチする

前項ではタスク実行ロールを作成しました。

そのタスク実行ロールに対して、
SystemsManagerにアクセスするためのポリシーをアタッチします。

こちらもAWS公式ページのドキュメントがありますので、そちらに従って設定を行なっていきます。

まず、コンソールのIAM画面に移り、サイドバーよりポリシーを押します。

スクリーンショット 2021-12-12 16.38.00.png

新しいポリシーを作成するので、ポリシーを作成をクリックします。

スクリーンショット 2021-12-12 16.39.00.png

AWS公式ページにあるJSONコードをコピペしつつ、今回は使用しない
・secretsmanager
・kms
に関するコードを削除します。

なお、*(ワイルドカード)を使って3つパラメータを取得できるように細工します。
AWSアカウントIDは、自分のものに置き換えてください。

スクリーンショット 2021-12-12 16.42.24.png

タグの追加はせずに、そのままクリックします。

スクリーンショット 2021-12-12 16.45.50.png

任意のポリシー名称をつけて、概要欄から
SystemsManagerへの読取が許可されている権限を確認し、ポリシーを作成します。

スクリーンショット 2021-12-12 16.48.52.png

続いて、たった今作成したポリシーをタスク実行ロールにアタッチします。
まず、IAMのサイドバーよりロールをクリックします。

スクリーンショット 2021-12-12 16.51.24.png

ロール一覧からecsTaskExecutionRoleをクリックします。

スクリーンショット 2021-12-12 16.52.59.png

ecsTaskExecutionRoleの画面に移ったら、ポリシーをアタッチしますをクリックします。

スクリーンショット 2021-12-12 16.54.31.png

最後に、
先ほど作成したSystemsManagerへのアクセスを許可するポリシー名で検索をかけて、
同ポリシーのチェックボックスを押して、
ポリシーのアタッチをクリックします。

スクリーンショット 2021-12-12 16.56.28.png

8. ECS(タスク定義、クラスター、サービス)の作成

さあ、7.までの作業で一通り準備が終わりました。

ここからは、ECSのコンソール画面からインフラを構築していきます。

・タスク定義
・クラスター
・サービス

の順番で実装していきます。

タスク定義の作成

実装に入る前にタスク内でコンテナが起動することを念頭に置いておきましょう。

タスク定義: タスクに各種設定を定義するもの

その上で、タスク定義は
 ・コンテナはどのイメージから生成するか
 ・そのコンテナにはどのくらいCPUやメモリのリソースを割り振るか
 ・環境変数を取得するか
 ・ログはどこに収集するか
などを色んな設定を定義するものだと捉えます。

では、コンソール画面でも説明していきます。

AWSサービス一覧からECSを選択します。

スクリーンショット 2021-12-13 11.41.08.png

サイドバーからタスク定義を押します。

スクリーンショット 2021-12-13 11.41.57.png

もちろんFargateを選択します。

スクリーンショット 2021-12-13 11.42.31.png

ページ中央までスクロールして、コンテナの追加をクリックします。
(先にコンテナ登録しておいたほうが分かりやすいのでこの順序で進めてます。)

スクリーンショット 2021-12-13 11.44.31.png

コンテナの登録画面が横から出てきますので
各種項目を埋めていきます。

まず、スタンダードの設定から着手します。

イメージには、ECS準備編でECRに登録したイメージを設定しています。
ECSがECRからイメージをpullしていることを想像しておきましょう。

メモリ制限は512MiBとしています。
1つのRailsコンテナが512MiB使用すると考えましょう。

ポートは、HTTPの80番ポートを解放しています。

スクリーンショット 2021-12-13 12.26.23.png

続いて、詳細コンテナ設定です。

ヘルスチェックはALBで設定済みなので、ここでは設定しません。

環境は、CPUユニット数と環境変数のみ編集します。

CPUユニット数は256としています。
メモリと同様にRailsコンテナが256のリソースを使うことを想像します。

環境変数は、SystemsManagerで登録した秘匿情報をTaskが読み取るものです。
最終的にRailsに渡すイメージで良いと思います。

以下の点だけ注意して登録を行いましょう。
・Key:Railsのdatabase.ymlで展開する環境変数名と一致させる
・ValueFrom:SystemsManagerの登録名と一致させる

スクリーンショット 2021-12-13 12.32.13.png

あとは、ログ収集に関する設定です。

デフォルトでAuto-configure CloudWatch LogsがONになっているはずです。
そのまま変更は加えずに、下にスクロールして追加ボタンを押してコンテナを登録します。

スクリーンショット 2021-12-13 12.12.29.png

すると、元のタスク定義の画面に戻ります。

上から順番にプルダウンを選択していきます。

ここで事前に作成しておいたタスク実行ロールを紐付けます。

スクリーンショット 2021-12-13 12.15.05.png

続けて、タスクサイズの設定を行います。

コンテナをまとめるタスクの設定です。

先ほど、Railsコンテナ側では
・メモリ:512
・CPU:256
に設定しています。

それに対して、タスクサイズは
・メモリ:1GB
・CPU:0.5vCPU
としています。

当記事では1つのコンテナしか作成しませんので
現状は意味はありませんが、タスクの残りメモリおよびCPUに余裕があるので
VueやNginxの別コンテナを追加する構成にしても対応できるような設計としています。

棒グラフからもタスクのメモリ/CPUがRailsコンテナで半分は使用されていることが確認できます。

と理解しておいて、下にスクロールして作成を押して
タスク定義を完成させましょう。

スクリーンショット 2021-12-13 12.36.51.png

クラスターの作成

次は、タスクを配置するクラスターの作成です。

サイドバーよりクラスターを選択します。
続けてクラスターの作成を押します。

スクリーンショット 2021-12-13 13.37.51.png

クラスターテンプレートは、Fargateなのでネットワーキングのみを選択します。

スクリーンショット 2021-12-13 13.38.28.png

障害時の原因を掴むために活用できる
CloudWatch Container Insightsにチェックを入れて、作成を押します。

スクリーンショット 2021-12-13 13.40.04.png

サービスの作成

最後にサービスの作成となります。

ここでは、ECSとALBが連携して動作していることを意識しましょう。

それではコンソール画面を参照しながら説明します。

まず、ECSのサイドバーよりクラスターを押して、
先ほど作成したクラスター名をクリックします。

スクリーンショット 2021-12-13 13.54.27.png

対象のクラスター画面に移動したら、
そこで作成を押して、サービス作成画面に入ります。

スクリーンショット 2021-12-13 13.55.45.png

サービスの設定は、以下の通りに入力していきます。

項目
起動タイプ Fargate
タスク定義 app-backend-def(先ほど作成したもの)
リビジョン latest
クラスター app-backend-cluster(先ほど作成したもの)
サービス名 任意の名称
タスクの数 1

リビジョンは、タスク定義のバージョンを表すもので
タスク定義を更新すると数字の順番で増えていきます。
最新バージョンにはlatestがつきます。

タスクの数は起動させる数なので、可用性をあげたい場合は
数を増やして設定します。

スクリーンショット 2021-12-13 13.59.18.png

デプロイメントは、blue/greenデプロイメントを選択し
他項目はデフォルト通りで、次のステップをクリックします。

スクリーンショット 2021-12-13 14.04.50.png

VPC・サブネット・セキュリティグループは、
ECS準備編のネットワーク構築で作成したものを選択します。

スクリーンショット 2021-12-13 14.08.40.png

セキュリティグループの編集を押すと
横から設定画面が出てきますので、既存のセキュリティグループの選択から
作成済みのセキュリティグループにチェックをつけて保存します。

スクリーンショット 2021-12-13 14.15.22.png

ヘルスチェックの猶予期間は、ロードバランシング欄を完了しないと
設定できませんので、注意してください。

先に、ロードバランサーの種類でALBを選択して、
プルダウンで作成済みのロードバランサーを選択します。

その後に、ヘルスチェックの猶予期間を設定するのですが、
長めに300秒(5分)としています。

この5分の間に、ALBで設定した
・成功とみなす連続回数で
・成功コードでレスポンスされれば
チェックがクリアとなり、タスクを配置してくれます。

スクリーンショット 2021-12-13 14.20.49.png

続いて、ロードバランサーに追加をクリックします。

スクリーンショット 2021-12-13 14.52.16.png

ここでは、ALBに設定している
・リスナーポート
・ターゲットグループ
を設定していきます。

プロダクションリスナーポートは、一般ユーザー用のリスナーとして
80:HTTPを選択します。

テストリスナーのチェックボックスにチェックを入れて
テストリスナーポートは、別の10080ポートで設定します。

ターゲットグループは、blueとgreenのターゲットグループを設定します。

ALBがタスクセットする流れの整理(参考)
■ 1回目のデプロイ:
  切り替えする元のタスクが存在しないので、blueターゲットグループのみにタスクセットされる

■ 2回目のデプロイ:
  blueターゲットグループ内に存在する正常タスクと
  新しく生成されるgreenのターゲットグループ内にセットされたタスクを切り替えされる

■ 3回目のデプロイ:
  greenターゲットグループ内に存在する正常タスクと
  新しく生成されるblueのターゲットグループ内にセットされたタスクを切り替えされる

スクリーンショット 2021-12-13 14.44.49.png

サービスの検出は、必須ではないですが、
設定するタイミングがサービス作成時しかないので
念のため、作成しておきます。

スクリーンショット 2021-12-13 14.57.16.png

オートスケーリングは非常に便利な機能ですが、
後でも編集可能なので、ここではそのまま進めます。

スクリーンショット 2021-12-13 15.00.43.png

最後に、これまでの設定が上手くできているか一通り確認して
サービスの作成を押します。

スクリーンショット 2021-12-13 15.03.15.png

以上で、全ての作業が完了です。

これでサービスが自動的にタスクを動作されます。

ECS画面で
サイドバーのクラスター → 対象サービス名 → イベントのタブ とクリックし
service 対象サービス名 has reached a steady state.のメッセージが
表示されていれば、タスクが正常に起動できています!!!

コンテナ起動の確認

最後に起動できたタスクにアクセスして、アプリが表示されるか確認しましょう。

ALBで自動生成されているDNSをブラウザにコピペ入力して
アクセスできるかを確かめます。

スクリーンショット 2021-12-13 16.38.54.png

上手くいかない時

大変ですが、デバッグしましょう…

私自身、めちゃくちゃエラーが発生しましたので、
エラー文を拾って、ひたすら修正→起動…を繰り返してました。

デバッグについては、別記事でまとめておりますので
宜しければ、参考にしてください。

参考記事

続編

終わりに

画像をキャプチャーしてコメント入れての作業が多すぎてツリそうでした…

terraformでインフラ構成できるようになれば、
記事ももっとアッサリしてるだろうに…笑

こんな長い記事を最後までお読み頂き、ありがとうございました!!

4
2
1

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
4
2