🪣

Dockerはもう怖くないよ!

2023/11/29に公開

こんにちは!ビクトルと申します!今回Dockerに大して便利なコマンドとパターンを紹介したいと思っています。

たまに Dockerfileを書くとき大変になってしまいます。今回は Dockerfileにたいして役に立つコマンドやベストプラクティスについて話したいと思います。

まず基本的なDockerfileを書きましょう

FROM golang:1.21 as builder

WORKDIR /tmp/app

COPY . .
RUN go install github.com/go-delve/delve/cmd/dlv@latest
RUN go build -o /server -gcflags="-l -N" .

EXPOSE 8080

CMD ["/server"]

さきのDockerfileがフォルダーで作成して必要なファイルも作成しましょう

$ ls
Dockerfile  go.mod  main.go  README.md
main.go
package main

import (
	"fmt"
	"net/http"
)

func hello(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "hello\n")
}

func main() {
	http.HandleFunc("/hello", hello)
	http.ListenAndServe(":8080", nil)
}
go.mod
go mod init github.com/example/docker
README.md
This is an example

さささ!やっていきましょう!

Build args

docker buildを実行するとき --build-args を使ってパラメターを渡すことができます。

Multilayer

この機能について別のイメージにカプセル化やサイズなど小さくなって改善に行って行きます。

docker history example:latestを実行して

c5ad8c7d9737  2 seconds ago   /bin/sh -c #(nop) CMD ["/server"]              0B                       FROM a0fb5814dba9
<missing>     2 seconds ago   /bin/sh -c #(nop) EXPOSE 8080                  0B                       FROM c5ad8c7d9737
<missing>     2 seconds ago   /bin/sh -c go build -o /server -gcflags="-...  6.82MB                   FROM 77fd079a98b7
77fd079a98b7  6 seconds ago   /bin/sh -c go install github.com/go-delve/...  213MB                    FROM 62190e738985
62190e738985  39 seconds ago  /bin/sh -c #(nop) COPY dir:f5c2e292f81ed65...  20.5kB                   FROM 6fd7b9fc33ed
4c88d2e04e7d  40 seconds ago  /bin/sh -c #(nop) WORKDIR /tmp/app             0B                       FROM docker.io/library/golang:1.21
<missing>     6 days ago      /bin/sh -c #(nop) WORKDIR /go                  0B                       
<missing>     6 days ago      /bin/sh -c mkdir -p "$GOPATH/src" "$GOPATH...  3.07kB                   
<missing>     6 days ago      /bin/sh -c #(nop)  ENV PATH=/go/bin:/usr/l...  0B                       
<missing>     6 days ago      /bin/sh -c #(nop)  ENV GOPATH=/go              0B                       
<missing>     6 days ago      /bin/sh -c #(nop)  ENV GOTOOLCHAIN=local       0B                       
<missing>     6 days ago      /bin/sh -c set -eux;                           arch="$(dpkg --print...  224MB       
<missing>     6 days ago      /bin/sh -c #(nop)  ENV GOLANG_VERSION=1.21.4   0B                       
<missing>     12 days ago     /bin/sh -c #(nop)  ENV PATH=/usr/local/go/...  0B                       
<missing>     12 days ago     /bin/sh -c set -eux;                           apt-get update;          apt...      262MB       
<missing>     13 days ago     /bin/sh -c apt-get update && apt-get insta...  181MB                    
<missing>     13 days ago     /bin/sh -c set -eux;                           apt-get update;          apt...      49.6MB      
<missing>     13 days ago     /bin/sh -c #(nop)  CMD ["bash"]                0B                       
<missing>     13 days ago     /bin/sh -c #(nop) ADD file:3e9b6405f11dd24...  0B

結構ありますね、サイズはどんな感じかな

localhost/example  latest      f48d3fcb9285  2 minutes ago  1.06 GB

ファー!!!さって魔法かけましょう

Dockerfileに少し変更して

FROM golang:1.21 as builder

WORKDIR /tmp/app

COPY . .
RUN go install github.com/go-delve/delve/cmd/dlv@latest
RUN go build -o /server -gcflags="-l -N" .

FROM debian:trixie-slim as final
COPY --from=builder /server /server

EXPOSE 8080

CMD ["/server"]

サイズは変わりましたか?

REPOSITORY         TAG         IMAGE ID      CREATED             SIZE
localhost/example  latest      25aa1fbb8efb  About a minute ago  84.4 MB

historyはどんな感じでしょうか?

