k8s外部访问的几种方法实践

学习k8s的路上。。。
本次实践是本地部署了minikube 单节点的k8s 环境,minikube是一个虚拟机环境,只有一个节点,节点ip:172.17.0.2 ,自己打包了一个镜像 jalcge/k8s ,镜像里开放端口8080 ,服务是3个副本,支持滚动更新,给容器传参数进行滚动更新,启动服务后,http外部访问。


hostNetwork、hostPort、NodePort、LoadBalancer、Ingress


外部访问大多是使用service

service的类型:

• ClusterIP:默认值,k8s系统给service自动分配的虚拟IP,只能在集群内部访问。
• NodePort:将Service通过指定的Node上的端口暴露给外部,访问任意一个 NodeIP:nodePort都将路由到ClusterIP。
• LoadBalancer:在 NodePort 的基础上,借助 cloud provider 创建一个外部的负载均 衡器,并将请求转发到 :NodePort,此模式只能在云服务器上使用。
• ExternalName:将服务通过 DNS CNAME 记录方式转发到指定的域名(通过 spec.externlName 设定)。


基础 Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: k8stest           # deployment 名称
  namespace:
spec:
  minReadySeconds: 5      # pod启动后等待5s后提供外部服务,防止服务未启动
  strategy:               # 策略
    type: RollingUpdate   # 支持滚动更新设置
    rollingUpdate:
      maxSurge: 1         # 启动一个新的pod后 才删除 一个pod
      maxUnavailable: 1   # 当maxSurge不为0时,该值也不能为0,最好和maxSurge保持一致
  selector:               # 标签选择
    matchLabels:
      app: jalcge         # #选择label:app=jalcge的容器生成pod实例
  replicas: 3             # 副本数量
  template:
    metadata:
      labels:
        app: jalcge
    spec:
      containers:
        - name: jalcge
          image: jalcge/k8s:latest
          args:                # 给容器传参数方法 command: ["1.0"] 和 args
            - '1.0'
          imagePullPolicy: Always  # Always:总是拉取远程仓库镜像 IfNotPresent:默认值,本地有就不拉取  Never:只使用本地镜像不拉取
          ports:
            - containerPort: 8080  # 容器的开放端口

1, hostNetwork

在Pod中使用hostNetwork:true 配置, pod中的容器直接暴露在宿主机的网络环境中,这时PodIp就是其Node的IP,可以直接通过宿主机的网络访问pod中的应用程序,可以在宿主机中直接访问 NodeIp 来访问pod 服务。
注:
1, 次方法局限性太大,直接暴露 k8s节点的ip ,不安全作为web访问。
2, 对于同Deployment下的hostNetwork: true启动的Pod,每个node上只能启动一个。
也就是说Pod启动副本数不可以多于“目标node”的数量,“目标node”指的是在启动Pod时选定的node,若未选定(没有指定nodeSelector),“目标node”的数量就是集群中全部的可用的node的数量。当副本数大于“目标node”的数量时,多出来的Pod会一直处于Pending状态,因为schedule已经找不到可以调度的node了。

开始下面示例:myapp.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: k8stest          
  namespace:
spec:
  minReadySeconds: 5      
  strategy:              
    type: RollingUpdate   
    rollingUpdate:
      maxSurge: 1         
      maxUnavailable: 1   
  selector:               
    matchLabels:
      app: jalcge         
  replicas: 3             
  template:
    metadata:
      labels:
        app: jalcge
    spec:
      hostNetwork: true   # 将pod暴露在宿主机环境中,这时Pod的PodIP就是其所在Node的IP,
       # 可以直接在外部 http://NodeIP:容器端口/ 直接访问,无需service 缺点是不稳定且 副本数要和节点数一致,多余的副本会一直处于 Pending状态
      containers:
        - name: jalcge
          image: jalcge/k8s:latest
          args:               
            - '1.0'
          imagePullPolicy: Always  
          ports:
            - containerPort: 8080


创建deployment :

kubectl create -f  myapp.yaml
 baily@baily  ~  kubectl get deployments           
NAME      READY   UP-TO-DATE   AVAILABLE   AGE
k8stest   1/3     3            1           121m

