今までDockerイメージにGoなどのコンパイルが必要な言語で書かれたプログラムを埋め込むときは、TravisでプログラムのコンパイルとDockerイメージのビルドをしてから quay.io に push するという方法を使っていたのですが、docker cloud が multi-stage builds に対応したので試してみました。
Multi-Stage Builds とは
こちらの記事がわかりやすかったです。
Docker multi stage buildで変わるDockerfileの常識
ひとつの Dockerfile
で複数回のビルドができて、他のイメージからファイルをもってこれるという機能です。
今回はGo言語のプログラムを前段のビルドでコンパイルし、生成したバイナリを scratch
イメージにコピーして軽量なDockerイメージを作るために使います。
準備
Dockerイメージに埋め込むプログラムを用意します。
hello, world.
を返すだけのHTTPサーバーです。
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "hello, world.")
})
http.ListenAndServe(":8080", nil)
}
Dockerfile を書きます。
FROM golang:1.8
ADD main.go main.go
RUN go build --ldflags '-s -w -linkmode external -extldflags -static' -o /server
FROM scratch
COPY --from=0 /server /server
EXPOSE 8080
CMD ["/server"]
コンパイル部分ですが、なにも考えずに go build
すると dynamic link なバイナリができてしまうので ldflags
を指定しています。
-linkmode external -extldflags -static
で static link なバイナリになるようです。
-s -w
についてはファイルサイズを減らすために書いています。
COPY --from=0
が multi-stage builds の他のビルドからファイルをコピーする部分です。
docker cloud の automated builds 設定
Docker公式ブログに記事があったのでこれを見ながら設定します。
https://blog.docker.com/2017/07/multi-stage-builds/
使用するDockerのバージョンを 17.05.0-ce
に変える必要があるので注意してください。
検証
設定が終わったら git push
してみます。
$ git push
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 360 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To https://github.com/bgpat/helloworld-server
52f5d80..18cfefd master -> master
しばらくすると docker cloud の自動ビルドが始まります。
ビルドが終わったら docker pull
& docker run
で試してみます。
$ docker pull bgpat/helloworld-server
Using default tag: latest
latest: Pulling from bgpat/helloworld-server
0223ce31a88e: Pull complete
Digest: sha256:aaafdd815b9448c59da801ac4fa88a548782bb1e1dcef2da0683b08586a176f4
Status: Downloaded newer image for bgpat/helloworld-server:latest
$ docker images bgpat/helloworld-server
REPOSITORY TAG IMAGE ID CREATED SIZE
bgpat/helloworld-server latest 004a08d7f83b About an hour ago 4.79MB
イメージのサイズは 4.79MB
でした。軽いです。
$ docker run -d -p8080:8080 bgpat/helloworld-server
4523ae15024fd964d63f3f82c12b6a44d7759ade0e31811a5218b07facc98d1e
$ curl http://localhost:8080/
hello, world.
ちゃんと動いているようです。