news 2026/9/8 4:21:42

从Docker Compose到Kubernetes:单机编排与集群调度的迁移实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从Docker Compose到Kubernetes:单机编排与集群调度的迁移实践

1. Compose 跑得好好的,为什么要折腾 k8s

1.1 一个真实的“被迫升级”场景

我最早接触 docker compose 的时候,心里想的是“终于不用在一台服务器上手动敲一串 docker run 了”。那时候公司项目还不大,一台 4核8G 的机器,nginx + php-fpm + mysql + redis 全部用 compose 编排,一条 docker compose up -d 全起来,日志、网络、重启策略都安排得明明白白。说实话,对中小项目来说,docker compose 的体验是真好,它把“多容器协作”这件原本很琐碎的事情,压缩成了一两个命令。

但后来事情变了。某个活动周期流量上来之后,单机部署的瓶颈就暴露了:一台机器扛不住,想要横向扩容,compose 基本帮不上忙。你当然可以在另一台服务器上再起一套 compose,但负载均衡、服务发现、滚动更新、故障自愈这些事全都得自己搞定。此时你会看到团队里开始有人提 k8s,也有人在争论“docker compose 升级到 k8s”是不是过度设计。

这篇文章我不打算写成 k8s 教程,也不打算劝你无脑迁移。我想从一个实际使用者的角度,把这两个东西的底层逻辑、适用边界、迁移路径和踩坑过程讲清楚。无论你是在纠结要不要学 k8s,还是正在准备把一套 compose 项目搬到 k8s,这篇文章应该都能给你一些实在的参考。

1.2 先搞清楚 docker compose 是干什么的

热词里有“docker compose 是干什么的”,这个问题其实问得挺核心。简单来说,docker compose 是一个容器编排工具,但它编排的范围是“单台主机”。你在 docker-compose.yml 里定义几个 service,每个 service 用什么镜像、暴露哪些端口、挂载哪些卷、依赖哪个服务,然后 compose 帮你在同一台机器上把这些容器拉起来,并且管理它们的网络、生命周期和日志。

它解决的核心痛点是“多容器应用的管理”。比如一个 LNMP 项目,有 nginx、php-fpm、mysql、redis 四个容器,手工 docker run 四次会非常痛苦,尤其是网络配置、环境变量、重启策略这些细节,手工敲容易漏。compose 用声明式配置解决这个问题,而且 docker compose up 之后,如果容器挂了,restart: unless-stopped 这类策略也能帮你拉起。对单机开发、测试、小型生产部署来说,这套方案已经足够。

但你要注意,compose 的“编排”是扁平化的,它没有调度器,没有节点概念,没有自动伸缩,没有跨主机的服务发现。它更像一个“单机管家”,而 k8s 则是一个“集群操作系统”。

1.3 k8s 到底解决的是什么问题

提到 k8s,很多人第一反应是“复杂”“要命的 YAML”“运维门槛高”。这些印象不算错,但容易让人忽略它的本质:k8s 是一套分布式系统的编排和调度平台。它把多台服务器抽象成一个资源池,然后通过声明式 API 让你描述“我想要的最终状态”,比如“我要 3 个 nginx 副本”,k8s 负责调度、编排、自愈、伸缩、滚动更新。

为什么会有“k8s经典版”“k8s的lnmp架构实验”这类热搜?因为大多数人的学习路径是从单机 of things 开始的,接触 k8s 之后第一反应是“我要怎么把我熟悉的 compose 项目搬到 k8s 上”。而这正是我接下来要展开的部分。

如果你只有一台机器,跑 k8s 不是不行,但收益很低。一台机器上,compose 能做的,k8s 都能做,但绕远路。反过来也一样:如果你有五六台机器,想统一管理所有中间件和应用,想实现灰度发布、自动扩容、故障转移,这时候 compose 就力不从心了。

2. 两者本质:单机编排与集群调度

2.1 Compose 的模型:本机多容器协作

docker compose 的工作模型建立在 docker 引擎本身之上。每个 service 本质上还是一个容器,compose 做的事情是帮你把这些容器纳入一个共享网络,并按依赖关系决定启动顺序。

