Golang の Docker 環境はこれで落ち着いた
Golang をはじめて1週間ほどですが、最初に Docker を使って環境を構築する際に結構悩みました😅
自分の備忘録も兼ねて記述しておきます。
前提
- RDB が必要
- なるべく Mac の環境は汚したくない
- go module を使う
- IDE の利用を前提として良い
この構成は gin を使ってバックエンド API を作りたいとなった時に作成したものです。 よってそういった用途にしか適さない可能性もあるのでご了承ください。
全体的に改善の余地はあると思うので、教えて頂けると嬉しいです!!
こうしたら良いのではないか
FROM golang:1.15.7-alpine as dev
ENV ROOT=/go/src/app
ENV CGO_ENABLED 0
WORKDIR ${ROOT}
RUN apk update && apk add git
COPY go.mod go.sum ./
RUN go mod download
EXPOSE 8080
CMD ["go", "run", "main.go"]
FROM golang:1.15.7-alpine as builder
ENV ROOT=/go/src/app
WORKDIR ${ROOT}
RUN apk update && apk add git
COPY go.mod go.sum ./
RUN go mod download
COPY . ${ROOT}
RUN CGO_ENABLED=0 GOOS=linux go build -o $ROOT/binary
FROM scratch as prod
ENV ROOT=/go/src/app
WORKDIR ${ROOT}
COPY ${ROOT}/binary ${ROOT}
EXPOSE 8080
CMD ["/go/src/app/binary"]
version: "3.8"
services:
db:
image: postgres:13.1-alpine
volumes:
- ./tmp/db:/var/lib/postgresql/data
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
PGDATA: /var/lib/postgresql/data/pgdata
web:
build:
context: .
dockerfile: Dockerfile
target: dev
tty: true
stdin_open: true
volumes:
- .:/go/src/app
ports:
- 8080:8080
depends_on:
- db
解説
開発中は基本的に dev ステージを利用します。
builder
以降のステージは本番運用のためです。ビルドしてバイナリを実行するだけなので今回は特に解説しません。面倒臭いので。
Dockerfile ごと分けても良いでしょう。
FROM golang:1.15.7-alpine as dev
ENV ROOT=/go/src/app
ENV CGO_ENABLED 0
WORKDIR ${ROOT}
RUN apk update && apk add git
COPY go.mod go.sum ./
RUN go mod download
EXPOSE 8080
CMD ["go", "run", "main.go"]
今自分が書いているソースコードを配置するディレクトリは、 /go/src/app
あたりにしておくのが無難だと思います🙌
module をインストールする際に流石に git は必要なので、 alpine をベースに git だけは入れておきます。
最後の CMD
でメインプロセスを動かします。なので docker-compose などで上書きしない限りはコンテナが起動したタイミングで、 main.go
が実行されることになります。
開発用のイメージですので、ソースコードの変更が反映されるように docker-compose 側でボリュームマウントしています。
volumes:
- .:/go/src/app
経緯とか。。。
以下、時系列ではありませんが、考えたことをつらつら書いておきます。。。
- IDE の入力補完のため、どうしても Mac に直接 Golang を入れる必要があった
- どのみちローカルを汚すのだから、Docker を使わない方が良いかと思ったが、RDB との連携もしたかったのでやはり Docker を使いたい
- 調べていくと
Realize
などのホットリロードツールが見つかるが、開発も止まっているようだし採用を見送った - ソースコード変更時のコンパイル、リロードは自力で行うが、IDE(私の場合は
Goland
を使用)に頼ってショートカット1つで実行できるようにする - dev ステージのイメージサイズは大体 500MB ほどだったのでもうちょっと軽くしたい気もする
- prod ステージ(scratchにバイナリファイルをコピーしただけ)のイメージサイズは何と
15MB
だった😇
おまけ
この構成はホットリロードのために余計なライブラリを入れていないのは良いのですが、流石にソースコードを変更する度にコマンドを数回叩いて再起動するのは面倒です😢
なので Goland の利用が前提になりますが、どうしたかを書いておこうと思います。VSCode とかでも出来ると思います。知らんけど。
-
画面右上の
Add Configuration
をクリックします
-
既に見えちゃっていましたが、 Docker の実行構成を作ります。
こんな感じです。なんてことはなく、単にプロジェクトルートにある docker-compose.yml
の web サービスを実行するだけです。
先ほども見たように、コンテナを立ち上げると CMD ["go", "run", "main.go"]
が走りますので、これでソースコードの変更が反映された状態でコンテナが再起動します。
ここまでやれば後は簡単です。
- 右上に作成した実行構成が表示されていることを確認した上で、右隣の Run ボタンをクリックします。
これだけでも良いのですが、何回も実行することになると思うので、できればショートカットを覚えてしまいましょう。
ショートカットは、 Ctrl + R
です😁
実行するとウィンドウが表示され、ログも確認することができます。
gin のログが表示されていますね。
追記
Docker コンテナの実行構成を使っても良いのですが、なんかタブの移動が必要だったりサクサク感が無いので、シェルスクリプトを使う方法に切り替えました。
#!/bin/bash
echo "restarting..."
docker-compose restart web
docker-compose logs -f web
やることとしては同じです。
上のようなファイルをプロジェクトルートに置きます。
Docker の時と同じようにシェルスクリプトの実行構成を作れますので、配置したスクリプトのパスを設定してください。
あとは Ctrl + R
ですぐに以下のようになります。こっちの方が良いかもしれません。
もっと良いやり方がある気がしますが、今のところはこんな感じで落ち着きました!
以上現場からでした😎
Discussion