目录
一、pod资源限制(resources)
二、重启策略(restartPolicy)
三、扩容缩容
1.手动扩容
2.自动扩容
2.1、数据采集组件
2.1.1、部署
2.2、HPA
2.2.1、案例
2.2.1.1、HPA基于cpu自动扩缩容
2.2.1.2、HPA基于内存自动扩缩容
2.3、cluster-autoscaler
二、使用步骤
1.引入库
2.读入数据
总结
当定义 Pod 时可以选择性地为每个容器设定所需要的资源数量。最常见的可设定资源是 CPU 和 内存大小 ,以及其他类型的资源。
当为 Pod 中的容器指定了 request 资源时,调度器就使用该信息来决定将 Pod 调度到哪个节点上。当还为容器指定了 limit 资源时,kubelet 就会确保运行的容器不会使用超出所设的 limit 资源量。kubelet 还会为容器预留所设的 request 资源量,供该容器使用。
如果 Pod 运行所在的节点具有足够的可用资源,容器可以使用超出所设置的 request 资源量。不过,容器不可以使用超出所设置的 limit 资源量。
如果给容器设置了内存的 limit 值,但未设置内存的 request 值,Kubernetes 会自动为其设置与内存 limit 相匹配的 request 值。类似的,如果给容器设置了 CPU 的 limit 值但未设置 CPU 的 request 值,则 Kubernetes 自动为其设置 CPU 的 request 值 并使之与 CPU 的 limit 值匹配。
官网示例:https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/
spec.containers[].resources.requests.cpu //定义创建容器时预分配的CPU资源
spec.containers[].resources.requests.memory //定义创建容器时预分配的内存资源
spec.containers[].resources.limits.cpu //定义cpu的资源上限
spec.containers[].resources.limits.memory //定义内存的资源上限
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
—CPU 资源单位:Kubernetes 中的一个 cpu 相当于1个 vCPU(1个超线程)。Kubernetes 也支持带小数 CPU 的请求。spec.containers[].resources.requests.cpu 为 0.5 的容器能够获得一个 cpu 的一半 CPU 资源(类似于Cgroup对CPU资源的时间分片)。表达式 0.1 等价于表达式 100m(毫核),表示每 1000 毫秒内容器可以使用的 CPU 时间总量为 0.1*1000 毫秒。
—内存资源单位:内存以字节为单位。可以以整数表示,或者以10为底数的指数的单位(E、P、T、G、M、K)来表示, 或者以2为底数的指数的单位(Ei、Pi、Ti、Gi、Mi、Ki)来表示。
重启策略:Pod在遇到故障之后重启的动作
spec.Always:当容器终止退出后,总是重启容器,默认策略
spec.OnFailure:当容器异常退出(退出状态码非0)时,重启容器;正常退出则不重启容器
spec.Never:当容器终止退出,从不重启容器。
在生产环境下,在面临服务需要扩容的场景时,可以使用Deployment/RC的Scale机制来实现。
slace扩容或缩容 Deployment、ReplicaSet、Replication Controller或 Job 中Pod数量。
Kubernetes支持对Pod的手动扩容和自动扩容。replicas决定了集群pod的数量。
kubectl apply -f apache.yaml
kubectl edit deployments.apps apache
kubectl scale deployments.appse apache --replicas=3
metrics-server 是一个集群范围内的资源数据集和工具,同样的,metrics-server 也只是显示数据,并不提供数据存储服务,主要关注的是资源度量 API 的实现,比如 CPU、文件描述符、内存、请求延时等指标,metric-server 收集数据给 k8s 集群内使用,如 kubectl,hpa,scheduler 等。不同k8s版本根据官网安装对应版本的metrics-server。
wget registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server:v0.6.4
docker load -i metrics-server-0.6.4.tar.gz
注意:会中断业务,生产环境谨慎操作!这个是 k8s 在 1.17 的新特性,如果是 1.16 版本的可以不用添加,1.17 以后要添加。这个参数的作用是 Aggregation 允许在不修改 Kubernetes 核心代码的同时扩展 Kubernetes API。
vim /etc/kubernetes/manifests/kube-apiserver.yaml
22 - --enable-aggregator-routing=true # 增加
systemctl restart kubelet
用到的yaml文件到github下载,地址:https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.6.1/components.yam
kubectl apply -f components.yaml
kubectl get pods -n kube-system | grep metrics
kubernetes HPA(Horizontal Pod Autoscaling):根据监控指标(cpu 使用率、磁盘、自定义的等)自动扩容或缩容服务中的pod数量,当业务需求增加时,系统将无缝地自动增加适量 pod 容器,提高系统稳定性。hap监控容器资源的利用率。
kubernetes KPA(Knative Pod Autoscaler):基于请求数对 Pod 自动扩缩容,KPA 的主要限制在于它不支持基于 CPU 的自动扩缩容。
kubernetes VPA(Vertical Pod Autoscaler):基于 Pod 的资源使用情况自动设置 pod 的 CPU 和内存的 requests,从而让集群将 Pod 调度到有足够资源的最佳节点上。
整体逻辑:K8s 的 HPA controller 已经实现了一套简单的自动扩缩容逻辑,默认情况下,每 15s 检测一次指标,只要检测到了配置 HPA 的目标值,则会计算出预期的工作负载的副本数,再进行扩缩容操作。同时,为了避免过于频繁的扩缩容,默认在 5min 内没有重新扩缩容的情况下,才会触发扩缩容。
HPA 本身的算法相对比较保守,可能并不适用于很多场景。例如,一个快速的流量突发场景,如果正处在 5min 内的 HPA 稳定期,这个时候根据 HPA 的策略,会导致无法扩容。
通过现有 pods 的 CPU 使用率的平均值(计算方式是最近的 pod 使用量(最近一分钟的平均值,从 metrics-server 中获得)除以设定的每个 Pod 的 CPU 使用率限额)跟目标使用率进行比较,并且在扩容时,还要遵循预先设定的副本数限制:MinReplicas <= Replicas <= MaxReplicas。
计算扩容后 Pod 的个数:sum(最近一分钟内某个 Pod 的 CPU 使用率的平均值)/CPU 使用上限的整数+1
HPA官网: Pod 水平自动扩缩 | Kubernetes
kubectl -n jy-test create deployment nginx-web --image=harbortest.szjs.gov.cn/zjj-public/nginx:1.22.1-arm --dry-run=client -o yaml > nginx-web.yaml
为了平常使用yaml时,由于手抖,造成的格式错误,建议尽量使用
–dry-run
参数来生成一个基础的yaml
,再修改。
kubectl apply -f nginx-web.yaml
kubectl -n jy-test expose deployment nginx-web --port=80 --type=NodePort --target-port=80 --name=svc-nginx-web -o yaml >> nginx-web.yaml
kubectl apply -f nginx-web.yaml
配置资源限制
kubectl -n jy-test edit deploy nginx-web
spec:
containers:
- image: harbortest.szjs.gov.cn/zjj-public/nginx:1.22.1-arm
imagePullPolicy: IfNotPresent
name: nginx
resources: # 注意:nginx 的 pod 里需要有如下字段,否则 hpa 会采集不到内存指标
limits:
cpu: 500m
memory: 256Mi
requests:
cpu: 200m
memory: 256Mi
nginx-web 服务正在运行,使用 kubectl autoscale 创建自动缩放器,实现对 nginx-web 这个deployment 创建的 pod 自动扩缩容,下面的命令将会创建一个 HPA,HPA 将会根据 CPU资源指标增加或减少副本数,创建一个可以实现如下目的的 hpa:
(1)让副本数维持在 1-10 个之间(这里副本数指的是通过 deployment 部署的 pod 的副本数)
(2)将所有 Pod 的平均 CPU 使用率维持在 50%(通过 kubectl run 运行的每个 pod 如果是 200毫核,这意味着平均 CPU 利用率为 100 毫核)
kubectl -n jy-test autoscale deployment nginx-web --cpu-percent=50 --min=1 --max=10 --name=nginx-web
kubectl -n jy-test get hpa
kubectl -n jy-test exec -it nginx-web-f646c4b44-nlxjq bash
/# for i in {1..500000}; do curl http://www.test.com/my_service & done
当容器的cpu占用超过 50% 的时候,自动扩展一个POD,依次扩展,一直到最大值,如果cpu访问不足 50% 的时候,每 300s 缩减一个 POD 节点,直到最小值时停止。
kubectl -n jy-test get hpa
kubectl -n jy-test get pod
nginx 服务正在运行,使用 kubectl autoscale 创建自动缩放器,实现对 nginx 这个deployment 创建的 pod 自动扩缩容,下面的命令将会创建一个 HPA,HPA 将会根据内存资源指标增加或减少副本数,创建一个可以实现如下目的的 hpa:
(1)让副本数维持在 1-10 个之间(这里副本数指的是通过 deployment 部署的 pod 的副本数)
(2)将所有 Pod 的平均内存使用率维持在 60%
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-web-hpa2 # hpa的名称
namespace: jy-test
spec:
maxReplicas: 10
metrics:
- resource:
name: memory
target:
averageUtilization: 60
type: Utilization
type: Resource
minReplicas: 1
scaleTargetRef: # 定义监视控制器,需要扩容缩谷时需要通知的控制器
apiVersion: apps/v1
kind: Deployment
name: nginx-web # 控制器的名称
kubectl create -f hpa.yaml
kubectl -n jy-test get hpa
Cluster Autoscaler (CA)是一个独立程序,是用来弹性伸缩 kubernetes 集群的。它可以自动根据部署应用所请求的资源量来动态的伸缩集群。当集群容量不足时,它会自动去 Cloud Provider (支持GCE、GKE 和 AWS)创建新的 Node,而在 Node 长时间资源利用率很低时自动将其删除以节省开支。
项目地址:GitHub - kubernetes/autoscaler: Autoscaling components for Kubernetes
扩容:由于资源不足,某些 Pod 无法在任何当前节点上进行调度。
缩容: Node 节点资源利用率较低时,且此 node 节点上存在的 pod 都能被重新调度到其他 node节点上运行。
1、节点上有 pod 被 PodDisruptionBudget 控制器限制。
2、节点上有命名空间是 kube-system 的 pods。
3、节点上的 pod 不是被控制器创建,例如不是被 deployment, replica set, job, stateful set 创建。
4、节点上有 pod 使用了本地存储。
5、节点上 pod 驱逐后无处可去,即没有其他 node 能调度这个 pod。
6、节点有注解:“cluster-autoscaler.kubernetes.io/scale-down-disabled”: “true”(在 CA 1.0.3 或更高版本中受支持)。
kubectl annotate node cluster-autoscaler.kubernetes.io/scale-down-disabled=true
Horizontal Pod Autoscaler 会根据当前 CPU 负载更改部署或副本集的副本数。如果负载增加,则 HPA 将创建新的副本,集群中可能有足够的空间,也可能没有足够的空间。如果没有足够的资源,CA将尝试启动一些节点,以便 HPA 创建的 Pod 可以运行。如果负载减少,则 HPA 将停止某些副本。结果,某些节点可能变得利用率过低或完全为空,然后 CA 将终止这些不需要的节点。
Kubernetes Service定义了这样一种抽象: Service是一种可以访问 Pod逻辑分组的策略, Service通常是通过 Label Selector访问 Pod组。
Service能够提供负载均衡的能力,但是在使用上有以下限制:只提供 4 层负载均衡能力,而没有 7 层功能,但有时我们可能需要更多的匹配规则来转发请求,这点上 4 层负载均衡是不支持的。
2.1.1、ClusterIp
范围:默认类型,集群内部使用(master、node、pod),自动分配一个仅Cluster内部可以访问的虚拟IP(VIP),实现负载均衡和服务的发现。
场景:当发现某一个pod不能使用的时候RS会在其他机器上创建一个相同的pod,及其对应的容器。会变化的pod给我们访问带来非常多的不便,Service就是解决一个问题的方法。
2.1.2、NodePort(对外暴露应用)
在ClusterIP基础上为Service在每台机器上绑定一个端口,这样就可以通过NodeIP:NodePort访问来访问该服务。
端口范围:30000~32767
2.1.3、LoadBalancer(对外暴露应用,适用于公有云)
在NodePort的基础上,借助Cloud Provider创建一个外部负载均衡器,并将请求转发到NodePort。
2.1.4、ExternalName
创建一个dns别名指到service name上,主要是防止service name发生变化,要配合dns插件使用。通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容。这只有 Kubernetes 1.7或更高版本的kube-dns才支持。
客户端访问节点时通过 iptables实现的
iptables规则是通过 kube-proxy写入的
apiserver通过监控 kube-proxy去进行对服务和端点的监控
kube-proxy通过 pod的标签( lables)去判断这个断点信息是否写入到 Endpoints里
—
—Service会创建一个cluster ip,这个地址对应资源地址,不管pod如何变化,service总能找到对应的pod,且cluster ip 保持不变,如果pod对应多个容器,service会自动在多个容器间实现负载均衡。
—Service通过iptables/lvs规则将访问的请求最终映射到pod的容器内部服务上。
—port:service暴露在cluster ip上的端口,是提供给集群内部客户访问servie的入口,供集群内部服务访问使用。
—targetPort:是pod上容器服务监听的端口,从port或nodePort上到来的数据最终经过kube-proxy流入到后端pod的targetPort进入容器,从而达到访问pod容器内部服务的目的。
—创建服务:kubectl apply -f 资源文件
—查询服务:kubectl get service
—查询IP池:ipvsadm -L -n
—Cluster IP是集群分配的服务IP,供集群访问,在集群内部也可以通过服务名称访问,服务的名称是通过coredns解析的,每个服务在创建的过程中都会完成自动注册。
—服务名称:<服务名称>.<名称空间>.srv.cluser.local【容器内部可以使用】
—服务缩写:服务名称
代理模式:v1.0用户空间;v1.1 iptables代理;v1.8 ipvs代理,如果不满足条件退回至v1.1。
kube-proxy是实现kubernetes Service的通信与负载均衡机制的重要组件,是Kubernetes的核心组件。
vim clusterip.yaml #注:多个资源可以写到同一个yaml文件中,使用---分割。
---
kind: Service #定义资源类型
apiVersion: v1 #资源版本
metadata:
name: myapache #服务的名称
spec: #服务的详细信息
ports: #端口定义
- protocol: TCP #服务协议
port: 80 #监听端口,开放前端的访问端口,是service的端口
targetPort: 80 #容器的端口
selector: #选择为那个deployment提供服务(后端)
myapp: httpd # 标签必须与容器中一致,kubectl get pod --show-labels查看
type: ClusterIP #服务类型
kubectl apply -f clusterip.yaml #记载资源文件,创建新的IP。
kubectl get service #查询服务,可以通过该命令查看到集群中不变的clusterIP
ipvsadm --save #查看配置的规则
kubectl exec -it mypod -- /bin/bash #进去集群内部
curl http://clusterIP/ #查看是否可以联通其他的集群,clusterIP为之前查到的。
#注:此时即使增加集群中节点的数量,服务也会是扩展。
-LoadBalancer:使用外部的云服务(需要支持,externallPs),使用云提供商的负载局衡器(云容器引擎CCE)
-nodeport:基于端口对外提供服务(四层),优点,可以发布任何服务,性能更好,没有七层的功能。nodeport==clusterIP+IPtables
-lngress:使用ingress控制器(七层),只支持http协议,和nodeport区别,就类似于nginx和lvs的区别
ipvsadm -L -n #查LVS的规则
vim mynodeport.yaml
---
kind: Service
apiVersion: v1
metadata:
name: mynodeport
spec:
ports:
- protocol: TCP
port: 80
targetPort: 80
selector:
myapp: httpd
type: NodePort #指定服务类型
kubectl apply -f mynodeport.yaml #记载资源文件
kubectl get service -o wide #查看对外共享的端口
curl http://节点IP:查看到的端口号 #在同一局域网查看提供的服务,查看能否联通
vim myheadless.yaml
---
kind: Service
apiVersion: v1
metadata:
name: myheadless
spec:
ports:
- protocol: TCP
port: 80
targetPort: 80
selector:
myapp: httpd
type: ClusterIP
clusterIP: None # 新添加,重点
kubectl apply -f myheadless.yaml #加载配置文件
kubectl get service #查看service服务的内容
kubectl exec -it mypod -- /bin/bash #进入到mypod集群中
yum install -y bind-utils #安装提供host命令的软件
host myheadless.default.svc.cluster.local #查看集群中容器有哪些,以及集群的IP
docker load -i ingress-nginx.tar.gz #导入镜像
docker tag quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0 192.168.1.100:5000/nginx-ingress-controller:0.30.03 #为镜像打标签
docker push 192.168.1.100:5000/nginx-ingress-controller:0.30.0 #将镜像上传至私有仓库
curl http://192.168.1.100:5000/v2/nginx-ingress-controller/tags/list #查看是否上传成功
vim ingress/mandatory.yaml #更改资源文件
221: image: 192.168.1.100:5000/nginx-ingress-controller:0.30.0
kubectl apply -f ingress/mandatory.yaml #加载资源文件
kubectl -n ingress-nginx get pod #查看控制器是否创建成功
vim ingress-example.yaml #编写资源文件
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-web
annotations:
kubernetes.io/ingress.class: "nginx" #这个注释是找nginx类别
spec:
backend: #转发的目的地,叫后端
serviceName: myapache #定义后端服务的名称
servicePort: 80 #定义服务的端口号
kubectl apply -f ingress-example.yaml
kubectl get ingresses #查看释放node节点IP,然后给IP绑定弹性公网IP,就完成了对外发布服务
curl http://192.168.1.33/info.php
vim /etc/kubernetes/manifests/kube-apiserver.yaml #如果配置文件出错,kubectl启动不了
- --enable-aggregator-routing=true # spec.containers.command 最下面手动添加如下一行,聚合路由参数
systemctl restart kubelet #重启服务
kubectl -n kube-system get pod kube-apiserver-master -o yaml |grep enable-aggregator-routing #查看静态路由是否启动
vim /var/lib/kubelet/config.yaml
serverTLSBootstrap: true #在master主机最后追加
for i in 31 32 33 #在跳板机上执行以下命令
do
ssh 192.168.1.$i "echo 'serverTLSBootstrap: true' >> /var/lib/kubelet/config.yaml" #节点向master服务器要证书。
ssh 192.168.1.$i "systemctl restart kubelet" #重启服务
done
systemctl restart kubelet
kubectl get certificatesigningrequests #查看证书是否签发成功,所有证书状态都是Approved(已经被签发了)
kubectl certificate approve csr-wsfz7 #如果是pending状态,重新签发证书,将所有要签发的证书签发
kubectl delete certificatesigningrequests 证书名称 #删除申请的多余证书
docker load -i metrisc-server.tar.gz
docker tag gcr.io/k8s-staging-metrics-server/metrics-server:master 192.168.1.100:5000/metrics-server:master
docker push 192.168.1.100:5000/metrics-server:master
vim deployment.yaml #修改主进程文件
29: image: 192.168.1.100:5000/metrics-server:master
kubectl apply -f rbac.yaml -f pdb.yaml -f deployment.yaml -f service.yaml -f apiservice.yaml
kubectl -n kube-system get pod #验证pod
kubectl -n kube-system get apiservices #验证API
kubectl top node #查看节点的资源
kubectl top pod #查看pod占用资源的情况。
需要下载的官网:https://github.com/kubernetes-sigs/metrics-server
rbac.yaml :授权控制器
pdb.yaml :中断控制器
deployment.yaml :主进程metrics(修改镜像地址)
service.yaml :后端是metics主进程的服务
apiservice.yaml:注册集群API
kubectl apply -f myapache.yaml
kubectl get pod
kubectl exec -it 节点名称 -- /bin/bash #进入容器中
while 0 #写一个死循环
do
echo “hello word”
done
kubectl top pod #重新开启一个终端,连接master管理节点,查看pod的资源。
kubectl top node #重新开启一个终端,连接master管理节点,查看节点的资源利用。
补充:1cup=1000m
kube-proxy负责为Service提供cluster内部的服务发现和负载均衡,它运行在每个Node计算节点上,负责Pod网络代理, 它会定时从etcd服务获取到service信息来做相应的策略,维护网络规则和四层负载均衡工作。在K8s集群中微服务的负载均衡是由Kube-proxy实现的,它是K8s集群内部的负载均衡器,也是一个分布式代理服务器,在K8s的每个节点上都有一个,这一设计体现了它的伸缩性优势,需要访问服务的节点越多,提供负载均衡能力的Kube-proxy就越多,高可用节点也随之增多。
service是一组pod的服务抽象,相当于一组pod的负载均衡,负责将请求分发给对应的pod。service会为这个负载均衡提供一个IP,一般称为cluster IP。kube-proxy的作用主要是负责service的实现,具体来说,就是实现了内部从pod到service和外部的从node port向service的访问。
endpoint是k8s集群中的一个资源对象,存储在etcd中,用来记录一个service对应的所有pod的访问地址。service配置selector,endpoint controller才会自动创建对应的endpoint对象;否则,不会生成endpoint对象。
一个 Service 由一组 backend Pod 组成。这些 Pod 通过 endpoints 暴露出来。 Service Selector 将持续评估,结果被 POST 到一个名称为 Service-hello 的 Endpoint 对象上。 当 Pod 终止后,它会自动从 Endpoint 中移除,新的能够匹配上 Service Selector 的 Pod 将自动地被添加到 Endpoint 中。 检查该 Endpoint,注意到 IP 地址与创建的 Pod 是相同的。现在,能够从集群中任意节点上使用 curl 命令请求 hello Service
: 。
【例如】k8s集群中创建一个名为hello的service,就会生成一个同名的endpoint对象,ENDPOINTS就是service关联的pod的ip地址和端口。
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello
spec:
replicas: 3
selector:
matchLabels:
run: hello
template:
metadata:
labels:
run: hello
spec:
containers:
- name: nginx
image: nginx:latest
---
apiVersion: v1
kind: Service
metadata:
name: service-hello
labels:
name: service-hello
spec:
type: NodePort # 这里代表是NodePort类型的,另外还有ingress,LoadBalancer
ports:
- port: 80
targetPort: 8080
protocol: TCP
nodePort: 31111 # 所有的节点都会开放此端口30000--32767,此端口供外部调用。
selector:
run: hello
3.2.1、查看验证
Kube-proxy进程获取每个Service的Endpoints,实现Service的负载均衡功能。
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
hello-688d6b8d4c-bzfj9 1/1 Running 0 21m 10.254.1.2 node01
hello-688d6b8d4c-nwgd6 1/1 Running 0 21m 10.254.2.2 node02
hello-688d6b8d4c-s5ff8 1/1 Running 0 21m 10.254.3.2 harbor
[root@master ~]# kubectl get service service-hello -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service-hello NodePort 10.244.143.216 80:31111/TCP 18h run=hello
[root@master ~]# kubectl describe service service-hello
Name: service-hello
Namespace: default
Labels:
Annotations:
Selector: run=hello
Type: NodePort
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.244.143.216
IPs: 10.244.143.216
Port: 80/TCP
TargetPort: 8080/TCP
NodePort: 31111/TCP
Endpoints: 10.254.1.6:8080,10.254.2.3:8080,10.254.3.3:8080
Session Affinity: None
External Traffic Policy: Cluster
Events:
[root@master ~]# kubectl get endpoints service-hello
NAME ENDPOINTS AGE
service-hello 10.254.1.6:8080,10.254.2.3:8080,10.254.3.3:8080 18h
Service的负载均衡转发规则:访问Service的请求,不论是Cluster IP+TargetPort的方式;还是用Node节点IP+NodePort的方式,都被Node节点的Iptables规则重定向到Kube-proxy监听Service服务代理端口。kube-proxy接收到Service的访问请求后,根据负载策略,转发到后端的Pod。
- nodePort是外部访问k8s集群中service的端口,通过nodeIP: nodePort可以从外部访问到某个service。
- port是k8s集群内部访问service的端口,即通过clusterIP: port可以访问到某个service。
- targetPort是pod的端口,从port和nodePort来的流量经过kube-proxy流入到后端pod的targetPort上,最后进入容器。
- containerPort是pod内部容器的端口,targetPort映射到containerPort。
Kubernetes提供了两种方式进行服务发现, 即环境变量和DNS, 简单说明如下:
环境变量:当你创建一个Pod的时候,kubelet会在该Pod中注入集群内所有Service的相关环境变量。【注意】要想一个Pod中注入某个Service的环境变量,则必须Service要比该Pod先创建。这一点,几乎使得这种方式进行服务发现不可用。
DNS:这是k8s官方强烈推荐的方式!!! 可以通过cluster add-on方式轻松的创建KubeDNS来对集群内的Service进行服务发现。
这种模式,kube-proxy 会监视 Kubernetes 控制平面对 Service 对象和 Endpoints 对象的添加和移除操作。 对每个 Service,它会在本地 Node 上打开一个端口(随机选择)。 任何连接到“代理端口”的请求,都会被代理到 Service 的后端 Pods
中的某个上面(如 Endpoints
所报告的一样)。 使用哪个后端 Pod,是 kube-proxy 基于 SessionAffinity
来确定的。
最后,它配置 iptables 规则,捕获到达该 Service 的 clusterIP
(是虚拟 IP) 和 Port
的请求,并重定向到代理端口,代理端口再代理请求到后端Pod。
默认情况下,用户空间模式下的 kube-proxy 通过轮转算法选择后端。
这种模式,kube-proxy
会监视 Kubernetes 控制节点对 Service 对象和 Endpoints 对象的添加和移除。 对每个 Service,它会配置 iptables 规则,从而捕获到达该 Service 的 clusterIP
和端口的请求,进而将请求重定向到 Service 的一组后端中的某个 Pod 上面。 对于每个 Endpoints 对象,它也会配置 iptables 规则,这个规则会选择一个后端组合。
默认的策略是,kube-proxy 在 iptables 模式下随机选择一个后端。
使用 iptables 处理流量具有较低的系统开销,因为流量由 Linux netfilter 处理, 而无需在用户空间和内核空间之间切换。 这种方法也可能更可靠。
如果 kube-proxy 在 iptables 模式下运行,并且所选的第一个 Pod 没有响应, 则连接失败。 这与用户空间模式不同:在这种情况下,kube-proxy 将检测到与第一个 Pod 的连接已失败, 并会自动使用其他后端 Pod 重试。
你可以使用 Pod 就绪探测器 验证后端 Pod 可以正常工作,以便 iptables 模式下的 kube-proxy 仅看到测试正常的后端。 这样做意味着你避免将流量通过 kube-proxy 发送到已知已失败的 Pod。
[root@master ~]# vim mysql-service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
name: mysql
role: service
name: mysql-service
spec:
ports:
- port: 3306
targetPort: 3306
nodePort: 30964
type: NodePort
selector:
mysql-service: "true"
name: mysql
[root@master ~]# kubectl apply -f mysql-service.yaml
service/mysql-service created
[root@master ~]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.244.0.1 443/TCP 29h
mysql-service NodePort 10.244.140.208 3306:30964/TCP 19s
service-hello NodePort 10.244.143.216 80:31111/TCP 20h
特性状态: Kubernetes v1.11 [stable]
在 ipvs
模式下,kube-proxy 监视 Kubernetes 服务和端点,调用 netlink
接口相应地创建 IPVS 规则, 并定期将 IPVS 规则与 Kubernetes 服务和端点同步。 该控制循环可确保IPVS 状态与所需状态匹配。访问服务时,IPVS 将流量定向到后端Pod之一。
IPVS代理模式基于类似于 iptables 模式的 netfilter 挂钩函数, 但是使用哈希表作为基础数据结构,并且在内核空间中工作。 这意味着,与 iptables 模式下的 kube-proxy 相比,IPVS 模式下的 kube-proxy 重定向通信的延迟要短,并且在同步代理规则时具有更好的性能。 与其他代理模式相比,IPVS 模式还支持更高的网络流量吞吐量。
IPVS 提供了更多选项来平衡后端 Pod 的流量。 这些是:
rr
:轮替(Round-Robin)lc
:最少链接(Least Connection),即打开链接数量最少者优先dh
:目标地址哈希(Destination Hashing)sh
:源地址哈希(Source Hashing)sed
:最短预期延迟(Shortest Expected Delay)nq
:从不排队(Never Queue)5.3.1、kube-proxy配置 ipvs模式(所有节点)
1)加载ip_vs相关内核模块
[root@master ~]# modprobe -- ip_vs
[root@master ~]# modprobe -- ip_vs_sh
[root@master ~]# modprobe -- ip_vs_rr
[root@master ~]# modprobe -- ip_vs_wrr
[root@master ~]# modprobe -- nf_conntrack_ipv4
[root@master ~]# lsmod | grep ip_vs
ip_vs_sh 12688 0
ip_vs_wrr 12697 0
ip_vs_rr 12600 0
ip_vs 141432 6 ip_vs_rr,ip_vs_sh,ip_vs_wrr
nf_conntrack 133053 10 ip_vs,nf_nat,nf_nat_ipv4,nf_nat_ipv6,xt_conntrack,nf_nat_masquerade_ipv4,nf_nat_masquerade_ipv6,nf_conntrack_netlink,nf_conntrack_ipv4,nf_conntrack_ipv6
libcrc32c 12644 4 xfs,ip_vs,nf_nat,nf_conntrack
2)安装ipvsadm工具
[root@master ~]# yum -y install ipset ipvsadm
3)查看kube-proxy
[root@master ~]# kubectl get pod -n kube-system | grep kube-proxy
kube-proxy-2f9x9 1/1 Running 2 (18h ago) 29h
kube-proxy-8xjdp 1/1 Running 2 (18h ago) 29h
kube-proxy-f425c 1/1 Running 2 (18h ago) 29h
kube-proxy-t4pq8 1/1 Running 2 (18h ago) 29h
3)编辑kube-proxy配置文件,mode修改成ipvs
[root@master ~]# kubectl edit configmaps -n kube-system kube-proxy
mode: "ipvs"
[root@master ~]# kubectl get pod -n kube-system | grep kube-proxy |awk '{system("kubectl delete pod "$1" -n kube-system")}'
pod "kube-proxy-2f9x9" deleted
pod "kube-proxy-8xjdp" deleted
pod "kube-proxy-f425c" deleted
pod "kube-proxy-t4pq8" deleted
[root@master ~]# kubectl get pod -n kube-system | grep kube-proxy # 再次查看
kube-proxy-5p5tb 1/1 Running 0 10s
kube-proxy-c2vxk 1/1 Running 0 13s
kube-proxy-z2hjm 1/1 Running 0 12s
kube-proxy-zgjc7 1/1 Running 0 9s
[root@master ~]# ipvsadm -Ln
说明:要在 IPVS 模式下运行 kube-proxy,必须在启动 kube-proxy 之前使 IPVS 在节点上可用。当 kube-proxy 以 IPVS 代理模式启动时,它将验证 IPVS 内核模块是否可用。 如果未检测到 IPVS 内核模块,则 kube-proxy 将退回到以 iptables 代理模式运行。
从数据层面看状态,数据的状态往往受2个维度有关,一是与时间相关或者顺序相关的,不同的操作顺序可能导致同一个时间点上的数据状态大于1个,二是与数据的副本状态相关的。也就是数据的位置,数据落在多个副本上,可能出现多种数据状态的组合。
从服务层面看,服务层面的状态取决于实例是单独维护数据还是共享数据,或者说是否存在多个数据闭环让数据的流向产生了多条路径。有状态的服务往往比较难进行水平拓展,在现在容器盛行的环境,把服务设计成无状态的更加高效,即便是有状态的服务,也要将状态内敛在系统的某个范围,比如分布式的存储,对于业务服务,我不需要关心数据在多个副本的状态,数据的状态由分布式存储这个服务本身解决。
差异维度 | 有状态服务 | 无状态服务 |
服务本身 | 服务本身依赖或者存在局部的状态数据,这些数据需要自身持久化或者可以通过其他节点恢复。 | 服务不依赖自身的状态,实例的状态数据可以维护在内存中。 |
节 点 | 一个请求只能被某个节点(或者同等状态下的节点)处理。 | 任何一个请求都可以被任意一个实例处理。 |
数据状态 | 存储状态数据,实例的拓展需要整个系统参与状态的迁移。 | 不存储状态数据,实例可以水平拓展,通过负载均衡将请求分发到各个节点。 |
系统中 | 在一个封闭的系统中,存在多个数据闭环,需要考虑这些闭环的数据一致性问题。 | 在一个封闭的系统中,只存在一个数据闭环。 |
架构中 | 通常存在于分布式架构中。 | 通常存在于单体架构的集群中。 |
相关资源 | statefulSet,由于是有状态的服务,所以每个pod都有特定的名称和网络标识。比如pod名是由statefulSet名+有序的数字组成(0、1、2..) |
ReplicaSet、ReplicationController、Deployment等,由于是无状态服务,所以这些控制器创建的pod序号都是随机值。并且在缩容的时候并不会明确缩容某一个pod,而是随机的,因为所有实例得到的返回值都是一样,所以缩容任何一个pod都可以。 |
相关服务 | 有状态服务 可以说是 需要数据存储功能的服务、或者指多线程类型的服务,队列等。(mysql数据库、kafka、zookeeper等) | 多个实例可以共享相同的持久化数据。例如:nginx实例,tomcat实例等 |