Kubernetes

指令很全的K8s学习笔记

本文主要是介绍指令很全的K8s学习笔记,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

常用指令

Kubectl命令行管理对象
类型 命令 描述
基础命令
create 通过文件名或标准输入创建资源。
expose 将一个资源公开为一个新的Kubernetes服务。
run
创建并运行一个特定的镜像,可能是副本。
创建一个deployment或job管理创建的容器。
set 配置应用资源。
修改现有应用程序资源。
get 显示一个或多个资源。
explain 文档参考资料。
edit 使用默认的编辑器编辑一个资源。
delete 通过文件名、标准输入、资源名称或标签选择器来删除资源。
部署命令
rollout 管理资源的发布。
rolling-update 执行指定复制控制的滚动更新。
scale 扩容或缩容Pod数量,Deployment、ReplicaSet、RC或Job。
autoscale 创建一个自动选择扩容或缩容并设置Pod数量。
集群管理命令
certificate 修改证书资源。
cluster-info 显示集群信息。
top 显示资源(CPU/Memory/Storage)使用。需要Heapster运行。
cordon 标记节点不可调度。
uncordon 标记节点可调度。
drain 维护期间排除节点。
taint
--------------------------------------
Kubectl命令行管理对象
类型 命令 描述
故障诊断和调试命令
describe 显示特定资源或资源组的详细信息。
logs 在pod或指定的资源中容器打印日志。如果pod只有一个容器,容器名称是可选的。
attach 附加到一个进程到一个已经运行的容器。
exec 执行命令到容器。
port-forward 转发一个或多个本地端口到一个pod。
proxy 为kubernetes API Server启动服务代理。
cp 拷贝文件或目录到容器中。
auth 检查授权。
高级命令
apply 通过文件名或标准输入对资源应用配置。
patch 使用补丁修改、更新资源的字段。
replace 通过文件名或标准输入替换一个资源。
convert 不同的API版本之间转换配置文件。YAML和JSON格式都接受。
设置命令
label 更新资源上的标签。
annotate 在一个或多个资源上更新注释。
completion 用于实现kubectl工具自动补全。
其他命令
api-versions 打印受支持的API版本。
config 修改kubeconfig文件(用于访问API,比如配置认证信息)。
help 所有命令帮助。
plugin 运行一个命令行插件。
version 打印客户端和服务版本信息
------------------------------------
Kubectl命令行管理对象
示例:
# 运行应用程序
kubectl run hello-world --replicas=3 --labels="app=example" --image=nginx:1.10 --port=80
# 显示有关Deployments信息
kubectl get deployments hello-world
kubectl describe deployments hello-world
# 显示有关ReplicaSet信息
kubectl get replicasets
kubectl describe replicasets
# 创建一个Service对象暴露Deployment(在88端口负载TCP流量)
kubectl expose deployment hello-world --port=88 --type=NodePort --target-port=80 --name=example-service
# 创建一个Service对象暴露Deployment(在4100端口负载UDP流量)
kubectl expose deployment hello-world --port=4100 --type=NodePort --protocol=udp --target-port=80 --
name=example-service
# 显示有关Service信息
kubectl describe services example-service
# 使用节点IP和节点端口访问应用程序
curl http://<public-node-ip>:<node-port>

#根据端口查询服务
netstat -anpt | grep : 端口号

#ingress查看
kubectl get svc -n ingress-ngnix

#获取configmap
kubuvtl get cm

#configmap详细信息
kubectl describe cm configmap名称

#修改configmap
kubectl edit configmap configmap名称

#阿里云时间同步服务器
ntpdate ntp1.aliyun.com

#获取pv
kubectl get pv

#获取pvc
kubectl get pvc

#获取指定pv的内容输出格式为yaml
kubectl get pv pv名称 -o yaml

#修改内容
kubectl edit pv pv名称



#通过 kubectl replace 命令完成对Node 状态的修改
[root@master node]# kubectl replace -f unschedule_node.yaml 
node/192.168.0.222 replaced
[root@master node]# kubectl get nodes
NAME            STATUS                     ROLES     AGE       VERSION
192.168.0.144   Ready                      <none>    25d       v1.11.6
192.168.0.148   Ready                      <none>    25d       v1.11.6
192.168.0.222   Ready,SchedulingDisabled   <none>    5d        v1.11.6

#查看Node的状态,可以观察到在Node的状态中增加了一项SchedulingDisabled,对于后续创建的Pod,系统将不会再向该Node进行调度。也可以不使用配置文件,直接使用 kubectl patch 命令完成:
kubectl patch node k8s-node-1 -p '{"spec": {"unschedulaable": true}}'
#需要注意的是,将某个Node脱离调度范围时,在其上运行的pod并不会自动停止,管理员需要手动停止在改Node是上运行的pod.
#同样,如果需要将某个node重新纳入集群调度范围,则将unschedulable 设置为false,再次执行 kubectl replace 或者kubectl  patch 命令就能恢复系统对改node的调度。

#第三种方法:
#使用kubectl cordon <node_name> 对某个Node 进行隔离调度操作
[root@master node]# kubectl cordon 192.168.0.148
node/192.168.0.148 cordoned
[root@master node]# kubectl get nodes
NAME            STATUS                     ROLES     AGE       VERSION
192.168.0.144   Ready                      <none>    25d       v1.11.6
192.168.0.148   Ready,SchedulingDisabled   <none>    25d       v1.11.6
192.168.0.222   Ready,SchedulingDisabled   <none>    5d        v1.11.6

#恢复调度操作:
[root@master node]# kubectl uncordon 192.168.0.222
node/192.168.0.222 uncordoned
[root@master node]# kubectl get nodes
NAME            STATUS    ROLES     AGE       VERSION
192.168.0.144   Ready     <none>    25d       v1.11.6
192.168.0.148   Ready     <none>    25d       v1.11.6
192.168.0.222   Ready     <none>    5d        v1.11.6

#创建命名空间
kubectl create namespace 名称

#获取命名空间
kubectl get namespace

#删除命名空间
kubectl delete namespace 名称


#获取目前API接口信息
kubectl   api-resources

#对运行时容器进行修改
kubectl patch pod rc-容器app名称-kpiqt -p

#对副本扩缩容
kubectl scale rc rc-容器app名称 —replicas=扩缩容数量

#pod对副本自动进行扩缩容
kubectl autoscale rc rc-容器app名称 --min=1 --max=4

kubectl常用命令:
kubectl cluster-info #查看集群信息

kubectl describe pod -n kube-system kube-flannel-ds-amd64-trpqq #查看pod的描述信息

kubectl get pods -n kube-system #查看指定命名空间的pod

kubectl create deployment NAME --image=image [--dry-run] [options] #创建deployment, dry-run为true就是测试不执行

kubectl create serviceaccount admin -o yaml --dry-run #针对所有可以用kubectl create 创建的资源,都可以加 -o yaml --dry-run ,用来导出yaml标准格式的文件。

kubectl expose deployment nginx-deploy --name=nginx --port=80 --target-port=80 --protocol=TCP

#为deployment创建service, --name为service的名字, --port为暴露端口, --target-port为目标pod端口

dig -t A nginx.default.svc.cluster.local @10.96.0.10 #验证是否能正确解析service, @后边的ip为k8s的dns地址

kubectl describe svc nginx #查看名为nginx的这个service的详细信息

kubectl get pods --show-labels #查看pod的标签

kubectl scale deployment nginx-deploy --replicas=3 #扩容或缩容, --replicas为数量

wget -O - -q nginx-deploy

kubectl rollout undo deployment myapp-deploy --to-revision=1 #回滚到指定版本, 默认回滚到上一版本

kubectl explain pod #查看pod用法的详细信息(参数选项等)

kubectl指令使用

kubectl工具的使用

        #创建
        kubectl run nginx --replicas=3 --labels="app=nginx-example" --image=nginx:1.17.4 --port=80

        #查看
        kubectl get deploy
        kubectl get pods --show-labels
        kubectl get pods -l app=example
        kubectl get pods -o wide

        #发布
        kubectl expose deployment nginx --port=88 --type=NodePort --tartget-port=80 --name=nginx-service 
        kubectl describe service nginx-service

        #故障排查
        kubectl describe TYPE NAME_PREFIX
        kubectl logs nginx-xxx
        kubectl exec -it nginx-xxx bash

        #更新 
        kubectl set image deployment/nginx nginx=nginx:1.17.4 
        或 
        kubectl edit deployment/nginx

        #资源发布管理
        kubectl rollout status deployment/nginx
        kubectl rollout history deployment/nginx
        kubectl rollout history deployment/nginx --revision=3 kubectl scale deployment nginx --replicas=10

        #回滚 
        kubectl rollout undo deployment/nginx-deployment
        kubectl rollout undo deployment/nginx-deployment --to-revision=3

        #删除
        kubectl delete deploy/nginx
        kubectl delete svc/nginx-service

        #写yaml文件用到的api
        #定义配置时,指定最新稳定版API(当前为v1)
        kubectl api-versions

K8S创建的相关yaml文件

一、K8S-yaml的使用及命令

YAML配置文件管理对象
对象管理:
# 创建deployment资源
kubectl create -f nginx-deployment.yaml
# 查看deployment
kubectl get deploy
# 查看ReplicaSet
kubectl get rs
# 查看pods所有标签
kubectl get pods --show-labels
# 根据标签查看pods
kubectl get pods -l app=nginx
# 滚动更新镜像
kubectl set image deployment/nginx-deployment nginx=nginx:1.11
或者
kubectl edit deployment/nginx-deployment
或者
kubectl apply -f nginx-deployment.yaml
# 实时观察发布状态:
kubectl rollout status deployment/nginx-deployment
# 查看deployment历史修订版本
kubectl rollout history deployment/nginx-deployment
kubectl rollout history deployment/nginx-deployment --revision=3
# 回滚到以前版本
kubectl rollout undo deployment/nginx-deployment
kubectl rollout undo deployment/nginx-deployment --to-revision=3
# 扩容deployment的Pod副本数量
kubectl scale deployment nginx-deployment --replicas=10
# 设置启动扩容/缩容
kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80

二、POD

实例1:三种策略

apiVersion: v1
kind: Pod
metadata:
  name: pod-test
  labels:
     os: centos
spec:
  containers:
  - name: hello
    image: centos:7
    env:
    - name: Test
      value: "123456"
    command: ["bash","-c","while true;do date;sleep 1;done"]
  restartPolicy: OnFailure


支持三种策略:
Always:当容器终止退出后,总是重启容器,默认策略。
OnFailure:当容器异常退出(退出状态码非0)时,才重启容器。
Never:当容器终止退出,从不重启容器。

实例2:数据持久化和共享

apiVersion: v1
kind: Pod
metadata:
  name: pod-test1
  labels:
     test: centos
spec:
  containers:
  # 第一个容器
  - name: hello-write
    image: centos:7
    command: ["bash","-c","for i in {1..1000};do echo $i >> /data/hello;sleep 1;done"]
  # 第二个容器
  - name: hello-read
    image: centos:7
    command: ["bash","-c","for i in {1..1000};do cat $i >> /data/hello;sleep 1;done"]
    volumeMounts:
      - name: data
        mountPath: /data
  # 数据卷
  volumes:
  - name: data
    hostPath:
      path: /data

实例3:pod的端口映射

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.10
    ports:
    - name: http
      containerPort: 80
      hostIP: 0.0.0.0
      hostPort: 80
      protocol: TCP
    - name: https
      containerPort: 443
      hostIP: 0.0.0.0
      hostPort: 443
      protocol: TCP

实例4

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.10
    ports:
    - containerPort: 80
    livenessProbe:
      httpGet:
        path: /index.html
        port: 80

详细解析

apiVersion: v1 #指定api版本,此值必须在kubectl apiversion中  
kind: Pod #指定创建资源的角色/类型  
metadata: #资源的元数据/属性  
  name: web04-pod #资源的名字,在同一个namespace中必须唯一  
  labels: #设定资源的标签,详情请见http://blog.csdn.net/liyingke112/article/details/77482384
    k8s-app: apache  
    version: v1  
    kubernetes.io/cluster-service: "true"  
  annotations:            #自定义注解列表  
    - name: String        #自定义注解名字  
