服务器运维

k8s 是干什么的?容器编排解决的问题与 Docker 的区别

k8s 就是 Kubernetes,一个容器编排平台。你告诉它“这个网站跑 3 个副本、用这个镜像、对外提供 80 端口”,它负责把容器安排到合适的服务器上,挂了自动拉起,按负载增减副本,发新版时逐个替换,并给这组容器一个固定的访问地址。Docker 管的是一台机器上的容器,k8s 管的是一群机器上的容器。

作者 顶联产品团队发布于 7 分钟阅读

k8s 是干什么的?一句话:在多台服务器上自动部署、运行和管理容器。你用一份 YAML 文件描述想要的状态,比如“网站要 3 个副本、用 1.4.2 版本的镜像、每个副本要半核 CPU 和 256 MB 内存”,k8s 负责把它变成现实,并一直维持下去:容器挂了自动重启,服务器宕机就在别的服务器上重建,流量上来了加副本,发新版时一个一个替换。k8s 是 Kubernetes 的缩写,K 和 s 之间正好 8 个字母,于是写成 k8s。这个词来自希腊语,意思是舵手。它由 Google 在 2014 年开源,吸收了 Google 内部集群管理系统 Borg 的经验,2015 年发布 1.0 并捐给了新成立的云原生计算基金会(CNCF),现在是主流的容器编排平台。

从部署一个网站说起:没有 k8s 时要做什么

假设你要运维一个电商网站:前面是 nginx,中间是 3 个应用实例,后面是 Redis 和 MySQL,一共 3 台服务器。不用任何编排工具,日常工作是这样的:

  1. 部署:登录每台服务器装运行环境、上传代码、改配置、启动进程。三台机器的系统补丁、依赖版本稍有不同,就会出现“这台好的、那台报错”。
  2. 故障:凌晨应用进程崩溃,靠监控告警叫醒值班人员去重启;一台服务器硬件故障,上面的实例要手工挪到另外两台上,还要改 nginx 的 upstream 列表。
  3. 扩容:大促前加两台机器,重复一遍部署步骤,再把新实例加进负载均衡;活动结束后再手工撤下来。
  4. 发版:逐台停服务、换包、启动、验证;第二台出问题,再逐台回滚。
  5. 互相访问:应用连接 Redis 和 MySQL 的地址写在配置文件里,换一台机器就要把配置改一圈。

Docker 解决的是第 1 件事:把应用和依赖打成镜像,在任何装了 Docker 的机器上运行结果都一样。但后面 4 件事跨越了多台机器,Docker 本身管不了,这正是 k8s 要做的。

k8s 解决的五个问题

k8s 的工作方式可以概括为“声明期望状态,由控制器持续纠偏”:你只说要什么,不说怎么做;集群里的各个控制器不停地对比实际状态和期望状态,发现不一致就动手修正。上面的五件事对应到 k8s 里是这样的:

问题 k8s 的做法 相关的对象或命令
调度:容器放在哪台机器上 你声明每个容器需要的 CPU 和内存(requests),调度器在集群里挑资源够用的节点放置 Pod、resources、调度器
自愈:挂了怎么办 容器进程退出会被重启;健康检查失败的容器也会被重启;节点失联后,由 Deployment 管理的 Pod 默认约 5 分钟后在其他节点重建 重启策略、存活探针、Deployment
扩缩容 改副本数即可;配合 HPA(水平自动扩缩)可以按 CPU 使用率等指标自动增减,前提是集群里装了 metrics-server kubectl scale、HorizontalPodAutoscaler
滚动更新与回滚 换镜像版本后分批替换,默认多出或缺少的 Pod 都不超过副本数的 25%,新 Pod 通过就绪检查后才继续替换下一批;出问题一条命令退回上一版 kubectl set image、kubectl rollout undo
服务发现与负载均衡 Service 给一组 Pod 一个固定的虚拟 IP 和 DNS 名称,请求在这组 Pod 之间分发,Pod 重建换了 IP 也不用改配置 Service、集群 DNS

另外,配置和密码可以从镜像里拆出来,放进 ConfigMap 和 Secret,同一个镜像在测试和生产环境挂不同的配置。

把上面那个网站的应用层写成 k8s 的清单,大致是这样(镜像地址是示例):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: shop-web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: shop-web
  template:
    metadata:
      labels:
        app: shop-web
    spec:
      containers:
        - name: web
          image: registry.example.internal/shop/web:1.4.2
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: 500m
              memory: 256Mi
          readinessProbe:
            httpGet:
              path: /healthz
              port: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: shop-web
spec:
  selector:
    app: shop-web
  ports:
    - port: 80
      targetPort: 8080

Deployment 描述“跑 3 个副本、用哪个镜像、怎么判断它准备好了”,Service 给这 3 个副本一个统一入口:集群里的其他程序访问 shop-web 这个名字(完整写法是 shop-web.default.svc.cluster.local)的 80 端口,请求会被分到某个就绪的副本上。日常操作用 kubectl:

kubectl apply -f shop-web.yaml                       # 创建或更新
kubectl get pods -l app=shop-web -o wide             # 3 个 Pod 分别在哪个节点上
kubectl delete pod shop-web-7d9c8b6f5-x2k4q          # 模拟故障:删掉一个,几秒后会出现新的补位
kubectl scale deployment shop-web --replicas=6       # 扩到 6 个副本
kubectl set image deployment/shop-web web=registry.example.internal/shop/web:1.4.3
kubectl rollout status deployment/shop-web           # 观察滚动更新进度
kubectl rollout undo deployment/shop-web             # 新版本有问题,退回上一版

delete pod 那一条最能说明 k8s 的思路:你没有告诉它“再起一个”,是 Deployment 控制器发现实际只有 2 个副本、少于期望的 3 个,自己补上的。

k8s 和 Docker、Docker Compose 的区别

三者经常被放在一起比较,但它们不在同一层:

  • Docker 做两件事:用 docker build 把应用打成镜像,用 docker run 在一台机器上运行容器。
  • Docker Compose 用一个 compose.yaml 描述多个容器组成的应用(web、redis、db),docker compose up -d 一条命令在一台机器上全部拉起,容器之间按服务名互相访问。
  • k8s 不负责构建镜像,它负责在多台机器上运行和管理容器。镜像照样用 Docker 构建、推到镜像仓库,k8s 的节点再从仓库拉取。节点上实际启动容器的是 containerd、CRI-O 这类容器运行时;k8s 从 1.24 起不再直接对接 Docker Engine,但 Docker 构建的镜像符合 OCI 标准,在 k8s 里照常运行。

所以“k8s 和 Docker 的区别”的答案是:它们是上下游关系,不是二选一。Docker 也有自己的集群编排 Docker Swarm,概念少、上手快,但周边生态和社区规模不如 k8s。

按网站那个例子,把四种方式放在一起对比:

对比项 手工运维 Docker Docker Compose k8s
交付的东西 代码包加部署文档 镜像 镜像加 compose.yaml 镜像加 YAML 清单
环境一致性 靠人和文档 镜像保证 镜像保证 镜像保证
管理范围 每台单独操作 一台机器上的单个容器 一台机器上的一组容器 整个集群
进程崩溃 告警后人工重启 设置重启策略后自动重启 同 Docker 自动重启,健康检查失败也会重启
服务器宕机 人工迁移 无法处理 无法处理 在其他节点重建
扩容 加机器、重复部署 手工多起几个容器 --scale 在单机上加副本 改副本数,或按指标自动扩缩
发版与回滚 逐台操作 手工停旧起新 重建容器,期间会短暂中断 滚动更新,一条命令回滚
服务互相访问 配置里写死 IP 端口映射加手工配置 同一项目内按服务名访问 Service 名称和集群 DNS
学习与维护成本 低 低 低 高:控制平面、网络、存储、版本升级都要有人管

什么规模的业务值得上 k8s

k8s 的收益来自“机器多、服务多、变化多”,成本则是一整套需要专人维护的系统。可以对照下面几条判断:

判断依据 倾向于上 k8s 倾向于先不上
服务数量 多个独立部署的服务,或者多个项目想共用一套基础设施 一个应用加一个数据库
服务器数量 3 台以上,并且还在增加 一两台
发布频率 每周多次甚至每天发版 一个月一两次
流量 峰谷明显,需要临时扩容 平稳
团队 有人能负责集群升级、网络和存储排障 没有专人,出了问题没人能修
应用形态 能容器化的无状态 Web、API、后台任务 强依赖本机状态的老系统、Windows 桌面类软件

左列占了多数,k8s 带来的自动化值得它的维护成本;只有一两台服务器、一个月发一次版,用 Docker Compose 加 systemd 管理就足够,出问题时排查路径也短得多。

维护成本要提前算清楚:k8s 每年发布三个左右的小版本,每个小版本的补丁支持约 14 个月,升级又只能逐个小版本进行,所以一个集群至少每年要升级一次;控制平面的证书、etcd 的备份、网络插件和存储插件的版本,也都要有人跟。没有人力承担这些,集群跑上一两年就会变成不敢动的系统。

机房里几台服务器怎么起步

用自有机房的物理机起步,最常见的形态是 3 台服务器组成一个小集群,每台既是控制平面又跑业务。选 3 台的原因是 etcd(k8s 存放全部集群状态的数据库)靠多数派工作:3 个节点能容忍坏 1 台,2 个节点坏 1 台就失去多数,和 1 台没有区别。数据库先留在集群外的独立服务器上。

搭建工具按需要选:

方式 特点 适合
kubeadm 官方工具,组件标准;网络插件、对外入口、存储都要自己选择和安装 想按标准方式搭建,后续规模会变大
k3s 单个二进制,默认自带 flannel 网络、Traefik 入口、ServiceLB 负载均衡和本地存储,高可用模式内置 etcd 小集群,想先跑起来再说
云厂商托管 控制平面由厂商维护 业务在云上而不在自有机房

以 k3s 为例,3 台服务器内网地址为 10.10.30.11 至 10.10.30.13,以 root 执行:

# 第一台:生成共享密钥,以内置 etcd 初始化集群
TOKEN=$(openssl rand -hex 16); echo "$TOKEN"
curl -sfL https://get.k3s.io | K3S_TOKEN=$TOKEN sh -s - server --cluster-init

# 第二、三台:用第一台输出的密钥加入,同样作为 server 参与 etcd
curl -sfL https://get.k3s.io | K3S_TOKEN=第一台输出的密钥 sh -s - server --server https://10.10.30.11:6443

# 任意一台上确认三个节点都是 Ready
k3s kubectl get nodes -o wide

国内网络访问安装脚本和 GitHub 较慢时,按 k3s 官方文档里的说明改用国内镜像,或者用离线(air-gap)方式安装,镜像地址以文档当前写法为准。集群起来只是第一步,物理机上没有云平台代劳的那些东西,要自己补齐:

要补的 为什么 常见做法
对外入口 没有云负载均衡,LoadBalancer 类型的 Service 拿不到地址 k3s 自带 ServiceLB;kubeadm 集群常用 MetalLB,从机房分配的一段地址中给 Service 分配 IP
持久化存储 Pod 换了节点还要能读到原来的数据 起步用本地存储,数据跟着节点走;要跨节点就用 NFS、Ceph 或 Longhorn
镜像仓库 节点从仓库拉镜像,公网仓库在国内可能拉不下来 自建 Harbor 等私有仓库
备份 全部集群状态都在 etcd 里 k3s 内置 etcd 时默认定时生成快照,要把快照再拷到集群之外
监控与日志 容器随时会被重建,登录节点翻日志不现实 Prometheus 采集指标,日志集中收集
网段 Pod、Service 网段不能和机房已有的网段重叠 k3s 默认 Pod 网段 10.42.0.0/16、Service 网段 10.43.0.0/16,冲突时在安装时修改

容量也要按“坏一台”来算:3 个节点要能在其中 1 台故障时把所有 Pod 挪到另外 2 台上,所以平时所有 Pod 的 requests 加起来,不宜超过集群总容量的三分之二左右。

在机房里怎么落地

k8s 的思路是把节点当成可以随时替换的资源:节点出了问题,与其登录上去慢慢修,不如把它移出集群、重装系统、再加回来。这要求节点之间的硬件和系统尽量一致,重装也要足够快。Toplink DCIM 的 IPMI 远程管理可以把一批服务器设为从 PXE 启动、由任务队列批量重装,坏掉的节点远程重装后重新加入集群即可;机柜与资产会向服务器下发采集脚本,记录每台机器的 CPU、内存、硬盘配置并保留历史,节点的配件被更换或者配置对不上,在台账里能直接看出来,不会等到调度出问题才发现。

常见问题

学 k8s 之前要先学 Docker 吗?

建议先学。k8s 里运行的就是容器镜像,镜像怎么构建、容器怎么启动、端口和数据卷怎么映射,这些在 Docker 上更容易理解。会用 Docker 和 Docker Compose 跑起一个多容器应用,再学 k8s 的 Pod、Deployment、Service 会顺很多。

数据库适合放进 k8s 吗?

能放,但不建议起步就放。数据库依赖稳定的存储和网络,迁移、备份、故障切换都比无状态服务复杂。常见做法是先把 Web、API 这类无状态服务搬进 k8s,数据库继续跑在独立的服务器上,等团队熟悉了持久化存储和相关的运维工具后再评估。

k8s 能管理虚拟机吗?

原生的 k8s 只管容器。社区有 KubeVirt 这类扩展项目,可以在 k8s 上运行和管理虚拟机,但这属于额外的组件。只是想把物理机切成虚拟机,用 ESXi、Proxmox VE 等虚拟化平台更直接。

想看看在你的机房里怎么用?

从一次产品演示开始,梳理你的业务链路。

查看价格
服务热线 400-112-2951

让我们聊聊你的 IDC 业务

扫码添加企业微信,预约产品演示或申请试用。

Toplink 企业微信二维码

长按保存或使用企业微信 / 微信扫描

也可致电
400-112-2951
Telegram
@TopLink88