古い環境を構築する話です。
ニーズは狭いですが、刺さる人には刺さるだろうなと思って書いてみます。
筆者が作業していた環境のバージョンは以下のとおりですが、多少異なる場合でも同じように環境構築できると思います。
- OS: Ubuntu 12.04
- Ruby: 1.9.3
- Rails: 3.2.18
- OpenSSL: 1.0.1
成果物
早速ですが、自分が作成したファイルを紹介します。
Dockerfile(クリックで展開)
FROM ubuntu:12.04
ENV LANG C.UTF-8
ENV RUBY_MAJOR 1.9
ENV RUBY_VERSION 1.9.3-p194
# バージョン2.3未満のRubyに対してはBundler 1しか対応していない https://bundler.io/compatibility.html
ENV BUNDLER_VERSION 1.16.6
# OSが古いためaptリポジトリを変更する
# OSを archive.ubuntu.com が管理するバージョンまでアップグレードした場合、以下の行は削除してよい
RUN sed -i -e 's/archive.ubuntu.com/old-releases.ubuntu.com/g' /etc/apt/sources.list
# Rubyのインストールに必要なaptパッケージをインストールする
# 参考 https://hub.docker.com/layers/library/ruby/2.1-slim/images/sha256-610647397432a2b1762e29beaf4f4c723399204f1e111531a90bc50d98ca867e
RUN apt-get update && \
apt-get install -y --no-install-recommends build-essential sudo \
bzip2 ca-certificates libffi-dev libgdbm3 libssl-dev libyaml-dev procps zlib1g-dev \
autoconf bison dpkg-dev gcc libbz2-dev libgdbm-dev libglib2.0-dev libncurses-dev libreadline-dev libxml2-dev libxslt-dev make ruby wget xz-utils
# gemのインストールに必要なaptパッケージをインストールする
# devise -> git(Gemfileでgitの指定あり)
# nokogiri -> pkg-config libxml2-dev libxslt-dev https://nokogiri.org/tutorials/installing_nokogiri.html#installing-using-standard-system-libraries
# 後者二つはインストール済み
# pg -> libpq-dev
# mini_magick -> imagemagick
# rspec -> xvfb
RUN apt-get -y install git pkg-config libpq-dev imagemagick xvfb
# Rubyをインストールする
RUN wget https://cache.ruby-lang.org/pub/ruby/$RUBY_MAJOR/ruby-$RUBY_VERSION.tar.gz && \
tar xvf ruby-$RUBY_VERSION.tar.gz && \
rm ruby-$RUBY_VERSION.tar.gz && \
cd ruby-$RUBY_VERSION && \
./configure --build="$gnuArch" --disable-install-doc --enable-shared && \
make -j "$(nproc)" && \
make install && \
cd .. && \
rm -rf ruby-$RUBY_VERSION
ENV APP_HOME /rails
RUN mkdir $APP_HOME
WORKDIR $APP_HOME
# gemをインストールする
COPY Gemfile* $APP_HOME
RUN gem install bundler -v $BUNDLER_VERSION
# nokogiri同梱のパッケージを利用するとインストールがパスしないので、OSのパッケージを利用する https://nokogiri.org/tutorials/installing_nokogiri.html#installing-using-standard-system-libraries
RUN bundle config build.nokogiri --use-system-libraries
RUN bundle config set jobs $(nproc) && bundle install
ADD . $APP_HOME
# 作業用非rootユーザーを作成する
ARG UID
ARG GID
ARG USERNAME
RUN groupadd $USERNAME -g $GID -o && \
useradd $USERNAME -u $UID -g $GID -o --create-home --shell /bin/bash
USER $USERNAME:$USERNAME
compose.yml(クリックで展開)
services:
web:
build:
context: .
args:
UID: ${UID:-1000}
GID: ${GID:-1000}
USERNAME: ${USERNAME:-rails}
ports:
- 3000:3000
command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
depends_on:
- db
tty: true
stdin_open: true
volumes:
- .:/rails:cached
- bundle_volume:/usr/local/bin:cached
db:
image: postgres:9.4
ports:
- 5432:5432
volumes:
- db_volume:/var/lib/postgresql/data
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
volumes:
bundle_volume:
db_volume:
動機
なんでUbuntuをベースイメージにしているんだ、Rubyをベースイメージにすればいいじゃないか、と思う方もいるかもしれません。
これは、UbuntuとRubyでそれぞれバージョンを指定したいためです。
具体的には以下のような事情があり、ローカル環境でUbuntuとRubyを別々にアップグレードして動作確認できるようにしました。
- Ubuntu、Ruby共に古い本番環境で、AWS S3 APIがTLS1.2以上を必須としたことに起因するエラーが発生していた
- エラーを解消しようにもTLS ← OpenSSL ← Ubuntuのaptパッケージ ← Rubyというバージョン依存があり、アップグレード作業がRubyまで波及していきそうではないかと、事前調査によって見当がついた
- 一方で、実際に着手すればディストリビューションのアップグレードだけで解決する可能性もあるため、個々のレイヤーで更新作業を実施しながらエラー解消に取り組みたかった
また、作業着手前には以下のような運用が行われており、開発環境構築について手入れしたかったというのが、Docker化のモチベーションになっています。
- ローカル開発環境の構築手順が整備されていなかった
- デプロイがCapistranoで行われていたが、昨今では一般的な方法ではなくなってしまったため、Docker Imageによるデプロイに移行したかった
※ 補足: 弊社では運用中のRailsアプリケーションに関する相談の中で、様々な事情から長らくアップデートされずに運用されていたRailsアプリケーションのアップグレード相談をお仕事として受けることもあります。
Dockerfile作成のポイント
aptリポジトリの指定を変更する
Ubuntu12用のパッケージは、デフォルトの archive.ubuntu.com
では最早管理されていないため、URL指定を old-releases.ubuntu.com
のようなリポジトリに変更する必要があります。
# Dockerfile
RUN sed -i -e 's/archive.ubuntu.com/old-releases.ubuntu.com/g' /etc/apt/sources.list
Rubyのインストールに必要なaptパッケージをインストールする
Docker Hubにある ruby:2.1-slim イメージのLayersを参考にしています。
今回インストールしたいRubyバージョンに対応する ruby:1.9.3-slim の方も確認しましたが、Layersが未記載になっており、代わりにできるだけ近いバージョンのイメージを参考にしました。
ruby:1.9.3-slim
のLayers/Command確認方法を知っている方がいれば、コメント等もらえると助かります!
build-essential
と sudo
だけ、個人的な希望で追加しています。
# Dockerfile
RUN apt-get update && \
apt-get install -y --no-install-recommends build-essential sudo \
bzip2 ca-certificates libffi-dev libgdbm3 libssl-dev libyaml-dev procps zlib1g-dev \
autoconf bison dpkg-dev gcc libbz2-dev libgdbm-dev libglib2.0-dev libncurses-dev libreadline-dev libxml2-dev libxslt-dev make ruby wget xz-utils
gemのインストールに必要なaptパッケージをインストールする
プロジェクトに応じて、利用されているgem用のパッケージをインストールすることになります。
今回手間取ったのは nokogiri のインストールです。
当初は nokogiriの同梱ライブラリを利用した環境構築 を図りましたが、解決できずに システムライブラリの利用 に切り替えました。
この場合、 nokogiri
に --use-system-libraries
オプションを指定しておく必要があります。
# Dockerfile
RUN apt-get -y install git pkg-config libpq-dev imagemagick xvfb
# ...
RUN bundle config build.nokogiri --use-system-libraries
Rubyをインストールする
これもDocker HubのRubyイメージを参考にして、 cache.ruby-lang.org
からダウンロードするようにしています。
# Dockerfile
RUN wget https://cache.ruby-lang.org/pub/ruby/$RUBY_MAJOR/ruby-$RUBY_VERSION.tar.gz && \
tar xvf ruby-$RUBY_VERSION.tar.gz && \
rm ruby-$RUBY_VERSION.tar.gz && \
cd ruby-$RUBY_VERSION && \
./configure --build="$gnuArch" --disable-install-doc --enable-shared && \
make -j "$(nproc)" && \
make install && \
cd .. && \
rm -rf ruby-$RUBY_VERSION
gemをインストールする
事前にBundlerのインストールが必要になります。
今回のようにRubyのバージョンが古い場合、Bundlerのバージョンも絞られることがあるので確認しておきましょう。 https://bundler.io/compatibility.html
既存のRailsプロジェクトがあるなら、 Bundlerのバージョンは Gemfile.lock
の BUNDLED WITH
に合わせるのが無難です。
# Dockerfile
COPY Gemfile* $APP_HOME
RUN gem install bundler -v $BUNDLER_VERSION
RUN bundle config set jobs $(nproc) && bundle install
ベースイメージをRubyにしたくない特殊事情があるとき、参考にしていただけると幸いです。