K8S实战笔记--3(网络通讯模式--2 + 集群资源分类 + YAML格式 + 容器生命周期)

K8S实战笔记–2中,我们针对K8S的前身,架构,服务发现等做了详细描述,并介绍了K8S中的一种网络解决方案,此篇将在此基础上对此网络方案与其他网络模型做相应的讲解。

1. 网络解决方案

1.1 K8S + Flannel

上一篇中已对此网络模型的工作原理做了阐述,在此过程中,ETCD与Flannel的关系为:

  1. ETCD负责存储Flannel中可分配的IP地址段。Flannel在启动后会向ETCD中插入可分配的网络资源,并将分配情况进行记录,防止该网段被Flannel重新分配。
  2. 监控ETCD中的每个Pod的实际地址,并建立维护Pod的节点路由表,用于在封装数据包时提供相应的信息。

1.2 网络分层

在K8S中,网络一共被分为三层,分别为Service网络、Pod网络与节点网络。在这几层网络中,具有真实物理网卡的只有节点网络,Pod网络与Service网络都是内部网络。

2. 集群资源分类

K8S中所有内容都抽象为资源,资源实例化后成为对象。

2.1 名称空间级别

例:系统组件默认放置与kube-system下,在某一名称空间下的内容,在其他名称空间中无法被访问。

  1. workload:工作负载型资源,如PodRSDeploymentStatefulsetDaemonSetJobCronJob
  2. ServiceDiscovery LoadBalance:服务发现及负载均衡型资源,如ServiceIngress
  3. 配置与存储型资源:volum(存储卷)、CSI(容器存储接口,可以扩展各种各样的第三方存储卷)
  4. 特殊类型的存储卷:ConfigMap(当配置中心来使用的资源类型)、Secret(保存敏感数据)、DownwardAPI(将外部环境中的信息输出给容器)。

2.2 集群级别

在整个集群中都可以进行与调用的资源。
例:NamespaceNodeRoleClusterRoleRoleBindingClusterRoleBinding

2.3 元数据型

通过指标进行操作的资源。
例:HPAPodTemplateLimitRange

3. YAML格式

在K8S中,我们通过yaml格式文件来创建自定义的Pod,这类文件就是资源清单。什么是YAML?YAML是一种以数据为中心的标记语言,通常,YAML缩进时不允许使用tab键而是使用空格,这点与Python类似。在解释器中,某些时候一个tab并不等于四个空格,但使用空格的数目未作规定,只需要将同级元素左侧对齐即可。在使用#做内容的注释时,单行会被解释器忽略掉。

3.1 YAML支持的数据结构

  1. 对象:即键值对的即可,如mappinghashesdictionary等。在书写时,使用冒号隔开。且YAML也允许将所有键值对写成一个行内对象,也就是哈希。
    例:
    hash:{name:codeName,age:18}
    
  2. 数组:一组连词线开头的行,组成一个数组。
    例:
    context
    - step1
    - step2
    - step3
    
    与对象相同,数组也支持行内表示:
    context:[step1,step2,step3]
    
  3. 复合结构:由对象与数组共同构成
    例:
    context:
    - step1
    - step2
    - step3
    newContext:
    newKey1:newValue1
    newKey2:newValue2
    newKey3:newValue3
    
  4. 纯量:纯量是最基本的,不可再分的值。如:字符串、布尔值、整数、浮点数、null、日期、时间等,在YAML中,null使用~表示,不写也表示null。日期、时间采用ISO8601格式,同时,YAML也允许使用两个感叹号强制转化数据类型。
    例:
    arg:!!str 123
    
    YAML与其他语言不同的是,在使用字符串时默认不使用引号表示,但需要将包含有特殊字符的字符串包含在引号中,此时单、双引号均可,但双引号不会对特殊字符进行转义。在出现的特殊字符为单引号时,需要连续使用两个单引号进行转义。
    例:
    输入:
    str:'Pite''s thing.'
    
    解释:
    Pite's thing.
    
    在YAML文件中,有时需要书写较长的字符串,例如密钥等,为了考虑格式问题,YAML支持换行书写,如|>
    这两种换行符在使用时有些许的不同,|表示在实际解释时进行自动换行,>表示在实际解释时不进行换行,后可跟+-来规定是否需要在文末带有自动新增的空行。
    例:
    str:|-
    	code day one,
    	code day two.
    
    str:>+
    	code day one,
    	code day two.
    
    在换行符中:
    |:代表在解释中自动换行,文末新增一空行;
    |+:代表在解释中自动换行,文末新增两空行;
    |-:代表在解释中自动换行,文末不新增行;
    >:代表在解释中不换行,文末新增一空行;
    >+:代表在解释中不换行,文末新增两空行;
    <-:代表在解释中不换行,文末不新增行;

