Sign inSign up

ribas89/l4d2as

By ribas89

•Updated 4 months ago

Left 4 Dead 2 Auto Scaler

Image
Integration & delivery
Developer tools
0

10K+

ribas89/l4d2as repository overview

⁠L4D2AS

Left 4 Dead 2 Auto Scaler.

L4D2AS is a small Docker autoscaler for Left 4 Dead 2 dedicated servers. It watches a template server container, checks active player counts with A2S, and creates or removes extra server containers as needed.

The goal is simple: keep one empty spare server online, and remove extra empty servers after a grace period.

⁠Features

  • Uses an existing Docker Compose service as a template.
  • Creates new L4D2 server containers with docker run.
  • Increments container names, hostnames, ports, and static IP addresses.
  • Queries running servers using A2S.
  • Keeps one empty spare room available.
  • Removes extra empty rooms after a configurable delay.
  • Removes old autoscaled containers outside the configured range.
  • Reloads settings on every tick.

⁠How it works

L4D2AS reads a template service from a Docker Compose file.

For example, a template container named l4d2c00 can generate:

l4d2c01
l4d2c02
l4d2c03

If the template has hostname RS CASUAL 00, generated containers get:

RS CASUAL 01
RS CASUAL 02
RS CASUAL 03

If the template exposes 192.168.8.220:51000:51000/udp, generated containers get:

192.168.8.220:51001:51001/udp
192.168.8.220:51002:51002/udp
192.168.8.220:51003:51003/udp

If the template uses static IP 172.20.1.100, generated containers get:

172.20.1.101
172.20.1.102
172.20.1.103

⁠Requirements

L4D2AS needs access to the Docker daemon.

The autoscaler container must be able to run Docker commands and inspect/create/remove containers.

Usually this means mounting the Docker socket:

- /var/run/docker.sock:/var/run/docker.sock

The autoscaler also needs read access to the Compose file, env files, and bind mount paths used by the template service.

⁠Docker image

l4d2as:local

or:

ribas89/l4d2as:latest

⁠Environment variables

⁠L4D2AS_SETTINGS_FILE

Path to the Python settings file inside the container.

L4D2AS_SETTINGS_FILE: /config/l4d2as_settings.py
⁠L4D2AS_LOG_LEVEL

Log level.

L4D2AS_LOG_LEVEL: INFO

Supported values:

DEBUG
INFO
WARNING
ERROR

⁠Settings file

L4D2AS uses a Python settings file.

Example:

MAX_PLAYERS = 8
CHECK_INTERVAL_SECONDS = 30
EMPTY_GRACE_SECONDS = 300
SERVICE_NAME = "l4d2c00"
COMPOSE_FILE = "/compose/docker-compose.yml"
MAX_REPLICAS = 5
REMOVE_CONTAINERS_WHEN_STOPPED = True
REMOVE_CONTAINERS_NOT_IN_ROOMS = True

⁠Settings reference

⁠MAX_PLAYERS

Maximum expected player count.

MAX_PLAYERS = 8
⁠CHECK_INTERVAL_SECONDS

How often the autoscaler checks server state.

CHECK_INTERVAL_SECONDS = 30
⁠EMPTY_GRACE_SECONDS

How long an extra empty server must stay empty before it is removed.

EMPTY_GRACE_SECONDS = 300
⁠SERVICE_NAME

The Compose service used as the template.

SERVICE_NAME = "l4d2c00"
⁠COMPOSE_FILE

Path to the Compose file inside the autoscaler container.

COMPOSE_FILE = "/compose/docker-compose.yml"
⁠MAX_REPLICAS

Maximum number of generated containers.

If the template is l4d2c00 and MAX_REPLICAS = 5, L4D2AS manages:

l4d2c01
l4d2c02
l4d2c03
l4d2c04
l4d2c05
⁠REMOVE_CONTAINERS_WHEN_STOPPED

Kept for backward compatibility.

The current lifecycle is ephemeral, so unused containers are removed instead of only stopped.

