Fix CI/CD
This commit is contained in:
@@ -65,9 +65,13 @@ jobs:
|
||||
--filename auth-proxy.yaml \
|
||||
--filename kubernetes-dashboard-ingressroute.yaml
|
||||
|
||||
for deployment in kubernetes-dashboard-api kubernetes-dashboard-auth kubernetes-dashboard-web kubernetes-dashboard-metrics-scraper kubernetes-dashboard-kong kubernetes-dashboard-auth-proxy; do
|
||||
kubectl --namespace "${NAMESPACE}" rollout status "deployment/${deployment}" --timeout=10m
|
||||
done
|
||||
bash ./wait-for-deployments.sh \
|
||||
kubernetes-dashboard-api \
|
||||
kubernetes-dashboard-auth \
|
||||
kubernetes-dashboard-web \
|
||||
kubernetes-dashboard-metrics-scraper \
|
||||
kubernetes-dashboard-kong \
|
||||
kubernetes-dashboard-auth-proxy
|
||||
|
||||
status=$(curl --silent --show-error --output /dev/null --write-out '%{http_code}' --max-time 15 https://kubernetes.brunner.ninja/)
|
||||
case "${status}" in
|
||||
|
||||
@@ -18,6 +18,11 @@ automatically every hour; it is never stored in Git, a static Secret, Gitea, or
|
||||
Traefik configuration. Supplying the Authorization header makes Dashboard skip
|
||||
its bearer-token login page.
|
||||
|
||||
Every Dashboard container retains a CPU request, right-sized to `25m` from an
|
||||
observed idle use of roughly `1-2m`. Requests are not removed: they still give
|
||||
the scheduler a placement signal while the higher CPU limits leave room for
|
||||
interactive bursts.
|
||||
|
||||
This preserves the previous cluster-admin behavior, but Kubernetes audit events
|
||||
identify every Dashboard action as the same service account. Native Authentik
|
||||
OIDC would provide per-user identity, but requires kube-apiserver configuration
|
||||
@@ -44,6 +49,8 @@ Then run `./create-ci-kubeconfig.sh` and store its final line as the Gitea
|
||||
Actions secret `KUBE_CONFIG_BASE64`. The CI identity can update only named,
|
||||
already-existing Dashboard objects. It cannot read Secrets, edit the
|
||||
`admin-user` cluster-admin binding, create resources, or delete resources.
|
||||
Deployment readiness is checked by polling those exact object names; the CI
|
||||
identity deliberately has no namespace-wide Deployment `list/watch` access.
|
||||
|
||||
The deploy workflow runs only for `main`; pull requests and all pushes run the
|
||||
validation job. The chart's generated CSRF Secret is created by the bootstrap
|
||||
|
||||
@@ -20,6 +20,14 @@ auth:
|
||||
scaling:
|
||||
replicas: 2
|
||||
revisionHistoryLimit: 3
|
||||
containers:
|
||||
resources:
|
||||
requests:
|
||||
cpu: 25m
|
||||
memory: 200Mi
|
||||
limits:
|
||||
cpu: 250m
|
||||
memory: 400Mi
|
||||
|
||||
api:
|
||||
image:
|
||||
@@ -28,6 +36,14 @@ api:
|
||||
scaling:
|
||||
replicas: 2
|
||||
revisionHistoryLimit: 3
|
||||
containers:
|
||||
resources:
|
||||
requests:
|
||||
cpu: 25m
|
||||
memory: 200Mi
|
||||
limits:
|
||||
cpu: 250m
|
||||
memory: 400Mi
|
||||
|
||||
web:
|
||||
image:
|
||||
@@ -36,6 +52,14 @@ web:
|
||||
scaling:
|
||||
replicas: 2
|
||||
revisionHistoryLimit: 3
|
||||
containers:
|
||||
resources:
|
||||
requests:
|
||||
cpu: 25m
|
||||
memory: 200Mi
|
||||
limits:
|
||||
cpu: 250m
|
||||
memory: 400Mi
|
||||
|
||||
metricsScraper:
|
||||
enabled: true
|
||||
@@ -44,6 +68,14 @@ metricsScraper:
|
||||
tag: 1.2.2
|
||||
scaling:
|
||||
revisionHistoryLimit: 3
|
||||
containers:
|
||||
resources:
|
||||
requests:
|
||||
cpu: 25m
|
||||
memory: 200Mi
|
||||
limits:
|
||||
cpu: 250m
|
||||
memory: 400Mi
|
||||
|
||||
# Browser TLS terminates at Traefik. Kong still uses TLS because the private
|
||||
# auth proxy sends the privileged projected bearer token on this hop.
|
||||
@@ -55,7 +87,7 @@ kong:
|
||||
replicaCount: 2
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
cpu: 25m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
|
||||
@@ -11,6 +11,7 @@ bash -n \
|
||||
"${project_dir}/pin-images.sh" \
|
||||
"${project_dir}/render.sh" \
|
||||
"${project_dir}/create-ci-kubeconfig.sh" \
|
||||
"${project_dir}/wait-for-deployments.sh" \
|
||||
"${project_dir}/test.sh"
|
||||
awk -f "${project_dir}/filter-secrets.awk" /dev/null >/dev/null
|
||||
|
||||
@@ -34,11 +35,24 @@ if grep -Fq 'namespace: default' "${project_dir}/kubernetes-dashboard-ingressrou
|
||||
echo "Dashboard route must not use a cross-namespace middleware" >&2
|
||||
exit 1
|
||||
fi
|
||||
if grep -Fq 'rollout status' "${project_dir}/.gitea/workflows/deploy.yml"; then
|
||||
echo "Restricted CI must poll exact Deployment names instead of list/watch" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -Fq 'expirationSeconds: 3600' "${project_dir}/auth-proxy.yaml"
|
||||
grep -Fq 'proxy_pass https://kubernetes-dashboard-kong-proxy' "${project_dir}/auth-proxy.yaml"
|
||||
grep -Fq 'containerPort: 8443' "${workdir}/dashboard.yaml"
|
||||
grep -Fq 'dashboard-api:1.14.0@sha256:2bd14c0ffee99d15fb1595644ebd1083ac32c5157c6e6fd8615b0f556a1390c2' "${workdir}/dashboard.yaml"
|
||||
|
||||
request_count=$(awk '
|
||||
$1 == "cpu:" && $2 == "25m" { count++ }
|
||||
END { print count + 0 }
|
||||
' "${workdir}/dashboard.yaml")
|
||||
if [[ "${request_count}" -lt 5 ]] || grep -Fq 'cpu: 100m' "${workdir}/dashboard.yaml"; then
|
||||
echo "Expected every Dashboard chart component to request only 25m CPU" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
image=ghcr.io/yannh/kubeconform:v0.7.0@sha256:85dbef6b4b312b99133decc9c6fc9495e9fc5f92293d4ff3b7e1b30f5611823c
|
||||
for file in \
|
||||
"${workdir}/dashboard.yaml" \
|
||||
|
||||
Executable
+44
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
namespace=${NAMESPACE:-kubernetes-dashboard}
|
||||
timeout_seconds=${DEPLOYMENT_TIMEOUT_SECONDS:-600}
|
||||
poll_seconds=${DEPLOYMENT_POLL_SECONDS:-5}
|
||||
|
||||
if [[ "$#" -eq 0 ]]; then
|
||||
echo "Usage: wait-for-deployments.sh DEPLOYMENT..." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
for deployment in "$@"; do
|
||||
deadline=$((SECONDS + timeout_seconds))
|
||||
state="not observed"
|
||||
complete=false
|
||||
|
||||
while ((SECONDS < deadline)); do
|
||||
state=$(kubectl --namespace "${namespace}" get "deployment/${deployment}" \
|
||||
--output=jsonpath='{.metadata.generation}{"|"}{.status.observedGeneration}{"|"}{.spec.replicas}{"|"}{.status.updatedReplicas}{"|"}{.status.readyReplicas}{"|"}{.status.availableReplicas}{"\n"}')
|
||||
IFS='|' read -r generation observed desired updated ready available <<< "${state}"
|
||||
observed=${observed:-0}
|
||||
desired=${desired:-0}
|
||||
updated=${updated:-0}
|
||||
ready=${ready:-0}
|
||||
available=${available:-0}
|
||||
|
||||
if [[ "${observed}" -ge "${generation}" \
|
||||
&& "${updated}" -eq "${desired}" \
|
||||
&& "${ready}" -eq "${desired}" \
|
||||
&& "${available}" -eq "${desired}" ]]; then
|
||||
echo "deployment/${deployment} is ready (${ready}/${desired})"
|
||||
complete=true
|
||||
break
|
||||
fi
|
||||
sleep "${poll_seconds}"
|
||||
done
|
||||
|
||||
if [[ "${complete}" != true ]]; then
|
||||
echo "Timed out waiting for deployment/${deployment}; generation observed desired updated ready available: ${state}" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
Reference in New Issue
Block a user