从实操到原理:一文搞懂 Docker、Tomcat 与 k8s 的关系(附踩坑指南 + 段子解疑)

发布于:2025-09-04 ⋅ 阅读:(17) ⋅ 点赞:(0)

目录

一、先分清:Docker、Tomcat、k8s 到底是 “干啥的”?

二、它们的 “合作关系”:从 Java 项目到集群部署的全流程

三、实际应用场景:什么时候该用谁?

1. 单独使用场景

2. 组合使用场景(最常见)

四、简单实操示例:手把手部署一个 Java 项目

1. 步骤 1:用 Docker 打包 Tomcat 镜像

2. 步骤 2:用 k8s 部署这个 Docker 镜像

五、常用使用方法:核心命令速查

1. Docker 核心命令

2. Tomcat 核心操作

3. k8s 核心命令

六、踩坑指南:常见问题 + 解决方法

1. Docker+Tomcat:访问项目 404

2. k8s:Pod 一直处于 Pending 状态

3. Tomcat:启动报错 “Address already in use”

七、段子解疑:抽象概念秒懂

1. 用 “小区物业” 理解 k8s 的 “编排”

2. 用 “外卖” 理解 Docker+Tomcat 的关系

3. 用 “奶茶店” 理解 k8s 的 “副本”

八、专业总结


大家好,我是做云原生运维的小大..刚入行时,我曾对着服务器上的 Docker 容器、Tomcat 进程和 k8s 控制台发懵:“为啥部署个 Java 项目,一会儿打包 Docker 镜像,一会儿启动 Tomcat,最后还要 k8s 来‘管闲事’?” 后来踩了无数坑才明白,这三者不是 “互斥选项”,而是从 “单机部署” 到 “集群运维” 的协同工具链。今天咱们就从定位、联系、实操到踩坑,一次性讲透,还会用段子帮你啃下抽象难点~

一、先分清:Docker、Tomcat、k8s 到底是 “干啥的”?

很多人混淆它们,核心是没搞懂各自的 “核心定位”—— 它们解决的是完全不同的问题,咱们用表格一目了然:

工具 核心定位 解决的核心痛点 角色类比
Docker 容器引擎(打包工具) 开发 / 测试 / 生产环境不一致(“我这能跑啊”) 外卖打包盒
Tomcat Java Web 服务器(运行环境) Java 项目无法直接运行,需依赖 Web 容器 外卖里的 “米饭”
k8s 容器编排平台(管理工具) 多容器集群的运维(启停 / 扩容 / 高可用) 小区物业

重点标显

  • Docker 不负责 “运行项目”,只负责 “把项目和运行环境打包成容器”;
  • Tomcat 不负责 “环境一致性”,只负责 “让 Java 项目在容器里跑起来”;
  • k8s 不负责 “打包或运行”,只负责 “管理一堆容器的生命周期”。

二、它们的 “合作关系”:从 Java 项目到集群部署的全流程

三者不是 “二选一”,而是 “流水线协作”,以部署一个 Spring MVC 项目为例,完整链路是这样的:

  1. 开发端:写好 Java 项目,打成 War 包(比如my-project.war);
  2. Docker 打包:写一个 Dockerfile,把 “Tomcat 镜像” 和 “War 包” 一起打包成新镜像(比如my-tomcat:v1)—— 相当于 “用外卖盒(Docker)装起米饭(Tomcat)和菜(Java 项目)”;
  3. k8s 部署:用 k8s 的 Deployment 配置,指定 “启动 3 个my-tomcat:v1容器副本”,并通过 Service 暴露访问端口 —— 相当于 “物业(k8s)安排 3 个‘打包好的外卖’(容器)上架,还贴上门牌号(Service)方便别人找到”;
  4. 用户访问:用户通过 k8s 的 Service 地址访问,请求会被分发到任意一个容器上,实现高可用。

重点标显

  • 没有 Docker:Tomcat 和项目在不同环境可能 “水土不服”(比如开发端 Tomcat 8,生产端 Tomcat 9);
  • 没有 Tomcat:Docker 容器里只有项目文件,Java 项目 “没地方跑”;
  • 没有 k8s:几十上百个 Docker 容器需要手动启停、监控,运维能累到 “脱发”。

三、实际应用场景:什么时候该用谁?

1. 单独使用场景

  • Docker:个人开发 / 小型项目的 “环境一致性” 需求。比如你本地开发用 Ubuntu,测试环境是 CentOS,用 Docker 打包后,测试端直接运行镜像,不用再装依赖;
  • Tomcat:单机部署 Java Web 项目。比如公司内部的 OA 系统,用户少、访问量低,直接在服务器上装 Tomcat,把 War 包扔到webapps目录就能跑;
  • k8s:微服务集群 / 高可用场景。比如电商的订单系统、支付系统,需要几十上百个容器,还要应对 “双 11” 的流量峰值,k8s 能自动扩容、故障恢复。

