从 Docker 到 Kubernetes 的路线
大家好,今天想跟你们聊聊我是怎么从只会 docker run 的小白,一步步走到在生产环境里跑 Kubernetes 集群的。这条路说长不长,说短不短,中间踩过不少坑,也收获了很多成长。下面把我的经验整理成一篇“路线图”,希望能帮到正在准备迁移的朋友。
1. Docker 入门:从容器化开始
一开始接触容器,是因为公司要做微服务拆分,大家都在讨论 Docker。最初的学习其实很直接:
1. 安装 Docker Desktop(或直接在 Linux 上装 docker-ce)。
2. 写一个 Dockerfile,把业务代码、依赖全部打包进去。
FROM golang:1.20 AS builder
WORKDIR /src
COPY . .
RUN go build -o myapp .
FROM alpine:latest
COPY --from=builder /src/myapp /usr/local/bin/
CMD ["myapp"]
3. 构建、运行:
docker build -t myapp .
docker run -d -p 8080:8080 myapp
这几步走完,你的应用已经在容器里跑起来了。刚开始的成就感真的很高——一次构建,随处运行,完全不担心环境差异。
随后我们用 Docker Compose 来管理多容器:
version: '3'
services:
web:
image: myapp
ports:
- "8080:8080"
depends_on:
- db
db:
image: postgres:13
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
docker-compose up 一键启动所有服务,调试本地开发环境变得异常轻松。那时候我甚至觉得 Docker 已经足够解决所有问题了。
---
2. Docker Compose 的局限与集群需求
随着业务规模逐渐扩大,我们遇到了几个棘手的问题:
- 水平扩展:手动 docker-compose up --scale web=3 只能在本机玩,跨机器部署根本不可行。
- 服务发现:容器 IP 会变,Compose 只能靠 depends_on 做简单的启动顺序,无法动态感知新实例。
- 滚动更新:想平滑升级版本,需要自己写脚本控制旧容器停止、新容器启动,一不小心就会导致服务中断。
- 健康检查与自愈:容器挂了不会自动拉起,需要外部监控脚本配合。
这些问题在单机开发环境里不明显,但到了测试、预生产乃至正式生产环境就成了瓶颈。于是我们开始把目光投向 容器编排——Kubernetes(K8s)几乎是行业标准。
---3. Kubernetes 基础概念:Pod、Service、Deployment
如果你刚接触 K8s,可能会被一堆新名词吓到。其实只要把下面几个概念弄清楚,后面的迁移就会顺畅很多。
- Pod:K8s 的最小调度单元,通常是一个或多个共享网络的容器。我们的 myapp 容器在 K8s 里会以 Pod 的形式运行。
- Deployment:用来管理 Pod 的副本数、滚动升级、回滚等策略。可以把它想象成 Docker Compose 的 replicas + restart_policy。
- Service:为一组 Pod 提供稳定的访问入口(ClusterIP),还支持 LoadBalancer、NodePort 等类型,用来对外暴露服务。
- Ingress:基于 HTTP/HTTPS 的七层路由,适合把多个域名或路径映射到不同的 Service。
下面是一个最常见的 Deployment + Service 示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:latest
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /health
port: 8080
resources:
limits:
memory: "256Mi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
selector:
app: myapp
ports:
- port: 80
targetPort: 8080
type: LoadBalancer
把这段 YAML 保存为 myapp.yaml,执行 kubectl apply -f myapp.yaml,K8s 会自动创建 3 个 Pod,并通过一个 LoadBalancer 类型的 Service 对外暴露。滚动升级时只需要改镜像 tag,kubectl set image deployment myapp myapp=myapp:v1.1.0,K8s 会平滑替换旧 Pod,保证服务不中断。
4. 迁移实战:从 docker‑compose 到 Kubernetes
把已有的 Compose 项目搬到 K8s,一般会经历下面几个步骤。我把每一步都列出来,配上常见的要点,帮助你快速落地。
4.1 容器化检查
- 确保所有依赖都已经写在镜像里(不要把本地目录 volumes 直接映射进容器)。
- 确认入口进程是前台运行(PID 1),不要使用 supervisord 或 systemd 这类后台进程。
- 加上健康检查探针(livenessProbe / readinessProbe),K8s 会根据探测结果决定是否把流量转发给 Pod。
4.2 编写 Deployment 与 Service
- 先把原来的 docker-compose.yml 里的每个服务对应成一个 Deployment。
- 使用 labels 把 Pod 与 Service 关联起来,如 app: myapp。
- 对于需要持久化的数据,使用 PersistentVolumeClaim(PVC)代替 Compose 里的 volumes。如果使用云厂商的存储,只需要声明 storageClassName 即可。
4.3 配置 ConfigMap 与 Secret
- 环境变量、配置文件放到 ConfigMap,敏感信息(密码、Token)放到 Secret。
- 在 Pod 模板里通过 envFrom、volumeMounts 引入。
apiVersion: v1
kind: ConfigMap
metadata:
name: myapp-config
data:
DATABASE_HOST: "postgres.default.svc.cluster.local"
LOG_LEVEL: "info"
---
apiVersion: v1
kind: Secret
metadata:
name: myapp-secret
data:
# echo -n "password" | base64
DB_PASSWORD: cGFzc3dvcmQ=
4.4 部署 Ingress(可选)
如果需要根据域名或路径把请求分到不同的 Service,只需写一个 Ingress 资源:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp
port:
number: 80
4.5 CI/CD 自动化
- 在 GitLab CI、GitHub Actions 或者 Jenkins 中加入 kubectl 步骤:
kubectl set image deployment/myapp myapp=${DOCKER_IMAGE} -n production
- 推荐使用 Argo CD 或 Flux 实现 GitOps,代码提交后自动同步到集群,省去手动 apply 的繁琐。
5. 常见坑与调试技巧
迁移过程中,下面几个问题几乎每个人都遇到过,提前了解可以省不少时间。
- 镜像拉取失败:很多公共镜像在国内访问慢,建议使用阿里云、DaoCloud 的镜像加速,或者直接在私有仓库里维护。
- 资源配额不足:Pod 启动时如果 resources.limits 设得太低,会被 OOMKilled。可以通过 kubectl describe pod 查看事件定位。
- 网络不通:K8s 内部 DNS 解析规则是 service-name.namespace.svc.cluster.local,如果跨 namespace 调用一定要写全名。
- 滚动更新卡住:检查 readinessProbe 是否配置错误,导致新 Pod 永远不 ready,Deployment 只能一直等待。可以临时把 maxSurge 调大一点来排查。
- 持久化数据丢失:记得把 storageClass 与实际的 PV/PVC 绑定好,别把数据写在节点的临时目录里。
调试时常用的几条命令:
kubectl get pods -n <ns> # 查看 Pod 状态
kubectl logs -f <pod> -n <ns> # 实时日志
kubectl exec -it <pod> -- /bin/sh # 进入容器
kubectl describe pod <pod> -n <ns> # 查看事件
kubectl top nodes / pods # 资源使用情况(需要 metrics-server)
总结与展望
从 Docker 到 Kubernetes 的迁移,其实是一条从“把应用装进容器”到“把容器交给集群管理”的自然演进。最初的 Docker 让我们体验到了环境一致性的甜头;随后 Compose 解决了本地多服务的协同;但当业务需要弹性伸缩、滚动升级、故障自愈时,K8s 才是最终的归宿。
迁移的过程并不需要一次性把所有服务全部搬过去。可以先选一个非核心业务做试点,验证 CI/CD、健康检查、滚动更新等流程是否顺畅,再逐步迁移其他服务。期间肯定会遇到网络、存储、权限等各种细节问题,但只要把 Pod → Deployment → Service 这条链路跑通,后面的 Ingress、ConfigMap、Secret、PV 等概念都是顺理成章的扩展。
希望这篇文章能帮你梳理出一条清晰的路线,少走弯路。如果还有其他具体场景想要了解,欢迎在评论区留言,我们一起交流。祝你的 K8s 之旅顺利愉快!
从 Docker 到 Kubernetes 的路线
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法