Pod 已经成功运行起来了,可是有两个问题。html
一是这些 Pod 没法从集群外部直接访问到,二是 Pod 出现故障自愈后,IP 会发生变化。前端
如何解决这两个问题,这里有一个很是重要的概念:Servicenode
Service 是由 kube-proxy 组件加上 iptables/LVS 共同实现。
说白了就是经过 kube-proxy 生成了一堆 iptables 规则,经过 iptables 规则来转发数据。linux
iptables 转发:nginx
LVS转发:算法
建立 Pod 和 默认Service,进行默认工做状态的测试。后端
先建立3个 Podapi
cat nginx.yaml微信
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: selector: matchLabels: app: nginx replicas: 3 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80
建立一个默认类型的 Service,名称为 nginx-service网络
cat nginx-service.yaml
apiVersion: v1 kind: Service metadata: name: nginx-service spec: selector: app: nginx ports: - port: 80 targetPort: 80 protocol: TCP
port: 80
是 service 在集群内部的VIP端口
targetPort: 80
是 Pod 的端口
执行建立
kubectl apply -f nginx.yaml kubectl apply -f nginx-service.yaml
查看运行状况
[root@master01 ~]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-d46f5678b-cldf4 1/1 Running 0 21m 192.10.137.153 work03 <none> <none> nginx-deployment-d46f5678b-lnxh9 1/1 Running 0 21m 192.10.205.252 work01 <none> <none> nginx-deployment-d46f5678b-th8xq 1/1 Running 0 21m 192.10.75.89 work02 <none> <none> [root@master01 ~]# kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-service ClusterIP 192.20.150.26 <none> 80/TCP 13m
查看名称为 nginx-service 的 service 成功挂载的后端 Pod
[root@master01 ~]# kubectl get endpoints nginx-service NAME ENDPOINTS AGE nginx-service 192.10.137.153:80,192.10.205.252:80,192.10.75.89:80 14m
能够看到咱们建立的名为 nginx-service 的 Service 后端挂载了3个 Pod
给3个 Pod 写入内容,访问 Pod 时返回自身的主机名
kubectl exec nginx-deployment-d46f5678b-cldf4 -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html'; kubectl exec nginx-deployment-d46f5678b-lnxh9 -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html'; kubectl exec nginx-deployment-d46f5678b-th8xq -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html';
咱们访问 Service IP 看看
[root@master01 ~]# curl 192.20.150.26 nginx-deployment-d46f5678b-th8xq [root@master01 ~]# curl 192.20.150.26 nginx-deployment-d46f5678b-cldf4 [root@master01 ~]# curl 192.20.150.26 nginx-deployment-d46f5678b-lnxh9
能够看到 Service 成功将请求代理到了后端的一组 Pod,而且进行了流量的分配。
这是 Service 的默认工做类型,只能在集群所属的节点上访问到,离开集群后没法被访问到。
这种工做类型叫作 ClusterIP。
上一节能够看到,Service 默认不对集群外部提供服务,那么如何才能在集群外部访问到呢,有三种方案。
Service 中配置能够 externalIPs,IP 为本集群中 work 节点宿主机 IP。
apiVersion: v1 kind: Service 。。。 。。。 spec: 。。。 。。。 externalIPs: - 192.168.10.16 - 192.168.10.17
在 192.168.10.16/17 上执行 ss -lntp 能够看到 Service 定义的暴露端口。
在集群外部访问 192.168.10.16/17 上 Service 暴露的端口便可。
改造 nginx-service.yaml,增长一行 type: NodePort
cat nginx-service.yaml
apiVersion: v1 kind: Service metadata: name: nginx-service spec: type: NodePort selector: app: nginx ports: - port: 80 targetPort: 80 protocol: TCP
建立 service
kubectl apply -f nginx-service.yaml
查看运行状况
[root@master01 ~]# kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-service NodePort 192.20.167.221 <none> 80:30913/TCP 13m
参数 PORT(S) 80:30913/TCP,其中 30913 就是用来集群外部访问的端口。
能够访问任何一台物理宿主机的 ip:30913 来访问到 Pod。
30913 是 K8S 从固定范围 30000-32767 中选择的,也能够经过参数 nodePort 指定固定端口。
可选择范围能够经过 kube-apiserver 的 –service-node-port-range 参数来修改。
[root@master01 ~]# ss -nltp | grep 30913 LISTEN 0 128 *:30913 *:*
能够看到宿主机上监听了 30913 端口。
测试
在没有运行 K8S 集群的机器上访问 K8S 宿主机 [root@192-168-10-18 ~]# curl 192.168.10.12:30913 nginx-deployment-d46f5678b-2pmts [root@192-168-10-18 ~]# curl 192.168.10.12:30913 nginx-deployment-d46f5678b-zv8m4 [root@192-168-10-18 ~]# curl 192.168.10.12:30913 nginx-deployment-d46f5678b-2pmts
能够看到从集群外部能够成功访问到 Pod 中内容,而且为随机分配。
原理
kube-proxy 在宿主机上建立了 iptables 规则,对宿主机 IP:30913 的访问将被转发到 Service IP,而后 Service 再经过本身的 iptables 规则分发到 Pod
NodePort 方式中,若是要正式对外提供服务,咱们须要在集群外部再建立一个高可用的负载均衡器,以方便把流量转发到宿主机开放的端口上,若是宿主机开放端口发生了变动,咱们须要手工修改前端负载均衡器。
公有云的 LoadBalancer 自动化了这一过程。
LoadBalancer 这种方式应用于公有云,提交一个 type: LoadBalancer 的 Service 建立申请后,公有云会帮咱们建立一个负载均衡器,该负载均衡器会把请求直接分发给 Pod,同时 Pod IP 发生变化后,会自动更新到负载均衡器上。
经过指定 spec.clusterIP 的值为 "None" 能够建立 Headless Service。
Headless Service 不会分配 Cluster IP,kube-proxy 不会处理它们, 并且平台也不会为它们进行负载均衡和路由。
定义了 selector 的无头服务,Endpoint 控制器会在 API 中建立 Endpoints 记录, 而且修改 DNS 配置返回 A 记录,经过这个地址,请求能够直接到达 Service 的后端 Pod 上。
Service 对 IP 信息易变的 Pod 提供了服务发现、负载均衡等管理功能,同时提供了外部访问的能力,从而使外部用户可以稳定的访问到运行在集群内部的 Pod 提供的服务。
上面说的三种工做方式有以下问题:
这些问题致使没法直接应用于生产环境中。
若是想提供给自建集群的生产环境使用,须要在 Service 前面再加一层 Ingress Controller。
微信公众号:zuolinux_com