Kubernetes学习之路目录

学习总结:

1、k8s基本概念和术语
k8s相关组件介绍:

api service:所有服务访问统一入口。对外暴露K8S的api接口,是外界进行资源操作的唯一入口,并提供认证、授权、访问控制、API注册和发现等机制;

crontroller manager:负责维护集群的状态,比如故障检测、自动扩展、滚动更新等,它们是处理集群中常规任务的后台线程。

scheduler:负责资源的调度,按照预定的调度策略将Pod调度到相应的机器上;就是监视新创建的 Pod,如果没有分配节点,就选择一个节点供他们运行,这就是pod的调度。

etcd:一个可信赖的分布式键值存储服务,能够为整个分布式集群存储一些关键数据,协助分布式集群运转。储存K8S集群所有重要信息(持久化)。v2版本时基于内存的存储,v3开始才是序列化到介质。新版本K8S(v1.11以上)已经改用v3版本etcd。

kubelet:直接跟容器引擎交互实现容器的生命周期管理。

kube-proxy:负责写入规则至 IPTABLES、IPVS 实现服务映射访问的。

 Ipvs:监听Master节点增加和删除service以及endpoint的消息,调用Netlink接口创建相应的IPVS规则。通过IPVS规则,将流量转发至相应的Pod上。
 Iptables:监听Master节点增加和删除service以及endpoint的消息,对于每一个Service,他都会场景一个iptables规则,将service的clusterIP代理到后端对应的Pod。

其中scheduler和controller-manager两个组件是有leader选举的,这个选举机制是k8s对于这两个组件的高可用保障。api server是可以水平扩展的。

其他重要插件:
Calico:符合CNI标准的网络插件,给每个Pod生成一个唯一的IP地址,并且把每个节点当做一个路由器。Cilium
CoreDNS:用于Kubernetes集群内部Service的解析,可以让Pod把Service名称解析成IP地址,然后通过Service的IP地址进行连接到对应的应用上。

coredns:可以为集群中的SVC创建一个域名IP的对应关系解析

dashboard:给 K8S 集群提供一个 B/S 结构访问体系

ingress controller:官方只能实现四层代理,INGRESS 可以实现七层代理

federation:提供一个可以跨集群中心多K8S统一管理功能

prometheus :提供K8S集群的监控能力

elk:提供 K8S 集群日志统一分析介入平台

标签——污点(Taint),避免新的容器被调度到该Node上。而如果某些Pod可以(短期)容忍(Toleration)某种污点的存在

一、kubernetes命令式快速创建应用

使用命令kubectl run创建应用

kubectl run nginx-deploy --image=nginx:1.14-alpine --port=80  #命令创建POD

kubectl create deployment  nginx-test --image=nginx:1.14-alpine --port=80 --replicas=1 #命令创建deployment

kubectl expose deployment nginx-deploy --port=80 --target-port=8000  #创建一个nginx的service ,需要deployment创建好

#K8S删除zadig命名空间下所有的pod,deployment,statefulset
kubectl delete --all pods -n 命名空间
kubectl delete --all deploy -n 命名空间
kubectl delete --all sts -n 命名空间

应用副本的动态伸缩

kubectl scale  deployment nginx-deploy --replicas=2  #副本增加到2
kubectl set image deployment nginx-deploy nginx=nginx:1.15 #镜像修改为nginx:1.15
kubectl rollout undo deployment nginx-deploy  #不指定版本直接回滚到上一个版本
kubectl edit svc nginx-deploy  #TYPE:CLUSTER-IP改为TYPE:NodePort  实现外部访问service

二、Pod状态和生命周期管理

Pod的终止

示例流程如下:

1、用户发送删除pod的命令,默认宽限期是30秒;
2、在Pod超过该宽限期后API server就会更新Pod的状态为“dead”;
3、在客户端命令行上显示的Pod状态为“terminating”;
4、跟第三步同时,当kubelet发现pod被标记为“terminating”状态时,开始停止pod进程:
   1、如果在pod中定义了preStop hook,在停止pod前会被调用。如果在宽限期过后,preStop hook依然在运行,第二步会再增加2秒的宽限期;
   2、向Pod中的进程发送TERM信号;
5、跟第三步同时,该Pod将从该service的端点列表中删除,不再是replication controller的一部分。关闭的慢的pod将继续处理load balancer转发的流量;
6、过了宽限期后,将向Pod中依然运行的进程发送SIGKILL信号而杀掉进程。
7、Kublete会在API server中完成Pod的的删除,通过将优雅周期设置为0(立即删除)。Pod在API中消失,并且在客户端也不可见。

1、Pod phase

Pod 的 status 在信息保存在 PodStatus 中定义,其中有一个 phase 字段
挂起(Pending)运行中(Running)成功(Succeeded)失败(Failed)未知(Unknown)

2、Pod的创建过程

Pod是Kubernetes的基础单元,了解其创建的过程,更有助于理解系统的运作。
①用户通过kubectl或其他API客户端提交Pod Spec给API Server。
②API Server尝试将Pod对象的相关信息存储到etcd中,等待写入操作完成,API Server返回确认信息到客户端。
③API Server开始反映etcd中的状态变化。
④所有的Kubernetes组件通过"watch"机制跟踪检查API Server上的相关信息变动。
⑤kube-scheduler(调度器)通过其"watcher"检测到API Server创建了新的Pod对象但是没有绑定到任何工作节点。
⑥kube-scheduler为Pod对象挑选一个工作节点并将结果信息更新到API Server。
⑦调度结果新消息由API Server更新到etcd,并且API Server也开始反馈该Pod对象的调度结果。
⑧Pod被调度到目标工作节点上的kubelet尝试在当前节点上调用docker engine进行启动容器,并将容器的状态结果返回到API Server。
⑨API Server将Pod信息存储到etcd系统中。
⑩在etcd确认写入操作完成,API Server将确认信息发送到相关的kubelet。

3、Pod存活性探测

readinessProbe
livenessProbe
startupProbe(这个1.16版本增加的)

目前 LivenessProbe 和 ReadinessProbe 两种探针都支持下面三种探测方法:

