SimonKagstrom / kcov

Code coverage tool for compiled programs, Python and Bash which uses debugging information to collect and report data without special compilation options
http://simonkagstrom.github.io/kcov/
GNU General Public License v2.0
709 stars 109 forks source link

docker: Build for debian by default #450

Closed SimonKagstrom closed 1 month ago

SimonKagstrom commented 1 month ago

Good to test in musl.

kinow commented 1 month ago

Hi @SimonKagstrom ! Hijacking this issue, as it's somewhat related to an issue on our CICD pipeline.

We used kcov/kcov in a Docker multi-stage container, based on Debian, and noticed it started failing recently. I looked at the commits, and saw this one that changed the image to alpine: https://github.com/SimonKagstrom/kcov/commit/275e9229a5ffd37fb478481fa69199d1af73c676

And also saw the dockerhub image was uploaded a few days ago. It'd be great if there were alpine + debian images in DockerHub, but that would be a burden on maintenance. I will build kcov in our container using debian instead, but just in case you hear from anyone else with issues like this one :+1:

Cheers

SimonKagstrom commented 1 month ago

What was the failure?

@williamdes might also be interested, although I take the responsibility since I pushed for alpine-based docker builds :-)

williamdes commented 1 month ago

Can you share your workflow?

I think there is maybe something wrong as my CI does not pass as I said here https://github.com/SimonKagstrom/kcov/issues/437#issuecomment-2219955827

kinow commented 1 month ago

My pipelines are executed on a private GitLab repository, but they simply run kcov in a container that contained:

# -----------------------------------------------------------------------------
# kcov is a coverage tool for binaries that works with Bash shell
# ...
FROM kcov:latest AS kcov

# nothing here, image includes kcov

# -----------------------------------------------------------------------------
# bats is an old (one of the oldest?) Shell unit test libraries. It
# ...
FROM debian:bullseye-slim AS bats

# build bats

# -----------------------------------------------------------------------------
# Final base image.
FROM python:3.8.19-slim-bookworm

# Copy bats.

COPY --from=bats /usr/local/bin/bats* /usr/local/bin/
COPY --from=bats /usr/local/lib/bats-core/ /usr/local/lib/bats-core/
COPY --from=bats /usr/local/libexec/bats-core/ /usr/local/libexec/bats-core/
COPY --from=bats /usr/lib/bats/bats-assert/ /usr/lib/bats/bats-assert/
COPY --from=bats /usr/lib/bats/bats-support/ /usr/lib/bats/bats-support/

# Copy kcov.

COPY --from=kcov /usr/local/bin/kcov* /usr/local/bin/
COPY --from=kcov /usr/local/share/doc/kcov /usr/local/share/doc/kcov

WORKDIR "/code"

# ENTRYPOINT ["/bin/sh", "-c"]
CMD ["/usr/local/bin/bats"]

With the change to alpine, running ldd I could confirm that it was missing the musl libc when running the copied kcov. Which makes sense, since it's dangerous to copy binaries between musl & glibc binaries (even though I could try to make it work... probably could lead to more/other issues, I guess).

My first intention was to pin the kcov to a previous tag. But I did not see any recent tags on DockerHub.

Then I searched for an -slim or ubuntu etc. image, and noticed there was only an Alpine image (which is already very useful to have :)).

My fix was to update the first stage in the container to build kcov with debian, and then copy just the binary for the final image:

FROM debian:bullseye-slim AS kcov

ARG KCOV_COMMIT="9133fec158a11fd6b101f34da9152d695c7f47f7"

# Install build-time dependencies.

RUN apt-get update && \
    apt-get install --yes --no-install-suggests --no-install-recommends \
      binutils-dev \
      build-essential \
      ca-certificates \
      cmake \
      git \
      libssl-dev \
      libcurl4-openssl-dev \
      python3 \
      zlib1g-dev libdw-dev libiberty-dev && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

WORKDIR "/usr/src"

# Get kcov code, for a working commit (they are not tagging...).

RUN git clone \
      --depth 1 \
      https://github.com/SimonKagstrom/kcov.git && \
    cd kcov && \
    git checkout "${KCOV_COMMIT}"

# Build kcov.

RUN cd kcov && \
    mkdir build && \
    cd build && \
    cmake .. && \
    make && \
    make install

# other stages...
# ...

# Final base image.
FROM python:3.8.19-slim-bookworm

# Install run-time dependencies.

RUN apt-get update && \
    apt-get install --yes --no-install-suggests --no-install-recommends \
      binutils \
      ca-certificates \
      git \
      jq \
      libcurl4 \
      libdw1 \
      zlib1g && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# Copy bats.

COPY --from=bats /usr/local/bin/bats* /usr/local/bin/
COPY --from=bats /usr/local/lib/bats-core/ /usr/local/lib/bats-core/
COPY --from=bats /usr/local/libexec/bats-core/ /usr/local/libexec/bats-core/
COPY --from=bats /usr/lib/bats/bats-assert/ /usr/lib/bats/bats-assert/
COPY --from=bats /usr/lib/bats/bats-support/ /usr/lib/bats/bats-support/

# Copy kcov.

COPY --from=kcov /usr/local/bin/kcov* /usr/local/bin/
COPY --from=kcov /usr/local/share/doc/kcov /usr/local/share/doc/kcov

WORKDIR "/code"

