Merge pull request 'feat: align catalog runtime builds' (#5) from feat/align-runtime-catalog into main

Reviewed-on: #5
This commit is contained in:
eding 2026-09-15 20:44:37 +02:00
commit 0a765489ac
5 changed files with 287 additions and 169 deletions

View file

@ -2,4 +2,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization kind: Kustomization
resources: resources:
- maidn-node-static-image.yaml - maidn-node-static-image.yaml
- maidn-node-runtime-image.yaml
- maidn-preview-orphan-reconciler.yaml - maidn-preview-orphan-reconciler.yaml

View file

@ -0,0 +1,136 @@
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: maidn-node-runtime-image
namespace: tekton-pipelines
spec:
params:
- name: url
type: string
- name: revision
type: string
- name: image
type: string
volumes:
- name: work
emptyDir: {}
- name: git-credentials
secret:
secretName: forgejo-git-credentials
- name: registry-credentials
secret:
secretName: forgejo-registry-credentials
items:
- key: .dockerconfigjson
path: config.json
stepTemplate:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
seccompProfile:
type: RuntimeDefault
steps:
- name: clone
image: alpine/git:2.47.2
env:
- name: REPOSITORY_URL
value: $(params.url)
- name: REVISION
value: $(params.revision)
- name: IMAGE
value: $(params.image)
volumeMounts:
- name: work
mountPath: /work
- name: git-credentials
mountPath: /credentials
readOnly: true
script: |
#!/bin/sh
set -eu
case "$REPOSITORY_URL" in https://git.pingu.pw/*) ;; *) exit 1 ;; esac
repository_path=${REPOSITORY_URL#https://git.pingu.pw/}
case "$repository_path" in [A-Za-z0-9][A-Za-z0-9._-]*/[A-Za-z0-9][A-Za-z0-9._-]*.git) ;; *) exit 1 ;; esac
case "$repository_path" in *[!A-Za-z0-9._/-]*|*..*|*//*|*/|*/*/*) exit 1 ;; esac
case "$REVISION" in [A-Za-z0-9]*) ;; *) exit 1 ;; esac
case "$REVISION" in *[!A-Za-z0-9._/-]*|*..*|*//*|*/) exit 1 ;; esac
case "$IMAGE" in git.pingu.pw/*) ;; *) exit 1 ;; esac
image_path=${IMAGE#git.pingu.pw/}
case "$image_path" in [A-Za-z0-9][A-Za-z0-9._-]*/[A-Za-z0-9][A-Za-z0-9._-]*) ;; *) exit 1 ;; esac
case "$image_path" in *[!A-Za-z0-9._/-]*|*..*|*//*|*/|*/*/*) exit 1 ;; esac
cat >/work/askpass <<'EOF'
#!/bin/sh
case "$1" in *Username*) cat /credentials/username ;; *) cat /credentials/password ;; esac
EOF
chmod 0700 /work/askpass
GIT_ASKPASS=/work/askpass GIT_TERMINAL_PROMPT=0 git clone "$REPOSITORY_URL" /work/source
git -C /work/source checkout "$REVISION"
rm -f /work/askpass
- name: build-layer
image: node:22-alpine
resources:
requests:
memory: 256Mi
limits:
memory: 512Mi
volumeMounts:
- name: work
mountPath: /work
script: |
#!/bin/sh
set -eu
cd /work/source
npm install --ignore-scripts --no-audit --no-fund --package-lock=false
npm run build
npm prune --omit=dev --ignore-scripts --no-audit --no-fund
test -f package.json
test -d node_modules
test -d dist
mkdir -p /work/layer/app
cp package.json /work/layer/app/
cp -R node_modules dist /work/layer/app/
tar -C /work/layer -cf /work/layer.tar app
rm -rf /work/source /work/layer
- name: append
image: gcr.io/go-containerregistry/crane:v0.21.7
env:
- name: HOME
value: /tekton/home
- name: DOCKER_CONFIG
value: /tekton/home/.docker
args:
- append
- --base=node:22-alpine
- --new_layer=/work/layer.tar
- --new_tag=$(params.image):$(params.revision)
volumeMounts:
- name: work
mountPath: /work
- name: registry-credentials
mountPath: /tekton/home/.docker
readOnly: true
- name: mutate
image: gcr.io/go-containerregistry/crane:v0.21.7
env:
- name: HOME
value: /tekton/home
- name: DOCKER_CONFIG
value: /tekton/home/.docker
args:
- mutate
- $(params.image):$(params.revision)
- --entrypoint=node
- --cmd=dist/index.js
- --workdir=/app
- --user=node
- --env=PORT=8080
- --exposed-ports=8080/tcp
- --tag=$(params.image):$(params.revision)
volumeMounts:
- name: registry-credentials
mountPath: /tekton/home/.docker
readOnly: true

