跳到主要内容

Jenkins 与 K8s 发布

这套发布方式适合你现在描述的网络结构:

  1. Jenkins 构建 globi-website 镜像并推送到 Harbor。
  2. Jenkins 通过 SSH 登录 K3s Master,执行 kubectl apply 和滚动更新。
  3. K8s 通过 NodePort 对 VPN 内网暴露网站端口。
  4. 公网 VPS 与 K8s 在同一个 VPN 内,通过 Nginx 反向代理 NodePort,对外提供域名和 HTTPS。

推荐架构

Internet
|
v
Public Domain -> VPS Nginx (80/443)
|
| VPN
v
K3s Node VPN IP:30081 -> Service(NodePort) -> Deployment -> Nginx Container -> Docusaurus Static Files

这套方案的核心点是:

  • 公网流量只落在 VPS 上。
  • K3s 集群只需要在 VPN 内暴露 NodePort。
  • TLS 证书、域名和访问日志统一收敛在 VPS 上处理。

仓库内文件

  • Dockerfile: 多阶段构建 Docusaurus,并用 Nginx 托管静态文件。
  • nginx.conf: 容器内 Nginx 配置,负责静态站点服务和健康检查。
  • k8s/globi-website.yaml: K8s Deployment 与 NodePort Service。
  • Jenkinsfile: Jenkins 自动构建、推送和部署流水线。

Jenkins 准备

复用你现在 globi-server 的发布思路即可,至少需要这些 Jenkins 凭据:

  • harbor-robot-creds: Harbor 用户名密码。
  • homelab-chius: SSH 私钥,用于登录 K3s Master。

流水线里还提供了两个构建参数:

  • SITE_URL: 网站正式访问地址,例如 https://www.globi.lan.tamochi.cn
  • BASE_URL: 部署前缀,根路径部署就保持 /

如果网站挂在二级路径,比如 https://www.globi.lan.tamochi.cn/globi/,则:

  • SITE_URL=https://www.globi.lan.tamochi.cn
  • BASE_URL=/globi/

K8s 发布方式

网站通过 NodePort 暴露在 30081/TCP

手工发布时可以直接执行:

kubectl apply -f k8s/globi-website.yaml
kubectl set image deployment/globi-website-deployment \
globi-website=10.0.0.134/main/globi-website:<tag> \
-n default
kubectl rollout status deployment/globi-website-deployment -n default

如果你已经启用了 Jenkins,则正常情况不需要手工执行这些命令。

VPS 反向代理

VPS 上建议使用 Nginx 对外暴露域名,再通过 VPN 转发到 K3s 节点的 NodePort。

示例配置:

upstream globi_website_k8s {
server 10.0.0.190:30081;
keepalive 16;
}

server {
listen 80;
server_name www.globi.lan.tamochi.cn;

location / {
return 301 https://$host$request_uri;
}
}

server {
listen 443 ssl http2;
server_name www.globi.lan.tamochi.cn;

ssl_certificate /etc/letsencrypt/live/www.globi.lan.tamochi.cn/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.globi.lan.tamochi.cn/privkey.pem;

location / {
proxy_http_version 1.1;
proxy_pass http://globi_website_k8s;
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 https;
proxy_connect_timeout 5s;
proxy_read_timeout 60s;
}
}

如果你的 K3s 有多个可访问节点,可以把多个 VPN IP 都加进 upstream,让 VPS 侧做简单故障切换。

防火墙与网络要求

  • VPS 需要对公网开放 80/443
  • K3s 节点需要允许来自 VPS VPN 地址的 30081/TCP
  • 最好不要把 NodePort 直接暴露到公网,只对 VPN 网段放行。

验证链路

可以按这个顺序检查:

  1. kubectl get pods -n default -l app=globi-website
  2. kubectl get svc globi-website-service -n default
  3. 在 VPS 上执行 curl http://10.0.0.190:30081/healthz
  4. 在公网执行 curl -I https://www.globi.lan.tamochi.cn

如果第 3 步不通,先查 VPN 与 K3s 节点防火墙。 如果第 3 步通而第 4 步不通,重点查 VPS Nginx、证书和公网安全组。

为什么这里选 NodePort

因为你的公网入口已经确定放在 VPS,而不是直接放在 K8s Ingress 上。

在这个前提下,NodePort 的优点是:

  • 实现最直接,和你现有 globi-server 的发布方式一致。
  • VPS 不需要加入 K8s 集群,只要能通过 VPN 打到节点端口即可。
  • Jenkins 侧只需要更新镜像和 K8s 清单,不需要额外接入外部 LB。

后面如果你想把入口完全迁到集群内部,再考虑 Ingress Controller 或 LoadBalancer 会更合适。