Dockerイメージのビルド時にシンボリックリンクの実体を含める
タイトルがわかりにくいですが...
事の発端
以下のような構成のディレクトリがあったとします。
- /foo (共有したいファイル)
- /bar/foo (/fooへのシンボリックリンク)
- /bar/Dockerfile
- /baz/foo (/fooへのシンボリックリンク)
- /baz/Dockerfile
そして、{bar,baz}/Dockerfile
にCOPY foo ...
のような記述があったとします。
そのとき、fooとbarの各ディレクトリにおいてdocker build .
のようなコマンドで(そのディレクトリをコンテキストとして)dockerイメージをビルドしようとするとエラーが出ます。具体的にはCOPY failed: Forbidden path outside the build context
と言われます。
「それはそう」という感じなのですが、このような場面において「ファイルを追加する際、それがシンボリックリンクならばそれをたどって実体をイメージに追加する」といったことができても便利なのではないかと思ったりすることがありました。
解決策
ここでなるほどと思う解決策を見つけました。
「docker build .
の代わりにtar -czh . | docker build -
ようにすればよい」というものです。
具体的にはこのような感じのことが起こっています。
tar -czh .
で、カレントディレクトリをgzipにアーカイブする。その際、シンボリックリンクが存在した場合はそれをたどり、辿った先のファイルの内容でそのリンクを置き換える(-h
オプション)。- それをコンテキストとして
docker build
にわたす。
なるほどなあという感じですね。
実際にやってみると、このようにうまくいきます。
$ echo 'foo' > foo $ mkdir bar $ cd bar $ ln -s ../foo foo $ cat <<EOF >Dockerfile FROM busybox WORKDIR /work COPY foo . EOF $ tar -czh . | docker build - Sending build context to Docker daemon 10.24kB Step 1/3 : FROM busybox ---> e4db68de4ff2 Step 2/3 : WORKDIR /work ---> Using cache ---> 2daef8292bd0 Step 3/3 : COPY foo . ---> Using cache ---> 1ec7cbed7c90 Successfully built 1ec7cbed7c90 $docker run -it 1ec7cbed7c90 /work # cat foo foo
tar -czh . | docker build -
をdocker build .
におきかえるとエラーがでることも確認できます。
ちなみに執筆時点でのdockerのバージョンは以下の通りでした。
$ docker --version Docker version 18.09.2, build 6247962