🐳

Dockerfileのベストプラクティス8選

2021/12/29に公開
5

はじめに

Dockerfileを書く上で、Docker社の推奨するベストプラクティスを8つにまとめました。
ベストプラクティスに従うことによって、簡単・安全・効率的な、Dockerfileの作成を目指します。
https://docs.docker.jp/engine/articles/dockerfile_best-practice.html

Dockerのガイドライン

コンテナは、必要最小限(エフェメラル)であるべき。

Dockerfile で定義されたイメージを使って作成されるコンテナは、可能ならばエフェメラル(短命;ephemeral)にすべきです。私たちの「エフェメラル」とは、停止・破棄可能であり、明らかに最小のセットアップで構築して使えることを意味します。

Dockerfileベストプラクティス

1. Baseイメージは、公式の信頼できるものを使おう

特定の言語などを扱う場合は、公式が言語が入ったイメージを配布してくれている場合が多いので、そちらを使おう。

Bad
FROM ubuntu

RUN apt-get update && apt-get install -y node
Good
FROM node

2. Baseイメージのバージョンを指定しよう

Baseイメージのバージョンが未指定だと、最新のバージョンがインストールされる。環境毎の再現性が低くなってしまう。

Bad
FROM node
Good
FROM node:17.3.0

3. Baseイメージは、可能な限りミニマムなイメージを選ぼう

ミニマムだと、ビルド早いし、セキュリティリスクも減る。
alpine linuxのイメージが公式から配布されている場合は、積極的に選んだほうが良さそう。

Bad
FROM node:17.3.0
Good
FROM node:17.3.0-alpine

4. Dockerのキャッシュレイヤーを最適化しよう

Bad
FROM node:17.3.0-alpine

WORKDIR /app

COPY myapp /app

RUN npm install

CMD ["node", "src/index.js"]
Good
FROM node:17.3.0-alpine

WORKDIR /app

COPY package*.json .

RUN npm install

COPY myapp /app

CMD ["node", "src/index.js"]

実際にbuildしてみる

CACHEの効きを確かめるために、一度buildした後に、app/index.jsを編集して、再度buildしてみた。

Badパターンの場合、「3/4」以降はCACHEが効いておらず、buildが走っている。特に、[4/4]npm installが4.8sもかかってる。

Goodパターンの場合、「4/4」までCACHEが効いており、buildが走っていない。[4/4]npm installもbuildが走っておらず、爆速。

5. .dockerignoreを書こう

実行に必要の無いディレクトリ・ファイルは、buildから除外しましょう。
secretsなどの秘密データは、必要のない場合は除外しましょう。

.dockerignore
# ignore .git and .cache folders
.git
.cache

# ignore all markdown files (md)
*.md

# ignore sensitive files
private.key
setting.json

6. Multi-Stage Buildsを使おう

一つのイメージの中に、必要なものをすべて詰め込む(builder pattern)は保守が辛いのでやめよう。

Bad
# syntax=docker/dockerfile:1
FROM golang:1.16
WORKDIR /go/src/github.com/alexellis/href-counter/
COPY app.go ./
RUN go get -d -v golang.org/x/net/html \
  && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
Good
# syntax=docker/dockerfile:1
FROM golang:1.16 AS builder
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html  
COPY app.go    ./
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

FROM alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /go/src/github.com/alexellis/href-counter/app ./
CMD ["./app"]  

7. userの実行権限は最小限にしよう

USER を指定しないとrootで実行されるので、 USER を指定しましょう。

Bad
# run with default root user
CMD node index.js
Good
# create group and user
RUN groupadd -r tom && useradd -g tom tom

# set ownership and permission
RUN chown -R tom:tom /app

# switch to user
USER tom

# run with tom
CMD node index.js

8. Securityスキャンをしよう

dockerhubにログインする。

docker login

docker scanコマンドは、内部的にsnykを利用して、Securityスキャンをしてくれるので、snykでもログインする必要がある。

docker scan --login

build imageをSecurityスキャンするk

docker scan myapp:1.0

おわりに

今回は、Dockerfile作成時のベストプラクティスについてまとめました。
皆さんのDockerライフの一助となれば幸いです。

twitterでGolang・Flutter・GCP開発など情報発信していますので、よかったらフォローしてくださいmm

https://twitter.com/kenbu05

参考

https://docs.docker.jp/engine/articles/dockerfile_best-practice.html
https://docs.docker.com/develop/develop-images/multistage-build/

Discussion

ganyariyaganyariya

Dockerfile 苦手なので参考になりました,ありがとうございます><

https://zenn.dev/kenghaya/articles/36cd09b9f47ba6#3.-baseイメージは、可能な限りミニマムなイメージを選ぼう
alpine の typo があるみたいです.(alphine になっているみたいです><)

koukou

こんにちは!とても素敵な記事で参考になりました!🐶

追加でCACHEのタイポも確認したのでコメント添えておきます🙈笑
(「4. Dockerのキャッシュレイヤーを最適化しよう」あたりでCASHEになってますね)