2. 组合使用场景(最常见)

  • Docker + Tomcat:中小型 Java 项目的 “跨环境部署”。比如把 Tomcat 和项目打包成镜像,部署到不同服务器,不用再手动配置 Tomcat;
  • Docker + Tomcat + k8s:大型微服务的 “集群运维”。比如某互联网公司的用户服务,用 k8s 部署 10 个 Tomcat 容器副本,通过 Service 负载均衡,当某个容器挂了,k8s 自动重启,流量无缝切换。

四、简单实操示例:手把手部署一个 Java 项目

咱们以 “用 Docker 打包 Tomcat+Java 项目,再用 k8s 管理” 为例,走一遍核心步骤(假设你已有 Java War 包my-project.war)。

1. 步骤 1:用 Docker 打包 Tomcat 镜像

创建Dockerfile(核心配置):

dockerfile

# 基础镜像:用官方Tomcat 8(避免环境差异)
FROM tomcat:8-jdk8

# 重点:删除Tomcat默认的ROOT项目(避免冲突)
RUN rm -rf /usr/local/tomcat/webapps/ROOT

# 把本地的War包复制到Tomcat的webapps/ROOT(这样访问时不用加项目名)
COPY my-project.war /usr/local/tomcat/webapps/ROOT.war

# 暴露Tomcat默认端口8080
EXPOSE 8080

# 启动Tomcat(用官方镜像的启动脚本)
CMD ["catalina.sh", "run"]

然后构建镜像:

# 重点命令:-t 给镜像起名(my-tomcat)+ 版本(v1),. 表示当前目录找Dockerfile
docker build -t my-tomcat:v1 .

本地测试镜像是否能跑:

docker run -d -p 8080:8080 --name test-tomcat my-tomcat:v1
# 访问 http://localhost:8080,能看到项目页面说明成功

2. 步骤 2:用 k8s 部署这个 Docker 镜像

创建 k8s 部署配置文件tomcat-deploy.yaml

yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat-deployment  # 部署名
spec:
  replicas: 3  # 重点:启动3个副本(高可用)
  selector:
    matchLabels:
      app: tomcat
  template:
    metadata:
      labels:
        app: tomcat
    spec:
      containers:
      - name: tomcat-container
        image: my-tomcat:v1  # 用刚才构建的Docker镜像
        ports:
        - containerPort: 8080  # 容器内部端口
        resources:  # 可选:限制资源(避免占用太多)
          limits:
            cpu: "1"
            memory: "1Gi"
          requests:
            cpu: "0.5"
            memory: "512Mi"
---
# 重点:创建Service,让外部能访问容器(相当于“门牌号”)
apiVersion: v1
kind: Service
metadata:
  name: tomcat-service
spec:
  type: NodePort  # 适合测试:暴露节点端口
  selector:
    app: tomcat  # 和Deployment的label对应
  ports:
  - port: 8080  # Service内部端口
    targetPort: 8080  # 容器端口
    nodePort: 30080  # 外部访问端口(30000-32767之间)

然后部署到 k8s:

# 重点命令:应用配置文件
kubectl apply -f tomcat-deploy.yaml

# 查看部署状态
kubectl get pods  # 能看到3个Running的pod
kubectl get service tomcat-service  # 能看到暴露的节点端口30080

外部访问:http://k8s-node-ip:30080,就能访问到 Java 项目了。

五、常用使用方法:核心命令速查

1. Docker 核心命令

功能 命令示例 重点说明
构建镜像 docker build -t 镜像名:版本 . 末尾的 “.” 不能漏
运行容器 docker run -d -p 宿主端口:容器端口 镜像名 -d 表示后台运行
查看运行中的容器 docker ps 加 -a 看所有容器
查看容器日志 docker logs -f 容器名/ID -f 实时跟踪日志
停止容器 docker stop 容器名/ID 强制停止用 docker kill

2. Tomcat 核心操作

功能 操作方法 重点说明
启动(Linux) ./bin/startup.sh 需先给脚本执行权限(chmod +x)
停止(Linux) ./bin/shutdown.sh 强制停止用 kill -9 进程号
修改端口 编辑 conf/server.xml 中的 <Connector port="8080"> 避免端口冲突
部署项目 把 War 包放到 webapps 目录 重启 Tomcat 生效

3. k8s 核心命令

功能 命令示例 重点说明
应用配置文件 kubectl apply -f 文件名.yaml 新增 / 更新资源都能用
查看 Pod 状态 kubectl get pods 加 -o wide 看节点信息
查看 Pod 日志 kubectl logs -f pod名 加 -c 容器名(多容器时)
进入 Pod 内部 kubectl exec -it pod名 -- /bin/bash 调试用
扩缩容副本数 kubectl scale deployment 部署名 --replicas=5 快速调整副本数量

六、踩坑指南:常见问题 + 解决方法

1. Docker+Tomcat:访问项目 404

  • 问题现象:Docker 容器启动成功,但访问http://localhost:8080报 404;
  • 核心原因:War 包没放到 Tomcat 的正确路径,或没重命名为ROOT.war
  • 解决步骤
    1. 进入容器查看路径:docker exec -it 容器名 ls /usr/local/tomcat/webapps
    2. 确认 War 包是否存在,若不存在,检查 Dockerfile 的COPY路径是否正确;
    3. 若存在但不是ROOT.war,修改 Dockerfile 为COPY my-project.war /usr/local/tomcat/webapps/ROOT.war,重新构建镜像。

2. k8s:Pod 一直处于 Pending 状态

  • 问题现象kubectl get pods显示 Pod 状态为 Pending,事件里提示 “no nodes available to schedule pods”;
  • 核心原因:k8s 节点资源不足(CPU / 内存),或节点有污点(Taint);
  • 解决步骤
    1. 查看事件详情:kubectl describe pod pod名,找到 “Events” 部分;
    2. 若提示 “Insufficient cpu”,修改tomcat-deploy.yamlresources.limits.cpu为更小值(比如 0.5);
    3. 若提示 “Taint toleration not found”,给 Pod 添加污点容忍(Toleration),或移除节点污点。

3. Tomcat:启动报错 “Address already in use”

  • 问题现象:Tomcat 启动时提示 “8080 端口被占用”;
  • 核心原因:服务器上其他进程占用了 8080 端口;
  • 解决步骤
    1. 查找占用端口的进程:netstat -tulpn | grep 8080(Linux);
    2. 若进程可停止,用kill -9 进程号停止;
    3. 若进程不能停,修改 Tomcat 的conf/server.xml,把<Connector port="8080">改成其他端口(比如 8081),重启 Tomcat。

七、段子解疑:抽象概念秒懂

1. 用 “小区物业” 理解 k8s 的 “编排”

k8s 的 “编排” 到底是啥?其实就是 “小区物业的日常”:

  • Docker 容器 = 小区里的住户;
  • k8s = 物业;
  • 住户(容器)家里水管爆了(挂了),物业(k8s)不用你打电话,直接派维修员换个新住户(重启副本);
  • 小区人多了(容器多了),物业分单元管理(命名空间 Namespace),避免混乱;
  • 外人要找住户(外部访问),物业给个门牌号(Service),不用记住户的具体房间号(Pod IP);
  • 住户要用电(资源),物业规定每户最多用多少(resources.limits),避免有人占太多导致其他人没电用。

2. 用 “外卖” 理解 Docker+Tomcat 的关系

Docker 和 Tomcat 的配合,就像 “外卖套餐”:

  • Docker = 外卖盒;
  • Tomcat = 外卖里的米饭;
  • 你的 Java 项目 = 外卖里的菜;
  • 没有外卖盒(Docker):米饭(Tomcat)和菜(项目)容易撒(环境不一致),比如你在公司点的菜,带回家就凉了(依赖缺失);
  • 没有米饭(Tomcat):菜(项目)没法吃(Java 项目不能直接运行,需要 Web 容器解析);
  • 外卖盒里装着米饭和菜,不管你在公司、家里还是咖啡店(不同服务器),打开就能吃(一致部署)。

3. 用 “奶茶店” 理解 k8s 的 “副本”

k8s 的 “副本(Replicas)”,就是奶茶店的 “备用珍珠”:

  • 你点一杯奶茶(用户发一个请求),需要加珍珠(容器处理请求);
  • 如果珍珠不够(容器数量少),后面的人就要等(请求排队),店员赶紧加备用珍珠(k8s 扩容副本);
  • 如果有一颗珍珠坏了(容器挂了),店员直接换一颗新的(k8s 重启副本),你完全没感觉,继续喝奶茶;
  • 奶茶店打烊(服务下线),店员把所有珍珠收走(k8s 删除 Pod),下次开门再拿新的(重新部署)。

八、专业总结

Docker、Tomcat 与 k8s 的关系,本质是云原生架构下 “从单机到集群” 的工具协同链

  • Docker是基础:解决了 “环境一致性” 问题,让 “一次打包,到处运行” 成为可能,是容器化的基石;
  • Tomcat是核心:作为 Java 生态的主流 Web 服务器,是 Java 项目容器化的 “必需运行环境”,没有它,Java 项目无法在 Docker 容器中生效;
  • k8s是升华:基于 Docker 实现了 “容器集群的自动化管理”,解决了高可用、弹性扩容、故障自愈等运维痛点,让微服务架构落地成为可能。

三者并非替代关系,而是 “打包→运行→管理” 的递进:小项目可用 Docker+Tomcat 快速部署,大项目则需 k8s 实现集群化运维。理解它们的定位和协同逻辑,才能在云原生路上少走弯路~

如果大家在实操中遇到其他问题,欢迎在评论区留言,咱们一起讨论解决!