REMOVE_CONTAINERS_WHEN_STOPPED = True
⁠REMOVE_CONTAINERS_NOT_IN_ROOMS

When enabled, removes managed autoscaled containers that are no longer inside the configured room range.

REMOVE_CONTAINERS_NOT_IN_ROOMS = True

⁠Template service requirements

The template Compose service must define an image:

image: l4d2:local

The container name must end with a number:

container_name: l4d2c00

The service must expose at least one UDP port:

ports:
  - "192.168.8.220:51000:51000/udp"

The service must use dictionary-style network config with a static IPv4 address:

networks:
  gamenet:
    ipv4_address: 172.20.1.100

The service can define environment variables:

environment:
  HOSTNAME: "RS CASUAL 00"
  PORT: 51000

The service can use env files:

env_file:
  - ./l4d2casual/common.env

The service can use bind mounts:

volumes:
  - ./l4d2casual/addons/:/addons
  - ./l4d2casual/cfg/:/cfg

Relative bind mount paths are resolved relative to the Compose file directory.

⁠Generated containers

Generated containers are created with labels:

l4d2as.managed=true
l4d2as.template_service=<template-service>
l4d2as.room=<container-name>
l4d2as.index=<index>

These labels are used to identify autoscaled containers.

⁠Runtime behavior

On every tick, L4D2AS:

  1. reloads the settings file
  2. reloads the template service from the Compose file
  3. builds the expected room list
  4. checks whether each generated container exists and is running
  5. queries running servers with A2S
  6. tracks how long each room has been empty
  7. creates a new spare room if no empty room exists
  8. removes extra empty rooms after the grace period
  9. removes managed containers outside the configured range

⁠Build

docker build -t l4d2as:local .

⁠Run

docker run --rm -e L4D2AS_SETTINGS_FILE=/config/l4d2as_settings.py -e L4D2AS_LOG_LEVEL=INFO -v /var/run/docker.sock:/var/run/docker.sock -v ./l4d2as_settings.py:/config/l4d2as_settings.py:ro -v ./docker-compose.yml:/compose/docker-compose.yml:ro ribas89/l4d2as:latest

⁠Example Compose service

l4d2as:
  image: ribas89/l4d2as:latest
  container_name: l4d2as
  restart: unless-stopped
  environment:
    L4D2AS_SETTINGS_FILE: /config/l4d2as_settings.py
    L4D2AS_LOG_LEVEL: INFO
  volumes:
    - /var/run/docker.sock:/var/run/docker.sock
    - ./l4d2as_settings.py:/config/l4d2as_settings.py:ro
    - ./docker-compose.yml:/compose/docker-compose.yml:ro

⁠Troubleshooting

⁠Docker CLI cannot access Docker daemon

Make sure the Docker socket is mounted:

- /var/run/docker.sock:/var/run/docker.sock
⁠Settings file not found

Check L4D2AS_SETTINGS_FILE.

L4D2AS_SETTINGS_FILE: /config/l4d2as_settings.py
⁠Template service not found

Check SERVICE_NAME and COMPOSE_FILE.

SERVICE_NAME = "l4d2c00"
COMPOSE_FILE = "/compose/docker-compose.yml"
⁠Template service must define ports

The template service needs at least one port mapping.

ports:
  - "192.168.8.220:51000:51000/udp"
⁠Template service must define a static IP

The template service needs networks.<name>.ipv4_address.

networks:
  gamenet:
    ipv4_address: 172.20.1.100
⁠A2S query failed

Check that the generated server is reachable at the expected host and port.

Also check that the L4D2 server is listening on the generated PORT.

⁠No empty spare room exists, but no room is available

All generated containers up to MAX_REPLICAS are already running.

Increase MAX_REPLICAS.

MAX_REPLICAS = 10

⁠Security note

Mounting /var/run/docker.sock gives this container control over the Docker daemon.

Only run L4D2AS in an environment you trust.

⁠License

MIT

Tag summary

Content type

Image

Digest

sha256:4195548be…

Size

63.9 MB

Last updated

4 months ago

docker pull ribas89/l4d2as