ExecAction:在容器中执行指定的命令,如果执行成功,退出码为 0 则探测成功。
HTTPGetAction:通过容器的IP地址、端口号及路径调用 HTTP Get方法,如果响应的状态码大于等于200且小于400,则认为容器 健康。
TCPSocketAction:通过容器的 IP 地址和端口号执行 TCP 检 查,如果能够建立 TCP 连接,则表明容器健康。
 
探针探测结果有以下值:
Success:表示通过检测。
Failure:表示未通过检测。
Unknown:表示检测没有正常进行。

    livenessProbe:
      failureThreshold: 3
      httpGet:
        path: /
        port: 80
        scheme: HTTP
      initialDelaySeconds: 30
      periodSeconds: 10
      successThreshold: 1
      timeoutSeconds: 5
    
    readinessProbe:
      failureThreshold: 3
      httpGet:
        path: /
        port: 80
        scheme: HTTP
      initialDelaySeconds: 20
      periodSeconds: 5
      successThreshold: 1
      timeoutSeconds: 10

4、资源需求和资源限制

资源需求举例:

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      requests:
        memory: "128Mi"
        cpu: "200m"

三、Pod控制器--ReplicaSet、Deployment

一、Pod控制器及其功用

**ReplicaSet:** 代用户创建指定数量的pod副本数量,确保pod副本数量符合预期状态,并且支持滚动式自动扩容和缩容功能。
**Deployment:**工作在ReplicaSet之上,用于管理无状态应用,目前来说最好的控制器。支持滚动更新和回滚功能,还提供声明式配置。
**DaemonSet:**用于确保集群中的每一个节点只运行特定的pod副本,通常用于实现系统级后台任务。比如ELK服务
**Job:**只要完成就立即退出,不需要重启或重建。
**Cronjob:**周期性任务控制,不需要持续后台运行,
**StatefulSet:**管理有状态应用

Deployment控制器

1、解析Deployment Spec

apiVersion: apps/v1                  #版本号
kind: Deployment                     #类型
metadata:                            #元数据
  name:                              #rs名称
  namespace:                         #所属命名空间
  labels:                            #标签
    controller: deploy
spec:                                #详情描述
  replicas:                          #副本数量
  revisionHistoryLimit:              #保留历史版本,默认是10
  paused:                            #暂停部署,默认是false
  progressDeadlineSeconds:           #部署超时时间(s),默认是600
  strategy:                          #策略
    type: RollingUpdates             #滚动更新策略
    rollingUpdate:                   #滚动更新
      maxSurge:                      #最大额外可以存在的副本数,可以为百分比,也可以为整数
      maxUnavaliable:                #最大不可用状态的pod的最大值,可以为百分比,也可以为整数
  selector:                          #选择器,通过它指定该控制器管理哪些pod
    matchLabels:                     #Labels匹配规则
       app: nginx-pod
    matchExpressions:                #Expression匹配规则
      - {key: app, operator: In, values: [nginx-pod]}
  template:                          #模板,当副本数量不足时,会根据下面的模板创建pod副本
    metadata:
        labels:
          app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        ports:
        - containerPort: 80

2、Deployment更新升级

扩缩容
kubectl scale deploy deploy名称 --replicas=pod数量 -n 命名空间
kubectl edit deploy deploy名字 -n 命名空间
deployment升级和回滚

命令行创建deployment

kubectl run nginx --image=10.0.0.11:5000/nginx:1.13 --replicas=3 --record

命令行升级版本

kubectl set image deploy nginx nginx=10.0.0.11:5000/nginx:1.15

查看deployment所有历史版本

kubectl rollout history deployment nginx

deployment回滚到上一个版本

kubectl rollout undo deployment nginx

deployment回滚到指定版本

kubectl rollout undo deployment nginx --to-revision=2

3、金丝雀发布

deployment支持更新过程中的控制,如"暂停(pause)"或"继续(resume)"更新操作

(1)更新deployment的v3版本,并配置暂停deployment
[root@k8s-master ~]# kubectl set image deployment myapp-deploy myapp=ikubernetes/myapp:v3 && kubectl rollout pause deployment myapp-deploy

[root@k8s-master ~]# kubectl rollout status deployments myapp-deploy  #观察更新状态

(2)监控更新的过程,可以看到已经新增了一个资源,但是并未按照预期的状态去删除一个旧的资源,就是因为使用了pause暂停命令
[root@k8s-master ~]# kubectl get pods -l app=myapp -w 
(3)确保更新的pod没问题了,继续更新
[root@k8s-master ~]# kubectl rollout resume deploy  myapp-deploy
(4)查看最后的更新情况
[root@k8s-master ~]# kubectl get pods -l app=myapp -w 

四、DaemonSet
---------------------- 

1. DaemonSet的主要特征:

-这个 Pod 运行在 Kubernetes 集群里的每一个节点(Node)上;
-每个节点上只会运行一个这样的 Pod 实例;
-如果新的节点加入 Kubernetes 集群后,该 Pod 会自动地在新节点上被创建出来;
-而当旧节点被删除后,它上面的 Pod 也相应地会被回收掉。

2. DaemonSet常用场景:

-   网络插件的 Agent 组件,如(Flannel,Calico)需要运行在每一个节点上,用来处理这个节点上的容器网络;
-   存储插件的 Agent 组件,如(Ceph,Glusterfs)需要运行在每一个节点上,用来在这个节点上挂载F远程存储目录;
-   监控系统的数据收集组件,如(Prometheus Node Exporter,Cadvisor)需要运行在每一个节点上,负责这个节点上的监控信息搜集。
-   日志系统的数据收集组件,如(Fluent,Logstash)需要运行在每一个节点上,负责这个节点上的日志信息搜集。

3.DaemonSet 滚动更新

#查看DaemonSet历史版本
kubectl rollout history daemonset fluentd-elasticsearch -n kube-system
#更新DaemonSet中的镜像版本到 v2.2.0
kubectl set image ds/fluentd-elasticsearch fluentd-elasticsearch=k8s.gcr.io/fluentd-elasticsearch:v2.2.0 --record -n=kube-system
#查看fluentd-elasticsearch`对应的 ControllerRevision
kubectl get controllerrevision -n kube-system -l name=fluentd-elasticsearch
#回滚DaemonSet历史版本
kubectl rollout undo daemonset fluentd-elasticsearch --to-revision=1 -n kube-system

