GoogleContainerTools / distroless

🥑 Language focused docker images, minus the operating system.
Apache License 2.0
18.78k stars 1.15k forks source link

How to install git on a distroless image? #1588

Closed borja-rivera closed 1 week ago

borja-rivera commented 4 months ago

Hello,

I need to install git on a java11 distroless image. Is there any way to do this?

I have seen that the package information is added in the corresponding yaml and json in the /private/repos/deb folder.

However, when I want to install the "git" package, I get compilation errors when I run bazel build.

Does anyone know an easier way to install git on a distroless image?

Thanks!

loosebazooka commented 4 months ago

It would be helpful to include more details. What you tried exactly and what the errors were

loosebazooka commented 4 months ago

But in the end a distroless image isn't necessarily the ideal image for development/build packages like git

Kirk1984 commented 4 months ago

Distroless is not made to build but to run. Your Dockerfile should contain a builder to build and then a runner like the distroless image.

borja-rivera commented 3 months ago

Hello,

I understand that wanting to install git inside a distroless image clashes with the distroless concept, however, I need it for app running requirement.

I read about the concept of multistage. That said, I took a debian base image as a builder to install git and then copy the git binary to the distroless and its dependencies. The binary is copied correctly to the distroless, but when running a git clone, it shows an error that it is missing a dependency.

I guess there's something I'm not doing right, but I don't know how to move forward. Has anyone done something similar?

The Dockerfile I have used is this one, I am just starting with the construction of images of this type and surely there are things to improve

FROM debian:bullseye-slim AS builder

RUN apt-get update && apt-get install -y --no-install-recommends git ca-certificates \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

RUN ldd $(which git) | tr -s '[:blank:]' '\n' | grep '^/' | sort -u > /git-deps.txt

RUN mkdir -p /git-deps

RUN xargs -I '{}' cp --parents '{}' /git-deps < /git-deps.txt

FROM gcr.io/distroless/java11-debian11:debug-amd64

COPY --from=builder /usr/bin/git /usr/bin/git
COPY --from=builder /usr/lib/git-core /usr/lib/git-core

COPY --from=builder /git-deps /

When the container is created, I try to use git cloning a public repo, but error appears:

/ # git clone https://github.com/michaelliao/learn-python3.git
Cloning into 'learn-python3'...
warning: templates not found in /usr/share/git-core/templates
/usr/lib/git-core/git-remote-https: error while loading shared libraries: libcurl-gnutls.so.4: cannot open shared object file: No such file or directory
ngeorger commented 3 months ago

You should perform the clone before the use of distroless image, distroless images are intended to not use anything else but the base runtime and not having other executables in $PATH environment. As the executables and their dependencies don't exist and/or aren't registered into distroless image, they become unusable, in the best scenario. Also it doesn't have a shell to execute commands.

It's not into the scope or the intended use of this project. Please, correct me if I'm wrong about this.

From README:

"Distroless" images contain only your application and its runtime dependencies. They do not contain package managers, shells or any other programs you would expect to find in a standard Linux distribution.

Details:

Entrypoints
Note that distroless images by default do not contain a shell. That means the Dockerfile ENTRYPOINT command, when defined, must be specified in vector form, to avoid the container runtime prefixing with a shell.

This works:

ENTRYPOINT ["myapp"]
But this does not work:

ENTRYPOINT "myapp"
For the same reasons, if the entrypoint is set to the empty vector, the CMD command should be specified in vector form (see examples below). Note that by default static, base and cc images have the empty vector entrypoint. Images with an included language runtime have a language specific default (see: [java](https://github.com/GoogleContainerTools/distroless/blob/main/java/README.md#usage), [nodejs](https://github.com/GoogleContainerTools/distroless/blob/main/nodejs/README.md#usage), [python3](https://github.com/GoogleContainerTools/distroless/blob/main/python3/README.md#usage)).

Hello,

I understand that wanting to install git inside a distroless image clashes with the distroless concept, however, I need it for app running requirement.

I read about the concept of multistage. That said, I took a debian base image as a builder to install git and then copy the git binary to the distroless and its dependencies. The binary is copied correctly to the distroless, but when running a git clone, it shows an error that it is missing a dependency.

I guess there's something I'm not doing right, but I don't know how to move forward. Has anyone done something similar?

The Dockerfile I have used is this one, I am just starting with the construction of images of this type and surely there are things to improve

FROM debian:bullseye-slim AS builder

RUN apt-get update && apt-get install -y --no-install-recommends git ca-certificates \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

RUN ldd $(which git) | tr -s '[:blank:]' '\n' | grep '^/' | sort -u > /git-deps.txt

RUN mkdir -p /git-deps

RUN xargs -I '{}' cp --parents '{}' /git-deps < /git-deps.txt

FROM gcr.io/distroless/java11-debian11:debug-amd64

COPY --from=builder /usr/bin/git /usr/bin/git
COPY --from=builder /usr/lib/git-core /usr/lib/git-core

COPY --from=builder /git-deps /

When the container is created, I try to use git cloning a public repo, but error appears:

/ # git clone https://github.com/michaelliao/learn-python3.git
Cloning into 'learn-python3'...
warning: templates not found in /usr/share/git-core/templates
/usr/lib/git-core/git-remote-https: error while loading shared libraries: libcurl-gnutls.so.4: cannot open shared object file: No such file or directory
borja-rivera commented 3 months ago

The problem is the app needs to clone the repo in runtime, not before the app starts

ngeorger commented 3 months ago

Maybe a distroless container is not your best option, try to use a trusted publisher, such as https://hub.docker.com/r/bitnami/git or something similar if you need to clone in runtime.

The problem is the app needs to clone the repo in runtime, not before the app starts

loosebazooka commented 3 months ago

The problem is the app needs to clone the repo in runtime, not before the app starts

Yeah as soon as you start doing things like this, you must either use a language native git library or something that doesn't use the system exec functions. Otherwise distroless is probably not the right container for you.