#!/usr/bin/env bash # ============================================================ # release.sh — 构建 + 推送 + 更新 K8s 清单为不可变 tag # ============================================================ # 为什么需要它: # 线上清单一直用 `lghost/lokistack:latest` + imagePullPolicy: Always。 # 这个组合的问题是**静默回滚**:任何一次构建(包括别人并行的、或几分钟前 # 基于旧代码启动的构建)都会覆盖 latest,节点重启后拉到的可能不是你以为的版本。 # 本项目已实际踩过:两个构建并行,后完成但代码更旧的把 latest 覆盖回去, # Pod 跑回旧镜像,刚验过的功能"莫名消失"。 # # 做法: # 1) 用 <版本>-<日期>-<短commit> 作为不可变 tag(同 commit 同代码 → 同 tag) # 2) 同时推 latest 供本地/开发使用(不用于生产清单) # 3) 把 kubernetes/deployment.yaml 的 image 改成不可变 tag # 4) 打印三方 digest 供核对(本地镜像 / Hub tag / Pod) # # 用法: # bash scripts/release.sh # 构建 + 推送 + 改清单 + 部署 # bash scripts/release.sh --no-deploy # 只构建/推送/改清单,不 apply # ============================================================ set -euo pipefail cd "$(dirname "$0")/.." IMAGE_REPO="${IMAGE_REPO:-lghost/lokistack}" VERSION="${VERSION:-2.0.0}" DEPLOY="${1:-}" SHORT_SHA=$(git rev-parse --short=8 HEAD 2>/dev/null || echo "nogit") DIRTY="" if ! git diff --quiet 2>/dev/null; then DIRTY="-dirty" echo "⚠️ 工作区有未提交改动,tag 会带 -dirty 标记(发布前建议先提交)" fi TAG="${VERSION}-$(date +%Y%m%d)-${SHORT_SHA}${DIRTY}" echo "==========================================" echo " 构建镜像: ${IMAGE_REPO}:${TAG}" echo "==========================================" docker build -t "${IMAGE_REPO}:${TAG}" -t "${IMAGE_REPO}:latest" . IMAGE_ID=$(docker images --format '{{.ID}}' "${IMAGE_REPO}:${TAG}" | head -1) echo "✅ 构建完成 $IMAGE_ID" echo "推送不可变 tag 与 latest..." docker push "${IMAGE_REPO}:${TAG}" | tail -1 docker push "${IMAGE_REPO}:latest" | tail -1 echo "更新 kubernetes/deployment.yaml → ${IMAGE_REPO}:${TAG}" # 只替换 image 行,pullPolicy 改成 IfNotPresent: # 不可变 tag 不需要每次强拉,节点上有缓存就直接用(也避免仓库抖动导致启动失败) sed -i "s|image: ${IMAGE_REPO}:.*|image: ${IMAGE_REPO}:${TAG}|" kubernetes/deployment.yaml sed -i "s|imagePullPolicy: Always|imagePullPolicy: IfNotPresent|" kubernetes/deployment.yaml if [ "${DEPLOY}" != "--no-deploy" ]; then export KUBECONFIG="${KUBECONFIG:-/root/.kube/config}" echo "应用清单..." kubectl apply -f kubernetes/deployment.yaml kubectl -n log rollout status deploy/lokistack --timeout=300s POD_DIGEST=$(kubectl -n log get po -l app=lokistack -o jsonpath='{.items[0].status.containerStatuses[0].imageID}' 2>/dev/null | sed 's/.*@//') echo "" echo "==========================================" echo " 部署完成,请核对三方 digest 一致:" echo " 清单 tag : ${IMAGE_REPO}:${TAG}" echo " Pod : ${POD_DIGEST:0:19}" echo "==========================================" echo "⚠️ 记得把 deployment.yaml 的变更一并提交,否则下次 apply 会退回旧 tag" fi echo "" echo "回滚方法:" echo " git log --oneline -- kubernetes/deployment.yaml # 找上一个 tag" echo " git checkout -- kubernetes/deployment.yaml && kubectl apply -f kubernetes/deployment.yaml"