总结:在这篇文章中主要介绍了Kubernetes中第三个重要的编排对象DaemonSet,相比于 Deployment,DaemonSet 只管理 Pod 对象,然后通过 nodeAffinity 和 Toleration 这两个调度器的小功能,保证了每个节点上有且只有一个 Pod。与此同时,DaemonSet 通过使用 ControllerRevision,来保存和管理自己对应的"版本"。其中StatefulSet编排对象也是使用 ControllerRevision 进行版本管理的,这是因为在 Kubernetes 项目里,ControllerRevision 其实是一个通用的版本管理对象。

五、Service的概念

其中重要的4个字段:
apiVersion:
kind:
metadata:
spec:
  clusterIP: 可以自定义,也可以动态分配
  ports:(与后端容器端口关联)
  selector:(关联到哪些pod资源上)
  type:服务类型

Type 的取值以及行为如下:

ClusterIP:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的 ServiceType。
NodePort:通过每个 Node 上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求 <NodeIP>:<NodePort>,可以从集群的外部访问一个 NodePort 服务。
LoadBalancer:使用云提供商的负载均衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务。
ExternalName:通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容(例如, foo.bar.example.com)。 没有任何类型代理被创建,这只有 Kubernetes 1.7 或更高版本的 kube-dns 才支持。
[root@k8s-master mainfests]# cat redis-svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: redis
  namespace: default
spec:
  selector:           #标签选择器,必须指定pod资源本身的标签
    app: redis
    role: logstor
  type: ClusterIP     #指定服务类型为ClusterIP
  ports:              #指定端口
  - port: 6379        #暴露给服务的端口
  - targetPort: 6379  #容器的端口

sessionAffinity支持ClientIP和None 两种方式,默认是None(随机调度) ClientIP是来自于同一个客户端的请求调度到同一个pod中

Ingress和Ingress Controller

Ingress 简单的理解就是你原来需要改 Nginx 配置,然后配置各种域名对应哪个 Service,现在把这个动作抽象出来,变成一个 Ingress 对象,你可以用 yaml 创建,每次不要去改 Nginx 了,直接改 yaml 然后创建/更新就行了
Ingress Controller 这东西就是解决 “Nginx 的处理方式” 的;Ingress Controoler 通过与 Kubernetes API 交互,动态的去感知集群中 Ingress 规则变化,然后读取他,按照他自己模板生成一段 Nginx 配置,再写到 Nginx Pod 里,最后 reload 一下,工作流程如下图:

Ingress资源时基于HTTP虚拟主机或URL的转发规则,需要强调的是,这是一条转发规则。它在资源配置清单中的spec字段中嵌套了rules、backend和tls等字段进行定义。
创建Ingress资源

[root@k8s-master ingress]# vim ingress-myapp.yaml
apiVersion: extensions/v1beta1        #api版本
kind: Ingress                        #清单类型
metadata:                    #元数据
  name: ingress-myapp                   #ingress的名称
  namespace: default                    #所属名称空间
  annotations:                          #注解信息
    kubernetes.io/ingress.class: "nginx"
spec:                                   #规格
  rules:                                #定义后端转发的规则
  - host: myapp.magedu.com              #通过域名进行转发
    http:
      paths:       
      - path:                          #配置访问路径,如果通过url进行转发,需要修改;空默认为访问的路径为"/"
        backend:                       #配置后端服务
          serviceName: myapp
          servicePort: 80

Ingress资源类型

Ingress的资源类型有以下4种:

1、单Service资源型Ingress
2、基于URL路径进行流量转发
3、基于主机名称的虚拟主机
4、TLS类型的Ingress资源

Ingress Nginx部署

使用Ingress功能步骤:
1、安装部署ingress controller Pod
2、部署后端服务
3、部署ingress-nginx service
4、部署ingress

从前面的部署过程中,可以再次进行总结部署的流程如下:
①下载Ingress-controller相关的YAML文件,并给Ingress-controller创建独立的名称空间;
②部署后端的服务,如myapp,并通过service进行暴露;
③部署Ingress-controller的service,以实现接入集群外部流量;
④部署Ingress,进行定义规则,使Ingress-controller和后端服务的Pod组进行关联。
1349539-20180930160336958-1687092087.png

k8s架构师课程之流量入口Ingress上部

六、存储卷

k8s的存储卷类型:

emptyDir(临时目录):Pod删除,数据也会被清除,这种存储成为emptyDir,用于数据的临时存储。
hostPath(宿主机目录映射):
本地的SAN(iSCSI,FC)、NAS(nfs,cifs,http)存储
分布式存储(glusterfs,rbd,cephfs)
云存储(EBS,Azure Disk)

PVC(存储卷创建申请)
当你需要创建一个存储卷时,只需要进行申请对应的存储空间即可使用,这就是PVC
k8s要使用存储卷,需要2步:
1、在pod定义volume,并指明关联到哪个存储设备
2、在容器使用volume mount进行挂载

emptyDir存储卷

Pod删除,数据也会被清除,这种存储成为emptyDir,用于数据的临时存储。

volumes:  #定义存储卷
  - name: html    #定义存储卷名称  
    emptyDir: {}  #定义存储卷类型

hostPath存储卷

hostPath宿主机路径,就是把pod所在的宿主机之上的脱离pod中的容器名称空间的之外的宿主机的文件系统的某一目录和pod建立关联关系,在pod删除时,存储数据不会丢失。
hostPath可以实现持久存储,但是在node节点故障时,也会导致数据的丢失

volumes:
    - name: html
      hostPath:
        path: /data/pod/volume1
        type: DirectoryOrCreate

nfs共享存储卷

注意:必须先报纸NFS服务器正常运行在我们进行挂在nfs的时候

  volumes:
    - name: html
      nfs:
        path: /data/volumes
        server: stor01

PVC和PV的概念

PersistentVolume(PV)是集群中已由管理员配置的一段网络存储。 集群中的资源就像一个节点是一个集群资源。 PV是诸如卷之类的卷插件,但是具有独立于使用PV的任何单个pod的生命周期。 该API对象捕获存储的实现细节,即NFS,iSCSI或云提供商特定的存储系统。
PersistentVolumeClaim(PVC)是用户存储的请求。PVC的使用逻辑:在pod中定义一个存储卷(该存储卷类型为PVC),定义的时候直接指定大小,pvc必须与对应的pv建立关系,pvc会根据定义去pv申请,而pv是由存储空间创建出来的。pv和pvc是kubernetes抽象出来的一种存储资源。

