K8S的service和headless service,K8S的containerPort、hostPort和service的port、targetPort、nodePort
k8s集群的端口映射1.1 containerPort(容器内部端口)1.2 hostPort(将pod的端口直接映射到真机上,不使用service绑定)1.3 service的port、targetPort、nodePort1.4 普通service和clusterIP和endpoint1.5 headless service和clusterIP和endpoint...
K8S的service和K8S的headless service,K8S的containerPort、hostPort和service的port、targetPort、nodePort
k8s集群的端口映射
1.1 containerPort(容器内部端口)
搭建K8S文档:yum安装K8S
ansible搭建K8S集群:ansible搭建K8S
准备至少3个机器搭建好K8S集群
节点名称 | IP |
---|---|
k8s-master | 192.168.116.134 |
k8s-node1 | 192.168.116.135 |
k8s-node2 | 192.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。
注意:
- pod的yml必须要有containerPort字段指明端口
- 创建pod的节点不会开放端口,只会转发流量,如果节点也开放了这个端口,访问请求优先转发到pod
- 这种操作适合一次性测试使用,正式环境最好不要使用
- 因为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等控制器配合使用。
流程图
前端访问流程
- k8s创建nginx-pod和nginx-service
- 客户端访问存放nginx-pod的k8s-node节点的IP和端口进行访问
- k8s通过kube-proxy创建ipvsadm规则,将客户端访问流量调度到nginx-service的clusterIP
- clusterIP将流量轮询到nginx-pod的IP
后端访问流程 - nginx-pod通过proxy_pass反向代理到httpd-service,httpd-service已经通过kube-proxy创建了ipvsadm
- 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 是否定义了选择算符。
-
带选择算符的服务
对定义了选择算符的无头服务,Endpoints 控制器在 API 中创建了 Endpoints 记录, 并且修改 DNS 配置返回 A 记录(IP 地址),通过这个地址直接到达 Service 的后端 Pod 上。 -
无选择算符的服务
对没有定义选择算符的无头服务,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/
更多推荐
所有评论(0)