28
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Go1.12+go modでDockerコンテナ化

Posted at

お題

k8sの勉強しがてら、GoのアプリでもGKEに乗せてみようと思いつつ、そういえば、表題の組み合わせでDockerコンテナ作ったことないなと気づく。
前回最後にDockerコンテナ作った時は、Go1.9+dep だった、たしか。
というわけで、知識をアップデートしておく。

開発環境

# OS

$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="18.04.2 LTS (Bionic Beaver)"

# Docker

$ sudo docker version
Client:
 Version:           18.09.2
 API version:       1.39
 Go version:        go1.10.4
 Git commit:        6247962
 Built:             Tue Feb 26 23:52:23 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.09.2
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.4
  Git commit:       6247962
  Built:            Wed Feb 13 00:24:14 2019
  OS/Arch:          linux/amd64
  Experimental:     false

実践

Goアプリ

まあ、アプリの内容は何でもいいので、とりあえず http://localhost:8080/sample でアクセスしたら 200 OK をJSON形式で返すのを書いておく。

[main.go]
package main

import (
	"net/http"

	"github.com/labstack/echo"
)

func main() {
	e := echo.New()
	e.GET("/sample", func(c echo.Context) error {
		return c.JSON(
			http.StatusOK,
			struct {
				Code int    `json:"code"`
				Text string `json:"text"`
			}{
				Code: http.StatusOK,
				Text: http.StatusText(http.StatusOK),
			},
		)
	})
	e.Logger.Fatal(e.Start(":8080"))
}

ローカル環境で実行すると↓のように8080ポートで待ち受ける。

$ go run main.go 

   ____    __
  / __/___/ /  ___
 / _// __/ _ \/ _ \
/___/\__/_//_/\___/ v3.3.10-dev
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
                                    O\
⇨ http server started on [::]:8080

ちなみに、go.mod はこんな感じ。

[go.mod]
module t01

require (
	github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
	github.com/labstack/echo v3.3.10+incompatible
	github.com/labstack/gommon v0.2.8 // indirect
	github.com/mattn/go-colorable v0.1.1 // indirect
	github.com/mattn/go-isatty v0.0.7 // indirect
	github.com/valyala/fasttemplate v1.0.1 // indirect
	golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480 // indirect
)

Dockerfile

以下を参考に。
https://medium.com/@petomalina/using-go-mod-download-to-speed-up-golang-docker-builds-707591336888

# step 1: build
FROM golang:1.12.4-alpine3.9 as build-step

# for go mod download
RUN apk add --update --no-cache ca-certificates git

RUN mkdir /go-app
WORKDIR /go-app
COPY go.mod .
COPY go.sum .

RUN go mod download
COPY . .

RUN CGO_ENABLED=0 go build -o /go/bin/go-app

# -----------------------------------------------------------------------------
# step 2: exec
FROM scratch
COPY --from=build-step /go/bin/go-app /go/bin/go-app
ENTRYPOINT ["/go/bin/go-app"]

特記事項

■ベースイメージを「Docker Hub」から取得しているのでdocker loginが必要

してないと、こうなる。

$ sudo docker build -t sky0621/go-app:v0.1 .
Sending build context to Docker daemon  7.168kB
Step 1/8 : FROM "1.11.9-alpine3.9" AS builder
pull access denied for 1.11.9-alpine3.9, repository does not exist or may require 'docker login'

なので、docker loginする。
【参考】
http://docs.docker.jp/docker-hub/accounts.html

$ sudo docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: sky0621dhub
Password: 
WARNING! Your password will be stored unencrypted in /home/sky0621/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

■「RUN apk add --update --no-cache ca-certificates git」がないと、RUN go mod downloadが失敗する。

Step 6/11 : RUN go mod download
 ---> Running in 1b5ecc7774b5
go: github.com/dgrijalva/jwt-go@v3.2.0+incompatible: git init --bare in /go/pkg/mod/cache/vcs/11fb0427c36fe2d22a58c95464426a2d142ff24c438e1248eeb9ff450be5af41: exec: "git": executable file not found in $PATH
  〜〜 省略 〜〜
go: golang.org/x/crypto@v0.0.0-20190418165655-df01cb2cc480: git init --bare in /go/pkg/mod/cache/vcs/de5fd3af413a4f3f969455ae522b4002fcb7bb4c158f339396dfc77710c9007d: exec: "git": executable file not found in $PATH
go: error loading module requirements
The command '/bin/sh -c go mod download' returned a non-zero code: 1

■「CGO_ENABLED=0」がないと、docker runが失敗する。

$ sudo docker run -p 80:8080 sky0621/go-app:v0.1
standard_init_linux.go:207: exec user process caused "no such file or directory"

cgoというのは、GoからCのコードを呼び出すコマンドらしい。
それを有効にする(=1)か無効にする(=0)かの指定が「CGO_ENABLED」でデフォルトでは有効とのこと。
(ただし、クロスコンパイル時はデフォルトで無効)
有効の場合、ビルド制約としてcgoがセットされる。
【参考】
https://golang.org/cmd/cgo/

standard_init_linux.goの中身は追っていないので、ここでエラーになった原因であると断定は出来ないのだけど、ビルド制約cgoを外すことでdocker run時の失敗は回避された。

ビルド

事前にdockerプロセスもイメージもないことを確認。

$ sudo docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
$
$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

では、実行。

$ ls -l
total 16
-rw-r--r-- 1 sky0621 sky0621  464 Apr 20 08:52 Dockerfile
-rw-r--r-- 1 sky0621 sky0621  420 Apr 19 08:00 go.mod
-rw-r--r-- 1 sky0621 sky0621 1895 Apr 19 08:00 go.sum
-rw-r--r-- 1 sky0621 sky0621  375 Apr 19 09:23 main.go
$
$ date
Sat Apr 20 09:11:41 JST 2019
$
$ sudo docker build -t sky0621/go-app:v0.1 .
Sending build context to Docker daemon  6.656kB
Step 1/12 : FROM golang:1.12.4-alpine3.9 as build-step
1.12.4-alpine3.9: Pulling from library/golang
bdf0201b3a05: Pull complete 
38f114998adb: Pull complete 
21134b1a9e68: Pull complete 
cff36310a8c5: Pull complete 
02f293f0b51b: Pull complete 
Digest: sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Status: Downloaded newer image for golang:1.12.4-alpine3.9
 ---> b97a72b8e97d
Step 2/12 : RUN apk add --update --no-cache ca-certificates git
 ---> Running in 0c5bb1e980c9
fetch http://dl-cdn.alpinelinux.org/alpine/v3.9/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.9/community/x86_64/APKINDEX.tar.gz
(1/6) Installing nghttp2-libs (1.35.1-r0)
(2/6) Installing libssh2 (1.8.2-r0)
(3/6) Installing libcurl (7.64.0-r1)
(4/6) Installing expat (2.2.6-r0)
(5/6) Installing pcre2 (10.32-r1)
(6/6) Installing git (2.20.1-r0)
Executing busybox-1.29.3-r10.trigger
OK: 20 MiB in 21 packages
Removing intermediate container 0c5bb1e980c9
 ---> 0625379ca405
Step 3/12 : RUN mkdir /go-app
 ---> Running in 82c9e6be294d
Removing intermediate container 82c9e6be294d
 ---> 0e99542d29eb
Step 4/12 : WORKDIR /go-app
 ---> Running in 7929d16e6ce4
Removing intermediate container 7929d16e6ce4
 ---> 2bb8099a90aa
Step 5/12 : COPY go.mod .
 ---> 77a7fb906751
Step 6/12 : COPY go.sum .
 ---> da9177c9aaa1
Step 7/12 : RUN go mod download
 ---> Running in a60a8f304669
go: finding github.com/labstack/echo v3.3.10+incompatible
go: finding github.com/mattn/go-colorable v0.1.1
go: finding github.com/dgrijalva/jwt-go v3.2.0+incompatible
go: finding github.com/labstack/gommon v0.2.8
go: finding github.com/mattn/go-isatty v0.0.7
go: finding github.com/valyala/fasttemplate v1.0.1
go: finding golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480
go: finding github.com/mattn/go-isatty v0.0.5
go: finding github.com/valyala/bytebufferpool v1.0.0
go: finding golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e
go: finding golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223
Removing intermediate container a60a8f304669
 ---> 44992184e9e2
Step 8/12 : COPY . .
 ---> 8e8041d6ff86
Step 9/12 : RUN CGO_ENABLED=0 go build -o /go/bin/go-app
 ---> Running in 1baafdb9189b
Removing intermediate container 1baafdb9189b
 ---> 51d15d46907b
Step 10/12 : FROM scratch
 ---> 
Step 11/12 : COPY --from=build-step /go/bin/go-app /go/bin/go-app
 ---> 6031f71f0586
