【Docker/ECR作成】terraform AWS環境構築 第6回

AWS

AWSRails + Nginxな環境をTerraformで構築してみようと思います。

はじめに

本連載で一つずつインフラを構築していきます。

ドメインのhttps化したり、ECS Fargateを使用したコンテナオーケストレーションを用いてアプリケーションをデプロイします。

この記事ではRailsとNginxDockerイメージを作成してECRにpushをします。

環境は以下です。

OS Cataline 10.15.6
Terraform 0.14.4

 

 

 

基本構文などこちらにまとめてますので、よかったらみてください!
AWS Terraform 基本コード まとめ

連載一覧

やること

以下の作成します。

  • ローカル用 Rails イメージの作成
  • 本番用 Rails イメージの作成
  • Nginx イメージの作成
  • ECR へpush

Dockerイメージ作成

今回使用する作業フォルダを作成しておきましょう。

$ mkdir rails_hello
$ cd rails_hello

ローカル用 Rails イメージの作成

必要なファイルの準備

Dockerfileの作成

rails_helloフォルダ内でDockerイメージを構築するDockerfileを作成します。

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の作成

docker-composeドキュメント

アプリケーションを構成する各サービスを定義し、実行するためのファイルです。

ここでは、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の指定
アセットパイプライン

Railsproduction環境では、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行目の、upstreamservserは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イメージは、ECRpushする際にビルドしますので今は飛ばして大丈夫です。

ECR へpush

今まで作成した、イメージをECRpushします。

レポジトリの作成

Rails Nginxpush先レポジトリを作成します。

[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+NginxECS Fargateでデプロイします。

参考サイト

DockerでRuby on Railsの環境構築を行うためのステップ【Rails 6対応】

コメント

タイトルとURLをコピーしました