Kubernetes Service定义中targetPort和port的区别

Kubernetes Service在服务定义中可以有targetPortport:

kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376

porttargetPort之间的区别是什么?

111539 次浏览

服务:将流量导向一个pod。

发送:这是你的应用程序在容器中运行的实际端口。

有时候容器中的应用程序在不同的端口上提供不同的服务。

例子:实际应用程序可以运行8080,该应用程序的健康检查可以在容器的8089端口上运行。 因此,如果你点击没有端口的服务,它不知道应该将请求重定向到容器的哪个端口。服务需要有一个映射,这样它才能到达容器的特定端口

kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
nodePort: 30475
port: 8089
protocol: TCP
targetPort: 8080
- name: metrics
nodePort: 31261
port: 5555
protocol: TCP
targetPort: 5555
- name: health
nodePort: 30013
port: 8443
protocol: TCP
targetPort: 8085

如果你命中my-service:8089,流量被路由到容器的8080 (targetPort)。类似地,如果你点击my-service:8443,那么它会被重定向到容器的8085 (targetPort)。但是这个myservice:8089是kubernetes集群内部的,当一个应用程序想要与另一个应用程序通信时可以使用。因此,要从集群外部访问服务,需要公开运行kubernetes的主机上的端口 因此,流量被重定向到集装箱的一个端口。这是node port(主机上公开的端口)。 从上面的例子中,你可以通过host_ip:nodePort

从集群外部(Postman或任何rest-client)命中服务

假设你的主机ip是10.10.20.20,你可以通过10.10.20.20:3047510.10.20.20:3126110.10.20.20:30013来访问http, metrics,健康服务。

编辑:根据Raedwald注释编辑。

@Manikanta P上面给出的答案是正确的。然而,“Port”的解释初读时可能有点不清楚。我将用一个例子来解释:

考虑一个web应用程序,它的静态内容(首页,图像等)由httpd托管,而动态内容(例如。响应请求等)由tomcat托管。Webserver(或静态内容)由httpd在80端口提供,而Appserver(或动态内容)由tomcat在8080端口提供。

开发者想要的:用户应该能够从外部访问web服务器,但不能从外部访问应用服务器。

解决方案:服务中的web服务器的服务类型。yml将是NodePort,而Appserver的service-type在其服务中。yml将是ClusterIP。

webserver的service.yml代码:

spec:
selector:
app: Webserver
type: NodePort        // written to make this service accessible from outside.
ports:
- nodePort: 30475   // To access from outside, type <host_IP>:30475 in browser.
port: 5050        // (ignore for now, I will explain below).
protocol: TCP
targetPort: 80  // port where httpd runs inside the webserver pod.

Appserver的service.yml代码

spec:
selector:
app: appserver
type: ClusterIP        // written to make this service NOT accessible from outside.
ports:
- port: 5050         // port to access this container internally
protocol: TCP
targetPort: 8080   // port where tomcat runs inside the appserver pod.

还要注意,在Webserver的httpd.conf文件中,我们将写入将用户请求重定向到应用服务器的IP。这个IP将是:host_IP:5050

这里到底发生了什么? 用户写入hostIP:30475并看到web服务器的页面。这是因为它是由httpd在端口80 (targetport)提供的。当用户单击按钮时,就会发出请求。这个请求被重定向到Appserver,因为在httpd.conf文件中,端口5050被提到,这是Appserver的容器和Webserver的容器内部通信的端口。当应用服务器接收到请求时,它能够服务这个请求,因为在它内部的端口8080上运行了tomcat

它帮助我从关于服务的角度思考问题。

  • nodePort:外部流量将进入的节点上的端口
  • port:端口这项服务
  • targetPort pod上用于转发流量的目标端口

流量从nodePort进入,转发到服务上的port,然后路由到pod上的targetPort

值得强调的是,nodePort用于外部通信。集群中其他可能需要访问服务的pod将只使用port,而不是nodePort,因为它仅是对服务的内部访问。

同样值得注意的是,如果没有设置targetPort,它将默认为与port相同的值。例如,服务端口8080:80,容器端口8080:80

这个答案是参考Kubernetes的文档以及其他答案:

https://kubernetes.io/docs/concepts/services-networking/connect-applications-service/:

targetPort:是容器接收流量的端口,

port:是抽象的服务端口,它可以是其他pod用来访问服务的任何端口

https://kubernetes.io/docs/concepts/services-networking/service/:

Pods中的端口定义有名称,您可以在服务的targetPort属性中引用这些名称。即使服务中有使用单一配置名称的pod的混合物,通过不同的端口号使用相同的网络协议,这种方法也有效。

“目标port"运行容器的端口。

端口:端口将流量从服务重定向到容器。

公开部署

  master $ kubectl get deployments
NAME         READY   UP-TO-DATE   AVAILABLE   AGE


nginx        1/1     1            1           31s
master $ kubectl expose deployment nginx --name=nginx-svc --port=8080 --target-port=80
service/nginx-svc exposed


master $ kubectl get svc


NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE


nginx-svc    ClusterIP   10.107.209.151   <none>        8080/TCP   5s

NodePort:服务对外访问的端口。

希望这是答案。

在简而言之

nodeport:监听nodeip:nodeport上所有工作节点上的外部请求,并将请求转发到端口。

ClusterIP:请求来自入口,指向服务名和端口。

port:容器的内部集群服务端口,监听来自nodeport的传入请求并转发到targetPort。

targetPort:从端口接收请求并转发到它正在监听的容器pod(port)。即使不指定,默认情况下也会分配与port相同的端口号。

所以交通流量Ingress-->Service-->Endpoint(Basically has POD IP)-->POD

如果容器监听端口9376,则 发送< /强>:9376

如果服务监听端口80,则

< / >强港:80

然后服务端口配置如下所示

ports:
- protocol: TCP
port: 80
targetPort: 9376

最后,请求接收到服务的港口,并转发到pod的发送

案例1:

让我们假设没有nodPort或port,现在你想运行你的应用程序并将其暴露给外部,你将需要:

  1. 一个Ingress控制器,它将使用servicePort根据路由重定向到我们想要的服务。
  2. 一个集群IP服务,其中定义了到应用程序端口的目标(也称为targetPort)
  3. 用于标识计算机上运行的应用程序或服务的网络端口(换句话说就是应用程序端口)。

所以,要从外部进入,我们需要三个端口。

  1. servicePort(入口控制器)
  2. targetPort(集群Ip服务)
  3. networkPort(应用端口)

工作一切正常: servicePort === targetPort === networkPort

.使用实例

< >强案例2: 现在假设一个服务与集群中的另一个服务通信,或者假设一个服务从外部接收到一个请求,它发出一个事件,触发了集群内的另一个服务

假设服务X通过使用nodePort服务暴露在外部,在收到请求后,X服务希望与Y服务通信。

Y服务需要以下端口

  1. ClusterIP端口,X服务通过该端口转发请求
  2. 一个ClusterIP targetPort, Y服务将通过该ClusterIP targetPort确定哪个端口应用程序正在运行。
  3. 应用端口

端口=== any

targetPort ===应用程序端口

内部服务X:

app.post('/posts/create', async (req, res) => {
const id = randomBytes(4).toString('hex');
const { title } = req.body;


posts[id] = {
id,
title
};


await axios.post('http://event-bus-srv:4010/events', {
type: 'PostCreated',
data: {
id,
title
}
});


res.status(201).send(posts[id]);
});

服务Y的配置和内部

apiVersion: v1
kind: Service
metadata:
name: event-bus-srv
spec:
selector:
app: event-bus
type: ClusterIP
ports:
- name: event-bus
protocol: TCP
port: 4010
targetPort: 4009
app.listen(4009, () => {


console.log('Listening on 4009');
});

enter image description here

发送: pod中容器监听的一个或多个端口。

nodeport:主要用于接受消费者请求。(例如:从消费者到运行在容器中的web服务器的HTTP请求)

Nodeport在所有接口上的所有节点上侦听,即0.0.0.0:Nodeport。发送到nodeport的使用者服务请求被路由到容器的targetport,以便容器能够满足该请求。

