feat: 新增前端自动化部署
This commit is contained in:
1 parent
fb0121cced
commit
8741f019fa
5 files changed
+1566
-380
No files matched your search
@@ -0,0 +1,96 @@
|
|||||||
|
name: Deploy Frontend
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
paths:
|
||||||
|
- 'frontend/**'
|
||||||
|
- 'Dockerfile.frontend'
|
||||||
|
- 'nginx.conf'
|
||||||
|
- '.github/workflows/deploy_frontend.yml'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE_NAME: license-manager-frontend
|
||||||
|
CONTAINER_NAME: license-manager-frontend
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Build Docker image
|
||||||
|
run: |
|
||||||
|
docker build -f Dockerfile.frontend -t ${{ env.IMAGE_NAME }}:latest .
|
||||||
|
docker save ${{ env.IMAGE_NAME }}:latest > frontend-image.tar
|
||||||
|
|
||||||
|
- name: Copy files to server
|
||||||
|
uses: appleboy/scp-action@v0.1.7
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST_1 }}
|
||||||
|
username: root
|
||||||
|
password: ${{ secrets.PASS_1 }}
|
||||||
|
port: 22
|
||||||
|
source: "frontend-image.tar"
|
||||||
|
target: "/opt/license-manager/"
|
||||||
|
|
||||||
|
- name: Deploy to server
|
||||||
|
uses: appleboy/ssh-action@v1.0.3
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST_1 }}
|
||||||
|
username: root
|
||||||
|
password: ${{ secrets.PASS_1 }}
|
||||||
|
port: 22
|
||||||
|
script: |
|
||||||
|
cd /opt/license-manager
|
||||||
|
|
||||||
|
# Stop and remove existing container
|
||||||
|
docker stop ${{ env.CONTAINER_NAME }} || true
|
||||||
|
docker rm ${{ env.CONTAINER_NAME }} || true
|
||||||
|
|
||||||
|
# Load new image
|
||||||
|
docker load < frontend-image.tar
|
||||||
|
|
||||||
|
# Remove old image
|
||||||
|
docker rmi ${{ env.IMAGE_NAME }}:old || true
|
||||||
|
docker tag ${{ env.IMAGE_NAME }}:latest ${{ env.IMAGE_NAME }}:old || true
|
||||||
|
|
||||||
|
# Run new container
|
||||||
|
docker run -d \
|
||||||
|
--name ${{ env.CONTAINER_NAME }} \
|
||||||
|
--restart unless-stopped \
|
||||||
|
-p 18080:80 \
|
||||||
|
--add-host host.docker.internal:host-gateway \
|
||||||
|
${{ env.IMAGE_NAME }}:latest
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -f frontend-image.tar
|
||||||
|
docker image prune -f
|
||||||
|
|
||||||
|
# Check deployment status
|
||||||
|
sleep 5
|
||||||
|
if docker ps | grep -q ${{ env.CONTAINER_NAME }}; then
|
||||||
|
echo "✅ Frontend deployment successful! Container is running."
|
||||||
|
docker logs --tail 10 ${{ env.CONTAINER_NAME }}
|
||||||
|
else
|
||||||
|
echo "❌ Frontend deployment failed! Container is not running."
|
||||||
|
docker logs ${{ env.CONTAINER_NAME }}
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Health check
|
||||||
|
run: |
|
||||||
|
sleep 10
|
||||||
|
response=$(curl -s -o /dev/null -w "%{http_code}" http://${{ secrets.HOST_1 }}:18080/ || echo "000")
|
||||||
|
if [ "$response" = "200" ]; then
|
||||||
|
echo "✅ Frontend health check passed! Service is responding."
|
||||||
|
else
|
||||||
|
echo "⚠️ Frontend health check returned status: $response"
|
||||||
|
echo "Service may still be starting up..."
|
||||||
|
fi
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
# 前端自动化部署
|
||||||
|
|
||||||
|
基于Docker的前端自动化部署方案,使用GitHub Actions实现CI/CD。
|
||||||
|
|
||||||
|
## 部署特点
|
||||||
|
|
||||||
|
- 🐳 Docker容器化部署
|
||||||
|
- 🚀 自动构建和部署
|
||||||
|
- 🔄 零停机更新
|
||||||
|
- 🌐 内置Nginx服务器
|
||||||
|
- 📱 支持Vue Router history模式
|
||||||
|
- 🔗 API代理到后端服务
|
||||||
|
|
||||||
|
## 配置要求
|
||||||
|
|
||||||
|
### GitHub Secrets
|
||||||
|
在GitHub仓库设置以下Secrets:
|
||||||
|
- `HOST_1`: 服务器IP地址
|
||||||
|
- `PASS_1`: 服务器root密码
|
||||||
|
|
||||||
|
### 服务器要求
|
||||||
|
- 安装Docker
|
||||||
|
|
||||||
|
## 部署流程
|
||||||
|
|
||||||
|
1. 推送代码到main分支(前端相关文件有变更时)
|
||||||
|
2. GitHub Actions自动触发
|
||||||
|
3. 构建Docker镜像(Vue3 + Nginx)
|
||||||
|
4. 上传镜像到服务器
|
||||||
|
5. 停止旧容器并启动新容器
|
||||||
|
6. 健康检查
|
||||||
|
|
||||||
|
## 访问地址
|
||||||
|
|
||||||
|
部署完成后,前端服务将在以下地址提供:
|
||||||
|
- **前端地址**: http://服务器IP:18080
|
||||||
|
- **API代理**: 前端的 `/api/*` 请求会代理到后端 `http://localhost:18888/`
|
||||||
|
|
||||||
|
## 手动触发
|
||||||
|
|
||||||
|
可以在GitHub Actions页面手动触发部署,无需推送代码。
|
||||||
|
|
||||||
|
## 监控和维护
|
||||||
|
|
||||||
|
### 查看容器状态
|
||||||
|
```bash
|
||||||
|
docker ps | grep license-manager-frontend
|
||||||
|
```
|
||||||
|
|
||||||
|
### 查看容器日志
|
||||||
|
```bash
|
||||||
|
docker logs license-manager-frontend
|
||||||
|
```
|
||||||
|
|
||||||
|
### 重启容器
|
||||||
|
```bash
|
||||||
|
docker restart license-manager-frontend
|
||||||
|
```
|
||||||
|
|
||||||
|
## 故障排除
|
||||||
|
|
||||||
|
1. **部署失败**: 检查GitHub Actions日志
|
||||||
|
2. **容器无法启动**: 检查Docker镜像和容器配置
|
||||||
|
3. **页面无法访问**: 检查服务器防火墙18080端口
|
||||||
|
4. **API请求失败**: 确认后端服务运行在18888端口
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# Multi-stage build for frontend
|
||||||
|
FROM node:18-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY frontend/package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
COPY frontend/ ./
|
||||||
|
RUN npm run prod
|
||||||
|
|
||||||
|
# Production stage with Nginx
|
||||||
|
FROM nginx:alpine
|
||||||
|
|
||||||
|
# Copy built assets
|
||||||
|
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||||
|
|
||||||
|
# Copy custom nginx configuration
|
||||||
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
# Create log directory
|
||||||
|
RUN mkdir -p /var/log/nginx
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||||
|
CMD curl -f http://localhost/ || exit 1
|
||||||
|
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
Generated
+1311
-380
File diff suppressed because it is too large.
Load diff
+64
@@ -0,0 +1,64 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
# Gzip compression
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_min_length 1024;
|
||||||
|
gzip_comp_level 6;
|
||||||
|
gzip_types
|
||||||
|
text/plain
|
||||||
|
text/css
|
||||||
|
text/xml
|
||||||
|
text/javascript
|
||||||
|
application/javascript
|
||||||
|
application/xml+rss
|
||||||
|
application/json
|
||||||
|
image/svg+xml;
|
||||||
|
|
||||||
|
# Security headers
|
||||||
|
add_header X-Frame-Options DENY;
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header Referrer-Policy "strict-origin-when-cross-origin";
|
||||||
|
|
||||||
|
# Handle Vue Router history mode
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cache static assets
|
||||||
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# API proxy to backend (if backend is on the same server)
|
||||||
|
location /api/ {
|
||||||
|
proxy_pass http://host.docker.internal:18888/;
|
||||||
|
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_connect_timeout 60s;
|
||||||
|
proxy_send_timeout 60s;
|
||||||
|
proxy_read_timeout 60s;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Disable access to hidden files
|
||||||
|
location ~ /\. {
|
||||||
|
deny all;
|
||||||
|
access_log off;
|
||||||
|
log_not_found off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Custom error pages
|
||||||
|
error_page 404 /index.html;
|
||||||
|
error_page 500 502 503 504 /index.html;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user