这里有两种PV的提供方式:静态或者动态

查看pv定义的规格

spec:
  nfs(定义存储类型)
    path(定义挂载卷路径)
    server(定义服务器名称)
  accessModes(定义访问模型,有以下三种访问模型,以列表的方式存在,也就是说可以定义多个访问模式)
    ReadWriteOnce(RWO)  单节点读写
    ReadOnlyMany(ROX)  多节点只读
    ReadWriteMany(RWX)  多节点读写
  persistentVolumeReclaimPolicy: Recycle     # 回收策略Retain -- 需要管理员手工回收。 Recycle -- 清除 PV 中的数据,Delete -- 删除 Storage Provider 上的对应存储资源
  storageClassName: nfs     # 指定 PV 的 class 为 nfs。相当于为 PV 设置了一个分类
  capacity(定义PV空间的大小)
    storage(指定大小)

NFS使用PV和PVC

1、配置nfs存储
2、定义PV
3、定义PVC
4、测试访问

StorageClass

[root@k8s-master-01 k8s]# cat nfs-sc.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  namespace: kube-system

---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["list", "watch", "create", "update", "patch"]
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]

---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: kube-system
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io

---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: nfs-provisioner-01
  namespace: kube-system
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-provisioner-01
  template:
    metadata:
      labels:
        app: nfs-provisioner-01
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: hub.kaikeba.com/java12/nfs-client-provisioner:v1
          imagePullPolicy: IfNotPresent
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: nfs-provisioner-01  # 此处供应者名字供storageclass调用
            - name: NFS_SERVER
              value: 192.168.222.151   # 填入NFS的地址
            - name: NFS_PATH
              value: /nfs_dir   # 填入NFS挂载的目录
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.222.151   # 填入NFS的地址
            path: /nfs_dir   # 填入NFS挂载的目录

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-skyhu
provisioner: nfs-provisioner-01
# Supported policies: Delete、 Retain , default is Delete
parameters:
  server: 192.168.222.151
  path: /nfs_dir
reclaimPolicy: Retain

创建PVC

[root@k8s-master-01 k8s]# cat pvc-sc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: pvc-sc
spec:
  storageClassName: nfs-skyhu
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Mi

七、Secret和configMap

Secret:用于向Pod传递敏感信息,比如密码,私钥,证书文件等,这些信息如果在容器中定义容易泄露,Secret资源可以让用户将这些信息存储在急群众,然后通过Pod进行挂载,实现敏感数据和系统解耦的效果。
ConfigMap:主要用于向Pod注入非敏感数据,使用时,用户将数据直接存储在ConfigMap对象当中,然后Pod通过使用ConfigMap卷进行引用,实现容器的配置文件集中定义和管理。

创建 Secret的2种方式

1、通过 --from-literal
kubectl create secret generic mysecret --from-literal=username=admin --from-literal=password=123456
2、通过 --from-file

[root@k8s-master ~]# echo -n admin > ./username
[root@k8s-master ~]# echo -n 123456 > ./password
[root@k8s-master ~]# kubectl create secret generic mysecret --from-file=./username --from-file=./password 

3、通过 --from-env-file

[root@k8s-master ~]# 
cat << EOF > env.txt
username=admin
password=123456
EOF
[root@k8s-master ~]# kubectl create secret generic mysecret --from-env-file=env.txt

4、通过 YAML 配置文件

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
data:
  username: YWRtaW4=      #echo -n admin |base64
  password: MTIzNDU2      #echo -n 123456 |base64

echo -n MTIzNDU2 |base64 --decode #通过 base64 将 Value 反编码:

Pod 可以通过 Volume 或者环境变量的方式使用 Secret

[root@k8s-master volumes]# cat pod-secret-demo.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-secret
spec:
  containers:
  - name: pod-secret
    image: busybox
    args:
      - /bin/sh
      - -c
      - sleep 10;touch /tmp/healthy;sleep 30000
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    secret:
      secretName: mysecret
      items:    #自定义存放数据的文件名
      - key: username
        path: my-secret/my-username    #这时数据将分别存放在 /etc/foo/my-secret/my-username
      - key: password
        path: my-secret/my-password    # /etc/foo/my-secret/my-password

通过 Volume 使用 Secret,容器必须从文件读取数据,会稍显麻烦,Kubernetes 还支持通过环境变量使用 Secret。

apiVersion: v1
kind: Pod
metadata:
  name: pod-secret-env
spec:
  containers:
  - name: pod-secret-env
    image: busybox
    args:
      - /bin/sh
      - -c
      - sleep 10;touch /tmp/healthy;sleep 30000
env:
      - name: SECRET_USERNAME
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: username
      - name: SECRET_PASSWORD
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: password

通过环境变量 SECRET_USERNAME 和 SECRET_PASSWORD 成功读取到 Secret 的数据。
需要注意的是,环境变量读取 Secret 很方便,但无法支撑 Secret 动态更新。
Secret 可以为 Pod 提供密码、Token、私钥等敏感数据;对于一些非敏感数据,比如应用的配置信息,则可以用 ConfigMap。

ConifgMap

ConfigMap创建方式

通过 --from-literal

kubectl create configmap nginx-config --from-literal=nginx_port=80 --from-literal=server_name=myapp.magedu.com

通过 --from-file:

[root@k8s-master configmap]# vim www.conf
server {
    server_name myapp.magedu.com;
    listen 80;
    root /data/web/html;
}

kubectl create configmap nginx-www --from-file=./www.conf

环境变量方式注入到pod

[root@k8s-master configmap]# vim pod-configmap.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-cm-1
  namespace: default
  labels: 
    app: myapp
    tier: frontend
  annotations:
    magedu.com/created-by: "cluster admin"
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80 
    env:
    - name: NGINX_SERVER_PORT
      valueFrom:
        configMapKeyRef:
          name: nginx-config
          key: nginx_port
    - name: NGINX_SERVER_NAME
      valueFrom:
        configMapKeyRef:
          name: nginx-config
          key: server_name

