Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
[![Hadolint](https://img.shields.io/badge/Hadolint-clean-success)](https://github.com/hadolint/hadolint)
[![Prettier](https://img.shields.io/badge/Code_Style-Prettier-F7B93E?logo=prettier&logoColor=black)](https://prettier.io/)

Reference [Dockerfiles](https://docs.docker.com/engine/reference/builder/) and best-practice guides for building **secure container images** that ship to production: small, signed, scanner-friendly, [OCI](https://opencontainers.org/)-compliant. [Python](https://www.python.org/), [Go](https://go.dev/), [JAX](https://jax.readthedocs.io/), [Node.js](https://nodejs.org/), [TypeScript](https://www.typescriptlang.org/), [Rust](https://www.rust-lang.org/), and [Java](https://openjdk.org/) are covered.
Reference [Dockerfiles](https://docs.docker.com/engine/reference/builder/) and best-practice guides for building **secure container images** that ship to production: small, signed, scanner-friendly, [OCI](https://opencontainers.org/)-compliant. [Python](https://www.python.org/), [Go](https://go.dev/), [JAX](https://jax.readthedocs.io/), [Node.js](https://nodejs.org/), [TypeScript](https://www.typescriptlang.org/), [Rust](https://www.rust-lang.org/), [Java](https://openjdk.org/), and [Zig](https://ziglang.org/) are covered.

## Why these templates

Expand Down Expand Up @@ -147,11 +147,21 @@ Multi-stage [Java](https://openjdk.org/) images supporting both Maven and Gradle

Full documentation: [`dockerfiles/java/README.md`](dockerfiles/java/README.md).

### Zig — tarball builder + Distroless static

Multi-stage [Zig](https://ziglang.org/) images that download and SHA-256-verify the official Zig toolchain tarball before use. Produces fully-static binaries (musl libc bundled in the toolchain) that ship in [**Google Distroless static**](https://github.com/GoogleContainerTools/distroless) — the smallest possible runtime: no libc, no shell, no package manager.

- Distroless static image → [`dockerfiles/zig/Dockerfile.zig`](dockerfiles/zig/Dockerfile.zig)
- Chainguard static image → [`dockerfiles/zig/Dockerfile.zig.chainguard`](dockerfiles/zig/Dockerfile.zig.chainguard)
- VS Code devcontainer (Zig + ZLS + gdb + lldb) → [`dockerfiles/zig/Dockerfile.devcontainer`](dockerfiles/zig/Dockerfile.devcontainer)

Full documentation: [`dockerfiles/zig/README.md`](dockerfiles/zig/README.md).

### Coming soon

Tracked as issues — comment or 👍 to bump priority.

- [Zig Dockerfile templates](https://github.com/kssd/dockerfiles/issues/11) _(planned)_
_All planned ecosystems are now available. Open an issue to request a new one._

## Guides

Expand Down
29 changes: 29 additions & 0 deletions dockerfiles/zig/.devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "Zig",
"build": {
"dockerfile": "../Dockerfile.devcontainer",
"context": "..",
"args": {
"VARIANT": "bookworm",
"ZIG_VERSION": "0.16.0",
"ZLS_VERSION": "0.16.0"
}
},
"remoteUser": "vscode",
"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached",
"workspaceFolder": "/workspace",
"customizations": {
"vscode": {
"extensions": ["ziglang.vscode-zig", "vadimcn.vscode-lldb", "usernamehw.errorlens"],
"settings": {
"zig.zls.path": "/usr/local/bin/zls",
"zig.path": "/usr/local/bin/zig",
"editor.formatOnSave": true,
"[zig]": {
"editor.defaultFormatter": "ziglang.vscode-zig"
}
}
}
},
"postCreateCommand": "zig version && zls --version"
}
30 changes: 30 additions & 0 deletions dockerfiles/zig/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Zig build cache and output -- can be large; always exclude
zig-cache/
.zig-cache/
zig-out/

# Editor and IDE
.vscode/
.idea/
*.swp
*.swo

# Devcontainer
.devcontainer/

# Credentials and secrets
.env
*.pem
*.key
*.cert

# CI
.github/

# Git
.git/
.gitignore

# Documentation
*.md
LICENSE
68 changes: 68 additions & 0 deletions dockerfiles/zig/Dockerfile.devcontainer
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Zig devcontainer image (Debian bookworm-slim + Zig + ZLS).
#
# Installs Zig and ZLS (Zig Language Server) from official tarballs, both
# pinned by version and SHA-256. Versions must match: ZLS_VERSION = ZIG_VERSION.
#
# ZIG_VERSION / ZLS_VERSION:
# Update both together. Fetch new SHA-256 values from:
# https://ziglang.org/download/ (Zig)
# https://github.com/zigtools/zls/releases (ZLS)
#
# Non-root vscode user (UID 1000) from the base image.
#
# Build context: dockerfiles/zig/
# docker build -f Dockerfile.devcontainer .
ARG VARIANT=bookworm
ARG ZIG_VERSION=0.16.0
ARG ZLS_VERSION=0.16.0

FROM mcr.microsoft.com/devcontainers/base:1-${VARIANT}

ARG ZIG_VERSION
ARG ZLS_VERSION
ARG TARGETARCH

SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN apt-get update && apt-get install -y --no-install-recommends \
xz-utils=5.4.1-0.2 \
gdb=13.1-3 \
lldb=1:14.0-55.7~deb12u1 \
valgrind=3.19.0-1 \
&& rm -rf /var/lib/apt/lists/*

# Install Zig
RUN case "${TARGETARCH}" in \
amd64) \
ZIG_URL="https://ziglang.org/download/${ZIG_VERSION}/zig-x86_64-linux-${ZIG_VERSION}.tar.xz" ; \
ZIG_SHA256="70e49664a74374b48b51e6f3fdfbf437f6395d42509050588bd49abe52ba3d00" ;; \
arm64) \
ZIG_URL="https://ziglang.org/download/${ZIG_VERSION}/zig-aarch64-linux-${ZIG_VERSION}.tar.xz" ; \
ZIG_SHA256="ea4b09bfb22ec6f6c6ceac57ab63efb6b46e17ab08d21f69f3a48b38e1534f17" ;; \
*) echo "Unsupported TARGETARCH: ${TARGETARCH}" && exit 1 ;; \
esac && \
curl -fsSL "${ZIG_URL}" -o /tmp/zig.tar.xz && \
echo "${ZIG_SHA256} /tmp/zig.tar.xz" | sha256sum -c - && \
tar -xJf /tmp/zig.tar.xz -C /usr/local && \
ln -s "/usr/local/zig-"*"-linux-"*"-${ZIG_VERSION}/zig" /usr/local/bin/zig && \
rm /tmp/zig.tar.xz

# Install ZLS (Zig Language Server)
# Update ZLS_SHA256 values together with ZLS_VERSION.
# Fetch from: https://github.com/zigtools/zls/releases
RUN case "${TARGETARCH}" in \
amd64) \
ZLS_URL="https://github.com/zigtools/zls/releases/download/${ZLS_VERSION}/zls-x86_64-linux.tar.xz" ; \
ZLS_SHA256="ded6d562a0b86ee878b1ddf70ffab2797ce3cdca3b02d6077548f9d56dff96b6" ;; \
arm64) \
ZLS_URL="https://github.com/zigtools/zls/releases/download/${ZLS_VERSION}/zls-aarch64-linux.tar.xz" ; \
ZLS_SHA256="430cd293d201eb70ae2519dbc96c854bf8791b8df7fc9392e8d2dc9680a2bed7" ;; \
*) echo "Unsupported TARGETARCH: ${TARGETARCH}" && exit 1 ;; \
esac && \
curl -fsSL "${ZLS_URL}" -o /tmp/zls.tar.xz && \
echo "${ZLS_SHA256} /tmp/zls.tar.xz" | sha256sum -c - && \
tar -xJf /tmp/zls.tar.xz -C /tmp && \
mv /tmp/zls /usr/local/bin/zls && \
chmod +x /usr/local/bin/zls && \
rm /tmp/zls.tar.xz

USER vscode
81 changes: 81 additions & 0 deletions dockerfiles/zig/Dockerfile.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Zig application image (tarball builder + Google Distroless static, multi-stage).
#
# Downloads and SHA-256-verifies the official Zig toolchain tarball before
# use — the tarball is the supply-chain entry point for Zig builds, so hash
# pinning is mandatory (Zig does not ship signed packages via a package manager).
#
# Multi-arch note:
# The builder selects the correct tarball URL and SHA-256 based on
# TARGETARCH (amd64 -> x86_64, arm64 -> aarch64). The runtime stage is
# architecture-neutral (distroless/static ships a per-arch image).
#
# Optimise mode (ZIG_OPTIMIZE):
# ReleaseSafe (default) — optimised + safety checks (bounds, overflow).
# ReleaseFast — maximum speed, safety checks disabled.
# ReleaseSmall — minimum binary size, safety checks disabled.
#
# BIN_NAME must match the executable name in build.zig (root.name field).
#
# Runtime: gcr.io/distroless/static-debian12:nonroot — no libc, no shell.
# Zig targets musl libc by default (bundled), producing fully-static binaries
# that run without any shared libraries.
#
# Build:
# docker build --build-arg BIN_NAME=myapp -t myapp -f Dockerfile.zig .
#
# Multi-arch:
# docker buildx build --platform=linux/amd64,linux/arm64 \
# --build-arg BIN_NAME=myapp -t myapp -f Dockerfile.zig .
#
# Run (hardened):
# docker run --rm \
# --read-only \
# --cap-drop=ALL \
# --security-opt=no-new-privileges \
# myapp
ARG ZIG_VERSION=0.16.0
ARG DISTROLESS_TAG=debian12

FROM --platform=$BUILDPLATFORM debian:bookworm-slim AS builder
ARG ZIG_VERSION
ARG TARGETARCH
ARG BIN_NAME=app
ARG ZIG_OPTIMIZE=ReleaseSafe

SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates=20230311 \
curl=7.88.1-10+deb12u12 \
xz-utils=5.4.1-0.2 \
&& rm -rf /var/lib/apt/lists/*

# Select tarball URL and SHA-256 by target architecture.
# Update both values together when upgrading ZIG_VERSION.
RUN case "${TARGETARCH}" in \
amd64) \
ZIG_URL="https://ziglang.org/download/${ZIG_VERSION}/zig-x86_64-linux-${ZIG_VERSION}.tar.xz" ; \
ZIG_SHA256="70e49664a74374b48b51e6f3fdfbf437f6395d42509050588bd49abe52ba3d00" ;; \
arm64) \
ZIG_URL="https://ziglang.org/download/${ZIG_VERSION}/zig-aarch64-linux-${ZIG_VERSION}.tar.xz" ; \
ZIG_SHA256="ea4b09bfb22ec6f6c6ceac57ab63efb6b46e17ab08d21f69f3a48b38e1534f17" ;; \
*) echo "Unsupported TARGETARCH: ${TARGETARCH}" && exit 1 ;; \
esac && \
curl -fsSL "${ZIG_URL}" -o /tmp/zig.tar.xz && \
echo "${ZIG_SHA256} /tmp/zig.tar.xz" | sha256sum -c - && \
tar -xJf /tmp/zig.tar.xz -C /usr/local && \
ln -s "/usr/local/zig-"*"-linux-"*"-${ZIG_VERSION}/zig" /usr/local/bin/zig && \
rm /tmp/zig.tar.xz

WORKDIR /src
COPY build.zig build.zig.zon* ./
RUN zig build --fetch || true
COPY . .
RUN zig build -Doptimize="${ZIG_OPTIMIZE}" && \
cp "zig-out/bin/${BIN_NAME}" /server

FROM gcr.io/distroless/static-${DISTROLESS_TAG}:nonroot
COPY --from=builder --chown=nonroot:nonroot /server /app/server

USER nonroot

ENTRYPOINT ["/app/server"]
63 changes: 63 additions & 0 deletions dockerfiles/zig/Dockerfile.zig.chainguard
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Zig application image (tarball builder on Wolfi + Chainguard static, multi-stage).
#
# Chainguard sibling of Dockerfile.zig. Uses cgr.dev/chainguard/wolfi-base
# as the builder (cgr.dev/chainguard/zig:latest is a paid tier) and ships
# in cgr.dev/chainguard/static — daily-rebuilt, Sigstore-signed, with SLSA
# provenance and SBOMs attached.
#
# Free vs. paid Chainguard tags:
# The free Developer Edition only publishes :latest. Versioned tags
# require a paid Chainguard subscription. For free-tier reproducibility,
# pin by digest instead of relying on :latest:
#
# docker pull cgr.dev/chainguard/static:latest
# docker inspect --format='{{index .RepoDigests 0}}' cgr.dev/chainguard/static:latest
# # bake the digest into the FROM line:
# FROM cgr.dev/chainguard/static@sha256:<digest>
#
# Refresh the digest deliberately (e.g. weekly) and re-scan.
#
# Build:
# docker build --build-arg BIN_NAME=myapp -t myapp -f Dockerfile.zig.chainguard .
ARG ZIG_VERSION=0.16.0
ARG BASE_TAG=latest

FROM --platform=$BUILDPLATFORM cgr.dev/chainguard/wolfi-base:${BASE_TAG} AS builder
ARG ZIG_VERSION
ARG TARGETARCH
ARG BIN_NAME=app
ARG ZIG_OPTIMIZE=ReleaseSafe

RUN apk add --no-cache curl=7.87.0-r0 xz=5.6.4-r2

SHELL ["/bin/ash", "-eo", "pipefail", "-c"]

# Select tarball URL and SHA-256 by target architecture.
RUN case "${TARGETARCH}" in \
amd64) \
ZIG_URL="https://ziglang.org/download/${ZIG_VERSION}/zig-x86_64-linux-${ZIG_VERSION}.tar.xz" ; \
ZIG_SHA256="70e49664a74374b48b51e6f3fdfbf437f6395d42509050588bd49abe52ba3d00" ;; \
arm64) \
ZIG_URL="https://ziglang.org/download/${ZIG_VERSION}/zig-aarch64-linux-${ZIG_VERSION}.tar.xz" ; \
ZIG_SHA256="ea4b09bfb22ec6f6c6ceac57ab63efb6b46e17ab08d21f69f3a48b38e1534f17" ;; \
*) echo "Unsupported TARGETARCH: ${TARGETARCH}" && exit 1 ;; \
esac && \
curl -fsSL "${ZIG_URL}" -o /tmp/zig.tar.xz && \
echo "${ZIG_SHA256} /tmp/zig.tar.xz" | sha256sum -c - && \
tar -xJf /tmp/zig.tar.xz -C /usr/local && \
ln -s "/usr/local/zig-"*"-linux-"*"-${ZIG_VERSION}/zig" /usr/local/bin/zig && \
rm /tmp/zig.tar.xz

WORKDIR /src
COPY build.zig build.zig.zon* ./
RUN zig build --fetch || true
COPY . .
RUN zig build -Doptimize="${ZIG_OPTIMIZE}" && \
cp "zig-out/bin/${BIN_NAME}" /server

FROM cgr.dev/chainguard/static:${BASE_TAG}
COPY --from=builder /server /app/server

USER nonroot

ENTRYPOINT ["/app/server"]
Loading
Loading