From 8dfeb2d8e091c08badf71e80cf5ed8b8cff28131 Mon Sep 17 00:00:00 2001 From: DerTyp7 Date: Fri, 24 Nov 2023 13:57:03 +0100 Subject: [PATCH] first commit --- Dockerfile | 28 +++++++++ app/app.py | 134 +++++++++++++++++++++++++++++++++++++++++++ app/requirements.txt | 1 + docker-compose.yml | 45 +++++++++++++++ nginx.conf | 11 ++++ 5 files changed, 219 insertions(+) create mode 100644 Dockerfile create mode 100644 app/app.py create mode 100644 app/requirements.txt create mode 100644 docker-compose.yml create mode 100644 nginx.conf diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5aadbb4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,28 @@ +# Use the official Nginx base image +FROM nginx:1.25.3 + +ENV PORT_IP_MAP "" +ENV PYTHONUNBUFFERED=1 + +# Install Python and pip +RUN apt-get update && apt-get install -y python3 python3-pip python3-venv + +# Create a virtual environment and activate it +RUN python3 -m venv /app/venv +ENV PATH="/app/venv/bin:$PATH" + +# Copy the Python app files to the container +COPY app/* /app/ + +# Set the working directory +WORKDIR /app + +# Install the Python dependencies +RUN pip install --upgrade pip +RUN pip install -r requirements.txt + +# Expose port 80 for Nginx +EXPOSE 80 + +# Start Nginx and run the Python app +CMD service nginx start && exec python app.py \ No newline at end of file diff --git a/app/app.py b/app/app.py new file mode 100644 index 0000000..a98a3c6 --- /dev/null +++ b/app/app.py @@ -0,0 +1,134 @@ +import socket +import threading +import os +import docker + +client = docker.DockerClient(base_url='unix://var/run/docker.sock') + + +def setup_nginx_config(): + # Stop nginx + os.system('nginx -s stop') + # open nginx.conf for write create if not exist + nginx_conf = open('/etc/nginx/nginx.conf', 'w+') + nginx_conf.truncate() + nginx_conf.write('events { }\n') + nginx_conf.write('stream {\n') + + port_ip_map = docker_container_mapping() + for port in port_ip_map: + nginx_conf.write(' upstream upstream_{} {{\n'.format(port)) + nginx_conf.write(' server {}:{};\n'.format( + port_ip_map[port], port)) + nginx_conf.write(' server 127.0.0.1:{} backup;\n'.format(port)) + nginx_conf.write(' }\n') + + nginx_conf.write(' server {\n') + nginx_conf.write(' listen {}:{};\n'.format( + get_current_container_ip(), port)) + nginx_conf.write(' proxy_pass upstream_{};\n'.format(port)) + nginx_conf.write(' }\n') + nginx_conf.write('}\n') + nginx_conf.close() + os.system('nginx > /dev/null 2>&1 &') + + +def get_current_container_ip(): + # Get IP of current container + current_container_name = os.environ.get('HOSTNAME') + current_container = client.containers.get(current_container_name) + networks = current_container.attrs['NetworkSettings']['Networks'] + current_network = list(networks.keys())[0] + current_container_ip = networks[current_network]['IPAddress'] + return current_container_ip + + +def get_current_network(): + # Get network of current container + current_container_name = os.environ.get('HOSTNAME') + current_container = client.containers.get(current_container_name) + networks = current_container.attrs['NetworkSettings']['Networks'] + current_network = list(networks.keys())[0] + return current_network + + +def get_docker_container_by_ip(ip): + current_network = get_current_network() + print('getting docker container by ip {} in network {}'.format( + ip, current_network)) + containers = client.containers.list(all=True) + + for container in containers: + print('current network: {}'.format(current_network)) + print('checking container {}'.format(container.name)) + print('container networks: {}'.format( + container.attrs['NetworkSettings']['Networks'])) + print('container ip: {}'.format( + container.attrs['NetworkSettings']['Networks'][current_network]['IPAMConfig']['IPv4Address'])) + + networks = container.attrs['NetworkSettings']['Networks'] + if current_network in networks and networks[current_network]['IPAMConfig']['IPv4Address'] == ip: + print('found docker container {} with ip {} in network {}'.format( + container.name, ip, current_network)) + return container + print('no docker container found with ip {} in network {}'.format( + ip, current_network)) + return None + + +def docker_container_mapping(): + # Get the PORT_IP_MAP environment variable + port_ip_map_str = os.getenv('PORT_IP_MAP') + + # Convert the environment variable to a Python dictionary + port_ip_map = {} + for line in port_ip_map_str.split('\n'): + if line: # ignore empty lines + port, ip = line.split(':') + port_ip_map[port.strip()] = ip.strip() + + return port_ip_map + + +class RequestHandler(threading.Thread): + def __init__(self, port): + super().__init__() + self.port = port + # Create a TCP/IP socket + self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + # Bind the socket to the port + server_address = ('localhost', self.port) + print('starting up on {} port {}'.format(*server_address)) + self.sock.bind(server_address) + # Listen for incoming connections + self.sock.listen(1) + + def run(self): + while True: + print('waiting for a connection on port {}'.format(self.port)) + self.connection, self.client_address = self.sock.accept() + try: + print('connection from', self.client_address) + self.handle_request() + finally: + self.connection.close() + + def handle_request(self): + print('handling request on port {}'.format(self.port)) + # Get the Docker container name for this port + container_ip = docker_container_mapping().get(str(self.port)) + if container_ip: + # Start the Docker container + print('starting docker container {}'.format(container_ip)) + get_docker_container_by_ip(container_ip).start() + # Send a response + self.connection.sendall(b'Request handled') + else: + print('no docker container mapped to this port') + + +for port in range(25560, 25571): + handler = RequestHandler(port) + handler.start() + +setup_nginx_config() diff --git a/app/requirements.txt b/app/requirements.txt new file mode 100644 index 0000000..6d0eac4 --- /dev/null +++ b/app/requirements.txt @@ -0,0 +1 @@ +docker \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..66e21c3 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,45 @@ +version: "3.9" + +networks: + mc_network: + driver: bridge + ipam: + driver: default + config: + - subnet: 172.20.0.0/16 + +services: + minecraft_server_auto_starter: + build: . + ports: + - 25565:25565 + - 25566:25566 + environment: + PORT_IP_MAP: | + 25565: 172.20.0.3 + 25566: 172.20.0.4 + networks: + mc_network: + ipv4_address: 172.20.0.2 + volumes: + - /var/run/docker.sock:/var/run/docker.sock + + mc: + image: itzg/minecraft-server + environment: + type: "PAPER" + EULA: "TRUE" + MOTD: "TEST1" + networks: + mc_network: + ipv4_address: 172.20.0.3 + mc2: + image: itzg/minecraft-server + environment: + type: "PAPER" + EULA: "TRUE" + MOTD: "TEST2" + SERVER_PORT: "25566" + networks: + mc_network: + ipv4_address: 172.20.0.4 diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..665eb74 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,11 @@ +events { } +stream { + upstream mc_server { + server 172.20.0.3:25565; + server 127.0.0.1:25565 backup; + } + server { + listen 172.20.0.2:25566; + proxy_pass mc_server; + } +}