更新时间:2023年3月
Kubernetes API 简介
Kubernetes 控制面 的核心组件是 API 服务器(api server)。 API 服务器负责提供了基于 HTTP/HTTPS 的 Kubernetes API,以供用户对集群的管理,以及集群中的不同组件之间的相互通信
生产环境中经常会调用 Kubernetes API 查询和操作 Kubernetes API 中对象(例如:Pod、Namespace、ConfigMap 和 Event)。当然,使用 REST 调用或者 客户端库 来访问这些 API,显然并不方便,一般都是使用各种命令行工具,例如: kubectl 、 kubeadm
Kubernetes API 中的大部分操作都可以通过 kubectl
命令行或类似 kubeadm 这类命令行工具来执行, 这些工具本质上也是调用 API
不同版本的 Kubernetes,其 API 的版本也略有不同
API 信息
可以通过 kubectl
命令获取当前版本的 API 资源信息
$ kubectl api-resources
NAME SHORTNAMES APIVERSION NAMESPACED KIND
bindings v1 true Binding
componentstatuses cs v1 false ComponentStatus
configmaps cm v1 true ConfigMap
endpoints ep v1 true Endpoints
events ev v1 true Event
limitranges limits v1 true LimitRange
namespaces ns v1 false Namespace
nodes no v1 false Node
persistentvolumeclaims pvc v1 true PersistentVolumeClaim
persistentvolumes pv v1 false PersistentVolume
......
字段意义
NAME
:API 资源名称SHORTNAMES
:缩写APIVERSION
:API 版本NAMESPACED
:是否依赖于 Namespace 资源KIND
:API 资源类型
K8S API 资源对象简介
参考:理解 Kubernetes 对象 | Kubernetes
更多特有名称解释,参考:词汇表 | Kubernetes
Kubernetes API 中的所有内容都被抽象为 资源(Resources),例如 Pod、Service、Node 等等都是资源。而 对象(Object) 则是 **资源(Resources)**的实例,是持久化的实体。例如某个具体的 Pod、某个具体的 Node。Kubernetes 通过这些实体去表示整个集群的状态
Kubernetes 对象描述了以下信息:
- 哪些容器化应用在运行(以及在哪些节点上)
- 可以被应用使用的资源
- 关于应用运行时表现的策略,比如重启策略、升级策略,以及容错策略等
Kubernetes 对象是一种目标性的记录,通过创建对象,本质上是在告知 Kubernetes 系统,所需要的集群工作负载状态, 即 Kubernetes 集群的 期望状态(Desired State)
操作 Kubernetes 对象
无论是创建、修改,或者删除 Kubernetes 对象都需要调用 Kubernetes API。 生产环境中一般直接使用 kubectl
命令行操作
Kubernetes 中的资源类别有很多,kubectl
可以通过命令或者配置文件来创建资源的具体化对象(常用配置文件方式)。其中,配置文件是描述对象属性的文件,也称为资源对象文件,格式可以是 JSON 或 YAML,常用 YAML 格式
规范(Spec)与状态(Status)
关于对象 spec、status 和 metadata 的更多信息,可参考 Kubernetes API 约定
大部分的 Kubernetes 对象都包含两个嵌套的对象字段,负责管理对象的配置: 对象 spec
(规范) 和 对象 status
(状态)
-
规范(Spec)
对于具有
spec
的对象,必须在创建对象时设置其内容,描述希望对象所具有的特征,即: 期望状态(Desired State) -
状态(status)
status
则描述了对象的 当前状态(Current State),由 Kubernetes 系统和组件自动设置并维护更新。在任何时刻,Kubernetes 控制平面都会积极地管理着对象的实际状态,以使之与期望状态相匹配
对象的必需字段
一个完整的对象需要包含如下的字段:
-
apiVersion
:创建对象所使用的 Kubernetes API 的版本。可使用kucectl api-versions
命令查看当前支持的apiVersion
-
kind
:想要创建的对象的类型,即资源类型。可使用kubectl api-resources
命令查看当前版本支持的对象类型 -
metadata
:对象的唯一标识,包括一个name
字符串、UID 和可选的namespace
-
spec
:期望的对象状态的描述。不同类型的 Kubernetes 对象的spec
的格式是不同的,包含了特定于该对象资源类型的规范格式。可以在官网(Kubernetes API | Kubernetes)查看对应版本的 Kubernetes 对象的spec
格式也使用
kubectl explain 资源[.字段.字段...]
命令查看spec
格式、版本以及可选的值$ kubectl explain pods.spec KIND: Pod VERSION: v1 RESOURCE: spec <Object> DESCRIPTION: Specification of the desired behavior of the pod. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status PodSpec is a description of a pod. FIELDS: activeDeadlineSeconds <integer> Optional duration in seconds the pod may be active on the node relative to StartTime before the system will actively try to mark it failed and kill associated containers. Value must be a positive integer. affinity <Object> If specified, the pod's scheduling constraints .....
常见资源对象的使用
Pod
特点:
- Pod 是在 Kubernetes 中创建和管理的、最小的可部署的计算单元
- 一个 Pod 中可以运行一个或者多个容器
- 如果运行多个容器,则这些容器共享存储、网络、以及怎样运行这些容器的声明
一般不会直接管理 Pod,而是通过其他的工作负载资源(常用 Deployment、StatefulSet、DaemonSet)来管理 Pod。工作负载资源的控制器会使用 Pod 模板(Pod Template) 来创建 Pod 并管理它们
Deployment
简介
Deployment 是最常用的控制器。它不直接调用 Pod,而是通过调度 ReplicaSet 来调度 Pod。并向 Pod 提供声明式的更新、滚动升级、失败回滚以及许多其他有用的功能
注:不要直接管理 Deployment 所创建的 ReplicaSet 和 Pod,容易出现不一致问题。应该通过管理 Deployment 对其生成的 Pod 进行管理
更新操作通过更新 Deployment 的 PodTemplateSpec (.spec.template
)完成。 新的 ReplicaSet 会被创建,并将 Pod 从旧 ReplicaSet 迁移到新 ReplicaSet。,以达到更新的流程。每个新的 ReplicaSet 都会更新 Deployment 的修订版本
示例
创建 Deployment 的 yaml 文件
$ vim nginx-deployment.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.22.1
ports:
- containerPort: 80
在上面的例子中,完成了以下流程
-
创建一个名为
nginx-deployment
(由.metadata.name
字段标明)的 Deployment。 该名称将成为后续创建 ReplicaSet 和 Pod 的命名基础。 Deployment 的书写规则可以参阅:编写 Deployment 规约 -
该 Deployment 将会创建一个 ReplicaSet,ReplicaSet 创建三个(由
.spec.replicas
字段标明)Pod 副本 -
.spec.selector
字段定义了 Deployemnt 所创建的 ReplicaSet 如何查找要管理的 Pod 。 在这里,使用标签进行查找(app: nginx
)。 不过,更复杂的选择规则是也可能的,只要 Pod 模板本身满足所给规则即可。注:
spec.selector.matchLabels
字段是{key,value}
键值对映射。给出的所有条件都必须满足才能匹配。如果需要一些高级的选择符(例如In
、NotIn
、Exists
和DoesNotExist
),可以使用spec.selector.matchExpressions
,参考文档:标签和选择算符 | Kubernetes -
t
emplate
字段包含以下子字段:- Pod 使用
.metadata.labels
字段打上app: nginx
标签,使得 ReplicaSet 可以查找到 Pod - Pod 模板规约(即
.template.spec
字段)描述了 Pod 运行一个nginx
容器,将其命名为nginx
(.spec.template.spec.containers[0].name
字段标识), 该容器使用版本为 1.22.1 的nginx
在官方 Docker Hub 的镜像
- Pod 使用
创建 Deployment
$ kubectl apply -f nginx-deployment.yaml
检查 Deployment 状态
$ kubectl get deployments -n default
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 22m
显示的字段含义:
NAME
列出了 Namespace 中 Deployment 的名称READY
显示应用程序当前可用的副本数。显示的模式是 <就绪个数/期望个数
>UP-TO-DATE
显示为了达到期望状态已经更新的副本数AVAILABLE
显示当前应用可供用户使用的副本数AGE
显示应用程序运行的时间
注:期望副本数是根据 .spec.replicas
字段设置,此处为 3
# 查看 Deployment 上线状态,该命令会显示创建的进度信息
$ kubectl rollout status deployment/nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 0 of 3 updated replicas are available...
检查 ReplicaSet 状态
$ kubectl get rs -n default
NAME DESIRED CURRENT READY AGE
nginx-deployment-574b56f58b 3 3 3 22m
ReplicaSet 输出中包含以下字段:
NAME
列出 namespace 中 ReplicaSet 的名称DESIRED
显示应用的期望副本个数,即在创建 Deployment 时所定义的值。 此为期望状态CURRENT
显示当前运行状态中的副本个数。此为实际状态READY
显示应用中有多少副本可以为用户提供服务(就绪探针)AGE
显示应用已经运行的时间
注: ReplicaSet 的名称格式始终为
[Deployment 名称]-[hash 值]
。 该名称也是其创建的 Pod 的命名基础。 其中的 hash 值与 ReplicaSet 上的pod-template-hash
标签一致
检查 Pod 状态
$ kubectl get pods --show-labels -n default
NAME READY STATUS RESTARTS AGE LABELS
nginx-deployment-574b56f58b-2m9qr 1/1 Running 0 25m app=nginx,pod-template-hash=574b56f58b
nginx-deployment-574b56f58b-49844 1/1 Running 0 25m app=nginx,pod-template-hash=574b56f58b
nginx-deployment-574b56f58b-jnl9k 1/1 Running 0 25m app=nginx,pod-template-hash=574b56f58b
注:由 ReplicaSet 创建的 Pod 名称始终为 [ReplicaSet 名称]-[hash 值]
,即 [Deployment 名称]-[hash 值]-[hash 值]
Service
简介
Service 是将运行在一组 Pod 上的网络应用程序对外公开的方法
为什么需要 Service?
Pod 是临时资源,它的网络地址具有不稳定性。例如,滚动更新时,Deployment 动态地创建和销毁 Pod,Pod 的 IP 地址就会发生变化。这导致了一个问题: 如果一组 Pod(称为 <后端>)为集群内的其他 Pod(称为 <前端>)提供功能, 那么<前端> 无法准确地找出要连接的 <后端> 的 IP 地址
Service 就是用来解耦这种关联。 Service 对象可以定义一个逻辑组的 Endpoint(通常这些 Endpoint 就是 Pod)以及如何才能访问这些 Endpoint 的策略,即通过网络来暴露一组 Pod 组合。此时,<前端> 只需要通过 Service 就可以访问 <后端>,而不受 <后端> IP 变化的影响
原理
kube-proxy 会一直监听 kube-apiserver,当 Service 发生变化时,kube-proxy 就会通过调度模型(iptables 或 ipvs)生成或修改调度信息(iptables 或 ipvs 规则)
同时,CoreDNS 的 kubernetes 插件会向 kube-apiserver 同步 Service 的 DNS 记录,提供 DNS 解析服务
此时,应用就可以通过 Service 的 FQDN 来访问另一组 Pod
Service Type(服务类型)
Service 可以通过指定不同的 Service Type(由 .spec.type
指定),来控制应用的暴露范围
Service Type 的取值如下:
-
ClusterIP
:默认的 Service Type。通过集群的内部 IP 暴露服务,使用该值时,服务只能够在集群内部访问。但此时还是可以通过 Ingress 或者 Gateway API 向集群外暴露服务 -
NodePort
:通过每个节点上的 IP 和静态端口(NodePort
)暴露服务。 可以供集群外部访问 -
LoadBalancer
:使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的NodePort
服务和ClusterIP
服务上 -
ExternalName
:通过返回CNAME
记录和对应值,可以将服务映射到externalName
字段的内容(例如,foo.bar.example.com
),无需创建任何类型代理常用于将 kubernetes 集群外部的服务映射至集群内部访问,从而让集群内部的 Pod 能够通过固定的 Service Name 来访问集群外部服务。有时也会用于不同 Namespace 之间的 Pod 相互访问
注:
ExternalName
需要使用 kube-dns 1.7 及以上版本或者 CoreDNS 0.0.8 以上版本
示例一
使用 ClusterIP 类型的 Service
创建测试用的 Deploy
$ vim deploy-nginx.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx-deploy
spec:
replicas: 3
selector:
matchLabels:
app.kubernetes.io/name: nginx
template:
metadata:
labels:
app.kubernetes.io/name: nginx
spec:
containers:
- name: nginx
image: nginx:1.22.1
ports:
- containerPort: 80
name: web-http
创建 Service 的 yaml 文件
$ vim svc-clusterip-nginx.yaml
---
apiVersion: v1
kind: Service
metadata:
name: ng-svc
spec:
selector:
app.kubernetes.io/name: nginx
type: ClusterIP
clusterIP: 10.68.0.199
ports:
- name: http
protocol: TCP
port: 80
targetPort: web-http
在 yaml 文件中,有以下几个要点:
-
创建了一个名为 ng-deploy-80 的 Service。Service 对象名称需要符合 RFC 1035 标签名称
-
通过选择器和标签(此处为
app.kubernetes.io/name: nginx
)选择 EndPoint,即上面 Deployment 创建的三个 Pod -
设置了服务类型为
ClusterIP
,并设置该 Service 的clusterIP
为10.68.0.199
(该 IP 需要在SERVICE_CIDR
范围内)。如果未设置 IP,设 k8s 会自动分配一个SERVICE_CIDR
范围内的地址 -
Service 能够将一个接收
port
(Service 的端口,此处为 80)映射到任意的targetPort
(后端 EndPoint 的端口,此处为 web-http),并且选择传输层协议为 TCP默认情况下,
targetPort
将被设置为与port
字段相同的值。如果 Pod 中的端口定义是有名称的,可以在 Service 的targetPort
属性中直接引用这些名称
应用 yaml 文件
$ kubectl apply -f deploy-nginx.yaml
$ kubectl apply -f svc-clusterip-nginx.yaml
检查 Service 情况
# 检查 Service 是否正常创建
$ kubectl get svc ng-svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ng-svc ClusterIP 10.68.0.199 <none> 80/TCP 20s
# 检查 Service 对应的 EndPoint
$ kubectl get endpoints ng-svc
NAME ENDPOINTS AGE
ng-svc 172.20.119.209:80,172.20.119.210:80,172.20.195.7:80 65s
# 查看 Service 的详细信息
$ kubectl describe svc ng-svc
Name: ng-svc
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app.kubernetes.io/name=nginx
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.68.0.199
IPs: 10.68.0.199
Port: http 80/TCP
TargetPort: web-http/TCP
Endpoints: 172.20.119.209:80,172.20.119.210:80,172.20.195.7:80
Session Affinity: None
Events: <none>
# 在 kubernetes 节点上查看生成的 ipvs 规则
$ ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
......
TCP 10.68.0.199:80 rr
-> 172.20.119.209:80 Masq 1 0 0
-> 172.20.119.210:80 Masq 1 0 0
-> 172.20.195.7:80 Masq 1 0 0
......
映射情况如下
检查访问
# 访问 Service 的 ClusterIP 的对应端口
$ curl -I 10.68.0.199:80
HTTP/1.1 200 OK
Server: nginx/1.22.1
Date: Thu, 02 Mar 2023 19:17:03 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Wed, 19 Oct 2022 08:02:20 GMT
Connection: keep-alive
ETag: "634faf0c-267"
Accept-Ranges: bytes
示例二
使用 NodePort 类型的 Service
创建 Service 的 yaml 文件
$ vim svc-nodeport-nginx.yaml
---
apiVersion: v1
kind: Service
metadata:
name: ng-svc-nodeport
spec:
selector:
app.kubernetes.io/name: nginx
type: NodePort
ports:
- name: http
protocol: TCP
nodePort: 30080
port: 80
targetPort: web-http
在 yaml 文件中,有以下几个要点:
-
与 ClusterIP 类型的 Service 略有不同,NodePort 类型必须写明(由
spec.type
指定) -
节点端口由
spec.ports[].nodePort
指定,默认为30000-32767
,可以在通过指定 kube-apiserver 的启动参数--service-node-port-range=30000-32767
来修改端口范围 -
如果你要指定特定的 IP 地址来代理端口,可以将 kube-proxy 的
--nodeport-addresses
选项或 kube-proxy 配置文件 的等效nodePortAddresses
字段设置为特定的 IP 段。二进制安装的 kube-proxy 在配置文件中配置该参数,容器化安装可以直接使用 configmap 进行配置
注:如果使用
--nodeport-addresses=127.0.0.0/8
标志启动 kube-proxy, 则 kube-proxy 仅选择 NodePort 服务的环回接口。--nodeport-addresses
的默认值是一个空列表。 这意味着 kube-proxy 会考虑 NodePort 的所有可用网络接口
应用 yaml 文件
$ kubectl apply -f svc-nodeport-nginx.yaml
检查 Service
# 检查 Service 是否正常创建,即使 NodePort 类型还是会有 ClusterIP
$ kubectl get svc ng-svc-nodeport
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ng-svc-nodeport NodePort 10.68.250.185 <none> 80:30080/TCP 26s
# 检查 Service 对应的 EndPoint
$ kubectl get endpoints ng-svc-nodeport
NAME ENDPOINTS AGE
ng-svc-nodeport 172.20.119.209:80,172.20.119.210:80,172.20.195.7:80 69s
# 查看 Service 的详细信息
$ kubectl describe svc ng-svc-nodeport
Name: ng-svc-nodeport
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app.kubernetes.io/name=nginx
Type: NodePort
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.68.250.185
IPs: 10.68.250.185
Port: http 80/TCP
TargetPort: web-http/TCP
NodePort: http 30080/TCP
Endpoints: 172.20.119.209:80,172.20.119.210:80,172.20.195.7:80
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
# 在 kubernetes 节点上查看生成的 ipvs 规则
# 可以看到在节点的所有 IP 上都做了映射,同时也在 ClusterIP 上做了映射
$ ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
......
TCP 169.254.20.10:30080 rr
-> 172.20.119.209:80 Masq 1 0 0
-> 172.20.119.210:80 Masq 1 0 0
-> 172.20.195.7:80 Masq 1 0 0
......
TCP 172.20.251.0:30080 rr
-> 172.20.119.209:80 Masq 1 0 0
-> 172.20.119.210:80 Masq 1 0 0
-> 172.20.195.7:80 Masq 1 0 0
......
TCP 192.168.111.185:30080 rr
-> 172.20.119.209:80 Masq 1 0 0
-> 172.20.119.210:80 Masq 1 0 0
-> 172.20.195.7:80 Masq 1 0 0
......
TCP 10.68.250.185:80 rr
-> 172.20.119.209:80 Masq 1 0 0
-> 172.20.119.210:80 Masq 1 0 0
-> 172.20.195.7:80 Masq 1 0 0
......
映射情况如下:
检查访问
# 访问 Service 的 ClusterIP 的对应端口
$ curl -I 10.68.250.185:80
HTTP/1.1 200 OK
Server: nginx/1.22.1
Date: Thu, 02 Mar 2023 18:08:28 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Wed, 19 Oct 2022 08:02:20 GMT
Connection: keep-alive
ETag: "634faf0c-267"
Accept-Ranges: bytes
# 访问节点 IP 的对应端口
$ curl -I 192.168.111.185:30080
HTTP/1.1 200 OK
Server: nginx/1.22.1
Date: Thu, 02 Mar 2023 19:18:20 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Wed, 19 Oct 2022 08:02:20 GMT
Connection: keep-alive
ETag: "634faf0c-267"
Accept-Ranges: bytes