-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Build and publish Docker images #257
Open
TheAssassin
wants to merge
7
commits into
blue-nebula:master
Choose a base branch
from
TheAssassin:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
528e7a3
Add Docker build configuration for server
TheAssassin 6441714
Automatically publish Docker images on GitHub
TheAssassin 5b2f518
Update ignore patterns
TheAssassin 6b0074e
fixup! Add Docker build configuration for server
TheAssassin fb0b40c
fixup! Automatically publish Docker images on GitHub
TheAssassin a7118e5
Replace patch with new variable serverpublicip
TheAssassin 9298089
fixup! Replace patch with new variable serverpublicip
TheAssassin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
name: Build Docker images for Blue Nebula server | ||
|
||
on: | ||
push: | ||
tags: | ||
- "*" | ||
branches: | ||
- "*" | ||
pull_request: | ||
branches: | ||
- master | ||
workflow_dispatch: | ||
inputs: | ||
include_arm64: | ||
description: Build arm64 Docker image | ||
type: boolean | ||
required: false | ||
default: false | ||
|
||
jobs: | ||
build-and-push: | ||
runs-on: ubuntu-latest | ||
|
||
permissions: | ||
contents: read | ||
packages: write | ||
|
||
steps: | ||
- uses: actions/checkout@v3 | ||
|
||
- name: Fetch relevant submodules | ||
run: | | ||
git submodule update --init src/enet | ||
git submodule update --init data/maps | ||
|
||
- name: Log in to the Container registry | ||
uses: docker/login-action@v2 | ||
with: | ||
registry: ghcr.io | ||
username: ${{ github.actor }} | ||
password: ${{ secrets.GITHUB_TOKEN }} | ||
|
||
- name: Docker meta | ||
id: meta | ||
uses: docker/metadata-action@v4 | ||
with: | ||
images: | | ||
ghcr.io/blue-nebula/server | ||
tags: | | ||
type=semver,pattern={{version}},event=tag | ||
type=ref,event=branch | ||
type=sha | ||
|
||
- name: Set up QEMU | ||
uses: docker/setup-qemu-action@v2 | ||
|
||
- name: Set up Docker Buildx | ||
uses: docker/setup-buildx-action@v2 | ||
|
||
- name: Build and push Docker images | ||
uses: docker/build-push-action@v3 | ||
with: | ||
context: . | ||
file: docker/Dockerfile | ||
# enable arm64 by default once native runners are available | ||
platforms: ${{ inputs.include_arm64 && 'linux/amd64,linux/arm64' || 'linux/amd64' }} | ||
push: ${{ github.event_name != 'pull_request' }} | ||
tags: ${{ steps.meta.outputs.tags }} |
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
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,65 @@ | ||
# 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 \ | ||
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/ | ||
|
||
RUN mkdir build && \ | ||
cd build && \ | ||
# TODO: server-only build configuration | ||
cmake .. -DCMAKE_BUILD_TYPE=Release -G Ninja -DCMAKE_INSTALL_PREFIX=/blue-nebula/install -DBUILD_CLIENT=OFF && \ | ||
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 | ||
|
||
LABEL maintainer="https://blue-nebula.org" | ||
|
||
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 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 |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can remove this now as it does not exist anymore.