Docker で自身の作成したプログラムを動作させるためにはDockerイメージを作成する必要があります。
Dockerイメージを作成するための定義ファイルをDockerfileと呼びます。
# Dockerfile
FROM alpine
RUN apk add curl
ENTRYPOINT [“/usr/bin/curl”]
ビルドして実行するには以下のように実行します。
$ docker build --tag mycurl .
$ docker run -it --rm mycurl example.com
Dockerイメージの作成は簡単ですが、良いDockerイメージの作成はなかなか難しいです。
ベストプラクティスを参照してください。
https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
COPY, ADD, .dockerignore
docker build では指定したディレクトリにあるファイルを ADD や COPY を使って指定し、イメージを作成します。
イメージに必要となる設定ファイルや実行ファイルは指定したディレクトリに存在している必要があります。
docker build で指定したディレクトリの内容は全てdaemonに送られます。
特にDocker Desktop for Macなどの VMを使うような環境の場合、全てVMにコピーされることになるので注意が必要です。
ディレクトリにファイルが多いとコピーに時間がかかってしまいビルドが遅くなってしまうことがあります。
そのような場合は .dockerignore を使って適宜不要なファイルを除外すると良いです
ただし、書き過ぎると選別に時間が掛かるようになるので特に気になるものだけにするのをおすすめします。
ベースイメージ
Dockerではイメージ毎にLinuxディストリビューションに応じたディスクスペースを消費します。
このため、ベースとなるLinuxイメージはできるだけ小さいものを選択するのがおすすめです。
配布したりプロダクションで読み込む場合はイメージサイズを小さいと転送量を節約できる利点もあります。
- scratch: 最も小さいベースイメージ
- busybox: シェルと最小限のコマンドを収録した小さなベースイメージ
- distroless: Google製のコンテナアプリケーションにとって最小限の構成であるためサイズが小さく、収録ライブラリが少ないため比較的脆弱性に耐性がある
これらは apt などのパッケージマネージャーを内包していないため、何らかのライブラリに依存するようなプログラムを書く場合にはdebianなどを使う必要があります。
apt等で必要なパッケージをインストールした後にキャッシュを削除して容量を節約できます。
- alpine: イメージサイズを小さくするためにapkやmusl libcなどの独自実装のベースイメージ。プロダクションで使われることは少なくなりました
- [debian](https://hub.docker.com/_/debian): debian
- [ubuntu](https://hub.docker.com/_/ubuntu): ubuntu
- [RedHat UBI](https://access.redhat.com/ja/articles/5632841): Red Hat製のベースイメージ。UBI yumリポジトリを参照する
マルチステージビルド
通常、Dockerイメージを作る場合はバイナリを含めて必要なファイルを全てローカルマシン上にコンパイル等して用意し、 `COPY` でファイルを追加してイメージを作成します。
Go言語のようにバイナリのポータビリティが高い言語の場合、ビルド自体もDockerで行うことで、ローカルマシンの環境に依存せずDockerイメージを作成することができます。
main.go
package mainimport (
“fmt”
“os”
)func main() {
fmt.Println(“Hello, multi-stage build!”, os.Args[1:])
}
go.mod
module hello-multi-stage-buildgo 1.17
Dockerfile
FROM golang:1.17 AS build
WORKDIR /work
COPY . .
RUN CGO_ENABLED=0 go build -o /appFROM gcr.io/distroless/static
COPY — from=build /app /app
ENTRYPOINT [“/app”]
ビルドと実行はそれぞれ以下のようになります。
$ docker build --tag hello-multi-stage-build:1.0 .
$ docker run -it hello-multi-stage-build:1.0
Hello, multi-stage build! []
環境別にビルドする
1つのDockefileで本番環境とステージング環境のイメージを作成することもできます。
# Dockerfile
FROM golang:1.17 AS build
WORKDIR /work
COPY . .
RUN CGO_ENABLED=0 go build -o /appFROM gcr.io/distroless/static AS base
COPY — from=build /app /app
ENTRYPOINT [“/app”]FROM base AS production
CMD [“production”]FROM base AS staging
CMD [“staging”]
これは以下のようにビルドできます。
$ docker build --tag hello-multi-stage-build-staging:1.1 --target staging .
$ docker build --tag hello-multi-stage-build-production:1.1 --target production .
まとめ
docker build を使うことで任意のDockerイメージを作成することができます。特定のバージョンの python や ruby を動かしたい場合や、アプリケーションをサンドボックス化したい時にも便利です。
また、環境依存が大きいようなユーティリティプログラムを作成する場合などは、配布方法としても便利だと思います。