Skip to content

Conversation

@edvgui
Copy link
Contributor

@edvgui edvgui commented Aug 21, 2025

Following up on https://github.com/edvgui/gotify-cli/pull/1, targeted towards main repo. (didn't figure out how to change the target branch of the existing PR)

@edvgui edvgui requested a review from a team as a code owner August 21, 2025 16:26
@eternal-flame-AD eternal-flame-AD self-requested a review August 21, 2025 21:12
fi && \
LD_FLAGS=${LD_FLAGS} make OUTPUT=/target/app/gotify-cli _build_within_docker

FROM debian:${DEBIAN}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We currently package CLI as alpine, do we actually need debian here?

This should probably docker.io prefixed as well for podman buildx. I know the current server code is not but I am thinking we should.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a very good point, I didn't realize I was changing that. It sounds to me like it should be possible to do it with alpine too, but I didn't manage to do it. I tried keeping the build process as it is, and replacing the last stage with this code:

FROM docker.io/library/alpine:latest

RUN apk add --no-cache ca-certificates

COPY --from=builder /target/app/gotify-cli /gotify-cli

ENTRYPOINT ["/gotify-cli"]

But when I run the image, I get this error:

$ podman run --rm docker.io/gotify/cli:test
{"msg":"exec container process (missing dynamic library?) `/gotify-cli`: No such file or directory","level":"error","time":"2025-08-24T14:52:58.882554Z"}

I verified the binary was indeed inside the container at the right place, and it is. So my best guess is that some dependency of the binary is missing in the alpine image, but that confuses me too as I thought go binaries were fully standalone. Are you able to assist here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Binary is currently complied with glibc dependency but alpine doesn't have this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that explains, I guess we stick to debian then?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. We should use alpine. If the binary is built on a golang:xxx-alpine image, then we can run it on a alpine: image.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. Alpine it is then

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I just realized that the binary was indeed not statically linked, for the simple reason that CGO_ENABLED=0 was not set for the build command in the container. Changing this does allow to build the package on debian (i.e. using the gotify/build image) and then package it in an alpine container.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we have both alpine images, then we don't have to statically compile to save some space.


COPY --from=builder /target /

