上次写博客是n多年以前了,以前的几十篇在blogjava里面应该还能吵到。最近遭遇变故,忽然想把自己近期学的一点东西记录下来,日后查阅起来也是方便。
话不多说,笔者最近在啃k8s,容器也好、k8s也罢,里面和服务相关的port概念五六个,索性整理一下,看看他们之间的关系。
首先看一下我们的测试环境:
一组三从的k8集群:
root@dev-4-control-plane# sh node.sh
|NODE |INTERNAL_IP
|dev-4-control-plane |172.18.0.2
|dev-4-worker |172.18.0.5
|dev-4-worker2 |172.18.0.4
|dev-4-worker3 |172.18.0.3
三副本的前端服务:
root@dev-4-control-plane# sh pod.sh
|NAME |NODE |IP |STATUS
|frontend-5b79c8694b-6hjrc |dev-4-worker3/172.18.0.3 |10.244.1.9 |Running
|frontend-5b79c8694b-87xnh |dev-4-worker2/172.18.0.4 |10.244.3.9 |Running
|frontend-5b79c8694b-lkbt5 |dev-4-worker/172.18.0.5 |10.244.2.9 |Running
root@dev-4-control-plane# sh svc.sh
|NAME |CLUSTERIP |PORT |TARGETPORT |ENDPOINTS
|frontend |10.96.48.151 |NodePort% |80/TCP |10.244.1.9:80,10.244.2.9:80,10.244.3.9:80
接下来看看我们的service及deployment中的port定义:
root@dev-4-control-plane# kubectl describe svc frontend
Name: frontend
Namespace: default
Type: NodePort
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.96.48.151
IPs: 10.96.48.151
Port: <unset> 8088/TCP
TargetPort: 80/TCP
NodePort: <unset> 30080/TCP
Endpoints: 10.244.1.9:80,10.244.2.9:80,10.244.3.9:80
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
root@dev-4-control-plane# kubectl describe deployment frontend
Name: frontend
Namespace: default
CreationTimestamp: Thu, 20 Apr 2023 03:11:12 +0000
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=guestbook
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=guestbook
Containers:
php-redis:
Image: anjia0532/google_samples.gb-frontend:v5
Port: 8081/TCP
Host Port: 9088/TCP
Environment:
GET_HOSTS_FROM: dns
Mounts: <none>
Volumes: <none>
好了,开始进入今天的主题。从上面的内容中可以获取如下信息:
clusterIP: 10.96.48.151
nodeIP: 172.18.0.3\172.18.0.4\172.18.0.5
podIP: 10.244.1.9\10.244.2.9\10.244.3.9
containerPort: 8081(这个端口就是deployment中的port,由于测试中使用的image的问题,apache使用的80端口不可修改,因此这个8081定义实际不起作用)
hostPort:9088(这个端口就是deployment中的port)
servicePort: 8088(service中的port)
TargetPort: 80 (这个端口理论上需要和container保持一致,但因为咱们实验中的镜像使用了不可改的80,因此containerPort不生效,为了不影响测试,这个targetPort直接指向了实际listen的port)
NodePort: 30080
准备好两个客户端,分别为 dev-4-worker3(同集群客户端)、dev-2-worker(异集群客户端),看看他们分别可以通过哪些途径访问pod中的service。验证结果如下,其中同集群客户端有三种方式访问,分别为:podIP+containerPort、nodeIP+nodePort、clusterIP+servicePort,而集群外的客户端只有一种访问方式,即:nodeIP+nodePort。
#dev-4-worker2:
#1、podIP+containerPort: curl http://10.244.1.9:80
#2、nodeIP+nodePort: curl http://172.18.0.3:30080
#3、clusterIP+serviePort: curl http://10.96.48.151:8088
#dev-2-worker:
#1、nodeIP+nodePort: curl http://172.18.0.3:30080
不过大家发现问题没有?我们定义了hostPort,理论上hostPort和nodePort是一致的,但为什么无论集群内外的客户端都无法通过nodeIP+hostPort方式访问呢?看一下iptable信息吧
root@dev-4-worker3:/# iptables -t nat -nvL | grep 9088
0 0 CNI-HOSTPORT-SETMARK tcp -- * * 10.244.1.0/24 0.0.0.0/0 tcp dpt:9088
0 0 CNI-HOSTPORT-SETMARK tcp -- * * 127.0.0.1 0.0.0.0/0 tcp dpt:9088
0 0 DNAT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:9088 to:10.244.1.8:8081
0 0 CNI-DN-ae37526a616fce7a60616 tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* dnat name: "kindnet" id: "d5c4b7e0630bd6419d118eabcefe960976097792ac610eec265eecc691f9087a" */ multiport dports 9088
看到了吗?9088端口的流量被转发给无效containerPort 8081了(说明deployment中的hostPort代理了外部到containerPort的流量),访问自然无法正常。我们修改一下containerPort,看看能否正常访问。
看一下路由表,DNAT成功指向了80端口,再访问一下试试:
root@dev-4-worker3:/# iptables -t nat -nvL | grep 9088
0 0 CNI-HOSTPORT-SETMARK tcp -- * * 10.244.1.0/24 0.0.0.0/0 tcp dpt:9088
0 0 CNI-HOSTPORT-SETMARK tcp -- * * 127.0.0.1 0.0.0.0/0 tcp dpt:9088
0 0 DNAT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:9088 to:10.244.1.8:80
0
路由结果正常了,我们再分别测试一下两个客户端的访问情况:
同集群节点访问
root@dev-4-worker3:/# wget http://172.18.0.3:9088
--2023-04-20 03:13:13-- http://172.18.0.3:9088/
Connecting to 172.18.0.3:9088... connected.
HTTP request sent, awaiting response... 200 OK
成功,再从异集群节点访问看看,
root@dev-2-worker:/# wget http://172.18.0.3:9088
--2023-04-20 03:15:30-- http://172.18.0.3:9088/
Connecting to 172.18.0.3:9088... connected.
HTTP request sent, awaiting response... 200 OK
为什么我们再deployment中定义了containerPort为8081,而实际侦听端口仍旧为80呢?检查一下image文件就可以发现端倪(ExposePorts已经写死了80为服务端口)。
root@dev-4-worker2:/# crictl ps
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD
8b328f18c15e7 4ea64ff11cebf About an hour ago Running php-redis 0 11329fb49ffe0 frontend-5b79c8694b-87xnh
52a2ff4407dc2 2355926154447 5 hours ago Running leader 7 d532eeac5a9ee redis-leader-6b57b8f94f-598mp
93d983ce50eee eb3079d47a23a 5 hours ago Running kube-proxy 182 c2c0ac4a7dbff kube-proxy-sbrgc
4106a715cae68 a329ae3c2c52f 5 hours ago Running kindnet-cni 7 aa69fb8caeffe kindnet-qvdcd
root@dev-4-worker2:/# crictl inspecti 4ea64ff11cebf
{
"status": {
"id": "sha256:4ea64ff11cebf416e4a0629549d7f66275b8f1ba8e6dc714e44a1c47241b82d1",
"repoTags": [
"docker.io/anjia0532/google_samples.gb-frontend:v5"
],
......
"imageSpec": {
"created": "2021-12-31T18:54:06.462754392Z",
"architecture": "amd64",
"os": "linux",
"config": {
"ExposedPorts": {
"80/tcp": {}
},
好了,最后对几个port做一下简单的总结,如果错误不吝斧正:
container:containerPort | 容器中服务的listen port,当然这个port能否通过containerPort指定取决与image的写法,比如文中所提写死80的做法,此时containerPort怎么设置都不会生效。 |
service:port | 这个servicePort通常结合clusterIP使用的,用于集群内服务调用,当然集群内互访也可以通过podIP+containerPort、nodeIP+nodePort等方式访问,但这些方式没法做负载均衡和故障恢复透明。 |
service:targetport | 这个需要和container的containerPort保持一致,我们看到service的endpoint列表中使用的是这个端口,如果和container不一致,则数据无法正常理由 |
service:nodePort | 用于提供集群外的客户端访问,通过nodeIP + nodePort即可访问,但更常见的是用于前端的load balancer的服务端点 |
container:hostPort | 这个和nodePort类似,早期k8s中nodePort会在node上起对应的nodePort侦听,而hostPort不会起侦听,不过现在的版本中无论hostPort还是nodePort都是通过ipvs实现端口映射,不会再启用侦听,不知道这两个port概念将来会不会删掉一个。文章来源:https://www.toymoban.com/news/detail-553979.html |
文章来源地址https://www.toymoban.com/news/detail-553979.html
到了这里,关于k8s之containerPort、servicePort、nodePort、hostPort解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!