spec:#specification of the resource content 指定该资源的内容  
  restartPolicy: Always #表明该容器一直运行,默认k8s的策略,在此容器退出后,会立即创建一个相同的容器  
  nodeSelector:     #节点选择,先给主机打标签kubectl label nodes kube-node1 zone=node1  
    zone: node1  
  containers:  
  - name: web04-pod #容器的名字  
    image: web:apache #容器使用的镜像地址  
    imagePullPolicy: Never #三个选择Always、Never、IfNotPresent,每次启动时检查和更新(从registery)images的策略,
                           # Always,每次都检查
                           # Never,每次都不检查(不管本地是否有)
                           # IfNotPresent,如果本地有就不检查,如果没有就拉取
    command: ['sh'] #启动容器的运行命令,将覆盖容器中的Entrypoint,对应Dockefile中的ENTRYPOINT  
    args: ["$(str)"] #启动容器的命令参数,对应Dockerfile中CMD参数  
    env: #指定容器中的环境变量  
    - name: str #变量的名字  
      value: "/etc/run.sh" #变量的值  
    resources: #资源管理,请求请见http://blog.csdn.net/liyingke112/article/details/77452630
      requests: #容器运行时,最低资源需求,也就是说最少需要多少资源容器才能正常运行  
        cpu: 0.1 #CPU资源(核数),两种方式,浮点数或者是整数+m,0.1=100m,最少值为0.001核(1m)
        memory: 32Mi #内存使用量  
      limits: #资源限制  
        cpu: 0.5  
        memory: 32Mi  
    ports:  
    - containerPort: 80 #容器开发对外的端口
      name: httpd  #名称
      protocol: TCP  
    livenessProbe: #pod内容器健康检查的设置,详情请见http://blog.csdn.net/liyingke112/article/details/77531584
      httpGet: #通过httpget检查健康,返回200-399之间,则认为容器正常  
        path: / #URI地址  
        port: 80  
        #host: 127.0.0.1 #主机地址  
        scheme: HTTP  
      initialDelaySeconds: 180 #表明第一次检测在容器启动后多长时间后开始  
      timeoutSeconds: 5 #检测的超时时间  
      periodSeconds: 15  #检查间隔时间  
      #也可以用这种方法  
      #exec: 执行命令的方法进行监测,如果其退出码不为0,则认为容器正常  
      #  command:  
      #    - cat  
      #    - /tmp/health  
      #也可以用这种方法  
      #tcpSocket: //通过tcpSocket检查健康   
      #  port: number   
    lifecycle: #生命周期管理  
      postStart: #容器运行之前运行的任务  
        exec:  
          command:  
            - 'sh'  
            - 'yum upgrade -y'  
      preStop: #容器关闭之前运行的任务  
        exec:  
          command: ['service httpd stop']  
    volumeMounts:  #详情请见http://blog.csdn.net/liyingke112/article/details/76577520
    - name: volume #挂载设备的名字,与volumes[*].name 需要对应    
      mountPath: /data #挂载到容器的某个路径下  
      readOnly: True  
  volumes: #定义一组挂载设备  
  - name: volume #定义一个挂载设备的名字  
    #meptyDir: {}  
    hostPath:  
      path: /opt #挂载设备类型为hostPath,路径为宿主机下的/opt,这里设备类型支持很多种

Pod管理-创建/查询/更新/删除

基本管理:
# 创建pod资源
kubectl create -f pod.yaml
# 查看pods
kubectl get pods pod-test
# 查看pod描述
kubectl describe pod pod-test
# 替换资源
kubectl replace -f pod.yaml -force
# 删除资源
kubectl delete pod pod-test


健康管理
提供Probe机制,有以下两种类型:
livenessProbe
如果检查失败,将杀死容器,然后根据Pod的重启策略来决定是否
重启。
readinessProbe
如果检查失败,Kubernetes会把Pod从服务代理的分发后端剔除。

Probe支持以下三种检查方法:
httpGet
发送HTTP请求,返回200-400范围状态码为成功。
exec
执行Shell命令返回状态码是0为成功。
tcpSocket
发起TCP Socket建立成功。

三、Deployment

简单例子

apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.10
        ports:
        - containerPort: 80

详细解析

apiVersion: extensions/v1beta1
kind: Deployment
metadata: <Object>
spec: <Object>
  minReadySeconds: <integer> #设置pod准备就绪的最小秒数
  paused: <boolean> #表示部署已暂停并且deploy控制器不会处理该部署
  progressDeadlineSeconds: <integer>
  strategy: <Object> #将现有pod替换为新pod的部署策略
    rollingUpdate: <Object> #滚动更新配置参数,仅当类型为RollingUpdate
      maxSurge: <string> #滚动更新过程产生的最大pod数量,可以是个数,也可以是百分比
      maxUnavailable: <string> #
    type: <string> #部署类型,Recreate,RollingUpdate
  replicas: <integer> #pods的副本数量
  selector: <Object> #pod标签选择器,匹配pod标签,默认使用pods的标签
    matchLabels: <map[string]string> 
      key1: value1
      key2: value2
    matchExpressions: <[]Object>
      operator: <string> -required- #设定标签键与一组值的关系,In, NotIn, Exists and DoesNotExist
      key: <string> -required-
      values: <[]string>   
  revisionHistoryLimit: <integer> #设置保留的历史版本个数,默认是10
  rollbackTo: <Object> 
    revision: <integer> #设置回滚的版本,设置为0则回滚到上一个版本
  template: <Object> -required-
    metadata:
    spec:
      containers: <[]Object> #容器配置
      - name: <string> -required- #容器名、DNS_LABEL
        image: <string> #镜像
        imagePullPolicy: <string> #镜像拉取策略,Always、Never、IfNotPresent
        ports: <[]Object>
        - name: #定义端口名
          containerPort: #容器暴露的端口
          protocol: TCP #或UDP
        volumeMounts: <[]Object>
        - name: <string> -required- #设置卷名称
          mountPath: <string> -required- #设置需要挂载容器内的路径
          readOnly: <boolean> #设置是否只读
        livenessProbe: <Object> #就绪探测
          exec: 
            command: <[]string>
          httpGet:
            port: <string> -required-
            path: <string>
            host: <string>
            httpHeaders: <[]Object>
              name: <string> -required-
              value: <string> -required-
            scheme: <string> 
          initialDelaySeconds: <integer> #设置多少秒后开始探测
          failureThreshold: <integer> #设置连续探测多少次失败后,标记为失败,默认三次
          successThreshold: <integer> #设置失败后探测的最小连续成功次数,默认为1
          timeoutSeconds: <integer> #设置探测超时的秒数,默认1s
          periodSeconds: <integer> #设置执行探测的频率(以秒为单位),默认1s
          tcpSocket: <Object> #TCPSocket指定涉及TCP端口的操作
            port: <string> -required- #容器暴露的端口
            host: <string> #默认pod的IP
        readinessProbe: <Object> #同livenessProbe
        resources: <Object> #资源配置
          requests: <map[string]string> #最小资源配置
            memory: "1024Mi"
            cpu: "500m" #500m代表0.5CPU
          limits: <map[string]string> #最大资源配置
            memory:
            cpu:         
      volumes: <[]Object> #数据卷配置
      - name: <string> -required- #设置卷名称,与volumeMounts名称对应
        hostPath: <Object> #设置挂载宿主机路径
          path: <string> -required- 
          type: <string> #类型:DirectoryOrCreate、Directory、FileOrCreate、File、Socket、CharDevice、BlockDevice
      - name: nfs
        nfs: <Object> #设置NFS服务器
          server: <string> -required- #设置NFS服务器地址
          path: <string> -required- #设置NFS服务器路径
          readOnly: <boolean> #设置是否只读
      - name: configmap
        configMap: 
          name: <string> #configmap名称
          defaultMode: <integer> #权限设置0~0777,默认0664
          optional: <boolean> #指定是否必须定义configmap或其keys
          items: <[]Object>
          - key: <string> -required-
            path: <string> -required-
            mode: <integer>
      restartPolicy: <string> #重启策略,Always、OnFailure、Never
      nodeName: <string>
      nodeSelector: <map[string]string>
      imagePullSecrets: <[]Object>
      hostname: <string>
      hostPID: <boolean>
status: <Object>

四、Service

服务类型

服务类型:
ClusterIP
分配一个内部集群IP地址,只能在集群内部访问(同Namespace内的Pod),默认ServiceType。
 NodePort
分配一个内部集群IP地址,并在每个节点上启用一个端口来暴露服务,可以在集群外部访问。
访问地址:<NodeIP>:<NodePort>
LoadBalancer
分配一个内部集群IP地址,并在每个节点上启用一个端口来暴露服务。
除此之外,Kubernetes会请求底层云平台上的负载均衡器,将每个Node([NodeIP]:[NodePort])作为后端添加进去。
 ExternalName
通过CNAME将Service与externalName的值映射。要求kube-dns的版本为v1.7+。

实例1

apiVersion: v1
kind: Service
metadata:
  labels:
    run: nginx
  name: nginx
  namespace: default
spec:
  ports:
  - port: 88
    targetPort: 80
  selector:
    app: nginx

实例2:指定ip

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: nginx
  ports:
  - name: http
    protocol: TCP
    port: 888
    targetPort: 80
#  可以指定ip
  clusterIP: "10.10.10.123"
#  - name: https
#    protocol: TCP
#    port: 443
#    targetPort: 9377

实例3:发布服务

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  labels:
    app: nginx
spec:
  selector:
    app: nginx
  ports:
  - name: http
    port: 8080
    targetPort: 80
    nodePort: 30001
  type: NodePort

k8s是什么?

Kubernetes是容器集群管理系统,是一个开源的平台,可以实现容器集群的自动化部署、自动扩缩容、维护等功能。

通过Kubernetes你可以:

  • 快速部署应用
  • 快速扩展应用
  • 无缝对接新的应用功能
  • 节省资源,优化硬件资源的使用

我们的目标是促进完善组件和工具的生态系统,以减轻应用程序在公有云或私有云中运行的负担。

Kubernetes 特点

  • 可移植: 支持公有云,私有云,混合云,多重云(multi-cloud)
  • 可扩展: 模块化, 插件化, 可挂载, 可组合
  • 自动化: 自动部署,自动重启,自动复制,自动伸缩/扩展

Kubernetes是Google 2014年创建管理的,是Google 10多年大规模容器管理技术Borg的开源版本。

Kubernetes 特点

  • 可移植: 支持公有云,私有云,混合云,多重云(multi-cloud)
  • 可扩展: 模块化, 插件化, 可挂载, 可组合
  • 自动化: 自动部署,自动重启,自动复制,自动伸缩/扩展

Kubernetes是Google 2014年创建管理的,是Google 10多年大规模容器管理技术Borg的开源版本。

Why containers?

