Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you use python sockets for docker container communication?

In a docker network I am trying to communicate between two containers using python sockets (to send packets). Pinging works but python sockets library does not work.

The error:

line 6: conn, addr = sock.connect(('172.168.1.2', 4000)) TypeError: 'NoneType' object is not iterable

First python3 receive.py is run in container1. Then python3 send.py is run in container 2. Container 1 prints "accepted" and then nothing else. Container 2 errors as mentioned above.

This network is a user-defined network with it's own subnet and default gateway. This error does not occur with the same exact code when I use it to connect to my raspberry pi, but it errors with container communication.

All of the code:

container1:

import socket

def receive():
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.bind(("", 4000))
        s.listen(2)
        conn, addr = s.accept()
        print("accepted")
        print(bytes.decode(conn.recv(1024)))

container 2:

import socket

def send():
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        command = "bridge test!"
        conn, addr = sock.connect(('172.168.1.2', 4000))
        conn.sendall(command)

To setup the network:

docker network create --subnet 172.168.1.0/24 testNetwork
docker network connect testNetwork container1
docker network connect testNetwork container2

I got the IP addresses of the containers from docker inspect (plus pinging them works) Please help! Thanks!

like image 783
Joe N Avatar asked May 15 '18 23:05

Joe N


2 Answers

You have a couple of issues.

  1. socket.connect doesn't return anything. It returns None. You think it returns a tuple of conn, addr. Python tries to deconstruct whatever is returned into a tuple by iterating over it and you get the error:

    TypeError: 'NoneType' object is not iterable
    
  2. socket.sendall accepts bytes not a str. Convert by

    sock.sendall(command.encode())
    

Here's the fixed send.py:

import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
command = "bridge test!"
x, y = sock.connect(('172.168.1.2', 4000))
sock.sendall(command.encode())
like image 169
0xcaff Avatar answered Nov 15 '22 19:11

0xcaff


You might want to try the docker api for python. https://github.com/docker/docker-py.git

Here is an example.

#!/usr/bin/python3

import docker
import requests

def main():

  # Connect to the default unix socket (/var/run/docker.sock)
  client = docker.from_env()

  #Pull the nginx:alpine image
  client.images.pull('nginx:alpine')

  #Define some test parameters, our first HTTP port and the number of containers
  portstart = 10000
  count = 1000

  #Create and start 'count' number of containers. Map container port 80 to an external port.
  for a in range(1,count+1):
    container = client.containers.create('nginx:alpine',ports={'80/tcp':portstart+a})
    container.start()
    print('Created container number {} name: {}'.format(a,container.name))

  #Get a list of all the running containers (best you don't run this script on a system which has existing containers running)
  #Iterate through the list, pick out the remote port, and perform a GET request to it to check nginx is online. If the status code is 200, we must be successful!
  container_list = client.containers.list()
  count = 0
  for container in container_list:
    port = container.attrs['HostConfig']['PortBindings']['80/tcp'][0]['HostPort']
    r = requests.get('http://127.0.0.1:{}'.format(port))
    if(r.status_code == 200):
      print('Container {} is alive and working on port {}!'.format(container.name,port))
      count += 1
    else:
      print('Container {} is dead :( Code: {}'.format(container.name,r.status_code))

  print('Summary: Online Containers: {} Offline Containers: {}'.format(count,len(container_list)-count))
  print('Removing containers...')

  #Let's clean up and put our toys back in the toybox.
  for container in container_list:
    container.stop()
    container.remove()

if __name__ == "__main__":
    main()
like image 2
James Knott Avatar answered Nov 15 '22 20:11

James Knott