0
Help us understand the problem. What are the problem?

posted at

updated at

go開発環境をDockerで作成する④ - realizeでホットリロード

最終目的

  • go言語でWebアプリを構築するためのgo開発環境をDockerで作成する。

目標

やること

  • realizeをイメージビルド時にインストール
  • コンテナ立ち上げ時にrealizeでgo-blogをホットリロード

開発環境の構成

開発環境 go-env の構成は下記の通り。

開発環境
go-env/                           ★ 開発環境構成go-envはGitHubのレポジトリ
  ├── docker-compose.dev.yml
  ├── env/
  │   └── Dockerfile.blog.dev     ★ go-blogのDockerイメージを作成するためのDockerfile
  ├── Makefile
  └── src/
    └── go-blog/                  ★ go-blogディレクトリはgo-envとは別のGitHubレポジトリ
        ├── .realize.yaml         ★ realizeの設定ファイル
        └── app/
            ├── entrypoints/
            │   └── production/
            │       └── main.go
            ├── go.mod
            └── go.sum

realizeをイメージビルド時にインストール

ホットリロードとは、ソースコードが変更されたことを検知し、自動的にリビルドおよびプログラムを再起動すること。便利。
realizeとは、go言語で書かれたホットリロードアプリ。

realizeは2年近く更新されておらず、最近ではairが使われているようだが、airは使いにくい。
いつまで使えるかはわからないが、まだ手放せない...

Dockerfile.blog.devの修正(realizeのイメージビルド時インストール)

下記の通り、root権限で動作する位置に、realizeをインストールするように定義を追記する。

realizeの@latestはmodule modeでのgo installでのインストールが現在(2022/06/12)できない。
一度、module modeをoffにして、realizeをgo getでインストールする。
なお、現在、go1.15以下ではgo getでのインストールもエラーとなる。

realizeのインストール
--- a/env/Dockerfile.blog.dev
+++ b/env/Dockerfile.blog.dev
@@ -11,12 +11,18 @@ RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime

 ENV DEBIAN_FRONTEND=noninteractive
 RUN apt update && apt install -y sudo

 RUN apt install -y jq tree diffutils nano vim
 
+# realizeのインストール
+# module modeではインストールできない。
+ENV DEBIAN_FRONTEND=noninteractive
+RUN GO111MODULE=off go get github.com/oxequa/realize
+ENV GO111MODULE=on
+
 # システムアカウントの作成(ホームディレクトリは作成しない)
 RUN groupadd -g $GROUP_ID $GROUP_NAME && \
     useradd -s /bin/bash -u $USER_ID -g $GROUP_ID -G sudo $USER_NAME -r -d /home/$USER_NAME -M && \
     echo "$USER_NAME   ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

realizeの設定

realizeの設定は.realize.yamlに記述する。コンテナ内のディレクトリ構成を意識して、設定を記述する。

コンテナ内のディレクトリ構成は下記の通り。

コンテナ内のディレクトリ構成(抜粋)
/
├── dist/                                  ★ go-blogアプリを起動するディレクトリ
│   └── go-blog                            ★ webアプリケーションの実行バイナリ
└── src/ 
    └── go-blog/                           ★ コンテナ起動時にホストPCのディレクトリをマウント
        ├── .realize.yaml                  ★ realizeの設定ファイル
        └── app/
            ├── go.mod
            └── entrypoints/production
                └── main.go                ★ mainパッケージのエントリープログラム

realizeでやりたいこと

/src/go-blog/appディレクトリ配下のgoソースファイルが変更になったとき...

  • go mod tidyを実行したい
  • entrypoints/production/main.goから/dist/go-blogコマンドをビルドしたい
  • /dist/go-blogコマンドを再起動したい

airを使わない理由

  • Mac/Linuxではファイルの変更を検知できるが、WSL上ではある条件下でファイル変更が検知できない。
    • /mnt/<drive>配下のファイルはinotifyが働かないため。
  • go mod tidyをどうやったら実行できるかわからない...

