Using docker for production server

Post here your questions about SFS2X. Here we discuss all server-side matters. For client API questions see the dedicated forums.

Moderators: Lapo, Bax

willan
Posts: 7
Joined: 30 Nov 2021, 05:26

Using docker for production server

Postby willan » 23 Dec 2021, 05:04

Hi

I'm developing our game with smartfox2x as gameserver, and making use of docker to simplify the deployment.
And the only way I can run smartfox server through docker is using sfs2x.sh script
As I search around the forum (for example viewtopic.php?t=22059), you suggest to only use sfs2x.sh script for development and sfs2x-service start for production
But the thing about sfs2x-service script is it stops right at the start and thus make the docker container to stop as well

To workaround it, I can add a tail -f /dev/null command behind and force the process to run forever.
But one thing is that I don't know if it's a good idea, because there maybe the case where the smartfox server has some issues and stop, but the docker container will not notice that and continue to run.

So my question is, do you have any better suggestion about running smartfox server through docker by using sfs2x-service script? (other than my workaround above)
User avatar
Lapo
Site Admin
Posts: 23008
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Using docker for production server

Postby Lapo » 23 Dec 2021, 10:07

Hi,
what version of SFS2X are you using and under which OS?
Are there any errors when using the sfs2x-service command? Have you checked the server side logs after running the command to see if there's any relevant error message?

Also have you modified any of the launch scripts?
Have you modified or replaced the embedded java runtime?

Thanks
Lapo
--
gotoAndPlay()
...addicted to flash games
willan
Posts: 7
Joined: 30 Nov 2021, 05:26

Re: Using docker for production server

Postby willan » 24 Dec 2021, 09:16

Lapo wrote:what version of SFS2X are you using and under which OS?

It's the SFS2X latest version 2.18.0, and I run it on an EC2 instance with Amazon Linux 2 OS

Lapo wrote:Are there any errors when using the sfs2x-service command? Have you checked the server side logs after running the command to see if there's any relevant error message?

There is only the starting log of SFS2X, which is

Code: Select all

Starting sfs2x-service

There isn't even any java process running
I think it's because that's the way docker works. If the script uses to run the docker container stops, that docker container stops too, and also stops any of its child process

Lapo wrote:Also have you modified any of the launch scripts?
Have you modified or replaced the embedded java runtime?

Before 2.18.0, I had to replace the default jre with jre 11. But since updating to 2.18.0, I removed that, and used the default jre, as it's v11 and fit my needs.
No, I only modified the sfs2x.sh to change from using built-in jre to my jre (installed outside of SFS2X), but not the sfs2x-service script. And it's also removed since I updated to sfs2x 2.18.0

UPDATE:
I checked the sfs2x-service script and found out about the start-launchd parameter
It's almost the same with start parameter, except it prints out logs and only stop if sfs2x crash or stop itself
So I wonder should I use start-launchd parameter instead of start parameter?
Last edited by willan on 24 Dec 2021, 11:09, edited 1 time in total.
User avatar
Lapo
Site Admin
Posts: 23008
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Using docker for production server

Postby Lapo » 24 Dec 2021, 10:57

Hi,
I have to premise this by saying that I am not very familiar with Docker. I know what it is and how it works (by virtualizing the OS rather than the hardware) but I've never used it.

There isn't even any java process running
It's because that's the way docker works
If the script uses to run the docker container stops, that docker container stops too, and also stops any of its child process

So if you run the sfs2x-service start command it starts and dies immediately after?
I get that if you stop the docker container the process(es) associated with it will die, but I'd expect SFS2X to be able to run inside the container without issues. At least until the container is running.

Is it not the case? If it does run, then I am not sure I fully understand what the problem is.
Can you clarify?
Thanks
Lapo

--

gotoAndPlay()

...addicted to flash games
willan
Posts: 7
Joined: 30 Nov 2021, 05:26

Re: Using docker for production server

Postby willan » 24 Dec 2021, 11:43

