はじめに
今回は、Docker コンテナ上で Go の開発環境を構築し、Air を利用してホットリロードを実現していた際に発生したトラブルシューティングの内容をまとめました。
最終的に、Air の設定を修正することでエラー「/bin/sh: 1: main: not found
」が解消し、正常にサーバーが起動するようになりました。
環境構成
以下のようなツリー構造でプロジェクトを構成しています。
.
├── api
│ ├── cmd
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── main.go
│ │ └── .air.toml
│ ├── docker
│ │ └── Dockerfile # 本番用 Dockerfile
│ └── docker.dev
│ └── Dockerfile # 開発用 (Air 利用) Dockerfile
├── app
│ ├── src # フロントエンドのソースコードなど
│ └── docker
│ └── nginx
│ └── default.conf
└── docker-compose.yml
docker-compose.yml
では、api
サービスは ./api
をコンテキストとして、docker.dev/Dockerfile
を使ってビルドしています。また、ホストの ./api/cmd
をコンテナ内の /app
に volume マウントしており、Air を起動する構成になっています。
発生したエラー
開発用 Dockerfile(api/docker.dev/Dockerfile
)では以下のように Air を起動しています。
...
EXPOSE 8080
CMD ["air"]
しかし、コンテナのログを見ると以下のようなエラーが発生していました。
[06:41:11] running...
/bin/sh: 1: main: not found
...
[06:41:57] running...
[06:41:57] Process Exit with Code: 127
/bin/sh: 1: main: not found
また、コンテナ内で netstat
コマンドを使ってもポート 8080 で待ち受けしているプロセスは確認できませんでした。
エラー原因
Air は、.air.toml
の設定に基づいてアプリケーションをビルドし、生成されたバイナリを起動しようとします。
今回、.air.toml
の設定で bin
および full_bin
に "main"
と指定していたため、Air はカレントディレクトリ内から main
というコマンドを探していました。
しかし、Linux ではカレントディレクトリは PATH に含まれていないため、実行ファイルを起動するには ./main
と明示的に指定する必要があります。その結果、Air はビルドに成功しても、実行時に main
を見つけられずエラーが発生していました。
解決方法
1. .air.toml
の修正
.air.toml
の設定ファイルを下記のように修正しました。
[build]
cmd = "go build -o main ."
bin = "./main"
full_bin = "./main"
[log]
time = true
[color]
main = "yellow"
watcher = "cyan"
build = "green"
runner = "magenta"
これにより、Air は ./main
としてバイナリを実行するため、正しく起動できるようになりました。
2. 補足:PATH の設定変更(別案)
別の解決策として、Dockerfile 内でカレントディレクトリを PATH に追加する方法も考えられます。
例えば、以下のように環境変数を設定すれば、main
を直接実行できるようになります。
ENV PATH="/app:${PATH}"
ただし、今回は Air の設定を修正するほうがシンプルで分かりやすかったため、この方法は採用しませんでした。
結果
修正後、Air のログにはビルドと実行が正常に行われた旨のメッセージが表示され、コンテナ内で ss -tln
コマンドで確認したところ、0.0.0.0:8080
でサーバーが待ち受ける状態になりました。
これにより、ホストから localhost:8080
へアクセスすると正しくレスポンスが返却されるようになりました。
まとめ
-
エラーの原因
- Air の設定で実行するバイナリのパスが
"main"
となっており、PATH にカレントディレクトリが含まれていないため、実行できなかった。
- Air の設定で実行するバイナリのパスが
-
解決策
-
.air.toml
のbin
とfull_bin
を./main
に変更することで、ビルドしたバイナリを正しく実行できるようにした。
-
-
補足
- Docker コンテナ内ではサーバーが外部アクセス可能になるよう、Go のサーバーコードで
http.ListenAndServe("0.0.0.0:8080", handler)
とする必要がある点にも注意する。
- Docker コンテナ内ではサーバーが外部アクセス可能になるよう、Go のサーバーコードで
今回のトラブルシューティングを通して、Air の設定や Docker コンテナ内での実行環境について改めて理解を深めることができました。
皆さんの開発環境構築の参考になれば幸いです。