realizeの設定ファイルを作成

.realize.yamlファイルを作成。

WindowsでDockerを動かしているときは注意。

.realize.yaml
settings:
  # WindowsのWSLでdockerを動作させている場合で、コードが/mnt/<drive>に配置されている場合、
  # inotifyが働かないので、ポーリングで動作するようにforce:trueに変更する
  legacy:
    force: false      # ★ Windowsではtrueにする ★
    interval: 1s      # ポーリング間隔になるので短くするとPCに負荷がかかる

# サーバー設定(状態をWebで確認できる)
server:
  open: false
  port: 5002
  host: 0.0.0.0

# ホットロード設定
schema:
  - name: go-blog     # プロジェクト名(好きな名前で)
    path: app         # 監視対象パス(.realize.yamlがあるディレクトリからの相対パス)

    # コマンド実行設定
    commands:
      build:
        status: true  # ビルドを再起動前に実施する
        # ビルド時のコマンド(/dist/go-blogにビルド)
        method: go build -o /dist/go-blog entrypoints/production/main.go
      run:
        status: true  # コマンド再起動する
        # 再起動時のコマンド
        method: /dist/go-blog

    # ファイル監視設定
    watcher:
      extensions:    # 監視対象ファイルの拡張子
        - go
      paths:         # 監視対象ディレクトリ(schema/pathからの相対パスで指定)
        - .
      scripts:
        # go mod tidyを実施する
        - command: go mod tidy
          type: before     # ビルドの前
          path: app        # 実行ディレクトリ(.realize.yamlがあるディレクトリからの相対パス)
          output: true
      ignored_paths:
        - .git
        - .realize

コンテナ起動時にrealizeを起動させる

Dockerfile.blog.devの修正(realizeを立ち上げるように変更)

コンテナ起動時にrealizeを起動するように Dockerfile.blog.dev を修正する。

# ワークディレクトリを /dist に切り替え(システムアカウント実行)
WORKDIR /dist

# テンポラリの/tmp/appディレクトリを削除(システムアカウント実行)
RUN rm -rf /tmp/app

# # コンテナ起動時にgo-blogコマンドが実行されるように設定 --------------
# CMD ["./go-blog"]

# realizeを使ったホットリロード --------------------------------------
WORKDIR /src/go-blog
CMD [ "realize", "start", "--run", "--build" ]
# CMD [ "realize", "start", "--run", "--build", "--server" ]  # realizeサーバーを建てる場合

起動確認

コンテナを起動する。

コンテナ起動
$ docker-compose -f docker-compose.dev.yml up --build blog
Building blog
...
Recreating dev-env-blog ... done
Recreating dev-env-blog ... done
Attaching to dev-env-blog
dev-env-blog | [01:30:09][GO-BLOG] : Watching 4 file/s 8 folder/s
dev-env-blog | [01:30:09][GO-BLOG] : Command "go mod tidy"        ★ビルド前にgo mod tidyが走ってる
dev-env-blog | [01:30:09][GO-BLOG] : Build started                ★ビルド
dev-env-blog | [01:30:11][GO-BLOG] : Build completed in 1.971 s
dev-env-blog | [01:30:11][GO-BLOG] : Running..                    ★go-blogの実行
dev-env-blog | [01:30:11][GO-BLOG] : [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
...
dev-env-blog | [01:30:11][GO-BLOG] : [GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
dev-env-blog | [01:30:11][GO-BLOG] : [GIN-debug] Listening and serving HTTP on :8080

コンテナで起動されているプロセスを確認。
realizeのプロセスは17504で、go-blogのプロセスは17623で親プロセスは17504。realizeがgo-blogを立ち上げていることがわかる。

コンテナで動作しているプロセス
docker-compose -f docker-compose.dev.yml top
dev-env-blog
UID     PID    PPID    C   STIME   TTY     TIME                 CMD
-------------------------------------------------------------------------------
1000   17504   17483   0   16:32   ?     00:00:00   realize start --run --build
1000   17623   17504   0   16:32   ?     00:00:00   /dist/go-blog

ソースコードを変更すると、

dev-env-blog | [01:35:16][GO-BLOG] : GO changed /src/go-blog/app/routers/api_router.go   ★変更検知
dev-env-blog | [01:35:16][GO-BLOG] : Command "go mod tidy"        ★ビルド前にgo mod tidyが走ってる
dev-env-blog | [01:35:16][GO-BLOG] : Build started                ★ビルド
dev-env-blog | [01:35:17][GO-BLOG] : Build completed in 0.818 s
dev-env-blog | [01:35:17][GO-BLOG] : Running..                    ★go-blogの実行
...
dev-env-blog | [01:35:17][GO-BLOG] : [GIN-debug] Listening and serving HTTP on :8080

再度、コンテナで起動されているプロセスを確認。
realizeのプロセスは17504で変わりなく、go-blogの親プロセスは17504で変わりがないが、go-blogのプロセスが変更になっている。realizeがgo-blogを立ち上げ直していることがわかる。

docker-compose -f docker-compose.dev.yml top
dev-env-blog
UID     PID    PPID    C   STIME   TTY     TIME                 CMD
-------------------------------------------------------------------------------
1000   17504   17483   0   16:32   ?     00:00:01   realize start --run --build
1000   17744   17504   0   16:35   ?     00:00:00   /dist/go-blog

realizeサーバー(必要であれば)

コンテナをdeamonで起動するとgo-blogの動作が見えにくい。機能としてはログ確認しかできないが、簡易的にrealizeの状態をブラウザで確認することができる。

実際にはlogを出力するようにして確認できるようにするのが正当。

realize-server.png

realizeサーバーを立ち上げるようにDockerfileを変更

コンテナ起動時にrealizeのサーバーも起動するように Dockerfile.blog.dev を修正する。

# realizeを使ったホットリロード --------------------------------------
WORKDIR /src/go-blog
# CMD [ "realize", "start", "--run", "--build" ]
CMD [ "realize", "start", "--run", "--build", "--server" ]  # realizeサーバーを建てる場合

realizeサーバーは、.realize.yamlの設定どおりポート5002で待ち受けるので、ホストPCから接続できるように docker-compose.ymlにポートフォワード設定を追加する。

--- a/docker-compose.dev.yml
+++ b/docker-compose.dev.yml
@@ -19,12 +19,13 @@ services:
       - ./src/go-blog:/src/go-blog
     env_file: .env.dev
     environment:
       - GO111MODULE=on
     ports:
       - 8888:8080
+      - 5002:5002      # realizeサーバー用のPortFoward設定
     networks:
       dev-env-link:
         ipv4_address: $NETWORK_BASE.20

   golang:

コンテナを立ち上げると、下記のようにサーバーが起動したことがわかる。

Recreating dev-env-blog ... done
Attaching to dev-env-blog
dev-env-blog | [01:41:02][REALIZE] : Started on 0.0.0.0:5002     ★realizeサーバー起動
dev-env-blog | ⇨ http server started on [::]:5002
dev-env-blog | [01:41:02][GO-BLOG] : Watching 4 file/s 8 folder/s
dev-env-blog | [01:41:03][GO-BLOG] : Command "go mod tidy"
...
dev-env-blog | [01:41:04][GO-BLOG] : [GIN-debug] Listening and serving HTTP on :8080   ★go-blogも起動

後は、ホストPC上のブラウザで、http://localhost:5002にアクセスするとrealizeの状態を確認できる。

まとめ

ここまでで、go言語でWebアプリを構築し、プログラム変更をすぐに確認できるgo開発環境をDockerで作成できた。
現状の環境は下記の図の通り。

image.png

ここまでの一式

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
0
Help us understand the problem. What are the problem?