港口:在kubernetes pod网络中使用的端口,主要用于在pod之间交换请求。在这里,来自另一个pod的请求也被路由到腐蚀pod的容器targetport。

总结:所有请求都在发送中结束。nodeport用于k8s网络外部的请求;港口如果从内部。

我认为形象是最好的描述。

enter image description here

由于人们已经在Kubernetes服务定义中解释了porttargetPort,我将添加有关Dockerfile、Kubernetes部署和Kubernetes Ingress的信息,因为它们是公共工作流的一部分。

第1部分-应用程序及其Dockerfile

假设您在端口3000上运行Flask服务器,在端口4000上运行Golang服务器。当你使用Docker容器化这些应用程序时,你必须在它们的Dockerfiles中公开端口3000和4000:

Python

应用程序

...
...
if __name__ == "__main__":
app.run(host='0.0.0.0', port=3000)

Dockerfile

FROM python:3.10-alpine


...


...


EXPOSE 3000


CMD ...

Golang

应用程序

...
...
func main() {
...
log.Fatal(http.ListenAndServe(":4000", nil))
}

Dockerfile

FROM golang:1.18-alpine


...


...


EXPOSE 4000


CMD ...

第2部分- Dockerfiles和Kubernetes部署

__abc0中暴露的端口必须与部署清单中的containerPort匹配。

Python部署清单

---
apiVersion: apps/v1
kind: Deployment
metadata:
name: python-flask-api
spec:
...
...
app: flask-api
template:
metadata:
labels:
app: flask-api
spec:
containers:
- name: flask-api
image: ...
ports:
- containerPort: 3000
...
...

Golang部署清单

---
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-backend-api
spec:
...
...
app: go-api
template:
metadata:
labels:
app: go-api
spec:
containers:
- name: go-api
image: ...
ports:
- containerPort: 4000
...
...

第3部分- Kubernetes部署和服务

部署清单中的containerPort必须与服务清单中的targetPort匹配

Python服务清单

apiVersion: v1
kind: Service
metadata:
name: flask-api-service
spec:
type: NodePort
selector:
app: flask-api
ports:
- port: 80
targetPort: 3000

Golang服务舱单

apiVersion: v1
kind: Service
metadata:
name: go-api-service
spec:
type: NodePort
selector:
app: go-api
ports:
- port: 443
targetPort: 4000

第4部分- Kubernetes服务和入口

服务清单中的port必须与入口中的端口number匹配

适用于Python和Golang应用程序的AWS入口

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: microservice-app-ingress
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
spec:
rules:
- host: foo.biz.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: go-api-service
port:
number: 443
- host: bar.biz.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: flask-api-service
port:
number: 80

  • 一个传入请求命中端口number上的入口

  • 入口将此请求转发给服务port

  • 业务端口将port映射到targetPort

  • 从服务targetPort请求到部署containerPort

  • 部署containerPort是应用程序的Docker镜像,它在其Dockerfile中公开了相应的端口

  • 最后,Dockerfile中的暴露端口将请求发送给应用程序

  1. NodePort =将kubernetes服务对外公开到internet
  2. Port =将在集群中公开kubernetes服务,这样多个不同pod之间的通信就可以发生,并将请求重定向到TargetPort(因为不可能在同一个端口上运行多个pod, K8S引入了Port来处理可重用性)
  3. TargetPort =容器正在运行的实际端口

作为在docker-compose中指定的参考

ports:
- 8080:80

从上面你可以比较8080是主机端口代表端口,80是目标端口

目标器端口说明

# pod file
apiVersion: v1
kind: Pod
metadata:
name: pod_name
labels:
name: pod_ref
spec:
containers:
- name: docker-container
image: python:3:11
ports:
- containerPort: 5000 # this is the target port which we need to access (target) from service file


---
apiVersion: v1
kind: Service
metadata:
name: service_config
labels:
name: service_config_ref
spec:
type: NodePort
selector:
name: pod_ref  # same as pod metadata match labels
ports:
- targetPort: 5000 # this is where the pod is listening
port: 80 # this is where this service (this file) is going to listen.
# If you call the port 80, it will reach the service, then the service will forward the port to port:5000