Edited at

Docker + rails + Webpacker で buildしたときに COPY のstepでエラーが出る

Dockerを使ってRails+Webpackerで環境構築しようと思ったら以下のようなエラーに遭遇した。

ERROR: Service 'webpacker' failed to build: COPY failed: stat /var/lib/docker/overlay2/7a5a91db824e62b94de842827e48bdea3dc9c4d2d36c17134fcf61c8bf8dfdc9/merged/opt/yarn-v1.13.0: no such file or directory


Dockerfile

FROM node:10 as node

FROM ruby:2.6.2

ENV LANG C.UTF-8
ENV YARN_VERSION 1.13.0

RUN apt-get update -qq && apt-get install -y build-essential graphviz libpq-dev

RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - && \
apt-get install nodejs

COPY --from=node /opt/yarn-v$YARN_VERSION /opt/yarn
COPY --from=node /usr/local/bin/node /usr/local/bin/

RUN ln -s /opt/yarn/bin/yarn /usr/local/bin/yarn \
&& ln -s /opt/yarn/bin/yarnpkg /usr/local/bin/yarnpkg

RUN gem install bundler

CMD ["/bin/sh", "-c", "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"]

全く同じ構成でも動く人と動かない人(自分)が存在して解決に時間がかかった。


原因

自分がDockerでの環境構築を始めたのが遅かったから。

もう少し具体的に言うと、Dockerを使い始めたのが遅かった為、指定したversionのyarnをコンテナ内にCopyできず、冒頭にあるようなエラーが発生していた。

ENV YARN_VERSION 1.13.0という指定を、 COPY --from=node /opt/yarn-v$YARN_VERSION /opt/yarn でしており、今回でいうと FROM node:10 as node でpullしてきたベースのイメージから、yarnの1.13.0をコピーさせる命令を出しているが、そのVersionのyarnを扱ったnodeは自分のimageにはなく、pullしてきたnodeの中にもない(同じ構成で構築できた人は以前使ったyarn1.13.0が自分のimagesに存在しており、Dockerの仕組み上ローカルにベースイメージがあればそれを使い、もしなければDockerHubからpullする為、ローカルのimageを使って結果buildできた)為、そんなファイルやディレクトリはないと怒られていた。


解決策

copy時のVersion指定をワイルドカード(あるいは最新版などの指定nodeに存在するVersionを選ぶ。)

FROM node:10 as node

FROM ruby:2.6.2

ENV LANG C.UTF-8
##Yarnのバージョン指定は不要

RUN apt-get update -qq && apt-get install -y build-essential graphviz libpq-dev

RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - && \
apt-get install nodejs

COPY --from=node /opt/yarn-v$YARN_VERSION /opt/yarn <== ここの[v$YARN_VERSION] で環境変数指定でCopyしようとしていた部分を[*]ワイルドカードにする。
COPY --from=node /usr/local/bin/node /usr/local/bin/

RUN ln -s /opt/yarn/bin/yarn /usr/local/bin/yarn \
&& ln -s /opt/yarn/bin/yarnpkg /usr/local/bin/yarnpkg

RUN gem install bundler

CMD ["/bin/sh", "-c", "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"]

これで、指定nodeの中から、使えるversionのyarnをCOPYしてbuildする事ができるようになる。

実際の業務などでは、そもそもDockerを使う理由としてLocalでの開発環境から開放されたいのに、Docker内のモジュールのバージョンが各自違うというのはアレなのでbuildしたものを全員で共有して開発するというやり方がよい。