为什么要使用容器?通过以下两个图对比:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bkWcJzyz-1626275743487)(https://d33wubrfki0l68.cloudfront.net/e7b766e0175f30ae37f7e0e349b87cfe2034a1ae/3e391/images/docs/why_containers.svg#height=150&id=UvIIQ&originHeight=150&originWidth=196&originalType=binary&status=done&style=none&width=196)]

传统的应用部署方式是通过插件或脚本来安装应用。这样做的缺点是应用的运行、配置、管理、所有生存周期将与当前操作系统绑定,这样做并不利于应用的升级更新/回滚等操作,当然也可以通过创建虚机的方式来实现某些功能,但是虚拟机非常重,并不利于可移植性。

新的方式是通过部署容器方式实现,每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。相对于虚拟机,容器能快速部署,由于容器与底层设施、机器文件系统解耦的,所以它能在不同云、不同版本操作系统间进行迁移。

容器占用资源少、部署快,每个应用可以被打包成一个容器镜像,每个应用与容器间成一对一关系也使容器有更大优势,使用容器可以在build或release  的阶段,为应用创建容器镜像,因为每个应用不需要与其余的应用堆栈组合,也不依赖于生产环境基础结构,这使得从研发到测试、生产能提供一致环境。类似地,容器比虚机轻量、更“透明”,这更便于监控和管理。最后,

容器优势总结:

  • **快速创建/部署应用:**与VM虚拟机相比,容器镜像的创建更加容易。
  • **持续开发、集成和部署:**提供可靠且频繁的容器镜像构建/部署,并使用快速和简单的回滚(由于镜像不可变性)。
  • **开发和运行相分离:**在build或者release阶段创建容器镜像,使得应用和基础设施解耦。
  • **开发,测试和生产环境一致性:**在本地或外网(生产环境)运行的一致性。
  • **云平台或其他操作系统:**可以在 Ubuntu、RHEL、 CoreOS、on-prem、Google Container Engine或其它任何环境中运行。
  • **Loosely coupled,分布式,弹性,微服务化:**应用程序分为更小的、独立的部件,可以动态部署和管理。
  • 资源隔离
  • **资源利用:**更高效

使用Kubernetes能做什么?

可以在物理或虚拟机的Kubernetes集群上运行容器化应用,Kubernetes能提供一个以“容器为中心的基础架构”,满足在生产环境中运行应用的一些常见需求,如:

  • 多个进程(作为容器运行)协同工作。(Pod)
  • 存储系统挂载
  • Distributing secrets
  • 应用健康检测
  • 应用实例的复制
  • Pod自动伸缩/扩展
  • Naming and discovering
  • 负载均衡
  • 滚动更新
  • 资源监控
  • 日志访问
  • 调试应用程序
  • 提供认证和授权

Kubernetes是什么意思?K8S?

Kubernetes的名字来自希腊语,意思是“舵手” 或 “领航员”。_K8s_是将8个字母“ubernete”替换为“8”的缩写。

Master 组件

Master组件提供集群的管理控制中心。

Master组件可以在集群中任何节点上运行。但是为了简单起见,通常在一台VM/机器上启动所有Master组件,并且不会在此VM/机器上运行用户容器。请参考 构建高可用群集以来构建multi-master-VM。

kube-apiserver

kube-apiserver用于暴露Kubernetes API。任何的资源请求/调用操作都是通过kube-apiserver提供的接口进行。请参阅构建高可用群集。

ETCD

etcd是Kubernetes提供默认的存储系统,保存所有集群数据,使用时需要为etcd数据提供备份计划。

kube-controller-manager

kube-controller-manager运行管理控制器,它们是集群中处理常规任务的后台线程。逻辑上,每个控制器是一个单独的进程,但为了降低复杂性,它们都被编译成单个二进制文件,并在单个进程中运行。

这些控制器包括:

  • 节点(Node)控制器。
  • 副本(Replication)控制器:负责维护系统中每个副本中的pod。
  • 端点(Endpoints)控制器:填充Endpoints对象(即连接Services&Pods)。
  • Service Account
    和Token控制器:为新的
    Namespace
    创建默认帐户访问API Token。

cloud-controller-manager

云控制器管理器负责与底层云提供商的平台交互。云控制器管理器是Kubernetes版本1.6中引入的,目前还是Alpha的功能。

云控制器管理器仅运行云提供商特定的(controller loops)控制器循环。可以通过将--cloud-provider flag设置为external启动kube-controller-manager ,来禁用控制器循环。

cloud-controller-manager 具体功能:

  • 节点(Node)控制器
  • 路由(Route)控制器
  • Service控制器
  • 卷(Volume)控制器

kube-scheduler

kube-scheduler 监视新创建没有分配到Node的Pod,为Pod选择一个Node。

插件 addons

插件(addon)是实现集群pod和Services功能的 。Pod由Deployments,ReplicationController等进行管理。Namespace 插件对象是在kube-system Namespace中创建。

DNS

虽然不严格要求使用插件,但Kubernetes集群都应该具有集群 DNS。

群集 DNS是一个DNS服务器,能够为 Kubernetes services提供 DNS记录。

由Kubernetes启动的容器自动将这个DNS服务器包含在他们的DNS searches中。

了解更多详情

用户界面

kube-ui提供集群状态基础信息查看。更多详细信息,请参阅使用HTTP代理访问Kubernetes API

容器资源监测

容器资源监控提供一个UI浏览监控数据。

Cluster-level Logging

Cluster-level logging,负责保存容器日志,搜索/查看日志。

节点(Node)组件

节点组件运行在Node,提供Kubernetes运行时环境,以及维护Pod。

kubelet

kubelet是主要的节点代理,它会监视已分配给节点的pod,具体功能:

  • 安装Pod所需的volume。
  • 下载Pod的Secrets。
  • Pod中运行的 docker(或experimentally,rkt)容器。
  • 定期执行容器健康检查。
  • Reports the status of the pod back to the rest of the system, by creating a mirror pod if necessary.
  • Reports the status of the node back to the rest of the system.

kube-proxy

kube-proxy通过在主机上维护网络规则并执行连接转发来实现Kubernetes服务抽象。

docker

docker用于运行容器。

RKT

rkt运行容器,作为docker工具的替代方案。

supervisord

supervisord是一个轻量级的监控系统,用于保障kubelet和docker运行。

fluentd

fluentd是一个守护进程,可提供cluster-level logging.。

一、Pod

指令

#创建pod

	kubectl create -f pod配置文件

#运行pod

	kubectl apply -f pod.yaml

#获取pod信息

	describe pod 镜像id

	kubectl get pod

	kubectl log 镜像的ID -c 容器名称

#删除pod

	kubectl delete pod podID

#pod详细信息

	kubectl get pod -o wide

资源清单格式

apiVersion: group/apiversion # 如果没有给定group 名称,那么默认为 core,可以使用 kubectl api- versions # 获取当前 k8s 版本上所有的 apiVersion 版本信息( 每个版本可能不同 ) 
kind: #资源类别 
metadata: #资源元数据 
  name 
  namespace 
  lables
  annotations # 主要目的是方便用户阅读查找 
spec: # 期望的状态(disired state) 
  status: # 当前状态,本字段有 Kubernetes 自身维护,用户不能去定义

资源清单的常用命令

[root@k8s-master01 ~]# kubectl api-versions
[root@k8s-master01 ~]# kubectl explain pod
[root@k8s-master01 ~]# kubectl explain Ingress
[root@k8s-master01 ~]# kubectl explain pod

创建简单pod

apiVersion: v1
kind: Pod
metadata: 
	name: myapp
	labels:
		app: myapp
		version: v1
spec:
	containers: 
	- name: app
	  images: 镜像名:v1
    - name: test
      images: 镜像名:v1

pod生命周期:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iBEUZibC-1626275743489)(images%5Cpod%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F.png#id=J7m1o&originalType=binary&status=done&style=none)]

  当cri在初始化之后,会加载一个pause基础容器,这个是对pod中的所有其他容器服务的,包括数据卷,网络等等,之后会初始化容器Init C,这个容器初始化动作为串行执行,正常退出码为0,不为零会根据重启策略其判断执行,之后执行成功会消亡。加载成功之后进入Main C主容器的运行,在运行起始的时候可以执行一些命令或者脚本,结束的时候也可以运行一些命令和脚本,在运行开始多少秒之后进行readness探测,在readness没探测成功之前pod的状态不能变为running状态;在运行期间,还有liveness参与,liveness主要是探测主容器状态,如果主容器不可用或者异常,执行重启或者删除等操作,根据重启策略来操作。

Init 容器

init模板

apiVersion: v1 
kind: Pod 
metadata: 
  name: myapp-pod 
  labels: 
    app: myapp
spec:
  containers:
  - name: myapp-container 
    image: busybox
    command: ['sh', '-c', 'echo The app is running! && sleep 3600'] 
  initContainers:
  - name: init-myservice 
    image: busybox
    command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
  - name: init-mydb 
    image: busybox
    command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
kind: Service 
apiVersion: v1 
metadata: 
  name: myservice 
  spec: 
    ports: 
      - protocol: TCP 
        port: 80 
        targetPort: 9376 
--- 
kind: Service 
apiVersion: v1 
metadata: 
  name: mydb 
spec: 
  ports: 
    - protocol: TCP 
      port: 80 
      targetPort: 9377

探针检测

检测探针 - 就绪检测

readinessProbe-httpget
apiVersion: v1 
kind: Pod 
metadata: 
  name: readiness-httpget-pod 
  namespace: default 
spec: 
  containers: 
  - name: readiness-httpget-container 
    image: wangyanglinux/myapp:v1 
    imagePullPolicy: IfNotPresent 
    readinessProbe: 
      httpGet: 
        port: 80 
        path: /index1.html 
        initialDelaySeconds: 1 
        periodSeconds: 3

检测探针 - 存活检测

livenessProbe-exec
apiVersion: v1 
kind: Pod 
metadata: 
  name: liveness-exec-pod 
  namespace: default 
spec: 
  containers: 
  - name: liveness-exec-container 
    image: hub.atguigu.com/library/busybox 
    imagePullPolicy: IfNotPresent 
    command: ["/bin/sh","-c","touch /tmp/live ; sleep 60; rm -rf /tmp/live; sleep 3600"]
    livenessProbe: 
      exec: command: ["test","-e","/tmp/live"] 
      initialDelaySeconds: 1 
      periodSeconds: 3
livenessProbe-httpget
apiVersion: v1 
kind: Pod 
metadata: 
  name: liveness-httpget-pod
  namespace: default 
spec: 
  containers: 
  - name: liveness-httpget-container 
    image: hub.atguigu.com/library/myapp:v1 
    imagePullPolicy: IfNotPresent 
    ports: 
    - name: http 
      containerPort: 80 
    livenessProbe: 
      httpGet: 
        port: http 
        path: /index.html 
        initialDelaySeconds: 1 
        periodSeconds: 3 
        timeoutSeconds: 10
livenessProbe-tcp
apiVersion: v1 
kind: Pod 
metadata: 
  name: probe-tcp 
spec: 
  containers: 
  - name: nginx 
    image: hub.atguigu.com/library/myapp:v1 
    livenessProbe: 
      initialDelaySeconds: 5 
      timeoutSeconds: 1 
      tcpSocket: 
        port: 80

启动、退出动作

apiVersion: v1 
kind: Pod 
metadata: 
  name: lifecycle-demo 
spec: 
  containers: 
  - name: lifecycle-demo-container 
    image: nginx 
    lifecycle: 
      postStart: 
        exec: 
          command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"] 
      preStop: 
        exec:
          command: ["/bin/sh", "-c", "echo Hello from the poststop handler > /usr/share/message"]

二、资源控制器

Kubernetes 中内建了很多 controller(控制器),这些相当于一个状态机,用来控制 Pod 的具体状态和行为

一、什么是控制器

Kubernetes 中内建了很多 controller(控制器),这些相当于一个状态机,用来控制 Pod 的具体状态和行为

**二、**控制器类型

① ReplicationController 和 ReplicaSet

② Deployment

③ DaemonSet

④ StateFulSet

⑤ Job/CronJob

⑥ Horizontal Pod Autoscaling

**1、**ReplicationController 和 ReplicaSet

ReplicationController(RC)用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的 Pod 来替代;而如果异常多出来的容器也会自动回收;在新版本的 Kubernetes 中建议使用 ReplicaSet 来取代 ReplicationController 。ReplicaSet 跟ReplicationController 没有本质的不同,只是名字不一样,并且 ReplicaSet 支持集合式的 selector(标签 );

**2、**Deployment

Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义 (declarative) 方法,用来替代以前的ReplicationController 来方便的管理应用。典型的应用场景包括;

① 定义 Deployment 来创建 Pod 和 ReplicaSet

② 滚动升级和回滚应用

③ 扩容和缩容

④ 暂停和继续 Deployment

滚动更新:会创建一个新副本的rs1,旧的rs的pod减少一个时,rs1会新加一个,直到全部增减完成

回滚:同理,需要恢复旧的rs时,会启动rs,再进行增减操作

**3、**DaemonSet

DaemonSet确保全部(或者一些)Node 上运行一个 Pod 的副本。当有 Node 加入集群时,也会为他们新增一个Pod 。当有 Node 从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod

使用 DaemonSet 的一些典型用法:

① 运行集群存储 daemon,例如在每个 Node 上运行glusterd、ceph

② 在每个 Node 上运行日志收集 daemon,例如fluentd、logstash

③ 在每个 Node 上运行监控 daemon,例如Prometheus Node Exporter、collectd、Datadog 代理、New Relic 代理,或 Ganglia gmond

Job 负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个 Pod 成功结束

**4、**CronJobCron Job

管理基于时间的 Job,即:

  • 在给定时间点只运行一次
  • 周期性地在给定时间点运行

使用前提条件:当前使用的 Kubernetes 集群,版本 >= 1.8(对 CronJob)。对于先前版本的集群,版本 <1.8,启动 API Server时,通过传递选项–runtime-config=batch/v2alpha1=true可以开启 batch/v2alpha1API

典型的用法如下所示:

在给定的时间点调度 Job 运行

创建周期性运行的 Job,例如:数据库备份、发送邮件

**5、**StatefulSet

StatefulSet 作为 Controller 为 Pod 提供唯一的标识。它可以保证部署和 scale 的顺序

StatefulSet是为了解决有状态服务的问题(对应Deployments和ReplicaSets是为无状态服务而设计),其应用场景包括:

① 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现

② 稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现

③ 有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),基于init containers来实现

④ 有序收缩,有序删除(即从N-1到0)

**6、**Horizontal Pod Autoscaling(HPA )

应用的资源使用率通常都有高峰和低谷的时候,如何削峰填谷,提高集群的整体资源利用率,让service中的Pod个数自动调整呢?这就有赖于Horizontal Pod Autoscaling了,顾名思义,使Pod水平自动缩放

三、控制器实例

**1、**RS 与 RC 与 Deployment 关联RC (ReplicationController )

主要的作用就是用来确保容器应用的副本数始终保持在用户定义的副本数。即如果有容器异常退出,会自动创建新的Pod来替代;而如果异常多出来的容器也会自动回收

Kubernetes 官方建议使用 RS(ReplicaSet )替代 RC (ReplicationController )进行部署,RS 跟 RC 没有本质的不同,只是名字不一样,并且 RS 支持集合式的 selector

查看RS完整模板信息:kubectl explain rs

RS创建模板

apiVersion: extensions/v1beta1
kind: ReplicaSet
metadata:
  name: frontend
spec:
  replicas: 3
  selector:
    matchLabels:
      tier: frontend
  template:
    metadata:
      labels:
        tier: frontend
    spec:
      containers:
      - name: myapp
        image: hub.lqz.com/library/nginx:V1
        env:
        - name: GET_HOSTS_FROM
          value: dns
        ports:
        - containerPort: 80

