Kubernetes Pod是有生命周期的,它们可以被创建,也可以被销毁,然而一旦被销毁生命就永远结束。 通过ReplicationController能够动态地创建和销毁Pod, 每个 Pod 都会获取它自己的 IP 地址,可一旦销毁后,重新创建后,IP地址会产生改变。 这会导致一个问题:在 Kubernetes 集群中,如果一组 Pod(称为 backend)为其它 Pod (称为 frontend)提供服务,一旦backend的Pod重新创建,那么frontend的Pod该如何发现,并连接到这组 Pod 中的哪些 backend 呢?
Service资源用于为pod对象提供一个固定、统一的访问接口及负载均衡的能力,并借助新一代DNS系统的服务发现功能,解决客户端发现并访问容器化应用的问题。
在kubernetes中,在收到rc调控的时候,pod副本数是变化的,对应的虚IP也是变化的,比如发生迁移或者伸缩时。这对于pod的访问来说是不能接受的,kubernetes中的service是一种逻辑概念。它定义了一个pod逻辑集合以及访问它们的策略,service与pod的关联同样是通过label完成的。service的目标是提供一种桥梁,他会为访问者提供一个固定的访问IP地址,用于在访问时重定向到相应的后端,这可以使一些非kubernetes原生应用程序,在无需为kubernetes编写特定代码的前提下轻松访问后端。
注意: service只是在k8s集群内部起作用,集群外部访问是无效的
ClusterIP
:默认值,k8s系统给service自动分配的虚拟IP,只能在集群内部访问。一个Service可能对应多个EndPoint(Pod),client访问的是Cluster IP,通过iptables规则转到Real Server,从而达到负载均衡的效果NodePort
:将Service通过指定的Node上的端口暴露给外部,访问任意一个NodeIP
:nodePort都将路由到ClusterIP。LoadBalancer
:在 NodePort 的基础上,借助 cloud provider 创建一个外部的负载均衡器,并将请求转发到:NodePort
,此模式只能在云服务器上使用。ExternalName
:将服务通过 DNS CNAME记录方式转发到指定的域名(通过 spec.externlName 设定)Service 是由 kube-proxy 组件,加上 iptables 来共同实现的.
## 创建控制器
kubectl create deployment nginx --image=myapp:v1 --replicas=3
## 暴露服务的80端口
kubectl expose deployment nginx --port=80
kubectl get pod ## 查看pod的信息
## 查看nginx服务的信息,类型ClusterIP:k8s系统给service自动分配的虚拟IP,只能在集群内部访问
kubectl describe svc nginx
IPVS模式的service,可以使K8s集群支持更多量级的Pod
pod和service通信: 通过iptables或ipvs实现通信,ipvs取代不了iptables,因为ipvs只能做负载均衡,而做不了nat转换
(1)开启kube-proxy的ipvs模式
yum install ipvsadm -y
kubectl edit cm kube-proxy -n kube-system
kubectl get pod -n kube-system |grep kube-proxy |awk '{system("kubectl delete pod "$1" -n kube-system")}'
(3)应用文件:kubectl apply -f demo.yml
---
apiVersion: v1
kind: Service ## 服务
metadata:
name: myservice
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment ## 控制器创建pod
metadata:
name: deployment
spec:
replicas: 5 ## 副本数
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:v1
kubectl get svc
ip addr
ipvsadm -ln
(2)扩容:
vim demo.yml
kubectl apply -f demo.yml
,扩容成功ipvsadm -ln
kubectl -n kube-system get pod -o wide
kubectl -n kube-system get svc
kubectl attach demo -c demo -it
,访问服务时是负载均衡的Headless Service不需要分配一个VIP,而是直接以DNS记录的方式解析出被代理Pod的IP地址。
headless使用场景
第一种:自主选择权,client自己来决定使用哪个Real Server,可以通过查询DNS来获取Real Server的信息。
第二种:Headless Service的对应的每一个Endpoints,即每一个Pod,都会有对应的DNS域名;这样Pod之间就能互相访问,集群也能单独访问pod
$(servicename).$(namespace).svc.cluster.local
(1)应用文件:kubectl apply -f demo.yml
,修改上面实验中的demo.yml中service的类型为None
clusterIP: None表示是无头service
port: 80 service ip中的端口
targetPort: 80 容器ip中的端口
kubectl get svc
ipvsadm -ln
ip addr
kubectl describe svc myservice
kubectl -n kube-system get svc
dig -t A myservice.default.svc.cluster.local @10.96.0.10
,Real Server的信息kubectl describe -n kube-system svc kube-dns
(2)测试:在容器中访问myservice服务,是负载均衡的
(3)Pod滚动更新后,依然可以解析:
kubectl apply -f demo.yml
kubectl attach demo -c demo -it
,依然可以通过服务的名字访问服务后端的pod,实现负载均衡Kubernetes 的控制器能保证在任意副本(Pod)挂掉时自动从其他机器启动一个新的,还可以动态扩容等,通俗地说,这个 Pod 可能在任何时刻出现在任何节点上,也可能在任何时刻死在任何节点上;那么自然随着 Pod 的创建和销毁,Pod IP 肯定会动态变化;那么如何把这个动态的 Pod IP 暴露出去?这里借助于 Kubernetes 的 Service 机制,Service 可以以标签的形式选定一组带有指定标签的 Pod,并监控和自动负载他们的 Pod IP,那么我们向外暴露只暴露 Service IP 就行了。
这就是 NodePort 模式:即在每个节点上开起一个端口,然后转发到内部 Pod IP 上
(1)应用文件:kubectl apply -f demo.yml
kubectl get svc
,服务的80端口绑定到本机的31010端口ipvsadm -Ln
,轮询的方式ip addr
netstat -antlp| grep 31010
,将服务绑定到本地的31010端口(2)测试:curl 172.25.12.2:31010/hostname.html
,实现负载均衡
从外部访问 Service 的第二种方式
(1)应用文件:kubectl apply -f demo.yml
kubectl get svc
,服务的80端口绑定到本地的31199端口,外部访问的IP状态为prendingipvsadm -Ln
,轮询的方式kubectl describe svc myservice
(2)service允许为其分配一个公有IP
kubectl apply -f demo.yml
kubectl get svc
,服务中被分配到外部访问的VIP
(3)测试:curl 172.25.12.100/hostname.html
,能通过外部IP访问,并且实现负载均衡
(1)应用文件:kubectl apply -f demo.yml
apiVersion: v1
kind: Service
metadata:
name: ex-service
spec:
type: ExternalName
clusterIP:Name: www.baidu.com
kubectl get svc
,ex-service服务的EXTERNAL-IP=www.baidu.com
(2)查看DNS中的A记录:dig -t A ex-service.default.svc.cluster.local @10.96.0.10
当查找主机 ex-service.default.svc.cluster.local 时,群集DNS服务返回 CNAME 记录,其值为www.baidu.com 。 访问 ex-service 的方式与其他服务的方式相同,但主要区别在于重定向发生在 DNS 级别,而不是通过代理或转发