Dockerとは何なのか?の続きです。この記事では偉そうにDockerに付いて解説しましたが、実はEY-Officeの開発環境はDocker化されていませんでした。私はDockerについてはこのブログ記事のように2014年には試していました、また仕事でDockerを使った環境での開発も行っていました。
しかし、EY-Office主体のECサイトの開発環境等ではDockerを使っていませんでした。理由はこのブログ記事のように初期のDockerに触れて必ずしも良くなイメージを持っていました。またMac上での開発環境に問題もなかったので、ずっとDockerを使わずに来てしまいました。
その間に、Docker Desktop for Mac / Docker Desktop for Windows のような便利なDocker環境が現れ、 CircleCI、GitHub ActionsのようにDockerを基本としたCI/CDサービスなども現れ、世の中はどんどんDockerへと向かっていました。
私もこれはヤバイなと思いながらも、なかなかDockerへと舵が切れずにいました。しかし、GitHub ActionsでCI環境を作るという目標ができたので、ECサイトの開発環境をDockerに移行し始めました。
https://www.flickr.com/photos/134416355@N07/31518965950
Dockerとは何なのか?の続き
Dockerとは何なのか?ではDockerの原理、Dockerイメージなどを説明しましたが、今回はさらにいくつかのトピックを説明したいと思います。
Dockerfile
Dockerイメージの作成手順を記述したものがDockerfileです。Dockerfileには
- どのDockerイメージを元にするかの FROM
- Docker内でプログラムのインストール、ディレクトリー作成等のコマンドを実行する RUN
- Dockerを起動しているMac / PCからファイル等のコピーを行う ADD 、COPY
- 環境変数の設定を行う ENV
などが書かれています。下の「開発・テスト環境の構築」にDockerfileの例を説明しています。Dockerの作成・管理を行うコマンドはdocker
です。
Docker Compose
DockerはLinuxですから多数のサーバープログラムを動かすことも可能ですが、管理のし易さ、サーバーを並べてスケーラビリティーを上げたり、可用性を高める事を考え1つのDocker上では1つのサーバーを動かす事が多いです。
たとえばECサイトのようなサービスでは、RDB、アプリケーション(例、Ruby on Rails)、Webサーバー(例、Nginx)、高速化のためのキャッシュ(例、Redis)に分ます。
複数のDockerが連携して動かすために管理や、各Dockerの設定情報を管理するものがDocker Composeです。設定ファイルのデフォルトは docker-compose.yml
で、コマンドはdocker-compose
です。
Kubernetes (k8s)
多数のDockerを使った、大規模なシステムを運用、デプロイなどを行う標準規格です。 詳しくはKubernetesとは何か? を読んでください。
開発・テスト環境の構築
Docker構成
現在、Dockerへ移行中のECサイトの開発環境のに付いて簡単に説明します。このサイトはRuby on Rails + PostgreSQL (+ Nginx)で構成されています。開発環境ではNginxは不要なので、DockerはPostgreSQL(名前 pg)とRuby on Rails(名前 rails)の2つになります。
PostgreSQL用Dockerは、PostgreSQLと全文検索のPGroongaのみなので、PGroonga開発チームの公開するDockerイメージ を利用する事にしました。このDockerはデータベースのみなのでLinuxディストリビューションは軽量なAlpineにしました。
Ruby on Rails用DockerはRuby、Ruby on Railsに加え多数のGem、いつかのコマンドが必要なので、Dockerfileを書いて独自に構築しました。またDocker利用時の起動時間短縮のため、DockerイメージはDockerHubに保存しました、Rails等をバージョンアップした際にはイメージは構築し直しになりますが、もうメンテ状態なので頻繁にはなく問題はないと思います。
- docker/rails/Dockerfile
- FROM: で判るようにRuby 2.6、Linuxディストリビューションは実行環境のUbuntuに近いDebianを元に作っています
- いくつかのコマンドやテストで使うphantomjsをインストールしています
- 日本語の全文検索などを行うので、日本語環境にしています、またタイムゾーンも日本語にしています
- COPYで開発環境のGemfile, Gemfile.lockをコピーしGemをインストールしています
- ruby:2.6-stretchに入っているbundlerは1.Xなので2.1.4をインストールしています
FROM ruby:2.6-stretch
RUN apt-get update && \
apt-get install -y locales-all postgresql-client-9.6 tidy --no-install-recommends && \
rm -rf /var/lib/apt/lists/* && \
curl -L https://github.com/Medium/phantomjs/releases/download/v2.1.1//phantomjs-2.1.1-linux-x86_64.tar.bz2 | tar xj -C /tmp && \
cp /tmp/phantomjs-2.1.1-linux-x86_64/bin/phantomjs /usr/local/bin && \
rm -rf /tmp/phantomjs-2.1.1-linux-x86_64 && \
mkdir -p /usr/src/app
WORKDIR /usr/src/app
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
ENV TZ Asia/Tokyo
COPY ./Gemfile /usr/src/app
COPY ./Gemfile.lock /usr/src/app
RUN gem install bundler -v 2.1.4
RUN bundle install
EXPOSE 3000
- Dockerの作成手順は以下のようになります
- Dockerイメージ名は今のところ伏せておきます
docker build
でイメージを構築しますdocker tag
でRailsのバージョンをTAGに設定しますdocker push
でDockeHubに保存します
$ docker build -t xxxx/ruby_rails_xxxx -f docker/rails/Dockerfile .
$ docker tag <IMAGE-ID> xxxx/ruby_rails_xxxx:5.2.4.3
$ docker push xxxx/ruby_rails_xxxx:5.2.4.3
docker-compose
以下がpg, rails用Dockerを使い、開発環境を起動するdocker-composeの設定です
- docker-compose.yml
- rails用DockerはMac上の開発環境
.
をDockerの/usr/src/app
にマウントし、プログラムのコードはMac上のファイルを使います、これによりMac上のエディター(VSCode)でコードの編集が行えます - おなじみのポート3000をアクセスすればRailsが起動します
- command: でDocker上でコマンドを実行します
- Railsのpidファイルが残る事もあるので削除
- wait-for-it.shでPostgreSQLが起動するまで待ちます、depends_onでpgを指定していますがPostgreSQLが起動前にDB操作が動くのを防いでいます
- set_seed_db.shで開発環境用データを取り込んでいます、テーブル作成等もここで行われます
- 最後にrailsを起動
- pg用Dockerの設定は
- Dockerイメージは
groonga/pgroonga:latest-alpine-12-slim
- あまり使わないですが、Macからポート5433でこのPostgreSQLにアクセスできるよう設定
- rails用Dockerenvironmentで日本語環境に設定
- POSTGRES_USER、POSTGRES_PASSWORDでPostgreSQL管理アカウントの設定
- volumesでPostgreSQL起動時に実行されるSQLファイルを指定。この中で開発、テスト用データベース、アカウントの作成、PGroonga用extention作成を行っています
- Dockerイメージは
- rails用DockerはMac上の開発環境
version: "3"
services:
rails:
container_name: rails
image: xxxxx/ruby_rails_xxxx:5.2.4.3
environment:
- PGHOST=pg
- PGPASSWORD=xxxxxx
ports:
- "3000:3000"
volumes:
- ".:/usr/src/app"
depends_on:
- pg
command: bash -c "
rm -f /usr/src/app/tmp/pids/server.pid &&
./docker/bin/wait-for-it.sh pg:5432 --
./tools/set_seed_db.sh &&
./bin/rails server -b 0.0.0.0"
pg:
container_name: pg
image: groonga/pgroonga:latest-alpine-12-slim
ports:
- "5433:5432"
environment:
- LANG=ja_JP.UTF-8
- LANGUAGE=ja_JP:ja
- LC_ALL=ja_JP.UTF-8
- TZ=Asia/Tokyo
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=xxxxxxxx
volumes:
- ./docker/pg/init:/docker-entrypoint-initdb.d
- 開発用Dockerの起動は以下のようになります
- 必要があれば
docker-compose logs
でログを表示
- 必要があれば
$ docker-compose up -d
$ docker-compose logs rails
- テスト用Dokerの
docker-compose.test.yml
docker-compose.yml
との差分が書かれています。起動コマンドが開発環境とは違い- PostgreSQL待ち
- テスト用DBのマイグレーション実行
- Model, Controller等のRSpec実行
- 管理画面のfeature specを実行
- 本当はこの後にE2Eテストを実行するのですが、現在対応中
version: "3"
services:
rails:
command: bash -c "
./docker/bin/wait-for-it.sh pg:5432 --
rake tmp:create &&
rake db:migrate RAILS_ENV=test &&
rspec spec &&
rspec spec/features/*.rb"
テスト用Dokerのを起動するには作成手順は以下のようになります。 docker-compose.test.yml
には差分しか書いてないので、docker-compose.yml
も指定します。
$ docker-compose -f docker-compose.yml -f docker-compose.test.yml up
GitHub Actions
GitHub Actionsでテストを実行するワークフローファイルは以下のようになります。docker-compose.yml
に似ていますが微妙に違い苦労しました。
.github/workflows/main.yml
- on: はテスト(CI)を起動する設定
- scheduleは時間指定、ここでは1時間に1回
- workflow_dispatch: inputs: はGitHubページにあるボタンからの起動、ワークフロー開発時に便利です
- jobs: は
docker-compose.yml
に似ているので、解説なしでほぼわかるかと思います${{ github.workspace }}
はテストを行う作業用ディレクトリーがわかる変数です。GitHub Actionsのvolumesは絶対パスで指定しないといけないようです- Dockerイメージはpublicなものしか指定できません、少し困っています
- pg:にはvolumes:を指定していませんが、pg:が起動される時点ではまだコードがチェックアウトされてないからです
- steps: に実行コマンドを書きます
uses: actions/checkout@v2
でGitHubからコードのチェックアウトが行われます、ブランチはwith: ref: で指定します- run: で実行するコマンドを指定します
- PostgreSQLのテスト用データベース等の作成はこの時点で行っています
- 後のマイグレーション、RSpecの実行は
docker-compose.yml
と同様です
- on: はテスト(CI)を起動する設定
name: CI
on:
schedule:
- cron: '0 * * * *'
workflow_dispatch:
inputs:
jobs:
build:
runs-on: ubuntu-latest
container:
image: xxxx/ruby_rails_xxxx:5.2.4.3
env:
PGHOST: pg
PGPASSWORD: xxxxx
RAILS_ENV: test
volumes:
- ${{ github.workspace }}:/usr/src/app
services:
pg:
image: groonga/pgroonga:latest-alpine-12-slim
env:
LANG: ja_JP.UTF-8
LANGUAGE: ja_JP:ja
LC_ALL: ja_JP.UTF-8
TZ: Asia/Tokyo
POSTGRES_USER: postgres
POSTGRES_PASSWORD: xxxxxx
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- name: fetch from GitHub
uses: actions/checkout@v2
with:
ref: docker
- name: create DB
run: PGPASSWORD=xxxxxx psql -U postgres -f docker/pg/init/1_init.sql
- name: create tmp
run: rake tmp:create
- name: DB migration
run: rake db:migrate
- name: Run rspec models, controller, helper
run: rspec spec
- name: Run rspec admin feature
run: rspec spec/features/*.rb
まとめ
いろいろと苦労しましたが、Dockerベースの開発環境とGitHub ActionsのCI環境がだいたいできました。 Dockerベースの開発環境もCI環境は安定して動いています。
開発環境が簡単に短時間で作れるのには感動的です、まだDockerに不慣れで悩む事も多いですが、Dockerベースに移行して良かったと思います。Dockerアレルギーもすっかり無くなりました ^^)/