Step 12/12 : ENTRYPOINT ["/go/bin/go-app"]
 ---> Running in a27a508d1102
Removing intermediate container a27a508d1102
 ---> 1ecb02037408
Successfully built 1ecb02037408
Successfully tagged sky0621/go-app:v0.1
$
$ date
Sat Apr 20 09:12:23 JST 2019

かかった時間は、ざっと「42」秒。けっこうかかるね。。

Sat Apr 20 09:11:41 JST 2019
Sat Apr 20 09:12:23 JST 2019

イメージの確認

Goのビルドなどに使ったイメージはそれなりのサイズではあるものの、実際に動かすGoアプリのイメージは「8.43MB」と軽量。

$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
sky0621/go-app      v0.1                1ecb02037408        13 minutes ago      8.43MB
<none>              <none>              51d15d46907b        13 minutes ago      413MB
golang              1.12.4-alpine3.9    b97a72b8e97d        7 days ago          350MB

実行

$ sudo docker run -p 80:8080 sky0621/go-app:v0.1

   ____    __
  / __/___/ /  ___
 / _// __/ _ \/ _ \
/___/\__/_//_/\___/ v3.3.10-dev
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
                                    O\
⇨ http server started on [::]:8080

起動した。
では、アクセス。
screenshot-localhost-2019.04.20-09-32-43.png

OK。

キャッシュ確認

Dockerfileのつくりによるキャッシュの効果を確認するために、Goアプリを微修正して再ビルドしてみる。
ビルド時間が短くなることを期待。

Goアプリを微修正

受け付けるパスを「/sample」→「/sample2」に変えただけ。

$ git diff
diff --git a/chXX_try/app/main.go b/chXX_try/app/main.go
index acb93c1..522a0e4 100644
--- a/chXX_try/app/main.go
+++ b/chXX_try/app/main.go
@@ -8,7 +8,7 @@ import (
 
 func main() {
        e := echo.New()
-       e.GET("/sample", func(c echo.Context) error {
+       e.GET("/sample2", func(c echo.Context) error {
                return c.JSON(
                        http.StatusOK,
                        struct {

再ビルド

$ date
Sat Apr 20 09:43:21 JST 2019
$
$ sudo docker build -t sky0621/go-app:v0.2 .
Sending build context to Docker daemon  6.656kB
Step 1/12 : FROM golang:1.12.4-alpine3.9 as build-step
 ---> b97a72b8e97d
Step 2/12 : RUN apk add --update --no-cache ca-certificates git
 ---> Using cache
 ---> 0625379ca405
Step 3/12 : RUN mkdir /go-app
 ---> Using cache
 ---> 0e99542d29eb
Step 4/12 : WORKDIR /go-app
 ---> Using cache
 ---> 2bb8099a90aa
Step 5/12 : COPY go.mod .
 ---> Using cache
 ---> 77a7fb906751
Step 6/12 : COPY go.sum .
 ---> Using cache
 ---> da9177c9aaa1
Step 7/12 : RUN go mod download
 ---> Using cache
 ---> 44992184e9e2
Step 8/12 : COPY . .
 ---> c9a3ca188d54
Step 9/12 : RUN CGO_ENABLED=0 go build -o /go/bin/go-app
 ---> Running in 4aaa5be99f06
Removing intermediate container 4aaa5be99f06
 ---> f3ab3206497a
Step 10/12 : FROM scratch
 ---> 
Step 11/12 : COPY --from=build-step /go/bin/go-app /go/bin/go-app
 ---> fa6b7e4787a8
Step 12/12 : ENTRYPOINT ["/go/bin/go-app"]
 ---> Running in d17c0c300e5b
Removing intermediate container d17c0c300e5b
 ---> 0b607262dca1
Successfully built 0b607262dca1
Successfully tagged sky0621/go-app:v0.2
$
$ date
Sat Apr 20 09:43:33 JST 2019

早くなってる。「12」秒。(初回は「42」秒だった。)
キャッシュ効果、大きいね。

Sat Apr 20 09:43:21 JST 2019
Sat Apr 20 09:43:33 JST 2019

まとめ

簡素なアプリで試しただけではあるものの、ひとまずGo1.12+go modでのDockerコンテナ化は完了。
Dockerfileに関しては定期的に↓など再確認しないとなぁと思った。
http://docs.docker.jp/v1.9/engine/articles/dockerfile_best-practice.html

28
25
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
28
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?