Kubernetes Service
可以在服务定义中包含 targetPort
和 port
:
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
port
和 targetPort
有什么区别?
服务:这会将流量引导到 pod。
TargetPort:这是您的应用程序在容器内运行的实际端口。
端口:有时您的容器内的应用程序在不同的端口上提供不同的服务。
示例: 实际应用程序可以运行 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
,流量将被路由到容器 (targetPort) 的 8080
。同样,如果您点击 my-service:8443
,它会被重定向到容器 (targetPort) 的 8085
。但是这个 myservice:8089
是 Kubernetes 集群内部的,可以在一个应用程序想要与另一个应用程序通信时使用。因此,要从集群外部访问服务,需要在运行 kubernetes 的主机上公开端口,以便将流量重定向到容器的端口。这是 node port
(在主机上公开的端口)。从上面的示例中,您可以通过 host_ip:nodePort
从集群外部(邮递员或任何休息客户端)访问服务
假设您的主机 ip 是 10.10.20.20
,您可以通过 10.10.20.20:30475
、10.10.20.20:31261
、10.10.20.20:30013
访问 http、metrics、health services。
编辑:根据 Raedwald 评论编辑。
它帮助我从服务的角度思考问题。
nodePort:节点上将进入外部流量的端口
端口:此服务的端口
targetPort 将流量转发到的 Pod 上的目标端口
流量从 nodePort
进入,转发到服务上的 port
,然后路由到 pod 上的 targetPort
。
值得强调的是,nodePort
用于外部流量。集群中可能需要访问该服务的其他 pod 将只使用 port
,而不是 nodePort
,因为它只能在内部访问该服务。
另外值得注意的是,如果未设置 targetPort
,它将默认为与 port
相同的值。例如,80:80
用于服务端口 80
,以容器端口 80
为目标。
简而言之
nodeport:
在 nodeip:nodeport
上的所有工作程序节点上侦听外部请求并将请求转发到端口。
ClusterIP:
请求来自入口并指向服务名称和端口。
port:
容器的内部集群服务端口,侦听来自 nodeport 的传入请求并转发到 targetPort。
targetPort:
从端口接收请求并转发到它正在侦听的容器 pod(port)。即使您没有指定,默认情况下也会分配与 port 相同的端口号。
因此流量流向 Ingress-->Service-->Endpoint(Basically has POD IP)-->POD
@Manikanta P 上面给出的答案是正确的。但是,初读时对“端口”的解释可能有点不清楚。我将用一个例子来解释:
考虑一个 Web 应用程序,其静态内容(首页、图像等)由 httpd 托管,动态内容(例如,对请求的响应等)由 tomcat 托管。 Webserver(或静态内容)由 httpd 在端口 80
提供服务,而 Appserver(或动态内容)由 tomcat 在端口 8080
提供服务。
开发人员想要什么:用户应该能够从外部访问 Web 服务器,但不能从外部访问 Appserver。
解决方案:service.yml中Webserver的service-type为NodePort,service.yml中Appserver的service-type为ClusterIP。
网络服务器 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
文件中,我们将写入将用户请求重定向到 appserver 的 IP。此 IP 将是:host_IP:5050
。
这里到底发生了什么?用户写入 hostIP:30475
并看到 Web 服务器的页面。这是因为它是由 httpd 在端口 80
(targetport) 提供的。当用户单击按钮时,会发出请求。此请求被重定向到 Appserver,因为在 httpd.conf
文件中,提到了端口 5050
,这是 Appserver 的容器和 Webserver 的容器内部通信的端口。当应用服务器收到请求时,它能够为请求提供服务,因为它在端口 8080
上运行了 tomcat。
httpd.conf
在哪里
如果容器侦听端口 9376,则 targetPort: 9376
如果服务在端口 80 上侦听,则端口:80
然后服务端口配置如下所示
ports:
- protocol: TCP
port: 80
targetPort: 9376
最后,请求接收到服务的端口,并在 pod 的 targetPort 上转发。
除了其他答案之外,此答案还参考了 Kubernetes 的文档:
https://kubernetes.io/docs/concepts/services-networking/connect-applications-service/:
targetPort:是容器接受流量的端口,
port:是抽象出来的Service端口,可以是其他Pod访问Service的任意端口
https://kubernetes.io/docs/concepts/services-networking/service/:
Pod 中的端口定义具有名称,您可以在 Service 的 targetPort 属性中引用这些名称。即使 Service 中的 Pod 混合使用单个配置名称,也可以通过不同的端口号使用相同的网络协议,这仍然有效。
情况1:
假设没有 nodPort 或端口,现在您要运行您的应用程序并将其暴露给外部,您需要什么:
一个 Ingress 控制器,它将使用 servicePort 根据路由重定向到我们所需的服务。一个集群 IP 服务,它为您的应用程序端口定义了目标(也称为 targetPort) 一个网络端口,它将标识计算机上运行的应用程序或服务(即应用程序端口)。
因此,要从外部访问,我们发现需要三个端口。
servicePort(入口控制器) targetPort(集群 IP 服务) networkPort(应用程序端口)
正常工作: servicePort === targetPort === networkPort
案例 2:现在假设一个服务与我们集群中的另一个服务进行通信,或者假设一个服务接收到来自外部的请求并发出一个事件,该事件触发了我们集群内的另一个服务。
假设服务 X 通过使用 nodePort 服务暴露在外面,在收到请求后,X 服务想与 Y 服务进行通信。
Y服务需要以下端口
ClusterIP 端口,X 服务将通过该端口转发请求 一个 ClusterIP targetPort,Y 服务将通过该端口确定应用程序正在哪个端口运行。应用程序端口
端口 === 任何
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');
});
https://i.stack.imgur.com/2bVEz.png
由于人们已经在 Kubernetes 服务定义中解释了 port
和 targetPort
,我将添加有关 Dockerfile
、Kubernetes Deployment 和 Kubernetes Ingress 的信息,因为它们是通用工作流程的一部分。
第 1 部分 - 应用程序及其 Dockerfile
假设您在端口 3000 上运行 Flask 服务器,在端口 4000 上运行 Golang 服务器。当您使用 Docker 将这些应用程序容器化时,您必须在其 Dockerfile
中公开端口 3000 和 4000:
Python
应用
...
...
if __name__ == "__main__":
app.run(host='0.0.0.0', port=3000)
Dockerfile
FROM python:3.10-alpine
...
...
EXPOSE 3000
CMD ...
戈朗
应用
...
...
func main() {
...
log.Fatal(http.ListenAndServe(":4000", nil))
}
Dockerfile
FROM golang:1.18-alpine
...
...
EXPOSE 4000
CMD ...
第 2 部分 - Dockerfile 和 Kubernetes 部署
Dockerfile
中公开的端口必须与部署清单中的 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 Ingress
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
流动
传入请求在端口号上命中入口
入口将此请求转发到服务端口
服务端口将端口映射到目标端口
从服务 targetPort 请求转到部署 containerPort
部署 containerPort 是应用程序的 Docker 镜像,它的 Dockerfile 中暴露了这个对应的端口
最后,Dockerfile 中暴露的端口将请求发送到应用程序
targetport:容器在 Pod 中侦听的一个或多个端口。
nodeport:主要用于接受消费者请求。 (例如:从消费者到容器中运行的网络服务器的 HTTP 请求)
在所有接口上的所有节点上监听 nodeport,即 0.0.0.0:nodeport。发送到 nodeport 的消费者服务请求被路由到容器的目标端口,以便容器可以满足请求。
port:kubernetes pod 网络中使用的端口,主要用于在 pod 之间交换请求。在这里,来自另一个 pod 的请求也被路由到相应 pod 的容器目标端口。
摘要:所有请求最终都在目标端口中。如果来自外部 k8s 网络的请求,则使用 nodeport;如果来自内部,则使用端口。
“目标端口”是运行容器的端口。
端口:端口将流量从服务重定向到容器。
暴露部署
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 :是使服务能够从外部访问的端口。
希望这个答案。
我认为图像描述的最好。
https://i.stack.imgur.com/O9e5U.png
port
和targetPort
不同有什么好处?因此,例如查看您的health
示例,为什么要使用port
8443
而不是8085
?基本上,为什么有两个参数而不是仅仅公开服务上的所有targetPort
?