k8s的组件

258 阅读11分钟

pod

pod之间的隔离

pod中所有容器都在相同的network和UTS命明空间下进行,所以他们共享相同的主机名和网络接口 通向他们也在相同的ipc命名空间下运行,因此可以通过ipc进行通讯,在最新的k8s的docker版本中 他们也能够在相同的pid命名空间下,也就是进行id递增,但是该特征默认是未激活的

pod的容器之间共享ip和端口注意点

  1. 因为他们共享,所以要注意端口冲突的问题
  2. 他们可以通过localhost进行和其他容器进行通讯

如何决定在pod中使用多个容器

  1. 他们需要一起运行还是可以在不同的主机上运行
  2. 他们代表的是一个整体还是相互独立的组件
  3. 他们必须一起进行扩缩容还是可以分别进行

pod的定义的主要部分

  1. metadata 包括名称,命名空间,标签和关于该容器的其他信息
  2. spec 包括pod的内容的实际说明,例如pod容器卷和其他书籍
  3. status 包括运行中的pod的当前信息,例如pod所处的条件,每个容器的描述和状态,以及内部ip和 其他版本信息,自己写yaml基本不用写status中的内容

一些命令

  1. kubectl get po -l <key=value>
  2. kubectl get po -l
  3. kubectl get po -l '!'

nodeSelect

nodeSelect可以让pod选择被调度到那个node上

注解

注解和标签很相似,但是注解主要用作工具使用,当k8s引入新功能的时候,通常会用 注解,而不是向api对象引入任何新字段

命名空间

尽管命名空间让各个对象彼此之间分离,但是这种分离只是在操作层面分离,具体的对象运行还是没有、 分割的,具体想要分离还要看k8s的网络方案来提供不同命名空间进行网络分离

存活指针

  1. http get返回2xx或者3xx代表探测成功
  2. tcp套接字指针,尝试建立连接,建立成功代表探测成功
  3. Exec探针,会检查命名执行的退出状态码,状态码返回0代表成功

存活指针的目的是探测pod是否存活,不存活就会根据控制器来保持pod的数量和配置上的数量想等

然后存活指针肯定可以进行配置容器启动多久后进行探活(initialDelaySeconds)

然后存活指针肯定可以配置容器没多久执行一次(periodSeconds)

然后还有成功阈值和失败阈值(successThreshold) (failureThreshold)

存活指针应该尽可能不占用计算资源,他只应该返回特定成功或失败,而不应该让他来进行计算各种东西,内部是否失败成功,因该又内部来进行更新,然后再探针中不应该实现重试循环,因为k8s自己会尝试多次

ReplicationController

  1. ReplicationController只是查询某种标签的pod,然后保证这个pod的数量和ReplicationController配置文件上设置的数量一致,然后用户额外操作pod不会又什么影响,ReplicationController只是判定label

  2. 注意ReplicationController的yaml中的select和template的label要一直,要不然会一直死循环

  3. 修改模板的时候,ReplicationController不会更新pod而需要你去删除对应的pod, 这样才会进行重新创建, 因为ReplicationController只是监听label

  4. kubectl delete rc kubia --cascade=false 这样会继续保持Pod的运行

ReplicaSet

  1. ReplicaSet和ReplicationController基本一样,只有select这一块不一样,ReplicaSet使用matchLabels来进行选择,这个选择器可以支持复杂点的选择

DaemonSet

DaemonSet目的是让pod再每个node节点上运行,也可以使用nodeSelect来让pod再指定的label的Node上执行

job

job其实就是执行一个pod只是这个pod不会重启,然后可以配置并发的job数量,和运行的job数量,还有设置job完成时间

cronjob

就是带有cron表达式的job,可以设置再什么时候执行

service

service的prot代表暴露的端口,targetprot代表对应容器的端口,然后用select标签来选择代理的容器,其实真正的service后面会创建endpoint来进行连接,而不是直接去查询pod

service的会话亲和性(sessionAffinity)只能是clientIp和none, 只能代理来自同一个client ip的请求转发至同一个pod上,为啥支持不了cookie的亲和性,因为service只是tcp和udp层的服务

然后一个服务可以暴露多个端口,prots多个-name就行

service的targetPort最好使用端口名,对应的名称可以再pod中用containerPort来进行定义,这样pod的端口变更了,service的端口不需要变更

服务发现

如果service再pod之前执行,pod的环境变量中就有服务的ip地址和端口号

通过dns来进行服务发现,pod在知道service的名称的情况下可以通过全限域名(FQDN)来访问,<service名称>..svc.cluster.local, 但是主要客户端仍需要知道服务的端口号,如果pod在同一个namespaces下,可以省略svc.cluster.local,甚至命名空间

然后无法ping通服务ip的原因,因为服务的ip只是一个虚拟的ip,具体流向是被iptable进行拦截,交给kube-proxy进行代理

想要代理到外部服务,可以自己进行创建endpoint然后service没有选择器就行了,然后可以在service上定义externalName来设置别名,然后pod可以通过FQDN来进行访问,

将服务暴露给外部客户端

  1. type: nodeport 给service设置nodeprot, 该服务仅在内部集群ip和端口上才可访问,也可以通过所有节点上的专用端口访问
  2. type: loadBalance 通过loadBalance,这是一种nodeport的扩容,使得服务可以通过一个专门的负载均衡器来访问,这是一些晕厂商的云基础设施提供的
  3. 创建ingress资源进行访问

