Merge pull request 'fix: 修复 deploy 工作流缺少 Node.js 导致 checkout 失败的问题' #72
53
.gitea/workflows/deploy.yml
Normal file
53
.gitea/workflows/deploy.yml
Normal file
@@ -0,0 +1,53 @@
|
||||
name: Deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
# ---- PR 时:验证 Docker 镜像可构建 ----
|
||||
verify:
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: aliyun
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: "http://8.161.227.145:3000/huanghaosheng/checkout@releases/v4"
|
||||
|
||||
- name: Verify Frontend Build
|
||||
run: docker build -t camtalk-frontend-test ./frontend
|
||||
|
||||
- name: Verify Backend Build
|
||||
run: docker build -t camtalk-backend-test ./backend
|
||||
|
||||
- name: Cleanup
|
||||
run: |
|
||||
docker rmi camtalk-frontend-test camtalk-backend-test || true
|
||||
|
||||
# ---- push main 时:构建并部署 ----
|
||||
deploy:
|
||||
if: github.event_name == 'push'
|
||||
runs-on: aliyun
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: "http://8.161.227.145:3000/huanghaosheng/checkout@releases/v4"
|
||||
|
||||
- name: Build and Deploy
|
||||
run: |
|
||||
chmod +x deploy.sh
|
||||
./deploy.sh build
|
||||
./deploy.sh restart
|
||||
|
||||
- name: Health Check
|
||||
run: |
|
||||
for i in $(seq 1 10); do
|
||||
if curl -sf http://localhost/api/health > /dev/null 2>&1; then
|
||||
echo "服务启动成功"
|
||||
exit 0
|
||||
fi
|
||||
echo "等待服务启动... ($i/10)"
|
||||
sleep 3
|
||||
done
|
||||
echo "服务启动超时"
|
||||
exit 1
|
||||
27
backend/Dockerfile
Normal file
27
backend/Dockerfile
Normal file
@@ -0,0 +1,27 @@
|
||||
# ---- 构建阶段 ----
|
||||
FROM golang:1.26-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 先复制依赖清单,利用 Docker 缓存层
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
# 复制源码并构建
|
||||
COPY . .
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o /camtalk ./cmd/server
|
||||
|
||||
# ---- 运行阶段 ----
|
||||
FROM alpine:3.20
|
||||
|
||||
RUN apk add --no-cache ca-certificates tzdata
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 复制二进制和配置
|
||||
COPY --from=builder /camtalk .
|
||||
COPY config.yaml .
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
ENTRYPOINT ["./camtalk"]
|
||||
91
deploy.sh
Executable file
91
deploy.sh
Executable file
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# 颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
||||
|
||||
# 确保 .env 存在
|
||||
ensure_env() {
|
||||
if [ ! -f .env ]; then
|
||||
if [ -f .env.example ]; then
|
||||
warn ".env 文件不存在,从 .env.example 复制模板"
|
||||
cp .env.example .env
|
||||
warn "请编辑 .env 填入实际的 API Key,然后重新运行"
|
||||
exit 1
|
||||
else
|
||||
error ".env.example 也不存在,请手动创建 .env"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
cmd_build() {
|
||||
info "构建 Docker 镜像..."
|
||||
docker compose build
|
||||
info "构建完成"
|
||||
}
|
||||
|
||||
cmd_up() {
|
||||
ensure_env
|
||||
info "启动服务..."
|
||||
docker compose up -d
|
||||
info "服务已启动"
|
||||
info "前端: http://localhost"
|
||||
info "健康检查: http://localhost/api/health"
|
||||
}
|
||||
|
||||
cmd_down() {
|
||||
info "停止服务..."
|
||||
docker compose down
|
||||
info "服务已停止"
|
||||
}
|
||||
|
||||
cmd_restart() {
|
||||
info "重启服务..."
|
||||
cmd_down
|
||||
cmd_up
|
||||
}
|
||||
|
||||
cmd_logs() {
|
||||
docker compose logs -f "${@}"
|
||||
}
|
||||
|
||||
cmd_status() {
|
||||
docker compose ps
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
CamTalk 部署脚本
|
||||
|
||||
用法: $0 <命令>
|
||||
|
||||
命令:
|
||||
build 构建 Docker 镜像
|
||||
up 启动服务(后台运行)
|
||||
down 停止服务
|
||||
restart 重启服务
|
||||
logs 查看日志(可加服务名,如: $0 logs backend)
|
||||
status 查看服务状态
|
||||
EOF
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
build) cmd_build ;;
|
||||
up) cmd_up ;;
|
||||
down) cmd_down ;;
|
||||
restart) cmd_restart ;;
|
||||
logs) shift; cmd_logs "$@" ;;
|
||||
status) cmd_status ;;
|
||||
*) usage; exit 1 ;;
|
||||
esac
|
||||
30
docker-compose.yml
Normal file
30
docker-compose.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
services:
|
||||
frontend:
|
||||
build:
|
||||
context: ./frontend
|
||||
dockerfile: Dockerfile
|
||||
container_name: camtalk-frontend
|
||||
ports:
|
||||
- "80:80"
|
||||
depends_on:
|
||||
- backend
|
||||
networks:
|
||||
- camtalk-net
|
||||
restart: unless-stopped
|
||||
|
||||
backend:
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile
|
||||
container_name: camtalk-backend
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- APP_ENV=production
|
||||
networks:
|
||||
- camtalk-net
|
||||
restart: unless-stopped
|
||||
|
||||
networks:
|
||||
camtalk-net:
|
||||
driver: bridge
|
||||
25
frontend/Dockerfile
Normal file
25
frontend/Dockerfile
Normal file
@@ -0,0 +1,25 @@
|
||||
# ---- 构建阶段 ----
|
||||
FROM node:22-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 先复制依赖清单,利用 Docker 缓存层
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci
|
||||
|
||||
# 复制源码并构建
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
# ---- 运行阶段 ----
|
||||
FROM nginx:stable-alpine
|
||||
|
||||
# 复制 Nginx 配置
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# 复制构建产物
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
46
frontend/nginx.conf
Normal file
46
frontend/nginx.conf
Normal file
@@ -0,0 +1,46 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# 前端静态资源
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# REST API 反代
|
||||
location /api/ {
|
||||
proxy_pass http://backend:8080;
|
||||
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;
|
||||
}
|
||||
|
||||
# WebSocket 反代
|
||||
location /ws {
|
||||
proxy_pass http://backend:8080;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
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;
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 86400s;
|
||||
}
|
||||
|
||||
# 静态资源缓存
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 7d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# Gzip 压缩
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
gzip_min_length 256;
|
||||
}
|
||||
Reference in New Issue
Block a user