DockerfileのCOPY --parentsが便利

はじめまして、Legalscapeエンジニアリングマネージャーの小林です。

今回は、DockerfileのCOPYが便利になっているのを発見したので紹介していきたいと思います。

DockerfileのCOPYは一癖ある

例えば、以下のようなディレクトリ構成において

tree
.
|-- Dockerfile
|-- package.json
`-- src
    |-- a.ts
    `-- b.ts

2 directories, 3 files

Dockerfileの中身が

FROM node:slim

WORKDIR /app

COPY package.json src ./

となっている時、このDockerfileから生成されるイメージでlsコマンドを実行すると

> docker run --rm sha256:4cd414a ls
a.ts
b.ts
package.json

src ディレクトリが生成されていない。

cp -r では当然 src ディレクトリ配下にファイルがコピーされる。

> cd app
> cp -r ../package.json ../src ./
> ls -R
.:
package.json  src

./src:
a.ts  b.ts

COPY --parents

Dockerfileを以下のようにすると、COPYが cp --parents 相当の処理をするようになり、上記の問題が解決する。

#syntax=docker/dockerfile:1.7-labs

FROM node:slim

WORKDIR /app

COPY --parents package.json src ./
> docker run --rm sha256:fd2eafe ls -R
.:
package.json
src

./src:
a.ts
b.ts

pnpm workspaceを使っていると、

COPY --parents packages/**/package.json ./

のように各パッケージのpackage.jsonだけをコピーすることができ、とても便利。

#syntax=docker/dockerfile:1.7-labsってなに?

buildkitが使用するDockerfileをのparserを指定している。

buildkitは内部でllbという中間言語を経てbuildを実行しており、Dockerfileからllbへの変換に docker/dockerfile:1.7-labs を使用してくださいという指示になっている。

このように中間言語を経るおかげで、

  • docker自体のアップグレードなしに新しいsyntaxを追加できる
  • オレオレDockerfileを実装できる
    • 例えば、 Gockerfile はGoアプリケーションを動かすDockerイメージをわずか3行のyamlでbuildできる
  • 他にも、 https://docs.docker.com/build/buildkit/frontend/ を参照

というメリットがある。