About

Golang(Echo)でDockerfileを開発と本番で同じものを使いつつ、docker-composeを使う。
なおかつホットリロードもする。

前提

    • Golang

1.12

docker

18.09.2

docker-compose

1.23.2

realize

2.0.2

Docker環境を用意する

とりあえず最低限のEchoサーバーを動かすこと前提

main.go

main.go を記述

package main

import (
    "net/http"

    "github.com/labstack/echo"
)

func main() {
    e := echo.New()
    e.GET("/", func(c echo.Context) error {
        return c.String(http.StatusOK, "Hello, World!")
    })
    e.Logger.Fatal(e.Start(":1323"))
}

modulesの初期設定

go.mod を手に入れる

$ docker run -v `pwd`:/go/app -w /go/app golang:1.12-alpine go mod init app
go: creating new go.mod: module app
$ ls
go.mod  main.go

ここで go.sum が欲しい人はよしなに。

Dockerfile

DockerのMulti-Stage Buildを使ってレイヤーを2つ用意します。
1つ目のレイヤーはdocker-composeで使用するため、
2つ目のレイヤーは本番で使用するために使います。

FROM golang:1.12-alpine as build

WORKDIR /go/app

COPY . .

RUN apk add --no-cache git \
 && go build -o app

FROM alpine

WORKDIR /app

COPY --from=build /go/app/app .

RUN addgroup go \
  && adduser -D -G go go \
  && chown -R go:go /app/app

CMD ["./app"]

動作確認をしておきましょう。

$ docker build -t myapp .
$ docker run -p 1323:1323 -d --name myapp myapp
$ curl localhost:1323
Hello, World!

動いたのを確認できたらコンテナを落とします。

$ docker stop down myapp
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
$

docker-compose

docker-composeを動かすために docker-compose.yml を記述します。

この時に指定する target: build がポイントです。
Multi-Stage Buildのレイヤーを使用することができます。

version: '3.5'

services:
  app:
    build:
      context: .
      target: build
    volumes:
      - ./:/go/app
    command: go run main.go
    ports:
      - 1323:1323

さて、動作確認です。

$ docker-compose up
Recreating echo_app_1 ... done
Attaching to echo_app_1
app_1  | go: finding github.com/labstack/gommon/color latest
app_1  | go: finding github.com/labstack/gommon/log latest
app_1  | go: finding golang.org/x/crypto/acme/autocert latest
app_1  | go: finding golang.org/x/crypto/acme latest
app_1  | go: finding golang.org/x/crypto latest
app_1  | go: finding github.com/valyala/fasttemplate latest
app_1  |
app_1  |    ____    __
app_1  |   / __/___/ /  ___
app_1  |  / _// __/ _ \/ _ \
app_1  | /___/\__/_//_/\___/ v3.3.10-dev
app_1  | High performance, minimalist Go web framework
app_1  | https://echo.labstack.com
app_1  | ____________________________________O/_______
app_1  |                                     O\
app_1  | ? http server started on [::]:1323

別のターミナルを起動してcurlを打ってみましょう

$ curl localhost:1323
Hello, World!

動いてますね。

ホットリロードを導入する

oxequa/realize を使用して実現します

Dockerfileの編集

realizeのインストール

FROM golang:1.12-alpine as build

WORKDIR /go/app

COPY . .

RUN apk add --no-cache git \
-  && go build -o app
+  && go build -o app \
+  && go get github.com/oxequa/realize

FROM alpine

WORKDIR /app

COPY --from=build /go/app/app .

RUN addgroup go \
  && adduser -D -G go go \
  && chown -R go:go /app/app

CMD ["./app"]

docker-composeの編集

realizeを使用して起動するようにする

version: '3.5'

services:
  app:
    build:
      context: .
      target: build
    volumes:
      - ./:/go/app
-    command: go run main.go
+    command: realize start --run --no-config
    ports:
      - 1323:1323

動作確認

$ docker-compose up
Recreating echo_app_1 ... done
Attaching to echo_app_1
app_1  | len [0/0]0x0
app_1  | [10:25:29][APP] : Watching 1 file/s 1 folder/s
app_1  | [10:25:29][APP] : Install started
app_1  | [10:25:30][APP] : Install completed in 0.805 s
app_1  | [10:25:30][APP] : Running..
app_1  | [10:25:30][APP] :    ____    __
app_1  | [10:25:30][APP] :   / __/___/ /  ___
app_1  | [10:25:30][APP] :  / _// __/ _ \/ _ \
app_1  | [10:25:30][APP] : /___/\__/_//_/\___/ v3.3.10-dev
app_1  | [10:25:30][APP] : High performance, minimalist Go web framework
app_1  | [10:25:30][APP] : https://echo.labstack.com
app_1  | [10:25:30][APP] : ____________________________________O/_______
app_1  | [10:25:30][APP] :                                     O\
app_1  | [10:25:30][APP] : ? http server started on [::]:1323

動いてますね。
curlをして動作確認してみましょう。

$ curl localhost:1323
Hello, World!

最後に main.go を編集してホットリロードされるかの確認です

package main

import (
    "net/http"

    "github.com/labstack/echo"
)

func main() {
    e := echo.New()
    e.GET("/", func(c echo.Context) error {
-        return c.String(http.StatusOK, "Hello, World!")
+        return c.String(http.StatusOK, "Good Bye.")
    })
    e.Logger.Fatal(e.Start(":1323"))
}
$ curl localhost:1323
Good Bye.
广告
将在 10 秒后关闭
bannerAds