もふもふ技術部

IT技術系mofmofメディア

dockerのRuby環境をHerokuと同じUbuntuで動くものにする

Dockerの公式が出しているRubyのdocker imageではdebianやapline linuxが使用されています。mofmofではHerokuで本番環境を作っているアプリも多いのですが、HerokuではUbuntuが使われています。

そのため、ローカルで使用しているdockerでもUbuntuを使ってHerokuと環境を合わせたいねという話が開発チームの中で出ました。

開発しているアプリでHeroku-20のstackからHeroku-22にアップグレード対応するものがあったため、このタイミングでDockerのRubyをUbuntu上で動くものにしてみました。

rubylang/rubyのdocker image

rubylang/ruby

rubylang/ruby:3.1.6-jammy

こちらが今回採用したdocker imageです。Heroku-22のstackはUbuntu 22.04で動作しており、こちらのdocker imageも同様にUbuntu 22.04で動作しているため、Heroku-22のstackで動作している環境と同じ環境で動かせるということになります。

変更する上でのポイント

bundle install時のインストール先ディレクトリの権限設定

ruby:3.1.6

今まではこちらのようなDocker公式のdocker imageを使っていたのですが、こちらを使った場合のDockerfileでは下記のように、dockerというUSERを作って、bundle installはUSER dockerが実行する形にしていました。

RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo

WORKDIR /usr/src/app
COPY Gemfile* ./
RUN chown docker:docker -R .

USER docker
RUN bundle install --jobs 4

今回も同様の形にしてdocker compose buildを実行したところ、

 > [app stage-1 10/12] RUN bundle install --jobs 4:
1.917 Fetching gem metadata from https://rubygems.org/..........
4.293 Using rake 13.0.6
4.295 Following files may not be writable, so sudo is needed:
4.295   /usr/local/bin
4.295   /usr/local/lib/ruby/gems/3.1.0
4.295   /usr/local/lib/ruby/gems/3.1.0/build_info
4.295   /usr/local/lib/ruby/gems/3.1.0/cache
4.295   /usr/local/lib/ruby/gems/3.1.0/doc
4.295   /usr/local/lib/ruby/gems/3.1.0/extensions
4.295   /usr/local/lib/ruby/gems/3.1.0/gems
4.295   /usr/local/lib/ruby/gems/3.1.0/plugins
4.295   /usr/local/lib/ruby/gems/3.1.0/specifications

ディレクトリへの書き込み権限が無いということでエラーが発生しました。最初は何が原因なのか分からなかったのですが、調査したところDocker公式のdocker imageとrubylang/rubyのdocker imageに構築時のコマンドの違いがあることが分かりました。

Docker公式のdocker imageの構築時のコマンド

Docker公式のdocker imageの場合、ENV GEM_HOMEでGemのインストール先ディレクトリを設定して、そのディレクトリに対してアクセス権限を設定しているんですね。これは知りませんでした。

つまり、rubylang/rubyのdocker imageではこのようなアクセス権限の設定処理は行われていないため、USER dockerでbundle installを実行しようとすると権限エラーになったということでした。これを解消するためには、ローカルのDockerfileで同様の設定をしてやればOKです。

Docker公式のdocker imageのDockerfileを参考に、ローカルのDockerfileを下記のように書き換えてやることで、エラーを解消できました。

RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo

WORKDIR /usr/src/app
COPY Gemfile* ./
RUN chown docker:docker -R .

ENV GEM_HOME /usr/local/bundle
ENV BUNDLE_SILENCE_ROOT_WARNING=1 \
    BUNDLE_APP_CONFIG="$GEM_HOME"
ENV PATH $GEM_HOME/bin:$PATH
RUN set -eux; \
    mkdir "$GEM_HOME"; \
    chmod 1777 "$GEM_HOME"

USER docker
RUN bundle install --jobs 4

postgresql利用時

こちらは本題とは少しズレますが、今回のアプリではDBにPostgreSQLを使用していたため、Gem pgを使っていました。bundle install時にDocker公式のdocker imageでは特にエラーは出なかったのですが、rubylang/rubyのdocker imageの場合では下記のエラーが出ました。

94.38 Unable to find PostgreSQL client library.
94.38
94.38 Please install libpq or postgresql client package like so:
94.38   sudo apt install libpq-dev
94.38   sudo yum install postgresql-devel
94.38   sudo zypper in postgresql-devel
94.38   sudo pacman -S postgresql-libs

こちらはエラーメッセージで表示されている通り、ローカルのDockerfileでライブラリをインストールしている箇所でlibpq-devを追加してやればOKです。

RUN apt-get update -qq \
    && apt-get install -y --no-install-recommends \
    libpq-dev \

まとめ

今回Docker公式以外のdocker imageを使ってみて、初めて構築時のコマンドに意識を向けることができました。本来の目的であるHerokuとの環境差異をなくす対応も出来、勉強になりました。