kubernetes集群上运行的pod,在集群内访问是很容易的,最简单的,可以通过pod的ip来访问,也可以通过对应的svc来访问,但在集群外,由于kubernetes集群的pod ip地址是内部网络地址,因此从集群外是访问不到的。

为了解决这个问题,kubernetes提供了如下几个方法。

  • hostNetwork
  • hostPort
  • service NodePort

hostNetwork: true
hostNetwork为true时,容器将使用宿主机node的网络,因此,只要知道容器在哪个node上运行,从集群外以 node-ip + port 的方式就可以访问容器的服务。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  hostNetwork: true
  containers:
    - name: nginx
      image: nginx

pod启动后,如下,可以看到pod的ip地址与node节点的地址是一致的

[root@localhost ~]# kubectl get pods -o wide nginx
NAME    READY   STATUS    RESTARTS   AGE    IP              NODE       NOMINATED NODE
nginx   1/1     Running   0          8m2s   192.168.10.10   minikube   <none>

[root@localhost ~]# kubectl get nodes -o wide 
NAME       STATUS   ROLES    AGE   VERSION   INTERNAL-IP     EXTERNAL-IP   OS-IMAGE                KERNEL-VERSION          CONTAINER-RUNTIME
minikube   Ready    master   11d   v1.12.1   192.168.10.10   <none>        CentOS Linux 7 (Core)   3.10.0-957.el7.x86_64   docker://17.12.1-ce

可以通过curl或者浏览器直接访问node节点的地址,即可以访问到nginx的服务

[root@localhost ~]# curl http://192.168.10.10
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
......
</html>
[root@localhost ~]#

hostNetwork的优点是直接使用宿主机的网络,只要宿主机能访问,Pod就可以访问;但缺点也是很明显的:

  • 易用性:Pod漂移到其他node上,访问时需要更换ip地址。解决方法是将Pod绑定在某几个node上,并在这几个node上运行keepalived以漂移vip,从而客户端可以使用vip+port的方式来访问。
  • 易用性:Pod间可能出现端口冲突,造成Pod无法调度成功。
  • 安全性:Pod可以直接观察到宿主机的网络。

hostPort
hostPort的效果与hostNetwork类似,hostPort是直接将容器的端口与所调度的节点上的端口进行映射,这样用户就可以通过宿主机的IP加上映射到绑定主机的端口来访问Pod了

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
    - name: nginx
      image: nginx
      ports:
        - containerPort: 80     #pod容器指定的端口
          hostPort: 9090        #映射到node主机的端口

pod启动后如下,可以看到,pod的ip地址是内部网络ip,与宿主机node的ip不同;与hostNetwork一样,也可以通过node ip + pod port访问,此处的访问port地址为,pod容器端口映射到node主机的端口地址

[root@localhost ~]# kubectl get pods -o wide nginx
NAME    READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE
nginx   1/1     Running   0          57s   172.17.0.2   minikube   <none>
[root@localhost ~]#

可以curl访问,也可以浏览器访问

[root@localhost ~]# curl -I http://192.168.10.10:9090
HTTP/1.1 200 OK
Server: nginx/1.19.2
Date: Tue, 01 Sep 2020 09:56:16 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 11 Aug 2020 14:50:35 GMT
Connection: keep-alive
ETag: "5f32b03b-264"
Accept-Ranges: bytes

[root@localhost ~]#

hostPort的优缺点与hostNetwork类似,因为它们都是使用了宿主机的网络资源。hostPort相对hostNetwork的一个优点是,hostPort不需要提供宿主机的网络信息,但其性能不如hostNetwork,因为需要经过iptables的转发才能到达Pod。

service NodePort
与hostPort、hostNetwork只是Pod的配置不同,NodePort是一种service,其使用的是宿主机node上的端口号,从集群外以 任意node的ip + nodePort 来访问Pod的服务。

NodePort 在 kubenretes 里是一个广泛应用的服务暴露方式。Kubernetes中的service默认情况下都是使用的ClusterIP这种类型,这样的service会产生一个ClusterIP,这个IP只能在集群内部访问,要想让外部能够直接访问service,需要将service type修改为 nodePort。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    name: nginx
spec:
  containers:
    - name: nginx
      image: nginx
      ports:
        - containerPort: 80
---
kind: Service
apiVersion: v1
metadata:
  name: nginx
spec:
  type: NodePort
  ports:
    - name: nginx
      port: 80
      nodePort: 30000
  selector:
    name: nginx

svc 配置中的nodePort,即为访问服务时,宿主机的端口号。可以在配置文件中指定(当然不能与其他nodePort类型的svc冲突),也可以不配置,由k8s来分配。

创建上述Pod和service后,如下,查看pod和svc的相关信息,我们可以通过宿主机的ip地址+noePort来访问pod的服务

[root@localhost ~]# kubectl get pods -o wide nginx
NAME    READY   STATUS    RESTARTS   AGE     IP           NODE       NOMINATED NODE
nginx   1/1     Running   0          5m47s   172.17.0.2   minikube   <none>
[root@localhost ~]# 
[root@localhost ~]# kubectl get svc -o wide nginx
NAME    TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE     SELECTOR
nginx   NodePort   10.96.116.150   <none>        80:30000/TCP   5m58s   name=nginx
[root@localhost ~]# 
[root@localhost ~]# kubectl get nodes -o wide
NAME       STATUS   ROLES    AGE   VERSION   INTERNAL-IP     EXTERNAL-IP   OS-IMAGE                KERNEL-VERSION          CONTAINER-RUNTIME
minikube   Ready    master   11d   v1.12.1   192.168.10.10   <none>        CentOS Linux 7 (Core)   3.10.0-957.el7.x86_64   docker://17.12.1-ce
[root@localhost ~]# 
[root@localhost ~]# curl -I http://192.168.10.10:30000
HTTP/1.1 200 OK
Server: nginx/1.19.2
Date: Tue, 01 Sep 2020 10:14:12 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 11 Aug 2020 14:50:35 GMT
Connection: keep-alive
ETag: "5f32b03b-264"
Accept-Ranges: bytes

[root@localhost ~]#

集群外就可以使用kubernetes任意一个节点的IP加上30000端口访问该服务了。kube-proxy会自动将流量以round-robin的方式转发给该service的每一个pod。

这种服务暴露方式,无法让你指定自己想要的应用常用端口,不过可以在集群上再部署一个反向代理作为流量入口

service的作用体现在两个方面,对集群内部,它不断跟踪pod的变化,更新endpoint中对应pod的对象,提供了ip不断变化的pod的服务发现机制,对集群外部,他类似负载均衡器,可以在集群内外部对pod进行访问。但是,单独用service暴露服务的方式,在实际生产环境中不太合适:
ClusterIP的方式只能在集群内部访问。
NodePort方式的话,测试环境使用还行,当有几十上百的服务在集群中运行时,NodePort的端口管理是灾难。
LoadBalance方式受限于云平台,且通常在云平台部署ELB还需要额外的费用。
————————————————

LoadBalancer、Ingress可以实现pod的外网访问,后续在做整理...

 

参考文档:https://ieevee.com/tech/2020/01/06/access-pods.html