K8s

前言

k8s 大名鼎鼎,是go语言的代表之作,但是作为后端RD一般是接触不到的,通常操作都已经白屏化了。我说有些鸡架会问,顺便学一下,省着没事打游戏。仅作为了解,浅浅的从八股的角度学习一下。

总览

按照 What Why How 的顺序进行

What

Kubernetes :可移植、可扩展的开源平台,用于管理容器化的工作负载和服务,方便进行声明式配置和自动化。

说人话就是 Docker -> Docker Compose -> K8s

架构:

Kubernetes架构
Control Plane·Node·Pod·Container
控制平面·CONTROL PLANE
kube-apiserver
集群唯一入口,提供REST API
etcd
键值存储,保存集群全部状态
kube-scheduler
决定Pod调度到哪个节点
kube-controller-manager
运行控制器,持续逼近期望状态
kubelet监听/watch · 上报节点与Pod状态
●NODE 1
kubeletkube-proxy
Container Runtime·containerd
●Pod
container
container
●Pod
container
●NODE 2
kubeletkube-proxy
Container Runtime·containerd
●Pod
container
●Pod
container
container
所有组件只与kube-apiserver通信,彼此不直接交互;etcd是唯一的持久化存储。
Pod是最小调度单元,内部可包含一个或多个共享网络与存储的容器。

组件作用:

控制面:

  • kube-apiserver: REST API

  • etcd:分布式KV存储

  • kube-scheduler:监听尚未绑定Node的 Pod,只负责选出应该去哪个 Node

  • kube-controller-manager:一堆控制器,每一个负责一类资源(运行的 Pod 个数,完成的 Job 个数等等)。如果每个是一个死循环,如果运行状态和期望不一样,就进行纠偏。

工作节点:

  • kubelet:和 apiserver 通信

  • kube-proxy:Service (Service 是一组 Pod 的稳定抽象入口)会被 apiserver 分配一个虚拟的内网 IP(ClusterIP)。通过写 iptables / IPVS 规则,实现这个 Node 上的 Pod(或主机)访问这个虚拟 IP 时,自动映射到某个真实 Pod IP,并做负载均衡。

  • Container Runtime:真正运行容器的组件,通过 CRI (Container Runtime Interface ,类似于 DDD 的依赖倒置思想,让 docker / rkt 实现相关抽象接口的操作)被 kubelet 调用,负责 Pod 的生命周期。

负载单位:

  • Pod:最小调度单元。同一个 Pod 内的容器共享 Network Namespace 和 Volume,互相连通。类似一个 docker compose
  • Container:同 Docker 里面的 container 大小

提供的功能:

  • 服务发现和负载均衡
  • 存储编排:挂载本地盘/远端存储
  • 自动部署和回滚:RD传说中的一键发版
  • 自动完成装箱计算:一个 Node 上可以跑很多个 Pod,Kubernetes 会自己决定哪个 Pod 放到哪个 Node 上。
  • 自我修复
  • 密钥与配置管理:ConfigMap 存非敏感配置,Secret 存敏感信息(base64编码,非安全,需要配合其它加密)。
  • 批处理执行 :训练/离线推理场景
    • Job:保证成功完成指定数量的 Pod。
    • CronJob:定时跑批
  • 水平扩缩 :单节点资源压力大自动扩容,扩的是Pod
  • IPv4/IPv6 双栈
  • 为可扩展性设计:在不改变上游源代码的情况下为你的 Kubernetes 集群添加功能

Why

显而易见,上面提供的功能太多了,比黑屏部署强多了

How

只讲容器的实现即资源隔离机制,因为其它的实现显然是业务/分布式上的逻辑,和操作系统没什么关系。

namespace: 给一组进程套上资源可见性显示,如 PID、网络、主机名、挂载点、用户。

注意存在一个特殊的 PID = 1 进程(docker 的第一个进程),宿主机看到的是类似 12345 的常见 PID,而在容器内它是 1。

最佳实践:

  1. 应用直接以 exec 形式启动,成为 PID 1。
  2. 应用自己处理 SIGTERM、回收子进程。
  3. 如果应用做不到,使用 docker run --init 或 tini / dumb-init。
  4. 避免 shell 形式启动,避免 --pid=host。
  5. 合理设置 STOPSIGNAL 和停止超时。

cgroups: 给一组进程套上资源限制和分配优先级

一些QA

  1. k8s 的服务发现和 consul 的区别
  2. gpu 推理 k8s 的不足