zoukankan      html  css  js  c++  java
  • kubernetes入门

    简介

    • Docker发布Docker Swarm,架构优秀,但是功能简单,不能完全符合市场需求

    • Google发布Go语言开发的开源Kubernetes项目,参考Borg系统开发,技术成熟,功能强大,使用简单

    • Kubernetes简称k8s,架构如下图所示:

    组件介绍

    • API-Server:整个集群的核心,基本上所有的组件都需要和API-Server进行交互,也是外界访问Kubernetes的唯一入口

    • Etcd:键值对分布式数据库,集群中所有的重要信息都存储在其中

    • Schedular:调度器,负责调度Pod到那个节点上运行

    • Controller:控制器,主要是对Pod进行控制

    • Kubelet:从节点上负责与主节点上的API-Server进行交互的组件,同时负责与本节点的容器进行通信

    • Kube-Proxy:用来转发service中定义的服务,实现外部可以访问集群内的服务

    • Flanner:一种覆盖网络,实现集群内Pod之间的通信

    • DNS:域名解析服务(高版本默认安装)

    • Dashboard:基于网页的Kubernetes用户界面,用于实时查看集群的内部状态

    • Helm:服务安装工具,类似Centos上的yum,python中的pip,方便高效

    • EFK:日志查看工具

    控制器

    • Replication Controller:用于控制副本的个数,是的副本个数始终等于期望的个数。

    • Replication Set:是Replication Controller的升级版本,包含Replication Controller的全部功能,新增基于Label selector的集合操作。

    • Deployment:新增组件,通过控制Replication Set的方式控制副本数,主要是新增升级和回滚功能。升级的大概流程:创建一个新的RS,控制老的RS杀死一个副本,控制新的RS创建一个副本,依次循环,直到所有的老副本都变成新副本,然后杀死老的RS。回滚也是相同的流程,可以把回滚理解成升级的目标版本是老版本。

    • StatefulSet:主要是处理有状态服务,目前是Kubernetes的短板。无状态:如流水线上的工人可以随时离开一段时间,回来后可以继续无缝连接工作;有状态:部门开发经理离开一段之后,再回来工作可能就不能跟上节奏了,因为项目的状态在实时更新,对比服务,最明显的例子就是数据库服务。

    • Daemon Set:保证每个节点上都运行一个Pod,主要适用于日志采集和性能监控服务

    • Job:保证任务执行一次且成功结束,相比于手动执行任务,Job的优势是如果任务异常结束,会被重新执行,直到成功结束

    • Corn Job:周期性定时运行任务

    Flanner网络

            Flannel实质上是一种“覆盖网络(overlay network)”,在现有的网络上实现另外一层网络,主要是将需要发送的报文通过UDP的方式封装,然后通过真实的网卡传输,在目的端解封得到传输的报文,最后根据传输的报文将报文发送给指定IP的Pod。需要注意的是:这里传输的数据是TCP/TCMP/UDP等格式的报文。宏观上理解是:在应用层上定义一种私有协议,实现多主机上的点对点传输,只不过这种私有协议是TCP/TCMP/UDP等。

            处理流程:数据从源容器中发出后,经由所在主机的docker0虚拟网卡转发到flannel0虚拟网卡(桥接方式),这是个P2P的虚拟网卡,flanneld服务监听在网卡的另外一端。Flannel通过Etcd服务维护了一张节点间的路由表,详细记录了各节点子网网段。源主机的flanneld服务将原本的数据内容UDP封装后根据自己的路由表投递给目的节点的flanneld服务,数据到达以后被解包,然后直接进入目的节点的flannel0虚拟网卡,然后被转发到目的主机的docker0虚拟网卡,最后就像本机容器通信一下的有docker0路由到达目标容器。flannel0虚拟网卡的作用就是UDP封装和解封,在容器层面感知不到,就像直接Socket通信一样。控制容器的的IP地址,是通过设置容器的启动参数--bip实现。

    Pod

    • Pod是Kubernetes中能够创建和部署的最小单元,一个Pod中可能包含一个或多个容器,属于同一个Pod的所有容器共享一个IP,且数据卷也是共享,彼此之间通过localhost就可以通信。Pod可以分为两种:自主式Pod和控制器管理的Pod。

    • 所有的Pod在启动时会默认创建一个pasue的容器,然后里面的其他容器共享pause的网络协议栈,达到IP相同的目的

    • Kubernetes为什么不将容器当做调度的最小单元?

      • Pod需要和ApiServer进行通信,包括交互探测到的容器健康状态,如果直接将具体的容器当做调度单元管理,那么需要针对具体的容器类型进行开发,非常麻烦。启用pod之后,直接在Pod里面进行差异化开发,对ApiServer统一接口。基本思想就是增加一层,解决差异化。

      • 大多数时候,一个业务的建立需要多个容器联合完成,将彼此管理的多个容器一起调度更加合适

    • Pod的状态

      • Pending:Pod已被Kubernetes系统接受,但尚未创建一个或多个Container

      • Running:Pod已绑定到节点,并且已创建所有Container

      • Succeeded:Pod中的所有容器都已成功终止,并且不会重新启动

      • Failed:Pod中的所有容器都已终止,并且至少有一个Container已终止失败

      • Unknown:由于某种原因,无法获得Pod的状态

    资源

    • 空间名称级别

      • 工作负载型:Pod,RC,RS,Deployment,StatefulSet,DaemonSet,Job,CronJob

      • 服务发现型:Service,Ingress

      • 存储型:Volume,CSI(容器存储统一接口,标准)

      • 特殊型存储卷:ConfigMap(当配置中心使用的资源类型),Secret(保存敏感数据),DownwardAPI(外部信息输入给容器)

    • 集群级别

      • Namespace,Node,Role,ClusterRole,RoleBinding,ClusterRoleBinding

    • 元数据型

      • HPA,PodTemplate,LimitRange

      • 理解成有一定指标的东西

    • Kubernetes中所有的内容都可以抽象为资源,资源实例化之后(理解为被执行),叫做对象

    yaml格式

    YAML语言的设计目标是方便人类读写。它实质上是一种通用的数据串行化格式。它的基本语法规则如下:

    • 大小写敏感

    • 使用缩进表示层级关系

    • 缩进时不允许使用Tab键,只允许使用空格

    • 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可

    • # 表示注释,从这个字符一直到行尾,都会被解析器忽略

    YAML支持的数据结构有三种:

    • 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)

    • 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)

    • 纯量(scalars):单个的、不可再分的值

    对象:对象的一组键值对,使用冒号结构表示

    animal: pets
    hash: { name: Steve, foo: bar } 

    数组:一组连词线开头的行,构成一个数组

    animal:
    - Cat
    - Dog
    - Goldfish
    ​
    animal: [Cat, Dog]

    纯量:纯量是最基本的、不可再分的值。以下数据类型都属于 JavaScript 的纯量:

    • 字符串

    • 布尔值

    • 整数

    • 浮点数

    • Null

    • 时间

    • 日期

    number: 12.30
    isSet: true
    iso8601: 2001-12-14t21:59:43.10-05:00 
    date: 1976-07-31

    字符串:字符串是最常见,也是最复杂的一种数据类型。

    • 字符串默认不使用引号表示

    • 如果字符串之中包含空格或特殊字符,需要放在引号之中

    • 单引号和双引号都可以使用,双引号不会对特殊字符转义

    • 单引号之中如果还有单引号,必须连续使用两个单引号转义

    • 字符串可以写成多行,从第二行开始,必须有一个单空格缩进。换行符会被转为空格

    • 多行字符串可以使用|保留换行符,也可以使用>折叠换行

    • +表示保留文字块末尾的换行,-表示删除字符串末尾的换行

    str: 这是一行字符串
    ​
    str: '内容: 字符串'
    ​
    str: 'labor''s day' 
    ​
    this: |
      Foo
      Bar
    that: >
      Foo
      Bar
    #{ this: 'Foo
    Bar
    ', that: 'Foo Bar
    ' }  
    ​
    str: 这是一段
      多行
      字符串
    #{ str: '这是一段 多行 字符串' }
    ​
    s1: |
      Foo
    ​
    s2: |+
      Foo
    ​
    ​
    s3: |-
      Foo
    #{ s1: 'Foo
    ', s2: 'Foo
    
    
    ', s3: 'Foo' }

    yaml常用字段

    apiVersion: v1  #必选,版本号,例如v1
    kind: Pod       #必选,Pod
    metadata:       #必选,元数据
      name: string       #必选,Pod名称
      namespace: string  #必选,Pod所属的命名空间
      labels:            #自定义标签
        - name: string   #自定义标签名字
      annotations:       #自定义注释列表
        - name: string
    spec:                #必选,Pod中容器的详细定义
      containers:        #必选,Pod中容器列表
      - name: string     #必选,容器名称
        image: string    #必选,容器的镜像名称
        imagePullPolicy: [Always | Never | IfNotPresent] #获取镜像的策略 
                         #Alawys表示总是下载镜像 
                         #IfnotPresent表示优先使用本地镜像,本地没有就下载镜像
                         #Nerver表示仅使用本地镜像
        command: [string]  #容器的启动命令列表,如不指定,使用打包时使用的启动命令
        args: [string]     #容器的启动命令参数列表
        workingDir: string #容器的工作目录,进入容器的起始目录
        volumeMounts:      #挂载到容器内部的存储卷配置
        - name: string     #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
          mountPath: string    #存储卷在容器内mount的绝对路径,应少于512字符
          readOnly: boolean    #是否为只读模式
        ports:                 #需要暴露的端口库号列表
        - name: string         #端口号名称
          containerPort: int   #容器需要监听的端口号
          hostPort: int        #容器所在主机需要监听的端口号,默认与Container相同
          protocol: string     #端口协议,支持TCP和UDP,默认TCP
        env:                   #容器运行前需设置的环境变量列表
        - name: string         #环境变量名称
          value: string        #环境变量的值
        resources:             #资源限制和请求的设置
          limits:              #资源限制的设置
            cpu: string        #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
            memory: string     #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
          requests:            #资源请求的设置
            cpu: string        #Cpu请求,容器启动的初始可用数量
            memory: string     #内存清楚,容器启动的初始可用数量
        livenessProbe:         #对Pod内个容器健康检查的设置,当探测无响应几次后将自动重启该容器
                               #检查方法有exec、httpGet和tcpSocket,对一个容器只需设置其中一种方法即可
          exec:                #对Pod容器内检查方式设置为exec方式
            command: [string]  #exec方式需要制定的命令或脚本
          httpGet:             #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
            path: string
            port: number
            host: string
            scheme: string
            HttpHeaders:
            - name: string
              value: string
          tcpSocket:               #对Pod内个容器健康检查方式设置为tcpSocket方式
             port: number
           initialDelaySeconds: 0  #容器启动完成后首次探测的时间,单位为秒
           timeoutSeconds: 0       #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
           periodSeconds: 0        #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
           successThreshold: 0
           failureThreshold: 0
           securityContext:
             privileged:false
        restartPolicy: [Always | Never | OnFailure] #Pod的重启策略
                                       #Always表示一旦不管以何种方式终止运行,kubelet都将重启
                                       #OnFailure表示只有Pod以非0退出码退出才重启
                                       #Nerver表示不再重启该Pod
        nodeSelector: obeject  #设置NodeSelector表示将该Pod调度到包含这个label的node上
                               #以key:value的格式指定
        imagePullSecrets:      #Pull镜像时使用的secret名称,以key:secretkey格式指定
        - name: string
        hostNetwork:false      #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
        volumes:               #在该pod上定义共享存储卷列表
        - name: string         #共享存储卷名称 (volumes类型有很多种)
          emptyDir: {}         #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
          hostPath: string     #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
            path: string       #Pod所在宿主机的目录,将被用于同期中mount的目录
          secret:              #类型为secret的存储卷,挂载集群与定义的secre对象到容器内部
            scretname: string  
            items:     
            - key: string
              path: string
          configMap:           #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
            name: string
            items:
            - key: string
    # 一个简单的Pod定义
    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
      labels:
        name: my-pod
        version: v1
    spec:
      containers:
        - name: one
          image: nginx
          ports:
            - containerPort: 80
        - name: two
          image: jcdemo/flaskapp
          ports:
            - containerPort: 5000 

    Pod生命周期

    1. 启动pause容器,每个Pod默认具有,主要是初始化网络和数据卷

    2. pause串行启动初始化容器(initC),只到所有的初始化容器都成功执行

    3. pause并行启动主容器(mainC),启动开始钩子(post start),启动探针(liveness probe,readness probe)

    4. 在主容器结束之前,调用结束钩子(pre stop)

     为什么分离出初始化容器,而不将所有的功能都封装在主容器中?

    • 容器功能越单一越好,越适合调度

    • 权限管理,更加安全。容器只具备需要访问的安全,其他都不应该具有

    • 执行共性操作,如果一个Pod里面包含多个容器,都需要使用同一份代码,那么可以在初始容器里面将代码下载好,然后主容器共用

    探针和钩子

    • livenessProbe:探测容器是否活着

      • httpGet:http请求方式,如果返回的HTTP状态码在200和399之间,则认为程序正常,否则异常

      • exec:命令方式,在用户容器内执行一次命令,如果命令执行的退出码为0,则认为程序正常,否则异常

      • tcpSocket:访问端口方式,如果能够建立成功则认为程序正常,否则异常

    • readnessProbe:探测容器是否准备就绪

      • httpGet:http请求方式,如果返回的HTTP状态码在200和399之间,则认为程序正常,否则异常

      • exec:命令方式,在用户容器内执行一次命令,如果命令执行的退出码为0,则认为程序正常,否则异常

      • tcpSocket:访问端口方式,如果能够建立成功则认为程序正常,否则异常

    • lifecycle

      • postStart 启动后执行

      • preStop 终止前执行

      • 执行方式和探针相同

    • 例子

    apiVersion: v1
    kind: Pod
    metadata:
      name: readiness-httpget-pod
      namespace: default
      labels:
        name: myapp
    spec:
      containers:
      - name: readiness-httpget
        image: ikubernetes/myapp:v1
        ports:
        - name: http
          containerPort: 80
        imagePullPolicy: IfNotPresent
        readinessProbe:
          httpGet:
            port: http
            path: /index.html
          initialDelaySeconds: 1
          periodSeconds: 3
    --- apiVersion: v1 kind: Pod metadata: name: liveness-httpget-pod namespace: default labels: name: myapp spec: containers: - name: livess-httpget image: ikubernetes/myapp:v1 ports: - name: http containerPort: 80 imagePullPolicy: IfNotPresent livenessProbe: httpGet: port: http path: /index.html initialDelaySeconds: 1 periodSeconds: 3
    --- apiVersion: v1 kind: Pod metadata: name: lifecycle-poststart namespace: default labels: name: myapp tier: appfront spec: containers: - name: lifecycle-poststart-pod image: nginx imagePullPolicy: IfNotPresent lifecycle: postStart: exec: command: ["/bin/sh","-c","echo Home+Page >> /usr/share/message"] preStop: exec: command: ["/usr/sbin/nginx","-s","quit"]

    最简单的Pod例子

    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
      labels:
        name: my-pod
    spec:
      containers:
      - name: busybox
        image: busybox:latest

    Deployment的升级和回退

    • 升级:如更新image:kubectl set image mydeploy mynginx=docker.io/nginx:1.15

    • --record=true:记录每次操作的命令,并与history查看

    • 回退:kubectl rollout history deployment mydeploy

    apiVersion: v1
    kind: Deployment
    metadata:
      name: my-deploy
      namespace: default
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: myapp
      template:
        metadata:
          labels:
            app: myapp
        spec:
          containers:
          - name: busybox
            image: busybox:latest

    DaemonSet升级策略

    • 通过.spec.updateStrategy.type指定

    • OnDelete: 该策略表示当更新了DaemonSet的模板后,只有手动删除旧的DaemonSet Pod才会创建新的DaemonSet Pod

    • RollingUpdate: 该策略表示当更新DaemonSet模板后会自动删除旧的DaemonSet Pod并创建新的DaemonSetPod

    • 要使用DaemonSet的滚动升级,需要 .spec.updateStrategy.type设置为RollingUpdate

    apiVersion: v1
    kind: DaemonSet
    metadata:
      name: my-DaemonSet
    spec:
      selector:
        matchLabels:
          name: myapp
      template:
        metadata:
          labels:
            name: myappt
        spec:
          containers:
          - name: busybox
            image: busybox:latest

    Job

    • spec.template格式同Pod

    • RestartPolicy仅支持Never或OnFailure

    • 单个Pod时,默认Pod成功运行后Job即结束

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: pi
    spec:
      backoffLimit: 6   # 最多失败6次
      completions: 1    # 有一个Job成功运行
      parallelism: 1    # 一次性运行pod的个数
      template:
        metadata:
          name: pi
        spec:
          containers:
          - name: pi
            image: perl
            command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
          restartPolicy: Never

    CornJob

    • CornJob通过控制JJob实现功能

    • schedule格式:(与crontab格式相同)

      • *****:从左到右依次是分钟,小时,每个月的第几天,月,星期几

      • 每15分钟:0,15,30,45****

      • 每隔30分钟运行一次,但仅在每月的第一天运行:0,30*1**

      • 每天3-5,17-20每隔30分钟:*/30 [3-5],[17-20] * * *

    apiVersion: batch/v1beta1
    kind: CronJob
    metadata:
      name: hello
    spec:
      schedule: "*/1 * * * *"
      jobTemplate:
        spec:
          template:
            spec:
              containers:
              - name: busybox
                image: busybox:latest
                args:
                - /bin/sh
                - -c
                - date; echo Hello from the Kubernetes cluster
              restartPolicy: OnFailure

    注意:Job和CornJob没有selector,deployment,DaemonSet有selector

    Service

    Service类型

    • ClusterIP:默认方式,仅集群内部可以访问

    • NodePort:service的port映射到集群内每个节点的一个相同端口,外部使用节点IP和端口就可以访问

    • LoadBalancer:使用外部云服务上的负载均衡服务,要交钱。也可以自己搭建一个负载均衡,如下如

    • ExternalName:将service接收到的请求转发到另外的域名(有可能是在集群内部,有可能是在集群外部)

    • 无头服务:也是一种service,只有service名称,没有ClusterIP,可以通过访问名称的方式访问后端Pod,但是没有负载均衡的功能。名称类似:my-service.default.svc.cluster.local.

    • 一个简单的service例子

    apiVersion: v1
    kind: Service
    metadata:
      name: my-nginx
      labels:
        app: nginx
    spec:
      type: ClusterIP
      ports:
        - port: 80
          targetPort: 80
      selector:
        app: my-pod

    Proxy模式

    • userspace模式,缺点kube-proxy的压力很大,已经放弃

    • iptables模式:使用iptables进行路由转发

    • ipvs模式:架构和iptables一样,不同的是ipvs的转发效率更高。需要注意的是:使用ipvs要事先进行配置。否则默认使用iptables模式

    StatefulSet

    • StatefulSet是deployment的变种,具有deployment的基本属性,如保存Pod的数量

    • StatefulSet是Kubernetes提供的管理有状态应用的负载管理控制器API。在Pods管理的基础上,保证Pods的顺序和一致性。与Deployment一样,StatefulSet也是使用容器的Spec来创建Pod,与之不同StatefulSet创建的Pods在生命周期中会保持持久的标记

    • 特点:

      • 具有固定的网络标记(主机名),是不是通过Pod的IP,使用的是无头服务

      • 具有持久化存储,使用pvc实现

      • 需要按顺序部署和扩展,第一个Pod启动完成后,才能启动第二个;如果序号为2的Pod死亡,会重新起一个Pod,名称和原来一样(无头服务通过名称解析IP,保证新起的Pod是第二个Pod)

      • 需要按顺序终止及删除,,删除的顺序和创建时相反,删除时也是上一个Pod删除成功后,才会删除下一个Pod

      • 需要按顺序滚动更新,更新时也是上一个Pod更新成功后,才会更新下一个Pod

    • demo

    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:
      serviceName: "nginx"
      replicas: 2
      selector:
         matchLabels:
           app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: docker.io/nginx
            ports:
            - containerPort: 80
              name: web
            volumeMounts:
            - name: www
              mountPath: /usr/share/nginx/html
      volumeClaimTemplates:
      - metadata:
          name: www
        spec:
          accessModes: ["ReadWriteOnce"]
          volumeMode: Filesystem
          resources:
            requests:
              storage: 50Mi
          storageClassName: local-storage

    Ingress

    Ingress的优势

    • service提供的是4层代理,Ingress提供的是7层代理(根据域名代理)

    • Ingress对外提供统一的IP和端口,减少对外暴露的端口

    • Ingess提供负载均衡

    Ingress的大致流程

    • 创建一个Ingress控制器,可以使用nginx搭建

    • 创建Ingress

    • Ingress控制器会实时监测Ingrss,将Ingress的配置自动添加到Ingress控制器(nginx的配置文件)

    Ingress流程图

    demo(http)

    • 搭建nginx-ingress

    # 直接到官网查看https://kubernetes.github.io/ingress-nginx/
    kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-0.31.1/deploy/static/provider/baremetal/deploy.yaml
    • 搭建私有service

    apiVersion: v1
    kind: Service
    metadata:
      name: test-ingress
      namespace: default
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      selector:
        app: test-ingress
    ---
    apiVersion: apps/v1beta1
    kind: Deployment
    metadata:
      name: test-ingress
    spec:
      replicas: 1
      template:
        metadata:
          labels:
            app: test-ingress
        spec:
          containers:
          - image: nginx:latest
            imagePullPolicy: IfNotPresent
            name: test-nginx
            ports:
            - containerPort: 80
    • 创建ingress,关联nginx-ingress与service

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: test-ingress
      namespace: default
      annotations:
        kubernetes.io/ingress.class: "nginx"
    spec:
      rules:
      - host: feiutest.cn
        http:
          paths:
          - path:
            backend:
              serviceName: test-ingress
              servicePort: 80
    • 测试:使用本地的host文件进行域名解析,然后通过域名访问

    demo(https)

    • 制作自签证书,生成tls.crt ,tls.key文件

    openssl genrsa -out tls.key 2048
    openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=Guangdong/L=Guangzhou/O=devops/CN=feiutest.cn
    • 创建secret

    #创建
    kubectl create secret tls nginx-test --cert=tls.crt --key=tls.key
    #查看
    kubectl get secret
    • 修改ingress

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: test-ingress
      namespace: default
      annotations:
        kubernetes.io/ingress.class: "nginx"
    spec:
      rules:
      - host: feiutest.cn
        http:
          paths:
          - path:
            backend:
              serviceName: test-ingress
              servicePort: 80
      tls:
      - hosts:
        - feiutest.cn
        secretName: nginx-test
    • 测试:使用https访问,注意端口号

    ConfigMap

    创建ConfigMap的方式:

    • 在命令行中指定configmap参数创建,--from-literal

    • 在命令行中将一个配置文件创建为一个ConfigMap--from-file=<文件>

    • 在命令行中将一个目录下的所有配置文件创建为一个ConfigMap,--from-file=<目录>,和指定文件的创建方式相同

    • 写好标准的configmap的yaml文件,然后kubectl create -f创建

    • demo

    kubectl create configmap test-config1 --from-literal = db.host = 10.5.10.116 --from-listeral = db.port = '3306'
    
    # key: db.host   Value: 10.5.10.116
    # key: db.port   value: 3306
    cat app.properties
    property.1 = value-1
    property.2 = value-2
    property.3 = value-3
    
    kubectl create configmap test-config2 --from-file = ./app.properties
    
    # key: property.1   Value: value-1
    # key: property.2   value: value-2
    # key: property.3   Value: value-3
    # configs 目录下的config-1和config-2内容如下
    # key1 =value1
    ###############
    # key2 =value2
    
    kubectl create configmap test-config3 --from-file = ./configs
    
    # key: key1  value: value1
    # key: key2  value: value2
    cat my-configmap.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: my-configmap
      namespace: default
    data:
      special.how: very
      special.type: charm
      
    kubectl create -f my-configmap.yaml
    
    # key: special.how   Value: very
    # key: special.type   value: charm

    使用ConfigMap的方式

    • 通过环境变量的方式,直接传递给pod

    • 通过环境变量的方式,在yaml文件中通过命令使用环境变量,本质上就是通过环境变量的方式

    • 作为volume的方式挂载到pod内,key就是文件名,value就是文件里面的内容,一个key一个文件

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: my-configmap
      namespace: default
    data:
      type: INFO
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
    spec:
      containers:
        - name: busybox
          image: busybox:latest
          command: [ "/bin/sh", "-c", "env" ]
          env:
            - name: SPECIAL_LEVEL_KEY
              valueFrom:
                configMapKeyRef:
                  name: my-configmap
                  key: type
      restartPolicy: Never
    # 环境变量中会有SPECIAL_LEVEL_KEY=INFO
    
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: my-configmap
      namespace: default
    data:
      type: INFO
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
    spec:
      containers:
        - name: busybox
          image: busybox:latest
          command: [ "/bin/sh", "-c", "echo ${SPECIAL_LEVEL_KEY}" ]
          env:
            - name: SPECIAL_LEVEL_KEY
              valueFrom:
                configMapKeyRef:
                  name: my-configmap
                  key: type
      restartPolicy: Never
      
    # 打印 INFO
    
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: my-configmap
      namespace: default
    data:
      type: INFO
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
    spec:
      containers:
        - name: busybox
          image: busybox:latest
          command: [ "/bin/sh", "-c", "cat /etc/config/type" ]
          volumeMounts:     
            - name: config-volume
              mountPath: /etc/config
      volumes:
      - name: config-volume
        configMap:
          name: my-configmap
      restartPolicy: Never
    # 容器的/etc/config/type文件里面的内容是INFO

    Secret

    Secret和ConfigMap的对比

    • Secret和ConfigMap的总体思想类似,都是存储信息到Etcd,不同的是Secret存储的是密文。

    • Secret和ConfigMap都可以通过环境变量和Volume的方式使用

    • Secret的特点

      • Secret可以被ServerAccount关联(使用)

      • Secret可以存储register的鉴权信息,用在ImagePullSecret参数中,用于拉取私有仓库的镜像

      • Secret支持Base64加密

      • Secret分为kubernetes.io/Service Account,kubernetes.io/dockerconfigjson,Opaque三种类型,Configmap不区分类型

    Secret的类型

    • Opaque:base64编码格式的Secret,用来存储密码、密钥等。注意:value必须是base64加密

    # 环境变量方式引用
    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
      name: wordpress-deployment
    spec:
      replicas: 2
      template:
        metadata:
          labels:
            app: wordpress
        spec:
          containers:
          - name: "wordpress"        
            image: "wordpress"
            ports:
            - containerPort: 80        
            env:
            - name: WORDPRESS_DB_USER          
              valueFrom:
                secretKeyRef:
                  name: mysecret
                  key: username
            - name: WORDPRESS_DB_PASSWORD          
              valueFrom:
                secretKeyRef:
                  name: mysecret
                  key: password  
    
    # volume的方式引用
    apiVersion: v1
    kind: Pod
    metadata:
      labels:
        name: db
      name: db
    spec:
      volumes:
      - name: secrets    
        secret:
          secretName: mysecret
      containers:
      - image: gcr.io/my_project_id/pg:v1    
        name: db
        volumeMounts:
        - name: secrets      
          mountPath: "/etc/secrets"
          readOnly: true
        ports:
        - name: cp      
          containerPort: 5432
          hostPort: 5432
    • kubernetes.io/dockerconfigjson:创建用于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_EMAIL 
    
    # pod中是使用registry信息
    apiVersion: v1
    kind: Pod
    metadata:
      name: foo
    spec:
      containers:
        - name: foo
          image: app:v1
      imagePullSecrets:
        - name: myregistrykey
    • kubernetes.io/service-account-token:被serviceaccount引用,serviceaccout创建时Kubernetes会默认创建对应的secret。Pod如果使用了serviceaccount,对应的secret会自动挂载到Pod的/run/secrets/kubernetes.io/serviceaccount目录中

    Volume

    • Vloume是Pod中能够被多个容器共享的磁盘目录

    • 主要用于持久化和同一个pod里面多个容器之间的目录文件共享

    • 分类很多:

      • emptydir:在Pod创建时被创建,初始化为空,同一个Pod里面的同期都可以读写这个路径,当Pod死亡时,emptyDir也被删除,且永久消失

      • hostPath:将node上的路径挂载到Pod中,Pod死亡后,路径里面的文件不会消失

    • demo

    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: {}
    apiVersion: v1
    kind: Pod
    metadata:
      name: test-pd
    spec:
      containers:
      - image: k8s.gcr.io/test-webserver
        name: test-container
        volumeMounts:
        # directory location on conainer
        - mountPath: /test-pd
          name: test-volume
      volumes:
      - name: test-volume
        hostPath:
          # directory location on host
          path: /data
          # this field is optional
          type: Directory

    PV/PVC

    • PV(PersistentVolume):是集群中由管理员配置的一段网络存储。 它是集群中的资源,就像节点是集群资源一样。PV的生命周期不受Pod影响,独立存在。主要的作用是适配后端所有的网络存储,对外提供统一接口。

    • PVC(PersistentVolumeClaim):是由用户进行存储的请求,类似 Pod消耗节点资源,PVC消耗PV资源。

    • PV和PVC一一绑定,PVC匹配满足条件的最小容量PV

    • PV状态:

      • Available – 资源尚未被claim使用

      • Bound – 卷已经被绑定到claim了

      • Released – claim被删除,卷处于释放状态,但未被集群回收。

      • Failed – 卷自动回收失败

    • demo(nfs服务以安装且正常运行)

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: pv001
      labels:
        name: pv001
    spec:
      nfs:
        path: /data/volumes/v1
        server: nfs
      accessModes: ["ReadWriteMany"]
      capacity:
        storage: 2Gi
    ---
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: pv002
      labels:
        name: pv002
    spec:
      nfs:
        path: /data/volumes/v2
        server: nfs
      accessModes: ["ReadWriteMany"]
      capacity:
        storage: 5Gi
    # 后端存储是nfs类型  
    
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: mypvc
      namespace: default
    spec:
      accessModes: ["ReadWriteMany"]
      resources:
        requests:
          storage: 4Gi
    # mypvc会绑定到pv002
    apiVersion: v1
    kind: Pod
    metadata:
      name: test-pod-pv-pvc
      namespace: default
    spec:
      volumes:
      - name: html
        persistentVolumeClaim:
          claimName: mypvc
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
        volumeMounts:
        - name: html
          mountPath: /usr/share/nginx/html/
    # 最后/data/volumes/v2会被挂在到容器mapp中的/usr/share/nginx/html/目录

    节点调度

    • scheduler进行调度主要分为两步:节点筛选和节点打分优先

    • 节点筛选:遍历所有节点,选择满足条件的节点,解决的是“能不能”的问题

    • 节点打分优先:遍历筛选后的节点,按照优先级打分,选择分数最高的节点。解决的是“那个更合适”的问题

    • 调度的简单过程如下所示

    • 节点筛选的规则

      • NoVolumeZoneConflict:检查给定的zone限制前提下,检查如果在此主机上部署Pod是否存在卷冲突

      • PodFitsResources:检查节点是否有足够资源(例如 CPU、内存与GPU等)满足一个Pod的运行需求

      • PodFitsHostPorts:检查Pod容器所需的HostPort是否已被节点上其它容器或服务占用

      • HostName:检查节点是否满足PodSpec的NodeName字段中指定节点主机名,不满足节点的全部会被过滤掉

      • MatchNodeSelector:检查节点标签(label)是否匹配Pod的nodeSelector属性要求

      • PodToleratesNodeTaints : 根据 taints 和 toleration 的关系判断Pod是否可以调度到节点上,Pod是否满足节点容忍的一些条件

      • MatchInterPodAffinity : 节点亲和性筛选

      • GeneralPredicates:包含一些基本的筛选规则

    • 节点打分优先

      • LeastRequestedPriority:节点的优先级由节点空闲资源与节点总容量的比值,即由(总容量-节点上Pod的容量总和-新Pod的容量)/总容量)来决定

      • BalancedResourceAllocation:CPU和内存使用率越接近的节点权重越高,该策略不能单独使用,必须和LeastRequestedPriority组合使用,尽量选择在部署Pod后各项资源更均衡的机器

      • InterPodAffinityPriority:通过迭代 weightedPodAffinityTerm 的元素计算和,并且如果对该节点满足相应的PodAffinityTerm,则将 “weight” 加到和中,具有最高和的节点是最优选的

      • SelectorSpreadPriority:为了更好的容灾,对同属于一个service、replication controller或者replica的多个Pod副本,尽量调度到多个不同的节点上

      • NodeAffinityPriority:节点亲和性机制

      • NodePreferAvoidPodsPriority(权重1W)

      • TaintTolerationPriority : 使用 Pod 中 tolerationList 与 节点 Taint 进行匹配,配对成功的项越多,则得分越低

    亲和性

    • 亲和性是Pod靠近节点

    • 节点亲和性:Pod优先调度到具有亲和性的节点上运行

      • nodeSelector:节点满足label要求才能得到调度,简单粗暴

    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx
      labels:
        env: test
    spec:
      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
      nodeSelector: # 选择具有disktype: ssd标签的节点
        disktype: ssd
    # 给节点添加label
    # kubectl node label <node-name> <label-key>=<label-value>
    
    # 查看节点label
    # kubectl get nodes --show-labels
    
    # 删除节点label
    # kubectl label node <node-name> label-key-
      • 亲和性支持的operator:In, NotIn, Exists, DoesNotExist, Gt, Lt

      • requiredDuringSchedulingIgnoredDuringExecution:硬条件,节点满足条件就可以得到调度,不满足条件就调度

      • preferredDuringSchedulingIgnoredDuringExecution:软条件,尽量在满足条件的节点上调度,如果没有满足条件的节点也可以得到调度

    apiVersion: v1
    kind: Pod
    metadata:
      name: with-node-affinity
    spec:
      affinity:
        nodeAffinity:
          # 硬条件:节点必须包含kubernetes.io/e2e-az-name=e2e-az1的label才符合条件
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: kubernetes.io/e2e-az-name
                operator: In
                values:
                - e2e-az1
          # 软条件:节点尽量包含another-node-label-key=another-node-label-value的label,
          #        不包含也可以调度
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            preference:
              matchExpressions:
              - key: another-node-label-key
                operator: In
                values:
                - another-node-label-value
      containers:
      - name: with-node-affinity
        image: k8s.gcr.io/pause:2.0
    • Pod亲和性:Pod之间的相互靠近和排斥

      • 具有亲和性的Pod被调度到同一节点域上运行,一个节点域包含多个节点,通过节点标签和topologyKey指定

      • 具有反亲和性的Pod会被调度到不同的节点域上运行

      • Pod的亲和性和反亲和性都具有硬条件和软条件

      • preferredDuringSchedulingIgnoredDuringExecution:硬条件

      • requiredDuringSchedulingIgnoredDuringExecution:软条件

    apiVersion: apps/v1beta1
    kind: Deployment
    metadata:
      name: affinity
      labels:
        app: affinity
    spec:
      replicas: 3
      revisionHistoryLimit: 15
      template:
        metadata:
          labels:
            app: affinity
            role: test
        spec:
          containers:
          - name: nginx
            image: nginx:1.7.9
            ports:
            - containerPort: 80
              name: nginxweb
          affinity:
            podAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:  # 硬策略
              - labelSelector:
                  matchExpressions:
                  - key: app
                    operator: In
                    values:
                    - busybox-pod
                topologyKey: kubernetes.io/hostname
    # 上面这个例子中的pod需要调度到某个指定的主机上,且这个节点上运行了这样的pod:这个pod有一个
    # app=busybox-pod的label   

    污点和容忍

    • 污点和容忍是将Pod驱离节点,与亲和性相反

    • 打上污点的节点,如果Pod没有容忍这个污点的能力,那么Pod就不会被调度到这个节点上;只有具备容忍这个污点能力的Pod才会被调度到这个节点上

    • master节点上默认具有node-role.kubernetes.io/master:NoSchedule污点,所以Pod默认不会调度到master上

    • 增加污点,删除污点,查看污点

    # 查看节点具有的污点
    kubectl describe node nodeName
    
    # 删除节点的污点
    kubectl taint nodes nodeName key=value:NoSchedule
    
    # 删除节点的污点
    kubectl taint nodes nodeName key-
    • 污点驱离Pod的方式

      • NoSchedule:不要调度到这个节点上

      • PreferNoSchedule:尽量不调度到污点节点上

      • NoExecute:不要调度到这个节点上,且会立即驱离已经运行在这个节点上的Pod

    • 污点和容忍的匹配规则

      • 对tolerations属性的写法,其中pod的 key、value、effect 与Nod 的Taint设置需保持一致

      • 如果operator的值是Exists则value属性可省略

      • 如果operator的值是Equa,则表示其key与value之间的关系是equal(等于)

      • 如果不指定 operator 属性,则默认值为 Equal

    • demo

    apiVersion: apps/v1beta1
    kind: Deployment
    metadata:
      name: taint
      labels:
        app: taint
    spec:
      replicas: 3
      revisionHistoryLimit: 10
      template:
        metadata:
          labels:
            app: taint
        spec:
          containers:
          - name: nginx
            image: nginx:1.7.9
            ports:
            - name: http
              containerPort: 80
          tolerations:
          - key: "node-role.kubernetes.io/master"
            operator: "Exists"
            effect: "NoSchedule"
    # 该Pod可以被调度到matser上  

    接入管理---前言

    API Server作为Kubernetes网关,是访问和管理资源对象的唯一入口,其各种集群组件访问资源都需要经过网关才能进行正常访问和管理。每一次的访问请求都需要进行合法性的检验,其中包括认证,授权以及准入等,需要通过一系列验证之后,才能访问或者存储数据到etcd当中。如下图所示。

    接入管理---认证

    • 认证的主要作用是识别需要接入的对端身份,也就是解决“你是谁”的问题

    • ControllerManager、Scheduler与ApiServer进行通信,直接走127.0.0.1进行通信,因为都在同一台服务器上

    • kubelet和kube-peoxy与ApiServer进行通信,需要双向验证

    • Pod与ApiServer进行通信,通过ServiceAccount进行通信。 当创建Pod的时候,如果没有指定一个service account,系统会自动在与该Pod相同的namespace下为其指派一个default service account。

    接入管理---鉴权

    • 鉴权的主要作用是识别接入对端的权限,也就是解决“你能干什么”的问题

    • kubernetes中鉴权使用的是RBAC(Role-Based Access Control),基于角色的访问控制,通过自定义角色并将角色和特定的 user,group,serviceaccounts 关联起来已达到权限控制的目的。

    • Role:角色,它其实是一组规则,定义了一组对 Kubernetes API 对象的操作权限

    • Subject:被作用者,包括 user,group,serviceaccounts,通俗来讲就是认证机制中所识别的用户

    • RoleBinding:定义了“被作用者”和“角色”的绑定关系,也就是将用户以及操作权限进行绑定

    • ClusterRole:集群角色,可以包含多个namespace

    • ClusterRoleBinding:一次绑定多个namespace

    • ClusterRole既可以被ClusterRoleBinding绑定,也可以被RoleBinding绑定,灵活处理即可

    接入管理---准入控制

    准入控制是请求的最后一个步骤,准入控制有许多内置的模块,可以作用于对象的 “CREATE”、“UPDATE”、“DELETE”、“CONNECT” 四个阶段。在这一过程中,如果任一准入控制模块拒绝,那么请求立刻被拒绝。一旦请求通过所有的准入控制器后就会写入对象存储中。准入控制的配置是有序的,不同的顺序会影响 Kubernetes 的性能,建议使用官方的配置。

    Helm3安装和使用

    • 安装

    # 1. 下载
    wget https://github.com/helm/helm/releases
    ​
    # 2. 解压
    tar -zxvf helm-v3.0.0-linux-amd64.tgz
    ​
    # 3. 解压后的目录中找到二进制文件,然后将其移至所需的目标位置
    mv linux-amd64/helm /usr/local/bin/helm
    ​
    # 4. 验证
    helm help
    • 自定义chart

    # 创建文件和目录
    # test/Chart.yaml test/values.yaml /test/templates/nginx.yaml
    ​
    # cat test/Chart.yaml
    apiVersion: v1  # 当前helm api版本,不需要修改
    appVersion: 1.0.0  # 此处为你应用程序的版本号 [*]
    description: Chart for the nginx server  # 介绍此chart是干嘛的,按需求修改
    name: example-chart  # 模板名,对应目录名 [*]
    version: 1.0.0  # 此chart版本号 [*]
    maintainers:  # 维护人员列表 [*]
    - email: xxx
      name: yyy
      
    # cat test/values.yaml
    version: "1.0"
    ​
    # cat /test/templates/nginx.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx
      labels:
        name: myapp
    spec:
      containers:
      - name: nginx
        image: nginx:{{.Values.version}} # 引用value中的配置
        ports:
        - name: http
          containerPort: 80
        imagePullPolicy: IfNotPresent

    资源限制

    • 资源限制主要是限制CPU和内存

    • pod级别:在Pod级别对资源进行限制

    • 名称空间级别:在名称空间级别对资源进行限制

    日志查看EFK

    • kubernetes中日志管理系统,主要是收集、存储、查看kubernetes中所有节点的所有日志

    • ELK也是日志管理系统,但是ELK很“重”,EFK是ELK的变种,但是很“轻”

    • EFK不是一个软件,而是一套解决方案,并且都是开源软件,之间互相配合使用,完美衔接,高效的满足了很多场合的应用,是目前主流的一种日志系统。EFK是三个开源软件的缩写,分别表示:Elasticsearch , FileBeat, Kibana , 其中ELasticsearch负责日志保存和搜索,FileBeat负责收集日志,Kibana 负责界面,当然EFK和大名鼎鼎的ELK只有一个区别,那就是EFK把ELK的Logstash替换成了FileBeat,因为Filebeat相对于Logstash来说有2个好处:

      • 侵入低,无需修改程序目前任何代码和配置

      • 相对于Logstash来说性能高,Logstash对于IO占用很大

    • EFK的架构如下所示

    修改证书时间

    • 原因:以kubeadmin安装的kubernetes集群,证书的有效时间是1年,超过一年就无法使用

    • 查看有效时间

    cd /etc/kubernetes/pki
    openssl x509 -in apiserver.crt -text -noout
    ---
    Validity
                Not Before: Apr  2 02:42:39 2020 GMT
                Not After : Apr  2 02:42:39 2021 GMT
    ---
    apiserver 只有一年的默认时间使用期限
    ​
    -------------
    • go环境部署

    wget https://dl.google.com/go/go1.12.7.linux-amd64.tar.gz
    tar -zxvf go1.12.1.linux-amd64.tar.gz -C /usr/local
    ​
    vim /etc/profile
    ---
    export PATH=$PATH:/usr/local/go/bin
    ---
    source /etc/profile
    • 下载源码

    git clone https://github.com/kubernetes/kubernetes.git
    ​
    git checkout -b remotes/origin/release-1.15.1 v1.15.1
    • 修改kubeadmin源码

    vim staging/src/k8s.io/client-go/util/cert/cert.go # kubeadm 1.14 版本之前
    ​
    vim cmd/kubeadm/app/util/pkiutil/pki_helpers.go # kubeadm 1.14 至今
    ​
    ----
    const duration3650d = time.Hour * 24 * 365 * 10
    NotAfter: time.Now().Add(duration365d).UTC(),
    ​
    ----
    make WHAT=cmd/kubeadm GOFLAGS=-v
    cp _output/bin/kubeadm /root/kubeadm-new
    ​
    ----
    cp -p /usr/bin/kubeadmn /usr/bin/kubeadmn.old
    cp -p /root/kubeadm-new /usr/bin/kubeadm
    ​
    chmod +x /usr/bin/kubeadmn
    ​
    ----
    cd /etc/kubernetes/
    ​
    cp -ap pki pki.old
    ​
    ----
    cd /root/k8s-install/core
    ​
    kubeadm alpha certs renew all --config=./kubeadm-config.yaml
    • 验证是否修改成功

    openssl x509 -in apiserver.crt -text -noout
  • 相关阅读:
    shared pointer
    realsense数据分析
    cmake log
    Qt自定义类添加qvector报错
    Java csv
    opencv C++ mask_rcnn
    realsense data
    Test
    ubuntu18 bluebooth
    LSTM_Model
  • 原文地址:https://www.cnblogs.com/chusiyong/p/12841411.html
Copyright © 2011-2022 走看看