存储卷方式挂载configmap

[root@k8s-master configmap ~]# vim pod-configmap-2.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-cm-2
  namespace: default
  labels: 
    app: myapp
    tier: frontend
  annotations:
    magedu.com/created-by: "cluster admin"
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80 
    volumeMounts:
    - name: nginxconf
      mountPath: /etc/nginx/config.d/
      readOnly: true
  volumes:
  - name: nginxconf
    configMap:
      name: nginx-config

以nginx-www配置nginx

[root@k8s-master configmap ~]# vim pod-configmap3.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-cm-3
  namespace: default
  labels: 
    app: myapp
    tier: frontend
  annotations:
    magedu.com/created-by: "cluster admin"
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80 
    volumeMounts:
    - name: nginxconf
      mountPath: /etc/nginx/conf.d/
      readOnly: true
  volumes:
  - name: nginxconf
    configMap:
      name: nginx-www

八、statefulset

1、稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现
2、稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现
3、有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),基于init containers来实现
4、有序收缩,有序删除(即从N-1到0)
5、有序的滚动更新
有状态服务sts比较常见的mongo复制集 ,redis cluster,rabbitmq cluster等等
在创建StatefulSet之前需要准备的东西,值得注意的是创建顺序非常关键,创建顺序如下:
1、Volume
2、Persistent Volume
3、Persistent Volume Claim
4、Service
5、StatefulSet
Volume可以有很多种类型,比如nfs、glusterfs等,我们这里使用的ceph RBD来创建。

清单定义StatefulSet

[root@k8s-master mainfests]# vim stateful-demo.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp-svc
  labels:
    app: myapp-svc
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: myapp-pod
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: myapp
spec:
  serviceName: myapp-svc
  replicas: 3
  selector:
    matchLabels:
      app: myapp-pod
  template:
    metadata:
      labels:
        app: myapp-pod
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: myappdata
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: myappdata
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 2Gi

当删除的时候是从myapp-2开始进行删除的,关闭是逆向关闭

####扩展伸缩
kubectl scale sts myapp --replicas=4  #扩容副本增加到4个
kubectl patch sts myapp -p '{"spec":{"replicas":2}}'  #打补丁方式缩容
####更新策略和版本升级  (金丝雀部署)
修改更新策略,以partition方式进行更新,更新值为2,只有myapp编号大于等于2的才会进行更新。类似于金丝雀部署方式。
kubectl patch sts myapp -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":2}}}}'
版本升级,将image的版本升级为v3,升级后对比myapp-2和myapp-1的image版本是不同的。这样就实现了金丝雀发布的效果
kubectl set image sts/myapp myapp=ikubernetes/myapp:v3
将剩余的Pod也更新版本,只需要将更新策略的partition值改为0即可,如下:
kubectl patch sts myapp -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'

九、K8S组件运行原理详解总结

k8s master 组件: apiserver、 scheduler controller-manager、ectd
node 组件:docker 、kubelet、kube-proxy
完整的集群还包括:ingress controler、coredns、dashboard、prometheus等附加组件

Master组件

1、API Server
K8S对外的唯一接口,提供HTTP/HTTPS RESTful API,即kubernetes API。所有的请求都需要经过这个接口进行通信。主要负责接收、校验并响应所有的REST请求,结果状态被持久存储在etcd当中,所有资源增删改查的唯一入口。

2、etcd
负责保存k8s 集群的配置信息和各种资源的状态信息,当数据发生变化时,etcd会快速地通知k8s相关组件。etcd是一个独立的服务组件,并不隶属于K8S集群。生产环境当中etcd应该以集群方式运行,以确保服务的可用性。

etcd不仅仅用于提供键值数据存储,而且还为其提供了监听(watch)机制,用于监听和推送变更。在K8S集群系统中,etcd的键值发生变化会通知倒API Server,并由其通过watch API向客户端输出。

3、Controller Manager
负责管理集群各种资源,保证资源处于预期的状态。Controller Manager由多种controller组成,包括replication controller、endpoints controller、namespace controller、serviceaccounts controller等 。由控制器完成的主要功能主要包括生命周期功能和API业务逻辑,具体如下:

生命周期功能:包括Namespace创建和生命周期、Event垃圾回收、Pod终止相关的垃圾回收、级联垃圾回收及Node垃圾回收等。
API业务逻辑:例如,由ReplicaSet执行的Pod扩展等。
4、调度器(Schedule)
资源调度,负责决定将Pod放到哪个Node上运行。Scheduler在调度时会对集群的结构进行分析,当前各个节点的负载,以及应用对高可用、性能等方面的需求。

Node组件

Node主要负责提供容器的各种依赖环境,并接受Master管理。每个Node有以下几个组件构成。

1、Kubelet
kubelet是node的agent,当Scheduler确定在某个Node上运行Pod后,会将Pod的具体配置信息(image、volume等)发送给该节点的kubelet,kubelet会根据这些信息创建和运行容器,并向master报告运行状态。

2、Container Runtime
每个Node都需要提供一个容器运行时(Container Runtime)环境,它负责下载镜像并运行容器。目前K8S支持的容器运行环境至少包括Docker、RKT、cri-o、Fraki等。

3、Kube-proxy
service在逻辑上代表了后端的多个Pod,外借通过service访问Pod。service接收到请求就需要kube-proxy完成转发到Pod的。每个Node都会运行kube-proxy服务,负责将访问的service的TCP/UDP数据流转发到后端的容器,如果有多个副本,kube-proxy会实现负载均衡,有2种方式:LVS或者Iptables

核心附件

1、KubeDNS
在K8S集群中调度并运行提供DNS服务的Pod,同一集群内的其他Pod可以使用该DNS服务来解决主机名。K8S自1.11版本开始默认使用CoreDNS项目来为集群提供服务注册和服务发现的动态名称解析服务。

2、Dashboard
K8S集群的全部功能都要基于Web的UI,来管理集群中的应用和集群自身。

3、Heapster
容器和节点的性能监控与分析系统,它收集并解析多种指标数据,如资源利用率、生命周期时间,在最新的版本当中,其主要功能逐渐由Prometheus结合其他的组件进行代替。

