域名部署实战:docs.ljdou.cn
本文完整记录 docs.ljdou.cn 技术文档站从零到可访问的部署过程,作为静态站点接入 Traefik 的标准范例。
目标链路
GitHub 源码 → VitePress 构建 → 静态文件 → Nginx 容器 → K8s Service/Endpoints → Ingress → Traefik → docs.ljdou.cn目录结构
服务器统一目录:
/www/server/ljdou-docs/
├── repo -> /www/server/go_project/ljdou-docs # 源码(软链)
├── dist/ # 生产静态文件
├── releases/ # 版本回滚预留
├── nginx.conf # Nginx 配置
├── k8s/ # K8s 资源清单
│ ├── service.yaml / endpoints.yaml / ingress.yaml
│ ├── clusterissuer.yaml
│ └── middleware-https-redirect.yaml
└── .deploy/ # CI 部署密钥1. 构建 VitePress
bash
cd /www/server/go_project/ljdou-docs
npm ci
npm run docs:build # 产物在 docs/.vitepress/dist/public 目录位置
VitePress 的 public/ 必须放在 docs/public/(与 docs/.vitepress/ 同级),放在仓库根目录不会被拷贝到产物,导致 favicon/logo 丢失。
2. Nginx 容器
nginx.conf(注意 cleanUrls 的处理):
nginx
server {
listen 3001;
server_name _;
root /usr/share/nginx/html;
index index.html;
location / {
# VitePress cleanUrls:
# /roadmap → /roadmap.html
# /bigdata/ → /bigdata/index.html
try_files $uri $uri.html $uri/ =404;
}
error_page 404 =404 /404.html;
location = /404.html { internal; }
location /assets/ {
expires 7d;
add_header Cache-Control "public, immutable";
}
}启动容器(不对外发布端口,只走 Traefik):
bash
docker run -d --name ljdou-docs \
--network ljdou-home_default \
--restart unless-stopped \
-v /www/server/ljdou-docs/dist:/usr/share/nginx/html:ro \
-v /www/server/ljdou-docs/nginx.conf:/etc/nginx/conf.d/default.conf:ro \
nginx:alpine3. K8s Service + Endpoints
Docker 容器不在 K8s 管理内,通过无头 Service + 手工 Endpoints 桥接:
yaml
# service.yaml —— clusterIP: None 表示无头服务
apiVersion: v1
kind: Service
metadata:
name: ljdou-docs
namespace: default
spec:
clusterIP: None
ports:
- name: http
port: 3001
targetPort: 3001
---
# endpoints.yaml —— 指向 Docker 容器 IP
apiVersion: v1
kind: Endpoints
metadata:
name: ljdou-docs
namespace: default
subsets:
- addresses:
- ip: 172.19.0.6 # docker inspect 获取容器 IP
ports:
- name: http
port: 3001Endpoints 的坑
Docker 容器重启可能导致 IP 变化 → Endpoints 失效 → 502。务必固定容器 IP(见安全加固篇)。
4. Ingress
见 Traefik 路由与 Middleware 中的完整示例,核心是 host: docs.ljdou.cn + TLS 注解。
5. 验证
bash
# 容器直连
curl http://172.19.0.6:3001/roadmap # 200(cleanUrls 生效)
# 域名访问
curl -I http://docs.ljdou.cn/ # 301 → https
curl -I https://docs.ljdou.cn/ # 200
# 证书信息
echo | openssl s_client -connect docs.ljdou.cn:443 -servername docs.ljdou.cn 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates关键经验
- 容器不发布宿主端口:Traefik 通过桥接网络 IP 直接访问容器,无需
-p映射公网端口 - rsync 部署注意 bind mount:
rsync --delete只删目录内文件、不删目录本身,不会破坏挂载 - 先验容器后建路由:每次改动后先
curl容器 IP,再验证域名,逐层排查