目录
一、先分清: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 项目为例,完整链路是这样的:
- 开发端:写好 Java 项目,打成 War 包(比如
my-project.war
); - Docker 打包:写一个 Dockerfile,把 “Tomcat 镜像” 和 “War 包” 一起打包成新镜像(比如
my-tomcat:v1
)—— 相当于 “用外卖盒(Docker)装起米饭(Tomcat)和菜(Java 项目)”; - k8s 部署:用 k8s 的 Deployment 配置,指定 “启动 3 个
my-tomcat:v1
容器副本”,并通过 Service 暴露访问端口 —— 相当于 “物业(k8s)安排 3 个‘打包好的外卖’(容器)上架,还贴上门牌号(Service)方便别人找到”; - 用户访问:用户通过 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: tomcattemplate:metadata:labels:app: tomcatspec:containers:- name: tomcat-containerimage: 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
; - 解决步骤:
- 进入容器查看路径:
docker exec -it 容器名 ls /usr/local/tomcat/webapps
; - 确认 War 包是否存在,若不存在,检查 Dockerfile 的
COPY
路径是否正确; - 若存在但不是
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);
- 解决步骤:
- 查看事件详情:
kubectl describe pod pod名
,找到 “Events” 部分; - 若提示 “Insufficient cpu”,修改
tomcat-deploy.yaml
的resources.limits.cpu
为更小值(比如 0.5); - 若提示 “Taint toleration not found”,给 Pod 添加污点容忍(Toleration),或移除节点污点。
- 查看事件详情:
3. Tomcat:启动报错 “Address already in use”
- 问题现象:Tomcat 启动时提示 “8080 端口被占用”;
- 核心原因:服务器上其他进程占用了 8080 端口;
- 解决步骤:
- 查找占用端口的进程:
netstat -tulpn | grep 8080
(Linux); - 若进程可停止,用
kill -9 进程号
停止; - 若进程不能停,修改 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 实现集群化运维。理解它们的定位和协同逻辑,才能在云原生路上少走弯路~
如果大家在实操中遇到其他问题,欢迎在评论区留言,咱们一起讨论解决!