7 Commits

Author SHA1 Message Date
typist
1a2bdf5bd0 chore: update Dockerfile to install pnpm globally and modify Gitea CI/CD workflow to specify platform
All checks were successful
Build and Push Docker Image / build (push) Successful in 4m58s
2025-10-27 22:15:05 +08:00
typist
82e10b72c7 chore: update Gitea CI/CD workflow to use local caching for Docker builds
Some checks failed
Build and Push Docker Image / build (push) Failing after 3m35s
2025-10-27 22:06:20 +08:00
typist
1219deea89 chore: update Gitea CI/CD workflow to use secrets for Docker registry credentials
Some checks failed
Build and Push Docker Image / build (push) Failing after 5m38s
2025-10-27 20:50:10 +08:00
typist
b5b9d94119 chore: update Gitea CI/CD workflow to use new variable syntax for Docker registry and metadata
Some checks failed
Build and Push Docker Image / build (push) Failing after 4m3s
2025-10-27 20:33:06 +08:00
typist
d5959ca3c3 chore: update Gitea CI/CD workflow to conditionally enable 'latest' Docker image tag based on branch name
Some checks failed
Build and Push Docker Image / build (push) Failing after 2m1s
2025-10-27 20:20:59 +08:00
185ce1fac1 Merge pull request 'feat: add Docker support with multi-stage build and CI/CD workflow' (#2) from chore/build-and-push-docker-image into main
Reviewed-on: #2
2025-10-27 20:17:04 +08:00
typist
c11bb6d637 feat: add Docker support with multi-stage build and CI/CD workflow
- Introduced Dockerfile for multi-stage application build and deployment using Nginx.
- Added .dockerignore to exclude unnecessary files from the Docker context.
- Created nginx.conf for server configuration, including Gzip compression and SPA routing.
- Implemented Gitea CI/CD workflow for building and pushing Docker images on version tags.
2025-10-27 20:16:22 +08:00
4 changed files with 220 additions and 0 deletions

62
.dockerignore Normal file
View File

@@ -0,0 +1,62 @@
# 依赖
node_modules
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# 构建产物
dist
dist-ssr
*.local
# 编辑器
.vscode
.idea
*.swp
*.swo
*~
# 操作系统
.DS_Store
Thumbs.db
# Git
.git
.gitignore
.gitattributes
# CI/CD
.gitea
.github
.gitlab-ci.yml
# Docker
Dockerfile
.dockerignore
docker-compose.yaml
docker-compose.*.yaml
compose*yaml
# 测试
coverage
.nyc_output
# 环境变量
.env
.env.local
.env.*.local
# 日志
logs
*.log
# 临时文件
tmp
temp
# 文档
README.md
LICENSE
*.md

View File

@@ -0,0 +1,49 @@
name: Build and Push Docker Image
on:
push:
tags:
- 'v*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: 检出代码
uses: actions/checkout@v4
- name: 设置 Docker Buildx
uses: docker/setup-buildx-action@v3
- name: 登录到 Gitea Container Registry
uses: docker/login-action@v3
with:
registry: ${{ secrets.REGISTRY_ENDPOINT }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: 提取 Docker 元数据
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ secrets.REGISTRY_ENDPOINT }}/${{ github.repository_owner }}/litek
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=raw,value=latest,enable=${{ !contains(github.ref, 'snapshot') && !contains(github.ref, 'alpha') && !contains(github.ref, 'beta') }}
- name: 构建并推送 Docker 镜像
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=local,src=/cache
cache-to: type=local,dest=/cache,mode=max
# platforms: linux/amd64,linux/arm64
platforms: linux/amd64

36
Dockerfile Normal file
View File

@@ -0,0 +1,36 @@
# 第一阶段: 构建应用
FROM node:22-alpine AS builder
# 安装 pnpm
RUN npm install -g pnpm
# 设置工作目录
WORKDIR /app
# 复制依赖配置文件
COPY package.json pnpm-lock.yaml ./
# 安装依赖
RUN pnpm install --frozen-lockfile
# 复制源代码
COPY . .
# 构建应用
RUN pnpm build
# 第二阶段: 运行应用
FROM nginx:alpine
# 复制自定义 nginx 配置
COPY nginx.conf /etc/nginx/nginx.conf
# 从构建阶段复制构建产物
COPY --from=builder /app/dist /usr/share/nginx/html
# 暴露端口
EXPOSE 80
# 启动 nginx
CMD ["nginx", "-g", "daemon off;"]

73
nginx.conf Normal file
View File

@@ -0,0 +1,73 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# Gzip 压缩配置
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml+rss
application/rss+xml font/truetype font/opentype
application/vnd.ms-fontobject image/svg+xml;
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# SPA 路由支持 - 所有请求都返回 index.html
location / {
try_files $uri $uri/ /index.html;
}
# 健康检查端点
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# 错误页面
error_page 404 /index.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}