ID            CREATED        CREATED BY                                     SIZE        COMMENT
c36612233573  4 seconds ago  /bin/sh -c #(nop) CMD ["/server"]              0B          FROM adec807294e4
<missing>     4 seconds ago  /bin/sh -c #(nop) EXPOSE 8080                  0B          FROM c36612233573
<missing>     4 seconds ago  /bin/sh -c #(nop) COPY file:abc6a385865f2d...  6.78MB      FROM docker.io/library/debian:trixie-slim
50db52f24025  13 days ago    /bin/sh -c #(nop)  CMD ["bash"]                0B          
<missing>     13 days ago    /bin/sh -c #(nop) ADD file:0938f74e88fc9a5...  0B

non-root user

non-rootユーザ使ってセキュリティーのために権限を減らします。

docker run -ti example:latest /bin/sh

を実行してデフォルトはrootユーザ使っています。
それで Dockerfile を変更タイム!

FROM golang:1.21 as builder

WORKDIR /tmp/app

COPY . .
RUN go install github.com/go-delve/delve/cmd/dlv@latest
RUN go build -o /server -gcflags="-l -N" .

FROM debian:trixie-slim as final

RUN groupadd -r nonroot && \
    useradd -r -g nonroot nonroot                          

WORKDIR /home/nonroot

COPY --from=builder --chown=nonroot:nonroot /server /home/nonroot/server

RUN chmod -R 755 /home/nonroot/server

USER nonroot

EXPOSE 8080

CMD ["/home/nonroot/server"]

と同じコマンドを実行したらシェルが$を出してきます。

Volumes

キャッシュとかパソコンのフォルダーをコンテナの中に使用したい場合。

ENTRYPOINTとCMD

  • CMD: コマンドを実行、オーバロードができます。先の -ti パラメターを使って CMD を使用しませんでした。
  • ENTRYPOINT: コマンドを実行だがオーバロードできません

大ヒント! docker run -ti —entrypoint /bin/sh <image> つかって別のentrypointを設定できます。

Distroless images

さきのイメージはdebiangolangのベースイメージ使ってきましたがもっと小さいイメージも作成できます:

FROM golang:1.21 as builder

WORKDIR /tmp/app

COPY . .
RUN go install github.com/go-delve/delve/cmd/dlv@latest
RUN CGO_ENABLED=0 go build -o /server -gcflags="-l -N" .

FROM gcr.io/distroless/static-debian12 as final

COPY --from=builder /server /server

EXPOSE 8080

ENTRYPOINT ["/server"]

今回注意ことを確認しましょう

  • CGO_ENABLED=0
  • ENTRYPOINTやCMD使って大丈夫です
  • podman 使ってますので gcloud をインストールしないといけない

それでどんなイメージを作成されましたか

REPOSITORY     TAG                     IMAGE ID       CREATED         SIZE
example        latest                  43bb5066f693   5 minutes ago   8.7MB

8MiB。。。

ADDとCOPY

COPYはホストからコンテナにファイルをコピーします。ADDはコピーもできますがhttpリクエストもできます。

Compress RUNS

Dockerfileには RUNやCOPYや追加したらイメージにcommitが追加されてます。

IMAGE          CREATED          CREATED BY                        SIZE      COMMENT
43bb5066f693   16 minutes ago   ENTRYPOINT ["/server"]            0B        buildkit.dockerfile.v0
<missing>      16 minutes ago   EXPOSE map[8080/tcp:{}]           0B        buildkit.dockerfile.v0
<missing>      16 minutes ago   COPY /server /server # buildkit   6.71MB    buildkit.dockerfile.v0
<missing>      N/A                                                233kB
<missing>      N/A                                                346B
<missing>      N/A                                                497B
<missing>      N/A                                                0B
<missing>      N/A                                                64B
<missing>      N/A                                                149B
<missing>      N/A                                                1.46MB
<missing>      N/A                                                22.9kB
<missing>      N/A                                                271kB

もしあのRUNがまとめたらどうになりましょうか

FROM golang:1.21 as builder

WORKDIR /tmp/app

COPY . .
RUN go install github.com/go-delve/delve/cmd/dlv@latest && \
    go build -o /server -gcflags="-l -N" .

FROM debian:trixie-slim as final
COPY --from=builder /server /server

EXPOSE 8080

CMD ["/server"]

RUNには失敗してdocker buildもう一度実行してキャッシュを使わなくて最初からビルドされてます。

ビルドtargets

docker build --targetを実行してターゲットまでにビルドされてます。

Metadata for doc Docker

コメントアウトのように開発者の資料です。

Drop capabilities

セキュリティーに対してrootに権限を下がれます。

docker build --drop-cap

Expose ports

ドキュメントのためです。

Multi architecture

docker run --platform linux/amd64 とかできます

Ignore files

.gitignore と同じのようにしています、コンテナにコピーしたくないファイルを .dockerignore に追加してください

Workdir

$HOMEみたいなpathです


参考

Discussion