Skip to content

Add Docker image build and publish pipeline - #108

Closed
Lantum-Brendan wants to merge 8 commits into
devfrom
feat/docker-image-pr2
Closed

Add Docker image build and publish pipeline#108
Lantum-Brendan wants to merge 8 commits into
devfrom
feat/docker-image-pr2

Conversation

@Lantum-Brendan

Copy link
Copy Markdown
Collaborator

Adds a multi-stage Dockerfile, entrypoint script, CI workflow, and .dockerignore so the webui can be published as ghcr.io/trakli/webui — the image every downstream deployment template (compose stack, Helm, cloud providers) needs.

nfebe added 7 commits January 13, 2026 21:14
chore: Release v1.0.1
chore(release): Prepare 1.1.1
chore: Release 2.0.0-beta.1 Ailanthus
Copilot AI lite review requested due to automatic review settings August 11, 2026 12:14
@sourceant

sourceant Bot commented Aug 11, 2026

Copy link
Copy Markdown

Code Review Summary

This PR adds a comprehensive Docker pipeline including multi-stage builds and GitHub Actions integration. The implementation is solid but can be hardened for production security.

🚀 Key Improvements

  • Multi-stage Dockerfile for optimized production images.
  • Runtime configuration substitution via an entrypoint script.
  • Automated CI/CD workflow for GHCR publishing.

💡 Minor Suggestions

  • Include Dockerfile and .github in .dockerignore.

🚨 Critical Issues

  • The runtime container runs as the root user.

@sourceant sourceant Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review complete. See the overview comment for a summary.

Comment thread docker/entrypoint.sh
# This is how a single Docker image serves deployments with different API URLs
# without rebuilding — Nuxt 3 bakes runtimeConfig.public into .output/ at
# build time, so we patch the built files before starting the server.
if [ -n "$NUXT_PUBLIC_API_BASE_URL" ]; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The & character is a special backreference in sed replacement strings. If NUXT_PUBLIC_API_BASE_URL contains query parameters (e.g., ?key=val&other=1), the substitution will result in corrupted files because & will be replaced by the matched placeholder string. Additionally, using | as a delimiter will fail if the URL contains a pipe character. Escaping these characters ensures robust URL substitution.

Suggested change
if [ -n "$NUXT_PUBLIC_API_BASE_URL" ]; then
if [ -n "$NUXT_PUBLIC_API_BASE_URL" ]; then
# Escape special characters for sed: & (backreference) and | (delimiter)
SAFE_URL=$(printf '%s\n' "$NUXT_PUBLIC_API_BASE_URL" | sed 's/[&|]/\\&/g')
find /app/.output -type f \( -name '*.mjs' -o -name '*.js' -o -name '*.cjs' \) \
-exec sed -i "s|http://__NUXT_PUBLIC_API_BASE_URL__|${SAFE_URL}|g" {} +
fi


- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The current workflow duplicates build logic and lacks layer caching. Consolidating into a single build step using docker/metadata-action is more maintainable and ensures the exact same image is used for all tags. Adding type=gha cache will significantly speed up subsequent runs by persisting layers between builds.

Suggested change
with:
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/trakli/webui
tags: |
type=sha,prefix=,format=short,enable=${{ github.event_name == 'push' }}
type=raw,value=latest,enable=${{ github.event_name == 'release' }}
type=ref,event=tag,enable=${{ github.event_name == 'release' }}
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds containerization and CI publishing so the web UI can be built as a reusable Docker image and pushed to GitHub Container Registry for downstream deployment templates.

Changes:

  • Add a multi-stage Dockerfile to build Nuxt output and run it in a minimal runtime image.
  • Add a container entrypoint script to patch Nuxt baked runtimeConfig.public values at startup.
  • Add a GitHub Actions workflow to build and publish images to ghcr.io/trakli/webui, plus a .dockerignore.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
Dockerfile Multi-stage Node build/runtime image with entrypoint + healthcheck.
docker/entrypoint.sh Runtime placeholder replacement before starting Nuxt server.
.github/workflows/build-and-publish.yml CI job to build and push images on dev pushes and releases.
.dockerignore Reduce Docker build context size and avoid leaking local/env files.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread Dockerfile
Comment on lines +37 to +38
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
CMD wget -qO- http://localhost:3000/ || exit 1
Comment thread Dockerfile
# so a single image works across deployments with different API URLs.

# ── Stage 1: Build ──────────────────────────────────────────────────────────
FROM node:lts AS builder
Comment thread Dockerfile
RUN npm run build

# ── Stage 2: Runtime ────────────────────────────────────────────────────────
FROM node:lts-alpine
Comment thread docker/entrypoint.sh
Comment on lines +8 to +11
if [ -n "$NUXT_PUBLIC_API_BASE_URL" ]; then
find /app/.output -type f \( -name '*.mjs' -o -name '*.js' -o -name '*.cjs' \) \
-exec sed -i "s|http://__NUXT_PUBLIC_API_BASE_URL__|${NUXT_PUBLIC_API_BASE_URL}|g" {} +
fi
The webui has no published Docker image today. Every downstream
deployment template (compose stack, Helm, cloud providers) needs
ghcr.io/trakli/webui to exist.

Dockerfile (multi-stage):
- Stage 1 (node:lts): npm ci + npm run build with a placeholder API URL
  baked into the output. Nuxt 3 runtimeConfig.public values are embedded
  at build time, so we cannot set the real URL here.
- Stage 2 (node:lts-alpine): copies only .output/ from the build stage.
  Alpine-based for a small final image.

docker/entrypoint.sh:
- At container start, sed-replaces the build-time placeholder
  (http://__NUXT_PUBLIC_API_BASE_URL__) in all .output/ JS files with
  the actual NUXT_PUBLIC_API_BASE_URL env var, then starts the Node
  server. Standard Nuxt 3 pattern for a single image across deployments.

.github/workflows/build-and-publish.yml:
- Mirrors the webservice workflow: SHA tag on dev push, latest +
  release semver tag on GitHub Release publish. Pushes to ghcr.io.

.dockerignore:
- Excludes node_modules, .nuxt, .output, .git, .env*, tests.

Issue: trakli/webservice#308
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 11, 2026

Copy link
Copy Markdown

Deploying trakli-dev with  Cloudflare Pages  Cloudflare Pages

Latest commit: eff30fd
Status: ✅  Deploy successful!
Preview URL: https://a83abf8c.trakli-dev.pages.dev
Branch Preview URL: https://feat-docker-image-pr2.trakli-dev.pages.dev

View logs

@sourceant sourceant Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review complete. See the overview comment for a summary.

Comment thread .dockerignore
@@ -0,0 +1,10 @@
node_modules

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Excluding the Dockerfile and the .github directory from the build context is a best practice. It prevents meta-files from being included in layers and avoids unnecessary cache invalidation if only repository metadata changes.

Suggested change
node_modules
node_modules
Dockerfile
.github

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying webui with  Cloudflare Pages  Cloudflare Pages

Latest commit: eff30fd
Status: ✅  Deploy successful!
Preview URL: https://b74d7dc1.webui-9fh.pages.dev
Branch Preview URL: https://feat-docker-image-pr2.webui-9fh.pages.dev

View logs

@Lantum-Brendan
Lantum-Brendan requested a review from nfebe August 11, 2026 12:44
@nfebe

nfebe commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

#109 duplicates this?

@nfebe nfebe closed this Aug 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants