k8s集群的端口映射

1.1 containerPort(容器内部端口)

搭建K8S文档:yum安装K8S
ansible搭建K8S集群:ansible搭建K8S
准备至少3个机器搭建好K8S集群

节点名称IP
k8s-master192.168.116.134
k8s-node1192.168.116.135
k8s-node2192.168.116.136

官网port和service文档:K8S-service-port
containerPort:正常情况下,pod的镜像只要有启用服务和端口,就可以在pod和pod之间访问了,流量已经可以在pod出去了。而containerPort这个字段主要是为了指明端口(让机器知道开放了什么端口)以及和集群的service或者真机进行绑定,让流量知道怎么进入pod。

查看集群节点开放端口

ss -tnl    查看k8s-node1,k8s-node2没有创建pod的时候的开放的端口

在这里插入图片描述
在这里插入图片描述
创建一个pod

vi nginx-container.yml   创建pod

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-con
  name: nginx-con-deployment
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-con
  template:
    metadata:
      labels:
        app: nginx-con
    spec:
      containers:
      - name: nginx-con
        image: docker.io/library/nginx:1.18.0-alpine
        ports:
        - containerPort: 80   #让集群知道pod开放的端口


kubectl apply -f nginx-container.yml   创建pod
kubectl get pod -o wide                查看pod的创建节点

进入容器
kubectl exec -it nginx-con-deployment-7cff68b8f8-f5lbm /bin/sh

vi /etc/apk/repositories   修改源为国内源

https://mirrors.aliyun.com/alpine/v3.6/main
https://mirrors.aliyun.com/alpine/v3.6/community

apk add net-tools    安装网络工具
netstat -tnl         可以看到pod的80端口是开放的
ip a                查看ip为10.100.2.144

在这里插入图片描述

在创建上面pod的k8s-node2节点上查看没有新增的开放端口
证明这个pod没有对外开放端口

ss -tnl

在这里插入图片描述
在master创建一个测试容器,测试pod和pod之间的访问

kubectl run net-test1 --image=alpine --replicas=1 sleep 360000 创建测试pod
kubectl get pod  查看pod名字
kubectl exec -it net-test1-5fcc69db59-mztj2 /bin/sh 连接pod

vi /etc/apk/repositories   修改源为国内源

https://mirrors.aliyun.com/alpine/v3.6/main
https://mirrors.aliyun.com/alpine/v3.6/community

apk add curl    安装网络工具

可以看到网页内容
证明2个pod之间是可以相互访问的,上面的那个老的pod的80端口只是对pod和pod之间开放
curl http://10.100.2.144

在这里插入图片描述

1.2 hostPort(将pod的端口直接映射到真机上,不使用service绑定)

hostport:将pod开放的端口映射到真机节点上,只要有外来的访问到真机的这个端口,那么真机会通过路由和套接字的方式将访问转发到pod。

注意:

  1. pod的yml必须要有containerPort字段指明端口
  2. 创建pod的节点不会开放端口,只会转发流量,如果节点也开放了这个端口,访问请求优先转发到pod
  3. 这种操作适合一次性测试使用,正式环境最好不要使用
  4. 因为pod有重建机制,所以当pod重建到其他节点时,访问的IP也会发生变化

在master创建pod

vi nginx-hostport.yml 

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-host
  name: nginx-host-deployment
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-host
  template:
    metadata:
      labels:
        app: nginx-host
    spec:
      containers:
      - name: nginx-host
        image: docker.io/library/nginx:1.18.0-alpine
        ports:
        - containerPort: 80
          hostPort: 80
          
kubectl apply -f nginx-hostport.yml   创建pod
kubectl get pod -o wide               可以看到pod在k8s-node2创建

在这里插入图片描述
在k8s-node2可以看到没有开放80端口

ss -tnl

在这里插入图片描述
用master直接访问k8s-node2的真机IP的80端口,可以访问到网页

