Kubernetes 是什么
Kubernetes 将集群中的机器分为一个 Master
和一些 Node
在 Master 上运行着集群管理相关的一组进程:
kube-apiserver
kube-controller-manager
kube-scheduler
Node
作为集群中的工作节点, 运行真正的应用程序
在 Node
上 Kubernetes 管理的最小运行单元是 Pod
在 Node
上运行着 Kubernetes 的 kubelet
,kube-proxy
Kubernetes 的基本概念和术语
Master
Master
指的是集群控制节点
所有控制命令都发给它, 它负责具体的执行过程
在 Master
上运行着以下关键进程:
- Kubernetes API Server (
kube-apiserver
)- 集群控制的入口进程
- 集群资源的增删改查操作入口
- Kubernetes Controller Manager (
kube-controller-manager
)- 所有资源对象的自动化控制中心
- Kubernetes Scheduler (
kube-scheduler
)- 负责资源调度的进程
Node
在每个 Node
上运行以下关键进程:
kubelet
- 负责 Pod 对应的容器的创建, 启停等任务
kube-proxy
- 实现 Services 的通信与负载均衡机制
- 容器运行时
Pod
每个 Pod 都有一个特殊的”根容器” Pause容器
Pause容器
对应的镜像术语 Kubernetes 平台的一部分
每个 Pod 还包含一个或多个紧密相关的用户业务容器
引入业务无关的 Pause容器
作为 Pod 的根容器, 以它的状态代表整个容器组的状态
多个业务容器共享 Pause容器
的 IP, 共享 Pause容器
挂载的 Volume. 简化了关联的容器之间的通信问题, 解决了它们之间的文件共享问题
Kubernetes 为每个 Pod 都分配了唯一的 IP 地址, 称之为 Pod IP
一个 Pod 中的多个容器共享 Pod IP
地址
Kubernetes 要求底层网络支持集群内任意两个 Pod 之间的 TCP/IP 直接通信
这通常采用虚拟二层网络技术来实现
在 Kubernetes 中, 一个 Pod 里的容器与另外主机上的 Pod 容器能够直接通信
Pod 有两种类型:
- 普通 Pod
- 静态 Pod (
Static Pod
)
Static Pod
没有被存储在 etcd 中, 而是被存放在某个具体的 Node 中一个具体文件上, 并且只在此 Node 上启动, 运行
当 Pod 里的某个容器停止时, Kubernetes 会自动检测到这个问题并且重新启动这个 Pod (重启 Pod 里的所有容器)
Label
Deployment
, ReplicaSet
, DaemonSet
, Job
可以在 Selector
中使用基于集合的筛选条件定义:
selector:
matchLabels:
app: myweb
matchExpressions:
- {key: tier, operator: In, values: [frontend]}
- {key: environment, operator: NotIn, values: [dev]}
可用运算符包括:
In
NotIn
Exists
DoesNotExist
Label Selector 的重要使用场景:
kube-controller-manager
通过 Label Selector 来筛选要监控的 Pod 副本数量kube-proxy
通过 Service 的 Label Selector 来选择对应的 Podkube-scheduler
可以实现 Pod 定向调度的特性
ReplicationController
在 Kubernetes 1.2 中, ReplicationController
升级为另外一个新概念: ReplicaSet
ReplicaSet
支持基于集合的 Label Selector
ReplicationController
只支持基于等式的 Label Selector
很少单独使用 ReplicaSet
, 它主要被 Deployment
这个更高层的资源对象所使用
Deployment
Deployment
内部使用了 ReplicaSet
Deployment
随时知道当前 Pod “部署”的进度
Horizontal Pod Autoscaler
横向 Pod 自动扩容
HPA
HPA 也是一种资源对象
HPA 通过跟踪分析指定 ReplicaSet
控制的所有目标 Pod 的负载变化情况, 来确定是否需要有针对性地调整目标 Pod 的副本数量
HPA 有如下 Pod 负载度量指标:
CPUUtilizationPercentage
- 应用程序自定义度量指标, 如 TPS, QPS
CPUUtilizationPercentage
是一个算数平均值, 即目标 Pod 所有副本自身的 CPU 利用率的平均值
一个 Pod 自身的 CPU 利用率是该 Pod 当前 CPU 的使用量除以它的 Pod Request 的值
如果目标 Pod 没有定义 Pod Request 的值, 则无法使用 CPUUtilizationPercentage
实现 Pod 的横向自动扩容
在 CPUUtilizationPercentage
计算过程中使用到的 Pod 的 CPU 使用量通常是 1 min 内的平均值
可以从 Kubernetes Monitoring Architecture 来获取目标资源对象的性能数据
HPA 定义例子:
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
namespace: default
spec:
maxReplicas: 1
minReplicas: 10
scaleTargetRef:
kind: Deployment
name: php-apache
targetCPUUtilizationPercentage: 90
StatefulSet
StatefulSet
里的每个 Pod 都有稳定的, 唯一的网络标识
StatefulSet
控制的 Pod 副本的启停顺序是受控的
StatefulSet
里的 Pod 采用稳定的持久化存储卷, 通过 PV 或 PVC 来实现
StatefulSet
除了要与 PV 卷捆绑使用以存储 Pod 的状态数据, 还要与 Headless Service
配合使用
在每个 StatefulSet
定义中, 都要声明它属于哪个 Headless Service
Headless Service
与普通 Service 的关键区别在于, 它没有 Cluster IP
如果解析 Headless Service
的 DNS 域名, 则返回的是该 Service 对应的全部 Pod 的 Endpoint 列表
StatefulSet
在 Headless Service
的基础上又为 StatefulSet
控制的每个 Pod 实例都创建了一个 DNS 域名
这个域名格式为: ${podname}.${headless service name}
Service
运行在每个 Node 上的 kube-proxy
进程负责把对 Service 的请求转发到后端的某个 Pod 实例上, 并在内部实现服务的负载均衡与会话保持机制
每个 Service 都被分配了一个全局唯一的虚拟 IP 地址, 这个虚拟 IP 被称为 Cluster IP
在 Service 的整个生命周期中, 它的 Cluster IP
不会发生改变
外部系统访问 Service 的问题
Node IP
: Node 的 IP 地址Pod IP
: Pod 的 IP 地址Cluster IP
: Service 的 IP 地址
Node IP
是 Kubernetes 集群中每个节点的物理网卡的 IP 地址, 是一个真实存在的物理网络
Pod IP
:
- 是每个 Pod 的 IP 地址
- 根据 docker0 网桥的 IP 地址段进行分配
- 通常是一个虚拟的二层网络
- Kubernetes 要求位于不同 Node 上的 Pod 能够彼此直接通信, 所以 Kubernetes 里的一个 Pod 里的容器访问另一个 Pod 里的容器时, 就是通过 Pod IP 所在的虚拟二层网络进行通信的, 而真实的 TCP/IP 流量是通过 Node IP 所在的物理网卡流出的
Cluster IP
:
Cluster IP
仅作用于 Kubernetes Service 对象, 并由 Kubernetes 管理和分配 IP 地址Cluster IP
无法被 Ping, 因为没有一个”实体网络对象”来响应Cluster IP
只能结果 Service Port 组成一个具体的通信端口, 单独的Cluster IP
不具备 TCP/IP 通信的基础- 在 Kubernetes 集群内,
Node IP
,Pod IP
,Cluster IP
之间的通信, 采用的是 Kubernetes 自己设计的一种编程方式的特殊路由规则
Service 的 Cluster IP
属于 Kubernetes 集群内部的地址, 无法在集群外部直接使用这个地址
可以采用 NodePort
来解决这个问题:
apiVersion: v1
kind: Service
metadata:
name: tomcat-service
spec:
type: NodePort
ports:
- port: 8080
nodePort: 31002
selector:
tier: frontend
通过 http://<nodePort IP>:31002
即可访问
NodePort
的实现方式是在 Kubernetes 集群里的每个 Node 上都为需要外部访问的 Service 开启一个对应的 TCP 监听端口, 外部系统只要用任意一个 Node 的 IP 地址加上具体的 NodePort 端口号即可访问此服务
Job
Job 生成的 Pod 副本是不能自动重启的, 对应的 Pod 副本的 RestartPolicy
都被设置成 Never
Job 所控制的 Pod 副本的工作模式能够多实例并行计算
Volume
Volume (存储卷) 是Pod 中能够被多个容器访问的共享目录
Volume 被定义在 Pod 上
使用:
spec:
volumes:
- name: datavol
emptyDir: {}
containers:
- name: tomcat-demo
image: tomcat
volumeMounts:
- mountPath: /mydata-data
name: datavol
imagePullPolicy: IfNotPresent
Volume 类型
emptyDir
一个 emptyDir
Volume 是在 Pod 分配到 Node 时创建的
初始内容为空, 无须指定宿主机上对应的目录文件
因为这是 Kubernetes 自动分配的一个目录
当 Pod 从 Node 移除时, emptyDir
中的数据也会被永久删除
emptyDir
的一些用途:
- 临时空间
- CheckPoint 的临时保存目录
- 多容器共享目录
目前, 用户无法控制 emptyDir
使用的介质种类
hostPath
hostPath
为在 Pod 上挂载宿主机上的文件或目录
用途:
- 容器应用程序生成的日志文件需要永久保存时
- 需要访问宿主机上 Docker 引擎内部数据结构的容器应用时, 可以通过定义
hostPath
为宿主机/var/lib/docker
目录, 使容器内部应用可以直接访问 Docker 的文件系统
注意:
- 可能会因为宿主机上的目录和文件不同, 导致对 Volume 上目录和文件的访问结果不一致
- 如果使用了资源配额管理, 则 Kubernetes 无法将
hostPath
在宿主机上使用的资源纳入管理
NFS
使用 NFS 网络文件系统提供的共享目录存储数据时, 需要在系统中部署一个 NFS Server
volumes:
- name: nfs
nfs:
server: nfs-server.localhost
path: "/"
Persistent Volume
PV 可以理解为 Kubernetes 集群中的某个网络存储对应的一块存储
- PV 只能是网络存储, 不属于任何 Node, 但可以在每个 Node 上访问
- PV 并不是被定义在 Pod 上的, 而是独立于 Pod 之外定义的
- PV 目前支持的类型包括
- FC (Fibre Channel)
- Flocker
- NFS
- GlusterFS
- HostPath (仅供单机测试)
Example - NFS 类型的 PV 定义:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0003
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
nfs:
path: /somepath
server: 172.17.0.1
PV 的 accessModes
属性:
ReadWriteOnce
: 读写权限, 并且只能被单个 Node 挂载ReadOnlyMany
: 只读权限, 允许被多个 Node 挂载ReadWriteMany
: 读写权限, 允许被多个 Node 挂载
如果某个 Pod 想申请某种类型的 PV, 则首先需要定义一个 PersistentVolumeClaim
对象:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: myclaim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 8Gi
然后, 在 Pod 的 Volume 定义中引用上述 PersistentVolumeClaim
即可:
volumes:
- name: mypd
persistentVolumeClaim:
claimName: myclaim
PV 是有状态的对象:
Available
: 空闲状态Bound
: 已经绑定到某个 PVC 上Released
: 对应的 PVC 已经被删除, 但资源还没有被集群回收Failed
: PV 自动回收失败
Namespace
用于实现多租户的资源隔离
默认会创建并使用一个名称为 default
的 Namespace
使用 --namespace
参数来指定 Namespace
Annotation
用户任意定义的附加信息
ConfigMap
配置项可以作为 Map 表中的一个项, 整个 Map 的数据可以被持久化存储在 Kubernetes 的 Etcd 数据库中, 然后提供 API 以方便 Kubernetes 相关组件或客户应用 CRUD 操作这些数据
这个专门用来保存配置参数的 Map 就是 Kubernetes ConfigMap 资源对象
Kubernetes 提供了一种内建机制, 将存储在 etcd 中的 ConfigMap 通过 Volume 映射的方式变成目标 Pod 内的配置文件
不管目标 Pod 被调度到哪台服务器上, 都会完成自动映射
如果 ConfigMap 中的 key-value 数据被修改, 则映射到 Pod 中的”配置文件”也会随之自动更新