k8s简介
https://kuboard.cn/learning/k8s-basics/explore.html#pods概述 教程地址1.Kubernetes简介Kubernetes是一个可以移植、可扩展的开源平台,使用 声明式的配置 并依据配置信息自动地执行容器化应用程序的管理。在所有的容器编排工具中(类似的还有 docker swarm / mesos等),Kubernetes的生态系统更大、增长..
https://kuboard.cn/learning/k8s-basics/explore.html#pods概述 教程地址
1.Kubernetes简介
Kubernetes是一个可以移植、可扩展的开源平台,使用 声明式的配置 并依据配置信息自动地执行容器化应用程序的管理。在所有的容器编排工具中(类似的还有 docker swarm / mesos等),Kubernetes的生态系统更大、增长更快,有更多的支持、服务和工具可供用户选择。
2.Kubernetes的功能 容器化编排解决方案
Kubernetes提供的特性有
服务发现和负载均衡
存储编排
自动发布和回滚
自愈
Kubernetes提供如下自愈能力:
重启已经停机的容器
替换、kill 那些不满足自定义健康检查条件的容器
在容器就绪之前,避免调用者发现该容器
密钥及配置管理
3.Kubernetes master组件
Master组件是集群的控制平台(control plane):
master 组件负责集群中的全局决策(例如,调度)
master 组件探测并响应集群事件(例如,当 Deployment 的实际 Pod 副本数未达到 replicas 字段的规定时,启动一个新的 Pod)
Master组件可以运行于集群中的任何机器上。但是,为了简洁性,通常在同一台机器上运行所有的 master 组件,且不在此机器上运行用户的容器。
1)kube-apiserver
此 master 组件提供 Kubernetes API。这是Kubernetes控制平台的前端(front-end),可以水平扩展(通过部署更多的实例以达到性能要求)。kubectl / kubernetes dashboard / kuboard 等Kubernetes管理工具就是通过 kubernetes API 实现对 Kubernetes 集群的管理。
2)etcd
支持一致性和高可用的名值对存储组件,Kubernetes集群的所有配置信息都存储在
etcd 中。
3)kube-scheduler
此 master 组件监控所有新创建尚未分配到节点上的 Pod,并且自动选择为 Pod 选择一个合适的节点去运行。
影响调度的因素有:
单个或多个 Pod 的资源需求
硬件、软件、策略的限制
亲和与反亲和(affinity and anti-affinity)的约定
数据本地化要求
工作负载间的相互作用
4)kube-controller-manager
此 master 组件运行了所有的控制器
逻辑上来说,每一个控制器是一个独立的进程,但是为了降低复杂度,这些控制器都被合并运行在一个进程里。
kube-controller-manager 中包含的控制器有:
节点控制器: 负责监听节点停机的事件并作出对应响应
副本控制器: 负责为集群中每一个 副本控制器对象(Replication Controller Object)维护期望的 Pod 副本数
端点(Endpoints)控制器:负责为端点对象(Endpoints Object,连接 Service 和 Pod)赋值
Service Account & Token控制器: 负责为新的名称空间创建 default Service Account 以及 API Access Token
5)cloud-controller-manager
cloud-controller-manager 中运行了与具体云基础设施供应商互动的控制器。这是 Kubernetes 1.6 版本中引入的特性,尚处在 alpha 阶段。
cloud-controller-manager 只运行特定于云基础设施供应商的控制器。如果您参考 www.kuboard.cn 上提供的文档安装 Kubernetes 集群,默认不安装 cloud-controller-manager。
cloud-controller-manager 使得云供应商的代码和 Kubernetes 的代码可以各自独立的演化。在此之前的版本中,Kubernetes的核心代码是依赖于云供应商的代码的。在后续的版本中,特定于云供应商的代码将由云供应商自行维护,并在运行Kubernetes时链接到 cloud-controller-manager。
4.Kubernetes Node组件
Node 组件运行在每一个节点上(包括 master 节点和 worker 节点),负责维护运行中的 Pod 并提供 Kubernetes 运行时环境
1)kubelet
此组件是运行在每一个集群节点上的代理程序。它确保 Pod 中的容器处于运行状态。Kubelet 通过多种途径获得 PodSpec 定义,并确保 PodSpec 定义中所描述的容器处于运行和健康的状态。Kubelet不管理不是通过 Kubernetes 创建的容器。
2)kube-proxy
kube-proxy 是一个网络代理程序,运行在集群中的每一个节点上,是实现 Kubernetes Service 概念的重要部分。
kube-proxy 在节点上维护网络规则。这些网络规则使得您可以在集群内、集群外正确地与 Pod 进行网络通信。如果操作系统中存在 packet filtering layer,kube-proxy 将使用这一特性(iptables代理模式),否则,kube-proxy将自行转发网络请求(User space代理模式)
3)容器引擎
容器引擎负责运行容器。Kubernetes支持多种容器引擎:Docker、containerd、cri-o、rktlet 以及任何实现了 Kubernetes容器引擎接口 的容器引擎
5.Kubernetes Addons组件
Addons 使用 Kubernetes 资源(DaemonSet、Deployment等)实现集群的功能特性。由于他们提供集群级别的功能特性,addons使用到的Kubernetes资源都放置在 kube-system 名称空间下。
1)DNS
除了 DNS Addon 以外,其他的 addon 都不是必须的,所有 Kubernetes 集群都应该有 Cluster DNS
Cluster DNS 是一个 DNS 服务器,是对您已有环境中其他 DNS 服务器的一个补充,存放了 Kubernetes Service 的 DNS 记录。
Kubernetes 启动容器时,自动将该 DNS 服务器加入到容器的 DNS 搜索列表中。
2)Web UI(Dashboard)
Dashboard 是一个Kubernetes集群的 Web 管理界面。用户可以通过该界面管理集群。
3)Kuboard
Kuboard 是一款基于Kubernetes的微服务管理界面,相较于 Dashboard,Kuboard 强调:
无需手工编写 YAML 文件
微服务参考架构
上下文相关的监控
场景化的设计
导出配置
导入配置
4)ContainerResource Monitoring
Container Resource Monitoring 将容器的度量指标(metrics)记录在时间序列数据库中,并提供了 UI 界面查看这些数据
5)Cluster-level Logging
Cluster-level logging 机制负责将容器的日志存储到一个统一存储中,并提供搜索浏览的界面
6.k8s集群简单介绍
上图描述的是拥有一个Master(主)节点和三个Worker(工作)节点的k8s集群
Master 负责管理集群 负责协调集群中的所有活动,例如调度应用程序,维护应用程序的状态,扩展和更新应用程序。
Worker节点(即图中的Node)是VM(虚拟机)或物理计算机,充当k8s集群中的工作计算机。 每个Worker节点都有一个Kubelet,它管理该Worker节点并负责与Master节点通信。该Worker节点还应具有用于处理容器操作的工具,例如Docker。
7.部署一个应用程序
1)创建文件 nginx-deployment.yaml,内容如下:
apiVersion: apps/v1 #与k8s集群版本有关,使用 kubectl api-versions 即可查看当前集群支持的版本
kind: Deployment #该配置的类型,我们使用的是 Deployment
metadata: #译名为元数据,即 Deployment 的一些基本属性和信息
name: nginx-deployment #Deployment 的名称
labels: #标签,可以灵活定位一个或多个资源,其中key和value均可自定义,可以定义多组,目前不需要理解
app: nginx #为该Deployment设置key为app,value为nginx的标签
spec: #这是关于该Deployment的描述,可以理解为你期待该Deployment在k8s中如何使用
replicas: 1 #使用该Deployment创建一个应用程序实例
selector: #标签选择器,与上面的标签共同作用,目前不需要理解
matchLabels: #选择包含标签app:nginx的资源
app: nginx
template: #这是选择或创建的Pod的模板
metadata: #Pod的元数据
labels: #Pod的标签,上面的selector即选择包含标签app:nginx的Pod
app: nginx
spec: #期望Pod实现的功能(即在pod中部署)
containers: #生成container,与docker中的container是同一种
- name: nginx #container的名称
image: nginx:1.7.9 #使用镜像nginx:1.7.9创建container,该container默认80端口可访问
2)应用 YAML 文件
kubectl apply -f nginx-deployment.yaml
3)查看部署结果
# 查看 Deployment
kubectl get deployments
# 查看 Pod
kubectl get pods
8.Kubernetes Pods
Pod 容器组 是一个k8s中一个抽象的概念,用于存放一组 container(可包含一个或多个 container 容器,即图上正方体),以及这些 container (容器)的一些共享资源。这些资源包括:
共享存储,称为卷(Volumes),即图上紫色圆柱
网络,每个 Pod(容器组)在集群中有个唯一的 IP,pod(容器组)中的 container(容器)共享该IP地址
container(容器)的基本信息,例如容器的镜像版本,对外暴露的端口等
Pod(容器组)是 k8s 集群上的最基本的单元。当我们在 k8s 上创建 Deployment 时,会在集群上创建包含容器的 Pod (而不是直接创建容器)。每个Pod都与运行它的 worker 节点(Node)绑定,并保持在那里直到终止或被删除。如果节点(Node)发生故障,则会在群集中的其他可用节点(Node)上运行相同的 Pod(从同样的镜像创建 Container,使用同样的配置,IP 地址不同,Pod 名字不同)。
9.Node(节点)
Pod(容器组)总是在 Node(节点) 上运行。Node(节点)是 kubernetes 集群中的计算机,可以是虚拟机或物理机。每个 Node(节点)都由 master 管理。一个 Node(节点)可以有多个Pod(容器组),kubernetes master 会根据每个 Node(节点)上可用资源的情况,自动调度 Pod(容器组)到最佳的 Node(节点)上。
每个 Kubernetes Node(节点)至少运行:
Kubelet,负责 master 节点和 worker 节点之间通信的进程;管理 Pod(容器组)和 Pod(容器组)内运行的 Container(容器)。
容器运行环境(如Docker)负责下载镜像、创建和运行容器等。
10.常用命令
kubectl get - 显示资源列表
# kubectl get 资源类型
#获取类型为Deployment的资源列表
kubectl get deployments
#获取类型为Pod的资源列表
kubectl get pods
#获取类型为Node的资源列表
kubectl get nodes
名称空间
在命令后增加 -A 或 --all-namespaces 可查看所有 名称空间中 的对象,使用参数 -n 可查看指定名称空间的对象,例如
# 查看所有名称空间的 Deployment
kubectl get deployments -A
kubectl get deployments --all-namespaces
# 查看 kube-system 名称空间的 Deployment
kubectl get deployments -n kube-system
kubectl describe - 显示有关资源的详细信息
# kubectl describe 资源类型 资源名称
#查看名称为nginx-XXXXXX的Pod的信息
kubectl describe pod nginx-XXXXXX
#查看名称为nginx的Deployment的信息
kubectl describe deployment nginx
kubectl logs - 查看pod中的容器的打印日志(和命令docker logs 类似)
# kubectl logs Pod名称
#查看名称为nginx-pod-XXXXXXX的Pod内的容器打印的日志
#本案例中的 nginx-pod 没有输出日志,所以您看到的结果是空的
kubectl logs -f nginx-pod-XXXXXXX
kubectl exec - 在pod中的容器环境内执行命令(和命令docker exec 类似)
# kubectl exec Pod名称 操作命令
# 在名称为nginx-pod-xxxxxx的Pod中运行bash
kubectl exec -it nginx-pod-xxxxxx /bin/bash
11.公布应用程序 Kubernetes Service(服务)概述
事实上,Pod(容器组)有自己的 生命周期。当 worker node(节点)故障时,节点上运行的 Pod(容器组)也会消失。然后,Deployment 可以通过创建新的 Pod(容器组)来动态地将群集调整回原来的状态,以使应用程序保持运行。
举个例子,假设有一个图像处理后端程序,具有 3 个运行时副本。这 3 个副本是可以替换的(无状态应用),即使 Pod(容器组)消失并被重新创建,或者副本数由 3 增加到 5,前端系统也无需关注后端副本的变化。由于 Kubernetes 集群中每个 Pod(容器组)都有一个唯一的 IP 地址(即使是同一个 Node 上的不同 Pod),我们需要一种机制,为前端系统屏蔽后端系统的 Pod(容器组)在销毁、创建过程中所带来的 IP 地址的变化。
Kubernetes 中的 Service(服务) 提供了这样的一个抽象层,它选择具备某些特征的 Pod(容器组)并为它们定义一个访问方式。Service(服务)使 Pod(容器组)之间的相互依赖解耦(原本从一个 Pod 中访问另外一个 Pod,需要知道对方的 IP 地址)。一个 Service(服务)选定哪些 Pod(容器组) 通常由 LabelSelector(标签选择器) 来决定。
在创建Service的时候,通过设置配置文件中的 spec.type 字段的值,可以以不同方式向外部暴露应用程序:
ClusterIP(默认)
在群集中的内部IP上公布服务,这种方式的 Service(服务)只在集群内部可以访问到
NodePort
使用 NAT 在集群中每个的同一端口上公布服务。这种方式下,可以通过访问集群中任意节点+端口号的方式访问服务 <NodeIP>:<NodePort>。此时 ClusterIP 的访问方式仍然可用。
LoadBalancer
在云环境中(需要云供应商可以支持)创建一个集群外部的负载均衡器,并为使用该负载均衡器的 IP 地址作为服务的访问地址。此时 ClusterIP 和 NodePort 的访问方式仍然可用。
服务和标签
Service 将外部请求路由到一组 Pod 中,它提供了一个抽象层,使得 Kubernetes 可以在不影响服务调用者的情况下,动态调度容器组(在容器组失效后重新创建容器组,增加或者减少同一个 Deployment 对应容器组的数量等)。
Service使用 Labels、LabelSelector(标签和选择器) 匹配一组 Pod。Labels(标签)是附加到 Kubernetes 对象的键/值对,其用途有多种:
将 Kubernetes 对象(Node、Deployment、Pod、Service等)指派用于开发环境、测试环境或生产环境
嵌入版本标签,使用标签区别不同应用软件版本
使用标签对 Kubernetes 对象进行分类
下图体现了 Labels(标签)和 LabelSelector(标签选择器)之间的关联关系
Deployment B 含有 LabelSelector 为 app=B 通过此方式声明含有 app=B 标签的 Pod 与之关联
通过 Deployment B 创建的 Pod 包含标签为 app=B
Service B 通过标签选择器 app=B 选择可以路由的 Pod
12.伸缩应用程序
伸缩 的实现可以通过更改 nginx-deployment.yaml 文件中部署的 replicas(副本数)来完成
spec:
replicas: 2 #使用该Deployment创建两个应用程序实例
13.执行滚动更新
用户期望应用程序始终可用,为此开发者/运维者在更新应用程序时要分多次完成。在 Kubernetes 中,这是通过 Rolling Update 滚动更新完成的。Rolling Update滚动更新 通过使用新版本的 Pod 逐步替代旧版本的 Pod 来实现 Deployment 的更新,从而实现零停机。新的 Pod 将在具有可用资源的 Node(节点)上进行调度。
在上一个模块中,我们学习了将应用程序 Scale Up(扩容)为多个实例,这是执行更新而不影响应用程序可用性的前提(如果只有个实例那还玩啥)。默认情况下,Rolling Update 滚动更新 过程中,Kubernetes 逐个使用新版本 Pod 替换旧版本 Pod(最大不可用 Pod 数为 1、最大新建 Pod 数也为 1)。这两个参数可以配置为数字或百分比。在Kubernetes 中,更新是版本化的,任何部署更新都可以恢复为以前的(稳定)版本。
滚动更新概述
1)原本 Service A 将流量负载均衡到 4 个旧版本的 Pod (当中的容器为 绿色)上
2)更新完 Deployment 部署文件中的镜像版本后,master 节点选择了一个 worker 节点,并根据新的镜像版本创建 Pod(紫色容器)。新 Pod 拥有唯一的新的 IP。同时,master 节点选择一个旧版本的 Pod 将其移除。
此时,Service A 将新 Pod 纳入到负载均衡中,将旧Pod移除
3)同步骤2,再创建一个新的 Pod 替换一个原有的 Pod
4)如此 Rolling Update 滚动更新,直到所有旧版本 Pod 均移除,新版本 Pod 也达到 Deployment 部署文件中定义的副本数,则滚动更新完成
14.kubernates 节点
Kubernetes中节点(node)指的是一个工作机器,曾经叫做 minion。不同的集群中,节点可能是虚拟机也可能是物理机。每个节点都由 master 组件管理,并包含了运行 Pod(容器组)所需的服务。这些服务包括:
容器引擎
kubelet
kube-proxy
节点状态
节点的状态包含如下信息:
Addresses
Conditions
Capacity and Allocatable
Info
查看所有节点的列表:
kubectl get nodes -o wide
查看节点状态以及节点的其他详细信息
kubectl describe node
输出结果如下所示
Name: demo-worker-temp-01
Roles: <none>
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=demo-worker-temp-01
kubernetes.io/os=linux
Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock
node.alpha.kubernetes.io/ttl: 0
projectcalico.org/IPv4Address: 172.17.216.105/20
projectcalico.org/IPv4IPIPTunnelAddr: 192.168.199.128
volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp: Mon, 30 Sep 2019 06:30:16 +0800
Taints: <none>
Unschedulable: false
Conditions:
Type Status LastHeartbeatTime LastTransitionTime Reason Message
---- ------ ----------------- ------------------ ------ -------
NetworkUnavailable False Wed, 02 Oct 2019 22:37:33 +0800 Wed, 02 Oct 2019 22:37:33 +0800 CalicoIsUp Calico is running on this node
MemoryPressure False Sun, 06 Oct 2019 13:44:41 +0800 Mon, 30 Sep 2019 06:30:16 +0800 KubeletHasSufficientMemory kubelet has sufficient memory available
DiskPressure False Sun, 06 Oct 2019 13:44:41 +0800 Mon, 30 Sep 2019 06:30:16 +0800 KubeletHasNoDiskPressure kubelet has no disk pressure
PIDPressure False Sun, 06 Oct 2019 13:44:41 +0800 Mon, 30 Sep 2019 06:30:16 +0800 KubeletHasSufficientPID kubelet has sufficient PID available
Ready True Sun, 06 Oct 2019 13:44:41 +0800 Wed, 02 Oct 2019 22:37:41 +0800 KubeletReady kubelet is posting ready status
Addresses:
InternalIP: 172.17.216.105
Hostname: demo-worker-temp-01
Capacity:
cpu: 2
ephemeral-storage: 41147472Ki
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 7733524Ki
pods: 110
Allocatable:
cpu: 2
ephemeral-storage: 37921510133
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 7631124Ki
pods: 110
System Info:
Machine ID: 20190711105006363114529432776998
System UUID: 841EC123-F92C-4A3A-BEC0-DAADDD625067
Boot ID: 70c08b02-45ed-456f-8deb-b5c0ebeab414
Kernel Version: 3.10.0-957.21.3.el7.x86_64
OS Image: CentOS Linux 7 (Core)
Operating System: linux
Architecture: amd64
Container Runtime Version: docker://18.9.7
Kubelet Version: v1.16.0
Kube-Proxy Version: v1.16.0
Non-terminated Pods: (21 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits AGE
--------- ---- ------------ ---------- --------------- ------------- ---
default nginx-deployment-5754944d6c-8lnlx 0 (0%) 0 (0%) 0 (0%) 0 (0%) 3d14h
example gateway-example-6f6f45cd6-mhggv 0 (0%) 0 (0%) 0 (0%) 0 (0%) 3d14h
example monitor-grafana-ff99b5b6f-sxppz 0 (0%) 0 (0%) 0 (0%) 0 (0%) 3d14h
kube-system calico-node-qjfqd 250m (12%) 0 (0%) 0 (0%) 0 (0%) 6d7h
kube-system eip-nfs-cluster-storage-6c9c7d46f4-lmxql 0 (0%) 0 (0%) 0 (0%) 0 (0%) 3d14h
kube-system kube-proxy-4xz9h 0 (0%) 0 (0%) 0 (0%) 0 (0%) 3d15h
kube-system monitor-prometheus-node-exporter-t7d24 0 (0%) 0 (0%) 0 (0%) 0 (0%) 2d20h
kuboard-blog cloud-busybox-867645c5dd-7l97b 0 (0%) 0 (0%) 0 (0%) 0 (0%) 3d14h
kuboard-blog db-wordpress-79d88d66b7-j7kj8 0 (0%) 0 (0%) 0 (0%) 0 (0%) 3d14h
kuboard-press svc-busybox-6cc877b848-2kl28 0 (0%) 0 (0%) 0 (0%) 0 (0%) 3d14h
kuboard-press web-kuboard-press-6d6f8bdbb8-c4q44 0 (0%) 0 (0%) 0 (0%) 0 (0%) 2d3h
nginx-ingress nginx-ingress-hsv26 0 (0%) 0 (0%) 0 (0%) 0 (0%) 6d7h
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
Resource Requests Limits
-------- -------- ------
cpu 250m (12%) 0 (0%)
memory 0 (0%) 0 (0%)
ephemeral-storage 0 (0%) 0 (0%)
Events: <none>
Addresses
依据你集群部署的方式(在哪个云供应商部署,或是在物理机上部署),Addesses 字段可能有所不同。
HostName: 在节点命令行界面上执行 hostname 命令所获得的值。启动 kubelet 时,可以通过参数 --hostname-override 覆盖
ExternalIP:通常是节点的外部IP(可以从集群外访问的内网IP地址;上面的例子中,此字段为空)
InternalIP:通常是从节点内部可以访问的 IP 地址
Conditions
Conditions 描述了节点的状态。Condition的例子有:
Node Condition 描述
OutOfDisk 如果节点上的空白磁盘空间不够,不能够再添加新的节点时,该字段为
True,其他情况为 False
Ready 如果节点是健康的且已经就绪可以接受新的 Pod。则节点Ready字段为 True。False表明了该节点不健康,不能够接受新的 Pod。
MemoryPressure 如果节点内存紧张,则该字段为 True,否则为False
PIDPressure 如果节点上进程过多,则该字段为 True,否则为 False
DiskPressure 如果节点磁盘空间紧张,则该字段为 True,否则为 False
NetworkUnvailable 如果节点的网络配置有问题,则该字段为 True,否则为 False
Node Condition 以一个 JSON 对象的形式存在。例如,下面的yaml 描述了一个健康状态下节点的 Condition,如下所示:
"conditions": [
{
"type": "Ready",
"status": "True",
"reason": "KubeletReady",
"message": "kubelet is posting ready status",
"lastHeartbeatTime": "2019-06-05T18:38:35Z",
"lastTransitionTime": "2019-06-05T11:41:27Z"
}
]
如果 Ready 类型Condition 的 status 持续为 Unkown 或者 False 超过 pod-eviction-timeout(kube-controller-manager的参数)所指定的时间,节点控制器(node controller)将对该节点上的所有 Pod 执行删除的调度动作。默认的 pod-eviction-timeout 时间是 5 分钟。某些情况下(例如,节点网络故障),apiserver 不能够与节点上的 kubelet 通信,删除 Pod 的指令不能下达到该节点的 kubelet 上,直到 apiserver 与节点的通信重新建立,指令才下达到节点。这意味着,虽然对 Pod 执行了删除的调度指令,但是这些 Pod 可能仍然在失联的节点上运行。
在 kubernetes v1.5 以前,节点控制器将从 apiserver 强制删除这些失联节点上的 Pod。在 v1.5 及以后的版本中,节点控制器将不会强制删除这些 Pod,直到已经确认他们已经停止运行为止。您可能会发现失联节点上的 Pod 仍然在运行(在该节点上执行 docker ps 命令可查看容器的运行状态),然而 apiserver 中,他们的状态已经变为 Terminating 或者 Unknown。如果 Kubernetes 不能通过 cloud-controller-manager 判断失联节点是否已经永久从集群中移除(例如,在虚拟机或物理机上自己部署 Kubernetes 的情况),集群管理员需要手工(通过 kubectl delete node your-node-name 命令)删除 apiserver 中的节点对象。此时,Kubernetes 将删除该节点上的所有 Pod。
在 Kubernetes v1.12 中,TaintNodesByCondition 特性进入 beta 阶段,此时 node lifecycle controller 将自动创建该 Condition 对应的 污点。相应地,调度器在选择合适的节点时,不再关注节点的 Condition,而是检查节点的污点和 Pod 的容忍。
Capacity and Allocatable(容量和可分配量)
容量和可分配量(Capacity and Allocatable)描述了节点上的可用资源的情况:
CPU
内存
该节点可调度的最大 pod 数量
Capacity 中的字段表示节点上的资源总数,Allocatable 中的字段表示该节点上可分配给普通 Pod 的资源总数。
Info
描述了节点的基本信息,例如:
Linux 内核版本
Kubernetes 版本(kubelet 和 kube-proxy 的版本)
Docker 版本
操作系统名称
15.节点管理
与 Pod 和 Service 不一样,节点并不是由 Kubernetes 创建的,节点由云供应商(例如,Google Compute Engine、阿里云等)创建,或者节点已经存在于您的物理机/虚拟机的资源池。向 Kubernetes 中创建节点时,仅仅是创建了一个描述该节点的 API 对象。节点 API 对象创建成功后,Kubernetes将检查该节点是否有效。例如,假设您创建如下节点信息:
kind: Node
apiVersion: v1
metadata:
name: "10.240.79.157"
labels:
name: "my-first-k8s-node"
Kubernetes 在 APIServer 上创建一个节点 API 对象(节点的描述),并且基于 metadata.name 字段对节点进行健康检查。如果节点有效(节点组件正在运行),则可以向该节点调度 Pod;否则,该节点 API 对象将被忽略,直到节点变为有效状态。
节点控制器(Node Controller)
节点控制器是一个负责管理节点的 Kubernetes master 组件。在节点的生命周期中,节点控制器起到了许多作用。
首先,节点控制器在注册节点时为节点分配 CIDR 地址块
第二,节点控制器通过云供应商(cloud-controller-manager)接口检查节点列表中每一个节点对象对应的虚拟机是否可用。在云环境中,只要节点状态异常,节点控制器检查其虚拟机在云供应商的状态,如果虚拟机不可用,自动将节点对象从 APIServer 中删除。
第三,节点控制器监控节点的健康状况。当节点变得不可触达时(例如,由于节点已停机,节点控制器不再收到来自节点的心跳信号),节点控制器将节点API对象的 NodeStatus Condition 取值从 NodeReady 更新为 Unknown;然后在等待 pod-eviction-timeout 时间后,将节点上的所有 Pod 从节点驱逐。
默认40秒未收到心跳,修改 NodeStatus Condition 为 Unknown;
默认 pod-eviction-timeout 为 5分钟
节点控制器每隔 --node-monitor-period 秒检查一次节点的状态
在 Kubernetes v1.13 以前,NodeStatus 记录了从节点发出的心跳信号。从 Kubernetes v1.13 开始,node lease 特性进入 alpha 阶段(KEP-0009)。当 node lease 特性被启用时,每个节点都有一个 kube-node-lease 名称空间下对应的 Lease 对象,节点控制器周期性地更新 Lease 对象;此时 NodeStatus 和 node lease 都被用来记录节点的心跳信号。
NodeStatus 的更新频率远高于 node lease,原因是:
每次节点向 master 发出心跳信号,NodeStatus 都将被更新
只有在 NodeStatus 发生改变,或者足够长的时间未接收到 NodeStatus 更新时,节点控制器才更新 node lease(默认为1分钟,比节点失联的超时时间40秒要更长)
由于 node lease 比 NodeStatus 更轻量级,该特性显著提高了节点心跳机制的效率,并使 Kubernetes 性能和可伸缩性得到了提升
在 Kubernetes v1.4 中,优化了节点控制器的逻辑以便更好的处理大量节点不能触达 master 的情况(例如,master 出现网络故障)。主要的优化点在于,节点控制器在决定是否执行 Pod 驱逐的动作时,会检查集群中所有节点的状态。
大多数情况下,节点控制器限制了驱逐 Pod 的速率为 --node-eviction-rate (默认值是0.1)每秒,即节点控制器每 10 秒驱逐 1 个 Pod。
当节点所在的高可用区出现故障时,节点控制器驱逐 Pod 的方式将不一样。节点控制器驱逐Pod前,将检查高可用区里故障节点的百分比(NodeReady Condition 的值为 Unknown 或 False):
如果故障节点的比例不低于 --unhealthy-zone-threshold(默认为 0.55),则降低驱逐 Pod 的速率
如果集群规模较小(少于等于 --large-cluster-size-threshold 个节点,默认值为 50),则停止驱逐 Pod
如果集群规模大于 --large-cluster-size-threshold 个节点,则驱逐 Pod 的速率降低到 --secondary-node-eviction-rate (默认值为 0.01)每秒
针对每个高可用区使用这个策略的原因是,某一个高可用区可能与 master 隔开了,而其他高可用区仍然保持连接。如果您的集群并未分布在云供应商的多个高可用区上,此时,您只有一个高可用区(即整个集群)。
将集群的节点分布到多个高可用区最大的原因是,在某个高可用区出现整体故障时,可以将工作负载迁移到仍然健康的高可用区。因此,如果某个高可用区的所有节点都出现故障时,节点控制器仍然使用正常的驱逐 Pod 的速率(–node-eviction-rate)。
最极端的情况是,所有的高可用区都完全不可用(例如,集群中一个健康的节点都没有),此时节点控制器 master 节点的网络连接出现故障,并停止所有的驱逐 Pod 的动作,直到某些连接得到恢复。
自 Kubernetes v1.6 开始,节点控制器同时也负责为带有 NoExecute 污点的节点驱逐其上的 Pod。此外,节点控制器还负责根据节点的状态(例如,节点不可用,节点未就绪等)为节点添加污点。参考 NoExecute 获取更多信息。
自 Kubernetes v1.8 开始,节点控制器可以根据节点的 Condition 为节点添加污点,此特性处于 alpha 阶段
#节点自注册(Self-Registration)
如果 kubelet 的启动参数 --register-node为 true(默认为 true),kubelet 会尝试将自己注册到 API Server。kubelet自行注册时,将使用如下选项:
--kubeconfig:向 apiserver 进行认证时所用身份信息的路径
--cloud-provider:向云供应商读取节点自身元数据
--register-node:自动向 API Server 注册节点
--register-with-taints:注册节点时,为节点添加污点(逗号分隔,格式为 <key>=<value>:<effect>
--node-ip:节点的 IP 地址
--node-labels:注册节点时,为节点添加标签
--node-status-update-frequency:向 master 节点发送心跳信息的时间间隔
如果 Node authorization mode 和 NodeRestriction admission plugin 被启用,kubelet 只拥有创建/修改其自身所对应的节点 API 对象的权限。
#手动管理节点
集群管理员可以创建和修改节点API对象。
如果管理员想要手工创建节点API对象,可以将 kubelet 的启动参数 --register-node 设置为 false。
管理员可以修改节点API对象(不管是否设置了 --register-node 参数)。可以修改的内容有:
增加/减少标签
标记节点为不可调度(unschedulable)
节点的标签与 Pod 上的节点选择器(node selector)配合,可以控制调度方式,例如,限定 Pod 只能在某一组节点上运行。请参考 将容器组调度到指定的节点。
执行如下命令可将节点标记为不可调度(unschedulable),此时将阻止新的 Pod 被调度到该节点上,但是不影响任何已经在该节点上运行的 Pod。这在准备重启节点之前非常有用。
kubectl cordon $NODENAME
节点容量(Node Capacity)
节点API对象中描述了节点的容量(Capacity),例如,CPU数量、内存大小等信息。通常,节点在向 APIServer 注册的同时,在节点API对象里汇报了其容量(Capacity)。如果您 手动管理节点,您需要在添加节点时自己设置节点的容量。
Kubernetes 调度器在调度 Pod 到节点上时,将确保节点上有足够的资源。具体来说,调度器检查节点上所有容器的资源请求之和不大于节点的容量。此时,只能检查由 kubelet 启动的容器,不包括直接由容器引擎启动的容器,更不包括不在容器里运行的进程。
16.集群内通信
Cluster to Master
所有从集群访问 Master 节点的通信,都是针对 apiserver 的(没有任何其他 master 组件发布远程调用接口)。通常安装 Kubernetes 时,apiserver 监听 HTTPS 端口(443),并且配置了一种或多种 客户端认证方式 authentication。至少需要配置一种形式的 授权方式 authorization,尤其是 匿名访问 anonymous requests 或 Service Account Tokens 被启用的情况下。
节点上必须配置集群(apiserver)的公钥根证书(public root certificate),此时,在提供有效的客户端身份认证的情况下,节点可以安全地访问 APIServer。例如,在 Google Kubernetes Engine 的一个默认 Kubernetes 安装里,通过客户端证书为 kubelet 提供客户端身份认证。请参考 kubelet TLS bootstrapping,了解如何自动为 kubelet 提供客户端证书。
对于需要调用 APIServer 接口的 Pod,应该为其关联 Service Account,此时,Kubernetes将在创建Pod时自动为其注入公钥根证书(public root certificate)以及一个有效的 bearer token(放在HTTP请求头Authorization字段)。所有名称空间中,都默认配置了名为 kubernetes Kubernetes Service,该 Service对应一个虚拟 IP(默认为 10.96.0.1),发送到该地址的请求将由 kube-proxy 转发到 apiserver 的 HTTPS 端口上。请参考 Service连接应用程序 了解 Kubernetes Service 是如何工作的。
得益于这些措施,默认情况下,从集群(节点以及节点上运行的 Pod)访问 master 的连接是安全的,因此,可以通过不受信的网络或公网连接 Kubernetes 集群
Master to Cluster
从 master(apiserver)到Cluster存在着两条主要的通信路径:
apiserver 访问集群中每个节点上的 kubelet 进程
使用 apiserver 的 proxy 功能,从 apiserver 访问集群中的任意节点、Pod、Service
# apiserver to kubelet
apiserver 在如下情况下访问 kubelet:
抓取 Pod 的日志
通过 kubectl exec -it 指令(或 kuboard 的终端界面)获得容器的命令行终端
提供 kubectl port-forward 功能
这些连接的访问端点是 kubelet 的 HTTPS 端口。默认情况下,apiserver 不校验 kubelet 的 HTTPS 证书,这种情况下,连接可能会收到 man-in-the-middle 攻击,因此该连接如果在不受信网络或者公网上运行时,是 不安全 的。
如果要校验 kubelet 的 HTTPS 证书,可以通过 --kubelet-certificate-authority 参数为 apiserver 提供校验 kubelet 证书的根证书。
如果不能完成这个配置,又需要通过不受信网络或公网将节点加入集群,则需要使用 SSH隧道 连接 apiserver 和 kubelet。
同时,Kubelet authentication/authorization 需要激活,以保护 kubelet API
# apiserver to nodes, pods, services
从 apiserver 到 节点/Pod/Service 的连接使用的是 HTTP 连接,没有进行身份认证,也没有进行加密传输。您也可以通过增加 https 作为 节点/Pod/Service 请求 URL 的前缀,但是 HTTPS 证书并不会被校验,也无需客户端身份认证,因此该连接是无法保证一致性的。目前,此类连接如果运行在非受信网络或公网上时,是 不安全 的
# SSH隧道
Kubernetes 支持 SSH隧道(tunnel)来保护 Master --> Cluster 访问路径。此时,apiserver 将向集群中的每一个节点建立一个 SSH隧道(连接到端口22的ssh服务)并通过隧道传递所有发向 kubelet、node、pod、service 的请求。
更多推荐
所有评论(0)