curl http://192.168.116.136

在这里插入图片描述

1.3 service的port、targetPort、nodePort

port:在k8s集群中,service的port可任意取值的抽象端口,其他 Pod 通过该端口访问 Service,正常情况下,service的port和pod镜像开放的端口一致。

比如nginx的镜像是开放80端口,service的port指定的是80端口,那么pod和pod直接就可以进行访问,不用指定targetPort端口。

1.3.1 service的port端口和镜像的端口一致

在master查看service

kubectl get svc -A    可以看到集群2个默认的service

在这里插入图片描述
在master创建pod和service绑定

vi nginx-service-port.yml   创建pod

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-service-port
  name: nginx-service-port-deployment
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-service-port
  template:
    metadata:
      labels:
        app: nginx-service-port
    spec:
      containers:
      - name: nginx-service-port
        image: docker.io/library/nginx:1.18.0-alpine
        ports:
        - containerPort: 80
--- #2个api之间必须要有这个间隔
apiVersion: v1
kind: Service
metadata:
  labels:
    svc: nginx-svc-port     #设置service的标签
  name: nginx-svc-port      #设置service的显示名字
spec:
  ports:
  - port: 80               #让集群知道service绑定的端口
  selector:
    app: nginx-service-port  #指定pod的标签

kubectl apply -f nginx-service-port.yml    创建pod
kubectl get pod -o wide                    查看pod的IP
kubectl get svc -A                         查看service是否创建
kubectl describe svc nginx-svc-port        指定service查看详细信息

Endpoints:         10.100.2.159:80       这个就是代表service绑定的pod的IP

在这里插入图片描述
在master重建pod,查看service的Endpoints的ip会不会随着pod重建而发生改变

上面service的Endpoints的ip对应pod的ip10.100.2.159

kubectl get pod -o wide  查看老的pod的名字

指定pod名字删除,不指定名称空间只会重建pod
kubectl delete pod nginx-service-port-deployment-848bcb6657-5jcxf -n default
kubectl get svc -A   查看service名字
kubectl describe svc nginx-svc-port  再次查看service的详细信息

Endpoints:  10.100.2.160:80  可以看到service会随着绑定的pod的IP变化而变化

在这里插入图片描述
port 注意:
当pod和service绑定后:

  • 不是创建pod的真机node节点不能直接访问service的IP
  • 创建pod的真机node节点能直接访问service的IP
  • pod和pod之间可以直接访问pod的IP和service的IP
  • 有配置dns容器情况下,pod和pod之间可以直接用service的名字访问

在master节点查看

kubectl get pod -o wide             查看pod创建在k8s-node2,IP为10.100.2.160
kubectl get svc                     查看service
curl -I http://10.100.2.160         访问pod的IP
curl -I http://10.200.197.189       访问service的IP,可以看到不能直接访问

在这里插入图片描述
在pod之间访问

kubectl get pod -o wide           查看pod
kubectl exec -it net-test1-5fcc69db59-mztj2 /bin/sh   连接另外的pod
curl -I http://10.100.2.160         访问pod的IP
curl -I http://10.200.197.189       访问service的IP
curl -I http://nginx-svc-port       访问service的名字

在这里插入图片描述

在k8s-node2节点查看

在创建pod的节点上,直接访问pod的IP和service的IP可以直接访问
curl -I http://10.100.2.160         访问pod的IP
curl -I http://10.200.197.189       访问service的IP

在这里插入图片描述

1.3.2 service的port和targetPort配合使用

targetPort:指定从集群内部或外部流入pod的流量端口,通常配合port、nodePort使用。一般port、nodePort和镜像的3个端口一致。
当service的port为其他端口,targetPort指定pod镜像端口时:
比如nginx的镜像是开放80端口,但是service的port指定的是33端口,这种情况下其他pod访问时,就需要访问nginx的service的33端口。

在master创建pod和service