ENTRYPOINT ["./gotify-cli"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually never used a CLI app on docker before so I actually am not sure, will a /root/.config/gotify VOLUME be useful here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that should not be necessary. The volume directive is mostly useful when the container generates data we want to make sure the user doesn't accidentally lose by stopping a container (i.e. postgres image does it for the data folder). But I don't think the cli binary generates anything, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gotify login writes a user config file with your host and token. I was wondering what is the general accepted way for storing these preference files when using a CLI through docker, is the user expected to manually write a volume mount or is there a declarative way to do it at the image level?

Copy link
Contributor Author

@edvgui edvgui Aug 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah right, I completely missed that part. I have been trying to figure out what is the consensus for this directive, by reading though these, and I am struggling to make up my mind on a "general rule":

Personally, for this case, I would find it pretty annoying if this container image had the VOLUME directive, as for the usage I will do of it, it will never, ever, produce any data (the login command is not what I use the cli for), forcing me to mount an empty dir in the container everytime I run it (or cleanup an anonymous volume manually after each usage). If someone wants to use this image for the login command, I expect they will know it produces a file, and they should know how to persist it. And if they don't know how (to use the-v option), they probably don't know either how to get back the content of the anonymous volume once the container is removed, so I don't think the VOLUME directive will help them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the in depth research. I'm okay with both as I am not a heavy docker user so you probably know more about what workflow works more smoothly.

I will not mark this a resolved to keep it unfolded in case someone has a different opinion but not blocking merge.

fi && \
LD_FLAGS=${LD_FLAGS} make OUTPUT=/target/app/gotify-cli _build_within_docker

FROM debian:${DEBIAN}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Binary is currently complied with glibc dependency but alpine doesn't have this.

@edvgui edvgui requested a review from jmattheis August 24, 2025 19:46
COPY . /src/gotify

RUN cd /src/gotify && \
LD_FLAGS=${LD_FLAGS} make OUTPUT=/target/app/gotify-cli _build_within_docker
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GOARCH/GOOS must be somehow set here. Currently, images build where BUILDPLATFORM != TARGETPLATFORM have a broken binary.

$ docker buildx build \
              --load \
              -t docker.io/gotify/cli:arm64 \
              --build-arg GO_VERSION=1.24.1 \
              --build-arg LD_FLAGS=" -X main.BuildDate=2025-08-31-15:55:45 -X main.Commit=a452bc3593d8118e83214b331f55fc869052b1c4" \
              --platform linux/arm64 \
              -f docker/Dockerfile .
[+] Building 0.8s (15/15) FINISHED                                                                                                                                  docker-container:mybuilder
 => [internal] load build definition from Dockerfile                                                                                                                                      0.0s
 => => transferring dockerfile: 1.11kB                                                                                                                                                    0.0s
 => [internal] load metadata for docker.io/library/debian:sid-slim                                                                                                                        0.2s
 => [internal] load metadata for docker.io/library/golang:1.24.1                                                                                                                          0.2s
 => [internal] load .dockerignore                                                                                                                                                         0.0s
 => => transferring context: 2B                                                                                                                                                           0.0s
 => [builder 1/4] FROM docker.io/library/golang:1.24.1@sha256:52ff1b35ff8de185bf9fd26c70077190cd0bed1e9f16a2d498ce907e5c421268                                                            0.1s
 => => resolve docker.io/library/golang:1.24.1@sha256:52ff1b35ff8de185bf9fd26c70077190cd0bed1e9f16a2d498ce907e5c421268                                                                    0.1s
 => [stage-1 1/4] FROM docker.io/library/debian:sid-slim@sha256:e0c4b2263e68e6a65ea4fff98f1143bb7f205576bdb609168089a88d0e4b381c                                                          0.1s
 => => resolve docker.io/library/debian:sid-slim@sha256:e0c4b2263e68e6a65ea4fff98f1143bb7f205576bdb609168089a88d0e4b381c                                                                  0.1s
 => [internal] load build context                                                                                                                                                         0.1s
 => => transferring context: 52.77kB                                                                                                                                                      0.0s
 => CACHED [stage-1 2/4] WORKDIR /app                                                                                                                                                     0.0s
 => CACHED [stage-1 3/4] RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && apt-get install -yq --no-install-recommends     tzdata     curl     ca-certificates &&     rm -r  0.0s
 => CACHED [builder 2/4] RUN apt-get update && apt-get install -yq --no-install-recommends     ca-certificates     git                                                                    0.0s
 => CACHED [builder 3/4] COPY . /src/gotify                                                                                                                                               0.0s
 => CACHED [builder 4/4] RUN cd /src/gotify &&     LD_FLAGS= -X main.BuildDate=2025-08-31-15:55:45 -X main.Commit=a452bc3593d8118e83214b331f55fc869052b1c4 make OUTPUT=/target/app/gotif  0.0s
 => CACHED [stage-1 4/4] COPY --from=builder /target /                                                                                                                                    0.0s
 => exporting to docker image format                                                                                                                                                      0.3s
 => => exporting layers                                                                                                                                                                   0.0s
 => => exporting manifest sha256:253f36788ab78d2cdd3902e73aa632a061e02e68b96dc116dd93cc8b97dae0e6                                                                                         0.0s
 => => exporting config sha256:53f7533af78db949b01bac7285c89876f150bfa5cb30cd0b2a56de5fc511db8b                                                                                           0.0s
 => => sending tarball                                                                                                                                                                    0.3s
 => importing to docker                                                                                                                                                                   0.0s
$ docker create --name arm64-test docker.io/gotify/cli:arm64
WARNING: The requested image's platform (linux/arm64) does not match the detected host platform (linux/amd64/v3) and no specific platform was requested
70bc1adec5ad8e90493eda343fcab2b0735c8a3431e772133af91da1ae6314aa
$ docker cp arm64-test:/app/gotify-cli gotify-cli
Successfully copied 16.6MB to /home/jm/src/gotify/cli/gotify-cli
$ file gotify-cli
gotify-cli: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=a413928be6c73357706a5fd33944ce6ffe132ed6, with debug_info, not stripped

It should look like this for arm64

$ http -d https://github.com/gotify/cli/releases/download/v2.3.2/gotify-cli-linux-arm64
Downloading to gotify-cli-linux-arm64
Done. 14.4 MB in 00:1.29763 (11.1 MB/s)
$ file gotify-cli-linux-arm64
gotify-cli-linux-arm64: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, Go BuildID=4ZifwkehXR1kjwXoGuHw/zbrcmgqZ9CkNFaAIqmW_/un4dYE_TKvJR2kxu0o6e/G-fGGXO_xtDF-X3OhuFt, with debug_info, not stripped

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, it was one of the things done by gotify/build, which I feel would be a bit silly to re-implement. Any objection to using the existing build image for this repo too? (You said above we don't need it because we don't have any cgo deps, but it is an issue to use it anyway?) It doesn't prevent us to still package it with alpine, as the binary will be here statically linked: #79 (comment)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

THe only thing needed are 3 environment variables. Which are set by default in the gotify/build images. I don't think it's worth to use the images for only this. I'll push the changes myself, already have a working version.

@edvgui edvgui requested a review from jmattheis August 31, 2025 18:11
- name: Build
run: |
TAG=$(git describe --tags --abbrev=0)
GIT_TAG=$TAG make clean build
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is broken, as VERSION has to be set. (I'll change this)

Makefile Outdated
--sbom=true \
--provenance=true \
$(if $(DOCKER_BUILD_PUSH),--push) \
-t ${REGISTRY}/${IMAGE}:${COMMIT} \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll change this to :master, this repo will already have releases for nearly all commits, so we don't have to have a separate tag for this.

overwrite: true
file_glob: true

image:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, this is run for each push but not on pull_requests. I'll change this to master & tag pushes only and add another step to check.yml which only builds one platform to have a faster build.

@jmattheis jmattheis merged commit cfd2536 into gotify:master Sep 1, 2025
3 checks passed
@jmattheis
Copy link
Member

@edvgui
Copy link
Contributor Author

edvgui commented Sep 1, 2025

Thanks @jmattheis !

@edvgui edvgui deleted the issue/publish-container-image branch September 1, 2025 20:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants