コンテナ上でgo buildをすると error obtaining VCS status: exit status 128 が出る問題
概要
Dockerコンテナ上でgo build
をおこなったところ、以下のようなエラーが出た。
error obtaining VCS status: exit status 128
Use -buildvcs=false to disable VCS stamping.
failed to build, error: exit status 128
このエラーを解消する方法を探す。
原因究明
そもそもVCSとは
VCSはVersion Control Systemの略で、バージョン管理システムのことを指す。最も有名なVCSにGitがある。
Goではバグの原因を特定しやすくするためなどの目的で、ビルド時にVCSからコミットIDやコミット時刻などの情報を取得してバイナリに埋め込むという機能があるらしい。この機能のことをVCSスタンピングと呼ぶ。詳しくは以下。
以上のことを踏まえてエラー文を再読すると、Goがビルド時にVCSスタンピングをしようとしたが、VCS情報を取得することができず、エラーが発生したと考えられる。
git status
を実行してみる
本当にVCS情報を取得できていないのかどうかを確かめるために、ためしにDockerコンテナ内でgit status
を実行してみた。すると以下のようなエラーが出た。
fatal: detected dubious ownership in repository at '/app'
To add an exception for this directory, call:
git config --global --add safe.directory /app
dubious ownership とは
リポジトリの所有者がGitコマンドを実行しているユーザーと異なる場合に出るエラーらしい。
詳しくは以下。
正直あまり深く理解できていないが、ざっくり言えば、Gitに存在する脆弱性を防ぐために所有者のチェックを厳しくしたということらしい。
実際にコンテナ内でwhoami
コマンドを実行するとroot
だったが、ls -l
を実行すると、
-rw-rw-r-- 1 1001 1001 140 Jul 23 20:12 Dockerfile
drwxrwxr-x 4 1001 1001 4096 Jul 23 20:12 cmd
-rw-rw-r-- 1 1001 1001 402 Jul 23 20:12 docker-compose.yml
-rw-rw-r-- 1 1001 1001 645 Jul 23 20:12 go.mod
-rw-rw-r-- 1 1001 1001 3135 Jul 23 20:12 go.sum
drwxrwxr-x 2 1001 1001 4096 Jul 23 20:12 handler
-rw-rw-r-- 1 1001 1001 469 Jul 23 20:12 main.go
drwxr-xr-x 2 root root 4096 Jul 23 20:12 tmp
と返ってきた。コンテナ内で自動作成された/tmp
以外は所有者がコンテナ側のユーザーであるroot
ではなく、ホスト側のユーザーのuidを指す1001
になっていることが分かる。
ちなみに、ボリュームのマウント時にマウントされたファイルの所有者がホスト側のユーザーになるこの現象は、Docker for Macでは起こらないようだ。自分はMacユーザーなので開発中はタイトルの問題には遭遇せず、Linuxサーバーにデプロイして初めてこの問題に気付いた。
念の為、MacのDockerコンテナ上でwhoami
をおこなうとroot
が返り、ls -l
を実行すると以下のようになることを確認した。
-rw-r--r-- 1 root root 140 Jul 23 18:06 Dockerfile
drwxr-xr-x 5 root root 160 Jul 23 18:06 cmd
-rw-r--r-- 1 root root 402 Jul 23 18:06 docker-compose.yml
-rw-r--r-- 1 root root 645 Jul 23 18:06 go.mod
-rw-r--r-- 1 root root 3135 Jul 23 18:06 go.sum
drwxr-xr-x 5 root root 160 Jul 23 18:06 handler
-rw-r--r-- 1 root root 469 Jul 23 18:06 main.go
drwxr-xr-x 3 root root 96 Jul 23 18:07 tmp
Docker for Mac上ではボリュームのマウントをおこなっても、所有者をコンテナ側のユーザーに良い感じに書き換えてくれるようだ。
解決方法
やや複雑だったがまとめるとエラーの流れは以下のようになる。
- Dockerのボリュームをマウントするとコンテナ内のファイルの所有者がホスト側のユーザーになる
- Goのビルド時にGitの情報を取得しようとする
- Gitコマンドの実行者はコンテナ側のユーザーなのにファイルの所有者はホスト側のユーザーなので、脆弱性対策のためにGitがエラーを発生させる
- Gitがエラーを返すのでGoのビルドも失敗する
つまり根本的な原因はボリュームマウント時の所有者の問題にあるので、そこを解決してやれば良い。具体的な方法については以下の記事に託す。
余談だが、この記事を書いている途中で「そもそも本番環境でボリュームのマウントをする必要はないのでは?」と思い、本番環境でのボリュームのマウント自体をやめた。ボリュームのマウントはホスト側での変更をコンテナ側に即反映させるための機能のはずなので、変更を即反映させる必要性の薄い本番環境では不必要な場面が多いだろう。
怪我の功名ではあるが、自分が今まで思考停止で適当にマウントの機能を使ってきたということを思い知ることができてよかった。
今回の自分のように、開発環境はMacで本番環境はLinuxの人は、上記のQiitaの記事の内容を実行せずとも、本番でのボリュームのマウントを止めるだけでエラーは発生しなくなるだろう。根本的な解決にはなっていないが…。
参考
追記(2024-11-19)
Dockerのuserns-remapという機能を使えば、ホストとコンテナ間でユーザーをマッピングすることができるというコメントを頂いた。詳しくは以下の記事を参照。
Discussion
dockerのuserns-remapを利用して、コンテナ内のrootをホストのユーザにマッピングしてあげるとこの手の権限問題は解消できると思います。
ホストでuid=1001のファイルがコンテナ内からはuid=0(root)に見える形です。
なるほど、存じ上げませんでした。追記しておきます。
情報ありがとうございます!