资源控制器所创建的pod,删除后会被新建

kubectl get pod --show-labels 查看标签

2、RS 与 Deployment 的关联

Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationController 来方便的管理应用。典型的应用场景包括:

① 定义Deployment来创建Pod和ReplicaSet

② 滚动升级和回滚

③ 应用扩容和缩容

④ 暂停和继续Deployment

**3、**部署一个简单的 Nginx 应用(Deployment )

1、创建

kubectl apply -f deployment.yaml --record

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
	spec:
      containers:
      - name: nginx
	  image: nginx:1.7.9
	  ports:
	  - containerPort: 80

kubectl create -f https://kubernetes.io/docs/user-guide/nginx-deployment.yaml --record## --record参数可以记录命令,我们可以很方便的查看每次 revision 的变化

2、扩容

kubectl scale deployment nginx-deployment --replicas 10

3、如果集群支持 horizontal pod autoscaling 的话,还可以为Deployment设置自动扩展

kubectl autoscale deployment nginx-deployment --min=10–max=15–cpu-percent=80

4、更新镜像也比较简单

kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1

5、回滚

kubectl rollout undo deployment/nginx-deployment

6、更新 Deployment

6.1假如我们现在想要让 nginx pod 使用nginx:1.9.1的镜像来代替原来的nginx:1.7.9的镜像

kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1deployment “nginx-deployment” image updated

6.2可以使用edit命令来编辑 Deployment

kubectl edit deployment/nginx-deploymentdeployment “nginx-deployment” edited

6.3查看 rollout 的状态

kubectl rollout status deployment/nginx-deployment

6.4查看历史 RS

6.5 Deployment 更新策略

  • Deployment 可以保证在升级时只有一定数量的 Pod 是 down 的。默认的,它会确保至少有比期望的Pod数量少一个是up状态(最多一个不可用)
  • Deployment 同时也可以确保只创建出超过期望数量的一定数量的 Pod。默认的,它会确保最多比期望的Pod数量多一个的 Pod 是 up 的(最多1个 surge )
  • 未来的 Kuberentes 版本中,将从1-1变成25%-25%

6.6Rollover(多个rollout并行)

假如您创建了一个有5个niginx:1.7.9 replica的 Deployment,但是当还只有3个nginx:1.7.9的 replica 创建出来的时候您就开始更新含有5个nginx:1.9.1 replica 的 Deployment。在这种情况下,Deployment 会立即杀掉已创建的3个nginx:1.7.9的 Pod,并开始创建nginx:1.9.1的 Pod。它不会等到所有的5个nginx:1.7.9的Pod 都创建完成后才开始改变航道

6.7回退 Deployment

kubectl set image deployment/nginx-deployment nginx=nginx:1.91

kubectl rollout status deployments nginx-deployment

kubectl get pods

kubectl rollout history deployment/nginx-deployment

kubectl rollout undo deployment/nginx-deployment
## 可以使用 --revision参数指定某个历史版本
kubectl rollout undo deployment/nginx-deployment --to-revision=2  
## 暂停 deployment 的更新
kubectl rollout pause deployment/nginx-deployment

您可以用kubectl rollout status命令查看 Deployment 是否完成。如果 rollout 成功完成,kubectl rolloutstatus将返回一个0值的 Exit Code

6.8清理 Policy

您可以通过设置.spec.revisonHistoryLimit项来指定 deployment 最多保留多少 revision 历史记录。默认的会保留所有的 revision;如果将该项设置为0,Deployment 就不允许回退了

4、DaemonSet

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: daemon-example
  labels:
    app: daemonSet
spec:
  selector: 
    metchLables:
      name: daemon-example
    template:
      metadatas:
        lables: 
          name: daemon-example
    spec:
      containers:
      - name: daemon-example
        images: 容器镜像:版本

5、Job

Job 负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个 Pod 成功结束
特殊说明
spec.template格式同Pod
RestartPolicy仅支持Never或OnFailure
单个Pod时,默认Pod成功运行后Job即结束
spec.completions 标志Job结束需要成功运行的Pod个数,默认为1
spec.parallelism 标志并行运行的Pod的个数,默认为1
spec.activeDeadlineSeconds 标志失败Pod的重试最大时间,超过这个时间不会继续重试

apiVersion: batch/v1
kind: Job
metadata: 
  name: pi
