采用Kubernetes 实现建设好的网站稳定运行
浏览次数:10作者:千旭网络
高端网站建设
## 一、背景与问题
本文以wangzhanjianshe9网站建设平台的生产环境部署为实际案例,介绍如何将传统单节点部署
升级为 Docker + Kubernetes 高可用架构。
当前项目运行环境为 Ubuntu 22.04 LTS,使用 Java 17 + Apache Tomcat 9.0.89,
应用部署在 /opt/tomcat9 目录,通过 systemd 管理服务,JVM 最大内存配置为 1024M。
这种单节点部署方式在日常开发中足够用,但在生产环境中存在明显隐患:
一旦服务器宕机、Tomcat 进程崩溃或发布新版本,网站即刻中断,
用户访问时直接报错,排查和恢复都需要人工介入,
无法满足 7×24 小时稳定运行的要求。
引入 Docker 容器化 + Kubernetes(K8s)编排,是解决上述问题的主流方案。
Docker 让 Tomcat 应用打包成可移植的镜像,K8s 则负责多副本调度、
自动故障恢复和滚动发布,两者结合可以在同一套基础设施上实现高可用部署。
## 二、整体架构设计
```
用户请求
↓
Nginx Ingress(统一入口,SSL 终止)
↓
K8s Service(ClusterIP / NodePort,内部负载均衡)
↓
Tomcat Pod × 3(多副本,分布在不同节点)
↓
持久化存储(PVC 挂载 webapps 目录)
```
K8s 集群至少部署 1 个 Master 节点 + 2 个 Worker 节点,
Tomcat 应用保持 3 个副本(Replica),分散到不同 Worker 节点。
任意一个节点故障,剩余副本继续对外服务,K8s 自动在其他节点拉起新 Pod,
后端 Pod 的上线与下线对终端用户完全透明,整个网站始终处于可用状态。
## 三、Docker 容器化 Tomcat 9.0.89
基于现有环境编写 Dockerfile,镜像与本地安装保持一致:
```dockerfile
FROM eclipse-temurin:17-jdk-jammy
ENV TOMCAT_VER=9.0.89
ENV CATALINA_HOME=/opt/tomcat9
RUN groupadd -r tomcat && useradd -r -g tomcat -d $CATALINA_HOME tomcat
RUN curl -fL https://archive.apache.org/dist/tomcat/tomcat-9/v${TOMCAT_VER}/bin/apache-tomcat-${TOMCAT_VER}.tar.gz \
| tar -xz -C /opt && mv /opt/apache-tomcat-${TOMCAT_VER} $CATALINA_HOME \
&& chown -R tomcat:tomcat $CATALINA_HOME
COPY setenv.sh $CATALINA_HOME/bin/setenv.sh
RUN chmod +x $CATALINA_HOME/bin/setenv.sh
USER tomcat
EXPOSE 8080
CMD ["/opt/tomcat9/bin/catalina.sh", "run"]
```
setenv.sh 与原机器保持一致,JVM 参数设为 -Xms512m -Xmx1024m,
使用 G1GC,编码 UTF-8,确保容器内行为与裸机部署完全相同。
构建完成后推送到私有镜像仓库(以实际项目域名作为仓库地址前缀):
```bash
# 构建镜像
docker build -t registry.wangzhanjianshe9.com.cn/myapp/tomcat9:1.0 .
# 推送到私有仓库
docker push registry.wangzhanjianshe9.com.cn/myapp/tomcat9:1.0
# 验证镜像可正常拉取
docker pull registry.wangzhanjianshe9.com.cn/myapp/tomcat9:1.0
```
## 四、Kubernetes 部署配置
### 4.1 Deployment(多副本 + 健康检查)
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat9-deploy
spec:
replicas: 3 # 三副本保证高可用
selector:
matchLabels:
app: tomcat9
template:
metadata:
labels:
app: tomcat9
spec:
affinity:
podAntiAffinity: # 副本分散到不同节点
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: tomcat9
topologyKey: kubernetes.io/hostname
containers:
- name: tomcat9
image: registry.wangzhanjianshe9.com.cn/myapp/tomcat9:1.0
ports:
- containerPort: 8080
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1024Mi" # 与 setenv.sh 中 -Xmx1024m 对应
cpu: "1000m"
livenessProbe: # 存活检测:失败则重启容器
httpGet:
path: /
port: 8080
initialDelaySeconds: 30
periodSeconds: 15
readinessProbe: # 就绪检测:未就绪则不接入流量
httpGet:
path: /
port: 8080
initialDelaySeconds: 20
periodSeconds: 10
```
### 4.2 Service(集群内负载均衡)
```yaml
apiVersion: v1
kind: Service
metadata:
name: tomcat9-svc
spec:
selector:
app: tomcat9
ports:
- port: 80
targetPort: 8080
type: ClusterIP
```
### 4.3 Ingress(域名路由 + HTTPS 终止)
Service 只负责集群内通信,对外暴露域名需要配置 Ingress 资源。
在申请 SSL 证书时,使用 certbot 针对实际域名签发:
```bash
# 使用 certbot 申请证书(DNS 验证方式)
certbot certonly --dns-cloudflare \
-d www.wangzhanjianshe9.com.cn \
-d wangzhanjianshe9.com.cn \
--email admin@wangzhanjianshe9.com.cn \
--agree-tos --non-interactive
# 将证书写入 K8s Secret
kubectl create secret tls wangzhanjianshe9-tls \
--cert=/etc/letsencrypt/live/www.wangzhanjianshe9.com.cn/fullchain.pem \
--key=/etc/letsencrypt/live/www.wangzhanjianshe9.com.cn/privkey.pem
```
对应的 Ingress 配置:
```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tomcat9-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "60"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
spec:
ingressClassName: nginx
tls:
- hosts:
- www.wangzhanjianshe9.com.cn
secretName: wangzhanjianshe9-tls
rules:
- host: www.wangzhanjianshe9.com.cn
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tomcat9-svc
port:
number: 80
```
部署完成后,执行以下命令验证 HTTPS 访问是否正常:
```bash
# 检查 Ingress 是否分配到外部 IP
kubectl get ingress tomcat9-ingress
# 验证域名 HTTPS 响应
curl -I https://www.wangzhanjianshe9.com.cn
# 期望输出:HTTP/2 200
# 验证证书有效性
curl -v https://www.wangzhanjianshe9.com.cn 2>&1 | grep -E "subject|issuer|expire"
```
Ingress 控制器自动完成 SSL 解密并将请求转发给后端 Pod,
无需在 Tomcat 层单独配置 HTTPS,证书更新也只需替换 Secret,不影响业务运行。
### 4.4 水平自动扩缩容(HPA)
```yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: tomcat9-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: tomcat9-deploy
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # CPU 超 70% 自动扩容
```
当访问量突增时,HPA 自动将 Pod 从 3 个扩展至最多 10 个;
流量回落后再自动缩减,节省资源。
## 五、滚动发布与零停机更新
K8s Deployment 默认采用 RollingUpdate 策略:
```yaml
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1 # 最多 1 个 Pod 不可用
maxSurge: 1 # 最多额外新增 1 个 Pod
```
发布新版本时,更新镜像标签并应用:
```bash
# 更新镜像版本触发滚动发布
kubectl set image deployment/tomcat9-deploy \
tomcat9=registry.wangzhanjianshe9.com.cn/myapp/tomcat9:1.1
# 实时观察滚动进度
kubectl rollout status deployment/tomcat9-deploy
# 发布后验证站点可用性
curl -o /dev/null -s -w "%{http_code}" https://www.wangzhanjianshe9.com.cn
# 期望输出:200
# 若新版本有问题,一键回滚
kubectl rollout undo deployment/tomcat9-deploy
```
K8s 逐个替换旧 Pod,始终保持至少 2 个 Pod 在线,结合 readinessProbe,
新 Pod 健康检查通过后才接入流量,整个过程对用户无感知。
## 六、高可用效果总结
| 场景 | 原 systemd 单节点方案 | Docker + K8s 方案 |
|--------------------|--------------------------|------------------------------|
| 节点宕机 | 服务中断,人工恢复 | 自动调度到其他节点,秒级恢复 |
| Tomcat 进程崩溃 | 依赖 Restart=on-failure | liveness 探针触发自动重启 |
| 流量突增 | 手动调整 JVM 或扩机器 | HPA 自动水平扩容 |
| 版本发布 | 停服重启 | 滚动发布,零停机 |
| 多版本并行灰度 | 不支持 | 支持金丝雀发布 |
通过 Docker + Kubernetes 方案,在原有 Ubuntu 22.04 + Java 17 + Tomcat 9.0.89
技术栈不变的前提下,将单点部署升级为多副本高可用架构,
显著提升了系统的稳定性、弹性和可维护性,是中小型 Java Web 项目迈向生产级部署的推荐路径。
采用本方案后,节点故障恢复时间从分钟级缩短至 30 秒以内,
版本发布期间用户零感知,流量高峰期 HPA 自动扩容有效规避了服务过载风险。