# ENTRYPOINT ["/bin/sh", "-c"]
CMD ["/usr/local/bin/bats"]
kinow commented 1 month ago

BTW, I think the image is useful for others testing it, and maybe for CI tests in this repo. And I wouldn't want to add any extra burden on the maintainer :slightly_smiling_face: The INSTALL instructions were very helpful, and it only took a bit longer.

The tag in DockerHub would be helpful to allow me to procrastinate a bit, and fix it later, but not a big issue :+1:

Thanks a lot again for kcov! (p.s. I also updated our CI to drop jq, and now we are only using the new --dump-summary option :heart: )

williamdes commented 1 month ago

I have to read all this soon But before switching to alpine I upgraded to bookworm and left the Debian instructions in the Dockerfile to users to build for Debian: https://github.com/SimonKagstrom/kcov/blob/master/Dockerfile Maybe we can provide a Debian alternative

SimonKagstrom commented 1 month ago

Well, I see that this can be a problem, and I'm maybe inclined to go with a debian-based image as default. However, is this really how the docker images should be used? In this case, it fails since the image is copied from an alpine-based build, but I guess it could also fail if e.g., the debian version would mismatch after the copy?

Anyway, I'd say we revert back to debian for the docker images, and that's probably good enough for now. Maybe in the future, it could make sense to build for alpine as well.

kinow commented 1 month ago

There are some initiatives to have support to both ^1, but I never tried that. For popular images it's common to have a glibc and musl version.

But for smaller projects I believe it's totally fine to a) provide instructions only, b) provide a Dockerfile only, c) provide a single image on DockerHub without promises that it can be used in production. Any of these are fine for me (and the option a), is pretty much what you have in INSTALL, that's enough for anyone to build a container).

I know maintaining Open Source projects is hard, and there is already a toll on doing that and having to make something that's a bit generic and works for everybody.

But IMHO, your personal life & happiness maintaining the project comes first.

Anyway, I'd say we revert back to debian for the docker images, and that's probably good enough for now. Maybe in the future, it could make sense to build for alpine as well.

Up to you, but it really does not bother me at all to have to build it on my CICD. Maybe later I will be able to use it if Debian stable adds kcov (I couldn't install it with bookworm), or if I switch to a Ubuntu based image. There are probably other workarounds... but being able to have coverage for my shell scripts with kcov is already a great thing :slightly_smiling_face:

Thanks!

p.s.: Not sure how you are building and uploading the images, but most (if not everything?) of that nowadays can be automated with GitHub Actions, which helps to ease a bit the burden of testing, maintaining the images, uploading to DockerHub, tagging, etc.

SimonKagstrom commented 1 month ago

Anyway, I'd say we revert back to debian for the docker images, and that's probably good enough for now. Maybe in the future, it could make sense to build for alpine as well.

Up to you, but it really does not bother me at all to have to build it on my CICD. Maybe later I will be able to use it if Debian stable adds kcov (I couldn't install it with bookworm), or if I switch to a Ubuntu based image. There are probably other workarounds... but being able to have coverage for my shell scripts with kcov is already a great thing 🙂

@williamdes already did the transition to bookworm, so I'll revert to that and hopefully it should be easier to use in this usecase.

In #444 , there's also some work to make it easier for debian packaging, but even with an updated version, the distribution version will always lag behind.

p.s.: Not sure how you are building and uploading the images, but most (if not everything?) of that nowadays can be automated with GitHub Actions, which helps to ease a bit the burden of testing, maintaining the images, uploading to DockerHub, tagging, etc.

Yeah, @williamdes did a lot of improvements there, so it's automated, so not much burden to maintain (except waiting for the builds).

I rephrased this issue to be more aligned with the discussion :-) Will create a new one for the original issue.

kinow commented 1 month ago

As I'm using this at $work, I can also help here with testing/doc/code/etc. if needed :slightly_smiling_face: Thank you @SimonKagstrom !

williamdes commented 1 month ago

@williamdes already did the transition to bookworm, so I'll revert to that and hopefully it should be easier to use in this usecase

Ha, but I really liked the alpine version and need it for my GitHub actions to be quick

Could we have both versions on docker hub? latest-alpine latest > is bookworm

and vxx-alpine and vxx is bookworm @SimonKagstrom I can do a PR for that

SimonKagstrom commented 1 month ago

@williamdes yes, sounds like a splendid idea!

While I don't use kcov from docker builds personally, I tend to base my other docker builds on alpine since it's generally faster and smaller, so having both sounds good.

I only just started on the change (so far failing the build), but feel free to take over! I'm also on MacOS and haven't bothered with a docker setup locally, so it's kind of a churn to test the changes for me.

williamdes commented 1 month ago

Okay, working on it!

williamdes commented 1 month ago

Done #452 Some more minor things about Docker labels and it will be okay

williamdes commented 1 month ago

@kinow there is now official documentation on how to copy kcov into your Dockerfile See: https://github.com/SimonKagstrom/kcov/blob/master/doc/docker.md#copy-into-your-image

kinow commented 1 month ago

@kinow there is now official documentation on how to copy kcov into your Dockerfile See: https://github.com/SimonKagstrom/kcov/blob/master/doc/docker.md#copy-into-your-image

Documentation tested, and it worked like a charm. I've reverted my previous changes, and our Docker image is now a lot simpler. Thanks @SimonKagstrom , @williamdes ! :bow: