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

目录

[一、先分清:Docker、Tomcat、k8s 到底是 "干啥的"?](#一、先分清:Docker、Tomcat、k8s 到底是 “干啥的”?)

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

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

[1. 单独使用场景](#1. 单独使用场景)

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

[四、简单实操示例:手把手部署一个 Java 项目](#四、简单实操示例:手把手部署一个 Java 项目)

[1. 步骤 1:用 Docker 打包 Tomcat 镜像](#1. 步骤 1:用 Docker 打包 Tomcat 镜像)

[2. 步骤 2:用 k8s 部署这个 Docker 镜像](#2. 步骤 2:用 k8s 部署这个 Docker 镜像)

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

[1. Docker 核心命令](#1. Docker 核心命令)

[2. Tomcat 核心操作](#2. Tomcat 核心操作)

[3. k8s 核心命令](#3. k8s 核心命令)

[六、踩坑指南:常见问题 + 解决方法](#六、踩坑指南:常见问题 + 解决方法)

[1. Docker+Tomcat:访问项目 404](#1. Docker+Tomcat:访问项目 404)

[2. k8s:Pod 一直处于 Pending 状态](#2. k8s:Pod 一直处于 Pending 状态)

[3. Tomcat:启动报错 "Address already in use"](#3. Tomcat:启动报错 “Address already in use”)

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

[1. 用 "小区物业" 理解 k8s 的 "编排"](#1. 用 “小区物业” 理解 k8s 的 “编排”)

[2. 用 "外卖" 理解 Docker+Tomcat 的关系](#2. 用 “外卖” 理解 Docker+Tomcat 的关系)

[3. 用 "奶茶店" 理解 k8s 的 "副本"](#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"]

然后构建镜像:

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

本地测试镜像是否能跑:

bash 复制代码
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:

bash 复制代码
# 重点命令:应用配置文件
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 实现集群化运维。理解它们的定位和协同逻辑,才能在云原生路上少走弯路~

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

相关推荐
码路工人6 小时前
第7章:迈向云原生 - Kubernetes 简介
docker·云原生·容器
码路工人7 小时前
第6章:Docker Compose - 多容器应用的编排利器
docker·云原生·容器
小马过河R8 小时前
K8s引入Service Mesh原因及Istio入门
云原生·容器·kubernetes·k8s·istio·service_mesh
能不能别报错9 小时前
K8s学习笔记(五) Velero结合minnio业务数据备份与恢复
笔记·学习·kubernetes
行者Sun19899 小时前
【K8s】Kubernetes 虚拟机管理工具之 KubeVirt
云原生·容器·kubernetes
能不能别报错9 小时前
K8s学习笔记(六) K8s升级与节点管理
笔记·学习·kubernetes
途经六月的绽放9 小时前
Docker Compose 从入门到实践
java·docker
青衫客369 小时前
浅谈 Kubernetes 微服务部署架构
微服务·架构·kubernetes
虚伪的空想家9 小时前
生产环境K8S的etcd备份脚本
运维·容器·kubernetes·脚本·备份·etcd
孙克旭_10 小时前
kind部署K8S集群并将“修仙业务“部署到kind集群
linux·运维·云原生·kubernetes·kind