EC2にdocker-composeでRailsをデプロイする (CI/CDまでの道⑥)
はじめに
前回はRailsをProductionモードで起動しました。今回はEC2にDockerをインストールして、そのうえでProductionモードで起動して、独自のドメインで実際にアクセスできるところまでチャレンジしていきます。
作成に利用するリポジトリはこちら
注意
このハンズオンでは以下の書籍を用います。

AWSではじめるインフラ構築入門 安全で堅牢な本番環境のつくり方
このハンズオンですべてインフラ環境構築の手順を画像付きで載せてもよかったのですが、ほぼこの本通りになってしまい、本を模写することになってしまい著作権に触れてしまう可能性があるためほぼ書籍通りに環境構築をおこないながら進めていきます。一部変更箇所があるのでそこだけ説明を別途入れたいと思います。EC2にドメインでアクセスできるような環境があればインフラ構築は飛ばしていただいて大丈夫です。
本ハンズオンの構成は以下となります。

CI/CDまでの道シリーズ
- Rails6+MySQLのDocker環境構築 (CI/CDまでの道①)
- DockerにWebpacker環境構築(jquery, Bootstrap5, Vue) (CI/CDまでの道②)
- Rails(Docker)に必要なGemを追加する (CI/CDまでの道③)
- Rails(Docker)にNginxを導入する (CI/CDまでの道④)
- Rails(Docker)をProductionモードで起動してみる (CI/CDまでの道⑤)
- EC2にdocker-composeでRailsをデプロイする (CI/CDまでの道⑥)
環境
- WSL2 (Ubuntu20.04)
- Docker 20.10.9
- docker-compose 1.29.1
- Git 2.25.1
- VSCode
AWSインフラ環境の構築
上で説明した通り基本的には書籍通りにインフラ環境を行います。一部だけ変更がありますのでそこは説明を行います。
第1章 AWSをはじめよう
今回は関係ないのでスキップで大丈夫です。
第2章 AWSアカウントを作ろう
書籍通りに作業を行ってください
第3章 安全に作業するための準備
関係ないのでスキップで大丈夫です。
第4章 仮想ネットワークを作ろう
書籍通りに作業を行ってください
第5章 踏み台サーバーを用意しよう
書籍通りに作業を行ってください
第6章 Webサーバーを用意しよう
書籍通りに作業を行ってください
第7章 ロードバランサーを用意しよう
ここは一部修正を行います。
書籍のハンズオンではNginxのポートを3000番で開いているためロードバランサーはEC2の3000番をみにいくように設定していますが、私たちの作成している環境はNginxが80番ポートで受け付けているのでターゲットグループ作成で3000と設定しているところを80に変更します。
具体的な修正箇所は以下です。
ここの80は変更せずターゲットグループを作成します。

このように設定をします。

ターゲットの登録でweb01とweb02を選択してinclude as pending belowでしっかりと登録してからターゲット登録するのを忘れないようにしてください。

あとは書籍通りですが7.3.1の動作確認で
$ python -m SimpleHTTPServer 3000
をしていますが、これは今回80番ポートにしたので動作確認はできません。 飛ばして大丈夫です。
その代わりに実際にデプロイして確認します。
第8章 データベースサーバーを用意しよう
基本的には書籍通りです。
しかし、データベースのパスワードに関してはこのハンズオンではpasswordにしたいと思います。

あとで.envにこのパスワードを設定しますが、passwordとしましたので各自読み替えて設定してください。
9章以降について
これ以降で行う必要があるのは10章のみとなりますが、これはデプロイ後に行いますので9章まで行ったらデプロイにチャレンジします。
9, 11, 12, 13, 14, 15章はこのハンズオンには不要です。
EC2にデプロイする
まずはWebサーバー(web01)にssh接続します。
$ ssh web01
ここでWSL2でなぜか多段階接続ができず、PowershellでC:\Users\ユーザー名\.sshにconfigとpemをおいて接続(ssh web01)を行ったあとにWSL2で多段階接続するといけました。
Windows環境との競合などが発生しているようです。
以下の記事を参考にEC2にDocker、docker-compose、Gitをインストールしていきます。
【AWS】EC2にDockerとDocker Composeをインストール
AWS EC2 AmazonLinux2 Gitをインストールする
$ sudo amazon-linux-extras install -y docker
$ sudo systemctl start docker
$ VER=v2.2.3
$ sudo curl -L https://github.com/docker/compose/releases/download/${VER}/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
$ sudo yum install git
次にGitから作成したDocker環境をクローンしてきます。
$ git clone https://github.com/jinwatanabe/CICD_Road
VSCodeのリモートSSHを利用してweb01のCICD_Road/chapter05にはいります。

