本当はalpine-rubyをベースにするべきなんだろうけど諸事情でJava系のベースにする必要があったので、rbenvを自力で入れて構築することにしました。
出来上がったDockerfileはこちら。
FROM openjdk:8-jdk-alpine
RUN apk update && \
apk upgrade && \
apk add --update --no-cache \
bash \
vim \
curl \
tzdata \
openssl-dev=1.0.2u-r0
RUN cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
RUN echo "http://dl-cdn.alpinelinux.org/alpine/v3.8/main" >> /etc/apk/repositories
RUN apk update && \
apk upgrade && \
apk add --update --no-cache --virtual=.build-dependencies \
build-base \
git \
gcc \
readline-dev \
zlib-dev \
libffi-dev
ENV PATH /usr/local/rbenv/shims:/usr/local/rbenv/bin:$PATH
ENV RBENV_ROOT /usr/local/rbenv
ENV CONFIGURE_OPTS "--disable-install-doc"
RUN git clone https://github.com/sstephenson/rbenv.git ${RBENV_ROOT} && \
git clone https://github.com/sstephenson/ruby-build.git ${RBENV_ROOT}/plugins/ruby-build && \
${RBENV_ROOT}/plugins/ruby-build/install.sh
RUN echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> /etc/profile.d/rbenv.sh && \
echo 'eval "$(rbenv init -)"' >> /etc/profile.d/rbenv.sh
RUN rbenv install 2.2.3 && \
rbenv global 2.2.3
COPY Gemfile .
COPY Gemfile.lock .
RUN gem install -N bundler -v 1.16.2
RUN bundle install -j4 && \
rm -rf /usr/local/bundle/cache/*.gem
RUN apk del .build-dependencies
大きな障害はは以下のようにopensslの1.0を取得することでした。
v3.8から1.0系のopensslを取得する
素直にapk add opensslでライブラリを入れるとrbenv install時に以下のようなエラーが発生する。
BUILD FAILED (Alpine Linux 3.9.4 using ruby-build 20200115-8-g73b926b)
Inspect or clean up the working tree at /tmp/ruby-build.20200123165940.26.gjbJCo
Results logged to /tmp/ruby-build.20200123165940.26.log
Last 10 log lines:
power_assert-0.2.2.gem
minitest-5.4.3.gem
installing rdoc: /usr/local/rbenv/versions/2.2.3/share/ri/2.2.0/system
installing capi-docs: /usr/local/rbenv/versions/2.2.3/share/doc/ruby
The Ruby openssl extension was not compiled.
ERROR: Ruby install aborted due to missing extensions
Configure options used:
--prefix=/usr/local/rbenv/versions/2.2.3
LDFLAGS=-L/usr/local/rbenv/versions/2.2.3/lib
CPPFLAGS=-I/usr/local/rbenv/versions/2.2.3/include
エラーの原因としては、ruby2.4以下の場合はopenssl1.1系に対応していないため、openssl1.0を入れる必要があるからでした。
rbenv/ruby-build
The openssl extension of Ruby version before 2.4 is not compatible with OpenSSL 1.1.x.
ubuntuベースのimageで構築するならこちらの記事で言及されているように有志が開発したパッチを当てれば動きますが、alpineの場合は自力で1.0系を入れる必要があります。
現在openjdk:8-jdk-alpineではデフォルトでv3.9のリポジトリを参照しているが、v3.9ではopensslは1.1系の提供になっています。
こちらで調べると1.0系の取得には1つ前のv3.8のリポジトリから取得が必要のようです。
https://pkgs.alpinelinux.org/packages?name=openssl&branch=v3.8&repo=main
そこでapkから取得する前に参照先にv3.8のリポジトリを追加して上げる必要があります。
RUN echo "http://dl-cdn.alpinelinux.org/alpine/v3.8/main" >> /etc/apk/repositories
追加後にopenssl-dev=1.0.2u-r0
とバージョンを指定することで1.0系のopensslを取得することができます。
また当初はgem install時にThe Ruby openssl extension was not compiled. Missing the OpenSSL lib?
エラーが発生していたが、修正前のDockerfikeでlibssl1.0
を入れていたことが原因でした。
おそらくssl系のライブラリ同士でバッティングしていたっぽい?
rbenvの前はruby-installを使用して軽量化を図っていましたが、上と同じOpenSSLのエラーがどうしても解消できなかったので諦めることに…
ruby-installで上手く行けば多分もう少し軽くできそう。
RUN wget -O - https://github.com/postmodern/ruby-install/archive/v0.7.0.tar.gz | tar xzvf - && \
( cd ruby-install-0.7.0 && \
make install ) && \
rm -rf ruby-install-*
RUN ruby-install --system --cleanup ruby 2.2.3
その他細かいポイントなど
docker軽量化系の記事では散々言及されているようなことですが、軽くまとめると
- ビルドに必要のないパッケージは残したくないので.build-dependenciesでまとめて最後の行で一括で削除しています。
- ENV CONFIGURE_OPTS "--disable-install-doc"
を指定することで不要なドキュメントをインストールしないようにしています
- bundle install時にrm -rf /usr/local/bundle/cache/*.gem
でgemのキャッシュを消すようにしています
今どき2.2.3を使うことはあまりないと思いますが、備忘録として残しておこうと思います。