K8s里的API对象

在K8s里,YAML用来声明API对象的,那么API对象都有哪些?我们之前接触过的pod、deployment、service、node都是,当然还有好多,可以这样查看:

kubectl api-resources

资源对象:pod

# 获取pod列表
kubectl get pods

# 运行一个pod
kubectl run pod-demo --image=busybox

# 查看pod详情
kubectl describe pod pod-demo

# 从已知Pod导出YAML文件
kubectl get pod pod-demo -o yaml  -o yaml > pod-demo.yaml

pod yaml示例

四个核心部分:apiVersion、Kind、metadata、spec
其他部分可以不用管,也可以删掉

vim testpod.yaml

#手动创建一个pod,直接复制下面内容
apiVersion: v1
kind: Pod
metadata:
  name: ngx-pod
  namespace: linyi
  labels:  ## labels字段非常关键,它可以添加任意数量的Key-Value,目的是为了让pod的信息更加详细
    env: dev

spec:  ##用来定义该pod更多的资源信息,比如contain, volume, storage
  containers:  ##定义容器属性
  - image: nginx:1.23.2
    imagePullPolicy: IfNotPresent  ##镜像拉取策略,三种:Always/Never/IfNotPresent,一般默认是IfNotPresent,也就是说只有本地不存在才会远程拉取镜像,可以减少网络消耗。
    name: ngx
    env:  ##定义变量,类似于Dockerfile里面的ENV指令
      - name: os
        value: "Rocky Linux"
    ports:
    - containerPort: 80
# 上述配置文件中的namespace没有的话,需要创建,不然会报错
kubectl create namespace linyi

# 使用yaml文件创建pod
kubectl apply -f testpod.yaml

# 查看pod(po为简写)
[root@linyi k8s]# kubectl get po -n linyi
NAME      READY   STATUS    RESTARTS   AGE
ngx-pod   1/1     Running   0          102s

# 查看pod详情。(这里有个问题,如果在虚拟机做测试,虚拟机长期挂起会导致这个pod启动有问题,重启k8s解决或重启k8s后删除这个pod重新创建)
kubectl describe po ngx-pod -n linyi

# 删除pod
kubectl delete pod ngx-pod

# 删除namespace
kubectl delete namespace linyi

资源对象:Job

可以理解成一次性运行后就退出的Pod。

先来生成一个YAML文件:

kubectl create job job-demo --image=busybox  --dry-run=client  -o yaml > job-demo.yaml
# 编辑此配置
vim job-demo.yaml

apiVersion: batch/v1
kind: Job
metadata:
  name: job-demo
spec:
  template:  ##模板,基于此模板来创建pod,它用来定义pod的属性,比如container
    spec:
      restartPolicy: OnFailure ##定义Pod运行失败时的策略,可以是OnFailure和Never,其中OnFailure表示失败的话需要重启容器,Never表示失败的话不重启容器,而是重新生成一个新的Pod
      containers:
      - image: busybox
        name: job-demo
        command: ["/bin/echo"]
        args: ["hellow", "world"]
# 创建job
kubectl apply -f job-demo.yaml

# 查看job
kubectl get job,pod

# 查看job详情
kubectl describe job job-demo

# 删除job
kubectl delete job job-demo

可以看到该容器运行完成后状态就变成了Completed。

对于Job,还有几个特殊字段:

  • activeDeadlineSeconds,设置 Pod 运行的超时时间。

  • backoffLimit,设置 Pod 的失败重试次数。

  • completions,Job 完成需要运行多少个 Pod,默认是 1 个。

  • parallelism,它与 completions 相关,表示允许并发运行的 Pod 数量,避免过多占用资源。

vi myjob.yaml

apiVersion: batch/v1
kind: Job
metadata:
  name: sleep-job

spec:
  activeDeadlineSeconds: 15  #15s就超时
  backoffLimit: 2 #失败重试2次就放弃
  completions: 4 #要运行4个pod,才算完成
  parallelism: 2 #允许并发运行2个pod

  template:
    spec:
      restartPolicy: OnFailure
      containers:
      - image: busybox
        name: echo-job
        imagePullPolicy: IfNotPresent
        command:
          - sh
          - -c
          - sleep $(($RANDOM % 10 + 1)) && echo done  ##$(($RANDOM % 10 + 1))表示取1-10任意一个数字