vi nginx-service-port2.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-service-port2
  name: nginx-service-port2-deployment
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-service-port2
  template:
    metadata:
      labels:
        app: nginx-service-port2
    spec:
      containers:
      - name: nginx-service-port2
        image: docker.io/library/nginx:1.18.0-alpine
        ports:
        - containerPort: 80  #指定流量进入pod的端口
---
apiVersion: v1
kind: Service
metadata:
  labels:
    svc: nginx-svc-port2
  name: nginx-svc-port2
spec:
  ports:
  - port: 33              #设置service的端口
    targetPort: 80        #设置pod的端口
  selector:
    app: nginx-service-port2  #指定pod的标签
    
kubectl apply -f nginx-service-port2.yml   创建pod
kubectl get pod -o wide                    查看pod的IP
kubectl get svc                            查看service
kubectl describe svc nginx-svc-port2       查看service的详细信息

Port:              <unset>  33/TCP   可以看到service的端口是33

在这里插入图片描述
在测试容器上安装工具,测试pod和pod之间的访问

kubectl get pod 
kubectl exec -it net-test1-5fcc69db59-7tbsz /bin/sh  进入容器
apk add busybox-extras curl
busybox-extras telnet 10.100.2.167 80     连接nginx的pod的80端口可以连接
curl -I http://10.100.2.167               访问网站可以访问

在这里插入图片描述
在测试容器上,测试pod和service之间的访问

kubectl exec -it net-test1-5fcc69db59-7tbsz /bin/sh   进入容器
busybox-extras telnet 10.200.79.16 80               连接service的80端口
busybox-extras telnet 10.200.79.16 33               连接service的33端口

可以看到service的80端口实际是没有在工作的
所以当其他pod需要指定service的端口时,必须指定33端口
curl -I http://10.200.79.16:33              访问service的33端口
curl -I http://10.200.79.16:80              访问service的80端口

在这里插入图片描述

1.3.2 nodePort(节点开放端口,pod对外端口)

nodePort:在k8s集群中,将pod的内部端口映射到创建pod的节点的指定端口,让外部的流量可以到达pod。

默认yum安装的K8S集群node的开放的端口为30000-32767
如果不是设置这个范围,会提示下面这个报错
The Service “nginx-svc-port” is invalid: spec.ports[0].nodePort: Invalid value: 80: provided port is not in the valid range. The range of valid ports is 30000-32767

如果想要修改K8S集群的端口,按照下面操作
全部master节点修改这个文件,yum按照k8s是这个路径

vi /etc/kubernetes/manifests/kube-apiserver.yaml
在spec.containers.- command字段中添加指定的端口
spec:
  containers:
  - command:
    - --service-node-port-range=10000-12767  #添加指定端口范围

查看k8s-master的api容器名字
kubectl get pods --selector=component=kube-apiserver -n kube-system --output=jsonpath={.items..metadata.name}

指定pod名字,让集群自动重建容器
kubectl delete pod kube-apiserver-k8s-master -n kube-system
kubectl get pod -n kube-system  查看pod的运行时间是否改变

查看pod的信息是否变化
kubectl describe pod kube-apiserver-k8s-master -n kube-system |grep service

在这里插入图片描述
master创建pod

vi nginx-service-nodeport.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-service-nodeport  #设置pod标签
  name: nginx-service-nodeport-deployment
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-service-nodeport
  template:
    metadata:
      labels:
        app: nginx-service-nodeport
    spec:
      containers:
      - name: nginx-service-nodeport
        image: docker.io/library/nginx:1.18.0-alpine
        ports:
        - containerPort: 80  #指定pod端口
---
apiVersion: v1
kind: Service
metadata:
  labels:
    svc: nginx-svc-nodeport
  name: nginx-svc-nodeport
spec:
  type: NodePort     #默认是clusterIP,如果是nodePort,要设置这个
  ports:
  - port: 80         #指定service端口
    targetPort: 80   #指定pod端口
    nodePort: 10080  #指定node的端口
  selector:
    app: nginx-service-nodeport  #指定pod的标签

