I am trying to create a docker image out of a mostly-go source base. The problem is that the go code also calls a C++ library (libsodium), so the generated container lacks libstdc++.
Here is my approach: first, I bundle the distroless go image with a few things created with pkg_tar()
:
container_image(
name = "new_base_image",
base = "@go_image_base//image",
tars = [
":bash_static_tar",
":passwd_tar",
":dirs_tar",
],
visibility = ["//:__subpackages__"],
)
Then I create my go image, package it, and push it to my registry:
go_image(
name = "alice-go-image",
embed = [":alice_lib"],
base = "//:new_base_image",
visibility = ["//visibility:public"],
)
container_image(
name = "alice-image",
base = ":alice-go-image",
user = "alice",
entrypoint = "/bin/sh",
directory = "/opt/alice",
workdir = "/opt/alice",
)
container_push(
name = "alice-push",
format = "Docker",
image = ":alice-image",
registry = "us-central1-docker.pkg.dev",
repository = "mycoolproject/pub-docker/alice",
)
Unforunately, the Go code calls some vendored C++ code (libsodium, not that it matters), so attempting to run the resulting binary from within the container yields:
sh-5.1$ ./apollo
./alice: error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file or directory
I thought I could simply include the distroless CC image in a bundle, but I cannot figure out how to do it. I would think that putting
container_load(
name = "distroless-cc",
registry = "gcr.io",
repository = "distroless/cc",
tag = "latest",
)
in the WORKSPACE
, then including the @distroless-cc//image
label as one of the entries in the tars
attribute of container_image
would do the trick. Unfortunately, what it does instead is include the layer.tar
files and associated metadata as part of the image! That is, if I change the first rule to:
container_image(
name = "new_base_image",
base = "@go_image_base//image",
tars = [
":bash_static_tar",
":passwd_tar",
":dirs_tar",
"@distroless-cc//image",
],
visibility = ["//:__subpackages__"],
)
the result is:
drwxr-xr-x 0/0 0 1969-12-31 19:00 ./
drwxr-xr-x 0/0 0 1969-12-31 19:00 ./bin/
-r-xr-xr-x 0/0 1248656 1969-12-31 19:00 ./bin/sh
drwxr-xr-x 0/0 0 1969-12-31 19:00 ./etc/
-rw-r--r-- 0/0 74 1969-12-31 19:00 ./etc/passwd
drwxr-xr-x 0/0 0 1969-12-31 19:00 ./opt/
drwxr-xr-x 0/0 0 1969-12-31 19:00 ./opt/config/
-rw-r--r-- 0/0 776 1969-12-31 19:00 ./46bdf18e6b66057ca3b88eb8e0e2b8443297e36629e5fba3f33c2b2c717aa083.json
-rw-r--r-- 0/0 3061760 1969-12-31 19:00 ./4441c0604495fd6824901b4a57c65ffbb9025023edc1bee6f1a8fe2c312347a3/layer.tar
-rw-r--r-- 0/0 245 1969-12-31 19:00 ./4441c0604495fd6824901b4a57c65ffbb9025023edc1bee6f1a8fe2c312347a3/json
-rw-r--r-- 0/0 3 1969-12-31 19:00 ./4441c0604495fd6824901b4a57c65ffbb9025023edc1bee6f1a8fe2c312347a3/VERSION
-rw-r--r-- 0/0 17786880 1969-12-31 19:00 ./51aee51224937d5c4fe6e805be3dac78ace093d894d99923afb39a6fbcb9711b/layer.tar
-rw-r--r-- 0/0 321 1969-12-31 19:00 ./51aee51224937d5c4fe6e805be3dac78ace093d894d99923afb39a6fbcb9711b/json
-rw-r--r-- 0/0 3 1969-12-31 19:00 ./51aee51224937d5c4fe6e805be3dac78ace093d894d99923afb39a6fbcb9711b/VERSION
-rw-r--r-- 0/0 1996800 1969-12-31 19:00 ./605a66edf924fdfdddccc79e556050288e91ecf53a2d71fa8c17d793c7d26451/layer.tar
-rw-r--r-- 0/0 485 1969-12-31 19:00 ./605a66edf924fdfdddccc79e556050288e91ecf53a2d71fa8c17d793c7d26451/json
-rw-r--r-- 0/0 3 1969-12-31 19:00 ./605a66edf924fdfdddccc79e556050288e91ecf53a2d71fa8c17d793c7d26451/VERSION
-rw-r--r-- 0/0 359 1969-12-31 19:00 ./manifest.json
-rw-r--r-- 0/0 92 1969-12-31 19:00 ./repositories
Which is clearly not what I want!
Of course I could manually create an image by untarring the go and the cc distroless images together and then pushing it to my private registry, but that would require doing stuff manually, and I can't figure out how to do it with the bazel docker rules.
Help?
You will need to assure that all of the dependancies for your code are installed in the image in order to be able to use the resulting image (without additional installation). This means that you need to install the libraries and binaries (in your case libstdc++
and other dependent libraries).
Unfortunately, bazel
rules do not run the Docker
container, rather, they are assembling static files (layers) in a resulting image, so you will not be able to install them during the packaging.
One approach would be to create a base image
with all tools and libraries you need and use this image as a starting point for the basel
. This can be done with the standard docker
build tools by creating a Dockerfile
that prepares the environment and pushing the resulting file to the repository (or as a tar
file) to be used as a base for basel
Another approach is to create the dependancies as a tar
layers and use them to assemble the image with container_layer("tars"=[])
and add the layer to the container_image("layers"=)
, however this is not recommended due to two major issues: 1) Creating the tar
is complex and prone to errors, and, 2) the tar
is static, so the subsequent builds will not include the patches and minor updates.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With