externalTraficPolicy来定义local,使得获取到的请求就在当前Node的pod中处理,这样防止不必要的网络跳数,但是有可能node上没有对应的pod造成404

ingress需要一个对应的组件,然后创建对应的ingrees来配置对应的域名访问那个service的那个端口,其实就是一种负载均衡,ingress在云服务器上运行的时候会获取一个ip,不是云服务器的时候可能要自定义loadBalance

就绪指针

就绪指针是定义pod在启动后,是否能进行接收服务的请求,和存活指针相似,也有3种类型

headless

headless的意思就是使用service去发现所有的pod ip也就是和所有pod进行连接,而不是进行负载均衡,对应的service clusterIp: none就行,使用FQDN进行查询的时候,handless返回的是所有pod的ip,而普通service返回的是service的ip(集群的ip)

pv和pvc

持久卷和持久卷声明,持久卷声明中的声明大小和访问模式要有对应的持久卷对应,然后持久卷是集群范围的东西 而持久卷声明是命名空间下的东西,所以pod只能在指定的命名空间中使用

删除持久卷声明和对应pod后,对应的pv并不会回收,当然你可以设置成自动回收,但是最好的方式是自己决定是否删除,然后gce硬盘是没有recycle这个选项的

然后pvc上的storageClassName: ""应该设置成这个,这样才会自动去寻找pv要不然可能回去storageClass申请自动分配

StorageClass

StorageClass是一种自动分配pv的程序也是一种集群上的资源没有命名空间,当声明的pvc中指明对应的sc的时候,他就会自动创建一个pv

docker的cmd和entrypoint

cmd和entrypoint其实都可以作为启动命令,但是一般cmd是最为传入的参数,而entrypoint作为启动命令 entrypoint有2种模式一种是shell一种是exec, 其中shell启动的结果是容器中的pid为1的命令是shell, 而exec是 直接运行

comand和args

使用comand可以覆盖docker中的entrypoint,使用args可以覆盖docker中的cmd

env

在pod中可以设置env来为容器配置环境变量,当然环境变量中可以引用其他环境变量

configmap

configmap可以从文件来导入也可以直接进行配置,从文件导入,其文件名就是key而value就是文件的内容,直接配置的话就是自定义的key和value, 然后从文件夹导入也就代表着配置多个key和value

configmap可以作为env的挂载,使其配置作为env的形式挂载到容器中。configmap也可以作为一种卷的形式,让容器可以作为存储的形式挂载到目录中,而作为文件夹然后配置对应文件可以单独挂载一个文件,然后还可以挂载整个目录,挂载整个目录的时候,configmap更新,pod对应也会被热更新,但是挂载单个文件好像不会

configmap可以挂载为env,然后再args中使用这个挂载的env

当容器引用了不存在的configmap的时候这个容器不会被启动,然后可以配置容器可以不强制依赖这个configmap

secret

secret和configmap用法差不读,只是secret的内容都是base64加密的,然后secret都是再内存中,然后secret最大不能超过1mb

dowanward api

该api是为了让pod中的容器知道自己的一些信息,可以通过env或者mount的形式获取,然后注意这里的api挂载的时候有些是container的不是pod中的,所以要指定container的名称,有个问题是,当更新了pod中的内容的时候,对应用env挂载api不会给更新,而用file挂载的api会热更新,所以推荐用file进行挂载

deployment

  1. deployment是一种更高层的对象,他进行控制replicaSet来创建pod,创建的rs会有一个hash的名称
  2. deployment滚动更新只需要更新其yaml就行了,然后deployment会自行滚动升级,当然可以通过设置不使用滚动升级(RollingUpdate)而直接进行停止所有pod然后升级(recreate)
  3. kubectl rollout status deployment 来查看整个升级过程
  4. kubectl rollout undo deployment 来停止滚动升级
  5. kubectl rollout history deployment 来展示滚动升级的日志
  6. kubectl rollout undo deployment --to-revision=1 直接回滚到指定的版本,所以不要手动删除deployment创建的rs
  7. maxSurge(除了副本数外,最多超出多少个)和maxUnavailable(最多少个副本处于不可用)进行设置滚动升级的速率
  8. kubectl rollout pause deployment 暂停滚动升级,可以用于观察
  9. kubectl rollout resume deployment 恢复滚动升级
  10. minReadySeconds 这个用于指定pod运行至少成功多少时间才继续进行滚动升级,所以pod最好配置就绪指针,当这2个都配置了后,即使一个升级容器初始化完了,但是他不就绪后续也不会继续升级,deployment有个progressDeadlineSeconds用于设置当滚动升级多久没成功会进行自动取消滚动升级(目前版本好像还没支持设置,默认是10min)

statefulset

statefulset对应创建的对象名称是一次递增的,当扩容和缩容的时候也是递增的,当删除其中一个pod的时候,然后再创建会填充之前删除的pod而且名称是相同的,statefulset创建的存储卷是各自分离的,而不是pod之间公用,所以对应的存储卷也是相同的

当创建headless service的时候会给statefulset创建一个srv记录来指向pod主机

通过dig srv .namespaces.svc.cluster.local可以进行查看对应所有statefulset主机

statefulset像replicaset一样,不会滚动升级,而是要手动操作

statefulset上节点出现问题的时候,比如节点出现网络故障,pod不能汇报状态,这时候statefulset删除pod是不会起作用的,这时候只是主节点标明这个节点是删除,而实际还需要对应的节点进行删除后才能更新,所以这时候可以进行标明强制删除pod而不用管node上对应的节点