All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m17s
189 lines
8.6 KiB
YAML
189 lines
8.6 KiB
YAML
name: Build and Deploy
|
||
|
||
on:
|
||
push:
|
||
branches:
|
||
- master
|
||
- dev
|
||
|
||
jobs:
|
||
build-and-deploy:
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- name: Checkout
|
||
run: |
|
||
git clone --depth=1 --branch=${{ github.ref_name }} https://gitea.airlabs.art/${{ github.repository }}.git .
|
||
|
||
- name: Set environment by branch
|
||
run: |
|
||
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
|
||
BUILD_DATE=$(date +%Y%m%d)
|
||
|
||
if [[ "${{ github.ref_name }}" == "master" ]]; then
|
||
echo "IMAGE_TAG=prod-${BUILD_DATE}-${SHORT_SHA}" >> $GITHUB_ENV
|
||
echo "CR_ORG=prod" >> $GITHUB_ENV
|
||
echo "DEPLOY_ENV=production" >> $GITHUB_ENV
|
||
echo "DOMAIN_API=airflow-studio-api.airlabs.art" >> $GITHUB_ENV
|
||
echo "DOMAIN_WEB=airflow-studio.airlabs.art" >> $GITHUB_ENV
|
||
echo "REDIS_URL=redis://zyc:Zyc188208@redis-shzlf5t46gjvow7ua.redis.ivolces.com:6379/0" >> $GITHUB_ENV
|
||
elif [[ "${{ github.ref_name }}" == "dev" ]]; then
|
||
echo "IMAGE_TAG=dev-${BUILD_DATE}-${SHORT_SHA}" >> $GITHUB_ENV
|
||
echo "CR_ORG=dev" >> $GITHUB_ENV
|
||
echo "DEPLOY_ENV=development" >> $GITHUB_ENV
|
||
echo "DOMAIN_API=airflow-studio-api.test.airlabs.art" >> $GITHUB_ENV
|
||
echo "DOMAIN_WEB=airflow-studio.test.airlabs.art" >> $GITHUB_ENV
|
||
echo "REDIS_URL=redis://zyc:Zyc188208@redis-shzlsczo52dft8mia.redis.ivolces.com:6379/0" >> $GITHUB_ENV
|
||
fi
|
||
|
||
- name: Login to Volcano Engine CR
|
||
run: |
|
||
echo "${{ secrets.CR_PASSWORD }}" | docker login --username "${{ secrets.CR_USERNAME }}" --password-stdin ${{ secrets.CR_SERVER }}
|
||
|
||
- name: Build and Push Backend
|
||
id: build_backend
|
||
run: |
|
||
set -o pipefail
|
||
DOCKER_BUILDKIT=0 docker build \
|
||
--tag ${{ secrets.CR_SERVER }}/${{ env.CR_ORG }}/video-backend:${{ env.IMAGE_TAG }} \
|
||
--tag ${{ secrets.CR_SERVER }}/${{ env.CR_ORG }}/video-backend:latest \
|
||
./backend 2>&1 | tee /tmp/build.log
|
||
docker push ${{ secrets.CR_SERVER }}/${{ env.CR_ORG }}/video-backend:${{ env.IMAGE_TAG }}
|
||
docker push ${{ secrets.CR_SERVER }}/${{ env.CR_ORG }}/video-backend:latest
|
||
|
||
- name: Build and Push Web
|
||
id: build_web
|
||
run: |
|
||
set -o pipefail
|
||
DOCKER_BUILDKIT=0 docker build \
|
||
--tag ${{ secrets.CR_SERVER }}/${{ env.CR_ORG }}/video-web:${{ env.IMAGE_TAG }} \
|
||
--tag ${{ secrets.CR_SERVER }}/${{ env.CR_ORG }}/video-web:latest \
|
||
./web 2>&1 | tee -a /tmp/build.log
|
||
docker push ${{ secrets.CR_SERVER }}/${{ env.CR_ORG }}/video-web:${{ env.IMAGE_TAG }}
|
||
docker push ${{ secrets.CR_SERVER }}/${{ env.CR_ORG }}/video-web:latest
|
||
|
||
- name: Setup Kubectl
|
||
run: kubectl version --client
|
||
|
||
- name: Set kubeconfig
|
||
run: |
|
||
mkdir -p $HOME/.kube
|
||
if [[ "${{ github.ref_name }}" == "master" ]]; then
|
||
echo "${{ secrets.VOLCANO_PROD_KUBE_CONFIG }}" > $HOME/.kube/config
|
||
elif [[ "${{ github.ref_name }}" == "dev" ]]; then
|
||
echo "${{ secrets.VOLCANO_TEST_KUBE_CONFIG }}" > $HOME/.kube/config
|
||
fi
|
||
chmod 600 $HOME/.kube/config
|
||
|
||
- name: Deploy to K3s
|
||
id: deploy
|
||
run: |
|
||
echo "Environment: ${{ env.DEPLOY_ENV }}"
|
||
CR_IMAGE="${{ secrets.CR_SERVER }}/${{ env.CR_ORG }}"
|
||
|
||
# Replace image placeholders
|
||
sed -i "s|\${CI_REGISTRY_IMAGE}/video-backend:latest|${CR_IMAGE}/video-backend:${{ env.IMAGE_TAG }}|g" k8s/backend-deployment.yaml
|
||
sed -i "s|\${CI_REGISTRY_IMAGE}/video-backend:latest|${CR_IMAGE}/video-backend:${{ env.IMAGE_TAG }}|g" k8s/celery-deployment.yaml
|
||
sed -i "s|\${CI_REGISTRY_IMAGE}/video-web:latest|${CR_IMAGE}/video-web:${{ env.IMAGE_TAG }}|g" k8s/web-deployment.yaml
|
||
|
||
# Replace domain placeholders in ingress
|
||
sed -i "s|airflow-studio-api.airlabs.art|${{ env.DOMAIN_API }}|g" k8s/ingress.yaml
|
||
sed -i "s|airflow-studio.airlabs.art|${{ env.DOMAIN_WEB }}|g" k8s/ingress.yaml
|
||
|
||
# Replace DB config for production
|
||
if [[ "${{ env.DEPLOY_ENV }}" == "production" ]]; then
|
||
sed -i "s|mysql-8351f937d637.rds.ivolces.com|mysqld9bb4e81696d.rds.ivolces.com|g" k8s/backend-deployment.yaml
|
||
sed -i "s|mysql-8351f937d637.rds.ivolces.com|mysqld9bb4e81696d.rds.ivolces.com|g" k8s/celery-deployment.yaml
|
||
fi
|
||
|
||
# Replace CORS origin
|
||
sed -i "s|https://airflow-studio.airlabs.art|https://${{ env.DOMAIN_WEB }}|g" k8s/backend-deployment.yaml
|
||
|
||
# Replace Redis URL by environment
|
||
sed -i "s|redis://zyc:Zyc188208@redis-shzlsczo52dft8mia.redis.ivolces.com:6379/0|${{ env.REDIS_URL }}|g" k8s/backend-deployment.yaml
|
||
sed -i "s|redis://zyc:Zyc188208@redis-shzlsczo52dft8mia.redis.ivolces.com:6379/0|${{ env.REDIS_URL }}|g" k8s/celery-deployment.yaml
|
||
|
||
# Create/update secrets (业务密钥,DB 已写在 yaml 里)
|
||
kubectl create secret generic video-backend-secrets \
|
||
--from-literal=ARK_API_KEY='${{ secrets.ARK_API_KEY }}' \
|
||
--from-literal=TOS_ACCESS_KEY='${{ secrets.TOS_ACCESS_KEY }}' \
|
||
--from-literal=TOS_SECRET_KEY='${{ secrets.TOS_SECRET_KEY }}' \
|
||
--from-literal=DJANGO_SECRET_KEY='${{ secrets.DJANGO_SECRET_KEY }}' \
|
||
--from-literal=ALIYUN_SMS_ACCESS_KEY='${{ secrets.ALIYUN_SMS_ACCESS_KEY }}' \
|
||
--from-literal=ALIYUN_SMS_ACCESS_SECRET='${{ secrets.ALIYUN_SMS_ACCESS_SECRET }}' \
|
||
--dry-run=client -o yaml | kubectl apply -f -
|
||
|
||
# Apply manifests
|
||
set -o pipefail
|
||
{
|
||
kubectl apply -f k8s/backend-deployment.yaml
|
||
kubectl apply -f k8s/celery-deployment.yaml
|
||
kubectl apply -f k8s/web-deployment.yaml
|
||
kubectl apply -f k8s/ingress.yaml
|
||
|
||
# Preserve real client IP
|
||
kubectl patch svc traefik -n kube-system -p '{"spec":{"externalTrafficPolicy":"Local"}}' 2>/dev/null || true
|
||
|
||
kubectl rollout restart deployment/video-backend
|
||
kubectl rollout restart deployment/celery-worker
|
||
kubectl rollout restart deployment/video-web
|
||
} 2>&1 | tee /tmp/deploy.log
|
||
|
||
# ===== Log Center: failure reporting =====
|
||
- name: Report failure to Log Center
|
||
if: failure()
|
||
run: |
|
||
BUILD_LOG=""
|
||
DEPLOY_LOG=""
|
||
FAILED_STEP="unknown"
|
||
|
||
if [[ "${{ steps.build_backend.outcome }}" == "failure" || "${{ steps.build_web.outcome }}" == "failure" ]]; then
|
||
FAILED_STEP="build"
|
||
if [ -f /tmp/build.log ]; then
|
||
BUILD_LOG=$(tail -50 /tmp/build.log | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g')
|
||
fi
|
||
elif [[ "${{ steps.deploy.outcome }}" == "failure" ]]; then
|
||
FAILED_STEP="deploy"
|
||
if [ -f /tmp/deploy.log ]; then
|
||
DEPLOY_LOG=$(tail -50 /tmp/deploy.log | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g')
|
||
fi
|
||
fi
|
||
|
||
ERROR_LOG="${BUILD_LOG}${DEPLOY_LOG}"
|
||
if [ -z "$ERROR_LOG" ]; then
|
||
ERROR_LOG="No captured output. Check Gitea Actions UI for details."
|
||
fi
|
||
|
||
if [[ "$FAILED_STEP" == "deploy" ]]; then
|
||
SOURCE="deployment"
|
||
ERROR_TYPE="DeployError"
|
||
else
|
||
SOURCE="cicd"
|
||
ERROR_TYPE="DockerBuildError"
|
||
fi
|
||
|
||
curl -s -X POST "https://qiyuan-log-center-api.airlabs.art/api/v1/logs/report" \
|
||
-H "Content-Type: application/json" \
|
||
-d "{
|
||
\"project_id\": \"video_backend\",
|
||
\"environment\": \"${{ env.DEPLOY_ENV }}\",
|
||
\"level\": \"ERROR\",
|
||
\"source\": \"${SOURCE}\",
|
||
\"commit_hash\": \"${{ github.sha }}\",
|
||
\"repo_url\": \"https://gitea.airlabs.art/zyc/video-shuoshan.git\",
|
||
\"error\": {
|
||
\"type\": \"${ERROR_TYPE}\",
|
||
\"message\": \"[${FAILED_STEP}] Build and Deploy failed on branch ${{ github.ref_name }}\",
|
||
\"stack_trace\": [\"${ERROR_LOG}\"]
|
||
},
|
||
\"context\": {
|
||
\"job_name\": \"build-and-deploy\",
|
||
\"step_name\": \"${FAILED_STEP}\",
|
||
\"workflow\": \"${{ github.workflow }}\",
|
||
\"run_id\": \"${{ github.run_number }}\",
|
||
\"branch\": \"${{ github.ref_name }}\",
|
||
\"actor\": \"${{ github.actor }}\",
|
||
\"commit\": \"${{ github.sha }}\",
|
||
\"run_url\": \"https://gitea.airlabs.art/${{ github.repository }}/actions/runs/${{ github.run_number }}\"
|
||
}
|
||
}" || true
|