5-2 Kubernetes 基础资源对象的使用

更新时间:2023年3月

Kubernetes API 简介

参考:Kubernetes API | Kubernetes

Kubernetes 控制面 的核心组件是 API 服务器(api server)。 API 服务器负责提供了基于 HTTP/HTTPS 的 Kubernetes API,以供用户对集群的管理,以及集群中的不同组件之间的相互通信

生产环境中经常会调用 Kubernetes API 查询和操作 Kubernetes API 中对象(例如:Pod、Namespace、ConfigMap 和 Event)。当然,使用 REST 调用或者 客户端库 来访问这些 API,显然并不方便,一般都是使用各种命令行工具,例如: kubectlkubeadm

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 是在 Kubernetes 中创建和管理的、最小的可部署的计算单元
  • 一个 Pod 中可以运行一个或者多个容器
  • 如果运行多个容器,则这些容器共享存储、网络、以及怎样运行这些容器的声明

一般不会直接管理 Pod,而是通过其他的工作负载资源(常用 Deployment、StatefulSet、DaemonSet)来管理 Pod。工作负载资源的控制器会使用 Pod 模板(Pod Template) 来创建 Pod 并管理它们

Deployment

参考:Deployments | Kubernetes

简介

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} 键值对映射。给出的所有条件都必须满足才能匹配。如果需要一些高级的选择符(例如 InNotInExistsDoesNotExist),可以使用spec.selector.matchExpressions,参考文档:标签和选择算符 | Kubernetes

  • template 字段包含以下子字段:

    • 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 的镜像

创建 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) | Kubernetes

简介

Service 是将运行在一组 Pod 上的网络应用程序对外公开的方法

为什么需要 Service?

Pod 是临时资源,它的网络地址具有不稳定性。例如,滚动更新时,Deployment 动态地创建和销毁 Pod,Pod 的 IP 地址就会发生变化。这导致了一个问题: 如果一组 Pod(称为 <后端>)为集群内的其他 Pod(称为 <前端>)提供功能, 那么<前端> 无法准确地找出要连接的 <后端> 的 IP 地址

Service 就是用来解耦这种关联。 Service 对象可以定义一个逻辑组的 Endpoint(通常这些 Endpoint 就是 Pod)以及如何才能访问这些 Endpoint 的策略,即通过网络来暴露一组 Pod 组合。此时,<前端> 只需要通过 Service 就可以访问 <后端>,而不受 <后端> IP 变化的影响

原理

参考:Service 与 Pod 的 DNS | Kubernetes

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 的 clusterIP10.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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值