AWSにRails + Nginxな環境をTerraformで構築してみようと思います。
はじめに
本連載で一つずつインフラを構築していきます。
ドメインのhttps化したり、ECS Fargateを使用したコンテナオーケストレーションを用いてアプリケーションをデプロイします。
この記事ではRailsとNginxのDockerイメージを作成してECRにpushをします。
環境は以下です。
OS | Cataline 10.15.6 |
Terraform | 0.14.4 |
基本構文などこちらにまとめてますので、よかったらみてください!
AWS Terraform 基本コード まとめ
連載一覧
- terraform AWS環境構築 事前準備
- 【ネットワーク環境構築】terraform AWS環境構築 第1回
- 【ドメインhttps化・ACM(SSL)証明書発行】terraform AWS環境構築 第2回
- 【ロードバランサー構築】terraform AWS環境構築 第3回
- 【ECS Fargate(nginx)実行】terraform AWS環境構築 第4回
- 【RDS構築】terraform AWS環境構築 第5回
- 【Docker/ECR作成】terraform AWS環境構築 第6回 ←ここ
- 【ECS Fargate(rails + nginx)実行】terraform AWS環境構築 第7回
- 【CircleCIによるCI/CD】terraform AWS環境構築 番外
やること
以下の作成します。
- ローカル用 Rails イメージの作成
- 本番用 Rails イメージの作成
- Nginx イメージの作成
- ECR へpush
Dockerイメージ作成
今回使用する作業フォルダを作成しておきましょう。
$ mkdir rails_hello
$ cd rails_hello
ローカル用 Rails イメージの作成
必要なファイルの準備
Dockerfileの作成
rails_helloフォルダ内でDockerイメージを構築するDockerfileを作成します。
./Dockerfile
FROM ruby:2.7.1-alpine3.12 RUN apk add --update-cache --no-cache tzdata libxml2-dev curl-dev \ make gcc libc-dev g++ linux-headers \ mysql-dev mysql-client nodejs git yarn && \ rm -rf /var/lib/apt/lists/* RUN mkdir /rails_hello WORKDIR /rails_hello ADD Gemfile /rails_hello/Gemfile ADD Gemfile.lock /rails_hello/Gemfile.lock RUN gem install bundle && \ bundle install RUN rm -rf /usr/local/bundle/cache/* /workdir/vendor/bundle/cache/* ADD . /rails_hello
- FROM:使用するイメージ:バージョン
- RUN :コマンドの実行
- WORKDIR: 作業ディレクトリを設定
- ADD :ローカルのファイルをコンテナへコピー
COPY :でも同じことができる(ここではCOPYのほうが良いかも。)
Gemfileの作成
インストールするRailsのバージョンを指定します。
./Gemfile
source 'https://rubygems.org' gem 'rails', '~> 6.1.3'
Gemfile.lockの作成
空のGemfile.lockを作成します。
docker-compose.ymlの作成
アプリケーションを構成する各サービスを定義し、実行するためのファイルです。
ここでは、dbコンテナ(MySQL)とwebコンテナ(Rails)を定義します。
version: '3' services: web: build: . volumes: - .:/rails_hello - bundle:/usr/local/bundle command: ash -c "rm -f /tmp/pids/server.pid && rails s -b '0.0.0.0'" ports: - 3000:3000 links: - db db: image: mysql:8.0.16 command: mysqld --default-authentication-plugin=mysql_native_password volumes: - mysql-data:/var/lib/mysql environment: MYSQL_USER: root MYSQL_ROOT_PASSWORD: password volumes: bundle: mysql-data:
- version:docker-composeのバージョン
- services:各コンテナの定義
- build:Dockerfileなどがあるパス
- volumes:コンテナ内とのマウント設定(ホスト側:コンテナ側)
- command:コンテナ立ち上げの際実行するコマンド
- ports:公開用ポート番号(ホスト側:コンテナ側)
- links:コンテナを他のサービスとリンクする
- image:実行時に元となるイメージ
- environment:環境変数
これで、準備は完了です。
[rails_hello] $ tree . ├── Dockerfile ├── Gemfile ├── Gemfile.lock └── docker-compose.yml
Rails アプリの作成
docker-compose run
コマンドを用いて、rails new
します。
[rails_hello] $ docker-compose run web rails new . --force --database=mysql
コンテナ内でrails new
コマンドが実行されrails_helloフォルダに見慣れたファイルが生成されていると思います。
[rails_hello] $ tree . ├── Dockerfile ├── Gemfile ├── Gemfile.lock ├── README.md ├── Rakefile ├── app │ ├── assets │ │ ├── config │ │ │ └── manifest.js │ │ ├── images │ │ └── stylesheets │ │ └── application.css ...
イメージのビルド
作成されたRailsアプリのコンテナイメージを作成します。
[rails_hello] $ docker-compose build
完了したら、イメージが作成されたか確認しましょう。
[rails_hello] $ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
rails_hello_web latest 28d0517f43e7 About a minute ago 517MB
webpackのインストール
Rails6からwebpackが必要になるのでインストールをします。
[rails_hello] $ docker-compose run web bundle exec rails webpacker:install
DB接続設定
mysqlコンテナに接続できるように、設定をします。
./config/database.yml
default: &default adapter: mysql2 encoding: utf8mb4 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: password host: db development: <<: *default database: rails_hello_development test: <<: *default database: rails_hello_test production: <<: *default database: rails_hello_production username: rails_hello password: <%= ENV['RAILS_HELLO_DATABASE_PASSWORD'] %>
コンテナの起動
実際にコンテナを起動してみましょう!
[rails_hello] $ docker-compose up
Creating network "rails_hello_default" with the default driver
Creating volume "rails_hello_mysql-data" with default driver
Creating rails_hello_db_1 ... done
Creating rails_hello_web_1 ... done
Attaching to rails_hello_db_1, rails_hello_web_1
db_1 | Initializing database
...
コマンド実行したら、http://localhost:300にアクセスしましょう。
「DBexiが無い!」って怒らていますね。(作ってないので当然^^;;)
DB作成
docker-compose exec
コマンドで、Railsコンテナに入りDBを作成します。
[rails_hello] $ docker-compose exec web ash
ログインシェルコマンドを指定することで、コンテナ内に入り込むことが可能になります。
※使用するイメージで使えたり使えなったりするので、注意が必要です。
コンテナ内で、DB作成コマンドを実行しましょう。
/rails_hello # rails db:create
Created database 'rails_hello_development'
Created database 'rails_hello_test'
それでは、http://localhost:3000にアクセスしましょう。
これで、完了です!
本番用 Rails イメージの作成
ここで、AWSで実行するRailsコンテナイメージを作成します。
Dockerfileの作成
containers/appフォルダを作成してそこに、本番用Dockerfileを作成します。
[rails_hello] $ mkdir -p containers/app
./containers/app/Dockerfile
FROM ruby:2.7.1-alpine3.12 ENV TZ=Asia/Tokyo \ RAILS_ENV=production RUN apk add --no-cache build-base libxml2-dev libxslt-dev \ tzdata ca-certificates mysql-dev mysql-client \ imagemagick imagemagick-dev imagemagick-c++ && \ gem install bundler WORKDIR /rails_hello RUN mkdir -p tmp/sockets ADD Gemfile /rails_hello/Gemfile ADD Gemfile.lock /rails_hello/Gemfile.lock RUN bundle config set without 'test development' && \ bundle install ADD . /rails_hello CMD bundle exec puma -C config/puma.rb
- ENV:環境変数
docker-compose.prod.ymlの作成
本番用のdocker-compose.ymlファイルも作成しておきます。
./containers/docker-compose.prod.yml
version: '3' services: app: image: rails_hello/app container_name: rails_hello_app build: context: ../ dockerfile: ./containers/app/Dockerfile command: bundle exec puma -C config/puma.rb volumes: - tmp:/rails_hello/tmp volumes: tmp:
- context:ビルド実行パス
- dockerfile:contextパスからDockerfileの指定
アセットパイプライン
Railsのproduction環境では、imageやjs、cssなどをコンパイルしておく必要があります。
イメージのビルド前に、コンパイルしておきます。
[rails_hello] $ docker-compose run web bundle exec rails <span>assets:precompile</span>
完了すると、public配下に jsファイルが生成されいると思います。
DB接続設定
本番用のDB接続設定をしておきましょう。
./config/database.yml
default: &default adapter: mysql2 encoding: utf8mb4 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: password host: db development: <<: *default database: rails_hello_development test: <<: *default database: rails_hello_test production: <<: *default database: <%= ENV['RDS_DB_NAME'] %> username: <%= ENV['RDS_USERNAME'] %> password: <%= ENV['RDS_PASSWORD'] %> host: <%= ENV['RDS_HOST'] %> port: <%= ENV['RDS_PORT'] %>
ページ作成
軽く新しいページを作成しましょう。
./app/views/home/index.html.erb
<h1>rails_hello</h1>
./app/views/layout/application.html.erb
<!DOCTYPE html> <html> <head> <title>RailsHello</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <%= csrf_meta_tags %> <%= csp_meta_tag %> <h1>HELLO</h1> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> </head> <body> <%= yield %> </body> </html>
./app/controllers/home/index_controller.rb
class HomeController < ApplicationController def index end end
./config/routes.rb
Rails.application.routes.draw do # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html root to: "home#index" end
コンテナ起動するとこのような画面が表示されると思います。
イメージのビルド
docker-compose.prod.yml を元にイメージをビルドします。
[rails_hello] $ docker-compose -f containers/docker-compose.prod.yml build
-f:composeファイルを指定
完了したら、イメージが作成されたか確認しましょう。
[rails_hello] $ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
rails_hello/app latest 0e84d88149e4 About a minute ago 636MB
rails_hello_web latest 28d0517f43e7 30 minute ago 517MB
これで、本番用のRailsイメージは完了です!
Nginx イメージの作成
こちらは、ローカルで使用しないので本番用のみ準備します。
ngxin 設定ファイルの作成
設定ファイルである confファイルを作成します。
./containers/nginx/nginx.conf
upstream rails_hello { # Fargateはポートマッピングでいける server 127.0.0.1:3000; } server { listen 80; server_name .*; access_log /dev/stdout main; error_log /dev/stderr warn; root /var/www/rails_hello/public; # アップロードできるファイルの最大サイズ client_max_body_size 100m; error_page 404 /404.html; error_page 505 502 503 504 /500.html; try_files $uri/index.html $uri @rails_hello; location /health { try_files $uri @rails_hello; satisfy any; allow all; } location @rails_hello { proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://rails_hello; } }
1行目の、upstream
のservser
はECSの起動タイプで変わるの注意が必要です。
Dockerfileの作成
containers/nginxフォルダを作成してそこに、Dockerfileを作成します。
./containers/nginx/Dockerfile
FROM nginx:1.17-alpine # インクルード用のディレクトリ内を削除 RUN rm -f /etc/nginx/conf.d/* # Nginxの設定ファイルをコンテナにコピー ADD nginx.conf /etc/nginx/conf.d/default.conf # ビルド完了後にNginxを起動 CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf
イメージのビルド
Nginxイメージは、ECRにpushする際にビルドしますので今は飛ばして大丈夫です。
ECR へpush
今まで作成した、イメージをECRへpushします。
レポジトリの作成
Rails と Nginx のpush先レポジトリを作成します。
[rails_hello] $ aws ecr create-repository --repository-name rails_hello
[rails_hello] $ aws ecr create-repository --repository-name nginx
作成されたかの確認しましょう。
[rails_hello] $ aws ecr describe-repositories --query <span class="s1">'repositories[].repositoryName'
[
"rails_hello",
"nginx"
]</span>
push 先のレポジトリ設定
環境変数にてレポジトリを設定します。
[rails_hello] $ export ECR_URI_RAILS_HELLO=$(aws ecr describe-repositories --repository-names rails_hello --query 'repositories[0].repositoryUri' --output text)
[rails_hello] $ echo ${ECR_URI_RAILS_HELLO}
<account id>.dkr.ecr.-1.amazonaws.com/rails_hello
[rails_hello] $ export ECR_URI_NGINX=$(aws ecr describe-repositories --repository-names nginx --query 'repositories[0].repositoryUri' --output text)
[rails_hello] $ echo ${ECR_URI_NGINX}
<account id>.dkr.ecr.<region>.amazonaws.com/nginx
Nginx イメージのビルド
ここで、Nginx イメージのビルドをします。
[rails_hello] $ docker build -t ${ECR_URI_NGINX} -f containers/nginx/Dockerfile .
ビルドできたらNginxイメージは完了です。
ECRへログイン
aws cliのバージョンが1系なら、$(aws ecr get-login --no-include-email)
このコマンドでログインできますが、2系から変わり以下のコマンドでログインできます。
[rails_hello] $ aws ecr get-login-password | docker login --username AWS --password-stdin https://<account id>.dkr.ecr.<region>.amazonaws.com
Login Succeeded
イメージのpush
[rails_hello] docker push ${ECR_URI_RAILS_HELLO}
[rails_hello] docker push ${ECR_URI_NGINX}
pushされているのが確認できましたね。
おわり
これで、Rails + Nginxな環境をECSで実行する準備が整いました。お疲れさまでした!
何か疑問に思うことがあれば、何でもコメントしてください!
次回は、いよいよ最後Rails+NginxをECS Fargateでデプロイします。
コメント