はじめに
Docker Desktop for Windowsでホットリローディング用ライブラリ「Air」を使ってGo言語の開発を行っていたところ、コードの変更がコンテナ内で自動的に反映されない問題に遭遇しました。WebやXで検索をかけても同様の問題で躓いている方が多いようだったので解決策の一つを共有したいと思い執筆しました。
(Mac用DockerDesktopではAirによるホットリロード可能)
結論
Airの代わりにwatchexec
を使うことで解決できました。
↓↓↓こちらのツールです。
https://github.com/watchexec/watchexec
ざっくり説明すると、「ファイルが更新されたときに任意のコマンドを実行するRust製のファイル監視ツール」らしい。
既存のコードと問題点
従来のセットアップでは以下の構成でした。(多少省略しています)
フォルダ構成
current_directory
|
├── docker/
| └── app/
| └── Dockerfile
├── src/
| └── main.go
|
└── docker-compose.yml
Dockerfile
FROM golang:1.18.3-alpine
WORKDIR /app
COPY ./src .
RUN apk upgrade --update && \
apk --no-cache add git && \
apk upgrade git
RUN go install github.com/cosmtrek/air@latest
RUN go mod download
CMD ["air", "-c", ".air.toml"]
docker-compose.yml
version: '3.9'
services:
app:
container_name: go_app
build:
context: .
dockerfile: ./docker/app/Dockerfile
ports:
- "8080:8080"
volumes:
- ./src/:/app
tty: true
environment:
# 環境変数の設定
起動コマンドは以下の通りです。
docker compose build
docker compose run --rm app go mod tidy
docker compose up -d
しかし、このセットアップではDocker Desktop for Windows環境においてホットリローディングが機能しませんでした。
解決策: watchexec の使用
問題を解決するために、watchexec を用いた新しい Dockerfile に変更しました。
dockerfile
FROM golang:1.18.3-alpine
WORKDIR /app
COPY ./src .
RUN apk upgrade --update && \
apk --no-cache add git && \
apk upgrade git
RUN go mod download
# watchexec のインストール
RUN apk add --no-cache -X http://dl-cdn.alpinelinux.org/alpine/edge/community watchexec
# ホットリロード用のコマンドを設定
CMD ["watchexec", "-w", ".", "--force-poll", "100", "-r", "go", "run", "main.go"]
動作原理
watchexec はファイルシステムの変更を監視し、変更が検出されると指定されたコマンド(この場合は go run main.go)を実行します。
--force-poll
オプションにより、定期的にファイルシステムをポーリングすることで、Docker Desktop for Windows上のファイルシステム通知の遅延や不具合を解決しています。
ホットリローディングの確認
この変更を適用した後、以下コマンドを使用してコンテナをビルド、起動します。
docker compose build
docker compose run --rm app go mod tidy
docker compose up -d --force-recreate
これで、ローカルのソースコードに変更を加えるとwatchexec が検知し、Golangアプリケーションを自動的に再起動します。これにより、変更がすぐに反映され、DockerDesktop for Windowsでの開発プロセスがスムーズになります。
まとめ
Docker Desktop for WindowsでGo言語の開発を行う際にホットリローディングを実現するためには、watchexec のようなツールの使用が効果的です。
watchexec により、Golangアプリケーションの開発効率が向上し、コードの変更が即座に反映されるため、より迅速な開発サイクルを実現できます。
同じような問題に直面している他の開発者にも、この方法を試してみることをお勧めします。ついでに❤くれると大変励みになります笑
また、当初DockerDesktop for Mac のみでGolangアプリの開発をしていたので気づかなかったのですが、DockerDesktop for Windowsだと、ファイルシステムの違いによりツールによってはうまく動作しないことがあると知ることができ、調べていて大変勉強になりました。