4、Ingress Controller
Service是一种工作于4层的负载均衡器,而Ingress是在应用层实现的HTTP(S)的负载均衡。不过,Ingress资源自身并不能进行流量的穿透,,它仅仅是一组路由规则的集合,这些规则需要通过Ingress控制器(Ingress Controller)发挥作用。目前该功能项目大概有:Nginx-ingress、Traefik、Envoy和HAproxy等

K8S的网络模型

K8S的网络中主要存在4种类型的通信:

①同一Pod内的容器间通信
②各个Pod彼此间的通信
③Pod和Service间的通信
④集群外部流量和Service之间的通信
一个K8S集群包含是三个网络。

(1)节点网络:各主机(Master、Node、ETCD等)自身所属的网络,地址配置在主机的网络接口,用于各主机之间的通信,又称为节点网络。
(2)Pod网络:专用于Pod资源对象的网络,它是一个虚拟网络,用于为各Pod对象设定IP地址等网络参数,其地址配置在Pod中容器的网络接口上。Pod网络需要借助kubenet插件或CNI插件实现。
(3)Service网络:专用于Service资源对象的网络,它也是一个虚拟网络,用于为K8S集群之中的Service配置IP地址,但是该地址不会配置在任何主机或容器的网络接口上,而是通过Node上的kube-proxy配置为iptables或ipvs规则,从而将发往该地址的所有流量调度到后端的各Pod对象之上。


而需要将集群外部的访问引入集群内部的常用方法是通过节点网络进行,其实现方法如下:

通过工作节点的IP地址+端口(Node Port)接入请求。
将该请求代理到相应的Service对象的Cluster IP的服务端口上,通俗地说:就是工作节点上的端口映射了Service的端口。
由Service对象将该请求转发到后端的Pod对象的Pod IP和 应用程序的监听端口。

十、k8s网络模型和网络策略

Kubernetes网络模型

我们知道的是,在K8S上的网络通信包含以下几类:

容器间的通信:同一个Pod内的多个容器间的通信,它们之间通过lo网卡进行通信。

Pod之间的通信:通过Pod IP地址进行通信。

Pod和Service之间的通信:Pod IP地址和Service IP进行通信,两者并不属于同一网络,实现方式是通过IPVS或iptables规则转发。

Service和集群外部客户端的通信,实现方式:Ingress、NodePort、Loadbalance

K8S网络的实现不是集群内部自己实现,而是依赖于第三方网络插件----CNI(Container Network Interface)

flannel、calico、canel等是目前比较流行的第三方网络插件。
常见的CNI网络插件包含以下几种:

Flannel:为Kubernetes提供叠加网络的网络插件,基于TUN/TAP隧道技术,使用UDP封装IP报文进行创建叠 加网络,借助etcd维护网络的分配情况,缺点:无法支持网络策略访问控制。
Calico:基于BGP的三层网络插件,也支持网络策略进而实现网络的访问控制;它在每台主机上都运行一个虚拟路由,利用Linux内核转发网络数据包,并借助iptables实现防火墙功能。实际上Calico最后的实现就是将每台主机都变成了一台路由器,将各个网络进行连接起来,实现跨主机通信的功能。
Canal:由Flannel和Calico联合发布的一个统一网络插件,提供CNI网络插件,并支持网络策略实现。
其他的还包括Weave Net、Contiv、OpenContrail、Romana、NSX-T、kube-router等等。而Flannel和Calico是目前最流行的选择方案。

十一、Pod资源调度

定义节点亲和性规则有2种:硬亲和性(require)和软亲和性(preferred)

硬亲和性:实现的是强制性规则,是Pod调度时必须满足的规则,否则Pod对象的状态会一直是Pending
软亲和性:实现的是一种柔性调度限制,在Pod调度时可以尽量满足其规则,在无法满足规则时,可以调度到一个不匹配规则的节点之上。
定义节点亲和规则的两个要点:一是节点配置是否合乎需求的标签,而是Pod对象定义合理的标签选择器,这样才能够基于标签选择出期望的目标节点。

用节点硬亲和性和规则定义将当前Pod调度到标签为zone=foo的节点上

apiVersion: v1
kind: Pod
metadata:
  name: with-require-nodeaffinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - {key: zone,operator: In,values: ["foo"]}
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
#由于集群中并没有节点含有节点标签为zone=foo,所以创建的Pod一直处于Pending状态
#查看Pending具体的原因
[root@k8s-master ~]# kubectl describe pods with-require-nodeaffinity
......
Events:
  Type     Reason            Age               From               Message
  ----     ------            ----              ----               -------
  Warning  FailedScheduling  3s (x21 over 1m)  default-scheduler  0/3 nodes are available: 3 node(s) didn't match node selector.

给node01节点打上zone=foo的标签,可以看到成功调度到node01节点上
[root@k8s-master ~]# kubectl label node k8s-node01 zone=foo

节点软亲和性

spec:
        affinity:
          nodeAffinity:
            preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 60
              preference:
                matchExpressions:
                - {key: zone, operator: In, values: ["foo"]}
            - weight: 30
              preference:
                matchExpressions:
                - {key: ssd, operator: Exists, values: []}
#首先先给node02和master都打上标签,master标签为zone=foo,node02标签为ssd=true,这里node01是没有对应标签的
kubectl label node k8s-node02 ssd=true
kubectl label node k8s-master zone=foo
可以看到5个Pod分别分布在不同的节点上,node01上没有对应的标签也会调度上进行创建Pod,体现软亲和性
如果我们给node01打上zone=foo,ssd=true的标签,再去创建时,你会发现所有的Pod都调度在这个节点上。因为节点的软亲和性,会尽力满足Pod中定义的规则,如下:
[root@k8s-master ~]# kubectl label node k8s-node01 zone=foo
[root@k8s-master ~]# kubectl label node k8s-node01 ssd=true
[root@k8s-master ~]# kubectl get pods -o wide |grep deploy-with
上面的实验结果显示,当2个标签没有都存在一个node节点上时,Pod对象会被分散在集群中的三个节点上进行创建并运行,之所以如此,是因为使用了 节点软亲和性的预选方式,所有的节点都能够通过MatchNodeSelector预选策略的筛选。当我们将2个标签都集合在node01上时,所有Pod对象都会运行在node01之上。

NodeSelector:定向调度

