Pod中的容器很可能因为各种原因发生故障而死掉。
而使用Deployment等Controller可以动态创建和销毁Pod来保证应用整体的健壮性。
每个Pod都有自己的IP地址。当Controller用新Pod替代发生故障的Pod时,新Pod会分配到新的IP地址。如果直接通过Pod的ip访问服务,就会产生问题。
为了解决这个问题,Kubernetes提供了Service,并通过service访问pod中的服务。
创建Service
Service从逻辑上代表了一组Pod。Service有自己的IP,而且这个IP是不变的。
客户端只需要访问Service的IP,Kubernetes则负责建立和维护Service与Pod的映射关系。
看个例子,创建下面的这个Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpd
spec:
replicas: 3
selector:
matchLabels:
app: httpd
template:
metadata:
labels:
app: httpd
spec:
containers:
- name: httpd
image: httpd
ports:
- containerPort: 80
启动了3个pod
pod分配了各自的IP,这些IP只能被集群内的容器和节点访问
接下来创建Service,配置文件如下
apiVersion: v1
kind: Service
metadata:
name: httpd-svc
spec:
selector:
app: httpd
ports:
- protocol: TCP
port: 8080
targetPort: 80
①v1是Service的apiVersion。
②指明当前资源的类型为Service。
③Service的名字为httpd-svc。
④selector使用标签和pod关联。
⑤将Service的8080端口映射到Pod的80端口,使用TCP协议。
执行kubectl apply创建Service httpd-svc
[root@master ~]# kubectl apply -f httpd-svc.yml
service/httpd-svc created
[root@master ~]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpd-svc ClusterIP 10.97.164.120 <none> 8080/TCP 40s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4h51m
httpd-svc分配到一个CLUSTER-IP 10.97.164.120。可以通过该IP访问后端的httpd Pod,根据前面的端口映射,这里要使用8080端口
[root@master ~]# curl 10.97.164.120:8080
<html><body><h1>It works!</h1></body></html>
这和直接访问Pod IP:80是一样的
除了我们创建的httpd-svc,还有一个Service kubernetes,Cluster内部通过这个Service访问Kubernetes API Server。
通过describe查看service的详细信息,从中可以看到Endpoints即为与之对应的Pod
Cluster IP底层实现
CLUSTER-IP是如何映射到Pod IP的呢?答案是iptables。
可以通过iptables-save命令打印出当前节点的iptables规则
大概意思是经过规则跳转,最终将请求转发到后端的三个Pod。
结论:iptables将访问Service的流量转发到后端Pod,而且使用类似轮询的负载均衡策略。
另外,需要补充一点:Cluster的每一个节点都配置了相同的iptables规则,这样就确保了整个Cluster都能够通过Service的Cluster IP访问Service
DNS访问Service
kubeadm部署时会默认安装coredns组件
coredns是一个DNS服务器。每当有新的Service被创建,coredns会添加该Service的DNS记录。Cluster中的Pod可以通过<SERVICE_NAME>.<NAMESPACE_NAME>访问Service。
如下在一个临时的busybox Pod中验证了DNS的有效性。
另外,由于这个Pod与httpd-svc同属于default namespace,因此可以省略default直接用httpd-svc访问Service
用nslookup查看httpd-svc的DNS信息
Server是DNS服务器
httpd-svc.default.svc.cluster.local是httpd-svc的完整域名
外网如何访问Service
Kubernetes提供了多种类型的Service,默认是ClusterIP。
ClusterIP只能在Cluster内部访问,如果要在外部访问service,这就要通过NodePort来实现。
apiVersion: v1
kind: Service
metadata:
name: httpd-svc
spec:
type: NodePort
selector:
app: httpd
ports:
- protocol: TCP
port: 8080
targetPort: 80
添加type: NodePort,重新创建httpd-svc
Kubernetes依然会为httpd-svc分配一个ClusterIP,8080是ClusterIP监听的端口
除此之外,8080后的端口:31639,则是节点监听的端口,每个节点都会监听此端口并将请求转发给Service
在master节点上测试
集群外访问测试
这时,集群外也可以访问服务了
NodePort默认的是随机选择,可以用nodePort指定某个特定端口
现在配置文件中就有三个Port了:
(1)nodePort是节点上监听的端口。
(2)port是ClusterIP上监听的端口。
(3)targetPort是Pod监听的端口。
也可以通过expose
命令创建service
查看service
浏览器访问节点ip:30355