020-29876379

高端网站建设

## 一、背景与问题

 

本文以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 自动扩容有效规避了服务过载风险。