举个例子。一个典型的 docker-compose.yml 可能长这样:

version: "3" services: nginx: image: nginx:1.26 ports: - "80:80" volumes: - ./html:/usr/share/nginx/html php: build: ./php expose: - "9000" mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: root123 volumes: - db_data:/var/lib/mysql volumes: db_data:

这里 nginx 和 php 之间通过 compose 创建的 bridge 网络通信,mysql 的数据存在命名卷里,nginx 把宿主机的 80 端口映射到容器内。这个模型很简单,所有容器都在同一台机器上,网络、存储、进程都是共享宿主机内核的。

compose 的优点是简单、直观、可读性高。缺点是它没有“跨主机”的抽象。一旦你有两台以上机器,compose 就不知道该怎么把容器分布在不同的节点上,也不知道怎么处理节点故障,更不知道如何做负载均衡。你只能在外面套一层像 nginx、keepalived、consul 这样的“外挂”来弥补。

2.2 Kubernetes 的模型:声明式集群调度

k8s 的模型复杂很多,但核心思想其实不复杂:你告诉它“我要什么”,它不断尝试让现实向期望状态收敛。

  • 你想跑一个 nginx,你创建一个 Deployment,里面写 replicas: 3,它会在集群里找三台合适的工作节点各自跑一个副本。
  • 你想让外部访问这些副本,你创建一个 Service,它会给你一个稳定的虚拟 IP,并做负载均衡。
  • 你想在发布新版本时不停机,你改一下镜像版本,它帮你做滚动更新。
  • 某个节点宕机了,它会把上面的 Pod 调度到其他节点重新创建。

这种模型的底层架构有几个核心组件:API Server、etcd、Scheduler、Controller Manager,以及每个节点上的 kubelet 和 kube-proxy。API Server 是所有操作的入口,etcd 存储所有状态,Scheduler 负责把 Pod 分配到合适的节点,Controller Manager 负责各种控制循环。听起来复杂,但你日常使用 k8s 时,直接面对的主要是 kubectl 和 YAML 配置。

这里有一个非常关键的思维转变:从“命令式”到“声明式”。compose 的 docker compose up 是你告诉 docker 去启动东西,k8s 的 kubectl apply -f 是你告诉集群“这个 YAML 描述了我想要的最终状态,请你去实现并持续维护”。compose 也不是没有声明式的东西,但它的“声明”范围比 k8s 小得多。

2.3 概念映射表:把 compose 翻译成 k8s

很多人觉得 k8s 难学,是因为概念太多。但如果从 compose 的视角去看,其实很多概念是可以一一对应的。我整理了一张对照表,方便你从熟悉的概念出发理解 k8s:

Docker Compose 概念Kubernetes 对应概念说明
serviceDeployment + ServiceDeployment 管副本和维护状态,Service 提供稳定访问入口
containerPod 内的容器Pod 是最小调度单元,可包含 1 个或多个容器
network(bridge)Pod 网络 + Service + Ingress默认同 Pod 内 localhost,跨 Pod 用 Service 抽象
volume(命名卷/绑定挂载)PersistentVolumeClaim(PVC)+ emptyDir持久化数据用 PVC,临时数据用 emptyDir
environment / env_fileConfigMap / Secret普通配置放 ConfigMap,敏感信息放 Secret
depends_oninitContainer + 探针(startup / readiness)控制启动顺序的方式完全不同
restart: unless-stoppedPod 的 restartPolicy + 控制器兜底k8s 中推荐用 Deployment 控制器保证自愈
portsService(NodePort / LoadBalancer)+ Ingress不建议直接在宿主机映射端口
扩展服务(docker compose up --scale)HPA(水平自动伸缩)k8s 支持基于 CPU/内存/自定义指标的自动伸缩

这张表是我做迁移时自己总结的,后来发现不少团队也是这么教新人的。你可以把它当成一本地图,而不是死记硬背的概念列表。真正需要理解的是每个映射背后的意图,比如 depends_on 在 compose 里只是控制启动顺序,但在 k8s 里光是顺序不够,还需要健康检查来判断“启动完成后是否可用”。

