k8s随笔
持续更新一些k8s遇到的错误和基础知识
kubelet
1. system.slice相关
cpu/system.slice,memery/system.slice内的资源分别对应SystemReserverd预留的cpu,memery资源
例如no space in device:定义的预留资源太小(一般会导致节点notReady)
no device:没有定义对应的预留资源(在enforceNodeAllocatable显式规定要为某些组件预留资源但是没有定义对应的预留资源)(一般会导致需要分配资源的pod异常)
2. pause容器
每个pod都有pause容器,作用是为pod的所有容器共享网络和linux命名空间。
1.pause容器将 一个pod所有的容器收纳到 一起。
2.pause容器是 一个基础容器, 它的唯 一 目的就是保存所有的命名空间。
3.所有pod的其他用户定义容器 使用pod自己的pause容器的命名空间
3. pod的生命周期对业务容器的影响
无论任何原因将pod的status标注成*(unknown、…),最后因为无法恢复,这个 pod 就会自动从节点上驱逐。这是由controller-manager)处理的 。 它通过删除 pod 的资源来把它从节点上驱逐。
1.整个流程pod的状态是Running-*-Terminating
2.但是对于里面的容器而言,只要pod没有被真正地删除,容器还是一直运行着,占用资源,提供服务.
kube-apiserver
1. watch
close to connection,watch失败,是否可以加一条显式关闭连接的操作保证下一次不再使用旧连接?
这个问题已经通过1.14修复go语言net包解决。具体详情看issue
https://github.com/kubernetes/kubernetes/issues/87615
2. 访问apiserver获取更多数据
敲kubect cluster-info获取apiserver访问地址
如果apiserver是https且单向认证,可以通过curl -k跳过服务端证书校验
如果apiserver是https且双项认证,要带认证参数–cacert/-k,-cert,–key!
$ curl --cacert /etc/kubernetes/pki/ca.crt --cert /etc/kubernetes/pki/apiserver-kubelet-client.crt --key /etc/ubernetes/pki/apiserver-kubelet-client.key https://172.17.0.7:6443/api/v1/namespaces/kube-system/pods/coredns-66bff467f8-5b7xh|more
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 9167 0 9167 0 0 596k 0 --:--:-- --:--:-- --:--:-- 596k
{
"kind": "Pod",
"apiVersion": "v1",
"metadata": {
"name": "coredns-66bff467f8-5b7xh",
注意:在真实的应用中, 永远不要跳过栓查服务器证书的环节(不要-k)。 这样做会导致你的应用验证凭证暴露给采用中间人攻击方式的攻击者
3. kubectl proxy连接apiserver
同样是客户端用curl ,之所以存在kubectl proxy的功能是因为双向认证直接访问apiserver时要带认证参数–cacert/-k,-cert,–key太繁琐,而使用kubectl proxy之后,通过使用kubectl.kubeconfig的认证方式,即使用kubectl的用户和认证去访问apiserver,把认证完全交给kubectl的配置,客户端只需要考虑curl的目标资源即可。(当然需要Kubectl的用户的资源权限足够多)
curl http://localhost:8001/api/v1/namespaces/kube-system/pods/coredns-66bff467f8-5b7xh|more
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 9167 0 9167 0 0 497k 0 --:--:-- --:--:-- --:--:-- 497k
{
"kind": "Pod",
"apiVersion": "v1",
"metadata": {
"name": "coredns-66bff467f8-5b7xh",
// 另一个终端
controlplane $ kubectl proxy -v 10
I0906 09:05:58.706913 13342 loader.go:375] Config loaded from file: /root/.kube/config
Starting to serve on 127.0.0.1:8001
// 访问pod资源,目标资源不变,从代理url转发到apiserver url
I0906 09:06:13.258789 13342 proxy_server.go:88] /api/v1/namespaces/kube-system/pods/coredns-66bff467f8-5b7xh matched ^.*
I0906 09:06:13.258996 13342 proxy_server.go:88] localhost matched ^localhost$
I0906 09:06:13.259098 13342 proxy_server.go:128] Filter accepting GET /api/v1/namespaces/kube-system/pods/coredns-66bff467f8-5b7xh localhost
I0906 09:06:13.259195 13342 upgradeaware.go:253] Request was not an upgrade
I0906 09:06:13.259345 13342 round_trippers.go:423] curl -k -v -XGET -H "User-Agent: curl/7.58.0" -H "Accept: */*" -H "X-Forwarded-For: 127.0.0.1" 'https://172.17.0.7:6443/api/v1/namespaces/kube-system/pods/coredns-66bff467f8-5b7xh'
I0906 09:06:13.271318 13342 round_trippers.go:443] GET https://172.17.0.7:6443/api/v1/namespaces/kube-system/pods/coredns-66bff467f8-5b7xh 200 OK in 11 milliseconds
I0906 09:06:13.271342 13342 round_trippers.go:449] Response Headers:
I0906 09:06:13.271351 13342 round_trippers.go:452] Content-Type: application/json
I0906 09:06:13.271361 13342 round_trippers.go:452] Date: Sun, 06 Sep 2020 09:06:13 GMT
4.访问pod中的容器通过端口暴露的应用的几种curl方式
- 进入另一个容器B中curl这个容器A的ip:containerPort
- 进入另一个容器B中curl这个容器A的clusterIP服务clusterIP:servicePort(负载均衡,有概率访问到A)
- 进入另一个容器B中curl这个容器A的NodePort服务NodeIP:NodePort(负载均衡,有概率访问到A)
- 在有kube-proxy的节点curl这个容器A的ip:containerPort
- 在有kube-proxy的节点curl这个容器A的NodePort服务NodeIP:NodePort
- 访问apiserver代理url访问容器A的selfLink,会访问到容器A第一个端口暴露的应用。
所谓的代理url就是在普通访问的基础的最后加上/proxy/
$ curl --cacert /etc/kubernetes/pki/ca.crt --cert /etc/kubernetes/pki/apiserver-kubelet-client.crt --key /etc/ubernetes/pki/apiserver-kubelet-client.key https://172.17.0.7:6443/api/v1/namespaces/kube-system/pods/coredns-66bff467f8-5b7xh/proxy/
//如果开启了Kubectl proxy
$ curl localhost:8001/api/v1/namespaces/kube-system/pods/coredns-66bff467f8-5b7xh/proxy/
//最后一个/可以用-L转发替代
$ curl -L --cacert /etc/kubernetes/pki/ca.crt --cert /etc/kubernetes/pki/apiserver-kubelet-client.crt --key /etc/ubernetes/pki/apiserver-kubelet-client.key https://172.17.0.7:6443/api/v1/namespaces/kube-system/pods/coredns-66bff467f8-5b7xh/proxy
但是,必须保证这个容器暴露的端口的应用是有响应的,否则会报错connetion refused。
此处是dns容器,容器启动命令是启动corddns,没有响应,所以最终会报错。
搞清楚代理的原理之后,是不是可以提个pr优化一下?遍历所有的端口???
7. 访问apiserver代理url访问容器A的Headless服务,随机访问到容器A,会访问到容器A第一个端口暴露的应用
5. downward api
1.定义pod级元数据
Downward API的方式并不像REST endpoint那样需要通过访问的方式获取数据。 这种方式主要是将在该pod的定义(已经定义的pod的蓝图,manifest)和状态中取得的数据作为该pod的容器环境变量(和downwardAPI卷,挂到容器内就是文件形式了,key,value分别是文件名和文件内容)的值
例如:
env:
- name:POD_NAME
value_from:
fieldRef:
fieldPath: metadata.name
- name: CONTAINER CPU REQUEST MILLICORES
valueFrom:
resourceFieldRef:
resource: requests.cpu
divisor: 1m #基数,如果定义了requests.cpu是100m,则容器暴露的值=100
2.不能通过环境变量的方式暴露label 和annotation,只能通过downwardAPI卷(不能通过环境变量的方式暴露标签和注解,在环境变量方式下,一旦标
签和注解被修改,在pod运行时新的值将无法暴露)
volumes:
- name: downward
downwardAPI:
items:
- path: "labels"
fieldRef:
fieldPath: metadata.labels
- path: "annotations"
fieldRef:
fieldPath: metadata.annotations
3.暴露容器级元数据,在downwardAPI卷数据定义时指定容器名,(env书中说只能暴露自身容器的元数据,没测试到底是否可行)
resourceFieldRef:
containerName: main #容器名
resource: requests.cpu
divisor: lm
4.使用卷的方式暴露容器元数据更加复杂,但好处是在同一个pod中,可以向一个容器暴露另一个容器的元数据
5. downward api的另一个优势
当用ds启动pod且有一个环境变量的值是可变的,例如需要取nodeIP,此时就可以直接传元数据/挂configmap卷/挂secret卷/挂文件
如calico-node pod,ipv4且非auto-detect时IP环境变量
6. pod内部curl访问apiserver简化
pod内部访问apiserver
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
NS=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
CACERT=NS=$(cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt)
//访问:
curl --cacert $CACERT -H "Authorization: Bearer $TOKEN" \
https://kubernetes/api/v1/namespaces/$NS/services
注意:如果启用了RBAC访问控制权限,默认serviceaccount只是部分授权,真实授权或者绕过RBAC:
kubectl create clusterrolebinding permissive-binding\
--clusterrole=cluster-admin\
--group=system:serviceaccounts
7. 操作api的几个动作
kubernetes使用restful风格api
CRUD代表创建、 读取、 修改和删除操作, 与之对应的HTTP方法分别是POST、 GET、 PATCH/PUT以及DELETE
若PATCH,curl时传入相应的-X patch 等等
强制删除:告诉 API 服务器不用等待 kubelet 来确认这个 pod 己经不再运行,而是直接删除它
delete … – force --grace period 0
8. ambassador 容器模式访问apiserver
启动 一个ambassador容器,并在其中运行kubecctl proxy命令, 通过它来实现与API服务器的交互
原理:
1.通过HTTP协议(不是HTTPS协议)与ambassador连接, 并且由ambassador通过HTTPS协议来连接API服务器
2.在同 一 个pod中的所有连接共享同样的回送网络接口, 所以我们的应用可以使用本地的端口来访问代理
service
1. NodePort服务不通
服务创建了,pod创建了,端口暴露和对应关系都是正确的,但是有时候访问别的节点+端口没法得到回复,因为那个节点的内核参数设置了net.ipv4.tcp_tw_recycle=1,tcp连接很快被释放。
2. 客户端典型的访问k8s内pod的方式
pod 由 ReplicationController 或ReplicaSet 来创建和管理的,并且创建pod的服务暴露pod;客户端(运行在其他 pod 或外部的客户端程序)通过 Service 访问 pod
3. 可以使用 kubectl set selector 命令来修改 Service 的 pod 选择器
4.有状态服务和无状态服务的区别
无状态服务,后端对应rc、rs控制器的副本
每次请求都包含所有信息,跟上一次没关系,例如:浏览网页
有状态服务,后端对应sts控制器的副本
每次请求需要使用上一次的请求上下文,例如:网络游戏
5.为什么需要服务
pod用后即焚,ip地址经常变化。但是服务的ip不变化。
6.集群内访问服务
1.访问服务的clusterIP
2.访问服务的域名,如果不同namespace下的pod访问服务,需要在域名后加**.namespace**
7.headless服务作用
clusterIP=none
nslookup解析服务域名会返回所有的后端pod真实ip,而不是服务的ip,从而用户可以选择自己想连哪一个pod
【nsloopkup的代码截图】
常用于sts有状态服务,因为sts的pod的ip是不变的,从而用sts + headless创建出来的服务,后端pod的名字、ip也不变,这样sts各个pod就可以直接通过pod名字/ip来访问,并且不用担心pod用后即焚的问题。。
资源
1. 某kubelet异常引起副本异常时,三类副本控制器的动作
模拟kubelet notReady(down网卡或者关机或者stop kubelet)
rc、rs(无状态副本控制器):
老副本卡在terminating状态,但是会在别的节点创建新的rc、rs副本
sts(有状态副本控制器):
老副本卡在terminating状态,不会在别的节点创建新的sts副本,直到kubelet自愈。
(同样是没法更新apiserver的信息,为什么rc、rs就能创建出新副本,sts不行?难道是kubelet异常前就更新了自身的信息吗?)
rc、rs、sts共同点:
只要kubelet仍然异常,旧的pod依然在Terminating状态。老的业务容器依然起作用。
2. configmap、secret、downwardAPI卷共同点:
defaultMode属性来改变文件的访问权限设置
3. kubernetes服务
在pod的容器内,因为kubernetes这个服务的endpoint后端就是apiserver,所以在容器内部,他也相当于能给apiserver做负载均衡!无需获取后端真实apiserver实例
4. pod基本概念
1.pod内共享存储卷,共享网络资源(共享podIP)
2.pod内一般是相互配合的容器, pod 之间相互通信 。 这正是微服务化:将一个大规模系统拆分成各个独立运行的组件(pod是k8s集群组成最小单位)
选择多进程+单容器模式 还是单进程+多容器模式来构建pod?
3. 用后即焚,不可自愈,伸缩。
5.label和annotation区别
都是metadata字段的对象
label:
和对象密切相关的信息,用于支持nodeSelector
annotation:
非识别信息
6. rc的滚动升级(已过期)
使用kubectl开始ReplicationController 的滚动升级
kubectl rolling-update kubia-vl kubia-v2 --image=luksa/kubia:v2
将新的副本控制器命名为kubia-v2,并且其初始期望的副本数被设置为0->添加额外的 deployment 标签->伸缩这两个rc,副本逐渐转移新rc上(如果业务做了区分,持续通过svc访问业务可以看到区别)
缺陷:
1.伸缩的请求是由 kubectl 客户端执行 的 ,而不是由 Kubemetes master 执行的。(kubectl --v=6 可以看到)这意味着如果网路连接中断了,升级失败卡在中间状态且无法恢复
2.Kubemetes 是通过不断地收敛达到期望的系统状态的,希望给出一个副本数来伸缩副本而不需要手动增删。在升级应用程序时, 需要引入 一个额外的ReplicationController, 并协调两个 Controller, 使它们再根据彼此不断修改, 而不会造成干扰
为什么推荐rs替代rc?
rs有基于集合的标签选择器,功能更强大,不局限于nodeSelector
7. Deployment的滚动升级
滚动升级,rs-》rs,至少有两类rs才能转移,使用不方便,所以创建了deploy用于管理rs。(或者称调和)
Deployment比rs更高一阶,虽然都是声明式。使用Deployment可以更容易地更 新应用程序,因为可以直接定义单个Deployment资源所需达到的状态,并让Kubemetes处理中间的状态。
当使用apply-》自动创建新rs,通过升级策略(one by one 或者delete all and create)将流量转移到新的pod上
对于服务后端的pod,那当然是一个接一个升级好,防止访问中断,保证可用性。
对于类似网络插件这类pod,不清楚,再看看吧。
8.sts基本概念
1.sts 扩容/缩容,按照序号升序/倒序依次创建/删除pod
2.创建sts资源需要有前置service
3.相同序号的pod,重建之后分配的ip改变,pod名字不变
- 支持固定的网络标识。
nslookup查询sts前置服务service域名查看后端该服务真实地址,返回的后端是所有的pod的ip,而不仅仅是这个服务的真实ip。由特点3可知,nslookup查询服务后端实例,address不变,之后后端pod ip变了。
[图]
意味着使用sts的服务可以一直沿用同一个后端域名保证通信稳定。
5.支持持久化存储,删除sts不会删除pvc
其他的副本控制器可支持持久化存储,rc、rs用完就删掉不好吗?
6.升级策略
rollingUpdate
滚动升级,逆序,删除老pod,创建新pod,删除老pod… …
OnDelete
先主动删除老pod才能触发pod更新 - 为什么一般都用动态pvc sts.spec.volumeClaimTemplates而不直接用sts.spec.template.spec.volumes声明sts的pod存储?
由于sts的pod本身是有序,需要体现出存储的有序,所以一般通过pvc关联到某一个只允许绑定一次的pv,并且这个pvc会跟pod一样,名称带序号。
6.sts是怎么使用pv,pvc的?
通过pvc sts.spec.volumeClaimTemplates,声明pvc和StorageClass,自动创建并绑定有序的pv。
9.声明式资源的组成
1.metadata:基础信息/元信息,描述pod的名字,命名空间(逻辑隔离)pod id等等
3. spec:期望状态信息(用户定义,资源创建时自动更新,对象存储后不再变化),控制器会把spec转化成现实
4. status:实际状态信息(k8s自动定义,会自动更新),是各个组件通信的渠道;通过status的信息,各个组件可以对资源状态信息进行更新
10.副本控制器几种扩缩容(扩缩副本)的方式
假设原副本只有3个
1.kubectl scale web-demo -n demo --replicas=5
2.kubectl edit web-demo -n demo
修改reolicas字段
3.修改蓝图(原yaml/json文件的replicas字段),然后kubectl apply
11.configmap和secret进行pod配置管理,敏感数据传递
存储简单键值对或者多行文本
1.pod和configmap在同一个ns,
2.cm先于pod创建,因为要先挂载
3.可以挂在cm某个key或者挂载整个cm;使用时,可以向环境变量注入cm某个key或者注入cm所有key
四种用法例子
4.挂到pod的cm文件是一个软连接,kubelet定时更新cm,将软连接指向最新的cm
例子
secret:
1.数据默认都是用base64加密,在stringData下的数据不会被base64加密
2个例子
总结:
1.通过环境变量注入的cm,kubelet无法感知更新,只能更新挂载的cm。
2.还没实现更新业务容器中使用的cm
(这个不正是confd的功能吗?)
3.业务容器的工具 使用 工具自身支持重载,例如nginx -s reload
4.开源项目reloader watch cm,secret,一旦发现对象更新,就出发deploy / sts等副本控制器的滚动升级
12.ds资源
deploy,sts负责无状态有状态服务,而ds从另一个方面提供基础服务。
- 监控各个节点的状态且副本数总是1;节点数目发生变化,希望快速拉起/删除1个副本
- 常用场景:
- 监控节点状态
例如node-problem-detector - 监控数据收集,上报给promethus
- 日志收集轮转和清理
- 网络插件,存储插件等
glusterd,ceph,flannel
- 通过nodeSelector的matchlabel决定哪些node调度pod这个阻塞阶段
- 怎么调度?
早期k8s版本,因为pod一早就写入了spec.NodeName,所以不会经过默认调度器,即不会经过pending等待调度,引起了跟别的pod不一致的行为,引起一系列的特例问题。
现在不会预先写入spec.NodeName,而是通过写入节点亲和性nodeAffinity,由默认调度器进行调度。 - 更新策略
- RollingUpdate
自动滚动更新,可以定义pod升级步长等等 - OnDelete
必须先手动删除原有pod,触发新pod生成
存储
1. k8s和docker的volume设计有什么不同?
k8s:pod内容器共享volume,生命周期跟pod挂钩,pod被删除才会被解绑。
docker:volume跟容器挂钩
2. 常用的vloume插件(volume-plugin)
configmap:
secret:
downwardapi:
emptyDir:pod被删除一同被删除,临时储存,存储临时结果
hostPath:持续储存数据,避免容器恶意修改宿主机内容弄,或者恶意占用存储,打包宿主机。
3. 为什么k8s不再接收内置volume-plugin,转而推荐通过csi(container-storage-interface)容器存储接口使用/拓展存储插件?
因为内置volune插件所有代码都需要放到k8s源码,k8s代码库变得臃肿,并使得代码必须开源,每次新拓展一种volume插件就要升级k8s。但是使用csi,将实现了的存储插件提前放到宿主机的指定目录即可。
目前社区开发的csi无感迁移在1.17已经bata了。
configmap也可以通过csi使用吗?怎么用?
4.pv,pvc的需求
直接把存储细节声明到pod的模板不安全,并且使用门槛高,因为不同厂商开发的存储的声明各不相同。所以抽象出一个pvc,通过pvc关联到实际存储的pv绑定到pod中。跟其他volume一样,通过pvcname绑定到容器中,降低了使用门槛,减少实际存储细节的暴露。
5.静态,动态pv使用区别
静态:
提前定义pv,无法动态按需创建,然后通过声明pvc关联pv,最后在pod声明该pvc
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0003
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: slow
mountOptions:
- hard
- nfsvers=4.1
nfs:
path: /tmp
server: 172.17.0.2
# 通过pvc声明到pod
动态:
通过声明使用StorageClass的pvc。创建pod,关联pvc时,通过StorageClass的provisioner创建指定类型的pv
# 可以将StorageClass耦合到pvc,例如sts的volumeClaimTemplates
# 也可以先单独定义StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: gluster-vol-default
provisioner: kubernetes.io/glusterfs # 必填项,指定volume plugin创建pv
parameters:
resturl: "http://192.168.10.100:8080"
restuser: ""
secretNamespace: ""
secretName: ""
allowVolumeExpansion: true
双向认证
tls认证是什么
安全传输层协议(TLS)用于在两个通信应用程序之间提供保密性和数据完整性。该协议由两层组成: TLS 记录协议(TLS Record)和 TLS 握手协议(TLS Handshake)
1.客户端ca校验服务端server.crt
应用应该验证 API服务器的证书是否是证书机构所签发
2.服务端ca校验客户端认证,即token,证书等等
应用应该将它在token文件中持有的凭证通过Authorization标头来获得 API服务器的授权
3.集群需要的几种双向认证(Mutual TLS)证书
单向tls只需要传ca.crt去校验服务端证书*-server.crt,*-server.key,
双向tls,服务端也需要用ca.crt去校验客户端身份;
简单来表达:
双向认证中,只看待客户端访问服务端这一方向:
etcd集群之间互相访问时需要
ca-etcd.crt,etcd-client,etcd-server
apiserver作为服务端,kubelet,controller,scheduelr,proxy访问apiserver时需要
ca.crt,apiserver-server,kubelet-client,controller-client,scheduelr-client,proxy-client
kubelet作为服务端,apiserver访问kubelet时需要
(ca.crt,)kubelet-server,apiserver-client
一般简单地,k8s组件之间的ca.crt用同一个,etcd的的ca跟k8s的ca不同。用于区别是两个不同类型的集群。.crt证书总数是(11crt=2ca+3server+6client)
//单向认证需要的.crt为:
ca-etcd,ca,etcd-server,apiserver-server,kubelet-server
//有时候apiserver访问kubelet根本不认证,即
ca-etcd,ca,etcd-server,apiserver-server
另外,开启apiserver聚合层,使用拓展api也需要证书进行tls认证,这属于第三个ca机构
service account可以用第四个ca机构进行sa token的签发,反正我是沿用k8s组件之间的ca.crt
一些metric指标也可能需要证书认证(普罗米修斯吗?这个还不太了解啊!)
管理工具
命令行客户端kubectl
- 使用详细日志模式-v=*运行其他 kubectl 命令, 将会看到 kubectl 和 API服务器之前的更多通信细节。
$ kubectl get no -v=8
I0906 05:41:16.948137 14461 loader.go:375] Config loaded from file: /root/.kube/config
I0906 05:41:16.954398 14461 round_trippers.go:420] GET https://172.17.0.63:8443/api/v1/nodes?limit=500
I0906 05:41:16.954554 14461 round_trippers.go:427] Request Headers:
I0906 05:41:16.954637 14461 round_trippers.go:431] Accept: application/json;as=Table;v=v1beta1;g=meta.k8s.io, application/json
I0906 05:41:16.954780 14461 round_trippers.go:431] User-Agent: kubectl/v1.17.3 (linux/amd64) kubernetes/06ad960
I0906 05:41:16.965563 14461 round_trippers.go:446] Response Status: 200 OK in 10 milliseconds
I0906 05:41:16.965598 14461 round_trippers.go:449] Response Headers:
I0906 05:41:16.965605 14461 round_trippers.go:452] Content-Type: application/json
I0906 05:41:16.965610 14461 round_trippers.go:452] Content-Length: 3805
I0906 05:41:16.965614 14461 round_trippers.go:452] Date: Sun, 06 Sep 2020 05:41:16 GMT
I0906 05:41:16.965678 14461 request.go:1017] Response Body: {"kind":"Table","apiVersion":"meta.k8s.io/v1beta1","metadata":{"selfLink":"/api/v1/nodes","resourceVersion":"4322"},"columnDefinitions":[{"name":"Name","type":"string","format":"name","description":"Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names","priority":0},{"name":"Status","type":"string","format":"","description":"The status of the node","priority":0},{"name":"Roles","type":"string","format":"","description":"The roles of the node","priority":0},{"name":"Age","type":"string","format":"","description":"CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. I [truncated 2781 chars]
NAME STATUS ROLES AGE VERSION
minikube Ready master 30m v1.17.3
编程式客户端client-go
包管理工具helm3.0
意义
helm降低了k8s使用的门槛,部署一个应用,无需手动生成部署文件,甚至不需要了解k8s部署文件语义和k8s对象。
例如:
以前部署完一个应用,部署文件没有被管理保存起来,只能通过edit,sacle等命令方式修改,很难把yaml找回来修改后apply。
想找一个应用pod的yaml,通常要自己重头开始定义,但只要引了开源repo,只要里面有应用chart,就能直接下载安装了。
2020 4月 已经在CNCF GA了。说明使用的问题不大。
基本组成Chart、Config、Release
1.Chart 目录,可以压缩打包,方便传输、储存,只需要Chart.yml既可以部署k8s应用
2.Config记录可配置的参数
3.Release是Chart包部署后的实例,一个Chart可以包括多个Release
特点
1.统一存放Chart到仓库repository(web服务器,安装包让用户下载使用,还有清单文件提供查询),跟yum,apt,dnf一样,helm可以配置多个repository一样
使用
《必须想办法记录下基本使用》
日志系统
收集什么?
- k8s 容器运行轨迹kubectl logs
- k8s内部各种事件kubectl get event /kubect describe
- 业务容器日志(nginx,dns,网络插件等等)
- 等等
一般设计
一般日志的持久化都是 hostpath + 日志轮转
但是日志轮转,很多日志就被打包,查看要一个一个打开;不打开日志轮转,hostpath很容易将磁盘打爆
几种日志收集架构
- 直接将pod内应用把日志写到数据中心(后端)
通过容器运行时Logging Driver实现
docker info |grep Logging Driver
Logging-Driver:json-file
《用法截图》 - 节点运行Agent采集节点级日志,推送到后端存储系统
对于容器应用来说无侵入,但是只适用于容器标准输出stdout stderr - sidecar容器收集日志
基于边车容器的日志文件,大规模集群开销更大 - 社区推荐:(ds)Fluentd + ElasticSearch + Kibiana 日志收集和管理
通过fluentd将日志导入ElasticSearch,用kibana查看
fluentd镜像的几个内置配置
fluent.conf 设置一些地址,如ElasticSearch
kubernetes.conf 记录跟k8s相关配置,如日志收集规则
prometheus.conf 定义prometheus地址,用于fluentd暴露指标
systemd.conf 配置fluentd通过systemd-journal来收集日志,定义收集哪些日志(docker、kubelet等等)
《用法截图》
监控系统prometheus
监控系统面临的挑战
从单点架构变成微服务架构:pod漂移,扩缩容;
pod名字/ip一般都是随机的(除sts)。
k8s通过lable和annotation管理pod,所以监听系统也需要通过他们采集信息。
应用级别数据:cpu使用率,运行内存使用率,磁盘空间,网络延迟, 并发请求数,请求失败率,线程数。
集群级别数据:时刻了解集群状态,了解集群的cpu memeory,网络吞吐。;比如etcd,schrduler,controller-manager,coredns
监控采集工具
cAdvisor,google为容器资源监控和性能分析二开发的开源工具,v1.12正式移除
heapster:通过cAdvisor来收集性能数据,用于自动伸缩(autoscale)
metrics-server,集群范围的监控数据聚合工具,用来替代heapster
kube-state-metrics,监听apiserver中的数据,生成有关资源对象的新的状态指标,如deploy,Node,Pod
node-exporter,prometheus的一个exporter,可以帮助我们获取到节点级别的监控指标,如cpu,memory,磁盘空间,网络流量等。
社区推荐的监控体系:prometheus+grafana
通过pull metrics – push alerts实现告警,通过grafana搭建图形化界面,数据都存在以时间为索引的数据库中。
《搭建和使用截图》
整体架构
1. Kubemetes系统组件间只能通过API服务器通信, 它们之间不会直接通信。
apiserver是和etcd通信的唯 一组件。 其他组件不会直接和etcd通信, 而是通过API服务器来修改集群状态。
2. API服务器和其他组件的连接基本都是由组件发起的。
但是,当你使用kubectl获取日志、 使用kubectl attach连接到 一 个运行中的容器或运行kubectl port-forward命令时, API服务器会向Kubelet发起连接(此时apiserver是客户端发起连接,kubelet是服务端)
3. list-watch
当apiserver作为服务端时,kubectl,kubelet的管理器们,scheduler的调度器们,controller-manager的控制器们,都属于客户端,并且通过list-watch,发布订阅机制,将服务端的变化通知到每一个客户端去。
例如:
1.kubectl请求创建一个pod,apiserver接收处理请求并将数据存储到etcd,完成一个pod数据的创建;
2.接着,apiserver将pod新建的变更通知到每一个监听了apiserver的客户端:
controller控制器们将收敛pod资源实际状态-》期望状态(,并上报apiserver更新etcd信息);
scheduler调度器们将通过调度算法完善pod资源所在节点的描述信息(,并上报apiserver更新etcd信息);
kubelet管理器们知道pod在哪个节点,将pod的容器在本节点运行起来(,并上报apiserver更新etcd信息)
期望用源码分析一遍整个pod创建时各个组件的工作
更多推荐
所有评论(0)