6
4

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.

docker + Go言語でAPIサーバを立てる

Posted at

やること

Docker + Go言語でAPIサーバを立てたいという時の環境構築をします。その際、以下のことを満たせるようにDockerfile等を設計していきます。

  • multi stage buildを用いて、production環境でのimageサイズをなるべく小さくする
  • Dockerfileはdev環境とprod環境で共通のものを用いる

Dockerfileの書き方

まず、Docker 17.05でmulti stage buildという機能が導入されているので、それを使います。

次のようにFROMが2つあるようにし、中間ステージのものに対してはAS buildのように名前をつけておきます。

FROM golang:latest AS build
WORKDIR /go/src/github.com/nkjmsss/sample
ENV GO111MODULE=on
# make cache
COPY go.mod .
COPY go.sum .
RUN go mod download
# COPY the source code as the last step
COPY . .
# build app for next stage
RUN go build -o /go/bin/app

FROM alpine:latest
WORKDIR /app
COPY --from=build /go/bin/app .
# add user
RUN addgroup go && \
    adduser -D -G go go && \
    chown -R go:go /app/app
CMD [ "./cms" ]

これの大事な部分について説明していきます。

1. GO111MODULE

これは、Go 1.11より導入されたバージョン管理機能を有効にするためのフラグです。v1.11と現バージョンのv1.12では、これはデフォルトでautoとなっているので、これを強制的にonにしておきます(gopathの中では、GO111MODULEのautoはoffと等価です)。なお、秋頃リリースと噂のGo 1.13ではこの環境変数がデフォルトでonとなるようなので、過渡期の今限定で設定しなければならないものです。

なぜこれをわざわざ指定しているかというと、例えばechoというフレームワークでAPIサーバを立てる場合、v4を明示的に指定する必要があるためです。個人的にはecho + swaggoでの開発が好きなのですが、そうする場合次のようにimportすることになります。GO111MODULEを指定していない段階ではそもそも組み合わせるのがかなり困難だったので、指定するようにしましょう。

import (
	"github.com/labstack/echo/v4"
	echoSwagger "github.com/swaggo/echo-swagger/v2"
)

2. cache

imageのビルドを高速化するにはかなり重要な部分です。

Go modulesが有効な状態では、go.modとgo.sumの2つのファイルで使用するパッケージのバージョンを指定しています。そして、これらは通常の開発の場合はパッケージを追加インストールする時くらいしか更新されません。なので、これらをdockerの中の単独なレイヤーにしておくことで、ビルド時にdockerがcacheを使えるようになり、go mod downloadを高速化できます。

最初にCOPY . .としてしまうとcacheが上手に使えず、ビルドの度にgo mod downloadでネット上からダウンロードしようとするので非常に時間がかかってしまいます。

3. 中間ステージからのCOPY

後半にCOPY --from=build /go/bin/app .というものがありますが、--from=buildでbuildステージで予めビルドしておいたものをコピーしてきます。これのおかげでproduction環境の方はGoをインストールする必要がなくなるので、イメージサイズを小さくすることが可能になります。

4. ユーザの追加

公式docにあるように、rootでないユーザで実行するようにしたほうがセキュリティの観点上良いと思われます。

docker-compose.ymlの書き方

version: "3.5"
services:
  echo:
    build:
      context: .
      target: build
    volumes:
      - .:/go/src/github.com/nkjmsss/sample
    ports:
      - "1323:1323"
    command: go run main.go

これの大事なところは、versionを3.4以上に指定してbuild時にbuild stageをtargetにすることです。

docker-compose.prod.ymlの書き方

version: "3.5"
services:
  echo:
    build: .
    ports:
      - "1323:1323"

こちらでは、別にversion3.5を指定する必要は特にないです。

おわりに

$ docker-compose build
$ docker-compose up -d

とすると、dev環境が立ち上がり、

$ docker-compose -f docker-compose.prod.yml build
$ docker-compose -f docker-compose.prod.yml up -d

とするとprod環境が立ち上がります。

今回は説明の都合から最小構成で書いていますが、

  • docker-compose.ymlにdev環境かどうかを指定する環境変数を追加する
  • realize等のツールを用いて、dev環境では自動リロードできるようにする
  • makefileで長いdocker-compose -f docker-compose.prod.yml build等を簡潔にする

などをしておけば、より快適な開発環境が整うのではないでしょうか。

ちなみに、自分の最近作ったAPIサーバでは、build stageが1GB程度あったものが、prod環境では90MBとイメージサイズを1/10程度にすることができています。

6
4
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
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?