3. 从 Compose 到 k8s:5 步迁移路径

3.1 第一步:把 compose 项目容器化合规

我见过很多人把 docker-compose.yml 直接扔给 k8s,想找个自动转换工具一步到位。工具确实有,比如 compose-spec 转换成 k8s 的插件,但实际用下来效果一般,因为 compose 和 k8s 的模型差异太大了。我的建议是:先手工做一次“容器化合规检查”,再动手迁移。

具体检查四点:

  • 镜像是否已经构建并推送到镜像仓库。compose 里如果用的是 build,k8s 里默认是没有构建能力的,你需要先构建镜像,推到私有仓库或 Docker Hub,然后在 k8s 的 deployment YAML 里用 image 指定完整地址。
  • 环境变量是否可配置。compose 的 environment 可以硬编码,但到 k8s 里最好用 ConfigMap 管理,避免频繁改 YAML。
  • 启动顺序是否有强依赖。如果某个服务必须等另一个服务完全就绪才能启动,你需要考虑 k8s 的 initContainer 或者探针。注意,initContainer 只能保证“启动前检查”,如果对方是一个外部服务,不如直接让应用支持重试。
  • 数据持久化在哪里。compose 里无论是绑定挂载还是命名卷,迁移到 k8s 都要换成 PVC,这涉及存储类的选择,尤其是有状态服务(mysql、redis)时要特别小心。

这个阶段不用写任何 k8s 配置,先把 compose 项目的规范性和可移植性提上来。如果 compose 本身就依赖宿主机文件路径、特定内核模块或者宿主机端口,迁移时大概率会卡住。

3.2 第二步:镜像仓库与版本管理

k8s 调度到哪台机器是随机的,Pod 重建后会在新节点启动,所以镜像必须在集群所有节点都能拉取的位置。自建 Harbor 是最常见的方案,开发环境用 Docker Hub 或者阿里云 ACR 也可以。

这里有个细节常被忽略:镜像 tag 一定要带版本。很多人习惯用 latest,这在单机 compose 上没问题,但在 k8s 里会非常坑。因为 Deployment 滚动更新的判断依据是镜像 tag 或 digest 变化,如果你一直用 latest,那么你重新构建镜像、推送同一个 tag 到仓库之后,kubectl rollout restart 才能触发重新拉取,不然节点上的 kubelet 可能直接用本地的缓存镜像。正确的做法是每次构建都打一个新 tag,或者用 commit SHA 做 tag。

另外一个坑是私有仓库认证。k8s 节点拉取私有镜像需要配置 imagePullSecret,你可以把它挂在 Deployment 的 spec.template.spec.imagePullSecrets 里。很多新手迁移时镜像一直拉取失败,排查半天发现是没配 secret。

3.3 第三步:配置剥离——ConfigMap 与 Secret

compose 里最常见的配置方式有两种:直接在 environment 里写,或者用 env_file 引用文件。到 k8s 里,我强烈建议把配置统一剥离到 ConfigMap 和 Secret 中。

普通配置放 ConfigMap 的例子:

apiVersion: v1 kind: ConfigMap metadata: name: app-config data: APP_ENV: production DB_HOST: mysql-service DB_PORT: "3306"

敏感信息放 Secret:

apiVersion: v1 kind: Secret metadata: name: app-secret type: Opaque stringData: DB_PASSWORD: "root123"

然后在 Deployment 里引用:

env: - name: APP_ENV valueFrom: configMapKeyRef: name: app-config key: APP_ENV - name: DB_PASSWORD valueFrom: secretKeyRef: name: app-secret key: DB_PASSWORD

为什么推荐这么做?因为配置和镜像分离之后,你改配置不需要重新构建镜像,只需要 kubectl apply 更新 ConfigMap,然后滚动重启 Pod 即可。在团队协作时,也不容易把密码提交到 Git。

