• Kubernetes快速入门


    二、Kubernetes快速入门

    (1)Kubernetes集群的部署方法及部署要点

     

    (2)部署Kubernetes分布式集群

     

    (3)kubectl使用基础

    1、简介

    kubectl就是API service的客户端程序,通过连接master节点上的API service实现k8s对象、资源的增删改查操作。

    对象:node、pod、service、controller(replicaset,deployment,statefulet,daemonset,job,cronjob)

    2、子命令

    分类

    #基本命令

    Basic Commands (Beginner:初级):
    create :Create a resource from a file or from stdin.
    expose :Take a replication controller, service, deployment or pod and expose it as a new Kubernetes Service
    run :Run a particular image on the cluster
    set :Set specific features on objects

     

    Basic Commands (Intermediate:中级):
    explain :Documentation of resources
    get :Display one or many resources
    edit :Edit a resource on the server
    delete :Delete resources by filenames, stdin, resources and names, or by resources and label selector

     

    Deploy Commands(部署命令):
    rollout :Manage the rollout of a resource #回滚
    scale :Set a new size for a Deployment, ReplicaSet, Replication Controller, or Job #手动改变应用程序的规模
    autoscale :Auto-scale a Deployment, ReplicaSet, or ReplicationController #自动改变

     

    Cluster Management Commands(集群管理命令):
    certificate :Modify certificate resources. #证书
    cluster-info :Display cluster info #集群信息
    top :Display Resource (CPU/Memory/Storage) usage.
    cordon :Mark node as unschedulable #标记节点不可被调用
    uncordon :Mark node as schedulable
    drain :Drain node in preparation for maintenance #排干节点
    taint :Update the taints on one or more nodes #给节点增加污点

     

    Troubleshooting and Debugging Commands(故障排除和调试命令):
    describe :Show details of a specific resource or group of resources #描述资源的详细信息
    logs :Print the logs for a container in a pod
    attach :Attach to a running container
    exec :Execute a command in a container
    port-forward :Forward one or more local ports to a pod #端口转发
    proxy :Run a proxy to the Kubernetes API server
    cp :Copy files and directories to and from containers.
    auth :Inspect authorization

     

    Advanced Commands(高级命令):
    apply :Apply a configuration to a resource by filename or stdin
    patch :Update field(s) of a resource using strategic merge patch
    replace :Replace a resource by filename or stdin
    wait :Experimental: Wait for a specific condition on one or many resources.
    convert :Convert config files between different API versions

     

    Settings Commands(设置命令):
    label :Update the labels on a resource #标签,有长度限制
    annotate :Update the annotations on a resource #注解
    completion :Output shell completion code for the specified shell (bash or zsh) #命令补全

     

    Other Commands:
    alpha :Commands for features in alpha
    api-resources :Print the supported API resources on the server
    api-versions :Print the supported API versions on the server, in the form of "group/version"
    config :Modify kubeconfig files
    plugin :Provides utilities for interacting with plugins.
    version :Print the client and server version information

     

    Usage:
    kubectl [flags] [options]

    3、创建Pod

    创建一个控制器名为nginx-deploy,镜像版本为nginx:1.14-alpine的Pod,暴露端口80,副本为1

    [root@master ~]# kubectl run nginx-deploy --image=nginx:1.14-alpine --port=80 --replicas=1

    如下图,此时可以看出创建成功了,而且在node02节点上,网段是10.244.2.0/24,而node01节点的网段是10.244.1.0/24。

    可通过node01节点进行访问试试,而10.244.2.2是pod地址,只能在k8s集群中内部才能访问。

    Pod的客户端有两类:其他Pod和集群外的客户端。

    现在我们把nginx-deploy-5b595999-2q6j5删除,然后控制器会自动创建一个新的Pod,如下图:

     

    而此时Pod的ip为10.244.1.2,因此需要给Pod一个固定端点来进行访问,而这个固定端点是有servcie创建的

    service的类型有:ClusterIP、NodePort、LoadBalancer、ExternalName。默认是ClusterIP,意思是这个service只有一个service IP,只能在集群内被各Pod客户端访问,而不能被集群外部的客户端访问。

    创建service命令:kubectl expose deployment(控制器类型)nginx-deploy(控制器名称) --name 服务名 --port=service端口 --target-port=Pod的端口(即容器端口)

    这样就可以通过固定的service的IP(10.98.39.54)来访问nginx了

    不仅可以通过访问service的ip来访问Pod,也可以通过service的服务名来访问,前提是Pod客户端需要能解析这个服务名,解析时需要依赖Core-dns服务。而物理机上的解析文件/etc/resolv.conf中的解析的IP不是Core-dns,可以通过master节点查看,命令为:kubectl get pods -n kube-system -o wide。如下图:

    而coredns也有服务名,叫kube-dns,如下图:

    如果从master节点上创建一个Pod客户端来访问其他Pod,它的dns服务直接指定到kube-dns的IP上。

    因此在各个Pod客户端之外解析的时候要加上搜索域,例如,在clinet这个Pod之外的master节点上解析就需要加上搜索域:

    此时可以将这个nginx的Pod删除,当控制器再次自动创建时,Pod的ip已经变为10.244.1.3,然后再次访问servic的ip和服务名都可以访问得到。

    通过service的ip和服务名访问Pod,不管Pod是如何变化,它都是根据service的标签选择器来判断的

    如何验证,我们可以在master节点查看各Pod的标签选择器

     

    同理,service的ip也动态生成的,当你删除service,再创建相同的service的话,ip已经是另外一个。

    同理,Pod是根据标签选择器归为一类,而控制器,例如deployment也是根据标签选择器归为一类。

    4、集群外部访问Pod

    修改service中spec的type即可,将其改为NodePort

    此时就可以在集群外部,通过节点ip:30020来访问Pod了。

    (4)命令式应用部署、扩缩容、服务暴露

    1、扩、缩容Pod

    创建一类名为myapp的Pod,副本为2个,可以kubectl get deployment -w进行实时监控创建情况

     

    同时也创建一个service,服务名为myapp

    通过Pod客户端来访问进行验证,访问服务名myapp是可以看到Hell MyApp,然后也可以访问hostname.html查看Pod名称

    通过循环语句来验证是随机访问这两个Pod的

    在副本为2的基础上,进行扩容为5个

    2、升级Pod

    kubectl set image 控制器名称 Pod名 容器名=镜像:版本

    注:容器名可以指多个,是指Pod内中的各层容器

    将myapp版本更新为v2

    kubectl set image deployment myapp myapp=ikubernetes/myapp:v2

    通过rollout进行查看更新状态

     

    3、回滚

    三、资源配置清单及Pod资源

    (1)Kubernetes API中的资源配置格式

     Restful定义:representational state transfer(表象性状态转变)或者表述性状态转移,详解见:https://blog.csdn.net/hzy38324/article/details/78360525?utm_source=gold_browser_extension

    Restful中的状态get、put、delete、post通过kubectl run,get,edit等命令展现出来

    (2)资源类型、API群组及其版本介绍

    1、资源类型

    k8s中所有内容抽象为资源,资源实例化后称为对象。

    workload(工作负载):Pod,ReplicaSet,Deployment,StatefulSet,DaemonSet,Job,Cronjob等

    服务发现及均衡:Service,Ingress等

    配置与存储:Volume,CSI等

      ConfigMap,Secret

      DownwardAPI

    集群级资源:Namespace,Node,Role,ClusterRole,RoleBinding,ClusterRoleBinding

    元数据型资源:HPA,PodTemplate,LimitRange  

    (3)Pod资源及其配置格式

    1、yaml格式

     

    # yaml格式的pod定义文件完整内容:
    apiVersion: v1        #必选,api版本号(或者组名+版本号:group/version。而group省略,则表示core(核心组)的意思),例如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
              path: string     

    (4)使用配置清单创建自主式Pod资源

    创建资源的方法:

      apiserver仅接收JSON格式的资源定义;

      yaml格式提供配置清单,apiserver可自动将其转为json格式,而后再提交;

    命令:kubectl api-versions可以查看所有API 群组/版本

    其中Pod是最核心资源因此属于核心组即v1,像控制器属于应用程序管理核心资源因此他们是apps组,即apps/v1。

    大部分资源的配置清单格式都由5个一级字段组成:

    apiVersion:api版本号

    kind:资源类别

    metadata:元数据

    name:同一类别下的name是唯一的
            namespace:对应的对象属于哪个名称空间
            labels:标签,每一个资源都可以有标签,标签是一种键值数据
            annotations:资源注解
            
            每个的资源引用方式(selflink):
                /api/GROUP/VERSION/namespace/NAMESPACE/TYPE/NAME

    spec:用户定义一个资源对象应该所处的目标状态,也叫期望状态(可自定义)(disired state)

    status:显示资源的当前状态(只读),本字段由kubernetes进行维护(current state)

     

     K8s存在内嵌的文档格式说明,可以使用kubectl explain 进行查看,如查看Pod这个资源需要怎么定义:

    [root@k8s-master ~]# kubectl explain pods
    KIND:     Pod
    VERSION:  v1
    
    DESCRIPTION:
         Pod is a collection of containers that can run on a host. This resource is
         created by clients and scheduled onto hosts.
    
    FIELDS:
       apiVersion    <string>
         APIVersion defines the versioned schema of this representation of an
         object. Servers should convert recognized schemas to the latest internal
         value, and may reject unrecognized values. More info:
         https://git.k8s.io/community/contributors/devel/api-conventions.md#resources
    
       kind    <string>
         Kind is a string value representing the REST resource this object
         represents. Servers may infer this from the endpoint the client submits
         requests to. Cannot be updated. In CamelCase. More info:
         https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
    
       metadata    <Object>
         Standard object's metadata. More info:
         https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
    
       spec    <Object>
         Specification of the desired behavior of the pod. More info:
         https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
    
       status    <Object>
         Most recently observed status of the pod. This data may not be up to date.
         Populated by the system. Read-only. More info:
         https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status

    从上面可以看到apiVersion,kind等定义的键值都是<string>,而metadata和spec看到是一个<Object>,当看到存在<Object>的提示,说明该字段可以存在多个二级字段,那么可以使用如下命令继续查看二级字段的定义方式:

    [root@k8s-master ~]# kubectl explain pods.metadata
    [root@k8s-master ~]# kubectl explain pods.spec

    二级字段下,每一种字段都有对应的键值类型,常用类型大致如下:

    <[]string>:表示是一个字串列表,也就是字符串类型的数组

      例如:command字段

      

    <Object>:表示是可以嵌套的字段

      例如:像上图图中的spec下嵌套containers字段

    <map[string]string>:表示是一个由键值组成映射

    <[]Object>:表示是一个对象列表

      例如:上图图中的containers字段下的name列表,只是标明image这个镜像名称

         -name:myapp(标明ikubernetes/myapp:v1简称为myapp)

         -name:busybox

    <[]Object> -required-:required表示该字段是一个必选的字段

    使用配置清单创建自主式Pod资源 

    [root@k8s-master ~]# mkdir manifests
    [root@k8s-master ~]# cd manifests
    [root@k8s-master manifests]# vim pod-demo.yaml
    apiVersion: v1 kind: Pod metadata: name: pod-demo namespace: default labels: app: myapp tier: frontend spec: containers: - name: myapp image: ikubernetes/myapp:v1 - name: busybox image: busybox:latest command: - "/bin/sh" - "-c" - "sleep 3600" [root@k8s-master manifests]# kubectl create -f pod-demo.yaml
    [root@k8s-master manifests]# kubectl get pods
    [root@k8s-master manifests]# kubectl describe pods pod-demo  #获取pod详细信息
    [root@k8s-master manifests]# kubectl logs pod-demo myapp #kubectl logs pod名称 容器名称 可以具体查看某个pod中某个容器的日志
    [root@k8s-master manifests]# kubectl exec -it pod-demo -c myapp -- /bin/sh
    [root@k8s-master manifests]# kubectl delete -f xxxxx.yaml   #删除这个yaml文件创建的资源
    使用yaml清单创建资源,可以创建裸控制器Pod,无控制器管理,一删除就没有了。

    事实上使用kubectl命令管理资源有三种用法:

    • 命令式用法;
    • 命令式资源清单用法;
    • 声明式资源清单。使用声明式资源清单,可以确保资源尽可能的向我们声明的状态改变,而且可以随时改变声明,并随时应用。

    Pod资源下spec的containers必需字段解析

    自主式Pod资源(不受控制器控制)

    [root@k8s-master ~]# kubectl explain pods.spec.containers
    
    name    <string> -required-    #containers 的名字
    image    <string>  #镜像地址
    imagePullPolicy    <string>  #如果标签是latest,默认就是Always(总是下载镜像)  IfNotPresent(先看本地是否有此镜像,如果没有就下载) Never (就是使用本地镜像,如果没有就从不下载)
                     #这个字段是不允许被更改的
    ports    <[]Object>  #是个对象列表;可以暴露多个端口;可以对每个端口的属性定义 例如:(名称(可后期调用)、端口号、协议、暴露在的地址上) 暴露端口只是提供额外信息的,不能限制系统是否真的暴露
    
       - containerPort 容器端口
    
         hostIP  节点地址(基本不会使用)
    
         hostPort 节点端口
    
         name 名称
    
         protocol  (默认是TCP)
    #修改镜像中的默认应用
    args  <[]string>   传递参数给command 相当于docker中的CMD
    
    command    <[]string> 相当于docker中的ENTRYPOINT;如果不提供命令,就运行镜像中的ENTRYPOINT。

    官方文档对于command和args有个详细的介绍:

    https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/

    DescriptionDocker field nameKubernetes field name
    The command run by the container Entrypoint command
    The arguments passed to the command Cmd args

    表示docker中的entrypoint、cmd分别相当于kubernetes中的command和args。

    如果Pod不提供commandargs使用Container,则使用Docker镜像中的cmd或者ENTRYPOINT。

    如果Pod提供command但不提供args,则仅使用提供 command的。将忽略Docker镜像中定义EntryPoint和Cmd。

    如果Pod中仅提供args,则args将作为参数提供给Docker镜像中EntryPoint。

    如果提供了commandargs,则Docker镜像中的ENTRYPOINT和CMD都将不会生效,Pod中的args将作为参数给command运行

    (5)标签及标签选择器

    标签既可以在对象创建时指定,也可以在创建之后使用命令来管理

    1、标签

    key=value

    • key:只能使用字母、数字 、_ 、- 、. (只能以字母数字开头,不能超过63给字符)
    • value: 可以为空,只能使用字母、数字开头及结尾,中间可以使用字母、数字 、_ 、- 、.(不能超过63给字符)
    [root@k8s-master manifests]# kubectl get pods --show-labels  #查看所有资源的pod标签
    NAME READY STATUS RESTARTS AGE LABELS pod-demo 2/2 Running 0 25s app=myapp,tier=frontend [root@k8s-master manifests]# kubectl get pods -l app  #只显示包含app的标签
    NAME READY STATUS RESTARTS AGE pod-demo 2/2 Running 0 1m [root@k8s-master manifests]# kubectl get pods -L app #显示app字段的标签值的pod的资源
    NAME READY STATUS RESTARTS AGE APP pod-demo 2/2 Running 0 1m myapp [root@k8s-master manifests]# kubectl label pods pod-demo release=canary  #给pod-demo打上标签
    pod/pod-demo labeled [root@k8s-master manifests]# kubectl get pods -l app --show-labels
    NAME READY STATUS RESTARTS AGE LABELS pod-demo 2/2 Running 0 1m app=myapp,release=canary,tier=frontend [root@k8s-master manifests]# kubectl label pods pod-demo release=stable --overwrite  #修改标签
    pod/pod-demo labeled [root@k8s-master manifests]# kubectl get pods -l release
    NAME READY STATUS RESTARTS AGE pod-demo 2/2 Running 0 2m [root@k8s-master manifests]# kubectl get pods -l release,app
    NAME READY STATUS RESTARTS AGE pod-demo 2/2 Running 0 2m

    2、标签选择器类别

    • 等值关系标签选择器:=, == , !=  (kubectl get pods -l app=test,app=dev)
    • 集合关系标签选择器: KEY in (value1,value2,value3);KEY notin (value1,value2,value3); !KEY (例如:kubectl get pods -l "app in (test,dev)")

    许多资源支持内嵌字段定义其使用的标签选择器

    • matchLabels: 直接给定键值
    • matchExpressions: 基于给定的表达式来定义使用标签选择器,{key:"KEY",operator:"OPERATOR",values:[V1,V2,....]}
      • 操作符(即OPERATOR):in、notin(Values字段的值必须为非空列表)、Exists、NotExists(Values字段的值必须为空列表)

    (6)Pod的节点选择器

    
    
    [root@k8s-master manifests]# kubectl get nodes --show-labels #查看node节点的标签
    如上图beta.kubernetes.io是标签前缀,标签前缀必须是DNS名称,DNS域名或者子域名,最长长度不能超过254个字符
    [root@k8s-master
    manifests]# kubectl explain pod.spec
       nodeName    <string> #直接指定node节点名称
         NodeName is a request to schedule this pod onto a specific node. If it is
         non-empty, the scheduler simply schedules this pod onto that node, assuming
         that it fits resource requirements.
    
       nodeSelector    <map[string]string>
         NodeSelector is a selector which must be true for the pod to fit on a node.
         Selector which must match a node's labels for the pod to be scheduled on
         that node. More info:
         https://kubernetes.io/docs/concepts/configuration/assign-pod-node/

     nodeSelector可以限定pod创建或者运行在哪个或哪类节点上,举个例子,给节点k8s-node01打上标签disktype=ssd,让pod-demo指定创建在k8s-node01上

    (1)给k8s-node01节点打标签
    [root@k8s-master manifests]# kubectl label nodes k8s-node01 disktype=ssd
    node/k8s-node01 labeled [root@k8s-master manifests]# kubectl get nodes --show-labels
    NAME STATUS ROLES AGE VERSION LABELS k8s-master Ready master 10d v1.11.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=k8s-master,node-role.kubernetes.io/master= k8s-node01 Ready
    <none> 10d v1.11.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/hostname=k8s-node01 k8s-node02 Ready <none> 9d v1.11.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=k8s-node02 (2)修改yaml文件,增加标签选择器 [root@k8s-master manifests]# cat pod-demo.yaml
    apiVersion: v1 kind: Pod metadata: name: pod-demo namespace: default labels: app: myapp tier: frontend spec: containers: - name: myapp image: ikubernetes/myapp:v1 - name: busybox image: busybox:latest command: - "/bin/sh" - "-c" - "sleep 3600" nodeSeletor: disktype: ssd (3)重新创建pod-demo,可以看到固定调度在k8s-node01节点上 [root@k8s-master manifests]# kubectl delete -f pod-demo.yaml
    pod "pod-demo" deleted [root@k8s-master manifests]# kubectl create -f pod-demo.yaml
    pod/pod-demo created [root@k8s-master mainfests]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE pod-demo 2/2 Running 0 20s 10.244.1.13 k8s-node01 [root@k8s-master manifests]# kubectl describe pod pod-demo
    ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 42s default-scheduler Successfully assigned default/pod-demo to k8s-node01 ......

     

    annotations:

     

      与label不同的地方在于,annotations不能用于挑选资源对象,仅用于为对象提供"元数据",没有键值长度限制。在声明式配置构建大型镜像相关信息时,通常都会添加annotations,用来标记对应的资源对象的元数据或者属性信息,同样想查看annotations的信息可以使用kubectl describe pod pod-demo

     

    (7)容器存活状态探测及就绪状态探测

    1、Pod生命周期

    在pod生命周期中需要经历以下几个阶段。主容器(main container)在运行前需要做一些环境设定,因此在启动之前可以运行另一个容器,为主容器做一些环境初始化,这类容器被称为init容器(init container)。初始化容器可以有多个,他们是串行执行的,执行完成后就退出了。在主容器刚刚启动之后,可以嵌入一个post start命令执行一些操作,在主容器结束前也可以指定一个 pre stop命令执行一些操作,作为开场的预设,结束时的清理。在整个主容器执行过程中,还可以做两类对Pod的检测 liveness probe 和 readness probe。如下图:

    Kubelet 可以选择是否执行在容器上运行的两种探针执行和做出反应:

    • livenessProbe:存活状态检测。指容器是否正在运行。如果存活探测失败,则 kubelet 会杀死容器,并且容器将受到其 重启策略 的影响。如果容器不提供存活探针,则默认状态为 Success
    • readinessProbe:就绪状态检测。指容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与 Pod 匹配的所有 Service 的端点中删除该 Pod 的 IP 地址。初始延迟之前的就绪状态默认为 Failure。如果容器不提供就绪探针,则默认状态为 Success

    2、常见的Pod状态

    Pod 的 status 在信息保存在 PodStatus 中定义,其中有一个 phase 字段。

    Pod 的相位(phase)是 Pod 在其生命周期中的简单宏观概述。该阶段并不是对容器或 Pod 的综合汇总,也不是为了做为综合状态机。

    Pod 相位的数量和含义是严格指定的。除了本文档中列举的状态外,不应该再假定 Pod 有其他的 phase值。

    下面是 phase 可能的值:

    • 挂起(Pending):Pod 已被 Kubernetes 系统接受,但有一个或者多个容器镜像尚未创建。等待时间包括调度 Pod 的时间和通过网络下载镜像的时间,这可能需要花点时间。
    • 运行中(Running):该 Pod 已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态。
    • 成功(Succeeded):Pod 中的所有容器都被成功终止,并且不会再重启。
    • 失败(Failed):Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。
    • 未知(Unknown):因为某些原因无法取得 Pod 的状态,通常是因为与 Pod 所在主机通信失败。

    下图是Pod的生命周期示意图,从图中可以看到Pod状态的变化。

    3、总结

    Pod生命周期中的重要行为

      1、初始化容器

      2、容器探测:livenessProbe和readinessProbe

        livenessProbe:存活状态检测(判定主容器是否处于运行状态)

        readinessProbe:就绪状态检测(判定容器中的主进程,是否已经准备就绪并可以对外提供服务)

      #kubernetes把容器探测分为这两种形式,而docker只需探测第一种,如果容器不存活,这个docker就结束了;相对于kubernetes而言,一个Pod里可以存在多个容器。

    容器探测的三种行为:

    • ExecAction:在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
    • TCPSocketAction:对指定端口上的容器的 IP 地址进行 TCP 检查。如果端口打开,则诊断被认为是成功的。
    • HTTPGetAction:对指定的端口和路径上的容器的 IP 地址执行 HTTP Get 请求。如果响应的状态码大于等于200 且小于 400,则诊断被认为是成功的。

    容器重启策略

    [root@k8s-master manifests]# kubectl explain pod.spec

      Spec 中有一个 restartPolicy 字段,可能的值为 Always、OnFailure 和 Never。默认为 Always。

        Always:一旦Pod中的容器挂了,总是重启

        OnFailure:状态错误时才重启,正常关掉不重启

        Never: 状态错误和正常关掉也从不重启

      其中默认值是Always,如果一直重启对服务器是有压力的,所以它重启策略是,第一次为立即重启;接下来第二次重启则需要延时,比如延时10s在进行重启;第三次延时20s;第四次延时40s;往下80s、160s、300s,300s是最长的延时时间(即5分钟)。pod一旦绑定到一个节点,Pod 将永远不会重新绑定到另一个节点,除非删除Pod重新创建。

    4、livenessProbe解析

    [root@k8s-master ~]# kubectl explain pod.spec.containers.livenessProbe
    
    KIND:     Pod
    VERSION:  v1
    
    RESOURCE: livenessProbe <Object>
    
    exec  #command 的方式探测。例如:ps一个进程
    
    failureThreshold #探测几次失败才算失败,默认是连续三次
    
    periodSeconds #每次多长时间探测一次,默认10s
    
    timeoutSeconds #探测超时的秒数 默认1s
    
    initialDelaySeconds  #初始化延迟探测。第一次探测的时候延迟探测,因为主程序未必启动完成
    
    tcpSocket #检测端口的探测
    
    httpGet #http请求探测

    举个例子:定义一个liveness的pod资源类型,基础镜像为busybox,在busybox这个容器启动后会执行创建/tmp/test的文件啊,并删除,然后等待3600秒。随后定义了存活性探测,方式是以exec的方式执行命令判断/tmp/test是否存在,存在即表示存活,不存在则表示容器已经挂了。

    [root@master manifests]# cat liveness.exec.ymal 
    apiVersion: v1 kind: Pod metadata: name: liveness-exec-pod namespace: default spec: containers: - name: liveness-exec-container image: busybox:latest imagePullPolicy: IfNotPresent #如果存在就不要下载了 command: ["/bin/sh","-c","touch /tmp/healthy;sleep 60;rm -f /tmp/healthy;sleep 3600"] livenessProbe: #存活性探测 exec: command: ["test","-e","/tmp/healthy"] #-e表示探测文件是否存在 initialDelaySeconds: 1 #表示容器启动后多长时间开始探测 periodSeconds: 3 #表示每隔3s钟探测一次
    [root@master manifests]# kubectl create -f liveness.exec.ymal 
    pod/liveness-exec-pod created
    [root@master manifests]# kubectl get pods -w
    NAME                          READY     STATUS             RESTARTS   AGE
    liveness-exec-pod             1/1       Running            2          4m
    [root@master manifests]# kubectl get pods -w
    NAME                          READY     STATUS             RESTARTS   AGE
    liveness-exec-pod             1/1       Running            4          6m
    [root@master manifests]# kubectl get pods -w
    NAME                          READY     STATUS             RESTARTS   AGE
    client                        1/1       Running            0          3d
    liveness-exec-pod             1/1       Running            5          9m
    [root@master manifests]#  kubectl get pods -w
    NAME                          READY     STATUS             RESTARTS   AGE
    client                        1/1       Running            0          3d
    liveness-exec-pod             1/1       Running            9          23m

    可以看到restart此时在随着时间增长。 

    上面的例子是用exec执行命令进行探测的。 

    下面我们看看基于tcp和httpget探测的选项。

    [root@master manifests]kubectl explain pods.spec.containers.livenessProbe.tcpSocket
    
    [root@master manifests]# kubectl explain pods.spec.containers.livenessProbe.httpGet

    下面举个例子

    [root@master manifests]# cat liveness.httpget.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      name: liveness-httpget-pod
      namespace: default
    spec:
      containers:
      - name: liveness-httpget-container
        image: nginx:latest
        imagePullPolicy: IfNotPresent #如果存在就不要下载了
        ports:
        - name: http
          containerPort: 80
        livenessProbe: #存活性探测
          httpGet:
            port: http
            path: /index.html
          initialDelaySeconds: 1
          periodSeconds: 3 #表示每隔3s钟探测一次
    [root@master manifests]# kubectl  create -f liveness.httpget.yaml
    
    [root@master manifests]# kubectl get pods NAME READY STATUS RESTARTS AGE liveness-httpget-pod 1/1 Running 0 4m
    [root@master manifests]# kubectl exec -it liveness-httpget-pod -- /bin/sh # rm -rf /usr/share/nginx/html/index.html
    [root@master manifests]# kubectl get pods NAME READY STATUS RESTARTS AGE liveness-httpget-pod 1/1 Running 1 27m

    上面可以看到,当删除pod里面的/usr/share/nginx/html/index.html,liveness监测到index.html文件被删除了,所以restarts次数为1,但是只重启一次,不会再重启了。这是因为重启一次后,nginx容器就重新初始化了,里面就会又生成index.html文件。所以里面就会有新的index.html文件了。 

    readlinessProbe(准备就绪型探针) 

    [root@master manifests]# cat  readiness-httpget.ymal 
    apiVersion: v1
    kind: Pod
    metadata:
      name: readdliness-httpget-pod
      namespace: default
    spec:
      containers:
      - name: readliness-httpget-container
        image: nginx:latest
        imagePullPolicy: IfNotPresent #如果存在就不要下载了
        ports:
        - name: http
          containerPort: 80
        readinessProbe: #准备型探针
          httpGet:
            port: http
            path: /index.html
          initialDelaySeconds: 1
          periodSeconds: 3 #表示每隔3s钟探测一次
    [root@master manifests]# kubectl create -f readiness-httpget.ymal 
    pod/readdliness-httpget-pod created
    
    [root@master ~]# kubectl get pods
    NAME                          READY     STATUS             RESTARTS   AGE
    readdliness-httpget-pod       1/1       Running            0          16h
    
    [root@master ~]# kubectl exec -it readdliness-httpget-pod -- /bin/sh
    # rm -rf /usr/share/nginx/html/index.html
    
    [root@master ~]# kubectl get pods
    NAME                          READY     STATUS             RESTARTS   AGE
    readdliness-httpget-pod       0/1       Running            0          16h

     上面可以看到,ready变成0/1了,但是status是runing的,这就是说nginx进程是在的,只是index.html不见了,可以判定nginx没有就绪。

    postStart(启动后钩子)

    [root@master ~]# kubectl  explain pods.spec.containers.lifecycle.postStart

     postStart是指容器在启动之后立即执行的操作,如果执行操作失败了,容器将被终止并且重启。而重启与否是由重启策略。

    [root@master manifests]# cat poststart-pod.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      name: poststart-pod
      namespace: default
    spec:
      containers:
      - name: busybox-httpd
        image: busybox:latest
        imagePullPolicy: IfNotPresent
        lifecycle: #生命周期事件
          postStart:
            exec:
              command: ["mkdir", "-p","/data/web/html"] #这个command是定义postStart后的需要执行的命令
        command: ["/bin/sh","-c","sleep 3600"] #这是定义容器里面执行的命令,不过这个命令要先于postStart里面的command
        #args: ["-f","-h /data/web/html"]  #-f是前台,-h是家目录
    [root@master manifests]# kubectl create -f poststart-pod.yaml 
    pod/posttart-pod created

    说明:删除的方法

    [root@master manifests]# kubectl delete -f poststart-pod.yaml 
    pod "posttart-pod" deleted
    
    [root@master manifests]# kubectl get pods
    NAME                          READY     STATUS             RESTARTS   AGE
    poststart-pod                 1/1       Running            0          3m
    
    [root@master manifests]#  kubectl exec -it poststart-pod -- /bin/sh
    / # ls /data
    web
    / # ls /data/web/html/

    上面看到在容器启动后,建立了/data/web/html目录。这就是postStart的用法。

    preStop(终止之前钩子)

    [root@master ~]# kubectl  explain pods.spec.containers.lifecycle.preStop

    preStop是指容器在终止前要立即执行的命令,等这些命令执行完了,容器才能终止。

    容器的重启策略-restartPolicy

       一旦pod中的容器挂了,我们就把容器重启。

        策略包括如下:

        Always:表示容器挂了总是重启,这是默认策略 

        OnFailures:表容器状态为错误时才重启,也就是容器正常终止时才重启 

        Never:表示容器挂了不予重启 

        对于Always这种策略,容器只要挂了,就会立即重启,这样是很耗费资源的。所以Always重启策略是这么做的:第一次容器挂了立即重启,如果再挂了就要延时10s重启,第三次挂了就等20s重启...... 依次类推 

     容器的终止策略

        k8s会给容器30s的时间进行终止,如果30s后还没终止,就会强制终止。 

      总结

    pod:
            apiVersion
            kind
            metadata
            spec
            status(只读)
            spec:
                    containers
                    nodeSelector
                    nodeName
                    restartPolicy: Always,Never,OnFailure
                    containers:
                            name
                            image
                            imagePullPolicy: Always、Never、IfNotPresent
                            ports:
                                    name
                                    containerPort
                            livenessProbe
                            readinessProbe
                            liftcycle
                    ExecAction: exec
                    TCPSocketAction: tcpSocket
                    HTTPGetAction: httpGet

    四、Pod控制器

    (1)Pod控制器及其功用

    (2)通过配置清单管理ReplicaSet控制器,包括扩缩容及更新机制

    (3)Deployment控制器基础应用及滚动更新:灰度部署、金丝雀部署、蓝绿部署的实现;

    (4)DaemonSet控制器基础应用及使用案例

     

     

     上一节,我们创建的pod,是通过资源配置清单定义的,如果手工把这样的pod删除后,不会自己重新创建,这样创建的pod叫自主式Pod。 

     

        在生产中,我们很少使用自主式pod。 

     

        下面我们学习另外一种pod,叫控制器管理的Pod,控制器会按照定义的策略严格控制pod的数量,一旦发现pod数量少了,会立即自动建立出来新的pod;一旦发现pod多了,也会自动杀死多余的Pod。 

     

        pod控制器:ReplicaSet控制器、Deployment控制器(必须掌握)、DaenibSet控制器、Job控制器

     

         ReplicaSet控制器 :替用户创建指定数量Pod的副本,并保证pod副本满足用户期望的数量;而且更新自动扩缩容机制。

      replicat主要由三个组件组成:1、用户期望的pod副本数量;2、标签选择器(控制管理pod副本);3、pod资源模板(如果pod数量少于期望的,就根据pod模板来新建一定数量的pod)。 

         Deployment控制器 :Deployment通过控制replicaset来控制Pod。用于管理无状态应用,目前来说最好的控制器。Deployment支持滚动更新和回滚,声明式配置的功能。Deployment只关注群体,而不关注个体。

         DaemonSet控制器 :用于确保集群中的每一个节点只运行一个特定的pod副本(画外音,如果没有DaemonSet,一个节点可以运行多个pod副本)。如果在集群中新加一个节点,那么这个新节点也会自动生成一个Pod副本。

                       特性:服务是无状态的;服务必须是守护进程

         Job控制器 :对于那些 只做一次,只要完成就正常退出,没完成才重构pod  ,叫job控制器。 

     

        Cronjob:周期性任务控制,不需要持续后台运行

        

        StatefulSet控制器: 管理有状态应用,每一个pod副本都是被单独管理的。它拥有着自己独有的标识。 

     

        K8s在1.2+至1.7开始,支持TPR(third party resources 第三方资源)。在k8s 1.8+以后,支持CDR(Custom Defined Reources,用户自定义资源)。

      Operator是CoreOS推出的旨在简化复杂有状态应用管理的框架,它是一个感知应用状态的控制器,通过扩展Kubernetes API来自动创建、管理和配置应用实例。 

     ReplicaSet控制器

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

    在新版本的Kubernetes中建议使用ReplicaSet来取代ReplicationController。ReplicaSet跟ReplicationController没有本质的不同,只是名字不一样,并且ReplicaSet支持集合式的selector。

    虽然ReplicaSet可以独立使用,但一般还是建议使用 Deployment 来自动管理ReplicaSet,这样就无需担心跟其他机制的不兼容问题(比如ReplicaSet不支持rolling-update但Deployment支持)。

    [root@master manifests]# kubectl explain replicaset
    [root@master manifests]# kubectl explain  rs (replicaset的简写)
    [root@master manifests]# kubectl explain rs.spec.template
    [root@master manifests]# kubectl get deploy
    NAME           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
    myapp          2         2         2            0           10d
    mytomcat       3         3         3            3           10d
    nginx-deploy   1         1         1            1           13d
    [root@master manifests]# kubectl delete deploy myapp 
    deployment.extensions "myapp" deleted
    [root@master manifests]# kubectl delete deploy nginx-deploy
    deployment.extensions "nginx-deploy" deleted
    [root@master manifests]# cat rs-demo.yaml 
    apiVersion: apps/v1
    kind: ReplicaSet
    metadata:
      name: myapp
      namespace: default
    spec: #这是控制器的spec
      replicas: 2 #几个副本
      selector:   #查看帮助:,标签选择器。 kubectl explain rs.spec.selector
        matchLabels:
          app: myapp
          release: canary
      template:  # 查看帮助:模板 kubectl explain rs.spec.template
        metadata: # kubectl explain rs.spec.template.metadata
          name: myapp-pod
          labels:  #必须符合上面定义的标签选择器selector里面的内容
            app: myapp
            release: canary
            environment: qa
        spec: #这是pod的spec
          containers:
          - name: myapp-container
            image: ikubernetes/nginx:latest
            ports: 
            - name: http
              containerPort: 80
    [root@master manifests]# kubectl create -f rs-demo.yaml 
    replicaset.apps/myapp created
    [root@master manifests]# kubectl get rs
    NAME                 DESIRED   CURRENT   READY     AGE
    myapp                2         2         2         3m

    看到上面的ready是2,表示两个replcatset控制器都在正常运行。 

    [root@master manifests]# kubectl get pods --show-labels
    myapp-6kncv                1/1       Running            0          15m       app=myapp,environment=qa,release=canary
    myapp-rbqjz                1/1       Running            0          15m       app=myapp,environment=qa,release=canary         5m
    pod-demo                   0/2       CrashLoopBackOff   2552       9d        app=myapp,tier=frontend
    [root@master manifests]# kubectl describe pods myapp-6kncv 
    IP:                 10.244.2.44
    [root@master manifests]# curl  10.244.2.44
    Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>

    编辑replicatset的配置文件(这个文件不是我们手工创建的,而是apiserver维护的)

    [root@master manifests]# kubectl edit rs myapp

     把里面的replicas改成5,保存后就立即生效。

    [root@master manifests]#  kubectl get pods --show-labels
    NAME                       READY     STATUS              RESTARTS   AGE       LABELS
    client                     0/1       Error               0          11d       run=client
    liveness-httpget-pod       1/1       Running             3          5d        <none>
    myapp-6kncv                1/1       Running             0          31m       app=myapp,environment=qa,release=canary
    myapp-c64mb                1/1       Running             0          3s        app=myapp,environment=qa,release=canary
    myapp-fsrsg                1/1       Running             0          3s        app=myapp,environment=qa,release=canary
    myapp-ljczj                0/1       ContainerCreating   0          3s        app=myapp,environment=qa,release=canary
    myapp-rbqjz                1/1       Running             0          31m       app=myapp,environment=qa,release=canary

    同样,也可以用命令kubectl edit rs myapp升级版本,改里面的image: ikubernetes/myapp:v2,这样就变成v2版本了。

    [root@master manifests]# kubectl get rs -o wide
    NAME                 DESIRED   CURRENT   READY     AGE       CONTAINERS        IMAGES                 SELECTOR
    myapp                5         5         5         1h        myapp-container   ikubernetes/myapp:v2   app=myapp,release=canary

    不过,只有pod重建后,比如增加、删除Pod,才会更新成v2版本。 

    Deployment控制器

        我们可以通过Deployment控制器来动态更新pod的版本。 

        我们先建立replicatset v2版本,然后一个一个的删除replicatset v1版本中的Pod,这样自动新创建的pod就会变成v2版本了。当pod全部变成v2版本后,replicatset v1并不会删除,这样一旦发现v2版本有问题,还可以回退到v1版本。

        通常deployment默认保留10版本的replicatset。 

    [root@master manifests]# kubectl explain deploy
    [root@master manifests]# kubectl explain deploy.spec
    [root@master manifests]# kubectl explain deploy.spec.strategy (更新策略)
    [root@master ~]# kubectl delete rs myapp
    [root@master manifests]# cat deploy-demo.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: myapp-deploy
      namespace: default
    spec:
      replicas: 2
      selector: #标签选择器
        matchLabels: #匹配的标签为
          app: myapp
          release: canary
      template:
        metadata:
          labels:
            app: myapp #和上面的myapp要匹配
            release: canary
        spec:
          containers:
          - name: myapp
            image: ikubernetes/myapp:v1
            ports:
            - name: http
              containerPort: 80
    [root@master manifests]# kubectl apply -f deploy-demo.yaml 
    deployment.apps/myapp-deploy created

       apply表示是声明式更新和创建。 

    [root@master manifests]# kubectl get deploy
    NAME           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
    myapp-deploy   2         2         2            2           1m
    [root@master ~]# kubectl get rs
    NAME                      DESIRED   CURRENT   READY     AGE
    myapp-deploy-69b47bc96d   2         2         2         17m

      上面的rs式deployment自动创建的。 

    [root@master ~]# kubectl get pods
    NAME                            READY     STATUS    RESTARTS   AGE
    myapp-deploy-69b47bc96d-7jnwx   1/1       Running   0          19m
    myapp-deploy-69b47bc96d-btskk   1/1       Running   0          19m

    修改配置文件deploy-demo.yaml,把replicas数字改成3,然后再执行kubectl apply -f deploy-demo.yaml 即可使配置文件里面的内容生效。

    [root@master ~]# kubectl describe deploy myapp-deploy
    
    [root@master ~]# kubectl get pods -l app=myapp -w

      -l使标签过滤 

     -w是动态监控

    [root@master ~]# kubectl get rs -o wide
    NAME                      DESIRED   CURRENT   READY     AGE       CONTAINERS   IMAGES                 SELECTOR
    myapp-deploy-69b47bc96d   2         2         2         1h        myapp        ikubernetes/myapp:v1   app=myapp,pod-template-hash=2560367528,release=canary

    看滚动更新的历史:

    [root@master ~]# kubectl rollout history deployment myapp-deploy
    deployments "myapp-deploy"
    REVISION  CHANGE-CAUSE
    1         <none>

      下面我们把deployment改成5个:我们可以使用vim  deploy-demo.yaml方法,把里面的replicas改成5。当然,还可以使用另外一种方法,就patch方法,举例如下。

    [root@master manifests]# kubectl patch deployment myapp-deploy -p '{"spec":{"replicas":5}}'
    deployment.extensions/myapp-deploy patched
    
    
    [root@master manifests]# kubectl get deploy NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE myapp-deploy 5 5 5 5 2h
    [root@master manifests]# kubectl get pods NAME READY STATUS RESTARTS AGE myapp-deploy-69b47bc96d-7jnwx 1/1 Running 0 2h myapp-deploy-69b47bc96d-8gn7v 1/1 Running 0 59s myapp-deploy-69b47bc96d-btskk 1/1 Running 0 2h myapp-deploy-69b47bc96d-p5hpd 1/1 Running 0 59s myapp-deploy-69b47bc96d-zjv4p 1/1 Running 0 59s mytomcat-5f8c6fdcb-9krxn 1/1 Running 0 8h

    下面修改策略: 

    [root@master manifests]# kubectl patch deployment myapp-deploy -p '{"spec":{"strategy":{"rollingUpdate":{"maxSurge":1,"maxUnavaliable":0}}}}'
    deployment.extensions/myapp-deploy patched

    strategy:表示策略

    maxSurge:表示最多几个控制器存在

    maxUnavaliable:表示最多有几个控制器不可用

    [root@master manifests]# kubectl describe deployment myapp-deploy
    RollingUpdateStrategy: 0 max unavailable, 1 max surge

    下面我们用set image命令,将镜像myapp升级为v3版本,并且将myapp-deploy控制器标记为暂停。被pause命令暂停的资源不会被控制器协调使用,可以使“kubectl rollout resume”命令恢复已暂停资源。

    [root@master manifests]# kubectl set image deployment myapp-deploy myapp=ikubernetes/myapp:v3 &&
    kubectl rollout pause deployment myapp-deploy
    
    [root@master ~]# kubectl get pods -l app=myapp -w

    停止暂停:

    [root@master ~]# kubectl rollout resume deployment myapp-deploy
    deployment.extensions/myapp-deploy resumed

    看到继续更新了(即删一个更新一个,删一个更新一个):

    [root@master manifests]# kubectl rollout status deployment myapp-deploy
    Waiting for deployment "myapp-deploy" rollout to finish: 2 out of 5 new replicas have been updated...
    Waiting for deployment spec update to be observed...
    Waiting for deployment spec update to be observed...
    Waiting for deployment "myapp-deploy" rollout to finish: 2 out of 5 new replicas have been updated...
    Waiting for deployment "myapp-deploy" rollout to finish: 3 out of 5 new replicas have been updated...
    Waiting for deployment "myapp-deploy" rollout to finish: 3 out of 5 new replicas have been updated...
    Waiting for deployment "myapp-deploy" rollout to finish: 4 out of 5 new replicas have been updated...
    Waiting for deployment "myapp-deploy" rollout to finish: 4 out of 5 new replicas have been updated...
    Waiting for deployment "myapp-deploy" rollout to finish: 4 out of 5 new replicas have been updated...
    Waiting for deployment "myapp-deploy" rollout to finish: 1 old replicas are pending termination...
    Waiting for deployment "myapp-deploy" rollout to finish: 1 old replicas are pending termination...
    deployment "myapp-deploy" successfully rolled out
    [root@master manifests]# kubectl get rs -o wide
    NAME                      DESIRED   CURRENT   READY     AGE       CONTAINERS   IMAGES                 SELECTOR
    myapp-deploy-69b47bc96d   0         0         0         6h        myapp        ikubernetes/myapp:v1   app=myapp,pod-template-hash=2560367528,release=canary
    myapp-deploy-6bdcd6755d   5         5         5         3h        myapp        ikubernetes/myapp:v3   app=myapp,pod-template-hash=2687823118,release=canary
    mytomcat-5f8c6fdcb        3         3         3         12h       mytomcat     tomcat                 pod-template-hash=194729876,run=mytomcat

    上面可以看到myapp有v1和v3两个版本。 

    [root@master manifests]# kubectl rollout history deployment myapp-deploy
    deployments "myapp-deploy"
    REVISION  CHANGE-CAUSE
    1         <none>
    2         <none>

    上面可以看到有两个历史更新记录。 

    下面我们把v3回退到上一个版本(不指定就是上一个版本)。

    [root@master manifests]# kubectl  rollout undo deployment myapp-deploy --to-revision=1
    deployment.extensions/myapp-deploy

    可以看到第一版还原成第3版了: 

    [root@master manifests]# kubectl rollout history deployment myapp-deploy
    deployments "myapp-deploy"
    REVISION  CHANGE-CAUSE
    2         <none>
    3         <none>

     可以看到正在工作的是v1版,即回退到了v1版。 

    [root@master manifests]# kubectl get rs -o wide
    NAME                      DESIRED   CURRENT   READY     AGE       CONTAINERS   IMAGES                 SELECTOR
    myapp-deploy-69b47bc96d   5         5         5         6h        myapp        ikubernetes/myapp:v1   app=myapp,pod-template-hash=2560367528,release=canary
    myapp-deploy-6bdcd6755d   0         0         0         3h        myapp        ikubernetes/myapp:v3   app=myapp,pod-template-hash=2687823118,release=canary

    DaemonSet控制器 

     通过 https://hub.docker.com/r/ikubernetes/filebeat/tags/可以看到filebeat的版本有哪些:

    [root@node1 manifests]# docker pull ikubernetes/filebeat:5.6.5-alpine
    [root@node2 manifests]# docker pull ikubernetes/filebeat:5.6.5-alpine

    node1和node2上都下载filebeat镜像。 

    [root@node1 ~]# docker image inspect ikubernetes/filebeat:5.6.5-alpine
    
    [root@master manifests]# kubectl explain pods.spec.containers.env
    [root@master manifests]# cat ds-demo.yaml 
    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: myapp-ds
      namespace: default
    spec:
      selector: #标签选择器
        matchLabels: #匹配的标签为
          app: filebeat
          release: stable
      template:
        metadata:
          labels:
            app: filebeat #和上面的myapp要匹配
            release: stable
        spec:
          containers:
          - name: myapp
            image: ikubernetes/myapp:v1
            env:
            - name: REDIS_HOST
              value: redis.default.svc.cluster.local #随便取的名字
              name: REDIS_LOG_LEVEL
              value: info
    [root@master manifests]# kubectl apply -f ds-demo.yaml 
    daemonset.apps/myapp-ds created

    看到myapp-ds已经运行起来了,并且是两个myapp-ds,这是因为我们有两个Node节点。另外master节点上是不会运行myapp-ds控制器的,因为master有污点(除非你设置允许有污点,才可以在master上允许myapp-ds)

    [root@master manifests]# kubectl get pods
    NAME                            READY     STATUS    RESTARTS   AGE
    myapp-ds-5tmdd                  1/1       Running   0          1m
    myapp-ds-dkmjj                  1/1       Running   0          1m
    [root@master ~]# kubectl logs  myapp-ds-dkmjj
    
    [root@master manifests]# kubectl delete -f ds-demo.yaml
    [root@master manifests]# cat ds-demo.yaml 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: redis
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: redis
          role: logstor #日志存储角色
      template:
        metadata:
          labels:
            app: redis
            role: logstor
        spec: #这个是容器的spec
          containers:
          - name: redis
            image: redis:4.0-alpine
            ports:
            - name: redis
              containerPort: 6379
    #用减号隔离资源定义清单
    ---
    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: filebeat-ds
      namespace: default
    spec:
      selector: #标签选择器
        matchLabels: #匹配的标签为
          app: filebeat
          release: stable
      template:
        metadata:
          labels:
            app: filebeat #和上面的myapp要匹配
            release: stable
        spec:
          containers:
          - name: filebeat
            image: ikubernetes/filebeat:5.6.6-alpine
            env:
            - name: REDIS_HOST #这是环境变量名,value是它的值
              value: redis.default.svc.cluster.local #随便取的名字
            - name: REDIS_LOG_LEVEL
              value: info
    [root@master manifests]# kubectl create -f ds-demo.yaml 
    deployment.apps/redis created
    daemonset.apps/filebeat-ds created
    [root@master manifests]# kubectl expose deployment redis --port=6379 ##这是在用expose方式创建service,其实还有一种方式是根据清单创建service
    service/redis exposed
    [root@master manifests]# kubectl get svc  #service的简称
    NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
    redis        ClusterIP   10.106.138.181   <none>        6379/TCP       48s
    [root@master manifests]# kubectl get pods
    NAME                            READY     STATUS    RESTARTS   AGE
    filebeat-ds-hgbhr               1/1       Running   0          9h
    filebeat-ds-xc7v7               1/1       Running   0          9h
    redis-5b5d6fbbbd-khws2          1/1       Running   0          33m
    [root@master manifests]# kubectl exec -it redis-5b5d6fbbbd-khws2 -- /bin/sh
    /data # netstat -tnl
    Active Internet connections (only servers)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       
    tcp        0      0 0.0.0.0:6379            0.0.0.0:*               LISTEN      
    tcp        0      0 :::6379                 :::*                    LISTEN   
    /data # nslookup redis.default.svc.cluster.local  #看到DNS可以解析出来ip
    nslookup: can't resolve '(null)': Name does not resolve
    Name:      redis.default.svc.cluster.local
    Address 1: 10.106.138.181 redis.default.svc.cluster.local 
    /data # redis-cli -h redis.default.svc.cluster.local
    redis.default.svc.cluster.local:6379> keys *
    (empty list or set)
    redis.default.svc.cluster.local:6379>
    [root@master manifests]# kubectl exec -it filebeat-ds-pnk8b -- /bin/sh
    / # ps aux
    PID   USER     TIME   COMMAND
        1 root       0:00 /usr/local/bin/filebeat -e -c /etc/filebeat/filebeat.yml
       15 root       0:00 /bin/sh
       22 root       0:00 ps aux
       
    / # cat  /etc/filebeat/filebeat.yml
    filebeat.registry_file: /var/log/containers/filebeat_registry
    filebeat.idle_timeout: 5s
    filebeat.spool_size: 2048
    logging.level: info
    filebeat.prospectors:
    - input_type: log
      paths:
        - "/var/log/containers/*.log"
        - "/var/log/docker/containers/*.log"
        - "/var/log/startupscript.log"
        - "/var/log/kubelet.log"
        - "/var/log/kube-proxy.log"
        - "/var/log/kube-apiserver.log"
        - "/var/log/kube-controller-manager.log"
        - "/var/log/kube-scheduler.log"
        - "/var/log/rescheduler.log"
        - "/var/log/glbc.log"
        - "/var/log/cluster-autoscaler.log"
      symlinks: true
      json.message_key: log
      json.keys_under_root: true
      json.add_error_key: true
      multiline.pattern: '^s'
      multiline.match: after
      document_type: kube-logs
      tail_files: true
      fields_under_root: true
    output.redis:
      hosts: ${REDIS_HOST:?No Redis host configured. Use env var REDIS_HOST to set host.}
      key: "filebeat"
       
      
      
    / # printenv
    REDIS_HOST=redis.default.svc.cluster.local
    / # nslookup redis.default.svc.cluster.local
    nslookup: can't resolve '(null)': Name does not resolve
    Name:      redis.default.svc.cluster.local
    Address 1: 10.106.138.181 redis.default.svc.cluster.local

     daemon-set也支持滚动更新。 

    [root@master manifests]# kubectl set image daemonsets filebeat-ds filebeat=ikubernetes/filebeat:5.5.7-alpine

    说明: daemonsets filebeat-ds表示daemonsets名字叫filebeat-ds;

               filebeat=ikubernetes/filebeat:5.5.7-alpine表示filebeat容器=ikubernetes/filebeat:5.5.7-alpine

    五、Service资源对象

    (1)Service及其实现模型

    (2)Service的类型及其功用

    (3)Service类型的创建及应用方式

    (4)Headless Service

    (5)基于DNS的服务发现简介

    (6)Ingress类型及实现方式

     

     Ingress:就是能利用 Nginx(不常用)、Haproxy(不常用)、Traefik(常用)、Envoy(常用) 啥的负载均衡器暴露集群内服务的工具。

     

         Ingress为您提供七层负载均衡能力,您可以通过 Ingress 配置提供外部可访问的 URL、负载均衡、SSL、基于名称的虚拟主机等。作为集群流量接入层,Ingress 的高可靠性显得尤为重要。

     

        小知识:我们把k8s里面的pod服务发布到集群外部,可以用ingress,也可以用NodePort。 

     

     

        externalLB:外部的负载均衡器 

     

        service site:只是用来给pod分组归类的。 

     

    1
    [root@master manifests]# kubectl explain ingress

     

        创建名称空间: 

     

    1
    2
    3
    4
    5
    6
    7
    8
    [root@master manifests]# kubectl create namespace ingress-nginx
    namespace/dev created
    [root@master manifests]# kubectl get ns
    NAME          STATUS    AGE
    default       Active    17d
    ingress-nginx   Active    8s
    kube-public   Active    17d
    kube-system   Active    17d

     

        访问 https://github.com/kubernetes/ingress-nginx,进入deploy目录,里面就有我们要用的yaml文件。

     

    1
    2
    3
    4
    5
    6
    7
    8
     各文件的作用:
    configmap.yaml:提供configmap可以在线更行nginx的配置
    default-backend.yaml:提供一个缺省的后台错误页面 404
    namespace.yaml:创建一个独立的命名空间 ingress-nginx
    rbac.yaml:创建对应的role rolebinding 用于rbac
    tcp-services-configmap.yaml:修改L4负载均衡配置的configmap
    udp-services-configmap.yaml:修改L4负载均衡配置的configmap
    with-rbac.yaml:有应用rbac的nginx-ingress-controller组件

     

        访问https://kubernetes.github.io/ingress-nginx/deploy/#generice-deployment,里面是ingress的部署文档

     

    1
    2
    [root@master ~]# mkdir  ingress-nginx
    [root@master ~]# cd ingress-nginx

     

     部署ingress方法一(分步部署):

     

        下载如下配置文件: 

     

    1
    [root@master ingress-nginx]# for file in namespace.yaml configmap.yaml rbac.yaml tcp-services-configmap.yaml with-rbac.yaml udp-services-configmap.yaml; do wget  https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/$file; done

     

     

    1
    2
    [root@master ingress-nginx]# ls
    configmap.yaml  namespace.yaml  rbac.yaml  tcp-services-configmap.yaml  udp-services-configmap.yaml  with-rbac.yaml

     

    1、创建名称空间: 

     

    1
    2
    [root@master ingress-nginx]# kubectl apply -f namespace.yaml 
    namespace/ingress-nginx configured

     

    2、把剩下的ymal文件全应用

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    [root@master ingress-nginx]# kubectl  apply -f ./
    configmap/nginx-configuration created
    namespace/ingress-nginx configured
    serviceaccount/nginx-ingress-serviceaccount created
    clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created
    role.rbac.authorization.k8s.io/nginx-ingress-role created
    rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created
    clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created
    configmap/tcp-services created
    configmap/udp-services created
    deployment.extensions/nginx-ingress-controller created

     

    1
    2
    3
    4
    [root@master ingress-nginx]# kubectl get pods -n ingress-nginx -w
    NAME                                        READY     STATUS              RESTARTS   AGE
    default-http-backend-6586bc58b6-qd9fk       0/1       running    0          4m
    nginx-ingress-controller-6bd7c597cb-zcbbz   0/1       running   0          1m

     

        可以看到ingress-nginx名称空间里面有两个pod都处于running状态 

     

    部署ingress方法二(一键部署): 

     

    只下载mandatory.yaml文件,因为这个文件里面包含了上面所有yaml文件里面的内容。这是一键部署。

     

    1
    2
    [root@master ingress-nginx]# wget 
    https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml

     

    1
    [root@master ingress-nginx]#kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml

     

    1
    2
    3
    4
    [root@master ~]# kubectl get pods -n ingress-nginx -w  -o wide
    NAME                                        READY     STATUS    RESTARTS   AGE       IP            NODE      NOMINATED NODE
    default-http-backend-6586bc58b6-qd9fk       1/1       Running   0          11h       10.244.1.95   node1     <none>
    nginx-ingress-controller-6bd7c597cb-jlqzp   1/1       Running   3          11h       10.244.1.96   node1     <none>

     

         可以看到ingress-nginx名称空间里面有两个pod都处于running状态

     

    安装service-nodeport

     

        上面我们把ingress-nginx部署到了1号node上。接下来我们还需要部署一个service-nodeport服务,才能实现把集群外部流量接入到集群中来。 

     

    1
    [root@master ingress]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/baremetal/service-nodeport.yaml

     

        我们为了不让service nodeport自动分配端口,我们自己指定一下nodeport,修改文件中加两个nodePort参数,最终如下:

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    [root@master ingress]# cat service-nodeport.yaml 
    apiVersion: v1
    kind: Service
    metadata:
      name: ingress-nginx
      namespace: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    spec:
      type: NodePort
      ports:
      - name: http
        port: 80
        targetPort: 80
        protocol: TCP
        nodePort: 30080
      - name: https
        port: 443
        targetPort: 443
        protocol: TCP
        nodePort: 30443
      selector:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx

     

    1
    2
    [root@master ingress]# kubectl apply -f service-nodeport.yaml 
    service/ingress-nginx created

     

    1
    2
    3
    4
    [root@master ingress]# kubectl get svc -n ingress-nginx
    NAME                   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
    default-http-backend   ClusterIP   10.110.74.183   <none>        80/TCP                       12h
    ingress-nginx          NodePort    10.102.78.188   <none>        80:30080/TCP,443:30443/TCP   2m

     

        上面我看到80对应30080,,43对应30443 

     

        我们直接通过node1节点的ip就可以访问到应用: 

     

    1
    2
    [root@master ingress]# curl  http://172.16.1.101:30080
    default backend - 404

     

     

     

    定义myapp service

     

    1
    [root@master manifests]# mkdir /root/manifests/ingress

     

    1
    [root@master ~]# kubectl explain service.spec.ports

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    [root@master ingress]# cat deploy-demo.yaml 
    apiVersion: v1
    kind: Service
    #必须设置为无头service
    metadata:
     name: myapp
     namespace: default
    spec:
      selector:
        app: myapp
        release: canary
      ports:
      - name: http
        targetPort: 80   #这是容器port
        port: 80  #这是service port
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: myapp-deploy
      namespace: default
    spec:
      replicas: 2
      selector: #标签选择器
        matchLabels: #匹配的标签为
          app: myapp
          release: canary
      template:
        metadata:
          labels:
            app: myapp #和上面的myapp要匹配
            release: canary
        spec:
          containers:
          - name: myapp
            image: ikubernetes/myapp:v1
            ports:
            - name: http
              containerPort: 80

     

    1
    2
    3
    [root@master ingress]# kubectl apply -f deploy-demo.yaml 
    service/myapp created
    deployment.apps/myapp-deploy unchanged

     

    1
    2
    3
    4
    [root@master ingress]# kubectl get svc
    NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
    kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP    17d
    myapp        ClusterIP   10.108.177.62   <none>        80/TCP     1m

     

    1
    2
    3
    4
    [root@master ingress]# kubectl get pods
    NAME                            READY     STATUS             RESTARTS   AGE
    myapp-deploy-69b47bc96d-79fqh   1/1       Running            0          1d
    myapp-deploy-69b47bc96d-tc54k   1/1       Running            0          1d

     

     

    把myapp service通过ingress发布出去

     

         下面我们再定义一个清单文件,把myapp应用通过Ingress(相当于nginx的反向代理功能)发布出去: 

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    [root@master ingress]# cat ingress-myapp.yaml 
    apiVersion: extensions/v1beta1 
    kind: Ingress
    metadata:
      name: ingress-myapp
      namespace: default #要和deployment和要发布的service处于同一个名称空间
      annotations: #这个注解说明我们要用到的ingress-controller是nginx,而不是traefic,enjoy
        kubernetes.io/ingress.class: "nginx"
    spec:
      rules:
      - host: myapp.zhixin.com #表示访问这个域名,就会转发到后端myapp管理的pod上的服务:
        http:
          paths: 
          - path:
            backend:
              serviceName: myapp
              servicePort: 80

     

    1
    2
    [root@master ingress]# kubectl apply -f ingress-myapp.yaml 
    ingress.extensions/ingress-myapp created

     

    1
    2
    3
    [root@master ingress]# kubectl get ingress
    NAME            HOSTS              ADDRESS   PORTS     AGE
    ingress-myapp   myapp.zhixin.com             80        8m

     

    1
    [root@master ingress]# kubectl describe ingress

     

    1
    2
    3
    4
    [root@master ingress]# kubectl get pods -n ingress-nginx 
    NAME                                        READY     STATUS    RESTARTS   AGE
    default-http-backend-6586bc58b6-qd9fk       1/1       Running   0          12h
    nginx-ingress-controller-6bd7c597cb-jlqzp   1/1       Running   3          12h

     

        进入ingress-controller交互式命令行里面,可以清晰的看到nginx是怎么反向代理我们myapp.zhixin.com的: 

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [root@master ingress]# kubectl exec -n ingress-nginx -it nginx-ingress-controller-6bd7c597cb-jlqzp -- /bin/sh
    $ cat nginx.conf
    ## start server myapp.zhixin.com
    server {
    server_name myapp.zhixin.com ;
    listen 80;
    set $proxy_upstream_name "-";
    location / {
    set $namespace      "default";
    set $ingress_name   "ingress-myapp";
    set $service_name   "myapp";
    set $service_port   "80";
    ........

     

        测试,下面我们把myapp.zhixin.com域名解析到node1 ip 172.16.1.101上。

     

    1
    2
    [root@master ingress]# curl myapp.zhixin.com:30080
    Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>

     

     

     

    把tomcat service通过ingress发布出去(新例子)

     

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    [root@master ingress]# cat tomcat-demo.yaml 
    apiVersion: v1
    kind: Service
    #必须设置为无头service
    metadata:
     name: tomcat
     namespace: default
    spec:
      selector:
        app: tomcat
        release: canary
      ports:
      - name: http
        targetPort: 8080   #这是容器port
        port: 8080  #这是service port
      - name: ajp
        targetPort: 8009
        port: 8009
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: tomcat-deploy
      namespace: default
    spec:
      replicas: 2
      selector: #标签选择器
        matchLabels: #匹配的标签为
          app: tomcat
          release: canary
      template:
        metadata:
          labels:
            app: tomcat #和上面的myapp要匹配
            release: canary
        spec:
          containers:
          - name: tomcat
            image: tomcat:8.5.34-jre8-alpine  #在https://hub.docker.com/r/library/tomcat/tags/上面找
            ports:
            - name: http
              containerPort: 8080
            - name: ajp
              containerPort: 8009

     

    1
    2
    3
    [root@master ingress]# kubectl apply -f tomcat-demo.yaml 
    service/tomcat created
    deployment.apps/tomcat-deploy created

     

    1
    2
    3
    4
    [root@master ingress]# kubectl get svc
    NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
    kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP             17d
    tomcat       ClusterIP   10.109.76.87    <none>        8080/TCP,8009/TCP   1m

     

    1
    2
    3
    4
    [root@master ingress]# kubectl get pods
    NAME                             READY     STATUS             RESTARTS   AGE
    tomcat-deploy-64c4d54df4-68sk8   1/1       Running            0          51s
    tomcat-deploy-64c4d54df4-7b58g   1/1       Running            0          51s

     

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    [root@master ingress]# cat ingress-tomcat.yaml 
    apiVersion: extensions/v1beta1 
    kind: Ingress
    metadata:
      name: ingress-tomcat
      namespace: default #要和deployment和要发布的service处于同一个名称空间
      annotations: #这个注解说明我们要用到的ingress-controller是nginx,而不是traefic,enjoy
        kubernetes.io/ingress.class: "nginx"
    spec:
      rules:
      - host: tomcat.zhixin.com #表示访问这个域名,就会转发到后端myapp管理的pod上的服务:
        http:
          paths: 
          - path:
            backend:
              serviceName: tomcat
              servicePort: 8080

     

    1
    2
    [root@master ingress]# kubectl apply -f ingress-tomcat.yaml 
    ingress.extensions/ingress-myapp configured

     

    1
    2
    3
    [root@master ingress]# kubectl get ingress
    NAME             HOSTS               ADDRESS   PORTS     AGE
    ingress-tomcat   tomcat.zhixin.com             80        11s

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    [root@master ingress]# kubectl describe ingress ingress-tomcat
    Name:             ingress-tomcat
    Namespace:        default
    Address:          
    Default backend:  default-http-backend:80 (<none>)
    Rules:
      Host               Path  Backends
      ----               ----  --------
      tomcat.zhixin.com  
                            tomcat:8080 (<none>)
    Annotations:
      kubernetes.io/ingress.class:  nginx
    Events:
      Type    Reason  Age   From                      Message
      ----    ------  ----  ----                      -------
      Normal  CREATE  1m    nginx-ingress-controller  Ingress default/ingress-tomcat

     

        把tomcat.zhixin.com解析到node1上节点物理ip(我的是172.16.1.101)

     

        测试,可以看到tomcat欢迎界面:

     

    1
    [root@master ingress]# curl tomcat.zhixin.com:30080

     

     

     

    使用https访问(新例子)

     

    1、先做个自签的证书(我们这里不演示CA的例子) 

     

    1
    [root@master ingress]# openssl genrsa -out tls.key 2048

     

    1
    [root@master ingress]# openssl req -new -x509 -key tls.key  -out tls.crt -subj /C=CN/ST=Beijing/O=DevOps/CN=tomcat.zhixin.com

     

    2、通过secret把证书注入到pod中。 

     

    1
    2
    [root@master ingress]# kubectl create secret tls tomcat-infress-secret --cert=tls.crt --key=tls.key 
    secret/tomcat-infress-secret created

     

    1
    2
    3
    4
    [root@master ingress]# kubectl get secret
    NAME                    TYPE                                  DATA      AGE
    default-token-5r85r     kubernetes.io/service-account-token   3         17d
    tomcat-ingress-secret   kubernetes.io/tls                     2         41s

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [root@master ingress]# kubectl describe secret tomcat-ingress-secret 
    Name:         tomcat-ingress-secret
    Namespace:    default
    Labels:       <none>
    Annotations:  <none>
    Type:  kubernetes.io/tls
    Data
    ====
    tls.crt:  1245 bytes
    tls.key:  1679 bytes

     

    3、配置ingress为tls方式

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    [root@master ingress]# cat ingress-tomcat-tls.yaml 
    apiVersion: extensions/v1beta1 
    kind: Ingress
    metadata:
      name: ingress-tomcat-tls
      namespace: default #要和deployment和要发布的service处于同一个名称空间
      annotations: #这个注解说明我们要用到的ingress-controller是nginx,而不是traefic,enjoy
        kubernetes.io/ingress.class: "nginx"
    spec:
      tls:
      - hosts:
        - tomcat.zhixin.com
        secretName: tomcat-ingress-secret #kubectl get secret命令查到的名字
      rules:
      - host: tomcat.zhixin.com #表示访问这个域名,就会转发到后端myapp管理的pod上的服务:
        http:
          paths: 
          - path:
            backend:
              serviceName: tomcat
              servicePort: 8080

     

    1
    2
    3
    4
    [root@master ingress]# kubectl get ingress
    NAME                 HOSTS               ADDRESS   PORTS     AGE
    ingress-tomcat       tomcat.zhixin.com             80        2h
    ingress-tomcat-tls   tomcat.zhixin.com             80, 443   3m

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    [root@master ingress]# kubectl describe ingress ingress-tomcat-tls  
    Name:             ingress-tomcat-tls
    Namespace:        default
    Address:          
    Default backend:  default-http-backend:80 (<none>)
    TLS:
      tomcat-ingress-secret terminates tomcat.zhixin.com
    Rules:
      Host               Path  Backends
      ----               ----  --------
      tomcat.zhixin.com  
                            tomcat:8080 (<none>)
    Annotations:
      kubectl.kubernetes.io/last-applied-configuration:  {"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"nginx"},"name":"ingress-tomcat-tls","namespace":"default"},"spec":{"rules":[{"host":"tomcat.zhixin.com","http":{"paths":[{"backend":{"serviceName":"tomcat","servicePort":8080},"path":null}]}}],"tls":[{"hosts":["tomcat.zhixin.com"],"secretName":"tomcat-ingress-secret"}]}}
      kubernetes.io/ingress.class:  nginx
    Events:
      Type    Reason  Age   From                      Message
      ----    ------  ----  ----                      -------
      Normal  CREATE  4m    nginx-ingress-controller  Ingress default/ingress-tomcat-tls

     

    4、连如ingress-controller查看nginx.conf的配置 

     

    1
    2
    3
    4
    [root@master ingress]# kubectl get pods -n ingress-nginx
    NAME                                        READY     STATUS    RESTARTS   AGE
    default-http-backend-6586bc58b6-qd9fk       1/1       Running   0          16h
    nginx-ingress-controller-6bd7c597cb-jlqzp   1/1       Running   3          16h

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    [root@master ingress]# kubectl exec -n ingress-nginx -it nginx-ingress-controller-6bd7c597cb-jlqzp -- /bin/sh
    $ $ cat nginx.conf
        ## start server tomcat.zhixin.com
        server {
            server_name tomcat.zhixin.com ;
             
            listen 80;
             
            set $proxy_upstream_name "-";
             
            listen 443  ssl http2;

     

        看到有listen 443了。 

     

    5、测试https 

     

    1
    [root@master ingress]# curl https://tomcat.zhixin.com:30443

     

    部署方法三(利用ingress 的80端口)

     

        前面两种部署方法,是用node ip + 非80端口,访问k8s集群内部的服务。可是,我们实际生产中更希望的是node ip + 80端口的方式,访问k8s集群内的服务。我感觉这个方法最好,下面就就介绍这个方法。 

     

        这部分内容参考的是博文http://blog.51cto.com/devingeng/2149377

     

        下载地址 

     

    https://github.com/kubernetes/ingress-nginx/archive/nginx-0.11.0.tar.gz

     

    1
    2
    3
    4
    5
    6
    7
    8
    ingress-nginx文件位于deploy目录下,各文件的作用:
    configmap.yaml:提供configmap可以在线更行nginx的配置
    default-backend.yaml:提供一个缺省的后台错误页面 404
    namespace.yaml:创建一个独立的命名空间 ingress-nginx
    rbac.yaml:创建对应的role rolebinding 用于rbac
    tcp-services-configmap.yaml:修改L4负载均衡配置的configmap
    udp-services-configmap.yaml:修改L4负载均衡配置的configmap
    with-rbac.yaml:有应用rbac的nginx-ingress-controller组件

     

        修改with-rbac.yaml

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    apiVersion: extensions/v1beta1
    kind: Daemonset
    metadata:
      name: nginx-ingress-controller
      namespace: ingress-nginx 
    spec:
      selector:
        matchLabels:
          app: ingress-nginx
      template:
        metadata:
          labels:
            app: ingress-nginx
          annotations:
            prometheus.io/port: '10254'
            prometheus.io/scrape: 'true'
        spec:
          serviceAccountName: nginx-ingress-serviceaccount      
          hostNetwork: true
          containers:
            - name: nginx-ingress-controller
              image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.11.0
              args:
                - /nginx-ingress-controller
                - --default-backend-service=$(POD_NAMESPACE)/default-http-backend
                - --configmap=$(POD_NAMESPACE)/nginx-configuration
                - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
                - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
                - --annotations-prefix=nginx.ingress.kubernetes.io
              env:
                - name: POD_NAME
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.name
                - name: POD_NAMESPACE
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.namespace
              ports:
              - name: http
                containerPort: 80
              - name: https
                containerPort: 443
              livenessProbe:
                failureThreshold: 3
                httpGet:
                  path: /healthz
                  port: 10254
                  scheme: HTTP
                initialDelaySeconds: 10
                periodSeconds: 10
                successThreshold: 1
                timeoutSeconds: 1
              readinessProbe:
                failureThreshold: 3
                httpGet:
                  path: /healthz
                  port: 10254
                  scheme: HTTP
                periodSeconds: 10
                successThreshold: 1
                timeoutSeconds: 1
          nodeSelector:
            custom/ingress-controller-ready: "true"

     

    需要修改的地方:

     

    kind: DaemonSet:官方原始文件使用的是deployment,replicate 为 1,这样将会在某一台节点上启动对应的nginx-ingress-controller pod。外部流量访问至该节点,由该节点负载分担至内部的service。测试环境考虑防止单点故障,改为DaemonSet然后删掉replicate ,配合亲和性部署在制定节点上启动nginx-ingress-controller pod,确保有多个节点启动nginx-ingress-controller pod,后续将这些节点加入到外部硬件负载均衡组实现高可用性。

     

    hostNetwork: true:添加该字段,暴露nginx-ingress-controller pod的服务端口(80)

     

    nodeSelector: 增加亲和性部署,有custom/ingress-controller-ready 标签的节点才会部署该DaemonSet

     

    为需要部署nginx-ingress-controller的节点设置lable

     

    1
    2
    3
    kubectl label nodes vmnode2 custom/ingress-controller-ready=true
    kubectl label nodes vmnode3 custom/ingress-controller-ready=true
    kubectl label nodes vmnode4 custom/ingress-controller-ready=true

     

    加载yaml文件

     

    1
    2
    3
    4
    5
    6
    7
    kubectl apply  -f namespace.yaml
    kubectl apply -f default-backend.yaml
    kubectl apply -f configmap.yaml
    kubectl apply -f tcp-services-configmap.yaml
    kubectl apply -f udp-services-configmap.yaml
    kubectl apply -f rbac.yaml
    kubectl apply -f with-rbac.yaml

     

    查看pod是否正常创建

     

    ##下载镜像可能会比较慢,等待一会所有pod都是Running状态,按Ctrl + c 退出

     

    1
    2
    3
    4
    5
    6
    [root@vmnode1 deploy]# kubectl get pods --namespace=ingress-nginx  --watch
    NAME                                    READY     STATUS    RESTARTS   AGEdefault-
    http-backend-6c59748b9b-hc8q9   1/1       Running   0          6m
    nginx-ingress-controller-7fmlp          1/1       Running   1          13d
    nginx-ingress-controller-j95fb          1/1       Running   1          13d
    nginx-ingress-controller-ld2jw          1/1       Running   1          13d

     

    测试ingress 

     

    创建一个tomcat的Service

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    [root@k8s-master1 test]# cat mytomcat.yaml 
    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
      name: mytomcat
    spec:
      replicas: 2
      template:
        metadata:
          labels:
            run: mytomcat
        spec:
          containers:
          - name: mytomcat
            image: tomcat
            ports:
            - containerPort: 8080
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: mytomcat
      labels:
        run: mytomcat
    spec:
      type: NodePort
      ports:
      - port: 8080
        targetPort: 8080
      selector:
        run: mytomcat

     

    1
    [root@k8s-master1 test]# kubectl apply -f mytomcat.yaml

     

        配置ingress转发文件: 

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    [root@k8s-master1 test]# cat test-ingress.yaml 
    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: test-ingress
      namespace: default
    spec:
      rules:
      - host: test.zhixin.com
        http:
          paths:
          - path: /
            backend:
              serviceName: mytomcat
              servicePort: 8080

     

    host: 对应的域名  

     

    path: url上下文 

     

    backend:后向转发 到对应的 serviceName: servicePort:

     

    1
    2
    [root@k8s-master1 test]# kubectl apply -f test-ingress.yaml 
    ingress.extensions/test-ingress created

     

    nginx-ingress-controller运行在node1和nod2两个节点上。如果网络中有dns服务器,在dns中把这两个域名映射到nginx-ingress-controller运行的任意一个节点上,如果没有dns服务器只能修改host文件了。 

     

    正规的做法是在node1和node2这两个节点上安装keepalive,生成一个vip。在dns上把域名和vip做映射。

     

    我这里直接在node1节点上操作了:

     

    我这里node1节点的ip是172.16.22.201;node2节点的ip是172.16.22.202

     

    1
    2
    [root@k8s-master1 test]# echo " 172.16.22.201 test.zhixin.com" >> /etc/hosts
    [root@k8s-master1 test]# echo "172.16.22.202 test.zhixin.com" >> /etc/hosts

     

        然后访问测试: 

     

     

     

        看到,我们把域名test.zhixin.com绑定到Node节点的ip补上,然后我们直接访问http://test.zhixin.com,就能访问到k8s集群里面的pod服务。 

     

     

    (7)Ingress Controller及部署

    (8)Ingress使用案例:发布httphttpstomcat服务

    六、K8S-存储卷

    (1)存储卷及其功用

    (2)常见的存储卷类型及应用:emptyDirhostPathnfsglusterfs

    (3)PVPVC

    (4)StorageClassPV的动态供给

    (5)ConfigMap

    (6)Secret

    七、StatefulSet

    (1)有状态及无状态应用对比

    (2)有状态应用的容器难题

    (3)StatefulSet及其应用

    (4)案例

    八、网络模型及网络策略

    (1)flannel工作原理及host-gw等实现方式

    (2)calico及其应用

    (3)网络策略及其工作机制

    (4)基于calico的网络策略的实现

    九、认证、授权及准入控制

    (1)Kubernetes的认证、授权及准入控制机制

    (2)ServiceAccount

    (3)令牌认证及证书认证

    (4)RBAC及其实现机制

    (5)RoleRoleBinding

    (6)ClusterRoleClusterRoleBinding

    十、调度器

    (1)资源需求、资源限额及其应用

    (2)Pod优选级类别

    (3)Pod调度器工作原理

    (4)预选及预选策略

    (5)优选及优选算法

    (6)高级调度方法

    十一、资源监控及HPA(陆续上传)

    (1)HeapSterInfluxDBGrafana实现资源监控

    (2)HPA v1

    (3)PrometheusGrafana实现资源监控

    (4)Metrics-Server

    (5)HPA v2

    十二、helm及日志收集系统(陆续上传)

    (1)helm工作原理

    (2)helm部署及其应用

    (3)部署efk日志收集系统

    十三、基于KubernetesDevOps介绍 (陆续上传)

    manifests
  • 相关阅读:
    图像 resize 代码:保留 aspect ratio(长宽比)
    Pytorch lr_scheduler 中的 last_epoch 用法
    torch.optim用法(参数组的设置)
    课程式学习(Curriculum Learning)
    扇贝单词本-隐藏中文释义 tampermonkey
    电话号码正向标记认证网站申请地址
    考研英语做题计时器网页版(每隔3分钟播放声音,提醒计时)
    mac关闭自动更新后还在每天提醒进行安装更新
    mac 自动生成自签证书脚本
    Ditto
  • 原文地址:https://www.cnblogs.com/huhyoung/p/9788754.html
Copyright © 2020-2023  润新知