-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Docker build configuration for server
The final image is around 150M in size, which is totally reasonable. Most of the size is added by the maps.
- Loading branch information
1 parent
e1b3320
commit 10fbd27
Showing
6 changed files
with
295 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# remember: the last(!) line that matches a specific file defines the behavior | ||
|
||
# ignore everything, then unblock one by one (note: . does not work "for historical reasons") | ||
* | ||
|
||
#!.git/ | ||
!README.md | ||
!CMakeLists.txt | ||
!config/ | ||
!data/ | ||
!doc/ | ||
!docker/ | ||
!src/ | ||
|
||
# ignore the Dockerfile so changes in it don't retrigger an entire build | ||
!docker/Dockerfile |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# first, let's build the software | ||
# this is going to take the most time | ||
FROM alpine:3.17 AS builder | ||
|
||
RUN apk add gcc g++ binutils sdl2-dev zlib-dev perl git wget ca-certificates coreutils mesa-dev musl-dev glu-dev \ | ||
sdl2_image-dev sdl2_mixer-dev psmisc cmake ninja | ||
|
||
RUN mkdir /blue-nebula | ||
WORKDIR /blue-nebula | ||
|
||
COPY src/ /blue-nebula/src | ||
COPY config/ /blue-nebula/config | ||
COPY data/ /blue-nebula/data | ||
|
||
COPY CMakeLists.txt /blue-nebula/ | ||
COPY README.md /blue-nebula/ | ||
COPY docker/serverip.patch /serverip.patch | ||
|
||
RUN git apply < /serverip.patch && \ | ||
ls -al && \ | ||
mkdir build && \ | ||
cd build && \ | ||
# TODO: server-only build configuration | ||
cmake .. -DCMAKE_BUILD_TYPE=Release -G Ninja -DCMAKE_INSTALL_PREFIX=/blue-nebula/install && \ | ||
ninja -v && \ | ||
ninja install | ||
|
||
# next, we convert the example server config to a template | ||
# this is done in no time, so we do not have to benefit from Docker's caching a lot there | ||
FROM python:3.10-alpine AS template | ||
|
||
COPY docker/generate-servinit-template.py doc/examples/servinit.cfg / | ||
|
||
RUN python3 /generate-servinit-template.py /servinit.cfg > /servinit.tmpl | ||
|
||
|
||
|
||
# finally, let's build the final runtime image (doesn't need all of the build dependencies) | ||
FROM alpine:3.17 | ||
|
||
MAINTAINER "TheAssassin <[email protected]>" | ||
|
||
RUN apk add tini && \ | ||
apk add --repository=https://dl-cdn.alpinelinux.org/alpine/edge/testing dockerize | ||
|
||
RUN adduser -S -D -h /blue-nebula blue-nebula | ||
WORKDIR /blue-nebula | ||
|
||
COPY --from=template /servinit.tmpl / | ||
COPY --from=builder /blue-nebula/install /blue-nebula/install | ||
|
||
# keep the directory read-only but allow writing to the file | ||
# this is needed since dockerize runs as blue-nebula and needs to modify the file | ||
# we might want to run dockerize separately and then run the process as blue-nebula | ||
RUN mkdir /blue-nebula/.blue-nebula && \ | ||
install -o blue-nebula -m 0644 /dev/null /blue-nebula/.blue-nebula/servinit.cfg | ||
|
||
# install runtime dependencies | ||
RUN apk add --no-cache libstdc++ libgcc | ||
|
||
# keep files copied from elsewhere read-only to prevent the process from writing files | ||
USER blue-nebula | ||
|
||
EXPOSE 28799/udp 28800/udp 28801/udp 28802/udp | ||
|
||
ENTRYPOINT ["/sbin/tini", "--"] | ||
|
||
CMD dockerize -template /servinit.tmpl:/blue-nebula/.blue-nebula/servinit.cfg install/bin/blue-nebula_server_linux |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
version: "3" | ||
|
||
services: | ||
bn-server: | ||
image: ghcr.io/blue-nebula/server:latest | ||
restart: unless-stopped | ||
|
||
# adjust accordingly if you change the ports in the config | ||
# note: the ports must be in sync! otherwise, the server will announce the wrong ports to the master | ||
ports: | ||
- "0.0.0.0:28801:28801/udp" | ||
- "0.0.0.0:28802:28802/udp" | ||
|
||
# most-if-not-all environment variables are exposed as upper-case environment variables as shown below | ||
environment: | ||
ADMIN_PASS: "so-secret" | ||
SERVER_TYPE: 1 | ||
SERVER_PORT: 28801 | ||
SV_SERVERCLIENTS: 16 | ||
SV_SERVERDESC: "Example BN server running in Docker" | ||
SV_SERVERMOTD: "Welcome to this example Blue Nebula server hosted in a Docker container!" | ||
|
||
# to add additional maps, you can mount a directory as shown below | ||
volumes: | ||
- ./custom-maps:/blue-nebula/.blue-nebula/maps/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
#! /usr/bin/env python3 | ||
|
||
import re | ||
import sys | ||
import textwrap | ||
|
||
|
||
class ParsingException(Exception): | ||
pass | ||
|
||
|
||
def convert_variable(variable_name: str, default_value: str, comment: str, indentation: int = None): | ||
if indentation is None: | ||
indentation = 0 | ||
|
||
variable_name_upper = variable_name.upper() | ||
env_var_name = ".Env.%s" % variable_name_upper | ||
|
||
lines = [] | ||
lines.append("{{ if (contains .Env \"%s\") -}}" % variable_name_upper) | ||
#lines.append(comment) | ||
#lines.append("// default/example value: %s" % default_value) | ||
lines.append("%s \"{{ %s }}\"" % (variable_name, env_var_name)) | ||
lines.append("{{ else -}}") | ||
lines.append("// %s %s %s" % (variable_name, default_value, comment)) | ||
lines.append("{{ end -}}") | ||
lines.append("") | ||
|
||
return textwrap.indent("\n".join(lines), " "*indentation) | ||
|
||
|
||
def parse_and_convert_variable(pattern: str, line: str, indentation: int = None): | ||
match = re.match(pattern, line) | ||
|
||
if not match: | ||
return | ||
|
||
return convert_variable(*match.groups(), indentation) | ||
|
||
|
||
def parse_regular_variable(line: str): | ||
return parse_and_convert_variable(r"^//\s?((?:sv_|admin|server)\w+)\s+(.+)\s+(\/\/.*)$", line) | ||
|
||
|
||
def parse_rehashing_variable(line: str): | ||
return parse_and_convert_variable(r"^ //\s*((?!irc)\w+)\s+(.+)\s+(\/\/.*)$", line, 4) | ||
|
||
|
||
def parse_add_variable(line: str): | ||
match = re.match(r"^//\s? (add\w+)\s+(.+)\s*(|\/\/.*)$", line) | ||
|
||
if not match: | ||
return | ||
|
||
variable_name, default_value, comment = match.groups() | ||
|
||
variable_name_upper = variable_name.upper() | ||
env_var_name = ".Env.%s" % variable_name_upper | ||
|
||
lines = [] | ||
lines.append("{{ if (contains .Env \"%s\") -}}" % variable_name_upper) | ||
#lines.append(comment) | ||
#lines.append("// default/example value: %s" % default_value) | ||
lines.append("{{ range $e := ( split %s \";\" ) -}}" % env_var_name) | ||
lines.append("%s {{ $e }}" % variable_name) | ||
lines.append("{{ end -}}") | ||
lines.append("{{ else -}}") | ||
lines.append(line) | ||
lines.append("{{ end -}}") | ||
lines.append("") | ||
|
||
return "\n".join(lines) | ||
|
||
|
||
def parse_and_convert_line(line: str) -> str: | ||
for f in [parse_regular_variable, parse_rehashing_variable, parse_add_variable]: | ||
parsed = f(line) | ||
|
||
if parsed is not None: | ||
return parsed | ||
|
||
else: | ||
return line | ||
|
||
|
||
def make_irc_section(): | ||
return textwrap.dedent( | ||
""" | ||
{{ if (contains .Env "ENABLE_IRC") -}} | ||
// special single-server IRC configuration, suitable for our Docker deployment | ||
// setting ENABLE_IRC to some value will be sufficient in most cases | ||
if (= $rehashing 0) [ | ||
ircfilter {{ default .Env.IRC_FILTER "1" }} // defines the way the colour-to-irc filter works; 0 = off, "1" = convert, 2 = strip | ||
ircaddrelay ircrelay {{ default .Env.IRC_RELAY_HOSTNAME "localhost" }} {{ default .Env.IRC_RELAY_PORT "6667" }} {{ default .Env.IRC_RELAY_NICK "re-server" }} | ||
{{ if (contains .Env "IRC_BIND_ADDRESS") -}} | ||
ircbind ircrelay {{ .Env.IRC_BIND_ADDRESS }} // use this only if you need to bind to a specific address, eg. multihomed machines | ||
{{ end -}} | ||
{{ if (contains .Env "IRC_SERVER_PASS" ) -}} | ||
ircpass ircrelay {{ .Env.IRC_SERVER_PASS }} // some networks can use the PASS field to identify to nickserv | ||
{{ end -}} | ||
{{ if (contains .Env "IRC_CHANNELS") -}} | ||
{{ range $e := ( split .Env.IRC_CHANNELS "," ) -}} | ||
ircaddchan ircrelay "{{ $e }}" | ||
ircrelaychan ircrelay "{{ $e }}" 3 | ||
{{ end -}} | ||
{{ end -}} | ||
ircconnect ircrelay // and tell it to connect! | ||
] | ||
{{ end -}} | ||
""" | ||
) | ||
|
||
|
||
def make_additional_vars_section(): | ||
text = textwrap.dedent( | ||
""" | ||
{{ if (contains .Env "ADDITIONAL_VARS") -}} | ||
// additional variables | ||
{{ range $e := (split .Env.ADDITIONAL_VARS ";") -}} | ||
{{ $a := (split $e "=") -}} | ||
{{ index $a 0 }} {{ index $a 1 }} | ||
{{ end -}} | ||
{{ end -}} | ||
{{ if (contains .Env "SV_DUELMAXQUEUED") -}} | ||
sv_duelmaxqueued "{{ .Env.SV_DUELMAXQUEUED }}" | ||
{{ end -}} | ||
""" | ||
) | ||
|
||
for i in ["duelmaxqueued", "teamneutralcolour"]: | ||
pass | ||
text += textwrap.dedent( | ||
""" | ||
{{{{ if (contains .Env "SV_{upper}") -}}}} | ||
sv_{lower} "{{{{ .Env.SV_{upper} }}}}" | ||
{{{{ end -}}}} | ||
""".format(lower=i, upper=i.upper()) | ||
) | ||
|
||
return text | ||
|
||
|
||
def main(): | ||
with open(sys.argv[1]) as f: | ||
lines = f.read().splitlines() | ||
|
||
for line in lines: | ||
print(parse_and_convert_line(line)) | ||
|
||
print(make_irc_section()) | ||
print(make_additional_vars_section()) | ||
|
||
|
||
if __name__ == "__main__": | ||
try: | ||
sys.exit(main()) | ||
except BrokenPipeError: | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
diff --git a/src/engine/server.cpp b/src/engine/server.cpp | ||
index a8530e43..89e63f4f 100644 | ||
--- a/src/engine/server.cpp | ||
+++ b/src/engine/server.cpp | ||
@@ -1329,6 +1329,7 @@ int setupserversockets() | ||
if(!servertype || (serverhost && pongsock != ENET_SOCKET_NULL)) return servertype; | ||
|
||
ENetAddress address = { ENET_HOST_ANY, enet_uint16(serverport) }; | ||
+#if 0 | ||
if(*serverip) | ||
{ | ||
if(enet_address_set_host(&address, serverip) < 0) | ||
@@ -1338,6 +1339,7 @@ int setupserversockets() | ||
} | ||
else serveraddress.host = address.host; | ||
} | ||
+#endif | ||
|
||
if(!serverhost) | ||
{ |