有个坑要提醒:ConfigMap 更新后,已经运行的 Pod 里的环境变量不会自动变化。你需要修改 Deployment 的 annotations(比如加一个版本号)触发滚动更新,或者直接 kubectl rollout restart deployment 名称。如果你希望配置变化自动生效,可以考虑用 ConfigMap 挂载文件的方式,kubelet 会定期同步,但依然有延迟,业务方需要自己监听文件变化。

3.4 第四步:存储从 volume 到 PVC

如果你在 compose 里用了命名卷,迁移到 k8s 时对应的是 PVC。PVC 的挑战在于存储类的选择,不同云厂商的存储类能力不一样,常见的有:

  • 本地存储(local):性能好,但 Pod 漂移后数据不跟着走,适合临时数据。
  • 网络存储(NFS、Ceph、云盘):Pod 漂移后依然能挂载,适合有状态服务。

我迁移 LNMP 里的 mysql 时,用的是 NFS 存储类。配置大致是这样:

apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mysql-pvc spec: accessModes: - ReadWriteOnce storageClassName: nfs resources: requests: storage: 30Gi

然后在 Deployment 里挂载:

volumes: - name: mysql-data persistentVolumeClaim: claimName: mysql-pvc

这里要注意 accessModes 和实际存储类是否匹配。NFS 一般支持 ReadWriteMany,云盘可能只支持 ReadWriteOnce。如果多个副本同时读写同一个 PVC,用 ReadWriteOnce 类型的存储会直接失败。

还有一点:mysql、redis 这类有状态服务,迁移时千万不要直接把 compose 里的数据目录原样挂载过去。如果数据库版本或配置差异较大,轻则启动失败,重则数据文件损坏。稳妥的做法是先在新环境起一个空实例,再把数据导入进去。

3.5 第五步:启动顺序、探针与滚动更新

compose 里的 depends_on 看起来控制了启动顺序,但它实际上只控制容器创建的先后顺序,并不等待依赖服务就绪。比如说 mysql 还没初始化完成,php 可能就先启动了,连接数据库失败后如果应用有重试逻辑还好,没有重试逻辑就直接崩溃。

k8s 里没有 depends_on 这种写法,你需要用两种方式配合:

  • initContainer:在主容器启动前执行一些检查或初始化操作。比较常见的做法是在 initContainer 里运行一条命令去检查依赖服务是否就绪,比如用 nc 或 wget 探测端口。
  • 探针(Probe):k8s 有三种探针,livenessProbe 判断容器是否存活,readinessProbe 判断是否可以接收流量,startupProbe 保护启动较慢的应用。

一个简单的 readinessProbe 示例:

readinessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 10 periodSeconds: 5

配置探针之后,k8s 才会把 Pod 标记为 Ready,然后接入 Service 的负载均衡。这和 compose 的 depends_on 相比,是本质上的升级:compose 只能保证“启动了”,k8s 能保证“可用了”。

滚动更新也值得提前设计好。默认情况下,Deployment 更新镜像时会逐个替换 Pod,如果你的应用只有一个副本,更新时会有短暂中断。如果要求零停机,需要设置 minReadySeconds、maxSurge 和 maxUnavailable。compose v2 也有 rolling 更新,但比较复杂,实际用到的人很少。

4. 典型案例:在 k8s 上把 LNMP 架构跑起来

4.1 LNMP 容器化的注意点

热搜词里出现了“k8s的lnmp架构实验”“k8s部署lnmp”,说明不少人在拿 LNMP 当 k8s 练手项目。LNMP 确实是一个很好的案例,因为它涉及 Web 服务、动态语言、数据库三种不同类型的工作负载。

LNMP 在 k8s 里的部署思路大概是:

  • nginx:无状态 Web 层,Deployment 副本数可伸缩,前端静态文件可以放镜像里或挂 PVC。
  • php-fpm:无状态应用层,Deployment 副本数可伸缩,nginx 通过 Service 访问 php-fpm。
  • mysql:有状态数据库层,用 StatefulSet 或者 Deployment + PVC 部署,通常只跑一个副本,数据持久化到 PVC。
  • redis:有状态缓存层,可以用 Deployment + PVC,或者直接上 redis Operator。如果只是单机实验,Deployment 就够了。

