-
Notifications
You must be signed in to change notification settings - Fork 69
Issue/publish container image #79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
docker/Dockerfile
Outdated
| fi && \ | ||
| LD_FLAGS=${LD_FLAGS} make OUTPUT=/target/app/gotify-cli _build_within_docker | ||
|
|
||
| FROM debian:${DEBIAN} |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
docker/Dockerfile
Outdated
|
|
||
| COPY --from=builder /target / | ||
|
|
||
| ENTRYPOINT ["./gotify-cli"] |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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":
- Remove usage of the
VOLUMEinstruction docker-library/postgres#1319 - Feature: Ignore image volumes when running containers moby/moby#43190
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.
There was a problem hiding this comment.
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.
docker/Dockerfile
Outdated
| fi && \ | ||
| LD_FLAGS=${LD_FLAGS} make OUTPUT=/target/app/gotify-cli _build_within_docker | ||
|
|
||
| FROM debian:${DEBIAN} |
There was a problem hiding this comment.
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.
docker/Dockerfile
Outdated
| COPY . /src/gotify | ||
|
|
||
| RUN cd /src/gotify && \ | ||
| LD_FLAGS=${LD_FLAGS} make OUTPUT=/target/app/gotify-cli _build_within_docker |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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.
.github/workflows/build.yml
Outdated
| - name: Build | ||
| run: | | ||
| TAG=$(git describe --tags --abbrev=0) | ||
| GIT_TAG=$TAG make clean build |
There was a problem hiding this comment.
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} \ |
There was a problem hiding this comment.
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: |
There was a problem hiding this comment.
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.
|
Thanks @jmattheis ! |
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)