kubectl apply -f nginx-service-nodeport.yml  创建pod
kubectl get pod -o wide                      查看pod创建的节点
kubectl get svc                              查看service
kubectl describe svc nginx-svc-nodeport      查看service的详细信息

在这里插入图片描述
在创建pod的k8s-node2查看端口是否打开

ss -tnl     可以看到端口10080已经打开

在这里插入图片描述
在master测试访问,可以看到节点端口能被访问

kubectl get pod -o wide            查看pod的IP
kubectl get svc -o wide            查看service
kubectl describe svc nginx-svc-nodeport  查看service的信息
curl -I http://10.100.2.172              访问pod
curl -I http://192.168.116.136:10080     访问节点开放的端口

在这里插入图片描述

1.4 普通service和clusterIP和endpoint

官网文档:service和Headless Services
普通service是K8S的默认service,主要通过kube-proxy和ipvsadm创建service规则,clusterIP就相当于前端对外IP,endpoint记录后端的IP地址,默认调度方式就是轮询。一般和Deployment等控制器配合使用。

流程图
在这里插入图片描述

前端访问流程

  1. k8s创建nginx-pod和nginx-service
  2. 客户端访问存放nginx-pod的k8s-node节点的IP和端口进行访问
  3. k8s通过kube-proxy创建ipvsadm规则,将客户端访问流量调度到nginx-service的clusterIP
  4. clusterIP将流量轮询到nginx-pod的IP
    后端访问流程
  5. nginx-pod通过proxy_pass反向代理到httpd-service,httpd-service已经通过kube-proxy创建了ipvsadm
  6. httpd-service通过clusterIP将流量轮询到httpd-web-pod的IP

1.4.1 在master创建nginx-service

mkdir nginx-httpd-service
cd nginx-httpd-service

vi nginx-svc.yml  创建nginx的service

apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx-service  #指定service名字
  name: nginx-service
spec:
  type: NodePort    #虽然类型是写这个,但是实际还是用clusterIP
  ports:
    - name: nginx
      port: 80
      protocol: TCP
      targetPort: 80
      nodePort: 30080  #指定k8s-node开放的端口
  selector:
    app: nginx-1    #绑定nginx的pod名字


kubectl apply -f nginx-svc.yml   创建service

kubectl describe svc nginx-service -n default  查看service信息

Endpoints:                <none>   因为nginx的pod没有生成,所以没有pod的IP地址
IPs:                      10.0.190.115  实际就是ipvsadm分配的cluster-IP

kubectl get svc nginx-service -n default  可以看到clusterip

CLUSTER-IP

在这里插入图片描述

1.4.2 在master创建nginx-pod

vi nginx-pod.yaml     创建nginx

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-1        
  name: nginx-deployment
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-1   #service通过这个名字绑定pod
  template:
    metadata:
      labels:
        app: nginx-1
    spec:
      containers:
      - name: nginx-1
        image: docker.io/library/nginx:1.18.0-alpine
        ports:
        - containerPort: 80
          protocol: TCP
          name: nginx  #通过这个名字调用service定义的端口

kubectl apply -f nginx-pod.yaml     创建pod
kubectl get pod -n default -o wide  可以看到pod的IP和node的IP
kubectl describe svc nginx-service -n default  可以看到endpoint有IP信息了,对应pod的IP

ipvsadm -ln |egrep "10.0.59.93|20.0.2.90"  可以看到流量从clusterIP调度到pod的IP,方式是轮询

在这里插入图片描述
在这里插入图片描述

1.4.3 master创建httpd-service

vi httpd-svc.yml

apiVersion: v1
kind: Service
metadata:
  labels:
    app: httpd-service
  name: httpd-service
spec:
  type: clusterIP
  ports:
    - name: httpd
      port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: httpd-web-pod  #通过这个绑定pod