通常我们无法知道Pod最终会被调度到哪个节点上。在实际情况下,也可能需要将Pod调度到指定的一些Node上,可以通过Node的标签(Label)和Pod的nodeSelector属性相匹配,来达到上述目的。

#语法kubectl label nodes <node-name> <label-key>=<label-value>
#示例,如果节点名称是harmonycloud,需要添加‘disktype=ssd’标签kubectl lable nodes harmonycloud disktype=ssd
# 验证,使用如下命令查看是否成功给node添加标签kubectl get nodes --show-labels

然后,在Pod的定义中加上nodeSelector的设置

需要注意的是,如果我们指定了Pod的nodeSelector条件,且在集群中不存在包含相应标签的Node,则即使在集群中还有其他可供使用的Node,这个Pod也无法被成功调度。

NodeAffinity:Node亲和性调度

NodeAffinity 意为Node 亲和性的调度策略, 是用于替换NodeSelector的全新调度策略。目前有两种节点亲和性表达。
◎ requiredDuringSchedulingIgnoredDuringExecution:必须满足指定的规则才可以调度Pod到Node上(功能与nodeSelector很像,但是使用的是不同的语法),相当于硬限制。
◎ preferredDuringSchedulingIgnoredDuringExecution:强调优先满足指定规则,调度器会尝试调度Pod到Node上,但并不强求,相当于软限制。多个优先级规则还可以设置权重(weight)值,以定义执行的先后顺序。

硬策略

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: nodeType
          operator: In
          values:
          - dev

3.2.软策略

affinity:
  nodeAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
    - weight: 1
      preference:
        matchExpressions:
        - key: nodeType
          operator: In
          values:
          - test

NodeAffinity语法支持的操作
符包括In、NotIn、Exists、DoesNotExist、Gt、Lt。虽然没有节点排斥功能,但是用NotIn和DoesNotExist就可以实现排斥的功能了。

NodeAffinity规则设置的注意事项如下。
◎ 如果同时定义了nodeSelector和nodeAffinity,那么必须两个条
件都得到满足,Pod才能最终运行在指定的Node上。
◎ 如果nodeAffinity指定了多个nodeSelectorTerms,那么其中一
个能匹配成功即可。
◎ 如果在nodeSelectorTerms中有多个matchExpressions,则一个
节点必须满足所有matchExpressions才能运行该Pod。

PodAffinity:Pod亲和与互斥调度策略

Pod的亲和性和互斥性调度具体作法,就是通过在Pod上定义上增加topologyKey属性,来声明对应的目标拓扑区域内几种相关联的Pod“在一起或不在一起”。与节点亲和性相同,Pod亲和性与互斥的条件设置也是requireDuringSchedulingIgnoredExecution和preferredDuringSchedulingIgnoredExecution。Pod的亲和性被定义与PodSpec的affinity字段的podAffinity子字段中;Pod间的互斥性被定义与同一层次的PodAntiAffinity。

Pod亲和性调度测试
1.参数目标pod
首先创建一个名为pod-flag的Pod,带有标签security=S1和app=nginx,后面例子将使用到pod-flag作为Pod亲和性和互斥的目标Pod:

apiVersion: v1
kind: Pod
metadata:
  name: pod-flag
  labels:
    security: "S1"
    app: "nginx"
spec:
  containers:
  - name: nginx
    image: nginx

Pod 亲和性调度

 创建2个Pod来说明Pod亲和性调度,定义亲和性标签"security=S1"对应上面Pod "pod-flag",topologyKey的值被设置为 "kubernetes.io/hostname" :
apiVersion: v1
kind: Pod
metadata:
  name: pod-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
         matchExpressions:
         - key: security
           operator: In
           values:
            - S1
        topologyKey: kubernetes.io/hostname
  containers:
  - name: with-pod-affinity
    image: nginx

创建Pod之后,使用kubectl get pod -o wide 查看,两个Pod被调度到同一个k8s-node-01上。

pod-affinity       1/1     Running       0       10m   10.255.44.8      k8s-node-01     <none>     <none>

pod-flag           1/1     Running        0       13m   10.255.44.7      k8s-node-01     <none>    <none>

Pod互斥性调度测试

 创建3个Pod,希望它不与目标Pod运行在同一个Node上。
apiVersion: v1
kind: Pod
metadata:
  name: anti-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - S1
        topologyKey: topology.kubernetes.io/zone
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - nginx
        topologyKey: kubetnetes.io/hostname
  containers:
  - name: anti-affinity
    image: nginx

污点和容忍度

污点(taints)是定义在节点上的一组键值型属性数据,用来让节点拒绝将Pod调度到该节点上,除非该Pod对象具有容纳节点污点的容忍度。而容忍度(tolerations)是定义在Pod对象上的键值型数据,用来配置让Pod对象可以容忍节点的污点。

前面的节点选择器和节点亲和性的调度方式都是通过在Pod对象上添加标签选择器来完成对特定类型节点标签的匹配,实现的是Pod选择节点的方式。而污点和容忍度则是通过对节点添加污点信息来控制Pod对象的调度结果,让节点拥有了控制哪种Pod对象可以调度到该节点上的 一种方式。

Kubernetes使用PodToleratesNodeTaints预选策略和TaintTolerationPriority优选函数来完成这种调度方式。

定义污点和容忍度

污点的定义是在节点的nodeSpec,而容忍度的定义是在Pod中的podSpec,都属于键值型数据,两种方式都支持一个effect标记,语法格式为key=value: effect,其中key和value的用户和格式和资源注解类似,而effect是用来定义对Pod对象的排斥等级,主要包含以下3种类型:

NoSchedule:不能容忍此污点的新Pod对象不能调度到该节点上,属于强制约束,节点现存的Pod对象不受影响。
PreferNoSchedule:NoSchedule属于柔性约束,即不能容忍此污点的Pod对象尽量不要调度到该节点,不过无其他节点可以调度时也可以允许接受调度。
NoExecute:不能容忍该污点的新Pod对象不能调度该节点上,强制约束,节点现存的Pod对象因为节点污点变动或Pod容忍度的变动导致无法匹配规则,Pod对象就会被从该节点上去除。
在Pod对象上定义容忍度时,其支持2中操作符:Equal和Exists