View file

@ -1,30 +1,46 @@
apiVersion: tekton.dev/v1 apiVersion: tekton.dev/v1
kind: Task kind: Task
metadata: metadata:
name: maidn-git-clone name: maidn-node-static-image
namespace: tekton-pipelines namespace: tekton-pipelines
spec: spec:
params:
- name: url
type: string
- name: revision
type: string
- name: image
type: string
- name: output-directory
type: string
- name: build-configuration
type: string
default: ci
- name: base-image
type: string
default: nginx:1.27-alpine
volumes:
- name: work
emptyDir: {}
- name: git-credentials
secret:
secretName: forgejo-git-credentials
- name: registry-credentials
secret:
secretName: forgejo-registry-credentials
items:
- key: .dockerconfigjson
path: config.json
stepTemplate: stepTemplate:
env:
- name: HOME
value: /tekton/home
securityContext: securityContext:
runAsNonRoot: true runAsNonRoot: true
runAsUser: 1000 runAsUser: 1000
runAsGroup: 1000 runAsGroup: 1000
allowPrivilegeEscalation: false allowPrivilegeEscalation: false
capabilities: capabilities:
drop: drop: [ALL]
- ALL
seccompProfile: seccompProfile:
type: RuntimeDefault type: RuntimeDefault
params:
- name: url
type: string
- name: revision
type: string
workspaces:
- name: source
steps: steps:
- name: clone - name: clone
image: alpine/git:2.47.2 image: alpine/git:2.47.2
@ -33,160 +49,71 @@ spec:
value: $(params.url) value: $(params.url)
- name: REVISION - name: REVISION
value: $(params.revision) value: $(params.revision)
- name: SOURCE_PATH volumeMounts:
value: $(workspaces.source.path) - name: work
mountPath: /work
- name: git-credentials
mountPath: /credentials
readOnly: true
script: | script: |
#!/bin/sh #!/bin/sh
set -eu set -eu
case "$REPOSITORY_URL" in https://git.pingu.pw/*) ;; *) exit 1 ;; esac case "$REPOSITORY_URL" in https://git.pingu.pw/*.git) ;; *) exit 1 ;; esac
repository_path=${REPOSITORY_URL#https://git.pingu.pw/}
case "$repository_path" in *.git) ;; *) exit 1 ;; esac
case "$repository_path" in ''|*[!A-Za-z0-9._/-]*|/*|*//*|*..*) exit 1 ;; esac
case "$REVISION" in [A-Za-z0-9]*) ;; *) exit 1 ;; esac case "$REVISION" in [A-Za-z0-9]*) ;; *) exit 1 ;; esac
case "$REVISION" in *[!A-Za-z0-9._/-]*|*..*|*//*|*/) exit 1 ;; esac case "$REVISION" in *[!A-Za-z0-9._/-]*|*..*|*//*|*/) exit 1 ;; esac
git clone "$REPOSITORY_URL" "$SOURCE_PATH" cat >/work/askpass <<'EOF'
git config --global --add safe.directory "$SOURCE_PATH" #!/bin/sh
git -C "$SOURCE_PATH" checkout "$REVISION" case "$1" in *Username*) cat /credentials/username ;; *) cat /credentials/password ;; esac
--- EOF
apiVersion: tekton.dev/v1 chmod 0700 /work/askpass
kind: Task GIT_ASKPASS=/work/askpass GIT_TERMINAL_PROMPT=0 git clone "$REPOSITORY_URL" /work/source
metadata: git -C /work/source checkout "$REVISION"
name: maidn-node-static-build rm -f /work/askpass
namespace: tekton-pipelines
spec:
stepTemplate:
env:
- name: HOME
value: /tekton/home
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
params:
- name: output-directory
type: string
- name: build-configuration
type: string
default: ci
- name: target-directory
type: string
default: /www/target
workspaces:
- name: source
steps:
- name: build-layer - name: build-layer
image: node:22-alpine image: node:22-alpine
env:
- name: OUTPUT_DIRECTORY
value: $(params.output-directory)
- name: SOURCE_PATH
value: $(workspaces.source.path)
- name: TARGET_DIRECTORY
value: $(params.target-directory)
- name: BUILD_CONFIGURATION
value: $(params.build-configuration)
- name: NODE_OPTIONS
value: --max-old-space-size=384
resources: resources:
requests: requests:
memory: 256Mi memory: 256Mi
limits: limits:
memory: 512Mi memory: 512Mi
env:
- name: NODE_OPTIONS
value: --max-old-space-size=384
- name: OUTPUT_DIRECTORY
value: $(params.output-directory)
- name: BUILD_CONFIGURATION
value: $(params.build-configuration)
volumeMounts:
- name: work
mountPath: /work
script: | script: |
#!/bin/sh #!/bin/sh
set -eu set -eu
case "$OUTPUT_DIRECTORY" in ''|/*|-*|*[!A-Za-z0-9._/-]*|*..*|*//*|*/) exit 1 ;; esac case "$OUTPUT_DIRECTORY" in ''|/*|-*|*[!A-Za-z0-9._/-]*|*..*|*//*|*/) exit 1 ;; esac
case "$TARGET_DIRECTORY" in /*) ;; *) exit 1 ;; esac
target_path=${TARGET_DIRECTORY#/}
case "$target_path" in ''|-*|*[!A-Za-z0-9._/-]*|*..*|*//*|*/) exit 1 ;; esac
case "$BUILD_CONFIGURATION" in ''|-*|*[!A-Za-z0-9._-]*) exit 1 ;; esac case "$BUILD_CONFIGURATION" in ''|-*|*[!A-Za-z0-9._-]*) exit 1 ;; esac
build_dir=$(mktemp -d) cd /work/source
cp -R "$SOURCE_PATH"/. "$build_dir"
cd "$build_dir"
# ponytail: no lockfile; skip install scripts and use npm ci when package-lock.json is committed.
npm install --ignore-scripts --no-audit --no-fund --package-lock=false npm install --ignore-scripts --no-audit --no-fund --package-lock=false
npm run build -- --configuration "$BUILD_CONFIGURATION" npm run build -- --configuration "$BUILD_CONFIGURATION"
test -d "$OUTPUT_DIRECTORY" test -d "$OUTPUT_DIRECTORY"
layer_dir=$(mktemp -d) mkdir -p /work/layer/www
trap 'rm -rf "$build_dir" "$layer_dir"' EXIT cp -R "$OUTPUT_DIRECTORY"/. /work/layer/www/
mkdir -p "$layer_dir/$target_path" tar -C /work/layer -cf /work/layer.tar www
cp -R "$OUTPUT_DIRECTORY"/. "$layer_dir/$target_path/" rm -rf /work/source /work/layer
tar -C "$layer_dir" -cf "$SOURCE_PATH/layer.tar" "$target_path"
for memory_peak_path in /sys/fs/cgroup/memory.peak /sys/fs/cgroup/memory/memory.max_usage_in_bytes; do
if [ -r "$memory_peak_path" ] && memory_peak=$(cat "$memory_peak_path"); then
case "$memory_peak" in ''|*[!0-9]*) ;; *) printf 'cgroup memory peak: %s\n' "$memory_peak"; break ;; esac
fi
done
---
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: maidn-node-static-push
namespace: tekton-pipelines
spec:
stepTemplate:
env:
- name: HOME
value: /tekton/home
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
params:
- name: image
type: string
- name: revision
type: string
- name: base-image
type: string
default: nginx:1.27-alpine
workspaces:
- name: source
volumes:
- name: registry-credentials
secret:
secretName: forgejo-registry-credentials
items:
- key: .dockerconfigjson
path: config.json
steps:
- name: validate-inputs
image: alpine:3.21.3
env:
- name: IMAGE
value: $(params.image)
- name: REVISION
value: $(params.revision)
- name: BASE_IMAGE
value: $(params.base-image)
script: |
#!/bin/sh
set -eu
case "$IMAGE" in git.pingu.pw/*) ;; *) exit 1 ;; esac
image_path=${IMAGE#git.pingu.pw/}
case "$image_path" in ''|*[!A-Za-z0-9._/-]*|/*|*//*|*..*|*/) exit 1 ;; esac
case "$REVISION" in [A-Za-z0-9]*) ;; *) exit 1 ;; esac
case "$REVISION" in *[!A-Za-z0-9._/-]*|*..*|*//*|*/) exit 1 ;; esac
case "$BASE_IMAGE" in ''|-*|*[!A-Za-z0-9._/@:-]*|/*|*//*|*..*) exit 1 ;; esac
- name: push - name: push
image: gcr.io/go-containerregistry/crane:v0.21.7 image: gcr.io/go-containerregistry/crane:v0.21.7
env:
- name: HOME
value: /tekton/home
- name: DOCKER_CONFIG
value: /tekton/home/.docker
args: args:
- append - append
- --base=$(params.base-image) - --base=$(params.base-image)
- --new_layer=$(workspaces.source.path)/layer.tar - --new_layer=/work/layer.tar
- --new_tag=$(params.image):$(params.revision) - --new_tag=$(params.image):$(params.revision)
volumeMounts: volumeMounts:
- name: work
mountPath: /work
- name: registry-credentials - name: registry-credentials
mountPath: /tekton/home/.docker mountPath: /tekton/home/.docker
readOnly: true

View file

@ -0,0 +1,51 @@
#!/bin/sh
set -eu
root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
task="$root/catalog/maidn-node-runtime-image.yaml"
contains() {
grep -qF -- "$1" "$task"
}
for value in \
'apiVersion: tekton.dev/v1' \
'kind: Task' \
'name: maidn-node-runtime-image' \
'emptyDir: {}' \
'forgejo-git-credentials' \
'forgejo-registry-credentials' \
'case "$REPOSITORY_URL" in https://git.pingu.pw/*)' \
'case "$REVISION" in [A-Za-z0-9]*)' \
'case "$IMAGE" in git.pingu.pw/*)' \
'GIT_ASKPASS=/work/askpass' \
'runAsNonRoot: true' \
'allowPrivilegeEscalation: false' \
'drop: [ALL]' \
'type: RuntimeDefault' \
'npm install --ignore-scripts --no-audit --no-fund --package-lock=false' \
'memory: 256Mi' \
'memory: 512Mi' \
'npm run build' \
'npm prune --omit=dev --ignore-scripts --no-audit --no-fund' \
'cp package.json /work/layer/app/' \
'cp -R node_modules dist /work/layer/app/' \
'tar -C /work/layer -cf /work/layer.tar app' \
'--base=node:22-alpine' \
'--new_tag=$(params.image):$(params.revision)' \
'- mutate' \
'--entrypoint=node' \
'--cmd=dist/index.js' \
'--workdir=/app' \
'--user=node' \
'--env=PORT=8080' \
'--exposed-ports=8080/tcp' \
'--tag=$(params.image):$(params.revision)'; do
contains "$value"
done
for param in url revision image; do
contains "name: $param"
done
! grep -qiE 'kaniko|privileged: true' "$task"

View file

@ -2,36 +2,39 @@
set -eu set -eu
root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
catalog="$root/catalog/maidn-node-static-image.yaml" task="$root/catalog/maidn-node-static-image.yaml"
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
task() { contains() {
awk -v name="$1" ' grep -qF -- "$1" "$task"
/^---$/ { if (found) exit }
$0 == " name: " name { found=1 }
found { print }
' "$catalog"
} }
[ "$(grep -c '^apiVersion: tekton.dev/v1$' "$catalog")" -eq 3 ] for value in \
[ "$(grep -c '^kind: Task$' "$catalog")" -eq 3 ] 'apiVersion: tekton.dev/v1' \
[ "$(grep -cF 'runAsNonRoot: true' "$catalog")" -eq 3 ] 'kind: Task' \
[ "$(grep -cF 'forgejo-registry-credentials' "$catalog")" -eq 1 ] 'name: maidn-node-static-image' \
'emptyDir: {}' \
for name in maidn-git-clone maidn-node-static-build maidn-node-static-push; do 'forgejo-git-credentials' \
task "$name" > "$tmp/$name" 'forgejo-registry-credentials' \
grep -qF " name: $name" "$tmp/$name" 'case "$REPOSITORY_URL" in https://git.pingu.pw/*.git)' \
grep -qF ' - name: source' "$tmp/$name" 'case "$REVISION" in [A-Za-z0-9]*)' \
'case "$OUTPUT_DIRECTORY" in' \
'case "$BUILD_CONFIGURATION" in' \
'GIT_ASKPASS=/work/askpass' \
'runAsNonRoot: true' \
'allowPrivilegeEscalation: false' \
'drop: [ALL]' \
'type: RuntimeDefault' \
'npm install --ignore-scripts --no-audit --no-fund --package-lock=false' \
'memory: 256Mi' \
'memory: 512Mi' \
'tar -C /work/layer -cf /work/layer.tar www' \
'--base=$(params.base-image)' \
'--new_tag=$(params.image):$(params.revision)'; do
contains "$value"
done done
grep -qF 'git clone "$REPOSITORY_URL" "$SOURCE_PATH"' "$tmp/maidn-git-clone" for param in url revision image output-directory build-configuration base-image; do
grep -qF 'value: --max-old-space-size=384' "$tmp/maidn-node-static-build" contains "name: $param"
grep -qF 'memory: 256Mi' "$tmp/maidn-node-static-build" done
grep -qF 'memory: 512Mi' "$tmp/maidn-node-static-build"
grep -qF 'tar -C "$layer_dir" -cf "$SOURCE_PATH/layer.tar" "$target_path"' "$tmp/maidn-node-static-build" ! grep -qiE 'kaniko|privileged: true' "$task"
grep -qF 'for memory_peak_path in /sys/fs/cgroup/memory.peak /sys/fs/cgroup/memory/memory.max_usage_in_bytes; do' "$tmp/maidn-node-static-build"
grep -qF "if [ -r \"\$memory_peak_path\" ] && memory_peak=\$(cat \"\$memory_peak_path\"); then" "$tmp/maidn-node-static-build"
grep -qF 'image: gcr.io/go-containerregistry/crane:v0.21.7' "$tmp/maidn-node-static-push"
grep -qF ' - append' "$tmp/maidn-node-static-push"
grep -qF 'mountPath: /tekton/home/.docker' "$tmp/maidn-node-static-push"