fix build
All checks were successful
Build and Deploy Backend / build-and-deploy (push) Successful in 1m20s
Build and Deploy Web / build-and-deploy (push) Successful in 59s

This commit is contained in:
zyc 2026-02-12 15:03:28 +08:00
parent 2a03be54a5
commit df9147a554
10 changed files with 361 additions and 0 deletions

View File

@ -0,0 +1,59 @@
name: Build and Deploy Backend
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
uses: docker/build-push-action@v4
with:
context: ./backend
push: true
provenance: false
tags: ${{ secrets.SWR_SERVER }}/${{ secrets.SWR_ORG }}/airlabs-manage-backend:latest
- name: Setup Kubectl
run: |
curl -LO "https://files.m.daocloud.io/dl.k8s.io/release/v1.28.2/bin/linux/amd64/kubectl"
chmod +x kubectl
mv kubectl /usr/local/bin/
- name: Deploy to K3s
uses: Azure/k8s-set-context@v3
with:
method: kubeconfig
kubeconfig: ${{ secrets.KUBE_CONFIG }}
- name: Update K8s Manifests
run: |
# 替换镜像地址
sed -i "s|\${CI_REGISTRY_IMAGE}/backend:latest|${{ secrets.SWR_SERVER }}/${{ secrets.SWR_ORG }}/airlabs-manage-backend:latest|g" k8s/backend-deployment-prod.yaml
# 应用配置
kubectl apply -f k8s/backend-deployment-prod.yaml
kubectl apply -f k8s/backend-ingress.yaml
kubectl rollout restart deployment/airlabs-manage-backend

View File

@ -0,0 +1,59 @@
name: Build and Deploy Web
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 Web
uses: docker/build-push-action@v4
with:
context: ./frontend
push: true
provenance: false
tags: ${{ secrets.SWR_SERVER }}/${{ secrets.SWR_ORG }}/airlabs-manage-web:latest
- name: Setup Kubectl
run: |
curl -LO "https://files.m.daocloud.io/dl.k8s.io/release/v1.28.2/bin/linux/amd64/kubectl"
chmod +x kubectl
mv kubectl /usr/local/bin/
- name: Deploy to K3s
uses: Azure/k8s-set-context@v3
with:
method: kubeconfig
kubeconfig: ${{ secrets.KUBE_CONFIG }}
- name: Update K8s Manifests
run: |
# 替换镜像地址
sed -i "s|\${CI_REGISTRY_IMAGE}/web:latest|${{ secrets.SWR_SERVER }}/${{ secrets.SWR_ORG }}/airlabs-manage-web:latest|g" k8s/web-deployment-prod.yaml
# 应用配置
kubectl apply -f k8s/web-deployment-prod.yaml
kubectl apply -f k8s/web-ingress.yaml
kubectl rollout restart deployment/airlabs-manage-web

9
.gitignore vendored
View File

@ -6,6 +6,15 @@ __pycache__/
# Node # Node
node_modules/ node_modules/
# Database
*.db
# Build output
frontend/dist/
# Environment
.env
# OS # OS
.DS_Store .DS_Store
Thumbs.db Thumbs.db

25
backend/Dockerfile Normal file
View File

@ -0,0 +1,25 @@
FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR /app
# Install system dependencies
RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list.d/debian.sources && \
apt-get update && apt-get install -y gcc && rm -rf /var/lib/apt/lists/*
# Install Python dependencies
COPY requirements.txt /app/
RUN pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ && \
pip install --upgrade pip && pip install -r requirements.txt
# Copy project
COPY . /app/
# Create data directory for SQLite persistence
RUN mkdir -p /app/data
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

23
frontend/Dockerfile Normal file
View File

@ -0,0 +1,23 @@
# Build stage
FROM node:20-alpine AS build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# Production stage
FROM nginx:stable-alpine AS production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

32
frontend/nginx.conf Normal file
View File

@ -0,0 +1,32 @@
server {
listen 80;
server_name localhost;
# API 代理到后端服务K8s 内部通信)
location /api {
proxy_pass http://airlabs-manage-backend:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
root /usr/share/nginx/html;
index index.html index.htm;
# SPA 路由刷新 404 的关键配置
try_files $uri $uri/ /index.html;
}
# 静态资源缓存
location /assets/ {
root /usr/share/nginx/html;
expires 7d;
add_header Cache-Control "public";
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

View File

@ -0,0 +1,67 @@
# SQLite 持久化存储
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: airlabs-manage-sqlite-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: airlabs-manage-backend
labels:
app: airlabs-manage-backend
spec:
replicas: 1
selector:
matchLabels:
app: airlabs-manage-backend
template:
metadata:
labels:
app: airlabs-manage-backend
spec:
containers:
- name: airlabs-manage-backend
image: ${CI_REGISTRY_IMAGE}/backend:latest
imagePullPolicy: Always
ports:
- containerPort: 8000
env:
# SQLite 存储在持久卷中
- name: DATABASE_URL
value: "sqlite:////app/data/airlabs.db"
# 生产环境 JWT 密钥(部署前请修改)
- name: SECRET_KEY
value: "Ui5-xEvtAhKRDtlXKzDfd7TElsVZFUhakff0qcjn8jU"
volumeMounts:
- name: sqlite-data
mountPath: /app/data
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
volumes:
- name: sqlite-data
persistentVolumeClaim:
claimName: airlabs-manage-sqlite-data
---
apiVersion: v1
kind: Service
metadata:
name: airlabs-manage-backend
spec:
selector:
app: airlabs-manage-backend
ports:
- protocol: TCP
port: 8000
targetPort: 8000

23
k8s/backend-ingress.yaml Normal file
View File

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

View File

@ -0,0 +1,41 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: airlabs-manage-web
labels:
app: airlabs-manage-web
spec:
replicas: 1
selector:
matchLabels:
app: airlabs-manage-web
template:
metadata:
labels:
app: airlabs-manage-web
spec:
containers:
- name: airlabs-manage-web
image: ${CI_REGISTRY_IMAGE}/web:latest
imagePullPolicy: Always
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: airlabs-manage-web
spec:
selector:
app: airlabs-manage-web
ports:
- protocol: TCP
port: 80
targetPort: 80

23
k8s/web-ingress.yaml Normal file
View File

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