kubectl apply -f httpd-svc.yml    创建service
kubectl get svc httpd-service -n default   可以看到最开始endpoint没有IP
kubectl describe svc httpd-service -n default


在这里插入图片描述

1.4.4 master创建httpd-web-pod

vi httpd-web-pod.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: httpd-web-pod  
  name: httpd-deployment
  namespace: default
spec:
  replicas: 2   #创建2个httpd-web
  selector:
    matchLabels:
      app: httpd-web-pod  #service通过这个名字绑定pod
  template:
    metadata:
      labels:
        app: httpd-web-pod
    spec:
      containers:
      - name: httpd
        image: docker.io/library/httpd:2.4
        ports:
        - containerPort: 80
          protocol: TCP
          name: httpd

kubectl apply -f httpd-web-pod.yml
kubectl get pod -n default -o wide
kubectl describe svc httpd-service -n default  可以看到endpoint有2个IP地址,这个是因为定义了2个pod

ipvsadm -ln |egrep "10.0.130.6|20.0.1.68|20.0.2.91"

在这里插入图片描述
在这里插入图片描述

1.4.5 配置nginx-pod反向代理和httpd-web-pod的网页

kubectl get pod -o wide  可以看到创建nginx-pod的node的IP为192.168.116.133

配置nginx
kubectl exec -it nginx-deployment-6bc5d5f6db-vf989 /bin/sh
vi /etc/nginx/conf.d/default.conf    将这段location设置为反向代理

    location / {
        proxy_pass http://httpd-service;  #这里就是将httpd-pod-web绑定,不用再指定IP地址,有点像已经定义了upsteam
    }     
  
nginx -s reload
exit
   
配置httpd-web1,因为是轮询,所以名字不重要
kubectl exec -it httpd-deployment-dc574fc8c-l8jz2 /bin/bash
echo web1 >/usr/local/apache2/htdocs/index.html
exit

配置httpd-web2
kubectl exec -it httpd-deployment-dc574fc8c-2fr65 /bin/bash
echo web2 >/usr/local/apache2/htdocs/index.html
exit

在这里插入图片描述

1.4.6 客户端访问,可以看到轮询效果

访问nginx-pod的node的IP,也就是192.168.116.133,端口已经指定为30080

curl http://192.168.116.133:30080   可以看到后端httpd-web-pod的轮询状态
curl http://192.168.116.133:30080

在这里插入图片描述

1.5 headless service和clusterIP和endpoint

普通service和headless service最大的区别就是clusterIP,而且headless service通常搭配statefulset这种控制器创建pod。

对于headless Services 并不会分配 Cluster IP,kube-proxy 不会处理它们, 而且平台也不会为它们进行负载均衡和路由。 DNS 如何实现自动配置,依赖于 Service 是否定义了选择算符。

  1. 带选择算符的服务
    对定义了选择算符的无头服务,Endpoints 控制器在 API 中创建了 Endpoints 记录, 并且修改 DNS 配置返回 A 记录(IP 地址),通过这个地址直接到达 Service 的后端 Pod 上。

  2. 无选择算符的服务
    对没有定义选择算符的无头服务,Endpoints 控制器不会创建 Endpoints 记录。 然而 DNS 系统会查找和配置,无论是:
    对于 ExternalName 类型的服务,查找其 CNAME 记录
    对所有其他类型的服务,查找与 Service 名称相同的任何 Endpoints 的记录

1.5.1 创建后端httpd-web的headless service

mkdir /root/nginx-httpd-headlessservice
cd /root/nginx-httpd-headlessservice
vi httpd-headless-svc.yml

apiVersion: v1
kind: Service
metadata:
  name: httpd-headless   #pod通过这个名字绑定service
  labels:
    app: httpd-headless
spec:
  ports:
    - name: httpd
      protocol: TCP
      port: 80
      targetPort: 80
  clusterIP: None
  selector:
    app: httpd-web-statefulset  #通过这个绑定pod

