LoginSignup
27
29

More than 3 years have passed since last update.

docker-compose: マルチステージビルドの中間イメージにタグ付けするベストプラクティス

Last updated at Posted at 2020-07-27

はじめに

自分のメモ用に殴り書き。この記事では、docker-compose を使って、マルチステージビルドで中間生成される Docker イメージにタグ付けするためのベストプラクティスを紹介します。

TL;DR

  • Dockerfile の各ステージには名前を付けましょう。
  • 各ステージの中間イメージビルド用の docker-compose.build.yml を作りましょう。
  • 以上
  • なお、docker-compose は、バージョン 3.4 以上である必要があります。
    • V3.4 でサポートされた buildtarget という機能を利用します。

Dockerfile マルチステージビルドのムカつくところ

  • Dockerfile のマルチステージビルドは中間イメージにタグを付けてくれません。
  • 結果として、<none>:<none> という無名の Docker イメージが残存し続けます。
  • たまに掃除して上げないと、docker images に大量の無名イメージがリストされます。
  • 不要なイメージでサーバーストレージも無駄に消費します。
# image:latest は Dockerfile で生成された最終成果物となる Docker イメージ
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
image                   latest              439521aeed0d        1 hours ago         1.48GB
<none>                  <none>              f683a5456003        1 hours ago         1.33GB
<none>                  <none>              a92a033bf4e7        1 hours ago         1.03GB
<none>                  <none>              7fa2a4097f16        2 hours ago         1.33GB
<none>                  <none>              20acbe3cae6c        2 hours ago         1.03GB
<none>                  <none>              dee5b549543c        3 hours ago         1.33GB
<none>                  <none>              8679ced16d20        3 hours ago         1.03GB
<none>                  <none>              f683a5456003        4 hours ago         1.33GB
<none>                  <none>              a92a033bf4e7        4 hours ago         1.03GB
<none>                  <none>              7fa2a4097f16        5 hours ago         1.33GB
<none>                  <none>              20acbe3cae6c        5 hours ago         1.03GB
<none>                  <none>              dee5b549543c        6 hours ago         1.33GB
<none>                  <none>              8679ced16d20        6 hours ago         1.03GB
...延々と続く

マルチステージビルドって何?

  • 公式ドキュメント(英語)
  • Docker イメージのビルド工程を複数ステージに分割して最終イメージを生成する、Dockerfile の機能です。
  • 複雑になりがちだった Docker イメージ生成プロセスを効率よくするために導入された機能です。
  • 例えば、Webアプリケーションサーバーの Docker イメージの場合、フロントエンドのパッケージ生成は、node:latest イメージを使い、バックエンドのパッケージ生成は、python:latest イメージを用いて、最終的にフロントエンドとバックエンドの生成物を alpine:latest イメージにデプロイするといった感じになるでしょう。(図とか欲しいけど、そんな時間ない、殴り書き)

擬似サンプル: シンプルなマルチステージビルド

  • この記事では次のような Dockerfiledocker-compose.yml を利用して、手順を説明します。
Dockerfile
# 第1ステージビルド: node:latest を用いて、フロントエンドパッケージをビルドする
FROM node:latest
RUN build_frontend_package
# 第2ステージビルド: python:latest を用いて、バックエンドパッケージをビルドする
FROM python:latest
RUN build_backend_package
# 最終ステージビルド: alpine:latest をベースイメージとし、フロントエンドとバックエンドのパッケージを組み込んだ Web アプリケーションサーバを構築する
FROM alpine:latest
COPY --from 0 frontend_package
COPY --from 1 backend_package
RUN build_production frontend_package backend_package
docker-compose.yml
version: "3.4"
services:
    web:
        build: .
        image: image:latest

ポイント1: 各ステージには名前をつけましょう

  • FROM イメージ名 AS ステージ名 を使って、それぞれのステージに名前をつけてください。
  • そうすると、Dockerfile 内や、docker-compose から、その名前でステージを参照できます。
  • docker-compose でステージ名を指定してビルドするために、ステージに名前を付けるんです。
Dockerfile
# 第1ステージビルド: node:latest を用いて、フロントエンドパッケージをビルドする
FROM node:latest AS frontend_stage
RUN build_frontend_package
# 第2ステージビルド: python:latest を用いて、バックエンドパッケージをビルドする
FROM python:latest AS backend_stage
RUN build_backend_package
# 最終ステージビルド: alpine:latest をベースイメージとし、フロントエンドとバックエンドのパッケージを組み込んだ Web アプリケーションサーバを構築する
FROM alpine:latest AS final_stage
COPY --from frontend_stage frontend_package
COPY --from backend_stage backend_package
RUN build_production frontend_package backend_package

ポイント2: docker-compose.build.yml というファイルでビルドしましょう

  • 執筆段階では、docker-compose を使うなら、docker-compose.yml のみで実現するのは無理だと思います。
  • docker-compose.build.yml では、buildcontexttarget という設定を入れます。
  • context には、カレントディレクトリとか Docker のビルドコンテキストのパスを入れておきます。
  • target には、(先ほど名前をつけた) マルチステージビルドのステージ名を入れて上げます。
  • ファイル名は任意です。docker-compose.build.yml である必要はありません。
docker-compose.build.yml
version: "3.4"
services:
    frontend:
        build:
            context: .
            target: frontend_stage
        image: frontend:latest
    backend:
        build:
            context: .
            target: backend_stage
        image: backend:latest
    final:
        build:
            context: .
            target: final_stage
        image: image:latest
  • docker-compose.yml からは、build 設定を抜いておきましょう。(残しておいてもOK。使わないだけ。)
docker-compose.yml
version: "3.4"
services:
    web:
        image: image:latest

ビルドしてサービスを起動する方法

  • docker-compose build に、-f オプションで docker-compose.build.yml を指定してビルドします。
$ docker-compose -f docker-compose.build.yml build
  • ビルドが完了したら、docker-compose.yml を用いて、サービスを起動して上げます。
    • 注意: docker-compose.build.yml ではありません
$ docker-compose up -d
  • Docker イメージの一覧を表示すると、中間イメージがタグ付けされています。
$ docker images
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
image                   latest              439521aeed0d        1 hours ago         1.48GB
frontend                latest              f683a5456003        1 hours ago         1.33GB
backend                 latest              a92a033bf4e7        1 hours ago         1.03GB

まとめ

  • Dockerfile の各ステージには名前を付けましょう。
  • 各ステージの中間イメージビルド用の docker-compose.build.yml を作りましょう。
  • 細かな修正とかして、何度も docker-compose ビルドし直したりしても、タグ付けされます。(当たり前)
  • 知らず知らずのうちに、手元ビルドで大量に残存していた無名イメージがなくなります。
  • マルチステージビルドの中間イメージにタグ付けする方法は他にもありますが、私の試行錯誤したかぎりでは、これがベストプラクティスだと思います。
27
29
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
29