Add K8s
Some checks failed
Build and Deploy / build-and-deploy (push) Failing after 1m11s

This commit is contained in:
zyc 2026-03-20 18:35:15 +08:00
parent cbc19a6d9e
commit cc8a91995d
6 changed files with 334 additions and 4 deletions

View File

@ -0,0 +1,140 @@
name: Build and Deploy
on:
push:
branches:
- main
- master
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
with:
config-inline: |
[registry."docker.io"]
mirrors = ["https://docker.m.daocloud.io", "https://docker.1panel.live", "https://hub.rat.dev"]
- name: Login to Huawei Cloud SWR
uses: docker/login-action@v2
with:
registry: ${{ secrets.SWR_SERVER }}
username: ${{ secrets.SWR_USERNAME }}
password: ${{ secrets.SWR_PASSWORD }}
- name: Build and Push Backend
id: build_backend
run: |
set -o pipefail
docker buildx build \
--push \
--provenance=false \
--tag ${{ secrets.SWR_SERVER }}/${{ secrets.SWR_ORG }}/airgate-backend:latest \
./backend 2>&1 | tee /tmp/build.log
- name: Build and Push Web
id: build_web
run: |
set -o pipefail
docker buildx build \
--push \
--provenance=false \
--tag ${{ secrets.SWR_SERVER }}/${{ secrets.SWR_ORG }}/airgate-web:latest \
./frontend 2>&1 | tee -a /tmp/build.log
- name: Setup SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.K3S_SSH_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H ${{ secrets.K3S_HOST }} >> ~/.ssh/known_hosts 2>/dev/null
- name: Deploy to K3s via SSH
id: deploy
run: |
SWR_IMAGE="${{ secrets.SWR_SERVER }}/${{ secrets.SWR_ORG }}"
# Replace image placeholders in yaml files
sed -i "s|\${CI_REGISTRY_IMAGE}/airgate-backend:latest|${SWR_IMAGE}/airgate-backend:latest|g" k8s/backend-deployment.yaml
sed -i "s|\${CI_REGISTRY_IMAGE}/airgate-web:latest|${SWR_IMAGE}/airgate-web:latest|g" k8s/web-deployment.yaml
# Copy k8s manifests to server
scp -o StrictHostKeyChecking=no k8s/backend-deployment.yaml k8s/web-deployment.yaml k8s/ingress.yaml root@${{ secrets.K3S_HOST }}:/tmp/
# Create/update secrets and apply manifests on server
set -o pipefail
ssh -o StrictHostKeyChecking=no root@${{ secrets.K3S_HOST }} << ENDSSH
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
kubectl apply -f /tmp/backend-deployment.yaml
kubectl apply -f /tmp/web-deployment.yaml
kubectl apply -f /tmp/ingress.yaml
kubectl rollout restart deployment/airgate-backend
kubectl rollout restart deployment/airgate-web
rm -f /tmp/backend-deployment.yaml /tmp/web-deployment.yaml /tmp/ingress.yaml
ENDSSH
# ===== 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\": \"airgate\",
\"environment\": \"${{ github.ref_name }}\",
\"level\": \"ERROR\",
\"source\": \"${SOURCE}\",
\"commit_hash\": \"${{ github.sha }}\",
\"repo_url\": \"${{ github.server_url }}/${{ github.repository }}\",
\"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\": \"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_number }}\"
}
}" || true

View File

@ -1,7 +1,7 @@
version: '3.8'
services:
backend:
airgate-backend:
build: ./backend
ports:
- "8101:8100"
@ -15,12 +15,12 @@ services:
- backend-data:/app/data
restart: unless-stopped
frontend:
airgate-web:
build: ./frontend
ports:
- "5174:80"
depends_on:
- backend
- airgate-backend
restart: unless-stopped
volumes:

View File

@ -5,7 +5,7 @@ server {
index index.html;
location /api/ {
proxy_pass http://backend:8100;
proxy_pass http://airgate-backend:8100;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

View File

@ -0,0 +1,97 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: airgate-backend
labels:
app: airgate-backend
spec:
replicas: 1
selector:
matchLabels:
app: airgate-backend
template:
metadata:
labels:
app: airgate-backend
spec:
imagePullSecrets:
- name: swr-secret
containers:
- name: airgate-backend
image: ${CI_REGISTRY_IMAGE}/airgate-backend:latest
imagePullPolicy: Always
ports:
- containerPort: 8100
env:
- name: DJANGO_DEBUG
value: "False"
- name: DJANGO_ALLOWED_HOSTS
value: "*"
- name: DJANGO_SECRET_KEY
value: "HYsUppcrbCq05fEMzXfokwC8ge9CF3mV7auoSqlCbCakwC8t7lVrYG_pfixA6CHrCJc"
- name: DB_DIR
value: "/app/data"
# CORS
- name: CORS_ALLOWED_ORIGINS
value: "https://airgate.airlabs.art"
- name: AIRGATE_ENCRYPTION_KEY
value: "8By6udk4wn4VUQeHl_zvr8l6ZBEz77HKs_JkhwiC7FQ="
volumeMounts:
- name: sqlite-data
mountPath: /app/data
livenessProbe:
httpGet:
path: /healthz/
port: 8100
httpHeaders:
- name: Host
value: localhost
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /healthz/
port: 8100
httpHeaders:
- name: Host
value: localhost
initialDelaySeconds: 15
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "1024Mi"
cpu: "1000m"
volumes:
- name: sqlite-data
persistentVolumeClaim:
claimName: airgate-sqlite-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: airgate-sqlite-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
name: airgate-backend
spec:
selector:
app: airgate-backend
ports:
- protocol: TCP
port: 8100
targetPort: 8100

34
k8s/ingress.yaml Normal file
View File

@ -0,0 +1,34 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: airgate-ingress
annotations:
kubernetes.io/ingress.class: "traefik"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- airgate-api.airlabs.art
- airgate.airlabs.art
secretName: airgate-tls
rules:
- host: airgate-api.airlabs.art
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: airgate-backend
port:
number: 8100
- host: airgate.airlabs.art
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: airgate-web
port:
number: 80

59
k8s/web-deployment.yaml Normal file
View File

@ -0,0 +1,59 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: airgate-web
labels:
app: airgate-web
spec:
replicas: 1
selector:
matchLabels:
app: airgate-web
template:
metadata:
labels:
app: airgate-web
spec:
imagePullSecrets:
- name: swr-secret
containers:
- name: airgate-web
image: ${CI_REGISTRY_IMAGE}/airgate-web:latest
imagePullPolicy: Always
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "256Mi"
cpu: "250m"
---
apiVersion: v1
kind: Service
metadata:
name: airgate-web
spec:
selector:
app: airgate-web
ports:
- protocol: TCP
port: 80
targetPort: 80