fix(cd): deploy production images by digest
This commit is contained in:
@@ -1733,6 +1733,25 @@ jobs:
|
||||
docker push ${{ env.HARBOR }}/awoooi/api:${{ github.sha }}
|
||||
run_docker_push_step api_push_latest "${DOCKER_API_PUSH_TIMEOUT_SECONDS:-600}" \
|
||||
docker push ${{ env.HARBOR }}/awoooi/api:latest
|
||||
API_IMAGE_DIGEST="$(
|
||||
docker manifest inspect --verbose \
|
||||
"${{ env.HARBOR }}/awoooi/api:${{ github.sha }}" | \
|
||||
python3 -c '
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
|
||||
payload = json.load(sys.stdin)
|
||||
digest = payload.get("Descriptor", {}).get("digest", "")
|
||||
if not re.fullmatch(r"sha256:[0-9a-f]{64}", digest):
|
||||
raise SystemExit("api_harbor_digest_invalid")
|
||||
print(digest)
|
||||
'
|
||||
)"
|
||||
docker manifest inspect \
|
||||
"${{ env.HARBOR }}/awoooi/api@${API_IMAGE_DIGEST}" >/dev/null
|
||||
echo "API_IMAGE_DIGEST=${API_IMAGE_DIGEST}" >> "${GITHUB_ENV}"
|
||||
echo "api_harbor_digest_verified=${API_IMAGE_DIGEST}"
|
||||
|
||||
# 2026-03-31 ogt: 移除中間通知,減少訊息雜訊
|
||||
|
||||
@@ -1848,6 +1867,25 @@ jobs:
|
||||
docker push ${{ env.HARBOR }}/awoooi/web:${{ github.sha }}
|
||||
run_docker_push_step web_push_latest "${DOCKER_WEB_PUSH_TIMEOUT_SECONDS:-600}" \
|
||||
docker push ${{ env.HARBOR }}/awoooi/web:latest
|
||||
WEB_IMAGE_DIGEST="$(
|
||||
docker manifest inspect --verbose \
|
||||
"${{ env.HARBOR }}/awoooi/web:${{ github.sha }}" | \
|
||||
python3 -c '
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
|
||||
payload = json.load(sys.stdin)
|
||||
digest = payload.get("Descriptor", {}).get("digest", "")
|
||||
if not re.fullmatch(r"sha256:[0-9a-f]{64}", digest):
|
||||
raise SystemExit("web_harbor_digest_invalid")
|
||||
print(digest)
|
||||
'
|
||||
)"
|
||||
docker manifest inspect \
|
||||
"${{ env.HARBOR }}/awoooi/web@${WEB_IMAGE_DIGEST}" >/dev/null
|
||||
echo "WEB_IMAGE_DIGEST=${WEB_IMAGE_DIGEST}" >> "${GITHUB_ENV}"
|
||||
echo "web_harbor_digest_verified=${WEB_IMAGE_DIGEST}"
|
||||
|
||||
- name: Release Docker Build Lock
|
||||
if: always()
|
||||
@@ -2611,6 +2649,16 @@ jobs:
|
||||
|
||||
export IMAGE_TAG="${{ github.sha }}"
|
||||
HARBOR=192.168.0.110:5000
|
||||
if ! printf '%s\n' "${API_IMAGE_DIGEST:-}" | \
|
||||
grep -Eq '^sha256:[0-9a-f]{64}$'; then
|
||||
echo "BLOCKER api_harbor_digest_missing"
|
||||
exit 1
|
||||
fi
|
||||
if ! printf '%s\n' "${WEB_IMAGE_DIGEST:-}" | \
|
||||
grep -Eq '^sha256:[0-9a-f]{64}$'; then
|
||||
echo "BLOCKER web_harbor_digest_missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ─── Step 1: Apply NetworkPolicy + ConfigMap + ServiceRegistry ───
|
||||
# Preserve only live Deployment specs and Secret object existence.
|
||||
@@ -2789,7 +2837,7 @@ jobs:
|
||||
"KUBECTL='sudo kubectl --kubeconfig=/etc/rancher/k3s/k3s.yaml --server=${{ env.K8S_API_SERVER }}'; \$KUBECTL apply -f -"
|
||||
echo "✅ Service Registry ConfigMap 已更新"
|
||||
|
||||
# ─── Step 2: 更新 kustomization.yaml image tag ───
|
||||
# ─── Step 2: 更新 kustomization.yaml immutable image digest ───
|
||||
# kustomize is an immutable dependency of the internal runner image.
|
||||
# GitHub is frozen, so CD must never download tools from public GitHub.
|
||||
export PATH="${HOME}/.local/bin:${PATH}"
|
||||
@@ -2799,11 +2847,12 @@ jobs:
|
||||
}
|
||||
|
||||
cd k8s/awoooi-prod
|
||||
# kustomize edit set image 更新 tag
|
||||
# Source SHA remains in AWOOOI_BUILD_COMMIT_SHA; workload identity is
|
||||
# pinned to the independently read-back Harbor manifest digest.
|
||||
kustomize edit set image \
|
||||
192.168.0.110:5000/library/api:IMAGE_TAG_PLACEHOLDER=${HARBOR}/awoooi/api:${IMAGE_TAG}
|
||||
192.168.0.110:5000/library/api:IMAGE_TAG_PLACEHOLDER=${HARBOR}/awoooi/api@${API_IMAGE_DIGEST}
|
||||
kustomize edit set image \
|
||||
192.168.0.110:5000/library/web:IMAGE_TAG_PLACEHOLDER=${HARBOR}/awoooi/web:${IMAGE_TAG}
|
||||
192.168.0.110:5000/library/web:IMAGE_TAG_PLACEHOLDER=${HARBOR}/awoooi/web@${WEB_IMAGE_DIGEST}
|
||||
cd ../..
|
||||
|
||||
# 2026-06-29 Codex: API deploy readback uses AWOOOI_BUILD_COMMIT_SHA
|
||||
|
||||
@@ -469,6 +469,27 @@ def test_cd_docker_build_and_push_steps_are_bounded_and_classified() -> None:
|
||||
assert marker in block
|
||||
|
||||
|
||||
def test_cd_deploys_api_and_web_by_verified_harbor_digest() -> None:
|
||||
text = _workflow_text()
|
||||
expected = [
|
||||
'"${{ env.HARBOR }}/awoooi/api:${{ github.sha }}"',
|
||||
'"${{ env.HARBOR }}/awoooi/web:${{ github.sha }}"',
|
||||
'echo "API_IMAGE_DIGEST=${API_IMAGE_DIGEST}" >> "${GITHUB_ENV}"',
|
||||
'echo "WEB_IMAGE_DIGEST=${WEB_IMAGE_DIGEST}" >> "${GITHUB_ENV}"',
|
||||
"api_harbor_digest_missing",
|
||||
"web_harbor_digest_missing",
|
||||
"${HARBOR}/awoooi/api@${API_IMAGE_DIGEST}",
|
||||
"${HARBOR}/awoooi/web@${WEB_IMAGE_DIGEST}",
|
||||
]
|
||||
for marker in expected:
|
||||
assert marker in text
|
||||
|
||||
deploy_block = text.split("- name: Deploy to K8s (ArgoCD GitOps)", 1)[1]
|
||||
deploy_block = deploy_block.split("- name: Apply Runtime Image Mirror Policy", 1)[0]
|
||||
assert "${HARBOR}/awoooi/api:${IMAGE_TAG}" not in deploy_block
|
||||
assert "${HARBOR}/awoooi/web:${IMAGE_TAG}" not in deploy_block
|
||||
|
||||
|
||||
def test_host_pressure_gate_ignores_stale_docker_stats_for_cpu_attribution() -> None:
|
||||
text = WAIT_HOST_PRESSURE.read_text(encoding="utf-8")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user