• 02K8S之自主式Pod


    创建pod及deployment、service

    kubectl run nginx-deploy --image=nginx:1.20-alpine --port=80 --dry-run=true
    kubectl run nginx-deploy --image=nginx:1.20-alpine --port=80 # 创建静态pod
    kubectl run nginx-deploy --image=nginx:1.20-alpine --port=80 --replicas=1 # 创建deployment副本,运行此命令,会从远程拉取镜像,创建pod,并运行pod。这个pod受刚创建的deployment控制器管理。 
        
    kubectl expose deployment nginx-deploy --name=nginx --port=80 --target-port=80 --protocol=TCP # 将某个控制器所管理的一组pod暴露出去,能够通过service向pod代理
    kubectl expose pod  nginx-deploy --name=nginx --port=80 --target-port=80 --protocol=TCP # 将某个静态pod暴露出去,
     kubectl get svc
     '''
     nginx        ClusterIP   10.104.76.181   <none>        80/TCP    8s
     '''
    curl 10.104.76.181
    '''
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    <style>
        body {
             35em;
            margin: 0 auto;
            font-family: Tahoma, Verdana, Arial, sans-serif;
        }
    </style>
    </head>
    <body>
    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.</p>
    
    <p>For online documentation and support please refer to
    <a href="http://nginx.org/">nginx.org</a>.<br/>
    Commercial support is available at
    <a href="http://nginx.com/">nginx.com</a>.</p>
    
    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>
    '''
    
    kubectl run client -it --image=busybox --restart=Never # 图1
    	ping 10.244.2.4
        cat /etc/resolv.conf
        '''
    	nameserver 10.96.0.10
    	search default.svc.cluster.local svc.cluster.local cluster.local com
    	options ndots:5
        '''
        while true;do wget -O - -q http://nginx:80;done
    # 在master节点上进行域名解析
    dig -t A nginx.default.svc.cluster.local. @10.96.0.10  # nginx是service名称,default是名称空间,svc.cluster.local.是pod名称,是由核心组件coreDNS服务解析。图2
    
    

    图1:

    图2:

    扩缩容(scale)、滚动更新(升级)及回滚

    kubectl run myapp --image=ikubernetes/myapp:v1 --replicas=2
    kubectl get deployment -w # -w watch 动态监视
    kubectl expose deploment myapp --name=myapp
    
    # 1. 扩缩容
    kubectl scale --replicas=5 deployment myapp --port=80  # 扩容
    kubectl scale --replicas=3 deployment myapp --port=80  # 缩容
    
    # kubectl set image 
    kubectl set image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IMAGE_1 ... CONTAINER_NAME_N=CONTAINER_IMAGE_N
    [options]
    
    # 2. 滚动更新(升级)
    # 类似于金丝雀发布(或者叫灰度发布,但是粒度没有那么细) 
    kubectl set image deployment myapp myapp=ikubernetes/myapp:v2 # 更改镜像指定是更改哪个控制器下面的pod的镜像,这里控制器名是myapp, 容器名字也叫myapp,后面对应的是镜像 。首先要从远程仓库下载镜像
    kubectl rollout status deployment myapp # 查看滚动更新deployment副本的状态
    
    kubectl get pods # 下图1
    kubectl describe po myapp-74c9dcb8c-642fm # 查看新版本的pod镜像已经更新到ikubernetes/myapp:v2
    
    # 3. 回滚
    kubectl rollout undo (TYPE NAME | TYPE/NAME) [flags] [options]
    kubectl rollout undo  deployment myapp # 不指定回滚的镜像版本,默认回滚到上一个版本 图3
    
    

    图1:

    图2:

    图3:

    创建service的时候就会在iptables表中生成转发规则(如果没有ipvs,就会降级到iptables)
    iptables -nvL -t nat
    

    集群外部访问service代理的pod

    [root@master01 yum.repos.d]# kubectl get svc
    '''
    NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
    kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   7h1m
    nginx        ClusterIP   10.104.76.181   <none>        80/TCP    104m
    '''
    kubectl edit service nginx # 下图1
    [root@master01 yum.repos.d]# kubectl get svc
    '''
    NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP        7h4m
    nginx        NodePort    10.104.76.181   <none>        80:32444/TCP   108m
    '''
    
    curl 192.168.1.130:32444 # 
    

    图1:

    图2:

    kubernetes资源清单

    RESTful:
        GET PUT DELETE POST、...
        kubectl run,get,edit,...
    资源:对象
    	workload: Pod,ReplicaSet,Deployment,StatefulSet,DaemonSet,Job,CronJob,...
    	服务发现及均衡: Service,Ingress,...
        配置与存储: Volume,CSI
        	ConfigMap,Secret
            DownwardAPI:向容器中注入信息
    	集群级资源;
        	Namespace,Node,Role,ClusterRole,RoleBinding,ClusterRoleBinding
    	元数据型资源
        	HPA,PodTemplate,LimitRange
    
    
    kubectl get pods
    kubectl get po nginx-deploy -o yaml # 将pod信息输出为yaml格式 
    kubectl get po nginx-deploy -o yaml >nginx-deploy.yaml 
    
    apiVersion: v1 # apiversion 的组成是 group/version 如果省略group,表示core,是核心组。
    spec: # specification:规格,我们创建的资源对象应该具有什么样的特性,或者满足什么样的规范。用户定义的
    status: # 当前资源的当前状态,如果当前状态和目标状态不一样,以目标状态为准,因为目标状态是用户期望的状态;当某一个k8s资源定义好之后,该资源的当前状态应该是无限靠近目标状态。只读的,系统维护
    
    

    创建资源的方法

    apiserver仅接收JSON格式的资源定义;命令行run 后跟的参数只不过被准换为json格式;
    yaml格式提供配置清单,apiserver可自动将其转为json格式,而后再提交;
    
    大部分资源的配置清单:
    	apiVersion: # group/version 
    		kubectl api-Versions
    		pod属于最核心资源,所以属于核心群组v1;控制器deployment、replicaSet属于应用程序管理的资源对象,它们属于apps/v1群组
    	kind:资源类别,都是内建的或自定义的(按照固定的语法格式进行定义),不能随意定义;
    	metadata:元数据
    		name:当前对象创建,实例化出来的当前类别的资源名称;
    		namespace:对象所属名称空间,是kuernates级别的概念,与NET、IPC、UTS不同。。。
    		labels:每一种类型资源的标签
    		annotations:资源注解
    		selflink:
    			每个资源引用的PATH
    				/api/GROUP/VERSION/namespaces/NAMESPACE/TYPE/NAME
    	spec:期望的状态,disired state
    	status:当前状态
    	
    # 群组中各版本区别
    alpha:内测版,不公开使用
    beta:公测版,非稳定,大部分功能都已经测试过并保留,但有极少部分内容有可能会改变,所以不稳定。
    stable:稳定版,已有的内容不会改变,最多是在原有的版本中再添加一些内容。
    

    k8s资源属性的类型

    <string> :字符串,直接就是 key: value
    <integer>:整型
    <[]string> : 字符串列表 
        第一种形式:[" "," "," "]
        第二种形式:
        - " "
        - " "
        - " "
     <map[string]string> : 映射类型
        key1: value1
        key2: value2
    <Object> 对象,在对象紧接一行,空两格写属性
      
    <[]Object> :对象列表 在对象列表紧接一行,以"-"开头,空一格然后写属性
    
    

    定义一个pod资源清单

    apiVersion: v1
    kind: Pod
    metadata: 
     name: pod-demo
     namespace: default
     labels: # <map[string]string> 映射类型,类似于json
     	app: myapp
     	tier: frontend
    spec:
      containers:
      - name: myapp
        image: nginx:1.20 # 使用镜像启动默认的命令
      - name: busybox
        image: busybox:latest 
        command: # ["/bin/sh","-c","sleep 3600"] # 这里使用自定义的命令,而没使用镜像启动默认的命令,就是为了防止默认命令启动之后会退出
        - "/bin/sh"
        - "-c"
        - "sleep 3600"
    

    运行pod-demo:

    kubectl create -f pod-demo.yaml 
    kubectl get po -o wide -w
    kubectl describe po pod-demo
    kubectl logs pod-demo -c myapp # 查看pod-demopod内myapp容器日志,如下图2
    kubectl logs pod-demo -c busybox  # 查看pod-demopod内busybox容器日志
    kubectl exec -it pod-demo -c myapp -- /bin/bash
    kubectl exec -it pod-demo -c busybox -- /bin/sh
    
    kubectl delete -f pod-demo.yaml # 或者 kubectl delete pod-demo
    
    kubectl get po -l app --show-labels # -l 显示具有app标签名称的pod,--show-labels,显示此类pod的标签列
    kubectl get po -L app,run # 显示具有app和run标签名称对应值的pod 
    
    kubectl label po pod-demo release=canary  # 给pod添加额外的标签
    kubectl label po pod-demo release=stable --overwrite # 修改pod的已有标签 
    
    kubectl label nodes worker01 disktype=ssd
    kubectl get nodes -l disktype --show-labels
    kubectl label nodes worker01 disktype=general-disk --overwrite
    kubectl get nodes -l disktype --show-labels
    

    图1:

    图2:

    自主式pod资源对象清单常用字段

    资源清单格式:
    	一级字段:apiVersion(group/version),kind,metadata(name,namespace,labels,annotations,...),spec,status(只读)
    
    Pod资源:
    	spec.containers <[]object>
        - name <string>
          image<string>
          imagePullPolicy <string>
          	Always,Never,IfNotPresent
    	
        修改镜像中的默认应用:
        	command,agrs
    	标签:
        	key=value # key、value不能超过63个字符,且key的前缀(域名)不能超过253个字符
            	key:字母、数字、_、-、. 
                value:可以为空,只能为字母数字开头及结尾,中间可使用
    	
        标签选择器:
    		等值关系:=,==,!=
                kubectl get pods -l release=canary
                kubectl get pods -l release,app
                kubectl get pods -l release=stable,app=myapp
                kubectl get pods -l release!=canary   
    
    		集合关系:
                KEY in (VALUE1,VALUE2,...)
    			kubectl get pods -l "release in (canary,beta,alpha)"
                KEY notin (VALUE1,VALUE2,...)
                 kubectl get pods -l "release notin (canary,beta,alpha)"
    	
        许多资源支持内嵌字段定义其使用的标签选择器:
    		matchLabels: # 直接给定键值支持service,deployment,replicaSet
    		matchExpressions: # 基于给定的表达式来定义使用标签选择器,支持deployment,replicaSet
    			{key:"KEY",operator:"OPERATOR",values:[VAL1,VAL2,...]}
    			操作符:
                	In,NotIn:values字段的值必须
    
    nodeSelector <map [string]string> # 将此pod调度到节点标签为名称为disktype,值为general-disk的这一类节点上。
    
    nodeName <string>  # 将pod调度到节点名称为某个值的某个节点上。
    annotations <map[string]string>:
        	与label不同的地方在于,它不能用于挑选资源对象,仅用于为对象提供"元数据",这些元数据可能被某些程序用到,而且很重要。键值长度不受限制。
    

    pod清单示例

    apiVersion: v1
    kind: Pod
    metadata: 
      name: pod-demo
      namespace: default
      labels: # <map[string]string> 映射类型,类似于json
     	app: myapp
     	tier: frontend
      annotations: 
        master01/created-by: cluster admin
    spec:
      containers:
      - name: myapp
        image: nginx:1.20 # 使用镜像启动默认的命令
        ports: # 仅仅只是告诉我们容器内部监听的端口,并不像docker容器动态绑定到宿主机上的某个端口。
        - name: http
          containerPort: 80
        - name: https
          containerPort: 443
      - name: busybox
        image: busybox:latest 
        imagePullPolicy: IfNotPresent
        command: # ["/bin/sh","-c","sleep 3600"] # 这里使用自定义的命令,而没使用镜像启动默认的命令,就是为了防止默认命令启动之后会退出
        - "/bin/sh"
        - "-c"
        - "sleep 3600"
      nodeSelector: 
        disktype: general-disk
      #nodeName:
    
    

    k8s中command、args和docker中ENTRYPOINT、CMD的区别和联系

    dockerfile中既有CMD:运行容器时,就执行CMD命令;如果既有CMD,又有EntryPoint,CMD命令将被传送给EntryPoint作为EntryPoint的参数,被执行;
    k8s中资源清单spec.containers中的command、args参数的含义是:
    	command(<[]string>):是一个EntryPoint数组,类似于dockerfile中的EntryPoint,但是区别在于,如果要执行shell脚本,必须要在command列表中手动指定shell参数(比如/bin/sh,/bin/bash)。
    	如果没指定command,就会运行镜像中的EntryPoint,如果只指定command,镜像当中的CMD和ENTRYPOINT都没用了。
    	args(<[]string>):在k8s中作为entrypoint的参数,就是command的参数;如果没有定义args,镜像中既有CMD指令,又有ENTRYPINT指令,镜像中的CMD指令的参数将作为参数传递给ENTRYPOINT后面的代码。如果这里我们指定了args 参数,镜像中CMD后的参数将不再作为参数传递,而传递agrs中所定义的内容。
    
    

    官方对command、args同docker中ENTRYPOINT、CMD的区别联系的解释:

    Pod生命周期

    状态:
    	Pending:处于挂起状态,已经创建,但是没有适合运行它的节点(调度尚未完成)。
    	Running:运行状态
    	Failed:
    	Successed:
    	Unknown:比如,apiserver无法连接pod所处节点的kubelet(加入kubelet故障),此时所处的状态就是Unknown
    	
    pod创建所经历的阶段:用户请求创建pod时,会将请求提交给apiserver,apiserver将请求信息保存在etcd中,apiserver接下来请求scheduler调度pod,如果成功调度到某个节点,将调度的结果信息更新到etcd资源的的状态信息当中,目标节点kubelet根据apiserver当中的状态变化,发现自己有任务要完成,kubelet会通过apiserver拿到此前用户提交创建的清单,根据此清单去启动并运行这个pod,启动、运行的状态并通过apiserver返回给etcd并保存。
    	
    

    pod生命周期中的重要行为:
    1.使用初始化容器完成初始化;
    2.在主容器启动后可以做启动后钩子;
    3.容器探测
    4.在主容器结束前可以做结束前钩子;
    
    在主容器运行当中可以做容器探测:
    	liveness_probe:探测主容器是否处于运行状态;
    	rediness_probe:探测主容器中的主进程是否准备就绪并可以对外提供服务;
    不论是liveness_probe还是rediness_probe,都可以支持三种方式的探测行为:
    	1.执行自定义命令;exec
        2.向指定的TCP套接字发请求;
        3.向指定的http服务发请求;
    

    容器重启策略

    kubectl explain pod.spec
    restartPolicy # 默认是Always
    	Always:一旦容器挂了,总是重启
    	OnFailure:只有当容器状态为错误时才重启,如果是正常终止不重启(比如:在容器启动时运行一个sleep 10,在睡完10s以后,容器就是正常终止,不会重启。)
    	Never:不重启,即使容器挂了。 
    当一个容器挂了,根据重启策略,第一次重启是立即进行的,随后可能隔10s,20s,40s,80s,160s,300s去重启。当一个pod被删除时,会进行平滑的迁移,给一个宽限期(好像是30s),先给pod发送terminate信号,之后再发送kill信号,将pod杀死。
    

    1.livenessprobe容器探针

    kubectl explain pod.spec.containers
    
    
    1.livenessProbe	<Object>
    	kubectl explain pod.spec.containers.livenessProbe
        exec	<Object>
        kubectl explain pod.spec.containers.livenessProbe.exec
        	command	<[]string>
            
        httpGet	<Object>
        kubectl explain pod.spec.containers.livenessProbe.httpGet
            host	<string> # 主机名,默认是pod IP.
            httpHeaders	<[]Object> # 自定义携带的请求头
            path	<string> # uri
            port	<string> -required- # 端口号或端口名称
            scheme	<string> # 协议
    		      
        tcpSocket	<Object>
        kubectl explain pod.spec.containers.livenessProbe.tcpSocket
        	host	<string> # 默认是pod IP
    		port	<string> -required- # 端口号,或者端口号的名称
        
        failureThreshold	<integer> # 探测几次失败之后才认为是失败的,默认是3次
        periodSeconds       <integer> # 探测周期,每隔多长时间探测一次,默认是10s
        timeoutSeconds	<integer> # 探测时多长时间没有响应,确认为超时。默认是1s
        initialDelaySeconds	<integer> # 再容器启动之后的多长时间开始探测,不指定,默认是容器一旦启动,立马进行探测。但是容器启动,不代表容器内的主进程已经正常运行起来了。
        
    2.readinessProbe	<Object> # 与livenessprobe探针相似
    kubectl explain pod.spec.containers.readinessProbe
    	exec
        httpGet
        tcpSocket
    
    3.lifecycle	<Object>
    kubectl explain pod.spec.containers.lifecycle
        postStart	<Object>
        kubectl explain pod.spec.containers.lifecycle.postStart # 与livenessprobe探针相似
            exec	<Object>
            httpGet	<Object>
            tcpSocket	<Object>
            
        preStop	<Object>
        kubectl explain pod.spec.containers.lifecycle.preStop # 与livenessprobe探针相似
            exec	<Object>
            httpGet	<Object>
            tcpSocket	<Object> 
    

    1.定义一个exec的容器存活性探针

    vim liveness-exec-pod.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: liveness-exec-container
      namespace: default
    spec:
      containers:
      - name: liveness-exec-container
        image: busybox:latest
        imagePullPolicy: IfNotPresent
        command: ['/bin/sh','-c','touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 3600']
        livenessProbe:
          exec:
            command: ['test', '-e', '/tmp/healthy']
          initialDelaySeconds: 2
          periodSeconds: 3
          
    
    kubectl get po -w
    kubectl describe po liveness-exec-container
    


    2.定义一个tcpSocket的容器存活性探针

    tcpSocket探针,类似httpGet中的字段:
        host	<string>
        port	<string> -required-
    

    3.定义一个httpGet的容器存活性探针

    vim liveness-httpget-container.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: liveness-exec-container
      namespace: default
    spec:
      containers:
      - name: liveness-httpget-container
        image: nginx:1.20
        ports:
        - name: http
          containerPort: 80
        imagePullPolicy: IfNotPresent
        livenessProbe:
          httpGet:
            port: http # 基于上面定义的port名称引用
            #port: 80
            path: /index.html
          initialDelaySeconds: 2
          periodSeconds: 3
    

    进入容器liveness-httpget-container删除index.html,模拟httpget方式探针探测容器响应失败,容器的重启情况。
    kubectl exec -it liveness-httpget-container -- /bin/bash
    cd /usr/share/nginx/html/
    rm -rf index.html # 删除容器层的index.html,其实并未删除镜像层的index.html,只是对容器层的index.html文件做了隐藏
    
    当探测默认三次httpget探测,均为请求到index页面,将会在k8s默认的重启策略指定的时间时重启容器,这时,会将镜像层的index.html再次挂到/usr/share/nginx/html/目录内。。容器就可以正常运行了。
    

    2.readinessprobe容器探针

    什么是就绪的容器?
    kubectl get po # 如下图1
    其中READY列:'/' 右侧的数字表示当前pod中有几个容器,'/'左侧的数字表示有几个容器已经就绪(已经运行起来,并可对外提供服务) 
    
    service关联一组pod,当一个pod加刚入到service时,可能容器并未初始化完成,并不能对外提供服务。这时候如果没做就绪性探针,那么service代理到刚加入的pod上就无法响应客户端的请求。
    

    1.定义一个httpGet的容器就绪性探针

    vim readiness-httpget-container.yaml 
    
    apiVersion: v1
    kind: Pod
    metadata:
      name: readiness-httpget-container
      namespace: default
    spec:
      containers:
      - name: readiness-httpget-container
        image: nginx:1.20
        ports:
        - name: http
          containerPort: 80
        imagePullPolicy: IfNotPresent
        readinessProbe:
          httpGet:
            port: http # 基于上面定义的port名称引用
            #port: 80
            path: /index.html
          initialDelaySeconds: 2
          periodSeconds: 3
    
    kubectl create -f readiness-httpget-container.yaml
    kubectl get po # 如下图
    

    删除容器中的index.html页面,模拟就绪性探测失败,容器不能对外提供服务。这时service不会把流量接入到当前pod上。
    kubectl exec -it readiness-httpget-container -- /bin/bash
    rm -rf /usr/share/nginx/html/index.html
    kubectl get po # 如下图1
    kubectl describe po readiness-httpget-container # 如下图2
    

    图1:

    图2:

    再向容器中添加index.html页面,容器立即处于就绪态。
    kubectl exec -it readiness-httpget-container -- /bin/bash
    echo readiness-httpget-container > /usr/share/nginx/html/index.html
    kubectl get po # 如下图1
    kubectl describe po readiness-httpget-container # 如下图2
    

    图1:

    图2:

    3.lifecycle生命周期钩子 poststart

    busybox镜像中自带httpd服务,但是没带主页,所以当busybox启动之后可以立马通过poststart钩子发送一个请求,如果请求失败,则终止容器,并根据重启策略重启容器,直到钩子请求正常为止
    

    定义一个poststart钩子

    vim 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: ["/bin/sh","-c","echo 'Home Page' >> /tmp/index.html"]
        # command: ["/bin/sh","-c","sleep 3600"]
        command: ["/bin/httpd"] # 容器在启动之后,执行httpd,没发现/tmp下的index.html文件失败,导致容器终止,在 启动的瞬间,同时postStart钩子也执行exec,发现容器已经终止,所以创建index.html页面失败。
        args: ["-f","-h /tmp"] # -f 表示前台运行 -h 指定家目录
        
    
    场景:在容器启动之后(postStart)克隆仓库,在容器退出之前(preStop)保存数据
    
  • 相关阅读:
    【python】学习笔记10-ddt数据驱动
    【python】学习笔记10-装饰器
    【Python】学习笔记8-多线程多进程
    【Python】学习笔记7-异常处理try。。except .. as e ....else
    【Python】学习笔记6-补充Flask模块:登录接口,mysql数据库、存redis-sesson、存浏览器cookie
    【Python】学习笔记6-创建Excel:xlwt,读取Excel:xlrd ,修改Excel:xlutils
    【Python】学习笔记6-网络编程urllib,request,请求rul
    【Python】学习笔记5-利用flask来mock接口
    【Python】学习笔记5-操作redis数据库redis
    【Python】学习笔记5-模块pymysql操作mysql数据库
  • 原文地址:https://www.cnblogs.com/zhangchaocoming/p/15648059.html
Copyright © 2020-2023  润新知