※ web01のCI_CD_Road_4となっていますが、皆様の画面ではCICD_Roadとなっているかと思います
リモートSSHについては以下を参考に入れてみてください。
VSCode の Remote - SSH 機能を使って EC2 上で開発する
CICD_Road/chapter05のディレクトリに移動します。
config/credentials.yml.encを削除します(ない場合は省略)
前回作成したconfig/credentials.yml.encとconfig/master.keyをconfig/にコピーします。
以下の記事を参考にProductionモードをEC2ように修正していきます。
EC2上でRailsアプリケーションにDockerを導入する(Rails、Nginx、RDS)
まずは.envの内容を以下に変更します。
DB_USERNAME="admin"
DB_PASSWORD="password"
DB_HOST="RDSのエンドポイント名"
DB_DATABASE="myapp"
RDSのエンドポイント名のところには、書籍のP178で確認したエンドポイントを入れてください。
次にDBのProduction時の設定を変えます。config/database.ymlのproduction部分を以下に修正します。
(省略)
production:
<<: *default
database: <%= ENV['DB_DATABASE'] %>
adapter: mysql2
encoding: utf8mb4
charset: utf8mb4
collation: utf8mb4_general_ci
host: <%= ENV['DB_HOST'] %>
username: <%= ENV['DB_USERNAME'] %>
password: <%= ENV['DB_PASSWORD'] %>
今回はRDSを利用するのでdocker-compose.production.ymlのDBに関する部分をコメントアウトします。
version: "3.9"
services:
rails:
build: .
container_name: rails
command: bundle exec puma -C config/puma.rb -e production
volumes:
- .:/myapp
- public-data:/myapp/public
- tmp-data:/myapp/tmp
- log-data:/myapp/log
- /myapp/node_modules
env_file:
- .env
# depends_on:
# - db
user: root
# db:
# image: mysql:8.0.27
# container_name: db
# environment:
# TZ: Asia/Tokyo
# MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
# ports:
# - "3306:3306"
# volumes:
# - db:/var/lib/mysql
web:
build:
context: containers/nginx
volumes:
- public-data:/myapp/public
- tmp-data:/myapp/tmp
ports:
- 80:80
depends_on:
- rails
volumes:
# db:
# driver: local
public-data:
tmp-data:
log-data:
次にNginxの設定をします。containers/nginx/nginx.confのserver_nameを変更します。
# プロキシ先の指定
# Nginxが受け取ったリクエストをバックエンドのpumaに送信
upstream myapp {
# ソケット通信したいのでpuma.sockを指定
server unix:///myapp/tmp/sockets/puma.sock;
}
server {
listen 80;
# ドメインもしくはIPを指定
server_name [Web01のプライベートIP]; #修正
(省略)
Web01のプライベートIPをいれます。
※ 注意 Web02の場合はWeb02のプライベートIPをいれます
次にコンテナを起動するための準備としてコンパイルとDB作成(Web01とWeb02で共有しているのでWeb01でやる1回でOK)を行います。
またDockerコマンド、docker-composeコマンドはすべてsudoで実行する必要があります。
$ sudo docker-compose -f docker-compose.production.yml build
$ sudo docker-compose -f docker-compose.production.yml run rails rails assets:precompile RAILS_ENV=production
# DB作成はweb01でのみ
$ sudo docker-compose -f docker-compose.production.yml run rails rails db:create RAILS_ENV=production
# 起動
$ sudo docker-compose -f docker-compose.production.yml up
実際にデプロイが成功しているか踏み台サーバーbastionから確認します。別のターミナル(Powershellなど)を開きbastionにssh接続して確認します。
$ ssh bastion
$ curl [web01のプライベートIP]/test
以下のように出力されていればうまくデプロイができています。
[ec2-user@ip-10-0-0-236 ~]$ curl 10.0.71.6/test
<!DOCTYPE html>
<html>
<head>
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type'>
<title>Myapp</title>
<meta content='width=device-width,initial-scale=1' name='viewport'>
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="wOB_duwKTFg2RWJThBSxhJyRM0ZhZpiM5StGDa648VnVaTP7VqhFIVGV8rLIa63WDcoO83cA5s22BgtDo96LBA" />
<script src="/packs/js/application-5c597b4d3c61e38cc616.js"></script>
<link rel="stylesheet" media="screen" href="/packs/css/application-8b2e0365.css" />
<script src="/packs/js/main-4c9d47074ceee9ee29cb.js"></script>
</head>
<body>
<h1>Hello World</h1>
<h2>CSSが適応されると色が変わる</h2>
<button class='btn btn-primary' type='button'>Bootstrap適応</button>
こんにちは
/testがないとproductionモードでは404エラーになります。(万歳画面はなくなるので)
ここまでできたら、Web02に関しても同じ手順でコンテナを起動します。nginx.confのプライベートIPをWeb02のプライベートIPにして、DB作成は行わないが違う点です。
ドメインを登録する
ここまでできたら書籍の第10章 独自ドメインとDNSを用意しようを行います。
こちらも書籍通りに行います。
Webサイトを確認する
https://www.自分のドメイン/testにアクセスしてページが表示され、CSSやJavascriptが適応されていれば成功です。

JavascriptのアラートはChoromeだと最初の1回のみしか(リロードでは)表示されませんので注意してください。Choromeをすべて閉じてから再度開いてください
/testを忘れるとNginxのエラー画面になるので注意してください。
おわりに
作成したものはこちらのリポジトリに用意しています。
ひとまずデプロイができるようになりました。
しかしこの状態ではコンテナを差し替えるときに起動までの時間ユーザーに利用できない時間ができたり、手間がかかったりと問題は多いので次はコンテナに適したデプロイにチャレンジしていきたいです。
Discussion