nginx 与 php-fpm 的通信在 compose 里很简单,因为它们在同一网络里。在 k8s 里,nginx 容器要访问 php-fpm Pod,需要给 php-fpm 创建一个 Service。比如:

apiVersion: v1 kind: Service metadata: name: php-fpm-service spec: selector: app: php-fpm ports: - port: 9000 targetPort: 9000

然后 nginx 配置里的 fastcgi_pass 指向 php-fpm-service:9000。这里有个小坑:compose 里 service 名可以直接作为 DNS 名称,比如 fastcgi_pass php:9000,而 k8s 里 Service 名称同样可以作为 DNS 名称,所以其实写法是类似的,只是要注意命名空间隔离和同名冲突。

4.2 网络规划:Service、Ingress 与多网卡场景

LNMP 对外提供 Web 服务,在 k8s 里通常有两种方案:NodePort 或者 Ingress。如果你只是实验,NodePort 最简单:

apiVersion: v1 kind: Service metadata: name: nginx-service spec: type: NodePort selector: app: nginx ports: - port: 80 targetPort: 80 nodePort: 30080

这样集群任何节点的 30080 端口都能访问到 nginx。但生产环境一般用 Ingress Controller,比如 nginx-ingress 或 traefik。Ingress 的好处是可以在七层做路由、TLS、限流等,而且不需要直接暴露 Service 端口。

顺便说一下热搜里提到的“k8s multus 网络 vlan 配置”。Multus 是一个多网络插件,允许 Pod 同时接入多个网络接口,可以在一个虚拟网络上跑管理面流量,另一个物理网络跑数据面流量。日常单集群项目基本用不到,但如果你在做 SDN、边缘计算或者对网络性能有特殊要求的场景,可以了解一下。它配置的核心是 NetworkAttachmentDefinition 资源,需要配合可用的 CNI(如 macvlan、vlan)和默认网络插件(如 Calico、Flannel)协同工作。这个扩展我不建议新手第一时间玩,先把基础 Service/Ingress 网络搞明白更重要。

4.3 LNMP 迁移时踩过的几个坑

我在把一套 compose 版 LNMP 迁到 k8s 的时候,踩过不少值得记录的坑。

第一个坑是 php-fpm 启动后,nginx 报 502。排查后发现是 php-fpm 的 listen 配置。compose 里容器内启动 php-fpm 默认监听 9000 端口,但在某些镜像里,php-fpm 的配置是监听 Unix socket 路径,而不是 TCP。如果是 socket,nginx 的 fastcgi_pass 需要改成 socket 文件路径,并额外挂 socket 目录。用 k8s 时,不同 Pod 之间没法共享 socket 文件,所以必须改成 TCP 监听,并在 php-fpm 的配置里指定 listen = 0.0.0.0:9000。

第二个坑是 mysql 初始化。compose 里可以用 environment 设置 MYSQL_ROOT_PASSWORD,k8s 环境也可以,但要小心 ConfigMap 里的密码包含特殊字符。比如密码里有 $ 或者 \,YAML 解析时会被转义,导致初始化密码和业务配置里的密码不一致。建议用 Secret 的 stringData 字段,避免手动 base64 转码时的格式问题。

第三个坑是镜像拉取超时。集群里如果有节点在中国大陆,直接拉 Docker Hub 镜像经常超时。解决办法是在镜像仓库层面做缓存/代理,或者把镜像同步到云厂商的镜像仓库,然后用完全限定名。这个话题跑题了,不展开,但要提醒你提前处理。

5. 常见问题与排坑实录

5.1 是不是所有 compose 项目都值得迁移到 k8s

这是每次聊到迁移时,最容易被问起的问题。我的看法是:不是。

如果你同时满足以下条件,迁移的收益其实不大:

  • 项目规模小,单台服务器足以支撑业务。
  • 团队没有专职运维,没有 k8s 使用经验。
  • 流量变化平缓,不需要自动扩缩容。
  • 数据存储强依赖本地磁盘,且没有现成网络存储。