# 创建job,并查看job情况
kubectl apply -f myjob.yaml ; kubectl get pod -w

资源对象:CronJob

CronJob简称(cj)是一种周期运行的Pod,比如有些任务需要每天执行一次,就可以使用CronJob。

先来生成一个YAML文件:

kubectl create cj cj-demo --image=busybox --schedule="" --dry-run=client  -o yaml > cj-demo.yaml
# 编辑此配置
vim cj-demo.yaml

apiVersion: batch/v1
kind: CronJob
metadata:
  name: cj-demo

spec:
  schedule: '*/1 * * * *'
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
          - image: busybox
            name: cj-demo
            imagePullPolicy: IfNotPresent
            command: ["/bin/echo"]
            args: ["hello", "world"]
# 运行并查看
kubectl apply -f cj-demo.yaml
kubectl get cj
kubectl get pod

资源对象:ConfigMap

ConfigMap(简称cm)用来存储配置信息,比如服务端口、运行参数、文件路径等等。

示例:

# 编辑配置
vim mycm.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: mycm

data:
  DATABASE: 'db'
  USER: 'wp'
  PASSWORD: '123123'
  ROOT_PASSWORD: '123123'
# 创建cm
kubectl apply -f mycm.yaml

# 查看cm
kubectl get cm

# 查看cm详情
kubectl describe cm mycm

# 删除cm
kubectl delete cm mycm

在其它pod里引用ConfigMap:

# 编辑配置
vim testpod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: testpod
  labels:
    app: testpod

spec:
  containers:
  - image: mariadb:10
    name: maria
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 3306

    envFrom:   ##将cm里的字段全部导入该pod
    - prefix: 'MARIADB_'  ##将导入的字段名前面自动加上前缀,例如MARIADB_DATABASE, MARIADB_USER
      configMapRef:  ##定义哪个cm
        name: mycm

验证:

kubectl exec -it testpod -- bash
## 进入pod,查看变量$MARIADB_DATABASE

资源对象:Secret

Secret和cm的结构和用法很类似,不过在 K8s里Secret 对象又细分出很多类,比如:

  • 访问私有镜像仓库的认证信息

  • 身份识别的凭证信息

  • HTTPS 通信的证书和私钥

  • 一般的机密信息(格式由用户自行解释)

前几种我们现在暂时用不到,所以就只使用最后一种。

示例:

# 编辑配置
vim mysecret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: mysecret

data:
  user: YW1pbmc=   ## echo -n "linyi"|base64
  passwd: bGludXgxMjM=  ## echo -n "test123"|base64

查看

kubectl apply -f mysecret.yaml
kubectl get secret
kubectl describe secret mysecret

在其它pod里引用Secret

# 编辑配置
vim testpod2.yaml
apiVersion: v1
kind: Pod
metadata:
  name: testpod2

spec:
  containers:
  - image: busybox
    name: busy
    imagePullPolicy: IfNotPresent
    command: ["/bin/sleep", "300"]

    env:
      - name: USERNAME
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: user
      - name: PASSWORD
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: passwd

查看

kubectl exec -it testpod2 -- sh
## 进去后可以 echo $PASSWORD查看变量值

资源对象:Deployment

示例

vim ng-deploy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: myng
  name: ng-deploy
spec:
  replicas: 2 ##副本数
  selector:
    matchLabels:
      app: myng
  template:
    metadata:
      labels:
        app: myng
    spec:
      containers:
        - name: myng
          image: nginx:1.23.2
          ports:
          - name: myng-port
            containerPort: 80

matchLabels和labels之间的关系:
../../_images/82.png

# 使用YAML创建deploy
kubectl apply -f ng-deploy.yaml

# 查看deploy
kubectl get deploy

# 查看deploy详情
kubectl describe deploy ng-deploy

# 查看pod
kubectl get pod

# 删除deploy
kubectl delete deploy ng-deploy

资源对象:Service

Service(简称svc)是K8s集群中的一种资源对象,它定义了Pod的逻辑集合和访问该集合的策略。

示例:

# 编辑配置
vim ng-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: ngx-svc
spec:
  selector:
    app: myng
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
# 使用YAML创建service
kubectl apply -f ng-svc.yaml

# 查看service
kubectl get svc

# 查看service详情
kubectl describe svc ngx-svc

# 删除service
kubectl delete svc ngx-svc

资源对象:Daemonset

有些场景需要在每一个node上运行Pod(比如,网络插件calico、监控、日志收集),Deployment无法做到,而Daemonset(简称ds)可以。Deamonset的目标是,在集群的每一个节点上运行且只运行一个Pod。

Daemonset不支持使用kubectl create获取YAML模板,所以只能照葫芦画瓢了,参考Deployment的YAML编写,其实Daemonset和Deployment的差异很小,除了Kind不一样,还需要去掉replica配置。

示例:

# 编辑配置
vim ds-demo.yaml

apiVersion: apps/v1
kind: DaemonSet
metadata:
  labels:
    app: ds-demo
  name: ds-demo
spec:
  selector:
    matchLabels:
      app: ds-demo
  template:
    metadata:
      labels:
        app: ds-demo
    spec:
      containers:
        - name: ds-demo
          image: nginx:1.23.2
          ports:
          - name: mysql-port
            containerPort: 80
# 使用YAML创建ds
kubectl apply -f ds-demo.yaml

# 查看ds
kubectl get ds

# 查看ds详情
kubectl describe ds ds-demo

# 查看pod
kubectl get pod

# 删除ds
kubectl delete ds ds-demo

但只在两个node节点上启动了pod,没有在master上启动,这是因为默认master有限制。

kubectl describe node k8s01 |grep -i 'taint'
Taints:             node-role.kubernetes.io/control-plane:NoSchedule

说明:
Taint叫做污点,如果某一个节点上有污点,则不会被调度运行pod。
但是这个还得取决于Pod自己的一个属性:toleration(容忍),即这个Pod是否能够容忍目标节点是否有污点。
为了解决此问题,我们可以在Pod上增加toleration属性,
下面改一下YAML配置:

# 编辑配置
vim ds-demo.yaml

apiVersion: apps/v1
kind: DaemonSet
metadata:
 labels:
    app: ds-demo
  name: ds-demo
spec:
  selector:
    matchLabels:
      app: ds-demo
  template:
    metadata:
      labels:
        app: ds-demo
    spec:
      # 新增容忍污点
      tolerations:
        - key: node-role.kubernetes.io/control-plane
          effect: NoSchedule
      containers:
        - name: ds-demo
          image: nginx:1.23.2
          ports:
          - name: mysql-port
            containerPort: 80


# 再次应用此YAML
kubectl apply -f ds-demo.yaml

资源对象:Ingress/IngressClass

有了Service之后,我们可以访问这个Service的IP(clusterIP)来请求对应的Pod,但是这只能是在集群内部访问,要想实现外部访问,还需要额外的组件。
../../_images/92.png
要想让外部用户访问此资源,可以使用NodePort,即在node节点上暴漏一个端口出来,但是这个非常不灵活。为了解决此问题,K8s引入了一个新的API资源对象Ingress,它是一个七层的负载均衡器,类似于Nginx。
../../_images/102.png

三个概念:Ingress、Ingress Controller、IngressClass

  • Ingress用来定义具体的路由规则,要实现什么样的访问效果;

  • Ingress Controller是实现Ingress定义具体规则的工具或者叫做服务,在K8s里就是具体的Pod;

  • IngressClass是介于Ingress和Ingress Controller之间的一个协调者,它存在的意义在于,当有多个Ingress Controller时,可以让Ingress和Ingress Controller彼此独立,不直接关联,而是通过IngressClass实现关联。

../../_images/112.png

Ingress YAML示例:

# 编辑配置
vim mying.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: mying  ##ingress名字
  
spec:
  ingressClassName: myingc  ##定义关联的IngressClass
  
  rules:  ##定义具体的规则
  - host: linyi.com  ##访问的目标域名
    http:
      paths:
      - path: /
        pathType: Exact
        backend:  ##定义后端的service对象
          service:
            name: ngx-svc
            port:
              number: 80
# 查看ingress
kubectl get ing
kubectl describe ing mying

IngressClassYAML示例:

# 编辑配置
vim myingc.yaml

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: myingc

spec:
  controller: nginx.org/ingress-controller  ##定义要使用哪个controller
# 查看ingressclass
kubectl get ingressclass
kubectl describe ingressclass myingc

安装ingress-controller

使用Nginx官方提供的ingress-controller

首先做一下前置工作

