使用版本1.23
1,什么是k8s service
- 是发现后端pod服务;
- 是为一组具有相同功能的容器提供一个统一的入口地址;
- 是将请求进行负载分发到后端各个容器应用上的控制器;
- 是k8s 中的一种资源抽象,定义了一组pod的逻辑集合和一个用于访问它们的策略——有时也被称之为微服务;Service 的目标pod集合通常是有Label Selector 来决定的。
2,对于Service的访问来源
请求来源主要有两种: k8s集群内部的程序(Pod)和 k8s集群外部的程序。
3,service类型
采用微服务架构,作为服务所有者,除了实现自身业务逻辑外,还需要考虑如何把服务发布到k8s 集群或者集群外部,使这些服务能够被k8s 集群内的应用、其它k8s集群的应用以及外部应用使用。因此k8s提供了灵活的服务发布方式,用户可以通过serviceType 来指定如何来发布服务;
service在k8s中有以下四种类型:
- Cluster Ip: 自动分配一个仅Cluster 内部可以访问的虚拟IP(service 默认类型)
- NodePort: 在ClusterIP 基础上为Service在每台Node 上绑定一个端口,这样集群外部的应用程序就可以通过:NodePort 来访问该服务。
- LoadBalancer: 在NodePort基础上,借助cloud provider 创建一个外部负载均衡器,并将请求转发到:NodePort
- ExternalName: 把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,这个只有在kubernetes1.7 或更高版本kube-dns 中才支持
service 负载分发策略
service负载分发策略有两种:
RoundRobin: 轮询模式,即轮询将请求转发到后端的各个pod上(默认模式);
SessionAffinity: 基于客户端IP地址进行会话保持的模式,第一次客户端访问后端某个pod, 之后的请求都转发到这个pod上。
查看k8s集群kube-proxy的代理模式
curl localhost:10249/proxyMode
kubectl get cm kube-proxy -n kube-system -o yaml | grep mode
修改kube-proxy的代理模式为ipvs
安装ipvs
yum install -y ipset ipvsadm #(master 、node 节点)
cat << 'EOF' > /etc/sysconfig/modules/ipvs.modules
#!/bin/bash
ipvs_modules=(ip_vsip_vs_lc ip_vs_wlc ip_vs_rr ip_vs_wrr ip_vs_lblc ip_vs_lblcr ip_vs_dh ip_vs_ship_vs_fo ip_vs_nq ip_vs_sed ip_vs_ftp nf_conntrack_ipv4)
forkernel_module in ${ipvs_modules[*]}; do
/sbin/modinfo -Ffilename ${kernel_module} > /dev/null 2>&1
if [ $? -eq 0 ];then
/sbin/modprobe${kernel_module}
fi
done
EOF
chmod +x /etc/sysconfig/modules/ipvs.modules
lsmod |grep ip_vs
配置更新kube-proxy
修改配置
kubectl -n kube-system edit cm kube-proxy
mode: “ipvs” # 修改mode模式为ipvs
更新kube-proxy
kubectl get pod -n kube-system |grep kube-proxy |awk ‘{system(“kubectl delete pod “$1” -n kube-system”)}’ # 更新kube-proxy pod
ipvsadm -ln # 查看是否生效
service 工作图
实例1:
ClusterIp,集群ip
默认类型,自动分配一个仅Cluster 内部可以访问的虚拟IP
ClusterIp 只在集群内部能被访问到
ClusterIP 主要在每个node 节点使用iptables/ipvs,将发送到clusterIP对应端口的数据转发到kube-proxy 中。然后kube-proxy自己内部实现有负载均衡的方法,并通过查询到这个service下对应pod的地址和端口,进而把数据转发给对应的pod的地址和端口。
为了实现图上的功能,主要需要以下几个组件的协同工作:
- apiserver 用户 通过kubectl 命令向apiserver发送创建 service 的命令,apiserver 接收到请求后将数据存储到etcd 中
- kube-proxy k8s 中的每个节点中都有一个kube-proxy 的进程,这个进程负责感知service,pod 的变化,并将变化的信息写入到本地的iptables/ipvs 规则中
- iptables /ipvs 使用NAT等技术将virtualIP的流量转至endpoint中
创建deployment
cat >> svc-deployment.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy
namespace: dev
spec:
replicas: 3
selector:
matchLabels:
app: myapp
release: stabe1
template:
metadata:
labels:
app: myapp
release: stabe1
env: test
spec:
containers:
- name: myapp
image: nginx:1.20.2
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
EOF
kubectl apply -f svc-deployment.yaml
创建svc
cat >> svc.yaml << EOF
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: dev
spec:
type: ClusterIP
selector:
app: myapp
release: stabe1
ports:
- name: http
port: 889
targetPort: 80
EOF
kubectl apply -f svc.yaml
kubectl get al -n dev
kubectl get svc -n dev
curl ClusterIp: clusterPort
Headless Service 无头服务
有的时候不需要或是不想要负载均衡,以及单独的ServiceIP。 遇到这种情况,可以通过指定的ClusterIP(spec.clusterIP)的值为‘None’来创建Headless Service。 这类Service 并不会分配ClusterIP ,kube-proxy 不会处理它们,而且平台也不会为它们进行负载均衡和路由
cat >> svc-headless.yaml << EOF
apiVersion: v1
kind: Service
metadata:
name: myapp-headless
namespace: dev
spec:
selector:
app: myapp
clusterIP: "None"
ports:
- port: 999
targetPort: 80
EOF
kubectl apply -f svc-headless.yaml
kubectl get svc -n dev
dig -t A myapp-headless.dev.svc.cluster.local. @10.6.0.28
实例2:NodePort
NodePort: 在ClusterIP的基础上为Service在每台机器上绑定一个端口,这样集群外部就可以通过:NodePort 来访问该服务
nodeport 的原理在于在node上开了一个端口,将向该端口的流量导入到kube-proxy ,然后有kube-proxy 进一步给到对应的pod 中。
创建一个实例:
cat >> nodeports.yaml << EOF
apiVersion: v1
kind: Service
metadata:
name: myapp-nodeport
namespace: dev
spec:
type: NodePort
selector:
app: myapp
release: stabe1
ports:
- name: http
port: 666
targetPort: 80
EOF
kubectl apply -f nodeports.yaml
kubectl get all -n dev
kubectl get svc -n dev
curl http://192.168.6.111:30777/