Skip to content

Commit e895902

Browse files
authored
Merge pull request #76 from joesturge/73-store-ip-in-configtoml-instead-of-hostname-if-provided
fix: use static ip in lazymc config file if availible
2 parents a25ca2f + cae0c84 commit e895902

File tree

6 files changed

+212
-24
lines changed

6 files changed

+212
-24
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Fixed
11+
12+
- Use static IP in the lazymc.toml instead of hostname
13+
14+
### Deprecated
15+
16+
- The app will throw a warning if it notices you are not using a static ip for the minecraft container
17+
1018
## [2.2.0] - 2024-08-05
1119

1220
### Added

README.md

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,39 @@ This project is also somewhat inspired by [lazytainer](https://github.com/vmorga
1414

1515
Here is a minimal Docker Compose example using [itzg/minecraft-server](https://github.com/itzg/docker-minecraft-server) as the server:
1616

17+
> ⚠️ It is **very important** that you assign **static** IP Address to each container.
18+
This is due to quirk in how lazymc monitors the servers, it does not expect the IP address of a server to change,
19+
this can happen when a container stops and starts again There is an open issue for this: https://github.com/joesturge/lazymc-docker-proxy/issues/63.
20+
As this is an issue with lazymc itself it is unlikely that a fix can be found. Im open to suggestions on this.
21+
1722
```yaml
23+
# Lazymc requires that the minecraft server have a static IP.
24+
#
25+
# To ensure that our servers have a static IP we need to create
26+
# a network for our services to use.
27+
#
28+
# By default, Docker uses 172.17.0.0/16 subnet range.
29+
# So we need to create a new network in a different subnet
30+
# See the readme for more information.
31+
#
32+
# Please ensure that the subnet falls within the private CIDRs:
33+
# https://datatracker.ietf.org/doc/html/rfc1918#section-3
34+
#
35+
# And that it is not in use by anything else.
36+
networks:
37+
minecraft-network:
38+
driver: bridge
39+
ipam:
40+
config:
41+
- subnet: 172.18.0.0/16
42+
1843
services:
1944
lazymc:
2045
image: ghcr.io/joesturge/lazymc-docker-proxy:latest
46+
# the IPs should start at .2 as .1 is reserved for the gateway
47+
networks:
48+
minecraft-network:
49+
ipv4_address: 172.18.0.2
2150
restart: unless-stopped
2251
volumes:
2352
# you should mount the minecraft server dir under /server, using read only.
@@ -32,6 +61,10 @@ services:
3261
# Standard Docker Minecraft server, also works with other server types
3362
mc:
3463
image: itzg/minecraft-server:java21
64+
# Assign a static IP to the server container
65+
networks:
66+
minecraft-network:
67+
ipv4_address: 172.18.0.3
3568
# We need to add a label here so that lazymc-docker-proxy knows which
3669
# container to manage
3770
labels:
@@ -59,27 +92,7 @@ volumes:
5992
6093
This container can also proxy to and control multiple containers at once. You could use it with `itzg/mc-router` if you choose to:
6194

62-
> ⚠️ When running multiple minecraft containers it is **very important** that you assign **static** IP Address to each container.
63-
This is due to quirk in how lazymc monitors the servers, it does not expect the IP address of a server to change,
64-
this can happen when a container stops and starts again There is an open issue for this: https://github.com/joesturge/lazymc-docker-proxy/issues/63.
65-
As this is an issue with lazymc itself it is unlikely that a fix can be found. Im open to suggestions on this.
66-
6795
```yaml
68-
# Lazymc requires that the minecraft server have a static IP.
69-
# This generally isn't a problem when running a single server
70-
# as the stopped container will usually start with same IP as before.
71-
#
72-
# To ensure that our servers have a static IP we need to create
73-
# a network for our services to use.
74-
#
75-
# By default, Docker uses 172.17.0.0/16 subnet range.
76-
# So we need to create a new network in a different subnet
77-
# See the readme for more information.
78-
#
79-
# Please ensure that the subnet falls within the private CIDRs:
80-
# https://datatracker.ietf.org/doc/html/rfc1918#section-3
81-
#
82-
# And that it is not in use by anything else.
8396
networks:
8497
minecraft-network:
8598
driver: bridge
@@ -196,9 +209,19 @@ volumes:
196209
## Forge 1.19.2
197210

198211
```yaml
212+
networks:
213+
minecraft-network:
214+
driver: bridge
215+
ipam:
216+
config:
217+
- subnet: 172.18.0.0/16
218+
199219
services:
200220
lazymc:
201221
image: ghcr.io/joesturge/lazymc-docker-proxy:latest
222+
networks:
223+
minecraft-network:
224+
ipv4_address: 172.18.0.2
202225
restart: unless-stopped
203226
volumes:
204227
- /var/run/docker.sock:/var/run/docker.sock:ro
@@ -208,6 +231,9 @@ services:
208231
209232
mc:
210233
image: itzg/minecraft-server:java21
234+
networks:
235+
minecraft-network:
236+
ipv4_address: 172.18.0.3
211237
labels:
212238
- lazymc.enabled=true
213239
- lazymc.group=mc
@@ -243,7 +269,7 @@ Here is the list of the supported container labels which can be added to the min
243269
which will be picked up by `lazymc-docker-proxy` (\* is required):
244270

245271
- **\*lazymc.enabled=true** - Enable this to inform `lazymc-docker-proxy` that this container should be managed.
246-
- **\*lazymc.server.address** - The address of the Docker Minecraft server to manage, should use the Docker network address, such as `mc:25565`.
272+
- **\*lazymc.server.address** - The address of the Docker Minecraft server to manage, should use the internal Docker network address of the server container, such as `mc:25565` or the assigned static IP such as `172.18.0.3:25565`.
247273
- **\*lazymc.group** - This is used by `lazymc-docker-proxy` to locate the container to start and stop
248274
- **lazymc.port** - The port on the `lazymc-docker-proxy` container this server will be accessible from. Defaults to `25565`.
249275
- **lazymc.motd.sleeping** - MOTD, shown in the server browser when sleeping.
@@ -281,7 +307,7 @@ You can enable debug logging using the `RUST_LOG` env var.
281307

282308
Here is a full list of the environment variables supported by this image (\* is required):
283309

284-
- **\*SERVER_ADDRESS** - The address of the Docker Minecraft server to manage, should use the Docker network address, such as `mc:25565`.
310+
- **\*SERVER_ADDRESS** - The address of the Docker Minecraft server to manage, should use the internal Docker network address of the server container, such as `mc:25565` or the assigned static IP such as `172.18.0.3:25565`.
285311
- **\*LAZYMC_GROUP** - The value of the `lazymc.group` label assigned to the Docker Minecraft server. This is used by the image to start or stop the server when lazymc triggers it.
286312
- **LAZYMC_PORT** - The port on the `lazymc-docker-proxy` container this server will be accessible from. Defaults to `25565`.
287313
- **MOTD_SLEEPING** - MOTD, shown in the server browser when sleeping.

src/entrypoint/docker.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub fn get_container_labels() -> Vec<HashMap<std::string::String, std::string::S
1616
let mut list_container_filters: HashMap<String, Vec<String>> =
1717
HashMap::<String, Vec<String>>::new();
1818

19-
// find all matching running containers which have labels starting with "lazymc."
19+
// find all docker containers with the label "lazymc.enabled=true"
2020
list_container_filters.insert("label".to_string(), vec![format!("lazymc.enabled=true")]);
2121

2222
// find all matching containers and then get their labels
@@ -40,6 +40,44 @@ pub fn get_container_labels() -> Vec<HashMap<std::string::String, std::string::S
4040
for (key, value) in container.labels.as_ref().unwrap() {
4141
labels.insert(key.clone(), value.clone());
4242
}
43+
44+
// parse port from lazymc.server.address label
45+
let port: Option<u16> = labels
46+
.get("lazymc.server.address")
47+
.and_then(|address| address.rsplit(':').next())
48+
.and_then(|port_str| port_str.parse().ok());
49+
50+
// try to get the container's IP address from the ipam config as optional
51+
let ip_address: Option<String> = container
52+
.network_settings
53+
.as_ref()
54+
.and_then(|network_settings| {
55+
network_settings
56+
.networks
57+
.as_ref()
58+
.and_then(|networks| {
59+
networks
60+
.values()
61+
.find(|network| network.ipam_config.is_some())
62+
})
63+
.and_then(|network| network.ipam_config.as_ref())
64+
.and_then(|ipam_config| ipam_config.ipv4_address.clone())
65+
})
66+
.or_else(|| {
67+
warn!(target: "lazymc-docker-proxy::entrypoint::docker", "**************************************************************************************************************************");
68+
warn!(target: "lazymc-docker-proxy::entrypoint::docker", "WARNING: You should use IPAM to assign a static IP address to your server container otherwise performance may be degraded.");
69+
warn!(target: "lazymc-docker-proxy::entrypoint::docker", " see: https://github.com/joesturge/lazymc-docker-proxy?tab=readme-ov-file#usage");
70+
warn!(target: "lazymc-docker-proxy::entrypoint::docker", "**************************************************************************************************************************");
71+
None
72+
});
73+
74+
// if we have a port and an IP address, add the resolved address to the labels
75+
if port.is_some() && ip_address.is_some() {
76+
let address = format!("{}:{}", ip_address.unwrap(), port.unwrap());
77+
debug!(target: "lazymc-docker-proxy::entrypoint::docker", "Resolved address: {}", address);
78+
labels.insert("lazymc.server.address".to_string(), address);
79+
}
80+
4381
label_sets.push(labels);
4482
}
4583

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
version: '3.7'
2+
3+
networks:
4+
minecraft-network:
5+
driver: bridge
6+
ipam:
7+
config:
8+
- subnet: 172.21.0.0/16
9+
10+
services:
11+
lazymc-static-network:
12+
container_name: lazymc-static-network
13+
networks:
14+
minecraft-network:
15+
ipv4_address: 172.21.0.2
16+
restart: unless-stopped
17+
environment:
18+
RUST_LOG: "debug"
19+
volumes:
20+
- /var/run/docker.sock:/var/run/docker.sock:ro
21+
- data:/server:ro
22+
ports:
23+
- "25565:25565"
24+
build: ../../../
25+
26+
mc-static-network:
27+
image: itzg/minecraft-server:java21
28+
container_name: mc-static-network
29+
networks:
30+
minecraft-network:
31+
ipv4_address: 172.21.0.3
32+
labels:
33+
- lazymc.enabled=true
34+
- lazymc.group=mc
35+
- lazymc.server.address=mc-vanilla:25565
36+
- lazymc.time.minimum_online_time=30
37+
- lazymc.time.sleep_after=5
38+
tty: true
39+
stdin_open: true
40+
restart: no
41+
environment:
42+
EULA: "TRUE"
43+
volumes:
44+
- data:/data
45+
46+
volumes:
47+
data:
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/usr/bin/env bats
2+
3+
load ../util.bash
4+
5+
project="./tests/bats/static-network"
6+
7+
@test "Static network - Test lazymc resolves the IP address of the minecraft server if using a static network" {
8+
# stop the server container
9+
stop_container mc-static-network
10+
11+
# restart the lazymc container
12+
restart_container lazymc-static-network
13+
14+
# reset the start timestamp
15+
reset_timestamp
16+
17+
#
18+
# The above steps ensures that this app can read the ip address of a stopped minecraft server
19+
#
20+
21+
# wait for lazymc to replace the address in the config
22+
wait_for_formatted_log "lazymc-static-network" "DEBUG" "lazymc-docker-proxy::entrypoint::docker" "Resolved address: 172.21.0.3:25565"
23+
24+
# wait for the config to generated
25+
wait_for_log "lazymc-static-network" "address = \"172.21.0.3:25565\""
26+
27+
# wait for lazymc process to start
28+
wait_for_formatted_log "lazymc-static-network" "INFO" "lazymc-docker-proxy::entrypoint" "Starting lazymc process for group: mc..."
29+
30+
# wait for lazymc to start the server
31+
wait_for_formatted_log "lazymc-static-network" "INFO" "mc::lazymc" "Starting server..."
32+
33+
# wait for the server to be online
34+
wait_for_formatted_log "lazymc-static-network" "INFO" "mc::lazymc::monitor" "Server is now online" 300
35+
36+
# wait for the mincraft server to be ready
37+
wait_for_log "mc-static-network" "RCON running on 0.0.0.0:25575" 300
38+
39+
# wait for the server to be idle
40+
wait_for_formatted_log "lazymc-static-network" "INFO" "mc::lazymc::monitor" "Server has been idle, sleeping..." 120
41+
42+
# wait for the server to be stopped
43+
wait_for_formatted_log "lazymc-static-network" "INFO" "mc::lazymc-docker-proxy::command" "Received SIGTERM, stopping server..."
44+
45+
# wait for the server to exit
46+
wait_for_log "mc-static-network" "Thread RCON Listener stopped"
47+
48+
# wait for lazymc to sleep
49+
wait_for_formatted_log "lazymc-static-network" "INFO" "mc::lazymc::monitor" "Server is now sleeping"
50+
}

tests/bats/util.bash

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@
22

33
start_timestamp=""
44

5+
# set up start timestamp
6+
reset_timestamp() {
7+
start_timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
8+
}
9+
510
# before all tests
611
setup() {
7-
start_timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
12+
reset_timestamp
813

914
echo "Building docker compose..." >&3
1015
docker compose --project-directory $project build
@@ -61,4 +66,18 @@ wait_for_log() {
6166
sleep 1
6267
((timeout--))
6368
done
69+
}
70+
71+
stop_container() {
72+
local container=$1
73+
74+
echo "Stopping container: $container" >&3
75+
docker compose --project-directory $project stop $container
76+
}
77+
78+
restart_container() {
79+
local container=$1
80+
81+
echo "Restarting container: $container" >&3
82+
docker compose --project-directory $project restart $container
6483
}

0 commit comments

Comments
 (0)