spec:
  template:
    metadata:
      name: pi
    spec:
      containers:
      - name: pi
        images: per1
        command: ["per1", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Nerver

6、CronJob

CronJob Spec
spec.template格式同Pod
RestartPolicy仅支持Never或OnFailure
单个Pod时,默认Pod成功运行后Job即结束
spec.completions 标志Job结束需要成功运行的Pod个数,默认为1

spec.parallelism 标志并行运行的Pod的个数,默认为1

spec.activeDeadlineSeconds 标志失败Pod的重试最大时间,超过这个时间不会继续重试

CronJob
Cron Job 管理基于时间的 Job,即:
在给定时间点只运行一次
周期性地在给定时间点运行
使用条件:当前使用的 Kubernetes 集群,版本 >= 1.8(对 CronJob)
典型的用法如下所示:
在给定的时间点调度 Job 运行
创建周期性运行的 Job,例如:数据库备份、发送邮件

CronJob Spec
.spec.schedule :调度,必需字段,指定任务运行周期,格式同 Cron
.spec.jobTemplate :Job 模板,必需字段,指定需要运行的任务,格式同 Job
.spec.startingDeadlineSeconds :启动 Job 的期限(秒级别),该字段是可选的。如果因为任何原因而错
过了被调度的时间,那么错过执行时间的 Job 将被认为是失败的。如果没有指定,则没有期限
.spec.concurrencyPolicy :并发策略,该字段也是可选的。它指定了如何处理被 Cron Job 创建的 Job 的
并发执行。只允许指定下面策略中的一种:
Allow (默认):允许并发运行 Job
Forbid :禁止并发运行,如果前一个还没有完成,则直接跳过下一个
Replace :取消当前正在运行的 Job,用一个新的来替换
注意,当前策略只能应用于同一个 Cron Job 创建的 Job。如果存在多个 Cron Job,它们创建的 Job 之间总
是允许并发运行。
spec.suspend :挂起,该字段也是可选的。如果设置为 true ,后续所有执行都会被挂起。它对已经开始
执行的 Job 不起作用。默认值为 false 。

spec.successfulJobsHistoryLimit 和

spec.failedJobsHistoryLimit :历史限制,是可选的字段。它
们指定了可以保留多少完成和失败的 Job。默认情况下,它们分别设置为 3 和 1 。设置限制的值为 0 ,相
关类型的 Job 完成后将不会被保留。

apiVersion: batch/v1beta1
kind: CronJob
metadata: 
  name: hello
spec:
  #每一分钟执行一次
  schedule: "*/1 * * * *"
  jobTemplate: 
    spec:
      template:
        spec:
          containers:
          - name: hello
            images: busybox
            atgs: 
            - /bin/sh
            - -C
            - data; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure
$ kubectl get cronjob NAME SCHEDULE SUSPEND ACTIVE LAST-SCHEDULE hello */1 * * * * False 0 <none> 
$ kubectl get jobs NAME DESIRED SUCCESSFUL AGE hello-1202039034 1 1 49s 
$ pods=$(kubectl get pods --selector=job-name=hello-1202039034 --output=jsonpath= {.items..metadata.name}) 
$ kubectl logs $pods Mon Aug 29 21:34:09 UTC 2016 Hello from the Kubernetes cluster # 注意,删除 cronjob 的时候不会自动删除 job,这些 job 可以用 kubectl delete job 来删除 
$ kubectl delete cronjob hello cronjob "hello" deleted

四、Service

**一、**Service 的概念

Kubernetes Service定义了这样一种抽象:一个Pod的逻辑分组,一种可以访问它们的策略 —— 通常称为微服务。这一组Pod能够被Service访问到,通常是通过Label Selector

Service能够提供负载均衡的能力,但是在使用上有以下限制:只提供 4 层负载均衡能力,而没有 7 层功能,但有时我们可能需要更多的匹配规则来转发请求,这点上 4 层负载均衡是不支持的

**二、**Service 的类型

Service 在 K8s 中有以下四种类型ClusterIp:

① 默认类型,自动分配一个仅 Cluster 内部可以访问的虚拟 IP

② NodePort:在 ClusterIP 基础上为 Service 在每台机器上绑定一个端口,这样就可以通过:NodePort 来访问该服务

③ LoadBalancer:在 NodePort 的基础上,借助 cloud provider 创建一个外部负载均衡器,并将请求转发到: NodePort

④ ExternalName:把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,这只有 kubernetes 1.7 或更高版本的 kube-dns 才支持

svc基础导论

总结

客户端访问节点时通过iptables实现的,

iptables规则是通过kube-proxy写入的,

apiserver通过监控kube-proxy去进行对服务和端点的监控,

kube-proxy通过pod的标签(lables)去判断这个断点信息是否写入到Endpoints里去。

**三、**VIP 和 Service 代理

在 Kubernetes 集群中,每个 Node 运行一个kube-proxy进程。kube-proxy负责为Service实现了一种VIP(虚拟 IP)的形式,而不是ExternalName的形式。在 Kubernetes v1.0 版本,代理完全在 userspace。在Kubernetes v1.1 版本,新增了 iptables 代理,但并不是默认的运行模式。从 Kubernetes v1.2 起,默认就是iptables 代理。在 Kubernetes v1.8.0-beta.0 中,添加了 ipvs 代理

在 Kubernetes 1.14 版本开始默认使用ipvs 代理

在 Kubernetes v1.0 版本,Service是 “4层”(TCP/UDP over IP)概念。在 Kubernetes v1.1 版本,新增了Ingress API(beta 版),用来表示 “7层”(HTTP)服务

为何不使用 round-robin DNS?

DNS会在很多的客户端里进行缓存,很多服务在访问DNS进行域名解析完成、得到地址后不会对DNS的解析进行清除缓存的操作,所以一旦有他的地址信息后,不管访问几次还是原来的地址信息,导致负载均衡无效。

四、代理模式的分类

1、userspace 代理模式

2、iptables 代理模式

3、ipvs 代理模式

这种模式,kube-proxy 会监视 Kubernetes Service对象和Endpoints,调用netlink接口以相应地创建ipvs 规则并定期与 Kubernetes Service对象和Endpoints对象同步 ipvs 规则,以确保 ipvs 状态与期望一致。访问服务时,流量将被重定向到其中一个后端 Pod

与 iptables 类似,ipvs 于 netfilter 的 hook 功能,但使用哈希表作为底层数据结构并在内核空间中工作。这意味着 ipvs 可以更快地重定向流量,并且在同步代理规则时具有更好的性能。此外,ipvs 为负载均衡算法提供了更多选项,例如:

① rr:轮询调度

② lc:最小连接数

③ dh:目标哈希

④ sh:源哈希

⑤ sed:最短期望延迟

⑥ nq:不排队调度

五、ClusterIP

clusterIP 主要在每个 node 节点使用 iptables,将发向 clusterIP 对应端口的数据,转发到 kube-proxy 中。然后 kube-proxy 自己内部实现有负载均衡的方法,并可以查询到这个 service 下对应 pod 的地址和端口,进而把数据转发给对应的 pod 的地址和端口

为了实现图上的功能,主要需要以下几个组件的协同工作:

  1. apiserver 用户通过kubectl命令向apiserver发送创建service的命令,apiserver接收到请求后将数据存储到etcd中
  2. kube-proxy kubernetes的每个节点中都有一个叫做kube-porxy的进程,这个进程负责感知service,pod的变化,并将变化的信息写入本地的iptables规则中
  3. iptables 使用NAT等技术将virtualIP的流量转至endpoint中

创建 myapp-deploy.yaml 文件

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
	  app: myapp
      release: stabel
  template:
    metadata:
      labels:
        app: myapp
  		release: stabel
        env: test
	spec:
      containers:
      - name: myapp
		image: wangyanglinux/myapp:v2
        imagePullPolicy: IfNotPresent
        ports:
		- name: http
  		  containerPort: 80

创建service

apiVersion: v1
kind: Service
metadata:
  name: myapp
  namespace: default
spec:
  type: ClusterIP
  selector:
    app: myapp
    release: stabel
  ports:
  - name: http
    port: 80
    targetPort: 80

六、Headless Service

有时不需要或不想要负载均衡,以及单独的 Service IP 。遇到这种情况,可以通过指定 ClusterIP(spec.clusterIP) 的值为 “None” 来创建 Headless Service 。这类 Service 并不会分配 Cluster IP, kube-proxy 不会处理它们,而且平台也不会为它们进行负载均衡和路由

[root@k8s-master mainfests]# vim myapp-svc-headless.yaml

 
apiVersion: v1
kind: Service
metadata:
  name: myapp-headless
  namespace: default
spec:
  selector:
    app: myapp
    clusterIP: "None"
  ports:
  - port: 80
    targetPort: 80


[root@k8s-master mainfests]# dig -t A myapp-headless.default.svc.cluster.local. @10.96.0.10

七、NodePortnodePort

的原理在于在 node 上开了一个端口,将向该端口的流量导入到 kube-proxy,然后由 kube-proxy 进一步到给对应的 pod

类型 命令 描述 基础命令 create 通过文件名或标准输入创建资源 expose 将一个资源公开为一个新的Service run 在集群中运行一个特定的镜像 set 在对象上设置特定的功能 get 显示一个或多个资源 explain 文档参考资料。 edit 使用默认的编辑器编辑一个资源。 delete 通过文件名、标准输入、资源名称或标签选择器来删除资源。 部署命令 rollout 管理资源的发布 rolling-update 对给定的复制控制器滚动更新 scale 扩容或缩容Pod数量,Deployment、ReplicaSet、RC或Job autoscale 创建一个自动选择扩容或缩容并设置Pod数量 集群管理命令 certificate 修改证书资源 cluster-info 显示集群信息 top 显示资源(CPU/Memory/Storage)使用。需要Heapster运行 cordon 标记节点不可调度 uncordon 标记节点可调度 drain 维护期间排除节点 taint

[root@master manifests]# vim myapp-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: myapp
  namespace: default
spec:
  type: NodePort
  selector:
    app: myapp
    release: stabel
  ports:
  - name: http
    port: 80
    targetPort: 80

 

查看流程

iptables -t nat -nv

八、LoadBalancer(了解  )

loadBalancer 和 nodePort 其实是同一种方式。区别在于 loadBalancer 比 nodePort 多了一步,就是可以调用cloud provider 去创建 LB 来向节点导流(LB收费)

**九、**ExternalName

这种类型的 Service 通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容( 例如:hub.atguigu.com )。ExternalName Service 是 Service 的特例,它没有 selector,也没有定义任何的端口和Endpoint。相反的,对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务

kind: Service
apiVersion: v1
metadata:
  name: my-service-1
  namespace: default
spec:
  type: ExternalName
  externalName: hub.atguigu.com

当查询主机 my-service.defalut.svc.cluster.local ( SVC_NAME.NAMESPACE.svc.cluster.local )时,集群的DNS 服务将返回一个值 my.database.example.com 的 CNAME 记录。访问这个服务的工作方式和其他的相同,唯一不同的是重定向发生在 DNS 层,而且不会进行代理或转发

五、ingress

**一、**资料信息

Ingress-Nginx github 地址:https://github.com/kubernetes/ingress-nginx

Ingress-Nginx 官方网站:https://kubernetes.github.io/ingress-nginx/

进入官方下载

**wget **https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml

**二、**部署 Ingress-Nginx

kubectl apply -f mandatory.yaml

kubectl apply -f service-nodeport.yaml

Ingress HTTP 代理访问

deployment、Service、Ingress Yaml 文件

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx-dm
spec:
  replicas: 2
  template:
    metadata:
      labels:
        name: nginx
    spec:
      containers:
      - name: nginx
 	    image: wangyanglinux/myapp:v1
 		imagePullPolicy: IfNotPresent
 		ports:
 		- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
  selector:
    name: nginx
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
   name: nginx-test
spec:
  rules:
  - host: www1.atguigu.com
  http:
	paths:
    - path: /
      backend:
 		serviceName: nginx-svc
 		servicePort: 80

**三、**Ingress HTTPS 代理访问

创建证书,以及 cert 存储方式

openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj"/CN=nginxsvc/O=nginxsvc" kubectl create secret tls tls-secret --key tls.key --cert tls.crt

deployment、Service、Ingress Yaml 文件

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx-test
spec:
  tls:
    - hosts:
      - foo.bar.com
 	  secretName: tls-secret
  rules:
    - host: foo.bar.com
 	  http:
		paths:
		- path: /
 		  backend:
			serviceName: nginx-svc
			servicePort: 80

**四、**Nginx 进行 BasicAuth

yum -y install httpd

htpasswd -c auth foo

kubectl create secret generic basic-auth --from-file=auth

yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-with-auth
  annotations:
 	nginx.ingress.kubernetes.io/auth-type: basic
 	nginx.ingress.kubernetes.io/auth-secret: basic-auth
 	nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - foo'
spec:
  rules:
  - host: foo2.bar.com
 	http:
      paths:
      - path: /
		backend:
		  serviceName: nginx-svc
 		  servicePort: 80

**五、**Nginx 进行重写

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx-test
  annotations:
  nginx.ingress.kubernetes.io/rewrite-target: http://foo.bar.com:31795/hostname.html
spec:
  rules:
  - host: foo10.bar.com
    http:
     paths:
     - path: /
       backend:
		 serviceName: nginx-svc
   		 servicePort: 80

六、存储

一、存储之ConfigMap

**1、**描述信息

ConfigMap 功能在 Kubernetes1.2 版本中引入,许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息。ConfigMap API 给我们提供了向容器中注入配置信息的机制,ConfigMap 可以被用来保存单个属性,也可以用来保存整个配置文件或者 JSON 二进制大对象

ConfigMap 的创建存储之ConfigMap

I、使用目录创建
$ ls docs/user-guide/configmap/kubectl/
game.properties
ui.properties

$ cat docs/user-guide/configmap/kubectl/game.properties
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30


$ cat docs/user-guide/configmap/kubectl/ui.properties
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice


$ kubectl create configmap game-config --from-file=docs/user-guide/configmap/kubectl

 game-config :configmap的名称
--from-file:指定一个目录,目录下的所有内容都会被创建出来。以键值对的形式
—from-file指定在目录下的所有文件都会被用在 ConfigMap 里面创建一个键值对,键的名字就是文件名,值就是文件的内容
kubectl get cm 查看configmap文件

kubectl get cm game-config -o yaml   查看详细信息

kubectl describe cm
II、使用文件创建

只要指定为一个文件就可以从单个文件中创建 ConfigMap

$ kubectl create configmap game-config-2 --from-file=docs/user-guide/configmap/kubectl/game.properties


$ kubectlget configmaps game-config-2 -o yaml

–from-file这个参数可以使用多次,你可以使用两次分别指定上个实例中的那两个配置文件,效果就跟指定整个目录是一样的

III、使用字面值创建

使用文字值创建,利用—from-literal参数传递配置信息,该参数可以使用多次,格式如下

$ kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm

$ kubectlget configmaps special-config -o yaml    #查看

--from-literal=special.how=very  

指定键名为special.how  键值为very
**2、**Pod 中使用 ConfigMap
I、使用 ConfigMap 来替代环境变
apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  special.how: very
  special.type: charm
apiVersion: v1
kind: ConfigMap
metadata:
  name: env-config
  namespace: default
data:
  log_level: INFO
#将两个ConfigMap文件注入到pod环境中
apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
  - name: test-container
    image: hub.atguigu.com/library/myapp:v1
    command: ["/bin/sh","-c","env"]
    env:                           #第一种导入方案
 	  - name: SPECIAL_LEVEL_KEY
        valueFrom:
		  configMapKeyRef:
			name: special-config    #从那个configMap文件导入
            key: special.how       #导入的是那个键的键名,就是将special.how键的键值赋予
	  - name: SPECIAL_TYPE_KEY
        valueFrom:
 		  configMapKeyRef:
            name: special-config
			key: special.type
	envFrom:                   #第二种导入方案
	  - configMapRef: 
          name: env-config
  restartPolicy: Never
II、用 ConfigMap 设置命令行参数
apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  special.how: very
  special.type: charm
apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: hub.atguigu.com/library/myapp:v1
      command: ["/bin/sh","-c","echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)"]
      env:
		- name: SPECIAL_LEVEL_KEY
 		  valueFrom:
 			configMapKeyRef:
              name: special-config
              key: special.how
		- name: SPECIAL_TYPE_KEY
          valueFrom:
			configMapKeyRef:
			  name: special-config
  			  key: special.type
  restartPolicy: Never
III、通过数据卷插件使用ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
  special.how: very
  special.type: charm

在数据卷里面使用这个 ConfigMap,有不同的选项。最基本的就是将文件填入数据卷,在这个文件中,键就是文件名,键值就是文件内容

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: hub.atguigu.com/library/myapp:v1
      command: ["/bin/sh","-c","cat /etc/config/special.how"]
      volumeMounts:                      #容器下进行volum挂载
      - name: config-volume                #挂载的名称为config-volume,与下边相呼应
        mountPath: /etc/config
  volumes:
    - name: config-volume      #名称为config-volume
      configMap:              #从configMap导入
        name: special-config     #导入的configMap名称
  restartPolicy: Never
**3、**ConfigMap 的热更新
#创建一个configMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: log-config
  namespace: default
data:
  log_level: INFO
---
#创建Deployment对configMap进行调用,调用的方式是以volum方式进行挂载
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 1
  template:
    metadata:
      labels:
		run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: hub.atguigu.com/library/myapp:v1
        ports:
        - containerPort: 80
		volumeMounts:
		- name: config-volume
         mountPath: /etc/config
	  volumes:
	    - name: config-volume
          configMap:
            name: log-config
#获取信息
$ kubectl exec `kubectl get pods -l run=my-nginx -o=name|cut -d "/" -f2`cat/etc/config/log_level

INFO

修改 ConfigMap

$ kubectl edit configmap log-config

修改log_level的值为DEBUG等待大概 10 秒钟时间,再次查看环境变量的值

$ kubectl exec `kubectl get pods -l run=my-nginx -o=name|cut -d "/" -f2`cat /tmp/log_levelDEBUG

ConfigMap 更新后滚动更新 Pod

更新 ConfigMap 目前并不会触发相关 Pod 的滚动更新,可以通过修改 pod annotations 的方式强制触发滚动更新

$ kubectl patch deployment my-nginx --patch'{"spec": {"template": {"metadata": {"annotations":{"version/config": "20190411" }}}}}'

这个例子里我们在.spec.template.metadata.annotations中添加version/config,每次通过修改version/config来触发滚动更新

!!!更新 ConfigMap 后:使用该 ConfigMap 挂载的 Env 不会同步更新使用该 ConfigMap 挂载的 Volume 中的数据需要一段时间(实测大概10秒)才能同步更新

二、存储之secret

**1、**Secret 存在意义

Secret 解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者 Pod Spec中。Secret 可以以 Volume 或者环境变量的方式使用

2、Secret 有三种类型

① Service Account:用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到 Pod 的/run/secrets/kubernetes.io/serviceaccount目录中

② Opaque:base64编码格式的Secret,用来存储密码、密钥等

③ kubernetes.io/dockerconfigjson:用来存储私有 docker registry 的认证信息

**3、**Service Account

Service Account 用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到 Pod的/run/secrets/kubernetes.io/serviceaccount目录中

**4、**Opaque Secret
**Ⅰ、**创建说明

Opaque 类型的数据是一个 map 类型,要求 value 是 base64 编码格式:

$ echo-n"admin" | base64
YWRtaW4=

$ echo-n"1f2d1e2e67df" | base64
MWYyZDFlMmU2N2Rm

secrets.yml

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
  type: Opaque
data:
  password: MWYyZDFlMmU2N2Rm
  username: YWRtaW4=
II、使用方式

1)、将 Secret 挂载到 Volume 中

apiVersion: v1
kind: Pod
metadata:
  labels:
    name: seret-test
  name: seret-test
spec:
  volumes:
  - name: secrets
    secret:
      secretName: mysecret
  containers:
  - image: hub.atguigu.com/library/myapp:v1
    name: db
    volumeMounts:
    - name: secrets
      mountPath: ""   #挂载目录
	  readOnly: true

2)、将 Secret 导出到环境变量中

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: pod-deployment
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: pod-deployment
    spec:
      containers:
 	  - name: pod-1
		image: hub.atguigu.com/library/myapp:v1
		ports:
		- containerPort: 80
 		env:
 		- name: TEST_USER
 		  valueFrom:
 			secretKeyRef:
 			  name: mysecret
 			  key: username
	  - name: TEST_PASSWORD
 		valueFrom:
 		  secretKeyRef:
 			name: mysecret
			key: password
**5、**kubernetes.io/dockerconfigjson

使用 Kuberctl 创建 docker registry 认证的 secret

$ kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAILsecret "myregistrykey" created.