这种情况下,docker compose 足够稳定,强行上 k8s 只会增加复杂度。迁移到 k8s 是有代价的:YAML 数量变多、学习成本上升、排查问题所需的技能栈变广、集群本身也需要维护(apiserver、etcd、网络插件、证书过期等)。“新版 docker 自带 compose”这个特性本来就是在降低单机用户的编排成本,说明 Docker 官方也在认可 compose 在轻量场景里的价值。

那什么情况下必须考虑 k8s?两条明确信号:一是需要横向扩容,二是需要故障自愈。当你的应用需要“机器挂了自动换一台继续跑”,或者“流量高峰自动增加副本”,compose 是做不了的,这时候上 k8s 就是刚需。

5.2 安装部署与版本选择的常见误区

热搜里有“k8s安装部署”“rancher装k8s”“k8s经典版”这些词,说明很多人卡在装环境这一步。k8s 的安装确实容易劝退新手,尤其是裸金属环境,证书、etcd、网络插件、kubelet 配置,每一步都可能出问题。

我给你的建议是分阶段:

  • 纯学习阶段:用 kind(Kubernetes in Docker)或者 k3d,一条命令起一个集群,省去了几乎所有安装环节。适合先熟悉概念和 YAML 写法。
  • 单机生产实验:用 k3s,轻量、内存占用小,也是 Rancher 团队出的产品,配 Rancher 的可视化管理界面非常方便。
  • 正规多节点生产:用 kubeadm 或者云厂商托管集群(比如 ACK、TKE、EKS)。托管集群省心很多,etcd 和 master 节点都不需要自己维护。

关于版本,我建议优先选择当前稳定版本,不要追“经典版”这种过时概念。k8s 的迭代速度很快,社区一般维护最近三个小版本,老版本会有安全漏洞和兼容性问题。安装工具链版本(如 kubeadm、kubelet、kubectl)要与集群版本匹配,这个在安装文档里写得很清楚,但很多人会栽在这上面。

Rancher 作为一个可视化管理平台,适合团队多人操作,它本身不替代 k8s,而是给你一个 UI 来管理多个集群和部署应用。如果你团队里有人畏惧命令行,Rancher 能显著降低使用门槛。

5.3 高频问题速查表

最后我整理了一个高频问题表,都是我在实际操作和帮同事排障时遇到过的经典问题,直接收藏可查:

问题现象常见原因排查与解决
Pod 一直 Pending节点资源不足 / 调度约束不满足kubectl describe pod 查看事件,检查 requests 配置与节点可用资源
ImagePullBackOff镜像地址错误 / 私有仓库未认证检查镜像 tag 是否存在,配置 imagePullSecret
CrashLoopBackOff应用启动失败 / 探针配置过严查看日志 kubectl logs 上一个容器,调整探针参数
503 Service UnavailableService 选择器无匹配 Pod / 后端未 Readykubectl get endpoints,检查 selector 是否匹配
Nginx 502 Bad Gateway后端服务端口不匹配 / php-fpm listen 配置错误进入 nginx 容器 curl 测试后端地址
ConfigMap 修改后不生效环境变量注入不会自动更新触发滚动更新 restart deployment
PVC 一直 Pending存储类不存在或不可用kubectl get storageclass,检查 storageClassName
NodePort 无法访问安全组/防火墙未放行检查节点安全组和防火墙规则,kubectl get svc 确认端口
跨节点 Pod 无法通信网络插件问题检查 CNI 组件状态,查看 kube-system 命名空间日志
证书过期导致 kubectl 报错集群证书有效期问题查看 kubeadm 证书期限,定期 renew

5.4 我的建议:小步慢走,别搞一刀切

迁移这件事,最忌讳的就是把所有服务一次性搬到 k8s。我见过一些团队,周会上定了“下个月全部上 k8s”的目标,结果三个月后还在和 YAML 搏斗,线上事故不断。更稳妥的方式是挑一个无状态服务先迁移,比如把 nginx 前端迁到 k8s,后面依然连 compose 环境的 php-fpm。之所以能这么干,是因为 Service 的抽象天然屏蔽了后端地址的细节,只要你把 compose 服务的地址改成 k8s Service 的 DNS 或者 NodePort 地址即可。等跑顺了,再逐步迁移 php-fpm、redis、mysql。

