69 lines
3.1 KiB
Docker
69 lines
3.1 KiB
Docker
# syntax=docker/dockerfile:1
|
|
|
|
# Node 22 LTS on Alpine. The tag is deliberately unpinned: rebuilding this image is
|
|
# how you pick up new Node patches, Alpine packages and tool releases.
|
|
FROM node:22-alpine
|
|
|
|
# Alpine package versions are intentionally unpinned. This image tracks "current" —
|
|
# reproducibility comes from the published image tag, not from version pins that
|
|
# would rot against Alpine's rolling repositories.
|
|
# hadolint ignore=DL3018
|
|
RUN apk add --no-cache \
|
|
bash \
|
|
ca-certificates openssl \
|
|
coreutils findutils diffutils gawk grep sed \
|
|
file less patch tree \
|
|
curl wget \
|
|
jq yamllint \
|
|
bind-tools iputils-ping netcat-openbsd socat rsync \
|
|
git git-lfs openssh-client-default \
|
|
ripgrep fd \
|
|
tar gzip xz zip unzip \
|
|
helm kubectl \
|
|
make procps-ng su-exec tini tzdata
|
|
|
|
# Use bash with pipefail for the remaining build steps so a failure anywhere in a
|
|
# pipeline fails the layer.
|
|
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
|
|
|
# yq is not packaged for Alpine, so take the current upstream release. Running the
|
|
# binary immediately is the verification that matters here: it catches a truncated
|
|
# or HTML-error-page download, which is the realistic failure mode.
|
|
RUN arch="$(apk --print-arch | sed -e 's/x86_64/amd64/' -e 's/aarch64/arm64/')" \
|
|
&& curl -fsSL -o /usr/local/bin/yq \
|
|
"https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${arch}" \
|
|
&& chmod 0755 /usr/local/bin/yq \
|
|
&& yq --version
|
|
|
|
# kubeconform validates manifests against the Kubernetes and CRD JSON schemas. Not
|
|
# packaged for Alpine either, so same treatment as yq: current upstream release, run it
|
|
# in the same layer so a truncated download fails the build.
|
|
#
|
|
# Defaults that keep non-interactive agent shells from hanging or failing:
|
|
# * pagers off — git/kubectl/helm otherwise block on `less` with no TTY
|
|
# * no git prompts — a private remote without creds fails fast instead of waiting
|
|
# * helm homes /tmp — lets the image run with a read-only root filesystem
|
|
ENV PAGER=cat \
|
|
GIT_PAGER=cat \
|
|
GIT_TERMINAL_PROMPT=0 \
|
|
HELM_CACHE_HOME=/tmp/.cache/helm \
|
|
HELM_CONFIG_HOME=/tmp/.config/helm \
|
|
HELM_DATA_HOME=/tmp/.local/share/helm
|
|
|
|
# tini reaps the grandchildren a shell workload leaves behind; the base image's
|
|
# docker-entrypoint.sh is kept so `node`-style invocations still work.
|
|
ENTRYPOINT ["/sbin/tini", "--", "docker-entrypoint.sh"]
|
|
CMD ["bash"]
|
|
|
|
# Last, so bumping build metadata does not invalidate the layers above.
|
|
ARG VERSION=dev
|
|
ARG REVISION=unknown
|
|
ARG CREATED=unknown
|
|
LABEL org.opencontainers.image.title="node-agent" \
|
|
org.opencontainers.image.description="Node 22 LTS on Alpine with a GNU shell, network, and Kubernetes toolchain for AI agent command execution" \
|
|
org.opencontainers.image.source="https://gitea.libretechconsulting.com/rmcguire/images" \
|
|
org.opencontainers.image.base.name="docker.io/library/node:22-alpine" \
|
|
org.opencontainers.image.version="${VERSION}" \
|
|
org.opencontainers.image.revision="${REVISION}" \
|
|
org.opencontainers.image.created="${CREATED}"
|