我試圖了解 docker swarm 如何進行負載平衡以及它如何影響套接字服務器的設計(因為服務器必須接受客戶端連接才能獲取它用于回傳服務結果的套接字物件),為此,我創建了以下回顯服務器:
# server.py
class Server:
def __init__(self, port=5050, header_size=64, encode_format='utf-8'):
port = port
host = "localhost"
self.addr = (host, port)
self.header_size = header_size
self.encode_format = encode_format
self.disconnect_message = 'DISCONNECT'
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.bind(self.addr)
self.id = np.random.randint(1024)
def do_stuff(self, conn, addr):
msg_length = conn.recv(self.header_size).decode(self.encode_format)
msg_length = int(msg_length)
# THIS PART WAS REMOVED TO KEEP THINGS SIMPLE
# message = conn.recv(msg_length) #.decode(self.encode_format)
# while len(message) < msg_length:
# packet = conn.recv(msg_length-len(message)) #.decode(self.encode_format)
# message = packet
print(f"[MSG] {msg_length} from {addr}")
self.send(conn, f"{msg_length} response from {self.id}")
return True
def send(self, conn, msg):
message = pickle.dumps(msg)
msg_length = len(message)
send_length = str(msg_length).encode(self.encode_format)
send_length = b' ' * (self.header_size - len(send_length))
# print("Sending response length")
conn.send(send_length)
# print("Sending response data")
# conn.send(message)
def handle_client(self, conn, addr):
print("-------------------------------------")
print(f"[CLIENT] new client {addr} connected.")
connected = True
while connected:
connected = self.do_stuff(conn, addr)
print(f"[CLIENT] {addr} has disconnected")
conn.close()
print(f"[Active CONNECTIONS] {threading.active_count() -2}")
def start(self):
self.server.listen()
print(f"[LISTENING] Server is listening on {self.addr[0]} port {self.addr[1]}")
print(f"[LISTENING] Server is listening on {self.addr[0]} port {self.addr[1]}")
try:
while True:
print("Listening . . .")
conn, addr = self.server.accept()
thread = threading.Thread(target=self.handle_client, args=(conn, addr))
thread.start()
print(f"[Active CONNECTIONS] {threading.active_count() -1}")
sleep(2)
except KeyboardInterrupt:
print("Interrupt signal received from Keyboard")
self.server.close()
print(f"[STOP] self.server {self.addr[0]} has stopped listening on port {self.addr[1]}")
if __name__ == "__main__":
server = Server()
server.start()
我能夠使用以下Dockerfile在 docker 容器中運行服務器:
FROM python:3.6.9
COPY App /App
WORKDIR /App
RUN pip3 install -U pip
RUN pip3 install numpy
EXPOSE 5050
ENTRYPOINT [ "python3" ]
CMD [ "server.py" ]
泊塢窗運行命令:
sudo docker run -it --rm -p 5050:5050 --name test IMAGE_NAME
客戶
# Client
PORT = 5050
HOST = "SERVER_IP" # or the IP of the server if is running on a different machine
ADDR = (HOST, PORT)
HEADER = 64
FORMAT = 'utf-8'
DISCONNECT_MESSAGE = 'DISCONNECT'
def send(sock, msg):
message = pickle.dumps(msg)
msg_length = len(message)
send_length = str(msg_length).encode(FORMAT)
send_length = b' ' * (HEADER - len(send_length))
sock.send(send_length)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(ADDR)
for i in range(200):
msg = f"Message number {i}"
send(sock, msg)
response = receive(sock)
print(response)
sock.close()
但是當部署在 docker swarm 服務中時,客戶端掛起sock.connect()
(我在 swarm 中有 2 個作業節點和 1 個管理節點)
服務創建命令:
sudo docker service create --name echo_server -p 5050:5050 --replicas 2 PRIVATE_REGISTRY_IP:PORT/IMAGE_NAME:TAG
我發現的所有 swarm 服務器示例都使用 nginx 影像,我能夠將其部署在作業節點上,然后使用管理器節點的 IP 訪問它(這是我試圖為 TCP 套接字服務器實作的)。
- 我錯過了什么?我究竟做錯了什么?
- 我應該做的 TCP 套接字服務器的設計有什么不同嗎?
- 客戶端如何通過 swarm 負載均衡器連接到服務器?
- 它總是被發送到它第一次連接到的同一臺服務器嗎?
- 每個請求都發送到不同的服務器嗎?
- 是否所有服務器都有 1 個客戶端,即負載均衡器(在這種情況下,無需為每個執行緒打開一個執行緒),并且負載均衡器具有客戶端的資訊?
解決方案
我能夠在堆疊中部署服務器
堆疊.yml
version: "3"
services:
echo_server:
image: REGISTRY_IP/IMAGE_NAME
ports:
- "5050:5050"
deploy:
replicas: 3
然后運行
sudo docker stack deploy -c /path/to/stack.yaml STACK_NAME
然后客戶端能夠通過其中一臺作業/管理節點 PC 的主機 IP 連接到服務
uj5u.com熱心網友回復:
為此,Docker swarm 有兩個負載均衡器:
當您從服務發布埠時,將呼叫入口負載平衡器。該埠從所有 swarm 節點發布,因此任何節點都可用于連接到該服務。并且 docker 將回圈連接到任何可用的(健康的)服務副本。
因為此流量是通過橋接介面到達的,所以您不能在“localhost”上監聽,因為這會阻止容器實際監聽橋接連接。
請注意,雖然每個 swarm 節點都會接受來自 localhost:port 的連接以連接到入口網路,但容器不能使用“localhost”連接到它,因為它指的是容器內的 localhost 介面,而不是主機。從容器內部連接到當前本地主機的正確方法是地址:“docker.host.internal:8080”(這需要在需要使用它的每個服務上啟用)。
另一個負載均衡器是網狀網路負載均衡器。在堆疊中部署服務時,docker 修改每個容器中的 resolve.conf 以指向一個 docker 決議器,該決議器將為容器所連接的每個網路決議服務名稱。Docker swarm 還為第 3 層負載均衡器的服務創建了一個虛擬 IP,并將其與每個網路上服務的 dns 名稱相關聯。
因此,如果您將名為“echotest”的服務部署為名為“test”的堆疊的一部分,并且創建了 2 個副本,那么 docker 將分配以下內容:
ip 為 10.0.1.5 的 vip,名稱為“echotest”和“test_echotest”。
兩個任務,IP 分別為 10.0.1.6 和 10.0.1.7。
附加到“test_default”網路 (10.0.1.0/24) 的任何其他服務將能夠使用名稱“echotest”和“test_echotest”連接到 vip,而 vip 實際上會連接到其中一個容器。
自己進行負載平衡的服務可以使用特殊名稱“tasks.echotest”和“tasks.test_echotest”來獲得 dns rr 回應:只是任務 ups 和它們的順序是隨機的。[10.0.1.6,10.0.1.7]
這組命令顯示了我的群的結果。
$ docker network create --attachable --driver overlay test
$ docker service create --network test --replicas 2 --name test-nginx nginx:latest
$ docker run --rm -it --network test nicolaka/netshoot
$ dig test-nginx short
10.0.38.2
$ dig tasks.test-nginx short
10.0.38.3
10.0.38.6
$ exit
$ docker service rm test-nginx
$ docker network rm test
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/535930.html
上一篇:python套接字連接安全嗎?
