Androidはワンツーパンチ 三歩進んで二歩下がる

Android卵プログラマーの記録ブログ

【5】GCP(GCE)でRailsアプリを外部IPアドレス+3000番ポートで動かしてみる(環境変数COMPOSE_FILE、GCE+Docker+Rails+Puma+PostgreSQL)

これはHerokuからGCP無料枠にRailsアプリを引越ししたときにやったことシリーズの【4】の続きです。
GCE に 作成した VM インスタンス上で Rails アプリを動かしてみるところのメモです。
http://localhost:3000/ でテストしていたものをそのまま GCE に持っていって動かすようなことをします。

1. 公式サイト

Compose CLI environment variables | Docker Documentation
Reference documentation | Docker Documentation
Overview of Docker Compose | Docker Documentation
ファイアウォール ルールの概要  |  VPC  |  Google Cloud

2. 目標

  • 環境変数 COMPOSE_FILE を GCE に設定して複数ある環境用の docker-compose.yml を読み込めるようにする
  • 3000 番ポートを開ける
  • Docker Compose コマンドを実行して Rails アプリが動くのを確認する

3. 注意点

  • Docker は勉強中ですので、Dockerfile や docker-compose.yml などはとりあえず動くことを確認するもの程度に考えていただければと思います。

  • 作業対象である Rails アプリ「ポケット糖質量」のデータは csv ファイルから投入すれば出来上がり、しかも ReadOnly なデータです。
    ほとんどソースコードの一部のようなものなので、DB をコンテナの外に設定していません。
    コンテナを消せば DB もすべて消えてしまいます。
    アプリの仕様によりこのような環境になっておりますので、参考にする時はご注意ください。

4. 参考サイト様

本当に参考になりました。ありがとうございます!

docker-compose.yml が環境別に複数ある場合は COMPOSE_FILE を定義しておくと幸せになれる

5. 環境変数 COMPOSE_FILE を GCE に設定して複数ある環境用の docker-compose.yml を読み込めるようにする

参考サイト様によると、 環境ごとに別名で作ってある docker-compose.yml を-fオプション無しで使う方法として環境変数 COMPOSE_FILE を設定すればよいということですので、設定してみたいと思います。
例として次の 2 つの環境用のファイルを用意します。

stage ファイル名
development docker-compose.development.yml
production docker-compose.production.yml

なお docker-compose.yml を用意しておいて共通の処理を書いておき、各環境用ファイルは差分を書いておくことで AND 合体されるというやり方もできるようです。

5.1. コマンドで環境変数 COMPOSE_FILE を設定する(一時的)

exportコマンドを使ってファイル名を COMPOSE_FILE 変数に入れます。
2 行目は COMPOSE_FILE 変数の中身を表示しています。

この方法はログアウトしてログインし直すと COMPOSE_FILE 変数自体消えてしまいます。

$export COMPOSE_FILE=docker-compose.development.yml
$env | grep COMPOSE_FILE

5.2. bashrc に環境変数 COMPOSE_FILE を設定する(永続的)

.bashrc を編集して環境変数 COMPOSE_FILE を設定します。
ログアウトしても COMPOSE_FILE 変数の設定はそのままです。

$nano ~/.bashrc

エディタを起動したら次の例のように書き加えます。

# docker-composeのデフォルトComposeファイルを本番用に設定
export COMPOSE_FILE=docker-compose.production.yml

保存後、次のように実行します。

$source ~/.bashrc

これでいつでも$env | grep COMPOSE_FILEを実行すると設定したファイル名が表示されると思います。

f:id:sakura_bird1:20190306155728p:plain:w400

6. 3000番ポートを開ける

GCE のインスタンスファイアウォールルールを設定して、Rails のデフォルトポート番号である 3000 番のポートを開ける処理を行います。

ポートを開ける処理はこのシリーズ記事の
【2】GCP(GCE)で無料の VM インスタンスを作る(Always Free 無料枠、外部 IP アドレス取得、SSH 接続、22 番ポート対応)
でも記述しております。

6.1. ファイアウォールルールの作成

ナビゲーションメニューから「ネットワーク詳細の表示」を選択します。

f:id:sakura_bird1:20190307015052p:plain:w400

ファイアウォールルール」→「ファイアウォールルールを作成」をクリックします。

f:id:sakura_bird1:20190307015159p:plain:w400

次の項目を設定します。

入力項目 内容
名前 デフォルトのルールにならって、 allow-3000 (3000 はポート番号)にするとよい
ターゲットタグ デフォルトのルールにならって、 allow3000-server にするとよい
ソース IP の範囲 0.0.0.0/0
プロトコルとポート 指定したプロトコルとポートをクリックし tcp のところに 3000 を入力する

f:id:sakura_bird1:20190307015409p:plain:w400

f:id:sakura_bird1:20190307015435p:plain:w400

入力し終えたら「保存」を押して追加されたのを確認します。 ここで入力したターゲットタグをインスタンスのネットワークタグに追加します。

VM インスタンスの詳細」→「編集」画面でターゲットタグを追加します。

f:id:sakura_bird1:20190307015532p:plain:w400

GCE 側の設定はこれでできました。

7. Docker Compose コマンドを実行して Rails アプリが動くのを確認する

このエントリの題名に「GCE+Docker+Rails+Puma+PostgreSQL」と書いてありますが、GCE と Docker 以外はローカルで Rails5 でrails newした時の構成とほとんど同じです。
DB が PostgreSQL になってるところぐらいが違うでしょうか。
http://localhost:3000/ でテストしていたものをそのまま GCE に持っていって動かすようなイメージで動作確認してみたいと思います。

前提としてアプリのソースコードが入ったプロジェクトディレクトリは VM 上にコピー済みとします。

環境変数 COMPOSE_FILEはdevelopmentをセットしておきます。

7.1. Dockerfile

Dockerfile は必死でググってこんな感じにしました。内容の説明は割愛させていただきます。

FROM ruby:2.5.3-alpine3.8
LABEL maintainer="My Name" Name=pocket_carbo Version=0.0.1

ENV LANG C.UTF-8

ENV APP_PATH /usr/src/app

WORKDIR $APP_PATH

COPY Gemfile $APP_PATH
COPY Gemfile.lock $APP_PATH

ENV RUNTIME_PACKAGES="libxml2-dev libxslt-dev libstdc++ bash tzdata postgresql-dev postgresql-client nodejs ca-certificates"\
  DEV_PACKAGES="build-base"

RUN set -x && \
  apk add --update --no-cache $RUNTIME_PACKAGES &&\
  apk add --update\
  --virtual build-dependencies\
  --no-cache\
  $DEV_PACKAGES &&\
  gem install bundler --no-document &&\
  bundle config build.nokogiri --use-system-libraries &&\
  bundle install &&\
  apk del build-dependencies && \
  cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
  rm -rf /var/cache/apk/*

COPY . APP_PATH

EXPOSE 3000

7.2. docker-compose.yml

この時点での docker-compose.development.yml ファイルはこんな感じです。

version: '3'
services:
  db:
    image: postgres:11.1-alpine
    ports:
      - '5432'
    volumes:
      - db-data:/var/lib/postgresql/data
  web:
    build: .
    command: bash -c "rm -f ./tmp/pids/server.pid; bundle exec rails s -p 3000 -b '0.0.0.0'"

    volumes:
      - .:/usr/src/app
      - bundle-data:/bundle
    environment:
      RAILS_ENV: development
    ports:
      - "3000:3000"
    depends_on:
      - db

volumes:
  bundle-data:
  db-data:

7.3. /config/database.yml

この時点での/config/database.yml はこんな感じです。
staging は結局環境を作らなかったんですが、定義だけしてあります。
DB が外部ではないのでコンテナを削除するとデータも全てなくなります。

default: &default
adapter: postgresql
encoding: utf8
# For details on connection pooling, see rails configuration guide
# http://guides.rubyonrails.org/configuring.html#database-pooling
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
host: db
username: postgres
password:

development:
<<: *default
database: db/pocket_carbo_development

test:
<<: *default
database: db/pocket_carbo_test

staging:
<<: *default
database: db/pocket_carbo_staging

production:
<<: *default
database: db/pocket_carbo_production

7.4. docker-compose コマンドでビルド&起動

これらのコマンドを実行していきます。
自分が実行する時はスクリプトファイルを実行する形にしてますが、あまりイケてないですね。
私のアプリでは初期データ投入が必要なのでrails db:seedしています。

#!/usr/bin/env bash

docker-compose build

docker-compose run --rm web bin/rails db:create
docker-compose run --rm web bin/rails db:migrate
docker-compose run --rm web bin/rails assets:precompile
docker-compose run --rm web bin/rails db:seed

docker-compose up -d

うまくいけばhttp://[外部IPアドレス]:3000でアプリ画面が表示されます。

f:id:sakura_bird1:20190307043046p:plain:w500

今回は以上です。
このシリーズでは今後独自ドメインで表示、SSL対応をするのでdocker-compose.ymlは変わっていきます。
次回は今回動かしたアプリをhttps+独自ドメインでアクセス出来るようにするための下準備として、テスト用の独自ドメインを取得してDNSサーバーの設定をして動かしてみます。

8. 関連リンク