Example of an air-gapped (no internet) self-hosting go build.
-
Assume that bazel (or bazelisk) is available on the path as
bazel
.See
.bazelrc
for command line flags. Particularly--distdir
and--repository_cache
.Also
.bazelignore
. -
Optional: clean up so we can be reasonably sure we're reproducing a clean build scenario:
rm -rf bazel.repo.cache resolved/distdir derived/distdir bazel clean --expunge
-
Get bazel's distdir content:
bazel_release=$(<.bazelversion) bazel_url="https://github.com/bazelbuild/bazel/releases/download/${bazel_release}/bazel-${bazel_release}-dist.zip" bazel_dist=$(curl -sSfJLO --write-out '%{filename_effective}' "$bazel_url") unzip $bazel_dist "derived/distdir/*"
-
Sync everything from
WORKSPACE.bazel
(andMODULE.bazel
if BZLMOD is enabled) and bazel's secret internal externals:bazel sync du -sh bazel.repo.cache
OMG. It downloaded about 3.8GB of crap‽
-
Resolve then prejudicially filter out crap we are not interested in on linux-x86_64 with a local jdk:
bazel run resolve < resolved.bzl | egrep --invert-match '(remotejdk|android|windows|darwin|arm64|s390x)' | tee resolved.lst
-
Copy from bazel's repository cache (or download):
bazel build fetch # Yeah, it's just a bash script, but let's pretend it's more complicated. bazel-bin/fetch < resolved.lst # Copies about ~100MB out of bazel's repository cache. What's the other 3.7Gb for‽
-
While figuring stuff out, put things in
manual/distdir
if necessary. -
What about the
go.starlark.net
go_repository
? Where did that go? It's not present anywhere inbazel.repo.cache
.bazel run go env GOPATH GOMODCACHE GOCACHE
/home/nick/go /home/nick/go/pkg/mod /home/nick/.cache/go-build
Grr it's
$HOME/go
(actually$HOME/go/pkg/mod
), we do not want crap in our home directory, outside the source tree, to be part of our build.GOPATH
is likely fiddled with deep in the bowels ofgo_binary
etc. so let's ignore that.We probably don't care about
GOCACHE
in$XDG_CACHE_HOME/go-build
as that's the cache of build artifacts; it's right next to bazel's output anyway in$XDG_CACHE_HOME/bazel
. -
Jail! Rather, network namespace!
sudo ip netns add jail sudo ip netns exec jail ip link set lo up
Clean up what has already been downloaded, hopefully not cached anywhere else, stop the bazel daemon:
rm -rf $HOME/go $HOME/.cache/go-build bazel clean --expunge bazel shutdown
Run a build in the jail:
sudo ip netns exec jail sudo -u $USER $(which bazel) build resolve
Haaaa! DNS apparently worked but the actual TCP connections failed!
Error in fail: failed to fetch go.starlark.net: fetch_repo: go.starlark.net@v0.0.0-20230224151120-c52844e64a10: Get "https://proxy.golang.org/go.starlark.net/@v/v0.0.0-20230224151120-c52844e64a10.info": dial tcp: lookup proxy.golang.org on 127.0.0.53:53: read udp 127.0.0.1:56368->127.0.0.53:53: read: connection refused
-
OK, did
bazel sync
pull those down? Yes, it did. We can change where though; but this time we'll use fetch:
bazel fetch resolve --repo_env=GOMODCACHE=$PWD/go/pkg/mod
Note: we can't do this in .bazelrc
as go requires an absolute path, and we need $PWD
because %workspace%
is
not evaluated for --repo_env
. We also set --repo_env=GO_REPOSITORY_USE_HOST_CACHE=1
in .bazelrc
.
Kia kaha! We have ./go/pkg/mod/cache/download
with the downloaded artifacts!
We do have all the expanded go mods too; let's delete them to ensure that they will be unpacked from the cache.
Also, see ./go/pkg/mod/cache/.gitignore
.
- Try another jail build.
sudo ip netns exec jail sudo -u $USER $(which bazel) build resolve --repo_env=GOMODCACHE=$PWD/go/pkg/mod
Hooray!
It just so happens that the GOMODCACHE
directory complies with the GOPROXY
protocol, so we can use it
that way too, either as a file://
URL or served with a simple HTTP server.