baily@baily  ~  kubectl get po -o wide
NAME                      READY   STATUS    RESTARTS   AGE     IP           NODE       NOMINATED NODE   READINESS GATES
k8stest-9cb5887f6-267gm   1/1     Running   0          9m34s   172.17.0.2   minikube              
k8stest-9cb5887f6-lbr28   0/1     Pending   0          9m34s                          
k8stest-9cb5887f6-wfwz5   0/1     Pending   0          9m34s                          

baily@baily  ~  curl http://172.17.0.2:8080/   # 访问服务节点ip:容器端口 http://172.17.0.2:8080/                
This is version:1.0 running in pod minikube  

浏览器访问:
k8s外部访问的几种方法实践_第1张图片
清理:

baily@baily  ~  kubectl delete deployment k8stest   # 删除deployment 会删除3个副本pod
deployment.apps "k8stest" deleted

2, hostPort

这是一种直接定义Pod网络的方式。
在pod 配置 hostPort :容器端口,hostPort是直接将容器的端口与所调度的节点上的端口路由,这样用户就可以通过宿主机的IP加上hostPort访问Pod了。hostPort的设置对象是容器,将容器的端口通过hostIP:hostPort的方式暴露出来。
这样做有个缺点,因为Pod重新调度的时候该Pod被调度到的宿主机可能会变动,这样就变化了,用户必须自己维护一个Pod与所在宿主机的对应关系。
使用了 hostPort 的容器只能调度到端口不冲突的 Node 上,除非有必要(比如运行一些系统级的 daemon 服务),不建议使用端口映射功能。如果需要对外暴露服务,建议使用 NodePort Service。

开始下面示例:myapp.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: k8stest          
  namespace:
spec:
  minReadySeconds: 5      
  strategy:              
    type: RollingUpdate  
    rollingUpdate:
      maxSurge: 1        
      maxUnavailable: 1  
  selector:              
    matchLabels:
      app: jalcge         
  replicas: 3            
  template:
    metadata:
      labels:
        app: jalcge
    spec:
      containers:
        - name: jalcge
          image: jalcge/k8s:latest
          args:              
            - '1.0'
          imagePullPolicy: Always 
          ports:
            - containerPort: 8080
              hostPort: 8080   # hostPort的设置对象是容器,将容器的端口通过hostIP:hostPort的方式暴露出来。

创建deployment :

 kubectl create -f  myapp.yaml

说明:因为本次实践使用的是 minikube, 存在虚拟机隔离,节点的宿主机不是本地,是minikube虚拟机,所以本地直接访问是不行的。

 baily@baily  ~  kubectl get po -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
k8stest-84cdb4d8c-88b4r   0/1     Pending   0          10m                          
k8stest-84cdb4d8c-fqh68   0/1     Pending   0          10m                          
k8stest-84cdb4d8c-lgkkz   1/1     Running   0          10m   172.18.0.5   minikube              

baily@baily  ~  curl http://127.0.0.1:8080/        # 本地访问失败
curl: (7) Failed to connect to 127.0.0.1 port 8080: 拒绝连接

baily@baily  ~  minikube ssh                      # 进入minikube 虚拟机    
docker@minikube:~$

docker@minikube:~$ curl http://127.0.0.1:8080/       # 在虚拟机本地访问
This is version:1.0 running in pod k8stest-84cdb4d8c-lgkkz

本地使用节点IP访问:
k8s外部访问的几种方法实践_第2张图片
清理:

baily@baily  ~  kubectl delete deployment k8stest   # 删除deployment 会删除3个副本pod
deployment.apps "k8stest" deleted

3, NodePort

NodePort在kubenretes里是一个广泛应用的服务暴露方式。外部流量访问K8s的一种方式,即nodeIP:nodePort,是提供给外部流量访问K8s集群资源的一种方式。
NodePort的设置对象是service,默认情况下service只能在集群内部通过ClusterIP访问。创建NodePort service时,用户可以指定范围为30000-32767的端口,对该端口的访问就能通过 kube-proxy 代理到service后端的pod中。

此方法需要新建service ,先创建deployment 和 pod ,使用最开始的基础 deployment

 kubectl create -f  myapp.yaml
baily@baily  ~  kubectl get deployment
NAME      READY   UP-TO-DATE   AVAILABLE   AGE
k8stest   3/3     3            3           49m

baily@baily  ~  kubectl get po -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
k8stest-fc685cb98-kwwtd   1/1     Running   0          50m   172.18.0.7   minikube              
k8stest-fc685cb98-qfhg9   1/1     Running   0          50m   172.18.0.6   minikube              
k8stest-fc685cb98-wp69q   1/1     Running   0          50m   172.18.0.5   minikube              

创建service , app_service.yaml 文件:

apiVersion: v1   # v1是service的apiversion
kind: Service    # 当前资源的类型为 Service。
metadata:
  name: mysvc       # Service 的名字
  namespace: default
spec:
  selector:       # 重要:选择器 label为容器名称 jalcge 的pod作为Service对象,不是pod或deployment的名称
    app: jalcge
  ports:
   - nodePort: 30009    # nodePort 默认30000-32767  外部通过节点ip:port 访问 ,不设置会自动分配
      port:    8010      # k8s内部pod间,服务调用的端口
      targetPort: 8080   # 容器的端口
      protocol: TCP
  type: NodePort   # LoadBalancer:使用负载均衡器 映射外部ip,NodePort:外部通过节点ip:nodePort 访问

执行 :

 kubectl create -f  app_service.yaml

也可以不写 service的yaml 文件创建,直接使用命令创建, 如:

kubectl expose deployment k8stest --type=NodePort --port=8080  --name=mysvc
 baily@baily  ~  kubectl get svc       # 获取service    
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1                443/TCP          45d
mysvc        NodePort    10.106.217.119           8010:30009/TCP   18s

minikube service mysvc                # minikube 访问服务命令
|-----------|-------|-------------|-------------------------|
| NAMESPACE | NAME  | TARGET PORT |           URL           |
|-----------|-------|-------------|-------------------------|
| default   | mysvc |        8010 | http://172.17.0.2:30009 |
|-----------|-------|-------------|-------------------------|
  正通过默认浏览器打开服务 default/mysvc...
正在现有的浏览器会话中打开。
[0415/164931.086972:ERROR:nacl_helper_linux.cc(308)] NaCl helper process running without a sandbox!
Most likely you need to configure your SUID sandbox correctly

外部访问 节点IP:NodePort
k8s外部访问的几种方法实践_第3张图片
清理:

baily@baily  ~  kubectl delete svc mysvc    # 删除服务
service "mysvc" deleted
 baily@baily  ~  kubectl delete deployment k8stest  # 删除deployment 及 pod
deployment.apps "k8stest" deleted

4, LoadBalancer

只能在service上定义,是公有云提供的负载均衡器,如AWS、Azure、CloudStack、GCE等,适用于公有云上的Kubernetes服务。
在那些支持外部负载均衡器的云提供者上面,将type字段设置为"LoadBalancer"会为你的Service设置好一个负载均衡器。该负载均衡器的实际的创建是异步进行的,并且该设置好均衡器会在该Service的status.loadBalancer字段中显示出来。
这时候,你可以指定一个 LoadBalancer 类型的 Service。在service提交后,Kubernetes就会调用 CloudProvider 在公有云上为你创建 一个负载均衡服务,并且把被代理的 Pod 的 IP地址配置给负载均衡服务做后端。

此方法需要新建service ,先创建deployment 和 pod ,使用最开始的基础 deployment ,

 kubectl create -f  myapp.yaml
baily@baily  ~  kubectl get deployment
NAME      READY   UP-TO-DATE   AVAILABLE   AGE
k8stest   3/3     3            3           49m

baily@baily  ~  kubectl get po -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
k8stest-fc685cb98-kwwtd   1/1     Running   0          50m   172.18.0.7   minikube              
k8stest-fc685cb98-qfhg9   1/1     Running   0          50m   172.18.0.6   minikube              
k8stest-fc685cb98-wp69q   1/1     Running   0          50m   172.18.0.5   minikube              

创建service , app_service.yaml 文件:

apiVersion: v1   # v1是service的apiversion
kind: Service    # 当前资源的类型为 Service。
metadata:
  name: mysvc       # Service 的名字
  namespace: default
  selfLink: /api/v1/namespaces/default/services/mysvc
spec:
  externalTrafficPolicy: Cluster
  selector:       # 选择器 label 为容器app jalcge 的pod作为Service对象,不是pod或deployment
    app: jalcge
  ports:
    - port:    8080      # k8s内部pod间,服务调用的端口,没有targetPort: 8080  默认 port和容器端口一样 是 8080
      protocol: TCP
  sessionAffinity: None
  type: LoadBalancer   # LoadBalancer:使用负载均衡器 映射外部ip,NodePort:外部通过节点ip:nodePort 访问

执行 :

 kubectl create -f  app_service.yaml

也可以不写 service的yaml 文件创建,直接使用命令创建, 如:

kubectl expose deployment k8stest --type=LoadBalancer --port=8080 --name=mysvc
 baily@baily  ~  kubectl get svc
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP      10.96.0.1              443/TCP          45d
mysvc        LoadBalancer   10.100.28.40        8080:31349/TCP   25s
 baily@baily  ~  minikube service mysvc
|-----------|-------|-------------|-------------------------|
| NAMESPACE | NAME  | TARGET PORT |           URL           |
|-----------|-------|-------------|-------------------------|
| default   | mysvc |        8080 | http://172.17.0.2:31349 |
|-----------|-------|-------------|-------------------------|
  正通过默认浏览器打开服务 default/mysvc...
正在现有的浏览器会话中打开。
[0415/173307.465364:ERROR:nacl_helper_linux.cc(308)] NaCl helper process running without a sandbox!
Most likely you need to configure your SUID sandbox correctly

外部访问:
正常情况是 service 信息里的 EXTERNAL-IP 会被负载均衡器映射一个可用ip , 使用这个IP和端口31349 在外部访问, 现在一直处于pending状态 ,是minikube 没有负载均衡器 ,一直等待状态。
此次还是使用 minikube 虚拟机的ip 也是节点ip 访问:
k8s外部访问的几种方法实践_第4张图片

清理:

baily@baily  ~  kubectl delete svc mysvc    # 删除服务
service "mysvc" deleted
 baily@baily  ~  kubectl delete deployment k8stest  # 删除deployment 及 pod
deployment.apps "k8stest" deleted

5, Ingress

ingress controller是由K8s管理的负载均衡容器,它的镜像包含一个nginx或HAProxy负载均衡器和一个控制器守护进程。
Ingress是自kubernetes1.1版本后引入的资源类型。必须要部署Ingress controller才能创建Ingress资源,Ingress controller是以一种插件的形式提供。Ingress controller 是部署在Kubernetes之上的Docker容器。它的Docker镜像包含一个像nginx或HAProxy的负载均衡器和一个控制器守护进程。控制器守护程序从Kubernetes接收所需的Ingress配置。它会生成一个nginx或HAProxy配置文件,并重新启动负载平衡器进程以使更改生效。换句话说,Ingress controller是由Kubernetes管理的负载均衡器。

Kubernetes Ingress提供了负载平衡器的典型特性:HTTP路由,粘性会话,SSL终止,SSL直通,TCP和UDP负载平衡等。目前并不是所有的Ingress controller都实现了这些功能,需要查看具体的Ingress controller文档。


apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: influxdb
spec:
  rules:
    - host: influxdb.kube.example.com
      http:
        paths:
          - backend:
              serviceName: influxdb
              servicePort: 8086

外部访问URL http://influxdb.kube.example.com/ping 访问该服务,入口就是80端口,然后Ingress controller直接将流量转发给后端Pod,不需再经过kube-proxy的转发,比LoadBalancer方式更高效。

总的来说Ingress是一个非常灵活和越来越得到厂商支持的服务暴露方式,包括Nginx、HAProxy、Traefik,还有各种Service Mesh,而其它服务暴露方式可以更适用于服务调试、特殊应用的部署。

你可能感兴趣的:(K8S,kubernetes,k8s,外部访问,NodePort,LoadBalancer)