Port ntfy to locally built container image (#202)
All checks were successful
Build Container / build (push) Successful in 6m28s

## Summary
- Add `containers/ntfy/Dockerfile` — three-stage build (Node web UI, Go+CGO server, Alpine runtime) pinned to commit SHA `a03a37fe` (v2.17.0), sourced from forge mirror
- Update ntfy deployment image from `binwiederhier/ntfy:v2.17.0` to `registry.ops.eblu.me/blumeops/ntfy:v1.0.0`
- Note fish shell in CLAUDE.md

## Deployment
After merge, release the container image:
```fish
mise run container-tag-and-release ntfy v1.0.0
```
Then sync:
```fish
argocd app sync ntfy
```

## Test plan
- [x] `docker build` succeeds
- [x] `dagger call build --src=. --container-name=ntfy` succeeds (exit 0, container ID printed)
- [x] `ntfy --help` works in built container
- [ ] Tag and release `ntfy-v1.0.0` after merge
- [ ] Verify ntfy pod starts with new image
- [ ] Verify health endpoint responds at `ntfy.ops.eblu.me/v1/health`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/202
This commit is contained in:
Erich Blume 2026-02-17 10:18:20 -08:00
commit 5fbe70d1ba
4 changed files with 66 additions and 1 deletions

View file

@ -8,6 +8,8 @@ blumeops is Erich Blume's GitOps repository for personal infrastructure, orchest
**CRITICAL: Public repo at github.com/eblume/blumeops - never commit secrets!** **CRITICAL: Public repo at github.com/eblume/blumeops - never commit secrets!**
**Shell:** The user's shell is **fish**. Use `$status` not `$?` for exit codes. Use fish syntax in interactive examples.
## Rules ## Rules
1. **Always run `mise run zk-docs -- --style=header --color=never --decorations=always` at session start** 1. **Always run `mise run zk-docs -- --style=header --color=never --decorations=always` at session start**

View file

@ -16,7 +16,7 @@ spec:
spec: spec:
containers: containers:
- name: ntfy - name: ntfy
image: binwiederhier/ntfy:v2.17.0 image: registry.ops.eblu.me/blumeops/ntfy:v1.0.0
args: ["serve", "--config", "/etc/ntfy/server.yml"] args: ["serve", "--config", "/etc/ntfy/server.yml"]
ports: ports:
- containerPort: 80 - containerPort: 80

View file

@ -0,0 +1,62 @@
# ntfy push notification server
# Three-stage build: Web UI (Node), server (Go+SQLite), runtime (Alpine)
ARG NTFY_VERSION=v2.17.0
ARG NTFY_COMMIT=a03a37feb1869e84e3af0dd6190bdc7183f211ec
FROM node:22-alpine AS web-build
ARG NTFY_COMMIT
RUN apk add --no-cache git
RUN mkdir /app && cd /app \
&& git init \
&& git remote add origin https://forge.ops.eblu.me/eblume/ntfy.git \
&& git fetch --depth 1 origin ${NTFY_COMMIT} \
&& git checkout FETCH_HEAD
WORKDIR /app/web
RUN npm ci
RUN npm run build
FROM golang:alpine3.22 AS build
ARG NTFY_VERSION
ARG NTFY_COMMIT
RUN apk add --no-cache build-base git
RUN mkdir /app && cd /app \
&& git init \
&& git remote add origin https://forge.ops.eblu.me/eblume/ntfy.git \
&& git fetch --depth 1 origin ${NTFY_COMMIT} \
&& git checkout FETCH_HEAD
WORKDIR /app
# Copy pre-built web UI assets
COPY --from=web-build /app/web/build /app/server/site
# Create docs placeholder with dummy file (go:embed requires non-empty dir)
RUN mkdir -p server/docs && touch server/docs/placeholder
ENV CGO_ENABLED=1
RUN go build \
-o /ntfy \
-tags sqlite_omit_load_extension,osusergo,netgo \
-ldflags "-linkmode=external -extldflags=-static -s -w -X main.version=${NTFY_VERSION}"
FROM alpine:3.22
LABEL org.opencontainers.image.title=ntfy
LABEL org.opencontainers.image.description="ntfy is a simple HTTP-based pub-sub notification service"
LABEL org.opencontainers.image.source=https://github.com/binwiederhier/ntfy
RUN apk --no-cache add tzdata
COPY --from=build /ntfy /usr/bin/ntfy
EXPOSE 80
USER 65534
ENTRYPOINT ["/usr/bin/ntfy"]

View file

@ -0,0 +1 @@
Port ntfy to a locally built container image from forge mirror source.