GKE - 在运行时将 Pod LoadBalancer(Pod 的外部 IP)旁路到 Pod 容器的 IP 以实现 WebSocket 目的
GKE - Bypass Pod LoadBalancer (Pod's external IP) to Pod's container's IP at runtime for WebSocket purpose
我有以下情况:
我有几个微服务,现在只有两个相关。
- 网络套接字服务 API
- 调度服务
我们有 3 个用户,分别称为 1、2 和 3。这些用户将自己连接到我们后端的 Web 套接字端点。我们的微服务在 Kubernetes 上 运行,每个服务都可以在 Pods 中复制多次。对于这种情况,我们有 1 个 运行 容器用于调度程序,3 个 运行 容器用于网络套接字 api。每个 pod 都有其负载均衡器,这将是每次入口点。
在我们的情况下,我们将有以下 "schema":
现在我们有了系统的表示(和图例),我们的 3 个用户将想要使用该应用程序并进行连接。
正如我们所见,我们 pod 的负载均衡器将用户的 web 套接字连接转发到不同的容器中。每个容器一旦获得新的连接,就会通知 Dispatcher Service,而这个容器会将其保存在自己的数据库中。
现在,3 个用户连接到 2 个不同的容器并且 Dispatcher 服务知道了。
用户1想给用户2发消息,容器A会收到一条消息,告诉Dispatcher Service:Please, send this to the user 2
.
因为调度程序知道用户 2 连接到哪个容器,所以我想将请求直接发送到我的 Container 而不是发送到 Pod。将它发送到 Pod 会导致将请求发送到负载均衡器,负载均衡器实际上会将请求分派到最可用的容器实例...
如何获取容器IP?它可以被另一个容器从另一个 Pod 访问吗?
对我来说,最好的方法是,应用程序启动后,它会获取当前容器的 IP,然后在注册请求中将其发送给调度程序,这样调度程序就会知道 ContainerID =IP
谢谢!
编辑 1
有我的web-socket-service-api.yaml
apiVersion: v1
kind: Service
metadata:
name: web-socket-service-api
spec:
ports:
# Port that accepts gRPC and JSON/HTTP2 requests over HTTP.
- port: 8080
targetPort: 8080
protocol: TCP
name: grpc
# Port that accepts gRPC and JSON/HTTP2 requests over HTTP.
- port: 8081
targetPort: 8081
protocol: TCP
name: rest
# Port that accepts WebSockets.
- port: 8082
targetPort: 8082
protocol: TCP
name: websocket
selector:
app: web-socket-service-api
type: LoadBalancer
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: web-socket-service-api
spec:
replicas: 3
template:
metadata:
labels:
app: web-socket-service-api
spec:
containers:
- name: web-socket-service-api
image: gcr.io/[PROJECT]/web-socket-service-api:latest
ports:
- containerPort: 8080
- containerPort: 8081
- containerPort: 8082
调度程序 ≈ 消息代理
根据我对您的设计的理解,您的 Dispatcher 本质上是 Websocket 服务 的 pods 的消息代理.让所有 Websocket pods 连接到代理并让代理路由消息。这是一个 stateful 服务,您应该使用 StatefulSet for this in Kubernetes. Depending on your requirements, a possible solution could be to use a MQTT-broker for this, e.g. mosquitto。大多数 MQTT 代理都支持 websockets。
横向扩展:pods
的多个副本
each services can be replicated multiple times inside Pods. For this situation, we have 1 running container for the dispatcher, and 3 running containers for the web socket api.
这不是 Kubernetes 的用途。使用 pods 的多个 副本,而不是 pod 中的多个容器。我建议您为您的 Websocket 服务 创建一个 Deployment 并包含任意数量的副本。
作为负载均衡器的服务
Each pod has its Load Balancer and this will be each time the entry point.
在 Kubernetes 中,您应该创建一个 Service 将流量负载均衡到一组 pods。
您的解决方案
To me, the best approach would be that, once the app start, it gets the current container's IP and then send it within the register request to the dispatcher, so the dispatcher would know that ContainerID=IP
是的,我基本同意。这与我在这里描述的类似。但是我会让 Websocket 服务 建立到 Broker/Dispatcher.
的连接
任何 pod 都有一些关于它自己的信息。其中一项信息是它自己的 IP 地址。例如:
apiVersion: v1
kind: Pod
metadata:
name: envars-fieldref
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "sh", "-c"]
args:
- while true; do
echo -en '\n';
printenv MY_POD_IP;
sleep 10;
done;
env:
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
在容器中,MY_POD_IP 将包含 pod 的 IP 地址。你可以让调度员知道。
$ kubectl logs envars-fieldref
10.52.0.3
$ kubectl get po -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
envars-fieldref 1/1 Running 0 31s 10.52.0.3 gke-klusta-lemmy-3ce02acd-djhm <none> <none>
请注意,依赖 pod IP 地址不是一个好主意。但这应该可以解决问题。
此外,向pod或容器发送请求是一回事
我有以下情况:
我有几个微服务,现在只有两个相关。 - 网络套接字服务 API - 调度服务
我们有 3 个用户,分别称为 1、2 和 3。这些用户将自己连接到我们后端的 Web 套接字端点。我们的微服务在 Kubernetes 上 运行,每个服务都可以在 Pods 中复制多次。对于这种情况,我们有 1 个 运行 容器用于调度程序,3 个 运行 容器用于网络套接字 api。每个 pod 都有其负载均衡器,这将是每次入口点。
在我们的情况下,我们将有以下 "schema":
现在我们有了系统的表示(和图例),我们的 3 个用户将想要使用该应用程序并进行连接。
正如我们所见,我们 pod 的负载均衡器将用户的 web 套接字连接转发到不同的容器中。每个容器一旦获得新的连接,就会通知 Dispatcher Service,而这个容器会将其保存在自己的数据库中。
现在,3 个用户连接到 2 个不同的容器并且 Dispatcher 服务知道了。
用户1想给用户2发消息,容器A会收到一条消息,告诉Dispatcher Service:Please, send this to the user 2
.
因为调度程序知道用户 2 连接到哪个容器,所以我想将请求直接发送到我的 Container 而不是发送到 Pod。将它发送到 Pod 会导致将请求发送到负载均衡器,负载均衡器实际上会将请求分派到最可用的容器实例...
如何获取容器IP?它可以被另一个容器从另一个 Pod 访问吗?
对我来说,最好的方法是,应用程序启动后,它会获取当前容器的 IP,然后在注册请求中将其发送给调度程序,这样调度程序就会知道 ContainerID =IP
谢谢!
编辑 1
有我的web-socket-service-api.yaml
apiVersion: v1
kind: Service
metadata:
name: web-socket-service-api
spec:
ports:
# Port that accepts gRPC and JSON/HTTP2 requests over HTTP.
- port: 8080
targetPort: 8080
protocol: TCP
name: grpc
# Port that accepts gRPC and JSON/HTTP2 requests over HTTP.
- port: 8081
targetPort: 8081
protocol: TCP
name: rest
# Port that accepts WebSockets.
- port: 8082
targetPort: 8082
protocol: TCP
name: websocket
selector:
app: web-socket-service-api
type: LoadBalancer
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: web-socket-service-api
spec:
replicas: 3
template:
metadata:
labels:
app: web-socket-service-api
spec:
containers:
- name: web-socket-service-api
image: gcr.io/[PROJECT]/web-socket-service-api:latest
ports:
- containerPort: 8080
- containerPort: 8081
- containerPort: 8082
调度程序 ≈ 消息代理
根据我对您的设计的理解,您的 Dispatcher 本质上是 Websocket 服务 的 pods 的消息代理.让所有 Websocket pods 连接到代理并让代理路由消息。这是一个 stateful 服务,您应该使用 StatefulSet for this in Kubernetes. Depending on your requirements, a possible solution could be to use a MQTT-broker for this, e.g. mosquitto。大多数 MQTT 代理都支持 websockets。
横向扩展:pods
的多个副本each services can be replicated multiple times inside Pods. For this situation, we have 1 running container for the dispatcher, and 3 running containers for the web socket api.
这不是 Kubernetes 的用途。使用 pods 的多个 副本,而不是 pod 中的多个容器。我建议您为您的 Websocket 服务 创建一个 Deployment 并包含任意数量的副本。
作为负载均衡器的服务
Each pod has its Load Balancer and this will be each time the entry point.
在 Kubernetes 中,您应该创建一个 Service 将流量负载均衡到一组 pods。
您的解决方案
To me, the best approach would be that, once the app start, it gets the current container's IP and then send it within the register request to the dispatcher, so the dispatcher would know that ContainerID=IP
是的,我基本同意。这与我在这里描述的类似。但是我会让 Websocket 服务 建立到 Broker/Dispatcher.
的连接任何 pod 都有一些关于它自己的信息。其中一项信息是它自己的 IP 地址。例如:
apiVersion: v1
kind: Pod
metadata:
name: envars-fieldref
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "sh", "-c"]
args:
- while true; do
echo -en '\n';
printenv MY_POD_IP;
sleep 10;
done;
env:
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
在容器中,MY_POD_IP 将包含 pod 的 IP 地址。你可以让调度员知道。
$ kubectl logs envars-fieldref
10.52.0.3
$ kubectl get po -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
envars-fieldref 1/1 Running 0 31s 10.52.0.3 gke-klusta-lemmy-3ce02acd-djhm <none> <none>
请注意,依赖 pod IP 地址不是一个好主意。但这应该可以解决问题。
此外,向pod或容器发送请求是一回事