Kubernetes 集群中的服务器-客户端连接使用 Python 套接字

Server-client connection in Kubernetes cluster using Python socket

我正在尝试使用 python socket 库在 K8s 集群中的 pods 之间进行服务器-客户端通信。

当 运行 在集群外部时,服务器-客户端连接有效,但是在 k8s 中,服务器甚至没有设置:

import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(("myApp", 30152))  # it breaks here
server_socket.listen()

这是我的配置 YAML:

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myApp
  labels:
    app: myApp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myApp
  template:
    metadata:
      labels:
        app: myApp
    spec:
      containers:
        - name: myApp
          image: app_image:version
          ports:
            - containerPort: 30152
          imagePullPolicy: Always

---
apiVersion: v1
kind: Service
metadata:
  name: myApp
  labels:
    app: myApp
spec:
  selector:
    app: myApp
  ports:
    - name: myApp
      protocol: TCP
      port: 30152
  type: ClusterIP
---

service type 是一个 ClusterIP,因为连接只会在同一集群中的 pods 之间。有谁知道问题出在哪里?

在这里,我构建了一些示例,其中包含客户端和服务器 python 应用程序,它们通过 k8s 服务相互通信。几乎从零开始 (如果您想继续,请从 here 克隆所有文件)

服务器

server.py

import socket
import sys
import os

PORT = int(os.getenv('LISTEN_PORT'))

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('0.0.0.0', PORT)
print('Starting up on {} port {}'.format(*server_address))
sock.bind(server_address)
sock.listen()

while True:
    print('\nWaiting for a connection')
    connection, client_address = sock.accept()
    try:
        print('Connection from', client_address)
        while True:
            data = connection.recv(64)
            print('Received {!r}'.format(data))
            if data:
                print('Sending data back to the client')
                connection.sendall(data)
            else:
                print('No data from', client_address)
                break
    finally:
        connection.close()

Docker 文件

FROM python:3-alpine
WORKDIR /app
COPY server.py .
CMD ["/usr/local/bin/python3", "/app/server.py"]

构建镜像、标记、推送到容器存储库 (GCP):

docker build --no-cache -t q69936079-server .
docker tag q69936079-server gcr.io/<project_id>/q69936079-server
docker push gcr.io/<project_id>/q69936079-server

客户

client.py

import socket
import os
import sys
import time

counter = 0

SRV = os.getenv('SERVER_ADDRESS')
PORT = int(os.getenv('SERVER_PORT'))

while 1:
    if counter != 0:
        time.sleep(5)

    counter += 1
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_address = (SRV, PORT)
    print("Connection #{}".format(counter))
    print('Connecting to {} port {}'.format(*server_address))
    try:
        sock.connect(server_address)
    except Exception as e:
        print("Cannot connect to the server,", e)
        continue

    try:
        message = b'This is the message. It will be repeated.'
        print('Sending:  {!r}'.format(message))
        sock.sendall(message)

        amount_received = 0
        amount_expected = len(message)

        while amount_received < amount_expected:
            data = sock.recv(64)
            amount_received += len(data)
            print('Received: {!r}'.format(data))
    finally:
        print('Closing socket\n')
        sock.close()

Docker 文件

FROM python:3-alpine
WORKDIR /app
COPY client.py .
CMD ["/usr/local/bin/python3", "/app/client.py"]

构建镜像、标记、推送到容器存储库(在我的例子中是 GCP):

docker build --no-cache -t q69936079-client .
docker tag q69936079-client gcr.io/<project_id>/q69936079-client
docker push gcr.io/<project_id>/q69936079-client

K8S

服务器部署

apiVersion: apps/v1
kind: Deployment
metadata:
  name: server-deployment
spec:
  selector:
    matchLabels:
      app: server
  replicas: 1
  template:
    metadata:
      labels:
        app: server
    spec:
      containers:
      - name: server
        image: "gcr.io/<project_id>/q69936079-server:latest"
        env:
        - name: PYTHONUNBUFFERED
          value: "1"
        - name: LISTEN_PORT
          value: "30152"

客户端部署

apiVersion: apps/v1
kind: Deployment
metadata:
  name: client-deployment
spec:
  selector:
    matchLabels:
      app: client
  replicas: 1
  template:
    metadata:
      labels:
        app: client
    spec:
      containers:
      - name: client
        image: "gcr.io/<project_id>/q69936079-client:latest"
        env:
        - name: PYTHONUNBUFFERED
          value: "1"
        - name: SERVER_ADDRESS
          value: my-server-service
        - name: SERVER_PORT
          value: "30152"

服务器服务

apiVersion: v1
kind: Service
metadata:
  name: my-server-service
spec:
  type: ClusterIP
  selector:
    app: server
  ports:
  - protocol: TCP
    port: 30152

验证

k8s 对象

k get all

NAME                                     READY   STATUS    RESTARTS   AGE
pod/client-deployment-7dd5d675ff-pvwd4   1/1     Running   0          14m
pod/server-deployment-56bd44cc68-w6jns   1/1     Running   0          13m

NAME                        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)     AGE
service/kubernetes          ClusterIP   10.140.0.1      <none>        443/TCP     12h
service/my-server-service   ClusterIP   10.140.13.183   <none>        30152/TCP   38m

NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/client-deployment   1/1     1            1           14m
deployment.apps/server-deployment   1/1     1            1           13m

NAME                                           DESIRED   CURRENT   READY   AGE
replicaset.apps/client-deployment-7dd5d675ff   1         1         1       14m
replicaset.apps/server-deployment-56bd44cc68   1         1         1       13m

服务器日志

k logs -f deployment.apps/server-deployment

Starting up on 0.0.0.0 port 30152

Waiting for a connection
Connection from ('10.136.1.11', 48234)
Received b'This is the message. It will be repeated.'
Sending data back to the client
Received b''
No data from ('10.136.1.11', 48234)

Waiting for a connection
Connection from ('10.136.1.11', 48246)
Received b'This is the message. It will be repeated.'
Sending data back to the client
Received b''
No data from ('10.136.1.11', 48246)

客户端日志

k logs -f deployment.apps/client-deployment

Connection #1
Connecting to my-server-service port 30152
Cannot connect to the server, [Errno 111] Connection refused

Connection #2
Connecting to my-server-service port 30152
Cannot connect to the server, [Errno 111] Connection refused

Connection #3
Connecting to my-server-service port 30152
Sending:  b'This is the message. It will be repeated.'
Received: b'This is the message. It will be repeated.'
Closing socket

Connection #4
Connecting to my-server-service port 30152
Sending:  b'This is the message. It will be repeated.'
Received: b'This is the message. It will be repeated.'
Closing socket