在创建 Pod 的时候,通过imagePullSecrets来引用刚创建的 `myregistrykey

apiVersion: v1
kind: Pod
metadata:
  name: foo
spec:
  containers:
    - name: foo
      image: roc/awangyang:v1
  imagePullSecrets:
  	- name: myregistrykey

三、存储数据卷Volume

容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先,当容器崩溃时,kubelet 会重启它,但是容器中的文件将丢失——容器以干净的状态(镜像最初的状态)重新启动。其次,在Pod中同时运行多个容器时,这些容器之间通常需要共享文件。Kubernetes 中的Volume抽象就很好的解决了这些问题

**1、**背景

Kubernetes 中的卷有明确的寿命 —— 与封装它的 Pod 相同。所f以,卷的生命比 Pod 中的所有容器都长,当这个容器重启时数据仍然得以保存。当然,当 Pod 不再存在时,卷也将不复存在。也许更重要的是,Kubernetes支持多种类型的卷,Pod 可以同时使用任意数量的卷

**2、**卷的类型

**3、**emptyDir

当 Pod 被分配给节点时,首先创建emptyDir卷,并且只要该 Pod 在该节点上运行,该卷就会存在。正如卷的名字所述,它最初是空的。Pod 中的容器可以读取和写入emptyDir卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上。当出于任何原因从节点中删除 Pod 时,emptyDir中的数据将被永久删除

emptyDir的用法有:

① 暂存空间,例如用于基于磁盘的合并排序

② 用作长时间计算崩溃恢复时的检查点

③ Web服务器容器提供数据时,保存内容管理器容器提取的文件

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: k8s.gcr.io/test-webserver
    name: test-container
    volumeMounts:
	- mountPath: /cache
 	  name: cache-volume
 volumes:
 - name: cache-volume
   emptyDir: {}
4、hostPathhostPath

卷将主机节点的文件系统中的文件或目录挂载到集群中

hostPath的用途如下:

① 运行需要访问 Docker 内部的容器;使用/var/lib/docker的hostPath

② 在容器中运行 cAdvisor;使用/dev/cgroups的hostPath

③ 允许 pod 指定给定的 hostPath 是否应该在 pod 运行之前存在,是否应该创建,以及它应该以什么形式存在

除了所需的path属性之外,用户还可以为hostPath卷指定type

空字符串(默认)用于向后兼容,这意味着在挂载 hostPath 卷之前不会执行任何检查

行为
空字符串(默认)用于向后兼容,这意味着在挂载 hostPath 卷之前不会执行任何检查
DirectoryOrCreate如果在给定的路径上没有任何东西存在,那么将根据需要在那里创建一个空目录,权限设置为0755,与Kubelet具有相同的组和所有权。
Directory给定的路径下必须存在目录
FileOrCreate如果在给定的路径上没有任何东西存在,那么会根据需要创建一个空文件,权限设置为0644,与Kubelet具有相同的组和所有权。
File给定的路径下必须存在文件
Socket给定的路径下必须存在UNIX套接字
CharDevice给定的路径下必须存在字符设备
BlockDevice给定的路径下必须存在块设备

使用这种卷类型是请注意,因为:

① 由于每个节点上的文件都不同,具有相同配置(例如从 podTemplate 创建的)的 pod 在不同节点上的行为可能会有所不同

② 当 Kubernetes 按照计划添加资源感知调度时,将无法考虑hostPath使用的资源

③ 在底层主机上创建的文件或目录只能由 root 写入。您需要在特权容器中以 root 身份运行进程,或修改主机上的文件权限以便写入hostPath卷

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
    - image: k8s.gcr.io/test-webserver
	  name: test-container
      volumeMounts:
 		- mountPath: /test-pd
 		  name: test-volume
  volumes:
  - name: test-volume
    hostPath:
# directory location on host
    path: /data
# this field is optional type: Directory
    type: Directory

四、PersistentVolumeClaim (PVC)

PersistentVolume (PV)

是由管理员设置的存储,它是群集的一部分。就像节点是集群中的资源一样,PV 也是集群中的资源。 PV 是 Volume 之类的卷插件,但具有独立于使用 PV 的 Pod 的生命周期。此 API 对象包含存储实现的细节,即 NFS、
iSCSI 或特定于云供应商的存储系统

PersistentVolumeClaim (PVC)

是用户存储的请求。它与 Pod 相似。Pod 消耗节点资源,PVC 消耗 PV 资源。Pod 可以请求特定级别的资源
(CPU 和内存)。声明可以请求特定的大小和访问模式(例如,可以以读/写一次或 只读多次模式挂载)

静态 pv

集群管理员创建一些 PV。它们带有可供群集用户使用的实际存储的细节。它们存在于 Kubernetes API 中,可用
于消费

动态

当管理员创建的静态 PV 都不匹配用户的 PersistentVolumeClaim 时,集群可能会尝试动态地为 PVC 创建卷。此
配置基于 StorageClasses :PVC 必须请求 [存储类],并且管理员必须创建并配置该类才能进行动态创建。声明该
类为 “” 可以有效地禁用其动态配置
要启用基于存储级别的动态存储配置,集群管理员需要启用 API server 上的 DefaultStorageClass [准入控制器]
。例如,通过确保 DefaultStorageClass 位于 API server 组件的 --admission-control 标志,使用逗号分隔的
有序值列表中,可以完成此操作

绑定

master 中的控制环路监视新的 PVC,寻找匹配的 PV(如果可能),并将它们绑定在一起。如果为新的 PVC 动态
调配 PV,则该环路将始终将该 PV 绑定到 PVC。否则,用户总会得到他们所请求的存储,但是容量可能超出要求
的数量。一旦 PV 和 PVC 绑定后, PersistentVolumeClaim 绑定是排他性的,不管它们是如何绑定的。 PVC 跟
PV 绑定是一对一的映射

持久化卷声明的保护

PVC 保护的目的是确保由 pod 正在使用的 PVC 不会从系统中移除,因为如果被移除的话可能会导致数据丢失
当启用PVC 保护 alpha 功能时,如果用户删除了一个 pod 正在使用的 PVC,则该 PVC 不会被立即删除。PVC 的
删除将被推迟,直到 PVC 不再被任何 pod 使用

持久化卷类型

PersistentVolume 类型以插件形式实现。Kubernetes 目前支持以下插件类型:

GCEPersistentDisk AWSElasticBlockStore AzureFile AzureDisk FC (Fibre Channel)

FlexVolume Flocker NFS iSCSI RBD (Ceph Block Device) CephFS

Cinder (OpenStack block storage) Glusterfs VsphereVolume Quobyte Volumes

HostPath VMware Photon Portworx Volumes ScaleIO Volumes StorageOS

持久卷演示代码

apiVersion: v1 
kind: PersistentVolume 
metadata: 
  name: pv0003 
spec: 
  capacity: 
    storage: 5Gi 
  volumeMode: Filesystem 
  accessModes: 
    - ReadWriteOnce 
  persistentVolumeReclaimPolicy: Recycle 
  storageClassName: slow 
  mountOptions: 
    - hard 
    - nfsvers=4.1 
  nfs:
    path: /tmp 
    server: 172.17.0.2
PV 访问模式

PersistentVolume 可以以资源提供者支持的任何方式挂载到主机上。如下表所示,供应商具有不同的功能,每个

PV 的访问模式都将被设置为该卷支持的特定模式。例如,NFS 可以支持多个读/写客户端,但特定的 NFS PV 可能

以只读方式导出到服务器上。每个 PV 都有一套自己的用来描述特定功能的访问模式

**ReadWriteOnce——**该卷可以被单个节点以读/写模式挂载


**ReadOnlyMany——**该卷可以被多个节点以只读模式挂载


**ReadWriteMany——**该卷可以被多个节点以读/写模式挂载

在命令行中,访问模式缩写为:

**RWO - ReadWriteOnce**


**ROX - ReadOnlyMany**


**RWX - ReadWriteMany**
回收策略

Retain(保留)——手动回收

Recycle(回收)——基本擦除( rm **-**rf /thevolume/)

Delete(删除)——关联的存储资产(例如 AWS EBSGCE PDAzure Disk OpenStack Cinder 卷)

将被删除

当前,只有 NFS HostPath **支持回收策略。AWS EBSGCE PD、**Azure Disk Cinder 卷支持删除策略

状态

卷可以处于以下的某种状态:

Available(可用)——一块空闲资源还没有被任何声明绑定

Bound(已绑定)——卷已经被声明绑定

Released(已释放)**——**声明被删除,但是资源还未被集群重新声明Failed(失败)——该卷的自动回收失败

命令行会显示绑定到 PV PVC 的名称

持久化演示说明 - NFS
Ⅰ、安装 NFS 服务器
yum install -y nfs-common nfs-utils rpcbind 
mkdir /nfsdata 
chmod 666 /nfsdata 
chown nfsnobody /nfsdata 
cat /etc/exports 
    /nfsdata *(rw,no_root_squash,no_all_squash,sync) 
systemctl start rpcbind 
systemctl start nfs
Ⅱ、部署 PV
apiVersion: v1 
kind: PersistentVolume 
metadata: 
  name: nfspv1 
spec: 
  capacity: 
    storage: 1Gi 
  accessModes: 
	- ReadWriteOnce 
  persistentVolumeReclaimPolicy: Recycle 
  storageClassName: nfs 
  nfs:
    path: /data/nfs 
    server: 10.66.66.10
Ⅲ、创建服务并使用 PVC
apiVersion: v1 
kind: Service 
metadata: 
  name: nginx 
  labels: 
  app: nginx 
spec: 
  ports: 
  - port: 80 
    name: web 
    clusterIP: None 
    selector: 
      app: nginx
---
apiVersion: apps/v1 
kind: StatefulSet 
metadata: 
  name: web 
spec: 
  selector: 
    matchLabels: 
      app: nginx 
  serviceName: "nginx" 
  replicas: 3 
  template: 
    metadata: 
	  labels: 
		app: nginx 
    spec: 
	  containers: 
		- name: nginx 
		  image: k8s.gcr.io/nginx-slim:0.8 
		  ports: 
		  - containerPort: 80 
			name: web 
		  volumeMounts: 
		  - name: www 
			mountPath: /usr/share/nginx/html 
    volumeClaimTemplates: 
    - metadata: 
		name: www 
	  spec: 
		accessModes: [ "ReadWriteOnce" ] 
		storageClassName: "nfs" 
		resources: 
		  requests: 
			storage: 1Gi
关于 StatefulSet
匹配 Pod name ( 网络标识 ) 的模式为:$(statefulset名称)-$(序号),比如上面的示例:web-0,web-1,
web-2
StatefulSet 为每个 Pod 副本创建了一个 DNS 域名,这个域名的格式为: $(podname).(headless server
name),也就意味着服务间是通过Pod域名来通信而非 Pod IP,因为当Pod所在Node发生故障时, Pod 会
被飘移到其它 Node 上,Pod IP 会发生变化,但是 Pod 域名不会有变化
StatefulSet 使用 Headless 服务来控制 Pod 的域名,这个域名的 FQDN 为:$(service
name).$(namespace).svc.cluster.local,其中,“cluster.local” 指的是集群的域名
根据 volumeClaimTemplates,为每个 Pod 创建一个 pvc,pvc 的命名规则匹配模式:
(volumeClaimTemplates.name)-(pod_name),比如上面的 volumeMounts.name=www, Pod
name=web-[0-2],因此创建出来的 PVC 是 www-web-0、www-web-1、www-web-2
删除 Pod 不会删除其 pvc,手动删除 pvc 将自动释放 pv,
Statefulset的启停顺序:

**有序部署:**部署StatefulSet时,如果有多个Pod副本,它们会被顺序地创建(从0到N-1)并且,在下一个
Pod运行之前所有之前的Pod必须都是Running和Ready状态。
**有序删除:**当Pod被删除时,它们被终止的顺序是从N-1到0。
**有序扩展:**当对Pod执行扩展操作时,与部署一样,它前面的Pod必须都处于Running和Ready状态。

StatefulSet使用场景:

1、稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于 PVC 来实现。
2、稳定的网络标识符,即 Pod 重新调度后其 PodName 和 HostName 不变。
3、有序部署,有序扩展,基于 init containers 来实现。
4、有序收缩。

七、集群调度原理以及集群调度策略略

一、k8s调度器Scheduler原理以及调度步骤:

  • 节点预选(Predicate):排除完全不满足条件的节点,如内存大小,端口等条件不满足。
  • 节点优先级排序(Priority):根据优先级选出最佳节点
  • 节点择优(Select):根据优先级选定节点
  1. 首先用户通过 Kubernetes 客户端 Kubectl 提交创建 Pod 的 Yaml 的文件,向Kubernetes 系统发起资源请求,该资源请求被提交到
  2. Kubernetes 系统中,用户通过命令行工具 Kubectl 向 Kubernetes 集群即 APIServer 用 的方式发送“POST”请求,即创建 Pod 的请求。
  3. APIServer 接收到请求后把创建 Pod 的信息存储到 Etcd 中,从集群运行那一刻起,资源调度系统 Scheduler 就会定时去监控 APIServer
  4. 通过 APIServer 得到创建 Pod 的信息,Scheduler 采用 watch 机制,一旦 Etcd 存储 Pod 信息成功便会立即通知APIServer,
  5. APIServer会立即把Pod创建的消息通知Scheduler,Scheduler发现 Pod 的属性中 Dest Node 为空时(Dest Node=””)便会立即触发调度流程进行调度。
而这一个创建Pod对象,在调度的过程当中有3个阶段:节点预选、节点优选、节点选定,从而筛选出最佳的节点
  • 节点预选:基于一系列的预选规则对每个节点进行检查,将那些不符合条件的节点过滤,从而完成节点的预选
  • 节点优选:对预选出的节点进行优先级排序,以便选出最合适运行Pod对象的节点
  • 节点选定:从优先级排序结果中挑选出优先级最高的节点运行Pod,当这类节点多于1个时,则进行随机选择

二、k8s的调用工作方式

Kubernetes调度器作为集群的大脑,在如何提高集群的资源利用率、保证集群中服务的稳定运行中也会变得越来越重要Kubernetes的资源分为两种属性。

  1. 可压缩资源(例如CPU循环,Disk I/O带宽)都是可以被限制和被回收的,对于一个Pod来说可以降低这些资源的使用量而不去杀掉Pod。
  2. 不可压缩资源(例如内存、硬盘空间)一般来说不杀掉Pod就没法回收。未来Kubernetes会加入更多资源,如网络带宽,存储IOPS的支持。

三、常用预选策略

预选策略作用
CheckNodeCondition检查是否可以在节点报告磁盘、网络不可用或未准备好时将Pod调度其上
HostName如果Pod对象拥有spec.hostname属性,则检查节点名称字符串是否和该属性值匹配。
PodFitsHostPortsPod的spec.hostPort属性时,检查端口是否被占用
MatchNodeSelectorPod的spec.nodeSelector属性时,检查节点标签
NoDiskConflictPod依赖的存储卷在此节点是否可用,默认没有启用
PodFitsResources检查节点上的资源(CPU、内存)可用性是否满足Pod对象的运行需求。
PodToleratesNodeTaintsPod的spec.tolerations属性,仅关注NoSchedule和NoExecute两个效用标识的污点
PodToleratesNodeNoExecuteTaintsPod的spec.tolerations属性,是否能接纳节点的NoExecute类型污点,默认没有启用
CheckNodeLabelPresence仅检查节点上指定的所有标签的存在性,默认没有启用
CheckServiceAffinity将相同Service的Pod对象放置在同一个或同一类节点上以提高效率,默认没有启用
MaxEBSVolumeCount检查节点已挂载的EBS(亚马逊弹性块存储)存储卷数量是否超过设置的最大值,默认为39
MaxGCEPDVolumeCount检查节点上已挂载的GCE PD(谷歌云存储) 存储卷数量是否超过最大值,默认为16
MaxAzureDiskVolumeCount检查节点上已挂载的Azure Disk存储卷数量是否超过最大值,默认为16
CheckVolumeBinding检查节点上已绑定和未绑定的PVC是否满足需求
NoVolumeZoneConflict在给定区域zone限制下,检查此节点部署的Pod对象是否存在存储卷冲突
CheckNodeMemoryPressure检查节点内存压力,如果压力过大,那就不会讲pod调度至此
CheckPodePIDPressure检查节点PID资源压力
CheckNodeDiskPressure检查节点磁盘资源压力
MatchInterPodAffinity检查节点是否满足Pod对象亲和性或反亲和性条件

四、常用优先函数

函数名称详细说明
LeastRequestedPriority节点的优先级就由节点空闲资源与节点总容量的比值,即由(总容量-节点上Pod的容量总和-新Pod的容量)/总容量)来决定。 CPU和内存具有相同权重,资源空闲比越高的节点得分越高。
cpu((capacity – sum(requested)) * 10 / capacity) + memory((capacity – sum(requested)) * 10 / capacity) / 2
BalancedResourceAllocationCPU和内存使用率越接近的节点权重越高,该策略不能单独使用,必须和LeastRequestedPriority组合使用,尽量选择在部署Pod后各项资源更均衡的机器。 如果请求的资源(CPU或者内存)需求大于节点的capacity,那么该节点永远不会被调度到。
InterPodAffinityPriority通过迭代 weightedPodAffinityTerm 的元素计算和,并且如果对该节点满足相应的PodAffinityTerm,则将 “weight” 加到和中,具有最高和的节点是最优选的。
SelectorSpreadPriority为了更好的容灾,对同属于一个service、replication controller或者replica的多个Pod副本,尽量调度到多个不同的节点上。 如果指定了区域,调度器则会尽量把Pod分散在不同区域的不同节点上。当一个Pod的被调度时,会先查找Pod对于的service或者replication controller, 然后查找service或replication controller中已存在的Pod,运行Pod越少的节点的得分越高。本质就是往运行同类pod少的节点上分配。
NodeAffinityPriority亲和性机制。Node Selectors(调度时将pod限定在指定节点上), 支持多种操作符(In, NotIn, Exists, DoesNotExist, Gt, Lt),而不限于对节点labels的精确匹配。 另外支持两种类型的选择器,一种是“hard(requiredDuringSchedulingIgnoredDuringExecution)”选择器, 它保证所选的主机必须满足所有Pod对主机的规则要求。 这种选择器更像是之前的nodeselector,在nodeselector的基础上增加了更合适的表现语法。 另一种是“soft(preferresDuringSchedulingIgnoredDuringExecution)”选择器, 它作为对调度器的提示,调度器会尽量但不保证满足NodeSelector的所有要求。
NodePreferAvoidPodsPriority(权重1W)如果 节点的 Anotation (注解信息)没有设置 key-value:scheduler. alpha.kubernetes.io/ preferAvoidPods = “…”,则节点对该 policy 的得分就是10分, 加上权重10000,那么该node对该policy的得分至少10W分。如果Node的Anotation设置了, scheduler.alpha.kubernetes.io/preferAvoidPods = “…” ,如果该 pod 对应的 Controller 是 ReplicationController 或 ReplicaSet, 则该 node 对该 policy 的得分就是0分。
TaintTolerationPriority使用 Pod 中 tolerationList 与 节点 Taint 列表项进行匹配,配对成功的项越多,则得分越低。污点越匹配,得分越低
ImageLocalityPriority根据Node上是否存在一个pod的容器运行所需镜像大小对优先级打分,分值为0-10。遍历全部Node, 如果某个Node上pod容器所需的镜像一个都不存在,分值为0; 如果Node上存在Pod容器部分所需镜像,则根据满足当前需求的镜像的大小来决定分值,镜像越大,分值就越高;如果Node上存在pod所需全部镜像,分值为10。默认没有启用
EqualPriority是一个优先级函数,它给予所有节点相等权重。
MostRequestedPriority在 ClusterAutoscalerProvider 中,替换 LeastRequestedPriority,给使用多资源的节点,更高的优先级。 计算公式为:

(cpu(10 sum(requested) / capacity) + memory(10 sum(requested) / capacity)) / 2
默认没有启用 |

五、节点亲和性调度

1、节点亲和性规则

硬亲和性 required 、软亲和性 preferred。

  • 硬亲和性规则不满足时,Pod会置于Pending状态,软亲和性规则不满足时,会选择一个不匹配的节点
  • 当节点标签改变而不再符合此节点亲和性规则时,不会将Pod从该节点移出,仅对新建的Pod对象生效
2、节点硬亲和性

requiredDuringSchedulingIgnoredDuringExecution

  • 方式一:Pod使用 spec.nodeSelector (基于等值关系)
  • 方式二:Pod使用 spec.affinity 支持matchExpressions属性 (复杂标签选择机制)
# 调度至 zone = foo 的节点
kubectl label nodes kube-node1 zone=foo
apiVersion: v1
kind: Pod
metadata:
  name: with-required-nodeaffinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:  # 定义硬亲和性
        nodeSelectorTerms:
        - matchExpressions:   #集合选择器
          - {key: zone,operator: In,values: ["foo"]}
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1

六、节点软亲和性

preferredDuringSchedulingIgnoredDuringExecution

  • 柔性控制逻辑,当条件不满足时,能接受被编排于其他不符合条件的节点之上
  • 权重 weight 定义优先级,1-100 值越大优先级越高
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy-with-node-affinity
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      name: myapp-pod
      labels:
        app: myapp
    spec:
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:   #节点软亲和性
          - weight: 60
            preference:
              matchExpressions:
              - {key: zone, operator: In, values: ["foo"]}
          - weight: 30
            preference:
              matchExpressions:
              - {key: ssd, operator: Exists, values: []}
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1

七、Pod资源亲和调度

  • Pod对象间亲和性,将一些Pod对象组织在相近的位置(同一节点、机架、区域、地区)
  • Pod对象间反亲和性,将一些Pod在运行位置上隔开

调度器将第一个Pod放置于任何位置,然后与其有亲和或反亲和关系的Pod据此动态完成位置编排

基于MatchInterPodAffinity预选策略完成节点预选,基于InterPodAffinityPriority优选函数进行各节点的优选级评估

位置拓扑,定义"同一位置"

Pod硬亲和调度

requiredDuringSchedulingIgnoredDuringExecution

Pod亲和性描述一个Pod与具有某特征的现存Pod运行位置的依赖关系;即需要事先存在被依赖的Pod对象

# 被依赖Pod
kubectl run tomcat -l app=tomcat --image tomcat:alpine
kubectl explain pod.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution.topologyKey
apiVersion: v1
kind: Pod
metadata:
  name: with-pod-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:  # 硬亲和调度
      - labelSelector:
          matchExpressions:    #集合选择器
          - {key: app, operator: In, values: ["tomcat"]}  # 选择被依赖Pod
          # 上面意思是,当前pod要跟标签为app值为tomcat的pod在一起
        topologyKey: kubernetes.io/hostname  # 根据挑选出的Pod所有节点的hostname作为同一位置的判定
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
Pod软亲和调度
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-with-preferred-pod-affinity
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      name: myapp
      labels:
        app: myapp
    spec:
      affinity:
        podAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 80
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - {key: app, operator: In, values: ["cache"]}
              topologyKey: zone
          - weight: 20
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - {key: app, operator: In, values: ["db"]}
              topologyKey: zone
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
Pod反亲和调度

Pod反亲和调度用于分散同一类应用,调度至不同的区域、机架或节点等
spec.affinity.podAffinity替换为 spec.affinity.podAntiAffinity

反亲和调度也分为柔性约束和强制约束

apiVersion: v1
kind: Pod
metadata:
    name: pod-first
    labels: 
        app: myapp
        tier: fronted
spec:
    containers:
    - name: myapp
      image: ikubernetes/myapp:v1
---
apiVersion: v1
kind: Pod
metadata:
    name: pod-second
    labels:
        app: backend
        tier: db
spec:
    containers:
    - name: busybox
      image: busybox:latest
      imagePullPolicy: IfNotPresent
      command: ["/bin/sh", "-c", "sleep 3600"]
    affinity:
      podAntiAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchExpressions:
            - {key: app, operator: In, values: ["myapp"]}
          topologyKey: zone

八、污点和容忍度

污点 taints 是定义在节点上的键值型属性数据,用于让节点拒绝将Pod调度运行于其上,除非Pod有接纳节点污点的容忍度容忍度 tolerations 是定义在Pod上的键值属性数据,用于配置可容忍的污点,且调度器将Pod调度至其能容忍该节点污点的节点上或没有污点的节点上

**1、**预选策略、优选函数

使用PodToleratesNodeTaints预选策略和TaintTolerationPriority优选函数完成该机制

  • 节点亲和性使得Pod对象被吸引到一类特定的节点 (nodeSelector和affinity)
  • 污点提供让节点排斥特定Pod对象的能力
2、定义污点和容忍度

污点定义于nodes.spec.taints容忍度定义于pods.spec.tolerations
语法: key=value:effect

3、effect定义排斥等级:
  • NoSchedule,不能容忍,但仅影响调度过程,已调度上去的pod不受影响,仅对新增加的pod生效。
  • PreferNoSchedule,柔性约束,节点现存Pod不受影响,如果实在是没有符合的节点,也可以调度上来
  • NoExecute,不能容忍,当污点变动时,Pod对象会被驱逐
4、在Pod上定义容忍度时:
  1. 等值比较 容忍度与污点在key、value、effect三者完全匹配
  2. 存在性判断 key、effect完全匹配,value使用空值

一个节点可配置多个污点,一个Pod也可有多个容忍度

5、管理节点的污点

同一个键值数据,effect不同,也属于不同的污点

给节点添加污点:
kubectl taint node <node-name> <key>=<value>:<effect>
kubectl taint node node2 node-type=production:NoShedule  #举例
查看节点污点:
kubectl get nodes <nodename> -o go-template={{.spec.taints}}
删除节点污点:
kubectl taint node <node-name> <key>[:<effect>]-
kubectl patch nodes <node-name> -p '{"spec":{"taints":[]}}'

kubectl taint node kube-node1 node-type=production:NoSchedule
kubectl get nodes kube-node1 -o go-template={{.spec.taints}}
# 删除key为node-type,effect为NoSchedule的污点
kubectl taint node kube-node1 node-type:NoSchedule-

# 删除key为node-type的所有污点
kubectl taint node kube-node1 node-type-

# 删除所有污点
kubectl patch nodes kube-node1 -p '{"spec":{"taints":[]}}'
给Pod对象容忍度

spec.tolerations字段添加
tolerationSeconds用于定义延迟驱逐Pod的时长

# 等值判断
tolerations:
- key: "key1"
  operator: "Equal"  #判断条件为Equal
  value: "value1"
  effect: "NoExecute"
  tolerationSeconds: 3600
 
# 存在性判断
tolerations:
- key: "key1"
  operator: "Exists"    #存在性判断,只要污点键存在,就可以匹配
  effect: "NoExecute"
  tolerationSeconds: 3600
apiVersion: v1
kind: Deployment
metadata:
    name: myapp-deploy
    namespace: default
spec:
    replicas: 3
    selector:
        matchLabels:
            app: myapp
            release: canary
    template:
        metadata:
            labels:
                app: myapp
                release: canary
        spec:
            containers:
            - name: myapp
            image: ikubernetes/myapp:v1
            ports:
            - name: http
              containerPort: 80
            tolerations:
            - key: "node-type"
              operator: "Equal"
              value: "production":
              effect: "NoExecute"
              tolerationSeconds: 3600

九、问题节点标识

自动为节点添加污点信息,使用NoExecute效用标识,会驱逐现有Pod
K8s核心组件通常都容忍此类污点

node.kubernetes.io/not-ready 节点进入NotReady状态时自动添加
node.alpha.kubernetes.io/unreachable 节点进入NotReachable状态时自动添加
node.kubernetes.io/out-of-disk 节点进入OutOfDisk状态时自动添加
node.kubernetes.io/memory-pressure 节点内存资源面临压力
node.kubernetes.io/disk-pressure 节点磁盘面临压力
node.kubernetes.io/network-unavailable 节点网络不可用
node.cloudprovider.kubernetes.io/uninitialized kubelet由外部云环境程序启动时,自动添加,待到去控制器初始化此节点时再将其删除

十、Pod优选级和抢占式调度

优选级,Pod对象的重要程度
优选级会影响节点上Pod的调度顺序和驱逐次序
一个Pod对象无法被调度时,调度器会尝试抢占(驱逐)较低优先级的Pod对象,以便可以调度当前Pod

Pod优选级和抢占机制默认处于禁用状态
启用:同时为kube-apiserver、kube-scheduler、kubelet程序的 --feature-gates 添加 PodPriority=true
使用:
事先创建优先级类别,并在创建Pod资源时通过 priorityClassName属性指定所属的优选级类别

八、 集群安全机制

学习目标:集群的认证 鉴权 访问控制 原理及流程

一、认证:

A、HTTP Token认证:通过一个Token来识别合法用户。

  1. HTTP  Token的认证是用一个很长的特殊编码方式的并且难以被模仿的字符串-token来表达客户的一种方式。Token是一个很长很复杂的字符串,每一个token对应一个用户名存储在API Server能访问的文件中。当客户端发起API调用请求的时候,需要在HTTP Header里放入token。

B、 HTTP Base认证:通过用户名+密码的方式认证

  1. 用户名+密码使用base64算法进行编码后的字符串放在HTTP Request中的Header Authorization域里发送给服务端,服务端收到后进行编码,获取用户名和密码

C、最严格的HTTPS证书认证:基于CA根证书签名的客户端身份认证方式

二、需要认证的节点

A、两种类型

  1. kubernetes组件对API Server的访问:kubectl、Controller Manager、Scheduler、kubelet、kube-proxy

  2. kubernetes管理的pod对容器的访问:pod(dashboard是以pod形式运行)

B、安全性说明

  1. Controller Manager、Scheduler与API Server在同一台机器,所以直接使用API Server的非安全端口访问, --insecure-bind-address=127.0.0.1

  2. kubectl、kubelet、kube-proxy访问API Server就需要证书进行HTTPS双向认证

  3. 证书颁发

a. 手动签发:通过k8s集群的根ca进行签发HTTPS证书

b. 自动签发:kubelet首次访问API Server时,使用token做认证,通过后,Controller Manager会为kubelet生成一个证书,以后的访问都是用证书做认证了。

C、kubeconfig

  1. kubeconfig文件包含集群参数(CA证书、API  Server地址),客户端参数(上面生成的证书和私钥),集群context信息(集群名称,用户名)。kubernetes组件通过启动时指定不同的kubeconfig文件可以切换到不同集群。

D、ServiceAccount

  1. Pod中的容器访问API Server。因为Pod的创建、销毁是动态的,所以要为它手动生成证书就不可行了。kubernetes使用了ServiceAccount解决pod访问apiserver的认证问题。

E、Secret和SA之间的关系

  1. kubernetes设计了一种资源对象叫做Secret,分为两类,一种是用于ServiceAccount的service-account-token,另一种是用于保存用户自定义保密信息的Opaque。ServiceAccount中用到包含三个部分:Token、ca.crt、namespace

a. token是使用api server私钥签名的JWT。用于访问API Server,Server端认证。

b. ca.crt,根证书用于Clien端验证API Server发送的证书。

c. namespace,标识这个server-account-token的作用域空间

e. kubectl get secrets --all-namespace

kubectl describe secret default-token-59mfg --namespace-kube-system

f. 默认情况下每个namespace都会有一个ServiceAccount,如果Pod在创建时没有指定ServiceAccount,就会使用Pod所属的namespace的ServiceAccount

默认挂载目录:/run/secrets/kubernetes.io/serviceaccount/
  F、总结

三、鉴权(Authorization)

A、上面认证过程,只是确认了通信的双方是可信的,可以互相通信。而鉴权是确定请求方有哪些资源的权限。API Server目前支持以下几种授权策略(通过API Server的启动参数“–authorization-mode”设置)

  1. AlwaysDeny:表示拒绝所有请求,一般用于测试

  2. AlwaysAllow:允许接收所有请求,如果集群不需要授权流程,则可以采用该策略。

  3. ABAC(Attribute-Based Access Control):基于属性的访问控制,表示使用用户配置的授权规则对用户进行匹配和控制

  4. webbook:通过调用外部的REST服务对用户进行授权

  5. RBAC(Role-Based Access Control):基于角色的访问控制,现行默认

B、RBAC授权模式

  1. RBAC的API资源对象说明

RBAC引入了4个新的顶级资源对象:Role、ClusterRole、RoleBinding、ClusterRoleBinding,4中对象类型均可以通过kubectl和API操作

  1. kubernetes组件(kubectl、kube-proxy)或是其它自定义的用户在向CA申请证书的时候,需要提供一个证书请求文件
{
	"CN": "admin",
    "hosts": [],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "name": {
        "C": "CN",
        "ST": "hangzhou",
        "L": "XS",
        "O": "system:masters",
        "OU": "System"
    }
}

API Server会把客户端的CN字段作为User,把names.O字段作为组Group

C、Role和ClusterRole

  1. Role要定义在一个namespace中,如果想要跨namespac则可以创建ClusterRole
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
  metadata:
    name: pod-reader
    namespace: default
rules:
  - apiGroups: [""] # ""代表API核心组
    resources: ["pods"]
	verbs: ["get", "watch","list"]
  1. ClusterRole和Role具有相同的权限角色控制能力,不同的是ClusterRole是集群级别的,ClusterRole可以用于:

a. 集群级别的资源控制(例如node访问权限)

b. 非资源型endpoints(例如/healz访问)

c. 所有名称空间资源控制(如pods)

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
# 这里不要定义namespace,因为ClusterRole是集群概念下的,不是名称空间概念下的
  name: secret-reader
rules:
  - apiGroup: [""]
	resources: ["secrets"]
	verbs: ["get","watch","list"]

D、RoleBind 和 ClusterRoleBinding

  1. RoleBinding可以将角色中定义的权限授予用户或用户组,RoleBinding包含一组权限列表(subjects),权限列表中包含有不同形式的待授权资源类型(users,groups,or service  account);RoleBind同样包含对被Bind的Role的引用;RoleBinding适用于某个名称空间内授权,而ClusterRoleBinding适用于集群范围内额授权。

a. 例子

kind: RoleBinding
apiServer: rbac.authorization.k8s.io/v1beta1
metadata:
  name: read-pods
  namespace: default
subjects:
  - kind: User
	name: jane
	apiGroup: rbac.autorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

2. RoleBing同样可以引用ClusterRole来对当前namespace内用户、用户组或ServiceAccount进行授权,这种操作允许集群管理员在整个集群内定义一些通用的ClusterRole,然后在不同的namespace中使用RoleBinding来引用。

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta
metadata:
  name: read-secrets
  namespace: development #这只会给development名称空间下的授予权限
subjects:
  - kind: User
	name: dave
	apiGroup: rbac.authorization.k8s.io
roleRef:
	kind: ClusterRole
	name: secrets-reader
	apiGroup: rbac.authorization.k8s.io

3.使用ClusterRoleBinding可以对整个集群中的所有命名空间资源进行授权

a. 例子

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: read-secret-global
subjects:
  - kind: Group
	name: manager
	apiGroup: rbac.authorization.k8s.io
roleRef:
	kind: ClusterRole
	name: secret-reader
	apiGroup: rbac.authorization.k8s.io

F、Resources

  1. Kubernetes集群内一些资源一般以其名称字符串来表示,这些字符串一般会在API的URL地址中出现;同时某些资源也会包含子资源,例如logs资源就属于pods的子资源,API中的URL样例如下

GET /api/v1/namespaces/{namespace}/pods/{pod}/log

  1. 如果要在RBAC授权模式中控制这些子资源的访问权限,可以通过/分隔符来实现,一下是一个定义pods资源logs访问权限的Role定义样例
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: pod-and-pod-logs-reader
  namespace: default
rules:
  - apiGroup: [""]
	resources: ["pods","pods/log"]
	verbs: ["get","list"]

H、实验:创建一个用户只能管理dev空间

  1. user add devuser

  2. passwd devuser

  3. cd /usr/local/install-k8s/ && mkdir cert && cd cert && vim devuser-csr.json

{
    "CN": "devuser",
    "hosts": [],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "ST": "BeiJing",
            "L": "BeiJing",
            "O": "k8s",
            "OU": "System"
        }
    ]
}

\4. 下载证书工具到/usr/local/bin下:

a. wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64

mv cfssl_linux-amd64 cfssl

b. wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64

mv cfssljson_linux-amd64 cfssljson

c. wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64

mv cfssl-certinfo_linux-amd64 cfssl-certinfo

d. cd /etc/kubernetes/pki/

f. cfssl gencert -ca=ca.crt -ca-key=ca.key -profile=kubernetes  /usr/local/install-k8s/cert/devuser/devuser-csr.json | cfssljson -bare  devuser

  1. 设置集群参数

a. export KUBE_APISERVER=“https://192.168.66.10:6443”

b. kubectl config set-cluster kubernetes  --certificate-authority=/etc/kubernetes/pki/ca.crt --embed-certs=true  --server=${KUBE_APISERVER} --kubeconfig=devuser.kubeconfig

  1. 设置客户端认证参数

a. kubectl config set-credentials devuser  --client-certificate=/etc/kubernetes/pki/devuser.pem  --client-key=/etc/kubernetes/pki/devuser-key.pem --embed-certs=true  --kubeconfig=devuser.kubeconfig

  1. 设置上下文参数

a. kubectl config set-context kubernetes --cluster=kubernetes  --user=devuser --namespace=dev --kubeconfig=devuser.kubeconfig

  1. 设置默认上下文

c. 创建一个rolebinding将admin角色绑定至dev名称空间下的devuser:kubectl create  rolebinding devuser-admin-binding --clusterrole=admin --user=devuser  --namespace=dev

e. 将devuser.kubeconfig拷贝至devuser下.kube目录下: cp devuser.kubeconfig /home/devuser/.kube/

f. 改变devuser.kubeconfig的所有者为devuser组下的devuser: chown devuser:devuser /home/devuser/.kube/devuser.kubeconfig

g. 将devuser.kubeconfig文件名修改为config: mv devuser.kubeconfig config

h. 切换上下文:kubectl config use-context kubernetes --kubeconfig=/home/devuser/.kube/config

四、准入控制

A、准入控制是Api Server的插件集合,通过添加不同的插件,实现额外的准入控制规则。甚至API  Server的一些主要功能都需要通过Admission  Controllers实现,比如ServiceAccount,官方文档上有一份针对不同版本的准入控制器推荐列表。

B、列举几个插件的功能

  1. NamespaceLifeCycle:防止在不存在的namespace上创建对象,防止删除系统预置的namespace,删除namespace时,连带删除它的所有资源对象。

  2. LimitRanger:确保请求的资源不会超过资源所在的Namespace的LimitRange

  3. ServiceAccount:实现了自动化添加ServiceAccount

  4. ResourceQuota:确保请求资源不会超过资源的ResourceQuota限制

查看系统运行日志:journalctl -f

这篇关于指令很全的K8s学习笔记的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!