K8S入门知识概念
1.查看节点的日志信息:journalctl -u kubelet -n 1000
2.查看对应deployment的pod数量,并对其进行设置:kubectl get deployments & kubectl scale deployment nginx-deployment --replicas
3.node节点加入k8s集群:kubeadm join --token 1f627e.a37793601a406d7e 10.0.1.22:6443 --discovery-token-ca-cert-hash sha256:e12a8e1d1be7d308dad31bebdb2684d9d4ba7e5ae290f4fd1f855089b1abe71a
4.K8S给node设置污点策略:
kubectl taint nodes node1 key=value:NoSchedule --新的不能容忍的pod不能再调度过来,但是老的运行在node上不受影响
kubectl taint nodes node1 key=value:NoExecute --新的不能容忍的pod不能调度过来,老的pod也会被驱逐
kubectl taint nodes node1 key=value:PreferNoSchedule --pod会尝试将pod分配到该节点
5.K8S如何给节点去除对应的污点:kubectl taint nodes master key:NoExecute-
6.重启kubelet:systemctl restart kubelet.service
7.设置kubelet开机自启动:systemctl enable kubelet.service
8.查看k8s存在的命名空间:kubectl get namespaces
9.查看命名空间里的服务:kubectl get services --namespace=logging
10.查看系统中所运行的容器:kubectl get po -n kube-system -o wide
11.查看对应的错误日志:kubectl describe pod XXX -n kube-system
12.K8S的pod调度策略:
可以参考链接详细学习:https://www.qikqiak.com/post/kubernetes-affinity-scheduler/
nodeSelector调度:强制调度pod到某个节点上
亲和性和反亲和性调度:
nodeAffinity(节点亲和性)、podAffinity(pod 亲和性) 以及 podAntiAffinity(pod 反亲和性)
亲和性调度可以分成软策略和硬策略两种方式:
- 软策略就是如果你没有满足调度要求的节点的话,pod 就会忽略这条规则,继续完成调度过程,说白了就是满足条件最好了,没有的话也无所谓了的策略
- 硬策略就比较强硬了,如果没有满足条件的节点的话,就不断重试直到满足条件为止,简单说就是你必须满足我的要求,不然我就不干的策略。
对于亲和性和反亲和性都有这两种规则可以设置: preferredDuringSchedulingIgnoredDuringExecution和requiredDuringSchedulingIgnoredDuringExecution,前面的就是软策略,后面的就是硬策略。
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 硬策略
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- node03
preferredDuringSchedulingIgnoredDuringExecution: # 软策略
- weight: 1
preference:
matchExpressions:
- key: com
operator: In
values:
- youdianzhishi
nodeSelectorTerms属性类型
- In:label 的值在某个列表中
- NotIn:label 的值不在某个列表中
- Gt:label 的值大于某个值
- Lt:label 的值小于某个值
- Exists:某个 label 存在
- DoesNotExist:某个 label 不存在
如果nodeSelectorTerms下面有多个选项的话,满足任何一个条件就可以了;如果matchExpressions有多个选项的话,则必须同时满足这些条件才能正常调度 POD。
13.k8s pod erro exit code 137 :该错误码表示node节点的内存不足
14.开启代理协议端口:kubectl proxy --address='192.168.30.30' --port=8888 --accept-hosts='^*$' &
15.K8s中yaml的资源类型(kind字段)
工作负载型资源对象(workload):POD,ReplicaSet,Deployment,StatefulSet,DaemonSet,Job,Cronjob ...
服务发现及均衡资源对象:Service,Ingress ...
配置与存储资源对象:Volume(存储卷),CSI(容器存储接口,可以扩展各种各样的第三方存储卷),ConfigMap,Secret,DownwardAPI
集群级资源:Namespace,Node,Role,ClusterRole,RoleBinding,ClusterRoleBinding
元数据型资源:HPA,PodTemplate,LimitRange
16.K8S中存储卷volume的类型
一.本地存储
1,EmptyDir
如果在此目录中创建删除文件,都将对容器中的/data目录有影响,如果删除Pod,文件将全部删除,即使是在宿主机上创建的文件也是如此,在宿主机上删除容器则k8s会再自动创建一个容器,此时文件仍然存在。
2.HostDir
在宿主机上指定一个目录,挂载到Pod的容器中,其实跟上面的写法不尽相同,这里只截取不同的部分,当pod删除时,本地仍然保留文件
二.网络数据卷(NFS)
1.NFS
如何加入NFS文件系统
# 安装nfs服务
[root@nfs01 ~]# yum install nfs-utils rpcbind
# 创建nfs挂载目录
[root@nfs01 ~]# mkdir /data/volums/data01/ -p
# 启动服务
[root@nfs01 ~]# systemctl start rpcbind
[root@nfs01 ~]# systemctl enable rpcbind
[root@nfs01 ~]# systemctl start nfs-server
[root@nfs01 ~]# systemctl enable nfs-server
# 配置nfs服务
[root@nfs01 ~]# cat /etc/exports
/data/volums/data01 *(async,insecure,no_root_squash,no_subtree_check,rw)
# 查看nfs状态
[root@nfs01 ~]# showmount -e 192.168.17.195
Export list for 192.168.17.195:
/data/volums/data01 192.168.17.0/24
注意:对应的节点需要安装客户端:yum install nfs-utils
采用nfc存储的yaml样例
spec:
containers:
- name: web
image: nginx
imagePullPolicy: Never #如果已经有镜像,就不需要再拉取镜像
ports:
- name: web
containerPort: 80
hostPort: 80 #将容器的80端口映射到宿主机的80端口
volumeMounts:
- name : nfs #指定名称必须与下面一致
mountPath: "/usr/share/nginx/html" #容器内的挂载点
volumes:
- name: nfs #指定名称必须与上面一致
nfs: #nfs存储
server: 192.168.30.32 #nfs服务器ip或是域名
path: "/nfs-data" #nfs服务器共享的目录
在/test目录中创建index.html文件后,这个文件也将在容器中生效,当Pod删除时,文件不受影响,实现了数据持久化。
三. Persistent Volume(PV)和Persistent Volume Claim(PVC)
其实这两种数据卷也属于网络数据卷,单拎出来是因为我觉得这个比前面的数据卷要酷多了,有种大数据,云平台的意思,当用户要使用数据存储的时候他是否还需要知道是什么类型的数据存储,答案是不需要,用户只想要安全可靠的数据存储,而且实现起来很简单,管理员建立一个存储平台,用户按自己的需求消费就可以了
PersistentVolume (PV) 是外部存储系统中的一块存储空间,由管理员创建和维护。与 Volume 一样,PV 具有持久性,生命周期独立于 Pod。
PersistentVolumeClaim (PVC) 是对 PV 的申请 (Claim)。PVC 通常由普通用户创建和维护。需要为 Pod 分配存储资源时,用户可以创建一个 PVC,指明存储资源的容量大小和访问模式(比如只读)等信息,Kubernetes 会查找并提供满足条件的 PV。
静态Pvc的示例
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: efk-pvc
namespace: kube-system #注意pvc所在的命名空间和所引用的pod需要在同一个
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 2Gi
storageClassName: efk-nfs
pod如何引用pvc
volumeMounts:
- name: elasticsearch-logging
mountPath: /data
env:
- name: "NAMESPACE"
valueFrom:
fieldRef:
fieldPath: metadata.namespace
volumes:
- name: elasticsearch-logging
persistentVolumeClaim:
claimName: efk-pvc
具体创建和使用参考:
https://blog.51cto.com/forall/2135152
动态pvc的使用
创建和使用参考链接:https://blog.51cto.com/goome/2423200
过程中遇到的问题
nfs-client-provisioner这个pod一直报错error retrieving resource lock default/fuseim.pri-ifs: Unauthorized
最后参考链接
https://github.com/kubernetes-incubator/external-storage/issues/953
把下面这段替换rbac.yaml文件就行,大概的原因是rbac分配给nfs-client的权限不够
kind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1metadata:
name: efs-provisioner-runnerrules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["list", "watch", "create", "update", "patch"]
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
不再需要再创建pod前先申请pvc然后再挂载进pod,可以通过在部署pod的yaml文件中采用StatefulSet
statefulset,可以翻译成有状态的设定.
和deployment的对比
deployment部署创建的pod是无状态的,重新调度pod,pod名字hostname,启动pod顺序删除pod顺序都是随机的.deployment使用的是共享存储,所有pod共用一个存储卷.
statefulset部署创建的pod是有状态的,重新调度pod,pod名字hostname保持固定不变,启动pod顺序删除pod顺序都可以根据定义的顺序有序执行操作,有序的动态更新,statefulset使用的存储,不是共用一个存储卷,一个pod对应一个存储卷(pv).pod重新创建调度挂载的存储卷保持不变.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: statefulset-testspec:
serviceName: headless-svc
replicas: 3
selector:
matchLabels:
app: headless-pod
template:
metadata:
labels:
app: headless-pod
spec:
containers:
- image: httpd
name: myhttpd
ports:
- containerPort: 80
name: httpd
volumeMounts:
- mountPath: /mnt
name: test
volumeClaimTemplates:
- metadata:
name: test
annotations:
volume.beta.kubernetes.io/storage-class: managed-nfs-storage
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 100Mi
accessModes
用于定义资源的访问方式,受限于存储底层的支持,访问方式包括以下几种:
ReadWriteOnce – 被单个节点mount为读写rw模式
ReadOnlyMany – 被多个节点mount为只读ro模式
ReadWriteMany – 被多个节点mount为读写rw模式
17.K8S进入pod中:kubectl exec -ti curl-6bf6db5c4f-hm96f -n default -- /bin/sh
18.K8S的service介绍
service是一个抽象概念,定义了一个服务的多个pod逻辑合集和访问pod的策略,一般把service称为微服务
服务类型
ClusterIP:
分配一个内部集群IP地址,只能在集群内部访问(同Namespace内的Pod),默认ServiceType。
Service对象在Cluster IP range池中分配到的IP只能在内部访问,如果服务作为一个应用程序内部的层次,还是很合适的。如果这个Service作为前端服务,准备为集群外的客户提供业务,我们就需要给这个服务提供公共IP了。
NodePort:
分配一个内部集群IP地址,并在每个节点上启用一个端口来暴露服务,可以在集群外部访问。
访问地址:<NodeIP>:<NodePort>
LoadBalancer:
分配一个内部集群IP地址,并在每个节点上启用一个端口来暴露服务。
除此之外,Kubernetes会请求底层云平台上的负载均衡器,将每个Node([NodeIP]:[NodePort])作为后端添加进去。
service的类型
ClusterIP 默认模式,只能在集群内部访问
NodePort 在每个节点上都监听一个同样的端口号(30000-32767),ClusterIP和路由规则会自动创建。集群外部可以访问<NodeIP>:<NodePort>联系到集群内部服务,可以配合外部负载均衡使用(我现在公司用的就是这个模式配合阿里云的SLB)
LoadBalancer 要配合支持公有云负载均衡使用比如GCE、AWS。其实也是NodePort,只不过会把<NodeIP>:<NodePort>自动添加到公有云的负载均衡当中
ExternalName 创建一个dns别名指到service name上,主要是防止service name发生变化,要配合dns插件使用,用户可以指定一个任意的名字,作为该service被解析的CNAME,这种类型的servcie不用指定clusterIP,因此kube-proxy不会管理这类service,这类service需要使用1.7版本以上的kubedns。比如用户想创建一个service,但要让所有容器访问该service的请求都引导到用户自己定义的外部域名服务,就可以通过这个方式实现。可以说这个是最自由的一个方式:你希望服务被如何解析,服务就能被如何解析。你甚至可以给多个service配置同一个externalName。
---
kind: Service
apiVersion: v1
metadata:
name: mysql-5-7-01-service
spec:
type: ExternalName
externalName: ai-production-mysql-bot.cfyipcsxzevb.rds.cn-northwest-1.amazonaws.com.cn
---
通过上面创建的servicename去访问对应的aws上的mysql服务
集群中容器访问集群外部服务
DNS
Service type:ExternalName
在Docker环境中,由于Docker Engine自带 DNS Server,我们使用容器名来访问其它容器,因为容器是不稳定的,当容器宕掉,再重新启动相同镜像的容器,IP地址会改变,所以我们不使用IP访问其它容器;同样的,在Kubernetes集群中,由于我们使用 kube-DNS,我们常用Service名称来访问某个服务,Service资源对象能保证其背后的容器副本始终是最新的IP。
因此,我们可以利用这个特性,对Service名称和外部服务地址做一个映射,使之访问Service名称既是访问外部服务。例如下面的例子是将 svc1 和 xxx.xxx.xxx.xxx 做了对等关系。
kind: Service
apiVersion: v1
metadata:
name: svc1
namespace: default
spec:
type: ExternalName
externalName: somedomain.org
设置 Service 的 EndPoint
在Kubernetes集群中,同一个微服务的不同副本会对集群内或集群外(取决于服务对外暴露类型)暴露统一的服务名称,一个服务背后是多个 EndPoint,EndPoint解决映射到某个容器的问题,在 EndPoint 中不仅可以指定集群内容器的IP,还可以指定集群外的IP,我们可以利用这个特性使用集群外部的服务。
EndPoint 方式的缺点是只能指定IP,不能使用网址,比如网址,比如RDS的地址,这种情况下只能使用ExternalName来解决。
apiVersion: v1
kind: Service
metadata:
name: mysql-production
spec:
ports:
- port: 3306
---
kind: Endpoints
apiVersion: v1
metadata:
name: mysql-production
namespace: default
subsets:
- addresses:
- ip: 192.168.1.25
ports:
- port: 3306
总结
本文介绍了集群内部访问外部服务的两种方法,ExternalName 类型的服务适用于外部服务使用域名的方式,缺点是不能指定端口;而EndPoint的方式适合于外部服务是IP的情况,但是可以指定端口。根据需要使用吧!
19. K8S中pod的内存和cpu设置
下面是如何给一个pod分配cpu和内存
在Kubernetes系统上,l个单位的CPU相当于虚拟机上的l颗虚拟CPU(vCPU)或物理机上的一个超线程(Hyperthread,或称为一个逻辑CPU),它支持分数计量方式,一个核心(1core)相当于1000个微核心(millicores),因此500m相当于是0.5个核心
apiVersion: v1
kind: Pod
metadata:
name: memory-demo
spec:
containers:
- name: memory-demo-ctr
image: vish/stress
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
args:
- -mem-total
- 150Mi
- -mem-alloc-size
- 10Mi
- -mem-alloc-sleep
- 1s
超出容器的内存限制报错
NAME READY STATUS RESTARTS AGE
memory-demo-2 0/1 OOMKilled 1 24s
配置超出节点能力范围的内存申请,pod会一直处于pending状态
kubectl get pod memory-demo-3 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-3 0/1 Pending 0 25s
查看具体报错信息如下
Events:
... Reason Message
------ -------
... FailedScheduling No nodes are available that match all of the following predicates:: Insufficient memory (3).
如果不配置内存限制
如果不给容器配置内存限制,那下面的任意一种情况可能会出现:
容器使用内存资源没有上限,容器可以使用当前节点上所有可用的内存资源。
容器所运行的命名空间有默认内存限制,容器会自动继承默认的限制。
内存申请和限制的原因
通过配置容器的内存申请和限制,你可以更加有效充分的使用集群里内存资源。配置较少的内存申请, 可以让Pod跟任意被调度。设置超过内存申请的限制,可以达到以下效果:
Pod可以在负载高峰时更加充分利用内存。
可以将Pod的内存使用限制在比较合理的范围。
20. 强制删除pod: kubectl delete po <your-pod-name> -n <name-space> --force --grace-period=0
21. K8S的镜像拉取策略
Always 总是拉取镜像
IfNotPresent 本地有则使用本地镜像,不拉取
Never 只使用本地镜像,从不拉取,即使本地没有
如果省略imagePullPolicy 镜像tag为 :latest 策略为always ,否则 策略为 IfNotPresent
22. Pod健康检测机制
对于Pod的健康状态检测,kubernetes提供了两类探针(Probe)来执行对Pod的健康状态检测:
- LivenessProbe探针:
用于判断容器是否存活,即Pod是否为running状态,如果LivenessProbe探针探测到容器不健康,则kubelet将kill掉容器,并根据容器的重启策略是否重启,如果一个容器不包含LivenessProbe探针,则Kubelet认为容器的LivenessProbe探针的返回值永远成功。 - ReadinessProbe探针:
用于判断容器是否启动完成,即容器的Ready是否为True,可以接收请求,如果ReadinessProbe探测失败,则容器的Ready将为False,控制器将此Pod的Endpoint从对应的service的Endpoint列表中移除,从此不再将任何请求调度此Pod上,直到下次探测成功。
每类探针都支持三种探测方法:
- exec:通过执行命令来检查服务是否正常,针对复杂检测或无HTTP接口的服务,命令返回值为0则表示容器健康。
- httpGet:通过发送http请求检查服务是否正常,返回200-399状态码则表明容器健康。
- tcpSocket:通过容器的IP和Port执行TCP检查,如果能够建立TCP连接,则表明容器健康。
探针探测的结果有以下三者之一:
- Success:Container通过了检查。
- Failure:Container未通过检查。
- Unknown:未能执行检查,因此不采取任何措施。