Lapo wrote:I'd expect SFS2X to be able to run inside the container without issues. At least until the container is running.

Is it not the case? If it does run, then I am not sure I fully understand what the problem is.
Can you clarify?

Yes, SFS2X will be running inside the container without any issue for as long as that SFS2X instance lifetime.
  • For development, I used the sfs2x.sh script, the SFS2X instance run fine, until the instance crashes, or I decide to stop the docker container.
  • For production, I used the sfs2x-service script, the SFS2X instance stopped right after the log "Starting sfs2x-service", so as the container
I guess it's because the way of sfs2x-service start work, it starts java process with nohup command, and stop itself right after, and leaves that background java process to continue the job.

To be honest, I'm also a docker newbie here, but that's what I learned from using it.
I think the script that runs inside the docker container will send an exit signal to the container when it stops, to notify the docker to stop as well.

Anyway, maybe you haven't read my UPDATE, so I re-post it here:
willan wrote:I checked the sfs2x-service script code and found out about the start-launchd parameter
It's almost the same with start parameter, except it prints out logs and continue to run.
I tried that with docker and it works just fine.
So I wonder if I can use start-launchd parameter instead of start parameter for production?
User avatar
Lapo
Site Admin
Posts: 23008
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Using docker for production server

Postby Lapo » 24 Dec 2021, 13:34

I think the script that runs inside the docker container will send an exit signal to the container when it stops, to notify the docker to stop as well.

Our start script doesn't do that. But maybe the difference using the start-launchd parameter is that it uses exec rather than nohup. Though it isn't really clear why nohup should behave differently in Docker. If that's the case. a lot of things are likely to break, since this is an often used mode of running background services.

Maybe this article is relevant?
https://unix.stackexchange.com/question ... ker-script

As regards your update I saw it, but I wanted to clear some basics before getting into more specific details:
So I wonder if I can use start-launchd parameter instead of start parameter for production?

Yes sure, it is probably the correct thing to do in that environment.

Meanwhile I have added a note in our TODO list to take a closer look at Docker and how to run SFS2X in it.
Let us know if you discover anything else, and happy holidays :)

Cheers
Lapo

--

gotoAndPlay()

...addicted to flash games
User avatar
Lapo
Site Admin
Posts: 23008
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Using docker for production server

Postby Lapo » 24 Dec 2021, 13:39

Small addendum:
have you tried this? --> ./sfs2x-service run
It seems the same as launchd, but it's documented among the available commands, while the launchd command isn't, for some reason.

I say so because the sfs2x-service script is auto-generated by the installer software, Install4J.

Cheers
Lapo

--

gotoAndPlay()

...addicted to flash games
willan
Posts: 7
Joined: 30 Nov 2021, 05:26

Re: Using docker for production server

Postby willan » 29 Dec 2021, 03:35

Happy holidays

Lapo wrote:Small addendum:
have you tried this? --> ./sfs2x-service run
It seems the same as launchd, but it's documented among the available commands, while the launchd command isn't, for some reason.

I say so because the sfs2x-service script is auto-generated by the installer software, Install4J.

Cheers


I haven't tried that, because I saw the 2 parameters use the different commands, so I didn't "dare" to try.
  • start/start-launchd parameter runs with install4j.com.smartfoxserver.v2.Main start
  • run parameter runs with install4j.com.smartfoxserver.v2.Main run
But if you said so, I will give it a go.

However, may I ask that is there any difference between start and run functions of install4j.com.smartfoxserver.v2.Main class, that used in the sfs2x-service script
User avatar
Lapo
Site Admin
Posts: 23008
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Using docker for production server

Postby Lapo » 29 Dec 2021, 06:44

Hi,
unfortunately I can't tell for sure, as the whole launch system is auto-generated by the installation tool we use, which is Install4J.
What that does behind the scenes we don't know.

The only commands that are documented are the: start / stop / restart / status

The only suggestion I can give is to try the different command and see if they behave as expected.
Let us know.
Lapo

--

gotoAndPlay()

...addicted to flash games
willan
Posts: 7
Joined: 30 Nov 2021, 05:26

Re: Using docker for production server

Postby willan » 02 Jan 2022, 16:39

Yeah sure, I'm doing that
I will come back later with the result

Thanks a lot for your support
Luke64
Posts: 21
Joined: 08 Nov 2020, 23:15

Re: Using docker for production server

Postby Luke64 » 15 Jan 2022, 21:21

Sorry to jump in but I use Docker for SFS2X and was unaware one shouldn't use sfs2x.sh in production because it works fine. ;)

What I usually do is make a universal base image with the server itself, then extending that image in my projects and adding project-specific configurations and data. I also added an entrypoint script which allows other startup-scripts to be added into a directory to be executed on startup.

The base repository looks like this:

Code: Select all

docker-entrypoint.sh
Dockerfile
log4j.properties.patch
SFS2X-Patch-2.18.1.zip
SFS2X_unix_2_18_0.tar.gz


This is the Dockerfile. The runtime is based on OpenJDK's JRE version 11 but the installation of SFSX2X is performed in a plain Ubuntu 20.04. It also applies a patch file and any .patch files (I failed to report this, there is a small mistake in the log4j.properties):

Code: Select all

FROM ubuntu:20.04 AS sfs2x

ARG SFS2X_BASE_TGZ=SFS2X_unix_2_18_0.tar.gz
ARG SFS2X_BASE_DIR=SmartFoxServer_2X
ARG SFS2X_PATCH_DIR=SFS2X-Patch-2.18.1
ARG SFS2X_PATCH_ZIP=${SFS2X_PATCH_DIR}.zip

WORKDIR /opt

COPY ["${SFS2X_BASE_TGZ}", "${SFS2X_PATCH_ZIP}", "*.patch", "./"]

RUN set -e \
    && apt-get update -y \
    && apt-get install -y --no-install-recommends unzip patch gettext-base \
    && tar -xzf "${SFS2X_BASE_TGZ}" \
    && cd "${SFS2X_BASE_DIR}" \
    && unzip ../"${SFS2X_PATCH_ZIP}" \
    && cd "${SFS2X_PATCH_DIR}" \
    && /bin/sh install-linux.sh \
    && cd .. \
    && rm -rf "${SFS2X_PATCH_DIR}" \
    && rm -rf jre \
    && cd .. \
    && for PATCH_FILE in *.patch; do \
        echo applying ${PATCH_FILE}...; \
        patch -p0 -i "${PATCH_FILE}"; \
        done


FROM openjdk:11-jre

ENV FROM_SFS2X_DIR=/opt/SmartFoxServer_2X
ENV SFS2X_DIR=/home/sfs2x/SmartFoxServer_2X
ENV WORKDIR=${SFS2X_DIR}/SFS2X

RUN set -e \
    && addgroup sfs2x --gid 1001 \
    && adduser sfs2x --gecos "" --disabled-password --uid 1001 --ingroup sfs2x \
    && mkdir -p /docker-entrypoint.d \
    && chown sfs2x:sfs2x /docker-entrypoint.d \
    && apt-get update -y \
    && apt-get install -y --no-install-recommends gettext-base \
    && apt-get autoremove -y --purge \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

COPY --from=sfs2x --chown=sfs2x:sfs2x ["${FROM_SFS2X_DIR}", "${SFS2X_DIR}"]
COPY --chown=sfs2x:sfs2x ["docker-entrypoint.sh", "/"]

USER sfs2x

RUN set -xe \
    && ln -s "${JAVA_HOME}" "${SFS2X_DIR}/jre"

WORKDIR ${WORKDIR}

EXPOSE 8080 8443 9933/tcp 9933/udp
# java debugger and visualvm default ports
EXPOSE 8787 5000

ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["bash", "sfs2x.sh"]


The entrypoint.sh is just a usual entrypoint script:

Code: Select all

#!/usr/bin/env bash

DIR=/docker-entrypoint.d

set -e

if [[ -d "$DIR" ]]; then
  /bin/run-parts --verbose --exit-on-error --regex '.' "$DIR"
fi

exec "$@"


@Lapo, the log4j patch is this:

Code: Select all

--- SmartFoxServer_2X/SFS2X/config/log4j.properties  2021-01-06 23:36:25.000000000 +0100
+++ SmartFoxServer_2X/SFS2X/config/log4j.properties     2021-01-06 23:38:29.000000000 +0100
@@ -55,7 +55,7 @@
 log4j.appender.bootFileAppender=org.apache.log4j.DailyRollingFileAppender
 log4j.appender.bootFileAppender.layout=org.apache.log4j.PatternLayout
 log4j.appender.bootFileAppender.File=logs/boot/boot.log
-log4j.appender.bootConsoleAppender.threshold=DEBUG
+log4j.appender.bootFileAppender.threshold=DEBUG
 log4j.appender.bootFileAppender.layout.ConversionPattern=%d{dd MMM yyyy | HH:mm:ss,SSS} | %-5p | %t | %c{3} | %3x | %m%n
 log4j.appender.bootFileAppender.Encoding=UTF-8


Both the SFS2X files are the official, unmodified ones.

Building this image gives you a startable, unconfigured SFS2X 2.18.1 in a container.


Now, in order to use it in my project, I needed to save the configuration files. As I like having those in source control, I configured a blank SFS2X to my liking, then copied all the configuration files (core.xml, server.xml, Zone(s), ...) from the image to my project.

Code: Select all

> database-driver
  mysql-connector-java-8.0.27.jar
  postgresql-42.3.1.jar
> server
  > config
    core.xml.envsubst
    log4j.properties
    server.xml.envsubst
  > docker-entrypoint.d
    envsubst_configs.sh
  > zones
    Fishing Friends.zone.xml.envsubst
Dockerfile


I can't go into all the details here but the Dockerfile installs maven into the OpenJDK 11 image, then builds my extension and custom storage JARs and a WAR for a push API I'm using, then copies everything on top of the SFS2X base image:

Code: Select all

FROM openjdk:11 AS openjdk-maven

# maven build source:
# https://github.com/AdoptOpenJDK/openjdk-docker-build-tools/blob/master/11/maven/ubuntu/Dockerfile.hotspot.releases.full
ARG MAVEN_VERSION="3.8.4"
ARG USER_HOME_DIR="/root"
ARG MAVEN_SHA="a9b2d825eacf2e771ed5d6b0e01398589ac1bfa4171f36154d1b5787879605507802f699da6f7cfc80732a5282fd31b28e4cd6052338cbef0fa1358b48a5e3c8"
ARG MAVEN_BASE_URL="https://apache.osuosl.org/maven/maven-3/${MAVEN_VERSION}/binaries"

ENV MAVEN_HOME /usr/share/maven
ENV MAVEN_CONFIG "${USER_HOME_DIR}/.m2"
ENV USER_HOME_DIR ${USER_HOME_DIR}

RUN set -e \
    && mkdir -p "${MAVEN_HOME}" \
    && curl -LsSo /tmp/maven.tar.gz "${MAVEN_BASE_URL}/apache-maven-${MAVEN_VERSION}-bin.tar.gz" \
    && echo "${MAVEN_SHA}  /tmp/maven.tar.gz" | sha512sum -c - \
    && tar -xzC "${MAVEN_HOME}" --strip-components=1 -f /tmp/maven.tar.gz \
    && rm -v /tmp/maven.tar.gz \
    && ln -s "${MAVEN_HOME}/bin/mvn" /usr/bin/mvn \
    && mvn -v

WORKDIR $USER_HOME_DIR


FROM openjdk-maven AS extension-build

COPY --from=registry.gitlab.com/robotriot/smartfoxserver-2x:2.18.1 /home/sfs2x/SmartFoxServer_2X/SFS2X/lib/sfs2x-core.jar /home/sfs2x/SmartFoxServer_2X/SFS2X/lib/sfs2x.jar ./

COPY custom-storage custom-storage
COPY zone-extension zone-extension
COPY push-api push-api
COPY pom.xml pom.xml

RUN set -e \
    && mvn clean package \
    && mkdir "${USER_HOME_DIR}/mvn-deps" \
    && mvn dependency:copy-dependencies -DincludeScope=runtime -DoutputDirectory="${USER_HOME_DIR}/mvn-deps"


FROM registry.gitlab.com/robotriot/smartfoxserver-2x:2.18.1

RUN set -xe \
    && rm -rf www/HelloServlet \
    && rm -rf extensions/pyTest \
    && rm -rf zones/*

COPY --chown=sfs2x:sfs2x --from=extension-build ["/root/zone-extension/target/*.jar", "extensions/MyCustomZone/"]
COPY --chown=sfs2x:sfs2x --from=extension-build ["/root/push-api/target/*.war", "www/"]
COPY --chown=sfs2x:sfs2x --from=extension-build ["/root/custom-storage/target/*.jar", "extensions/__lib__/"]
COPY --chown=sfs2x:sfs2x --from=extension-build ["/root/mvn-deps/*.jar", "extensions/__lib__/"]
COPY --chown=sfs2x:sfs2x ["database-driver/*.jar", "extensions/__lib__/"]
COPY --chown=sfs2x:sfs2x ["server/config/*", "config/"]
COPY --chown=sfs2x:sfs2x ["server/zones/*", "zones/"]
COPY --chown=sfs2x:sfs2x ["server/docker-entrypoint.d/*", "/docker-entrypoint.d/"]


The envsubst_configs.sh file replaces ENV variables in given files - it is being copied into the entrypoint.sh.d/ directory created in the baseimage and will therefore be automatically run on container start, replacing several values in the config files ending in .envsubst with ENV vars:

Code: Select all

#!/usr/bin/env sh

set -e

echo "envsubst'ing config files..."
# find all files ending with .envsubst and feed them to envsubst command,
# overwriting the file without that extension in the same path.
# note: ArrayList is defined because $ArrayList is used in the zone file,
# getting picked up and replaced with nothing by envsubst. defining the
# "variable" we replace it with its exact string again.
ArrayList='$ArrayList' find "${WORKDIR}" -type f -a -name '*.envsubst' -exec sh -c 'echo "${1} > ${1%.envsubst}"; envsubst < "${1}" > "${1%.envsubst}"' _ {} \;

echo "done."


This comes in handy in e.g. in the zone file:

Code: Select all

  <databaseManager active="true">
    <driverName>org.postgresql.Driver</driverName>
    <connectionString>jdbc:postgresql://${SFS2X_FF_DB_HOST}:${SFS2X_FF_DB_PORT}/${SFS2X_FF_DB_NAME}</connectionString>
    <userName>${SFS2X_FF_DB_USERNAME}</userName>
    <password>${SFS2X_FF_DB_PASSWORD}</password>
    ...

...or the server config:

Code: Select all

      <adminUser>
        <login>${SFS2X_ADMIN_USERNAME}</login>
        <password>${SFS2X_ADMIN_PASSWORD}</password>
        ...

This way, the image is usable both in local development (using docker compose) and in production.

Sorry this became so long. I hope you can extract some useful information from the above.

Cheers,
Luke
User avatar
Lapo
Site Admin
Posts: 23008
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Using docker for production server

Postby Lapo » 17 Jan 2022, 11:25

@Luke64, thanks for the detailed post :)
Lapo

--

gotoAndPlay()

...addicted to flash games
luxmobile
Posts: 1
Joined: 01 Mar 2022, 19:43

Re: Using docker for production server

Postby luxmobile » 01 Mar 2022, 19:45

This sounds like exactly what I want to do, using SFS2X in production on AWS ECS services. Might even use HAProxy on it...

How did you go about doing the licenses? Each instance needs it's own license to start, was there something you used to track and assign them?

Luke64 wrote:Sorry to jump in but I use Docker for SFS2X and was unaware one shouldn't use sfs2x.sh in production because it works fine. ;)

What I usually do is make a universal base image with the server itself, then extending that image in my projects and adding project-specific configurations and data. I also added an entrypoint script which allows other startup-scripts to be added into a directory to be executed on startup.

The base repository looks like this:

Code: Select all

docker-entrypoint.sh
Dockerfile
log4j.properties.patch
SFS2X-Patch-2.18.1.zip
SFS2X_unix_2_18_0.tar.gz


This is the Dockerfile. The runtime is based on OpenJDK's JRE version 11 but the installation of SFSX2X is performed in a plain Ubuntu 20.04. It also applies a patch file and any .patch files (I failed to report this, there is a small mistake in the log4j.properties):

Code: Select all

FROM ubuntu:20.04 AS sfs2x

ARG SFS2X_BASE_TGZ=SFS2X_unix_2_18_0.tar.gz
ARG SFS2X_BASE_DIR=SmartFoxServer_2X
ARG SFS2X_PATCH_DIR=SFS2X-Patch-2.18.1
ARG SFS2X_PATCH_ZIP=${SFS2X_PATCH_DIR}.zip

WORKDIR /opt

COPY ["${SFS2X_BASE_TGZ}", "${SFS2X_PATCH_ZIP}", "*.patch", "./"]

RUN set -e \
    && apt-get update -y \
    && apt-get install -y --no-install-recommends unzip patch gettext-base \
    && tar -xzf "${SFS2X_BASE_TGZ}" \
    && cd "${SFS2X_BASE_DIR}" \
    && unzip ../"${SFS2X_PATCH_ZIP}" \
    && cd "${SFS2X_PATCH_DIR}" \
    && /bin/sh install-linux.sh \
    && cd .. \
    && rm -rf "${SFS2X_PATCH_DIR}" \
    && rm -rf jre \
    && cd .. \
    && for PATCH_FILE in *.patch; do \
        echo applying ${PATCH_FILE}...; \
        patch -p0 -i "${PATCH_FILE}"; \
        done


FROM openjdk:11-jre

ENV FROM_SFS2X_DIR=/opt/SmartFoxServer_2X
ENV SFS2X_DIR=/home/sfs2x/SmartFoxServer_2X
ENV WORKDIR=${SFS2X_DIR}/SFS2X

RUN set -e \
    && addgroup sfs2x --gid 1001 \
    && adduser sfs2x --gecos "" --disabled-password --uid 1001 --ingroup sfs2x \
    && mkdir -p /docker-entrypoint.d \
    && chown sfs2x:sfs2x /docker-entrypoint.d \
    && apt-get update -y \
    && apt-get install -y --no-install-recommends gettext-base \
    && apt-get autoremove -y --purge \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

COPY --from=sfs2x --chown=sfs2x:sfs2x ["${FROM_SFS2X_DIR}", "${SFS2X_DIR}"]
COPY --chown=sfs2x:sfs2x ["docker-entrypoint.sh", "/"]

USER sfs2x

RUN set -xe \
    && ln -s "${JAVA_HOME}" "${SFS2X_DIR}/jre"

WORKDIR ${WORKDIR}

EXPOSE 8080 8443 9933/tcp 9933/udp
# java debugger and visualvm default ports
EXPOSE 8787 5000

ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["bash", "sfs2x.sh"]


The entrypoint.sh is just a usual entrypoint script:

Code: Select all

#!/usr/bin/env bash

DIR=/docker-entrypoint.d

set -e

if [[ -d "$DIR" ]]; then
  /bin/run-parts --verbose --exit-on-error --regex '.' "$DIR"
fi

exec "$@"


@Lapo, the log4j patch is this:

Code: Select all

--- SmartFoxServer_2X/SFS2X/config/log4j.properties  2021-01-06 23:36:25.000000000 +0100
+++ SmartFoxServer_2X/SFS2X/config/log4j.properties     2021-01-06 23:38:29.000000000 +0100
@@ -55,7 +55,7 @@
 log4j.appender.bootFileAppender=org.apache.log4j.DailyRollingFileAppender
 log4j.appender.bootFileAppender.layout=org.apache.log4j.PatternLayout
 log4j.appender.bootFileAppender.File=logs/boot/boot.log
-log4j.appender.bootConsoleAppender.threshold=DEBUG
+log4j.appender.bootFileAppender.threshold=DEBUG
 log4j.appender.bootFileAppender.layout.ConversionPattern=%d{dd MMM yyyy | HH:mm:ss,SSS} | %-5p | %t | %c{3} | %3x | %m%n
 log4j.appender.bootFileAppender.Encoding=UTF-8


Both the SFS2X files are the official, unmodified ones.

Building this image gives you a startable, unconfigured SFS2X 2.18.1 in a container.


Now, in order to use it in my project, I needed to save the configuration files. As I like having those in source control, I configured a blank SFS2X to my liking, then copied all the configuration files (core.xml, server.xml, Zone(s), ...) from the image to my project.

Code: Select all

> database-driver
  mysql-connector-java-8.0.27.jar
  postgresql-42.3.1.jar
> server
  > config
    core.xml.envsubst
    log4j.properties
    server.xml.envsubst
  > docker-entrypoint.d
    envsubst_configs.sh
  > zones
    Fishing Friends.zone.xml.envsubst
Dockerfile


I can't go into all the details here but the Dockerfile installs maven into the OpenJDK 11 image, then builds my extension and custom storage JARs and a WAR for a push API I'm using, then copies everything on top of the SFS2X base image:

Code: Select all

FROM openjdk:11 AS openjdk-maven

# maven build source:
# https://github.com/AdoptOpenJDK/openjdk-docker-build-tools/blob/master/11/maven/ubuntu/Dockerfile.hotspot.releases.full
ARG MAVEN_VERSION="3.8.4"
ARG USER_HOME_DIR="/root"
ARG MAVEN_SHA="a9b2d825eacf2e771ed5d6b0e01398589ac1bfa4171f36154d1b5787879605507802f699da6f7cfc80732a5282fd31b28e4cd6052338cbef0fa1358b48a5e3c8"
ARG MAVEN_BASE_URL="https://apache.osuosl.org/maven/maven-3/${MAVEN_VERSION}/binaries"

ENV MAVEN_HOME /usr/share/maven
ENV MAVEN_CONFIG "${USER_HOME_DIR}/.m2"
ENV USER_HOME_DIR ${USER_HOME_DIR}

RUN set -e \
    && mkdir -p "${MAVEN_HOME}" \
    && curl -LsSo /tmp/maven.tar.gz "${MAVEN_BASE_URL}/apache-maven-${MAVEN_VERSION}-bin.tar.gz" \
    && echo "${MAVEN_SHA}  /tmp/maven.tar.gz" | sha512sum -c - \
    && tar -xzC "${MAVEN_HOME}" --strip-components=1 -f /tmp/maven.tar.gz \
    && rm -v /tmp/maven.tar.gz \
    && ln -s "${MAVEN_HOME}/bin/mvn" /usr/bin/mvn \
    && mvn -v

WORKDIR $USER_HOME_DIR


FROM openjdk-maven AS extension-build

COPY --from=registry.gitlab.com/robotriot/smartfoxserver-2x:2.18.1 /home/sfs2x/SmartFoxServer_2X/SFS2X/lib/sfs2x-core.jar /home/sfs2x/SmartFoxServer_2X/SFS2X/lib/sfs2x.jar ./

COPY custom-storage custom-storage
COPY zone-extension zone-extension
COPY push-api push-api
COPY pom.xml pom.xml

RUN set -e \
    && mvn clean package \
    && mkdir "${USER_HOME_DIR}/mvn-deps" \
    && mvn dependency:copy-dependencies -DincludeScope=runtime -DoutputDirectory="${USER_HOME_DIR}/mvn-deps"


FROM registry.gitlab.com/robotriot/smartfoxserver-2x:2.18.1

RUN set -xe \
    && rm -rf www/HelloServlet \
    && rm -rf extensions/pyTest \
    && rm -rf zones/*

COPY --chown=sfs2x:sfs2x --from=extension-build ["/root/zone-extension/target/*.jar", "extensions/MyCustomZone/"]
COPY --chown=sfs2x:sfs2x --from=extension-build ["/root/push-api/target/*.war", "www/"]
COPY --chown=sfs2x:sfs2x --from=extension-build ["/root/custom-storage/target/*.jar", "extensions/__lib__/"]
COPY --chown=sfs2x:sfs2x --from=extension-build ["/root/mvn-deps/*.jar", "extensions/__lib__/"]
COPY --chown=sfs2x:sfs2x ["database-driver/*.jar", "extensions/__lib__/"]
COPY --chown=sfs2x:sfs2x ["server/config/*", "config/"]
COPY --chown=sfs2x:sfs2x ["server/zones/*", "zones/"]
COPY --chown=sfs2x:sfs2x ["server/docker-entrypoint.d/*", "/docker-entrypoint.d/"]


The envsubst_configs.sh file replaces ENV variables in given files - it is being copied into the entrypoint.sh.d/ directory created in the baseimage and will therefore be automatically run on container start, replacing several values in the config files ending in .envsubst with ENV vars:

Code: Select all

#!/usr/bin/env sh

set -e

echo "envsubst'ing config files..."
# find all files ending with .envsubst and feed them to envsubst command,
# overwriting the file without that extension in the same path.
# note: ArrayList is defined because $ArrayList is used in the zone file,
# getting picked up and replaced with nothing by envsubst. defining the
# "variable" we replace it with its exact string again.
ArrayList='$ArrayList' find "${WORKDIR}" -type f -a -name '*.envsubst' -exec sh -c 'echo "${1} > ${1%.envsubst}"; envsubst < "${1}" > "${1%.envsubst}"' _ {} \;

echo "done."


This comes in handy in e.g. in the zone file:

Code: Select all

  <databaseManager active="true">
    <driverName>org.postgresql.Driver</driverName>
    <connectionString>jdbc:postgresql://${SFS2X_FF_DB_HOST}:${SFS2X_FF_DB_PORT}/${SFS2X_FF_DB_NAME}</connectionString>
    <userName>${SFS2X_FF_DB_USERNAME}</userName>
    <password>${SFS2X_FF_DB_PASSWORD}</password>
    ...

...or the server config:

Code: Select all

      <adminUser>
        <login>${SFS2X_ADMIN_USERNAME}</login>
        <password>${SFS2X_ADMIN_PASSWORD}</password>
        ...

This way, the image is usable both in local development (using docker compose) and in production.

Sorry this became so long. I hope you can extract some useful information from the above.

Cheers,
Luke
Luke64
Posts: 21
Joined: 08 Nov 2020, 23:15

Re: Using docker for production server

Postby Luke64 » 30 Sep 2022, 08:46

luxmobile wrote:This sounds like exactly what I want to do, using SFS2X in production on AWS ECS services. Might even use HAProxy on it...

How did you go about doing the licenses? Each instance needs it's own license to start, was there something you used to track and assign them?

Currently I don't as we're still in development (launch in about 1 month) but I hope to be able to assign the licenses to the pods/containers through environment variables.
Sorry for coming back to you so late, did you eventually implement it? I'd like to know your findings going beyond what I wrote above :)

Cheers
Luke

Return to “SFS2X Questions”

Who is online

Users browsing this forum: No registered users and 52 guests