M1 MacにDockerでRuby on Rails 6を構築する
はじめに
Zennでの初投稿です。ふだんは業務委託でRailsアプリを開発したりしてますが、Dockerfileとかコピペして使い回ししてるので改めて備忘録を兼ねて1から手順を確認しながらまとめてみます。
M1 MacにDocker Desktopをインストールし、Docker Composeで環境を構築します。
環境
使用機材はMacBook Air (M1, 2020)でmacOS Montereyです。
sw_vers
ProductName: macOS
ProductVersion: 12.6
BuildVersion: 21G115
Docker Desktopのバージョン
Dockerfileを作る前に調査
公式のDockerfile best practicesでお薦めされているAlpine Linuxを使用します。
Dockerfileを作る前にruby:3.1.2-alpine3.16のイメージがどういう環境なのかざっと確認しました。
docker run -it --rm ruby:3.1.2-alpine3.16 /bin/sh
まずは基本的な情報を確認します。
uname -a
Linux feae492f77e3 5.10.124-linuxkit #1 SMP PREEMPT Thu Jun 30 08:18:26 UTC 2022 aarch64 Linux
ホストがM1 Macなためaarch64
になっています。
cat /etc/os-release
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.16.2
PRETTY_NAME="Alpine Linux v3.16"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"
次に環境変数を確認します。
env
環境変数
RUBY_MAJOR=3.1
HOSTNAME=31cbf56488fe
SHLVL=1
HOME=/root
BUNDLE_APP_CONFIG=/usr/local/bundle
RUBY_VERSION=3.1.2
TERM=xterm
PATH=/usr/local/bundle/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
LANG=C.UTF-8
GEM_HOME=/usr/local/bundle
RUBY_DOWNLOAD_SHA256=ca10d017f8a1b6d247556622c841fc56b90c03b1803f87198da1e4fd3ec3bf2a
PWD=/
BUNDLE_SILENCE_ROOT_WARNING=1
最後に初期インストールされているパッケージの一覧を確認します。
apk info -v
パッケージ一覧
alpine-baselayout-data-3.2.0-r22
musl-1.2.3-r0
busybox-1.35.0-r17
alpine-baselayout-3.2.0-r22
alpine-keys-2.4-r1
ca-certificates-bundle-20220614-r0
libcrypto1.1-1.1.1q-r0
libssl1.1-1.1.1q-r0
ssl_client-1.35.0-r17
zlib-1.2.12-r3
apk-tools-2.12.9-r3
scanelf-1.3.4-r0
musl-utils-1.2.3-r0
libc-utils-0.7.2-r3
bzip2-1.0.8-r1
ca-certificates-20220614-r0
gmp-6.2.1-r2
libgcc-11.2.1_git20220219-r2
libstdc++-11.2.1_git20220219-r2
libgmpxx-6.2.1-r2
pkgconf-1.8.0-r1
gmp-dev-6.2.1-r2
linux-headers-5.16.7-r1
libffi-3.4.2-r1
libffi-dev-3.4.2-r1
libintl-0.21-r2
ncurses-terminfo-base-6.3_p20220521-r0
ncurses-libs-6.3_p20220521-r0
libproc-3.3.17-r1
procps-3.3.17-r1
yaml-0.2.5-r0
yaml-dev-0.2.5-r0
zlib-dev-1.2.12-r3
readline-8.1.2-r0
.ruby-rundeps-20221007.071338
各ファイルの作成
まず、ホストのMacに作業用のディレクトリを作成し移動します。
mkdir docker_rails && cd $_
このディレクトリにQuickstart: Compose and Railsを参考に各ファイルを作成します。
- Gemfile
- Gemfile.lock
- Dockerfile
- docker-compose.yml
- 環境変数を設定する.envファイル
- .envをバージョン管理の対象外とする.gitignore
1. Gemfile
Gemfileはrails
だけ指定します。後でrails new
すると置き換わります。
vi Gemfile
source 'https://rubygems.org'
gem 'rails', '~> 6.1.7'
2. Gemfile.lock
Gemfile.lockはDockerfileでCOPY
できればいいので空の状態で作成します。
touch Gemfile.lock
3. Dockerfile
Docker DesktopでCPUsを4にしているのでBundlerのジョブ数も4にしています。aarch64なのでlibc6-compat
がないとnokogiri
gemなどでld-linux-aarch64.so
が存在しないというエラーが発生します。tzdata
はtzinfo-data
gemで必要です。tzdata
がないとエラーが発生します[1]。
vi Dockerfile
FROM ruby:3.1.2-alpine3.16
ENV TZ=Asia/Tokyo
ENV APP_ROOT /sample_app
RUN mkdir -p ${APP_ROOT}
WORKDIR ${APP_ROOT}
COPY Gemfile Gemfile.lock ${APP_ROOT}/
RUN apk update && apk add --no-cache \
libc6-compat \
nodejs \
postgresql-client \
tzdata \
yarn \
&& apk add --no-cache --virtual .build-dependencies \
build-base \
postgresql-dev \
&& bundle config set --jobs 4 \
&& bundle install \
&& apk del .build-dependencies
COPY . ${APP_ROOT}
参考まで
build-baseでインストールされるパッケージ
(1/16) Installing binutils (2.38-r3)
(2/16) Installing libmagic (5.41-r0)
(3/16) Installing file (5.41-r0)
(4/16) Installing libgomp (11.2.1_git20220219-r2)
(5/16) Installing libatomic (11.2.1_git20220219-r2)
(6/16) Installing isl22 (0.22-r0)
(7/16) Installing mpfr4 (4.1.0-r0)
(8/16) Installing mpc1 (1.2.1-r0)
(9/16) Installing gcc (11.2.1_git20220219-r2)
(10/16) Installing musl-dev (1.2.3-r0)
(11/16) Installing libc-dev (0.7.2-r3)
(12/16) Installing g++ (11.2.1_git20220219-r2)
(13/16) Installing make (4.3-r0)
(14/16) Installing fortify-headers (1.1-r1)
(15/16) Installing patch (2.7.6-r7)
(16/16) Installing build-base (0.5-r3)
Executing busybox-1.35.0-r17.trigger
OK: 209 MiB in 51 packages
postgresql-devでインストールされるパッケージ
(1/16) Installing libpq (14.5-r0)
(2/16) Installing openssl-dev (1.1.1q-r0)
(3/16) Installing libpq-dev (14.5-r0)
(4/16) Installing libecpg (14.5-r0)
(5/16) Installing libecpg-dev (14.5-r0)
(6/16) Installing xz-libs (5.2.5-r1)
(7/16) Installing libxml2 (2.9.14-r1)
(8/16) Installing llvm13-libs (13.0.1-r2)
(9/16) Installing clang-libs (13.0.1-r1)
(10/16) Installing clang (13.0.1-r1)
(11/16) Installing icu-data-en (71.1-r2)
Executing icu-data-en-71.1-r2.post-install
*
- If you need ICU with non-English locales and legacy charset support, install
- package icu-data-full.
(12/16) Installing icu-libs (71.1-r2)
(13/16) Installing icu (71.1-r2)
(14/16) Installing icu-dev (71.1-r2)
(15/16) Installing llvm13 (13.0.1-r2)
(16/16) Installing postgresql14-dev (14.5-r0)
Executing busybox-1.35.0-r17.trigger
OK: 493 MiB in 67 packages
4. docker-compose.yml
PostgreSQLのパスワードは.env
で設定しenv_file
で指定します。後ほど.gitignore
に追加してバージョン管理の対象外とします。
vi docker-compose.yml
version: "3"
services:
db:
image: postgres:14.5
env_file:
- .env
environment:
TZ: Asia/Tokyo
volumes:
- db_volume:/var/lib/postgresql/data
ports:
- 5432:5432
web:
build: .
command: sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
environment:
RAILS_ENV: development
NODE_ENV: development
volumes:
- .:/sample_app
- bundle_volume:/usr/local/bundle
ports:
- "3000:3000"
tty: true
stdin_open: true
depends_on:
- db
volumes:
db_volume:
bundle_volume:
5. .env(PostgreSQLのパスワードの設定)
環境変数を設定するための.env
ファイルを作成し、任意のパスワードを設定します(後ほどdotenv-rails
gemを追加し.env
をRailsが認識するようにします)。
vi .env
POSTGRES_PASSWORD=任意のパスワード
6. .gitignore
上記の.envを追加してバージョン管理に含まれないようします。
echo '.env' >> .gitignore
ここまでの手順のソースコードはこちら
イメージのビルド
1. Railsアプリのスケルトンの作成
まず、rails new
で新しくRailsアプリケーションのスケルトンを作成します。
Dockerfileで不要なパッケージを削除するようにしているため(apk delの箇所
)、このタイミングでbundle install
するとエラーになりますのでスキップします(同じくWebpackもスキップされます[2])。また、今回はRedisやImageMagick、FFmpegなどを用意していないためAction CableとActive Storageもスキップしています。
docker compose run --no-deps web rails new . --force --database=postgresql --skip-bundle --skip-action-cable --skip-active-storage
2. 設定ファイルの編集
.gitignore
rails new
で置き換えられた.gitignore
にどこでもいいので.env
を追記します(ここではファイル末尾に追加しています)。
echo '.env' >> .gitignore
database.yml
config/database.ymlを設定します。defaultを変更してpasswordは環境変数から取得するようにします。
vi config/database.yml
default: &default
adapter: postgresql
encoding: unicode
host: <%= ENV.fetch('DATABASE_HOST') { 'db' } %>
username: postgres
password: <%= ENV.fetch('POSTGRES_PASSWORD') { '' } %>
pool: <%= ENV.fetch('RAILS_MAX_THREADS') { 5 } %>
また、productionからpasswordを削除します。
production:
<<: *default
database: sample_app_production
username: sample_app
- password: <%= ENV['SAMPLE_APP_DATABASE_PASSWORD'] %>
Gemfile
必要なgemを追加します。開発環境の環境変数を.env
ファイルで管理するためにgroup :development, :test do
のブロック内にdotenv-rails
gemを追加します。また、Ruby3.1でnet-smtp
gemが別になったのでこれも追加します。
vi Gemfile
+ gem "net-smtp"
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
+ gem "dotenv-rails"
end
3. bundle installの実行
web
で必要なパッケージを追加しつつbundle install
およびrails webpacker:install
を実行するため、sh
でweb
のコンテナに入ります。
docker compose run --no-deps web sh
apk update && apk add --no-cache --virtual .build-dependencies build-base postgresql-dev && bundle install && rails webpacker:install && apk del .build-dependencies
bundle install
とrails webpacker:install
が無事に終了したらexit
でコンテナから出ます。
exit
4. .dockerignoreの追加
Railsで重要なconfig/master.key
や不要なファイルがイメージに含まれないように.dockerignore
を追加します(rails new
で生成された.gitignore
を基にしています)。
vi .dockerignore
.DS_Store
.git
.gitignore
.dockerignore
Dockerfile
docker-compose.yml
*.env
docker
# Ignore bundler config.
.bundle
# Ignore all logfiles and tempfiles.
log/*
tmp/*
!log/.keep
!tmp/.keep
# Ignore pidfiles, but keep the directory.
tmp/pids/*
!tmp/pids/.keep
public/assets
.byebug_history
# Ignore master key for decrypting credentials and more.
config/master.key
public/packs
public/packs-test
node_modules
yarn-error.log
yarn-debug.log*
.yarn-integrity
5. イメージのビルド
イメージをビルドします。
docker compose build --no-cache
ここまででイメージサイズは以下の通りになりました。
docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
docker_rails-web latest 86a7076375a1 57 seconds ago 280MB
参考まで
build-base
とpostgresql-dev
を残した場合のイメージサイズ
REPOSITORY TAG IMAGE ID CREATED SIZE
docker_rails_base_postgres-web latest 90dcb8dc0cdc 10 seconds ago 759MB
build-base
を残した場合のイメージサイズ
REPOSITORY TAG IMAGE ID CREATED SIZE
docker_rails_base-web latest 0a2d01c64056 34 seconds ago 473MB
サービス起動
RailsとPostgreSQLのサービスを起動します。
docker compose up -d
ログの確認
起動しているか確認します(ログが表示されるまでしばらくかかるかもしれません)。
docker compose logs web
| => Booting Puma
| => Rails 6.1.7 application starting in development
| => Runbin/rails server --help
for more startup options
| Puma starting in single mode...
| * Puma version: 5.6.5 (ruby 3.1.2-p20) ("Birdie's Version")
| * Min threads: 5
| * Max threads: 5
| * Environment: development
| * PID: 1
| * Listening on http://0.0.0.0:3000
| Use Ctrl-C to stop
データベースの作成
無事に起動していることを確認したら最後にデータベースを作成します。
docker compose exec web rails db:create
Running via Spring preloader in process 43
Created database 'sample_app_development'
Created database 'sample_app_test'
ブラウザで確認
ブラウザで http://localhost:3000 にアクセスするとRailsの初期状態のトップ画面が表示されます。
スケルトンアプリ作成までのソースコードはこちら
-
None of the paths included in TZInfo::DataSources::ZoneinfoDataSource.search_path are valid zoneinfo directories. (TZInfo::DataSources::ZoneinfoDirectoryNotFound ↩︎
-
Skipping
rails webpacker:install
becausebundle install
was skipped.
To complete setup, you must runbundle install
followed byrails webpacker:install
. ↩︎
Discussion