💭

Docker Desktop for WindowsでGoのホットリロードをAirでできなかったので、watchexec に変更した話

2023/12/04に公開

はじめに

Docker Desktop for Windowsでホットリローディング用ライブラリ「Air」を使ってGo言語の開発を行っていたところ、コードの変更がコンテナ内で自動的に反映されない問題に遭遇しました。WebやXで検索をかけても同様の問題で躓いている方が多いようだったので解決策の一つを共有したいと思い執筆しました。
(Mac用DockerDesktopではAirによるホットリロード可能)

結論

Airの代わりにwatchexecを使うことで解決できました。

↓↓↓こちらのツールです。
https://github.com/watchexec/watchexec

ざっくり説明すると、「ファイルが更新されたときに任意のコマンドを実行するRust製のファイル監視ツール」らしい。

既存のコードと問題点

従来のセットアップでは以下の構成でした。(多少省略しています)

フォルダ構成

src/
|
docker/ 
└── app/
│    └── Dockerfile
├── 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:
      # 環境変数の設定
      
    db:
      container_name: postgres
      image: postgres:alpine
      environment:
        # データベースの環境変数設定
      ports:
        - 5432:5432
      volumes:
        # 初期化スクリプトのマウント

起動コマンドは以下の通りです。

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/testing 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だと、ファイルシステムの違いによりツールによってはうまく動作しないことがあると知ることができ、調べていて大変勉強になりました。

Discussion