自作のGolang製プログラムをDockerで動かせるようになるまで
モチベーション
- Golangで作ったプログラムをDockerで動かせるようになりたい
- ベースとなるイメージは軽いほうがよい
- 重要度としては「イメージは軽いほうがよい」< 「とりあえず動く」
- 開発環境でもPostgreSQLを動かしたいが、構築が面倒なのでDockerとcomposeでシュッと構築できてほしい
前提
- PythonのプログラムをDockerで動かしたことがある程度
- 自作したプログラム
- Webアプリケーションのバックエンド
- PostgreSQLをDBとして利用
- docker composeでよしなにしたい
やること
- WSL上のdebianにDockerとdocker composeを入れる
- Dockerfileを書く
- compose.ymlを書く
- WSL上のdebianにDockerとdocker composeを入れる
このページを参考に構築すればできた。aptリポジトリを追加してapt update
、apt install
すればよい。
Dockerfileを書く際に、どこに注意してイメージを軽くできるだろうか?
- マルチステージングビルド: https://docs.docker.jp/develop/develop-images/multistage-build.html
- 使うコンテナを吟味する
マルチステージングビルド
1つのDockerfileに複数回のFROM
が使われること?
アプリケーションをビルドする際に使うイメージと、アプリケーションを動作させる際に使うイメージを分割する。
アプリケーションをビルドする際に使うイメージを仮にbuilder
とすると、実際にはFROM hogehoge AS builder
と書くことになる。
ビルドされた成果物をbuilderからアプリケーションを動作させる際に使うイメージへ移すとなると、COPY --from=builder hogehoge ./
みたいなことを書けばよいらしい
使うコンテナを吟味する
アプリケーションをビルドする際に使うイメージ
cgoなどが使えたほうが後々よさそう。というのも、データベースドライバなどがcgoを利用していたりするし、後々で音声を取り扱うことを予定しているため、音声を取り扱うライブラリがC言語で書かれていたりするため。
最終的には公式イメージのgolang:1.22-bookworm
を使うことに。
アプリケーションを動作させる際に使うイメージ
Googleが作っているdistrolessイメージが流行っているっぽい?
最近はalpine linuxを使うことは控えられてきている?代わりにdebianの-slim
みたいなやつが使われてきている?
Golangのコンパイラは静的なシングルバイナリを出力するため、distrolessイメージのうち、base
、base-nossl
、static
が使えそう。
どれを使えばいいのかよくわからないので、このREADMEを読む。
コンテナサイズも大事だがとりあえず動くことを目標としたいので、この中で一番安全そうなbase-debian12
を使うことにする
以上を踏まえて作ったDockerfileがこんな感じになった:
FROM golang:1.22-bookworm as builder
WORKDIR /app/
COPY go.mod ./
COPY go.sum ./
RUN go mod download
COPY . .
RUN go build -o main ./bin/main.go
FROM gcr.io/distroless/base-debian12
WORKDIR /app/
COPY ./.config /app
COPY ./files /app
COPY /app/main /app
CMD ["./main", "-config", "./.config/config.toml"]
dockerfileをビルドする際はこんな感じにshellを叩く:
$ docker build -t {{imageの名前}} {{Dockerfileのあるディレクトリ}}
compose.ymlはこんな感じ。misskeyのdocker-composeを参考に。
version: "3"
services:
backend:
build: .
restart: always
links:
- db
depends_on:
db:
condition: service_healthy
ports:
- "3001:3001"
env_file:
- .config/docker.env
volumes:
- ./files:/app/files
- ./.config:/app/.config:ro
db:
restart: always
image: postgres:16-alpine
ports:
- "5432:5432"
env_file:
- .config/docker.env
volumes:
- ./postgres:/var/lib/postgresql/data
healthcheck:
test: "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"
interval: 5s
retries: 20
ここまで来て気がついたのだが、マイグレーションが走っていないような気がする。
今回はdbmateを使っているのでdbmate up
をshellから実行すればよい。
しかし、使っているコンテナであるdistrolessでshellを実行するのには一癖がありそうである。
しかし、幸運なことにdbmateにはdocker imageを配布しているので、これを利用しようと思う。
これを利用すると、以下のように実行されれば起動することができそうである。
- postgresqlが起動する
- dbmateのコンテナを実行し、正常終了する
- 自作Webアプリケーションが起動する