这样做的另一个好处是团队能渐进式学习。先让一两个主力把 k8s 跑熟,再带着其他人一起踩坑。如果一开始就全员扑上去,大家的挫败感会非常强。

6. 写在最后:两个工具的定位从来不是替代关系

我接触 These two 工具多年,最深的感受是:它们不是同一层的东西,硬要比出高下其实是浪费时间。docker compose 解决的是“一台机器上怎么把多个容器组织起来”,k8s 解决的是“一个集群里怎么把各种应用调度的井井有条”。两者的关系更像自行车和汽车,都能代步,但适用场景和驾驶门槛完全不同。

如果你问我个人会怎么选,我的原则很简单:单机环境、开发测试、小规模生产,优先 compose;多节点、高可用、自动伸缩、复杂发布流程,直接 k8s。如果团队资源和精力有限,compose 完全够用的阶段强行上 k8s,只会给自己找麻烦。反过来,如果业务已经明显在增长,早点接触 k8s 其实是给未来省时间,因为真正的迁移成本会随着业务复杂度和数据量的增长指数上升。

最后分享一个比较反常识的经验:把 compose 项目迁到 k8s 之后,你再回头看 compose,往往能把 compose 写得更好。因为你理解了 ConfigMap 该怎么拆、探针该怎么配、存储边界在哪,这些认知反过来会让你的 compose 项目更加健壮。我在实际迁移完 LNMP 之后,就把原来 compose 里依赖启动顺序的写法全部改成了应用层重试加健康检查,整体稳定性提升非常明显。

工具永远在变,但“把应用状态描述清楚、让系统自己去维护”的这种声明式思维,是这两个工具共同传递给你的最有价值的东西。学会了它,将来不管再出现什么新编排系统,你上手都会快很多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 4:20:25

别再瞎做答辩PPT❌实测OKBIYE AI PPT|毕业答辩直接开挂

真心劝所有应届生!别再盲目熬夜肝答辩PPT了🙅♀️ 很多人踩坑无数:免费模板太花哨不学术、付费模板同质化严重、自己排版逻辑混乱、做完PPT还要通宵写答辩稿,忙活两三天,成品还漏洞百出,答辩被导师追问哑口…

作者头像 李华
网站建设 2026/9/8 4:20:19

JavaScript深拷贝与浅拷贝:从原理到实战,彻底搞懂对象复制

浅拷贝和深拷贝这俩概念,几乎每次前端面试都会碰到,但说真的,能把这两个概念讲透的人不多。很多人背了答案,知道 Object.assign() 是浅拷贝、 JSON.parse(JSON.stringify()) 是深拷贝,可真到了项目里,遇…

作者头像 李华
网站建设 2026/9/8 4:19:01

Docker私有仓库搭建实战:从Registry到HTTPS认证与故障排查

在公司内部跑了两年业务,部署环境从一台测试机膨胀到几十台服务器之后,我越来越觉得当初认真搭一套 Docker Registry 私有仓库是个极其正确的决定。 倒不是说 Docker Hub 不好用,而是在真实生产环境里,你会发现公共镜像源存在几个…

作者头像 李华
网站建设 2026/9/8 4:17:03

本地部署多模态模型实战:16G显存优化Qwen2.5-VL,性能直追云端

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/8 4:16:02

技术博客写作:从项目标题到摘要的关键准备方法

当前输入中“项目标题”显示为占位符“点击输入文字”,且没有提供项目正文、关键词、摘要描述等有效素材,我无法据此生成一篇真实可用的 CSDN 技术教程。为避免编造技术主题、虚构版本和项目信息,请补充以下内容后我再为你输出完整博文&#…

作者头像 李华
网站建设 2026/9/8 4:15:24

三模机械键盘选购与配置指南:从概念到实操

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华