Go モジュール:ファイルプロキシと vendor で閉域網ビルド
目標
Goモジュールを、接続された側で新しいモジュールキャッシュに取得してファイルプロキシに移し、エアギャップ環境側で、GOPROXY=file://とvendorの2つの道でビルドします。go.sumを持ち込みマニフェストとして使う方法と、GOFLAGSの1行がvendorを無視させてしまう落とし穴を、直接確認します。
なぜ重要なのか
Goは、デフォルトでproxy.golang.orgから取得して、sum.golang.orgにハッシュを問い合わせます。エアギャップ環境では、どちらも届きません。モジュールキャッシュのcache/downloadは、それ自体がプロキシプロトコルの形をしているので、移すだけでプロキシになり、go.sumが完全なら、チェックサムデータベースに問い合わせる必要がありません。このPodは、インターネット(80/443)に届くので、ダウンロード側の役割を果たし、エアギャップ環境側の確認は、採点が、外部へ向かうHTTP(S)を閉じたプロキシに向けてふさいだ状態で行います。
ステップ
/root/goair/appにモジュールexample.com/airgap-helloを作成して、rsc.io/quotev1.5.2のquote.Hello()を出力するmain.goを書いてください。新しいモジュールキャッシュとしてGOMODCACHE=/root/goair/outside-cacheを指定して取得し、go mod tidyまで行ってください。/root/goair/outside-cache/cache/downloadの内容を、/srv/goproxyに移してください。- エアギャップ環境側の設定
/root/goair/inside.envに、GOPROXY=file:///srv/goproxyとGOFLAGS=-mod=readonlyを書いてください。 - その設定を読み込んで、外部をふさいだ状態で、新しいモジュールキャッシュ
/root/goair/inside-cacheでビルドして、/root/goair/bin/hello-proxyを作成してください。 /root/goair/appで、vendorディレクトリを作成してください。- イメージの
GOFLAGS=-mod=modをそのままにして、GOPROXY=offと空のモジュールキャッシュでビルドしてみてください。失敗メッセージを/root/goair/gomod-trap.txtに保存します。 GOPROXY=offで、vendorだけでビルドして、/root/goair/bin/hello-vendorを作成してください。- go.sumから、モジュールzipのハッシュの行(
/go.modが付かない行)を、모듈 버전 해시の形式に移した(プレースホルダーはモジュール、バージョン、ハッシュです)持ち込み記録/root/goair/intake.txtを書いてください。各ハッシュは、/srv/goproxyの.ziphashと同じである必要があります。
参考
- 今の値:
go env GOPROXY GOFLAGS GOMODCACHE GOSUMDB - 環境ファイルの読み込み:
set -a; . /root/goair/inside.env; set +a - 外部をふさぐ:
HTTPS_PROXY=http://127.0.0.1:9 HTTP_PROXY=http://127.0.0.1:9 go build ...(Goは、これらの変数に従います) - よくある間違い1: いつものモジュールキャッシュでビルドして成功したと思い、終わりにしてしまうこと。すでに取得しておいたキャッシュが助けたもので、プロキシを試したことにはなりません。
- よくある間違い2: vendorを作成したのに、GOFLAGSを確認しないこと。このイメージでは、vendorが無視されます。
ダウンロード側: 新しいモジュールキャッシュで依存関係を取得する
/root/goair/appにモジュールexample.com/airgap-helloとmain.goを作成して、GOMODCACHE=/root/goair/outside-cacheでrsc.io/quote v1.5.2を取得し、go mod tidyまで行ってください。
go mod initでモジュールを作成し、go getでバージョンを正確に取得します。新しいキャッシュディレクトリをGOMODCACHEとして指定すれば、今回取得したものだけが、その中に積まれます。tidyは、使われている依存関係を、直接の依存として整理します。
モジュールキャッシュをファイルプロキシに移す
/root/goair/outside-cache/cache/downloadの内容を、/srv/goproxyに移してください。
モジュールキャッシュのcache/downloadの下は、すでにプロキシプロトコルの形(@v/list、.info、.mod、.zip)です。ディレクトリ構造をそのまま維持してコピーしてください。展開済みのソースがあるキャッシュの、ほかのディレクトリは必要ありません。
エアギャップ環境側のGo環境ファイル
/root/goair/inside.envに、GOPROXY=file:///srv/goproxyとGOFLAGS=-mod=readonlyを書いてください。
シェルがそのまま読める、名前=値の行です。fileスキームの後ろには、絶対パスが来るので、スラッシュが3つになります。-mod=readonlyは、ビルドがgo.modを勝手に直せないようにします。
外部をふさいで、ファイルプロキシでビルドする
inside.envを読み込んで、外部をふさいだ状態で、新しいモジュールキャッシュ/root/goair/inside-cacheでビルドして、/root/goair/bin/hello-proxyを作成してください。
環境ファイルをexportされる形で読み込んだあと、GOMODCACHEを新しいディレクトリとして指定し、外部のアドレスは、閉じたプロキシに向けてください。すでに取得してあるキャッシュでビルドすると、プロキシを試したことになりません。
2つ目の道: vendor
/root/goair/appで、vendorディレクトリを作成してください。
go modのサブコマンドの中に、依存関係のソースをリポジトリの中にコピーするものがあります。結果として、vendor/modules.txtができるかを見てください。
vendorがあるのに失敗するビルド
イメージのGOFLAGS=-mod=modをそのままにして、GOPROXY=offと空のモジュールキャッシュでビルドしてみて、失敗メッセージを/root/goair/gomod-trap.txtに保存してください。
このステップは、失敗を記録するステップです。go env GOFLAGSで、今の値を先に見てください。-mod=modがvendorをどう扱うかを、読み物の内容から思い出せば、メッセージが理解できます。
GOPROXY=offで、vendorでビルドする
GOPROXY=offで、vendorだけでビルドして、/root/goair/bin/hello-vendorを作成してください。
vendorを使わせる-modの値があります。環境のGOFLAGSを上書きするか、コマンドラインで直接指定してください。モジュールキャッシュが空でも、できる必要があります。
go.sumで持ち込み記録を書く
go.sumのモジュールzipのハッシュの行を、모듈 버전 해시の形式に移した(プレースホルダーはモジュール、バージョン、ハッシュです)/root/goair/intake.txtを書いてください。各ハッシュは、/srv/goproxyの.ziphashと同じである必要があります。
go.sumの行は、モジュール、バージョン、h1:ハッシュの3つの列です。バージョンの後ろに/go.modが付いた行は、go.modファイルのハッシュなので、zipとは違います。プロキシディレクトリの.ziphashファイルと、1行ずつ照合してみてください。