curl -O 'https://gitee.com/aminglinux/linux_study/raw/master/k8s/ingress.tar.gz'
tar zxf ingress.tar.gz
cd ingress
./setup.sh
##说明,执行这个脚本会部署几个ingress相关资源,包括namespace、configmap、secrect等
# 编辑配置
vim ingress-controller.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ngx-ing
  namespace: nginx-ingress

spec:
  replicas: 1
  selector:
    matchLabels:
      app: ngx-ing

  template:
    metadata:
      labels:
        app: ngx-ing
     #annotations:
       #prometheus.io/scrape: "true"
       #prometheus.io/port: "9113"
       #prometheus.io/scheme: http
    spec:
      serviceAccountName: nginx-ingress
      containers:
      #- image: nginx/nginx-ingress:2.2.0
      - image: nginx/nginx-ingress:2.2-alpine
        imagePullPolicy: IfNotPresent
        name: ngx-ing
        ports:
        - name: http
          containerPort: 80
        - name: https
          containerPort: 443
        - name: readiness-port
          containerPort: 8081
        - name: prometheus
          containerPort: 9113
        readinessProbe:
          httpGet:
            path: /nginx-ready
            port: readiness-port
          periodSeconds: 1
        securityContext:
          allowPrivilegeEscalation: true
          runAsUser: 101 #nginx
          capabilities:
            drop:
            - ALL
            add:
            - NET_BIND_SERVICE
        env:
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        args:
          - -ingress-class=myingc
          - -health-status
          - -ready-status
          - -nginx-status

          - -nginx-configmaps=$(POD_NAMESPACE)/nginx-config
          - -default-server-tls-secret=$(POD_NAMESPACE)/default-server-secret
# 应用YAML
kubectl apply -f ingress-controller.yaml

# 查看pod、deployment
kubectl get po -n nginx-ingress
kubectl get deploy -n nginx-ingress

测试:

# 将ingress对应的pod端口映射到master上临时测试
kubectl port-forward -n nginx-ingress ngx-ing-547d6575c7-fhdtt 8888:80 &  

# 测试前,可以修改ng-deploy对应的两个pod里的/usr/share/nginx/html/index.html文件内容,用于区分两个pod

# 测试访问
curl -x127.0.0.1:8888 linyi.com
## 或者:
curl -H 'Host:linyi.com' http://127.0.0.1:8888

API资源对象PersistentVolume/PersistentVolumeClaim/StorageClass

持久化相关

三个概念:

  • PersistentVolume(pv)
    是对具体存储资源的描述,比如NFS、Ceph、GlusterFS等,通过pv可以访问到具体的存储资源;

  • PersistentVolumeClaim(pvc)
    Pod想要使用具体的存储资源需要对接到pvc,pvc里会定义好pod希望使用存储的属性,通过pvc再去申请合适的存储资源(pv),匹配到合适的资源后pvc和pv会进行绑定,它们两者是一一对应的;

  • StorageClass(sc)
    pv可以手动创建,也可以自动创建,当pv需求量非常大时,如果靠手动创建pv就非常麻烦了,sc可以实现自动创建pv,并且会将pvc和pv绑定。
    sc对象会定义两部分内容:①pv的属性,比如存储类型、大小;②创建该pv需要用到的存储插件(provisioner),这个provisioner是实现自动创建pv的关键。

案例一(pv手动创建):

PV YAML示例:

vi  testpv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: testpv

spec:
  accessModes:
  - ReadWriteOnce
  capacity:
    storage: 500Mi  ##提供500Mi空间
  hostPath:
    path: /tmp/testpv/

说明: accessModes定义该pv的访问权限模式,有三种:

  • ReadWriteOnce:存储卷可读可写,但只能被一个节点上的 Pod 挂载;

  • ReadOnlyMany:存储卷只读不可写,可以被任意节点上的 Pod 多次挂载;

  • ReadWriteMany:存储卷可读可写,也可以被任意节点上的 Pod 多次挂载;

capacity 定义该存储大小。 hostPath 定义该存储访问路径。

PVC YAML示例:

vi  testpvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: testpvc

spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 100Mi  ##期望申请100Mi空间
# 应用pv和pvc的YAML
kubectl apply -f testpv.yaml -f testpvc.yaml

# 查看状态
kubectl get pv,pvc

实验: 将testpvc的期望100Mi改为1000Mi,查看pv的STATUS