Deterministic builds with go + bazel + grpc + docker
Deterministic container images for gRPC+golang bazel.
The following sample will build a golang gRPC client/server and then embed the binaries into container images.
These images are will have a consistent image hash no matter where it is built.
For reference, see:
To run this sample, you will need bazel
installed
Build Image
Note, the bazel base image specifies the image+hash so your’e starting off from a known state:
WORKSPACE
Check Image
Inspect the image thats generated…these wil be the same no matter where you generate the images
(optional) gRPC Client/Server
(why not?…you built it already, give it a shot)
docker run -p 50051:50051 bazel/greeter_server:greeter_server_image
docker run --net=host bazel/greeter_client:greeter_client_image
Specify docker image
You can specify a repo prefix by setting the repository
command here. In the case below, its on dockerhub as handle salrashid123
container_image(
name = "greeter_server_image",
base = "@alpine_linux_amd64//image",
entrypoint = ["/server"],
files = [":server"],
repository = "salrashid123"
)
on push to dockerhub
Client
$ docker push salrashid123/greeter_server:greeter_server_image
a1852e9ff2e7: Pushed
greeter_server_image: digest: sha256:e3e95e8f07b552ee2f60aaf6308b75ee660e24ff58d3a2b25be26f53476cde87 size: 738
On any other machine pull the image and inspect
$ docker inspect salrashid123/greeter_server@sha256:e3e95e8f07b552ee2f60aaf6308b75ee660e24ff58d3a2b25be26f53476cde87
[
{
"Id": "sha256:7ea0fc3e14c0d0cfdd8048f5ddd19566a1b78f822658b8c5318c14241340a982",
"RepoTags": [
"bazel/greeter_server:greeter_server_image",
"salrashid123/greeter_server:greeter_server_image"
],
"RepoDigests": [
"salrashid123/greeter_server@sha256:e3e95e8f07b552ee2f60aaf6308b75ee660e24ff58d3a2b25be26f53476cde87"
],
...
Cloud Build
You can use Cloud Build to create the image by using the bazel
builder and specifying the repository path to export to. In the sample below, the repository is set o google container registry:
container_image(
name = "greeter_server_image",
base = "@alpine_linux_amd64//image",
entrypoint = ["/server"],
files = [":server"],
repository = "gcr.io/mineral-minutia-820"
)
Then on the same system that it was built and pushed:
Thats about it…you’ve now got deterministic builds…now well…time to learn bazel!
TODOs:
- use
gazelle
for dependenciesbazel run //:gazelle -- update-repos -from_file=examples/greeter_server/go.mod