Equal:等值比较,表示容忍度和污点必须在key、value、effect三者之上完全匹配。
Exists:存在性判断,表示二者的key和effect必须完全匹配,而容忍度中的value字段使用空值。
在使用kubeadm部署的集群中,master节点上将会自动添加污点信息,阻止不能容忍该污点的Pod对象调度到该节点上,如下:

[root@k8s-master ~]# kubectl describe node k8s-master
Name:               k8s-master
Roles:              master
......
Taints:             node- role. kubernetes. io/ master: NoSchedule
......

而一些系统级别的应用在创建时,就会添加相应的容忍度来确保被创建时可以调度到master节点上,如flannel插件:

[root@k8s-master ~]# kubectl describe pods kube-flannel-ds-amd64-2p8wm -n kube-system
......
Tolerations:     node-role.kubernetes.io/master:NoSchedule
                 node.kubernetes.io/disk-pressure:NoSchedule
                 node.kubernetes.io/memory-pressure:NoSchedule
                 node.kubernetes.io/not-ready:NoExecute
                 node.kubernetes.io/unreachable:NoExecute
......

管理节点的污点

使用命令行向节点添加污点

语法:kubectl taint nodes <nodename> <key>=<value>:<effect>......
 
#定义k8s-node01上的污点
[root@k8s-master ~]# kubectl taint nodes k8s-node01 node-type=production:NoSchedule
node/k8s-node01 tainted
 
#查看节点污点信息
[root@k8s-master ~]# kubectl get nodes k8s-node01 -o go-template={{.spec.taints}}
[map[effect:NoSchedule key:node-type value:production]]
此时,node01节点上已经存在的Pod对象不受影响,仅对新建Pod对象有影响,需要注意的是,如果是同一个键值数据,但是最后的标识不同,也是属于不同的污点信息,比如再给node01上添加一个污点的标识为:PreferNoSchedule

[root@k8s-master ~]# kubectl taint nodes k8s-node01 node-type=production:PreferNoSchedule
node/k8s-node01 tainted
 
[root@k8s-master ~]# kubectl get nodes k8s-node01 -o go-template={{.spec.taints}}
[map[value:production effect:PreferNoSchedule key:node-type] map[key:node-type value:production effect:NoSchedule]]

删除污点

语法:kubectl taint nodes <node-name> <key>[: <effect>]-
 
#删除node01上的node-type标识为NoSchedule的污点
[root@k8s-master ~]# kubectl taint nodes k8s-node01 node-type:NoSchedule-
node/k8s-node01 untainted
 
#删除指定键名的所有污点
[root@k8s-master ~]# kubectl taint nodes k8s-node01 node-type-
node/k8s-node01 untainted
 
#补丁方式删除节点上的全部污点信息
[root@k8s-master ~]# kubectl patch nodes k8s-node01 -p '{"spec":{"taints":[]}}'

Pod对象的容忍度

Pod对象的容忍度可以通过spec.tolerations字段进行添加,同一的也有两种操作符:Equal和Exists方式。Equal等值方式如下:

tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "Noexecute"
  tolerationSeconds: 3600
Exists方式如下:

tolerations: 
- key: "key1" 
  operator: "Exists" 
  effect: "NoExecute" 
  tolerationSeconds: 3600

Helm程序包管理器

安装Helm

我们将 Helm 客户端安装在能够执行 kubectl 命令的节点上,只需要下面一条命令:
curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash

通常建议安装 helm 的 bash 命令补全脚本,方法如下:

helm completion bash > .helmrc
echo "source .helmrc" >> .bashrc

Tiller 服务器
Tiller 服务器安装非常简单,只需要执行 helm init
docker pull hqq365.com:8443/k8s/tiller:v2.17.0
docker tag hqq365.com:8443/k8s/tiller:v2.17.0 ghcr.io/helm/tiller:v2.17.0
yum install -y socat
kubectl get pods -n kube-system |grep tiller
helm version

卸载Tiller

(1)kubectl delete deployment tiller-deploy --n kube-system
(2)heml reset

helm的使用

helm常用命令:
- helm search:    搜索charts
- helm fetch:     下载charts到本地目录
- helm install:   安装charts
- helm list:      列出charts的所有版本

 helm repo remove stable #移除stable repo
 helm repo add stable https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts #增加阿里云的charts仓库
helm repo update #更新repo

安装mysql
helm search mysql
helm install stable/mysql
Error: no available release name found
如果看到上面的报错,通常是因为 Tiller 服务器的权限不足。执行以下命令添加权限:
kubectl create serviceaccount --namespace kube-system tiller
kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'
一旦安装了某个 chart,我们就可以在 ~/.helm/cache/archive 中找到 chart 的 tar 包。
Chart.yaml:YAML 文件,描述 chart 的概要信息。
README.md:Markdown 格式的 README 文件,相当于 chart 的使用文档,此文件为可选。
LICENSE:文本文件,描述 chart 的许可信息,此文件为可选。
requirements.yaml :chart 可能依赖其他的 chart,这些依赖关系可通过 requirements.yaml 指定。
values.yaml:chart 支持在安装的时根据参数进行定制化配置,而 values.yaml 则提供了这些配置参数的默认值。
templates目录:各类 Kubernetes 资源的配置模板都放置在这里。Helm 会将 values.yaml 中的参数值注入到模板中生成标准的 YAML 配置文件。
templates/NOTES.txt:chart 的简易使用文档,chart 安装成功后会显示此文档内容。 与模板一样,可以在 NOTE.txt 中插入配置参数,Helm 会动态注入参数值。

定制安装MySQL chart

1、chart安装准备
预先创建好相应的 PV
2、定制化安装chart
(1)指定自己的 values 文件。
通常的做法是首先通过 helm inspect values mysql > myvalues.yaml生成 values 文件,然后设置 mysqlRootPassword,之后执行 helm install --values=myvalues.yaml mysql。
(2)通过 --set 直接传入参数值,比如:
[root@k8s-master ~]# helm install stable/mysql --set mysqlRootPassword=abc123 -n my
3、升级和回滚release
helm upgrade --set imageTag=5.7.15 my stable/mysql
helm history my   #查看 release 所有的版本
helm rollback my 1 #可以回滚到任何版本

标签: none

添加新评论