ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

从Docker到Kubernetes:容器化部署到集群运维的实战排错指南

从Docker到Kubernetes:容器化部署到集群运维的实战排错指南 如果你已经能熟练地写 Dockerfile、能跑通docker-compose up -d甚至习惯了把 MySQL、Redis 都塞进容器里跑那说实话单机容器化这一关你已经过了。但阶段二的挑战恰好是从你试图把这些经验搬到 Kubernetes 集群里那一刻开始的。Docker 让你学会了怎么把应用装进箱子Kubernetes 则逼着你重新回答这个箱子在成百上千台机器上怎么活。这篇文章我不打算再重复一遍安装教程也不打算把 Deployment、Service、Ingress 的名词解释抄一遍。我想聊的是从一个能跑 Docker 的人变成能交付 Kubernetes 集群的人这条路上那些真正消耗时间的问题本地环境为什么起不来、镜像为什么拉不动、Pod 为什么一直 Pending、MySQL 为什么一重启就丢数据、网络为什么时通时不通。每个问题我都会按照实际排查链路来讲包含命令、配置、排错路径以及我踩过之后才明白的原理。适合已经具备 Docker 基础、正在准备或刚刚开始接触 Kubernetes 部署的读者也适合在公司里被人推着去做容器化落地的同学。1. 把应用塞进容器只是起点从Compose到集群跨越的到底是什么1.1 Compose让你觉得部署很简单这种错觉会付出代价很多团队接触容器化的第一步是 Docker Compose。一个docker-compose.yml里写好services、volumes、ports然后一条docker-compose up -d所有服务就起来了。这个体验非常爽但它掩盖了一个关键事实Compose 的编排范围是一台机器它不关心也不处理机器故障、网络分区、节点调度。到了 Kubernetes 阶段你面对的是同一套 YAML 但思维模型完全不同。最核心的转变有两个第一个转变是从命令式到声明式。你不再说帮我启动这个容器而是告诉集群我希望最终有 3 个 nginx 副本在运行。Kubernetes 的控制器循环会不断检查现实状态如果副本数变成 2 了它自动补一个如果节点挂了它把 Pod 重新调度到别的节点。这个机制叫 reconciliation loop可以类比成公司里的目标管理老板定了目标各级主管不断审视差距、推进执行而不是老板每次亲自盯着一个员工干活。第二个转变是从进程视角到API 视角。Compose 里你关心的是容器、网络、卷这些静态资源Kubernetes 里这一切都被抽象成 API 对象比如 Pod、Service、Deployment、StatefulSet。你操作的不再是机器上的进程而是通过kubectl apply往 API Server 提交期望状态。长期用下来你会发现真正稳定的部署流程一定基于声明式文件而不是命令。1.2 集群规划里最容易被忽略的三个前置问题如果你在公司里负责搭建集群先别急着装 kubeadm因为后面至少有三个问题会回头找你。第一个是网络模型。Kubernetes 本身不实现 Pod 间网络你需要选一个 CNI 插件。Flannel 简单、开销低适合小规模集群Calico 支持 NetworkPolicy、性能好更适合生产但要求内核模块和 IP 转发配置正确。无论选哪个一定要在kubeadm init之前把net.ipv4.ip_forward开好否则集群内部 DNS 和网络会以非常隐晦的方式坏掉。第二个是存储。单机上你用volumes挂载宿主机目录没毛病但在集群里 Pod 是会飘的今天跑在 node-1明天可能被调度到 node-2。本地目录跟着 Pod 走数据并不会跟着走。你必须在集群层面规划存储方案测试环境可以先用local或者 NFS生产环境建议考虑云服务商提供的云盘或者自建分布式存储比如基于 Rook 部署 Ceph。这个决策越往后拖成本越高尤其是当你已经有几十套 MySQL 跑在本地目录上时再迁移绝对痛苦。第三个是镜像仓库。企业里必然要有一个私有镜像仓库不然后面所有节点拉镜像都会慢到你怀疑人生。Harbor 是目前社区里最主流的开源选择支持镜像复制、漏洞扫描、权限控制。你需要在搭集群之前就把镜像仓库准备好并写好 tag 规范比如registry.internal/base/nginx:1.24.0不要等应用部署时才发现每个节点都要登录一次仓库。1.3 一个更接近生产的小集群长什么样我建议的最小生产参考架构是这样3 个 master 节点跑kube-apiserver、etcd、kube-controller-manager、kube-scheduler每个节点至少 4C8G。3 个 worker 节点跑业务负载每个节点至少 8C16G并且挂载一块独立数据盘给容器运行时。一个独立的镜像仓库节点跑 Harbor。一个独立的存储节点先跑 NFS 给测试环境用后续再扩分布式存储。一个负载均衡器用来暴露kube-apiserver的 6443 端口以及后续所有 Ingress 流量。如果你只有两台机器把 master 和 worker 混布也可以但要知道 master 被业务 Pod 打挂的风险是真实存在的。集群开始阶段我不建议上全套监控先装上metrics-server和kubectl top能看资源就够用了后面再按需加 Prometheus。2. 本地开发环境的高频翻车现场桌面端、启动失败与镜像拉取2.1 Docker Desktop 启动不了先别急着重装如果你用 Windows 开发大概率会遇到 Docker Desktop 启动失败报错里写着virtualization support not detected或者failed to start docker application container engine。这个报错字面意思是没检测到虚拟化支持但实际原因有好几种我按排查顺序给你理一遍第一步确认 BIOS/UEFI 里开启了虚拟化。Intel CPU 看 VT-xAMD CPU 看 SVM这个选项藏得比较深一般在Advanced - CPU Configuration里。如果之前开过 VMware/VirtualBox大概率没问题但有些主板更新 BIOS 后会把虚拟化重置回关闭状态所以值得看一眼。第二步检查 Windows 功能里是否启用了 Hyper-V、虚拟机平台、适用于 Linux 的 Windows 子系统WSL 2。Docker Desktop 在 Windows 上依赖这些组件缺一个都会起不来。你可以在 PowerShell 里跑dism.exe /online /get-featureinfo /featurename:Microsoft-Hyper-V dism.exe /online /get-featureinfo /featurename:VirtualMachinePlatform dism.exe /online /get-featureinfo /featurename:Microsoft-Windows-Subsystem-Linux如果显示 Disabled用下面的命令开启后重启dism.exe /online /enable-feature /featurename:Microsoft-Hyper-V-All /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart第三步确认 WSL 2 是默认版本。跑一下wsl --set-default-version 2然后wsl --status查看内核是否正常。旧版本的 WSL 内核也会导致 Docker Desktop 无法连接进程。第四步如果你开了 VMware Workstation 或 VirtualBox它们与 Hyper-V 的冲突是经典的翻车原因。要么共存时手动改 Docker Desktop 的 backend 配置要么干脆统一用 Hyper-V。这里没有所有人都适用的答案取决于你的其他虚拟化负载。2.2 镜像拉取慢与 daemon.json 的潜规则无论是 Docker Desktop 还是 Linux 上的 Docker Engine镜像下载慢几乎是国内团队第一天必遇的问题。解决方案是配置 registry mirror也就是镜像加速器。Docker 读的是/etc/docker/daemon.json改动后必须重启 Docker 才生效{ registry-mirrors: [ https://docker.mirrors.example.com ] }改完执行sudo systemctl daemon-reload sudo systemctl restart docker然后跑docker info看输出里的Registry Mirrors一节是否列出了你配置的地址确认生效。这里要提醒一句不要为了图快随便搜一个来路不明的加速地址填进去。镜像加速本质上是中间商你的镜像内容、拉取流量都会经过它选择正规云厂商提供的或者在团队内有统一运维管理的加速服务才靠谱。另外很多镜像下载慢其实不是 Docker 配置问题而是镜像本身太大、仓库在国外、或者本地 DNS 解析有问题。排查时可以先用docker pull hello-world这种小镜像测链路再用实际业务镜像测速度定位到底哪一环慢。热词里频繁出现docker镜像下载慢这个问题说明它确实是个普遍痛点但很多人一开始改错方向浪费时间。2.3 权限报错的真相docker 命令背后的 Unix Domain Socket在 Linux 上装完 Docker 后普通用户直接跑docker ps经常会看到permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock这不是你操作错了而是权限模型的问题。Docker 客户端与服务端通过/var/run/docker.sock通信这个 socket 文件默认属于root用户和docker组。把当前用户加入docker组sudo usermod -aG docker $USER newgrp docker然后重新登录终端再跑docker ps就能用了。注意newgrp docker只是让当前会话临时生效彻底生效需要重新登录或者重启。把用户加进docker组等同于给用户 root 权限因为 Docker 可以直接挂载宿主机目录、执行特权操作。所以生产服务器上不要随便把人加进 docker 组这是安全边界问题。Ubuntu 下安装 Docker 本身不复杂只要走官方 apt 仓库不装 Ubuntu 自带的旧版本docker.io就行。安装完成后再确认containerd和docker-buildx-plugin都装上了避免后面构建镜像时才发现缺少组件。3. 用声明式YAML接管应用从docker run到Deployment与Service的演替3.1 从 nginx 入手第一个 Deployment 的正确写法热词里频繁出现kubernetes 部署 nginx可见这是所有人练习的第一个对象。但如果你直接把docker run -d -p 8080:80 nginx翻译成 Kubernetes 对象方向就错了。Kubernetes 的最小调度单位是 Pod而 Pod 通常不直接创建而是通过 Deployment 来托管。一个最基础的 Deployment 文件长这样apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: default spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.24.0 ports: - containerPort: 80 resources: requests: cpu: 100m memory: 128Mi limits: cpu: 500m memory: 256Mi livenessProbe: httpGet: path: /healthz port: 80 initialDelaySeconds: 10 periodSeconds: 10 readinessProbe: httpGet: path: /index.html port: 80 initialDelaySeconds: 5 periodSeconds: 5这里有几个细节值得说。requests是给调度器看的资源申请limits是运行时限额。如果你不写 resources集群会把 Pod 当成无限资源容器调度时最容易被塞到高负载节点然后被莫名判定为异常。这是新手最常忽视的问题也是集群里 Pod OOM 的根源之一。livenessProbe决定容器是否存活失败会重启容器readinessProbe决定容器是否接收流量失败期间不会分配到请求。很多团队上线后发现明明 Pod 起来了但服务不稳定多半是探针没配好或者只配了 liveness 没配 readiness。把文件保存为nginx-deployment.yamlapply 之后用两条命令观察状态kubectl apply -f nginx-deployment.yaml kubectl get pods -o wide kubectl describe deployment nginx-deploymentdescribe是个宝藏命令它能告诉你 Deployment 的 ReplicaSet 创建情况、事件记录、镜像拉取状态绝大多数问题都能在这里找到线索。3.2 Service 和 Docker -p 的端口映射逻辑完全不同Docker 里用-p 8080:80把容器端口映射到宿主机端口在 Kubernetes 里这个逻辑被拆开了。Pod 的 IP 是集群内网 IP外界无法直接访问你需要 Service 提供稳定的访问入口。最常见的 ClusterIP 类型 Service 长这样apiVersion: v1 kind: Service metadata: name: nginx-service namespace: default spec: selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 80port是 Service 对外暴露的端口targetPort是后端 Pod 上的容器端口。Service 通过selector和 Pod 的 labels 关联这个机制替代了 Docker 里的服务名解析。集群内部其它应用访问它时直接用http://nginx-service就能通。如果你要让外部访问则需要 NodePort 或者 Ingress。NodePort 会在每个节点上开一个端口范围在 30000-32767 之间的随机端口适合临时调试不适合生产生产环境一般走 Ingress 统一入口。Ingress 本身也是要装一个控制器的比如 Nginx Ingress Controller它会根据 Ingress 规则把请求路由到对应的 Service。这个阶段有些人会犯一个错误直接在 Deployment 里配hostNetwork: true。这个配置确实能让 Pod 直接用宿主机网络但代价是端口冲突无法被 Kubernetes 管理几乎丢掉了 Service 和网络策略的全部优势。除非有特殊需求否则不要用。3.3 探针、优雅下线与滚动更新的实际问题上线一次发布后你会发现滚动更新的过程很有意思。Deployment 默认是 RollingUpdate 策略集群会先创建新 Pod等它 ready 后才销毁旧 Pod。如果你只更新镜像 tag命令如下kubectl set image deployment/nginx-deployment nginxnginx:1.26.0或者更推荐的方式修改 YAML 文件后重新kubectl apply -f。后者符合 GitOps 理念每一次变更都留痕可追溯。但这里有一个很容易被忽略的坑如果你的应用在收到 SIGTERM 信号时没有优雅处理滚动更新时会出现大量 502。Kubernetes 在销毁旧 Pod 前会发送 SIGTERM等待terminationGracePeriodSeconds默认 30 秒后强制杀死。Java 应用、长连接服务、消息队列消费者尤其要注意必须实现优雅停机逻辑否则每次发布都伴随报错告警。4. 有状态服务是阶段二真正的硬骨头MySQL与Redis的容器化持久生存4.1 为什么 MySQL 在容器里跑起来了却让你在深夜加班Docker 里安装 MySQL 有多简单生产环境里维护 MySQL 容器就有多头疼。热词里频繁出现docker安装mysql失败docker安装mysql8.0并使用说明大家都在容器化数据层上摔过跟头。核心问题在于数据持久化。如果你在 Docker 阶段用docker run -d -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD123456 \ mysql:8.0容器删除后数据直接消失。很多人在 Docker 阶段会挂载宿主机目录docker run -d -p 3306:3306 \ -v /data/mysql:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD123456 \ mysql:8.0这个思路在单机上没问题。但在 Kubernetes 里Pod 重建后不一定调度回原节点挂在 node-1 的/data/mysql目录对 node-2 上的新 Pod 完全没有意义。正确的做法是用 PersistentVolume 和 PersistentVolumeClaim把存储和节点解耦。一个使用 NFS 作为底层存储的 PV/PVC 长这样apiVersion: v1 kind: PersistentVolume metadata: name: mysql-pv spec: capacity: storage: 20Gi accessModes: - ReadWriteOnce nfs: server: 192.168.1.100 path: /data/k8s/mysql --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mysql-pvc namespace: database spec: accessModes: - ReadWriteOnce resources: requests: storage: 20Gi然后在 Deployment 的 volume 配置里引用这个 PVCMySQL 的 data 目录就不依赖于 Pod 所在节点了。这个机制是我建议所有有状态服务在集群上的第一步改造。4.2 redis 主从在 Kubernetes 里的正确姿势Redis 主从部署在 Docker 时代不复杂启动一个主节点再启动一个从节点用slaveof或者配置 replicaof 指向主节点的 IP。但到了 Kubernetes主节点 Pod 重启后 IP 会变你必须用稳定的方式访问它。对于有状态服务Kubernetes 提供了 StatefulSet。它和 Deployment 最大的区别是Pod 有稳定的网络标识如redis-0.redis-headless.database.svc.cluster.local和稳定的存储标识。StatefulSet 按序创建、按序删除配合 Headless Service每个副本都有固定 DNS 名称从节点可以直接配置replicaof redis-0.redis-headless.database.svc.cluster.local 6379这样即使 Pod 重建DNS 名称不变主从关系也不会断。要注意的是 Redis 的持久化配置。如果只配置了 RDB 快照宕机可能丢几十秒数据如果开了 AOF文件写入频率高对存储性能要求也随之上升。我的建议是测试环境用 RDB 够用生产环境必须 AOF并同时把appendfsync设置为everysec在数据安全与性能之间取平衡。4.3 ConfigMap 和 Secret别再把密码写死在镜像里我见过太多团队把 MySQL 密码、Redis 密码直接写进 Dockerfile 的 ENV 里或者写进 application.yml 然后打进镜像。这个习惯在 Kubernetes 阶段必须改掉因为镜像一旦构建里面的敏感信息就会被固化后续无法安全轮换密钥。Kubernetes 的解决方案是 ConfigMap 管普通配置Secret 管敏感信息。例如把 MySQL 链接信息放进 ConfigMapapiVersion: v1 kind: ConfigMap metadata: name: mysql-config namespace: database data: MYSQL_HOST: mysql-0.mysql-headless.database.svc.cluster.local MYSQL_PORT: 3306 MYSQL_DATABASE: business --- apiVersion: v1 kind: Secret metadata: name: mysql-secret namespace: database type: Opaque stringData: MYSQL_PASSWORD: your-strong-password然后在应用 Deployment 里通过envFrom注入spec: containers: - name: app image: your-app:1.2.0 envFrom: - configMapRef: name: mysql-config - secretRef: name: mysql-secret这样做的好处是换密码只需要更新 Secret 然后滚动重启应用不用重新构建镜像。密码不会出现在镜像层里也不会被推到镜像仓库。5. 故障排查链路复盘服务起不来、网络不通、镜像拉不动时我在查什么5.1 Docker 服务启动失败从 journalctl 到 daemon.json故障排查最忌乱猜。Docker 服务起不来的时候第一件事是看服务状态和日志systemctl status docker journalctl -u docker.service -n 100 --no-pager日志里常见的原因有三类第一类是daemon.json写坏了。JSON 语法错误、字段名不对Docker 直接拒绝启动。排查方法用dockerd --validate或者干脆把daemon.json备份后清空再启动试试。能启动就说明配置有问题用二分法把配置项逐个加回去。第二类是磁盘空间满了。Docker 镜像和容器日志默认存在/var/lib/docker日志无限增长很容易把分区撑满。你用df -h一看就知道。清理手段docker system prune清理悬空镜像、docker system df查看占用、日志可以通过配置 log rotation 来控制。第三类是服务之间端口或 iptables 规则冲突。如果你之前手动配置过 iptables清理了 FORWARD 链规则或者 docker 自定义链被破坏会导致容器之间、容器到外网的连接全部异常。最快速的办法是重启 Docker 让 iptables 规则重建但更重要的是搞清楚是谁在改 iptables比如 firewalld 和 Docker 的冲突就是云服务器上非常常见的组合。5.2 容器网络不通的完整排查链路容器网络不通的情况我遇到过太多次。错误的解决方式是反复重启容器正确的解决方式是沿着网络路径逐层排查。第一层确认容器状态docker ps -a docker inspect container_id | grep -A 10 NetworkSettings第二层确认容器能访问自己docker exec -it container_id ping 127.0.0.1 docker exec -it container_id ping 网关IP如果容器自己 ping 不通说明容器内部网络栈有问题如果能通网关说明桥接网络正常。第三层确认宿主机能不能访问容器ping 容器IP docker network inspect bridge如果宿主机 ping 不通容器多半是 bridge 网桥异常或 iptables 规则被清空。第四层确认容器能不能出外网docker exec -it container_id ping 8.8.8.8 docker exec -it container_id nslookup baidu.com能 ping 通 IP 但解析不了域名是 DNS 问题检查宿主机/etc/resolv.conf和 Docker daemon 的dns配置。IP 都不通就是 NAT 或路由问题检查iptables -t nat -L POSTROUTING有没有 MASQUERADE 规则。最后一层才考虑跨主机通信。Kubernetes 里的跨节点 Pod 通信依赖 CNI 插件如果 Pod A 能访问自己节点上的 Pod B但访问不了另一节点的 Pod C优先检查 CNI 的隧道接口或路由表而不是业务代码。这个排查思路写下来基本能覆盖docker网络不通这个热词背后 80% 的场景。5.3 Kubernetes 侧高频故障ImagePullBackOff、CrashLoopBackOff、Pending到了 Kubernetes 阶段你遇到最多的三个 Pod 状态就是 ImagePullBackOff、CrashLoopBackOff 和 Pending。ImagePullBackOff 就是镜像拉取失败。先用kubectl describe pod name看事件常见原因有镜像名或 tag 写错、私有仓库未登录可以使用 imagePullSecrets 解决、镜像仓库地址从节点访问不了、磁盘空间不足。注意kubectl get events --sort-by.lastTimestamp能按时间排序看所有事件比逐个 pod describe 效率高很多。CrashLoopBackOff 表示容器启动后崩溃被不断重启。这个状态只告诉你容器起不来但不告诉你原因。核心排查步骤是看日志kubectl logs pod-name --tail200 kubectl logs pod-name --previous--previous很重要因为容器崩溃后当前日志可能已经丢失上一条日志里往往才有真正的错误堆栈。常见原因集中在启动命令找不到、配置依赖缺失、探针配置过激进导致存活判定为失败、或者连接不上外部的数据库/中间件导致应用启动即失败。Pending 状态通常意味着资源不足或者调度失败。kubectl describe pod name最下面会写清楚调度失败的原因比如0/3 nodes are available: 1 Insufficient cpu, 2 Insufficient memory。很多人直接加资源但更好的办法是先kubectl top nodes看集群整体资源水位再决定是扩容节点、压缩现有 Pod 请求还是调整调度策略。6. 规模化运维的三件必须做的事配额、自动伸缩与日志可观测6.1 ResourceQuota 和 LimitRange别等互相挤爆了才后悔集群一旦开始有多个团队共享资源配额就不是可选项了。没有 ResourceQuota 的集群就像一个没有物业的小区谁家装修吵到别人、谁家用料占了公共区域最后一定出矛盾。给命名空间设置配额apiVersion: v1 kind: ResourceQuota metadata: name: dev-quota namespace: dev spec: hard: requests.cpu: 8 requests.memory: 16Gi limits.cpu: 16 limits.memory: 32Gi persistentvolumeclaims: 10 pods: 50LimitRange 则是约束单个 Pod 的最小和最大资源申请防止有人写requests.cpu: 100m但实际上限把整个节点吃干。配上之后团队写 YAML 时偷懒不写 resources 就不让你创建这招能从源头掐掉大量不规范部署。6.2 HPA从手动扩容到按指标扩容Kubernetes 的自动伸缩是很多人学它最初的吸引力之一。HorizontalPodAutoscaler 可以根据 CPU 使用率或自定义指标调整副本数前提是集群里装了metrics-server。一个基于 CPU 的 HPA 配置apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: myapp-hpa namespace: production spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: myapp minReplicas: 3 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 60设置完后用kubectl get hpa可以看到当前指标值和目标值用kubectl describe hpa能看到伸缩事件。实测里有两点要注意一是应用启动时间较长时扩容会被新 Pod 还没 ready 拖慢需要合理的探针配合二是缩容速度很保守因为默认的--horizontal-pod-autoscaler-downscale-stabilization是 5 分钟这是为了防止指标抖动导致频繁伸缩。6.3 日志和监控没有可观测性的集群等于盲飞容器化部署带来的一个麻烦是日志不再是落盘文件而是标准输出。K8s 里用kubectl logs只能看单个 PodPod 一重建日志就没了这在生产环境完全不可接受。常规做法是让应用把日志写到 stdout 和 stderr然后由节点上的日志采集组件统一收集。主流的方案是 EFKElasticsearch 存日志Filebeat/Fluentd 采日志Kibana 做可视化。更轻量的替代是 Loki Promtail Grafana资源占用小很多中小团队够用。监控层面Prometheus Grafana 是事实标准。部署方式可以直接用 kube-prometheus-stack装了之后能拿到节点、Pod、容器的 CPU/内存/网络/磁盘指标配合告警规则能第一时间发现异常。我个人的经验是告警宁可少配也不要乱配一条凌晨 3 点触发但完全不是问题的告警会让大家以后都不看告警疲倦感会毁掉监控体系。Kubernetes 集群的运维不是靠人肉盯出来的而是靠信息流日志给上下文、指标给趋势、事件给变化。这三样配齐了你才算有资格说自己做的是企业级容器化部署。最后再分享一点个人的真实体会。阶段二真正的门槛不是 Docker 和 Kubernetes 的命令行熟练度而是你能不能接受基础设施是代码、运行环境是声明出来的这套哲学。我见过不少团队Docker 玩得飞起但到了 Kubernetes 部署阶段遇到 Pod 起不来就习惯性上服务器手动敲命令救火最后反而比传统虚拟机部署更痛苦。原因很简单你想用 Kubernetes 的弹性、自愈、声明式能力却仍然用人肉运维的习惯去操作它两套思维打架。如果你正在搭建自己的集群我建议你先在一个可以随时重建的环境里练习把集群搞坏再恢复反复几次你会对 etcd、CNI、kubelet 这些组件之间的关系产生真正的体感。等你体会到一切皆 API 对象带来的确定性再看之前 Docker 阶段那些手工操作你会发现自己已经不太愿意回到那样做事的方式了。集群继续跑着后面还会有更复杂的坑但至少你已经知道去哪里看日志去哪里查事件往哪个方向找答案。这就是从会部署到能运维的分水岭。
返回列表