diff --git a/Jenkinsfile.pjt b/Jenkinsfile.pjt index 6d44fa7..0785569 100644 --- a/Jenkinsfile.pjt +++ b/Jenkinsfile.pjt @@ -100,17 +100,14 @@ pipeline { sh ''' set -e - echo "[1/4] Remove pushed image from Jenkins" + echo "[1/3] Remove pushed image from Jenkins" docker rmi ${REGISTRY_HOST}/${IMAGE_REPO}:${IMAGE_TAG} 2>/dev/null || true - echo "[2/4] Remove dangling images" + echo "[2/3] Remove dangling images" docker image prune -f - echo "[3/4] Remove old build cache (safe-ish)" - # 빌드 캐시만 정리: 다른 컨테이너/볼륨에는 영향 적음 + echo "[3/3] Remove old build cache (safe-ish)" docker builder prune -f || true - - echo "[4/4] Skip docker system prune --volumes (too aggressive on shared nodes)" ''' } } @@ -241,100 +238,69 @@ pipeline { stage('12) Registry cleanup (keep last 5 + protect running)') { steps { - sshagent(['ssh-pjt']) { - sh ''' - set -e - ssh -p ${SSH_PORT} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ - ${SSH_USER}@${SSH_HOST} \ - 'set -e + withCredentials([usernamePassword( + credentialsId: DOCKER_CRED, + usernameVariable: 'DOCKER_USER', + passwordVariable: 'DOCKER_PASS' + )]) { + sshagent(['ssh-pjt']) { + sh ''' + set -e + ssh -p ${SSH_PORT} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ + ${SSH_USER}@${SSH_HOST} \ + 'set -e + REGISTRY_URL="https://${REGISTRY_HOST}" + REPO="${IMAGE_REPO}" + KEEP=5 + AUTH="'${DOCKER_USER}':'${DOCKER_PASS}'" - REGISTRY_URL="https://'${REGISTRY_HOST}'" # 예: https://registry.pjt.kr - REPO="'${IMAGE_REPO}'" # 예: alist/api - KEEP=5 + command -v jq >/dev/null 2>&1 || (sudo apt-get update -y && sudo apt-get install -y jq) - # (옵션) Basic Auth 쓰면 아래 활성화하고 curl에 -u "$AUTH" 추가 - # AUTH="user:pass" + echo "[1/5] Collect running tags to protect" + RUNNING_TAGS=$(docker ps --format "{{.Image}}" | \ + grep -E "^${REGISTRY_HOST}/${IMAGE_REPO}:" | \ + awk -F: "{print \\$2}" | sort -u || true) - echo "[0/5] Ensure jq exists" - if ! command -v jq >/dev/null 2>&1; then - sudo apt-get update -y - sudo apt-get install -y jq - fi + echo "[2/5] Fetch tags from registry" + TAGS=$(curl -fsS -u "$AUTH" "$REGISTRY_URL/v2/$REPO/tags/list" | jq -r ".tags[]?" || true) - echo "[1/5] Collect running tags to protect" - # 현재 서버에서 실행 중인 컨테이너가 사용하는 해당 레포 이미지 태그만 추출 - RUNNING_TAGS=$(docker ps --format "{{.Image}}" | \ - grep -E "^'${REGISTRY_HOST}'/'${IMAGE_REPO}':" | \ - awk -F: "{print \\$2}" | sort -u || true) + [ -z "$TAGS" ] && { echo "No tags found. Skip."; exit 0; } - if [ -n "$RUNNING_TAGS" ]; then - echo "Running tags (protected):" - echo "$RUNNING_TAGS" | sed "s/^/ - /" - else - echo "No running tags found for ${REGISTRY_HOST}/${IMAGE_REPO} (ok)" - fi + echo "[3/5] Sort tags desc" + SORTED=$(echo "$TAGS" | sort -r) + KEEP_TAGS=$(echo "$SORTED" | head -n $KEEP) + DEL_CANDIDATES=$(echo "$SORTED" | tail -n +$((KEEP+1))) - echo "[2/5] Fetch tags from registry: $REPO" - TAGS=$(curl -fsS "$REGISTRY_URL/v2/$REPO/tags/list" | jq -r ".tags[]?" || true) - # Basic Auth 쓰면 위 curl을 아래로 바꿔: - # TAGS=$(curl -fsS -u "$AUTH" "$REGISTRY_URL/v2/$REPO/tags/list" | jq -r ".tags[]?" || true) + echo "Keep tags:" + echo "$KEEP_TAGS" | sed "s/^/ - /" - if [ -z "$TAGS" ]; then - echo "No tags found in registry. Skip." - exit 0 - fi + echo "[4/5] Delete old tags except running tags" + for TAG in $DEL_CANDIDATES; do + if [ -n "$RUNNING_TAGS" ] && echo "$RUNNING_TAGS" | grep -qx "$TAG"; then + echo "Skip running tag: $REPO:$TAG" + continue + fi - echo "[3/5] Sort tags desc (tag must be sortable for 'latest' semantics)" - SORTED=$(echo "$TAGS" | sort -r) + DIGEST=$(curl -fsSI -u "$AUTH" \ + -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \ + "$REGISTRY_URL/v2/$REPO/manifests/$TAG" \ + | awk -F": " "/Docker-Content-Digest/ {print \\$2}" | tr -d "\\r") - KEEP_TAGS=$(echo "$SORTED" | head -n $KEEP) - DEL_CANDIDATES=$(echo "$SORTED" | tail -n +$((KEEP+1))) + [ -z "$DIGEST" ] && { echo "digest not found. skip $TAG"; continue; } - echo "Keep tags (latest $KEEP):" - echo "$KEEP_TAGS" | sed "s/^/ - /" + curl -fsS -u "$AUTH" -X DELETE "$REGISTRY_URL/v2/$REPO/manifests/$DIGEST" || true + done - echo "[4/5] Delete old tags except protected running tags" - for TAG in $DEL_CANDIDATES; do - # 실행 중 태그는 무조건 스킵 - if [ -n "$RUNNING_TAGS" ] && echo "$RUNNING_TAGS" | grep -qx "$TAG"; then - echo "Skip running tag: $REPO:$TAG" - continue - fi + echo "[5/5] Garbage collect" + docker exec registry registry garbage-collect /etc/docker/registry/config.yml - echo "Deleting $REPO:$TAG" - - DIGEST=$(curl -fsSI \ - -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \ - "$REGISTRY_URL/v2/$REPO/manifests/$TAG" \ - | awk -F": " "/Docker-Content-Digest/ {print \\$2}" | tr -d "\\r") - - # Basic Auth 쓰면 위 curl을 아래로 바꿔: - # DIGEST=$(curl -fsSI -u "$AUTH" \ - # -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \ - # "$REGISTRY_URL/v2/$REPO/manifests/$TAG" \ - # | awk -F": " "/Docker-Content-Digest/ {print \\$2}" | tr -d "\\r") - - if [ -z "$DIGEST" ]; then - echo " digest not found. skip $TAG" - continue - fi - - curl -fsS -X DELETE "$REGISTRY_URL/v2/$REPO/manifests/$DIGEST" || true - # Basic Auth 쓰면: - # curl -fsS -u "$AUTH" -X DELETE "$REGISTRY_URL/v2/$REPO/manifests/$DIGEST" || true - done - - echo "[5/5] Garbage collect (reclaim disk space)" - # push가 진행 중이면 위험할 수 있으니, 배포 성공 후 마지막 단계에서만 실행 추천 - docker exec registry registry garbage-collect /etc/docker/registry/config.yml - - echo "Registry cleanup done." - ' - ''' + echo "Registry cleanup done." + ' + ''' + } } } } - } }