3.2 YAML中必须存在的属性

  1. version:String类型,这里指的是K8S API的版本,可以使用kubectl api-version查看;
  2. kind:String类型,用于指明YAML定义的资源类型和角色,如:Pod、Service等;
  3. metadata:Object类型,用于定义元数据对象。其中:
    • metadata.name是String类型,用于定义元数据对象的名字;
    • metadata.namespace也是String类型,用于定义其名称空间;
  4. spec:Object类型,用于详细定义对象。其中:
    • spec.containers[]是List类型,是spec对象的容器列表定义,是一个列表;
    • spec.containers[].name是String类型,用于定义容器的名字,不指明的话,会进行随机创建;
    • spec.containers[].image是String类型,用于定义要用到的镜像名称,是必须要指明的内容;
    • spec.containers[].imagePullPolicy是String类型,定义了镜像拉取的策略,有三种取值:
      • Always:是默认取值,表明每次都尝试从仓库拉取镜像,不使用本地镜像;
      • Never:表示仅使用本地镜像,没有就不用;
      • IfNotPresent:表示如果本地存在镜像,就使用本地镜像,否则从仓库拉取镜像来使用;
    • spec.containers[].command[]:是List类型,用于指定容器启动命令,不指定则使用镜像打包时使用的启动命令;
    • spec.containers[].args[]:是List类型,用于指定容器启动命令参数;
    • spec.containers[].workingDir:用于指定容器的工作目录,即进入容器时所在的目录;

其余更多属性,可以使用kubectl explain *来查看。

在排错时,可以使用kubectl describe pod *Pod名来查看Pod的信息,在确定Pod中报错的容器后,使用kubectl log *Pod名 -c *容器名来查看容器日志。在使用此命令时,若Pod中只有一个容器,则不需要参数c来指向具体容器名。

4. 容器生命周期

在启动一个容器时,Kubectl发送指令到API Server,API Server会通过ETCD将指令调度到Kubelet,Kubelet会操作CRI进行容器环境的初始化。在初始化的过程中,首先初始化用于共享网络与存储栈的容器Pause。在Pod启动过程中,init容器会按顺序在Pause初始化完成后开始启动,一个Pod中,可能会包含一个init或多个init,也可能不包含init,每个init容器都会在上一个init完成后启动,且必须运行到成功完成为止。init的作用在于,他们必须在主容器启动之前启动,可以为主容器起到一种延迟启动的效果,直到满足一组先决条件。init中可以运行一组实用工具,这些工具通常可以帮助主容器更加顺利地运行,但往往考虑到安全或冗余问题而不会出现在主容器中。若一个init启动失败,除非指定了Pod的重启策略,否则该init容器的启动操作会一直进行,直到成功启动为止,若Pod重启,所有的init必须重新运行。需要注意的是,对init容器spec的修改被限制在image字段,修改其他的字段都不会生效,但修改image字段,等价于重启Pod。

在一系列init容器启动成功后,会进入主容器的启动。在主容器启动和退出时,分别会执行启动和退出命令。在此过程中,会有Readiness进程和Liveness进程参与。Readiness即就绪检测,用于判断当前容器是否可用,在可用时将Pod状态改为Ready。若就绪检测失败,控制器将把与该Pod绑定的所有Service中该Pod的IP地址删除;Liveness即生存检测,用于检测当前容器内服务是否可用,在出现容器内服务失效的情况下控制容器删除或重启。若生存检测失败,Kubelet会杀死容器,并执行重启策略。在初始化主容器时,可以指明延迟执行就绪检测。

为了使容器状态可以被集群捕捉到,此时需要引入探针的概念。探针是一种针对容器的定期诊断,由每个node所在的Kubelet发起,通过调用如下三种Handler,来执行诊断:

  1. ExecAction:在容器内部执行指定命令,若命令退出代码为0,则诊断成功;
  2. TCPSocketAction:对指定端口上容器的IP地址进行检查,若端口打卡,则诊断成功;
  3. HTTPGetAction:对指定的端口和路径上的容器IP进行HTTP Get请求,若相应状态码大于等于200小于400,则诊断成功。

探针的返回结果,除了成功与失败外,还有一种探测无效的未知状态,在未知状态下,容器会被挂起,直到探测成功后进入就绪状态。在容器不提供探针的情况下,就绪检测与生存检测值默认为Success。

在使用kubectl get pods命令时,Pods可能出现的状态有如下几种:

  1. Pending:挂起状态。说明Pod已被K8S集群接受,但仍有一个或多个容器尚未创建;
  2. Running:运行状态。该Pod已被绑定到了一个节点上,Pod中所有容器都已被创建完成。此时Pod中至少有一个容器正在运行,或处于启动或重启状态;
  3. Succeeded:成功状态。表明该Pod中所有容器都被成功终止,且不再重启;
  4. Failed:失败状态。Pod中所有容器都已终止,且至少一个容器是因失败终止;
  5. Unknown:未知状态。在无法与Pod联络的情况下出现此状态,通常是由于通信失败引起的。

那么如何为Pod配置初始容器呢?我们可以先定义一个Pod,在详细描述中定义初始容器并为其配置需要执行的命令。在如下案例中,我们在初始容器中配置了使用wget命令下载页面内容的功能,其中busybox镜像为容器提供了精简的Linux命令支持,保证了初始容器的轻便性与可用性。

apiVersion: v1
kind: Pod
metadata:
  name: init-demo
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
    volumeMounts:
    - name: workdir
      mountPath: /usr/share/nginx/html
  initContainers:
  - name: install
    image: busybox
    command:
    - wget
    - "-O"
    - "/work-dir/index.html"
    - www.baidu.com
    volumeMounts:
    - name: workdir
      mountPath: "/work-dir"
  dnsPolicy: Default
  volumes:
  - name: workdir
    emptyDir: {}

使用kubectl exec命令进入容器内部,对nginx发送一个get请求,可以看到获取到的页面内容。

<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn"></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=http://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');</script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>&copy;2017&nbsp;Baidu&nbsp;<a href=http://www.baidu.com/duty/>使用百度前必读</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a>&nbsp;京ICP证030173号&nbsp; <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值