kubectl apply -f httpd-headless-svc.yml          创建service
kubectl describe svc httpd-headless -n default   可以看到没有clusterIP
kubectl get svc httpd-headless -o wide

在这里插入图片描述

1.5.2 创建后端httpd-web-statefulset

vi httpd-web-statefulset.yml

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: httpd-web-statefulset
spec:
  selector:
    matchLabels:
      app: httpd-web-statefulset
  serviceName: httpd-headless   #通过这个绑定service
  replicas: 2
  template:
    metadata:
      labels:
        app: httpd-web-statefulset
    spec:
      containers:
      - name: httpd-web
        image: docker.io/library/httpd:2.4
        ports:
        - containerPort: 80
          protocol: TCP
          name: httpd

kubectl apply -f httpd-web-statefulset.yml     创建2个pod
kubectl get pod -n default                     可以看到还是没有clusterIP
kubectl describe svc httpd-headless -n default 查看endpoint的IP

在这里插入图片描述

1.5.3 创建前端nginx-pod和nginx-service

vi nginx-svc.yml

apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx-service
  name: nginx-service
spec:
  type: NodePort
  ports:
    - name: nginx
      port: 80
      protocol: TCP
      targetPort: 80
      nodePort: 30080
  selector:
    app: nginx-1  #通过这个指定pod的名字


vi nginx-pod.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-1
  name: nginx-1     #pod的名字
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-1
  template:
    metadata:
      labels:
        app: nginx-1
    spec:
      containers:
      - name: nginx-1
        image: docker.io/library/nginx:1.18.0-alpine
        ports:
        - containerPort: 80
          protocol: TCP
          name: nginx   #通过这个使用service的端口


kubectl apply -f nginx-svc.yml 
kubectl apply -f nginx-pod.yml 
kubectl get pod -n default -o wide       查看pod
kubectl describe svc nginx-service -n default

在这里插入图片描述

1.5.4 查看httpd的地址,在nginx测试是否能通,配置反向代理

查看httpd的详细域名,修改主页

kubectl get pod -n default -o wide

kubectl exec -it httpd-web-statefulset-0 /bin/bash
cat /etc/hosts
可以看到详细的地址
20.0.2.92	httpd-web-statefulset-0.httpd-headless.default.svc.cluster.local.	httpd-web-statefulset-0

echo web1 >/usr/local/apache2/htdocs/index.html
exit

kubectl exec -it httpd-web-statefulset-1 /bin/bash
cat /etc/hosts
可以看到详细的地址
20.0.2.93	httpd-web-statefulset-1.httpd-headless.default.svc.cluster.local.	httpd-web-statefulset-1

echo web2 >/usr/local/apache2/htdocs/index.html
exit

在这里插入图片描述
在nginx-pod测试是否和httpd互通

kubectl exec -it nginx-1-6bc5d5f6db-wvg2t /bin/sh  可以看到通过域名可以ping通,这样当httpd的pod重启时,不会发送改变IP而不能访问的情况

ping httpd-web-statefulset-0.httpd-headless.default.svc.cluster.local.
ping httpd-web-statefulset-1.httpd-headless.default.svc.cluster.local.

vi /etc/nginx/conf.d/default.conf   在nginx修改配置

添加
    location /web1 {
        proxy_pass http://httpd-web-statefulset-0.httpd-headless.default.svc.cluster.local./;
     }
    location /web2 {
        proxy_pass http://httpd-web-statefulset-1.httpd-headless.default.svc.cluster.local./;
    }


nginx -s reload

在这里插入图片描述

1.5.5 客户端访问,测试是否代理成功

kubectl get pod -o wide  可以看到nginx的pod被创建在了k8s-node的192.168.116.132
curl http://192.168.116.132:30080/web1/
curl http://192.168.116.132:30080/web2/

在这里插入图片描述

在这里插入图片描述

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