Question to Teamspeak 3 with Docker and MariaDB

Hey together,

I have a new root server which will run most systems within docker containers. So i searched for a TS3 docker image and found this: Docker

Nice to see is, how to add database support for mariadb but the bad point is, how is mariadb installed? In the TS3 container directly?

If so, this is not, what I want, even if it’s nice to have a TS3 Docker image.

What I want is a MariaDB Galera Cluster with at last 3-4 MariaDB Instances to have access to the stored data, even if one MDB-Node gets killed or dies.

So is there any documentation/help out there, how to do the setup to fit my galera cluster instance?

Any help is welcome :slight_smile:

Cheers
Chaos234

I don’t know anything about Galera, but as long as you have a MariaDB endpoint you can access, set TS3SERVER_DB_HOST/TS3SERVER_DB_PORT (etc) as environment variables when you run the TeamSpeak docker image to point to it and it should work

Well, if the Galera Cluster is setuped correctly, I would have smth. like node1, node2, node3, …
So the TS3 Docker image should be able to “jump” to one of the active nodes if one node dies.

All nodes are in total the same mysql server only replicated n-times so if one node goes down the db
itself is still available until all nodes are down.

Right, in that case you’d want a load balancer/haproxy/etc in front of your Galera to act as a central endpoint and provide failover.

Ok, that makes sense. I hope that GitHub - traefik/traefik: The Cloud Native Application Proxy will be able to deliver, what is needed because this is, what we are using now, to mange all the routing ^^

Ok, my DB is runing now incl. PMA (docker).

But now I am confused with the TS3 Docker image:

Why are there only three ports for the container listed?
It is missing, how to open multiple ports for multiple virtual servers because when I open :9987,
:9000 isn’t opend. Is there an option to open a port range?

Also Query and FTP are opened, but what about tsdns and how to start it or is it started automaticly?
Becuase I am in need of TSDNS it must work or has SRV a special option to support ports? Because I have only one default domain which goes to 9987 (defualt ones, if no port is specified (TSDNS)) or to url:PORT which is also handled by TSDNS and I did not found anything to solve this with SRV.

Then I am unsure but outgoing to accounting/weblist/… shouldn’t be working as long as the ports are not opend or am I wrong?

Means in fact, that the documentation on the official TS3 Docker Image is missing very important information, which I need as fast as possible, thanks :slight_smile:

From memory, no - but there’s a lot of options with docker, and if you want something custom it’s probably better to think of the Dockerfile as a starting point and fork your own. There are various options out there but we don’t officially support them.

Depends on your docker/firewall setup but generally outgoing traffic is fine.

1 Like

I don’t see how this could happen. I use docker-compose for my container management and when I want to open another port it’s nothing more than to add a line. (It should not be hard to do so with plain docker too, I guess.)
This is my config:

  ts3server:
    network_mode: bridge # this is default (no need to specify this)
    ports:
      - "10011:10011"
      - "30032:30033"
      - "9987:9987/udp"
      - "2010:2010/udp"
      - "41144:41144"
      - "2008:2008"
      - "9988:9988/udp" # just add any extra port needed
    environment:
      TS3SERVER_LICENSE: "accept"
    restart: unless-stopped
    image: teamspeak
    tty: true
    stdin_open: true
    container_name: "teamspeak"

And I just read that you can actually publish a port range like this:

 -p 9980-9999:9980-9999/udp

or for docker-compose

 - "9980-9999:9980-9999/udp" 
2 Likes

Well, I looked in the github repro and there is one important thing missing, as long as SRV can’t act like TSDNS it does.

In the official repro, there is no start for TSDNS service but I assume that’s delivered. So there are only two solutions:

  1. Add the missing lines, with an optional ENV like TSDNS_ENABLE: 1 (or true) and TSDNS_CONF_FILE (for mounted volumes, when you have an external config file already) and add the missing starting command for TSDNS Service and expose the correct port.

  2. How must my command be in the docer-compose.yml, to start TSDNS manually? I mean smth. like that:

    command: ['mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci']

Hello Gamer92000,

just one question. Why did you run the network_mode in bridged mode?

Per default, docker runs an overlay gw_bridge network for network isolation.

You can take a look at my compose file, that’s a full running stack.

version: '3.1'
services:
  teamspeak:
    image: teamspeak:3.12.1
    restart: always
    ports:
      - 9987:9987/udp
      - 10011:10011
      - 30033:30033
    volumes:
      - /srv/docker/teamspeak/server:/var/ts3server
    environment:
      TS3SERVER_DB_PLUGIN: ts3db_mariadb
      TS3SERVER_DB_SQLCREATEPATH: create_mariadb
      TS3SERVER_DB_HOST: db
      TS3SERVER_DB_USER: ts3server
      TS3SERVER_DB_PASSWORD: xxxxx
      TS3SERVER_DB_NAME: teamspeak
      TS3SERVER_DB_WAITUNTILREADY: 30
      TS3SERVER_LICENSE: accept
      TS3SERVER_SERVERADMIN_PASSWORD: xxxxxxx
  db:
    image: mariadb
    restart: always
    environment:
      MYSQL_USER: ts3server
      MYSQL_PASS: xxxxxx
      MYSQL_DATABASE: teamspeak
    volumes:
      - /srv/docker/teamspeak/database:/var/lib/mysql

To use Traefik you can use simple labels for TCP/UDP routings.

docker docs: bridge : The default network driver. If you don’t specify a driver, this is the type of network you are creating.
Networking overview | Docker Documentation

As the comment says it is the default one and there is no need to specify this. It is effectively the same as not specifying it. It is just a relic from using host mode for some tests.

Ah yes… maybe I’ve been confused, at this late time, with host based networks… sorry

And how would a setup look like? Would be nice to see an example :slight_smile:

Depends on how your traefik is set up.

I have a running container in my swarm environment, where I can put some labels on the service.

It looks like:

services:
  teamspeak:
    ...
    deploy:
      labels:
        traefik.enable: "true"
        traefik.tcp.routers.ts3-test.rule: "Host(`ts.example.de`)"
        traefik.tcp.routers.ts3-test.entrypoints: "udp9987"
        traefik.tcp.services.ts3-test-service.loadbalancer.server.port: "9987"

You must create an entrypoint tcp_9987 in your traefik.toml like

[entryPoints] 
  [entryPoints.udp9987] 
    address = ":9987/udp"

My docker-compose.yml looks like this (it isn’t only me, who administrates the server and since we want later to deplay most parts over gitlab CI/CD, the following file is only for non-productive environment):

version: '3.3'

services:
  traefik:
image: traefik:latest
restart: always
container_name: traefik
ports:
  - "80:80" # <== http
  - "8080:8080" # <== :8080 is where the dashboard runs on
  - "443:443" # <== https
  #- "3306:3306" # <== mariadb
command:
#### These are the CLI commands that will configure Traefik and tell it how to work! ####
  ## API Settings - https://docs.traefik.io/operations/api/, endpoints - https://docs.traefik.io/operations/api/#endpoints ##
  - --api.insecure=true # <== Enabling insecure api, NOT RECOMMENDED FOR PRODUCTION
  - --api.dashboard=true # <== Enabling the dashboard to view services, middlewares, routers, etc...
  - --api.debug=true # <== Enabling additional endpoints for debugging and profiling
  ## Log Settings (options: ERROR, DEBUG, PANIC, FATAL, WARN, INFO) - https://docs.traefik.io/observability/logs/ ##
  - --log.level=DEBUG # <== Setting the level of the logs from traefik
  ## Provider Settings - https://docs.traefik.io/providers/docker/#provider-configuration ##
  - --providers.docker=true # <== Enabling docker as the provider for traefik
  - --providers.docker.exposedbydefault=true # <== Don't expose every container to traefik, only expose enabled ones
  - --providers.file.filename=/dynamic.yaml # <== Referring to a dynamic configuration file
  - --providers.docker.network=traefik # <== Operate on the docker network named traefik
  ## Entrypoints Settings - https://docs.traefik.io/routing/entrypoints/#configuration ##
  - --entrypoints.http.address=:80 # <== Defining an entrypoint for http port :80 named web
  - --entrypoints.https.address=:443 # <== Defining an entrypoint for https on port :443 named web-secured
  #- --entrypoints.mdb.address=:3306 # <== Defining an entrypoint for mdb on port :3306 named mdb
  ## Certificate Settings (Let's Encrypt) -  https://docs.traefik.io/https/acme/#configuration-examples ##
  - --certificatesresolvers.mytlschallenge.acme.tlschallenge=true # <== Enable TLS-ALPN-01 to generate and renew ACME certs
  - --certificatesresolvers.mytlschallenge.acme.email=xxx # <== Setting email for certs
  - --certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json # <== Defining acme file to store cert information
volumes:
  - ./letsencrypt:/letsencrypt # <== Volume for certs (TLS)
  - /var/run/docker.sock:/var/run/docker.sock # <== Volume for docker admin
  - ./dynamic.yaml:/dynamic.yaml # <== Volume for dynamic conf file, **ref: line 27
networks:
  - traefik # <== Placing traefik on the network named web, to access containers on this network
labels:
#### Labels define the behavior and rules of the traefik proxy for this container ####
  - "traefik.enable=true" # <== Enable traefik on itself to view dashboard and assign subdomain to view it
  - "traefik.http.routers.api.rule=Host(`xxx`)" # <== Setting the domain for the dashboard
  - "traefik.http.routers.api.service=api@internal" # <== Enabling the api to be a service to access

  gitlab:
image: gitlab/gitlab-ee:latest
container_name: gitlab
expose:
  - 80
  - 443
ports:
  - 22:22
  - 5555:5555
restart: always
volumes:
  - /xxx/config:/etc/gitlab
  - /xxx/logs:/var/log/gitlab
  - /xxx/data:/var/opt/gitlab
environment:
  - GITLAB_OMNIBUS_CONFIG="external_url 'xxx';"
labels:
  - traefik.enable=true
  - traefik.port=80
  - traefik.http.routers.gitlab.rule=Host(`xxxx`)
  - traefik.http.routers.gitlab.entryPoints=http
  - traefik.http.routers.gitlab.middlewares=redirect@file
  - traefik.http.routers.gitlabs.rule=Host(`xxxx`)
  - traefik.http.routers.gitlabs.entrypoints=https
  - traefik.http.routers.gitlabs.tls.certresolver=mytlschallenge
  - traefik.http.services.gitlab.loadbalancer.server.port=80
networks:
  - traefik

### MariaDB (für Datenbank)
  mdb:
image: mariadb:10.4
container_name: mariadb
restart: always
volumes:
  - /xxx/files:/var/lib/mysql
  - /xxx/my.cnf:/etc/mysql/my.cnf
  - /xxx/xxx:/run/secrets/xxx:ro
environment:
  MYSQL_ROOT_PASSWORD_FILE: /run/secrets/xxx
#labels:
  #- traefik.enable=true
  #- traefik.port=3360
  #- traefik.mdb.services.mdb.loadbalancer.server.port=3306
networks:
  - traefik
command: ['mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci']

### PMA
  pma:
image: phpmyadmin/phpmyadmin:latest
container_name: pma
depends_on:
  - mdb
expose:
  - 80
  - 443
restart: always
environment:
  #- PMA_ARBITRARY=1
  - PMA_HOST=mdb
  - PMA_UPLOAD_MAX_FILESIZE=1G
  - PMA_MAX_INPUT_VARS=1G
labels:
  - traefik.enable=true
  - traefik.port=80
  - traefik.http.routers.pma.rule=Host(`xxxx`)
  - traefik.http.routers.pma.entryPoints=http
  - traefik.http.routers.pma.middlewares=redirect@file
  - traefik.http.routers.pmas.rule=Host(`xxxx``)
  - traefik.http.routers.pmas.entrypoints=https
  - traefik.http.routers.pmas.tls.certresolver=mytlschallenge
  - traefik.http.services.pma.loadbalancer.server.port=80
networks:
  - traefik

### Teamspeak 3 - Server
  ts3:
image: teamspeak:latest
restart: unless-stopped
ports:
  - 9000-9100:9000-9100/udp
  - 9987:9987/udp
  - 30033:30033
  - 10011:10011
  - 41144:41144
  - 2010:2010/udp
  - 2008:2008
environment:
  TS3SERVER_DB_PLUGIN: ts3db_mariadb
  TS3SERVER_DB_SQLCREATEPATH: create_mariadb
  TS3SERVER_DB_HOST: mdb
  TS3SERVER_DB_USER: ts3
  TS3SERVER_DB_PASSWORD: /run/secrets/xxxx
  TS3SERVER_DB_NAME: ts3
  TS3SERVER_DB_WAITUNTILREADY: 30
  TS3SERVER_LICENSE: accept
volumes:
  - //xxxx:/run/secrets/xxxx:ro
  - /xxx/ts3server/files:/var/ts3server/files
  - /xxx/ts3server/licensekey.dat:/var/ts3server/licensekey.dat:ro
tty: true
stdin_open: true
depends_on:
  - mdb
networks:
  - traefik

### FTB-Server (Marcel) - 6GB:8GB RAM
  ftb-server-test:
image: itzg/minecraft-server:latest
container_name: ftb-server-test
expose:
  - 8124
ports:
  - 25569:25569
environment:
  - EULA=true
  - VERSION=1.7.10
  - TYPE=CUSTOM
  - CUSTOM_SERVER=/data/ftbserver.jar
  - INIT_MEMORY=6G
  - MAX_MEMORY=8G
  - GUI=false
  - JVM_OPTS=-d64
  - JVM_XX_OPTS=-XX:MaxPermSize=512M -XX:ParallelGCThreads=8 -XX:+UseG1GC -XX:SoftRefLRUPolicyMSPerMB=1 -XX:+UseAdaptiveGCBoundary -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+AggressiveOpts -XX:+UseFastAccessorMethods
  - tty=true
  - stdin=true
volumes:
  - /xxx/ftbmax:/data
restart: always

### Factorio-Server (Marcel - S1) ca. 4GB RAM
  factorio-server-s1:
image: factoriotools/factorio:latest
container_name: factorio-marcel-s1
ports:
  - 34197:34197/udp
  - 27015:27015/tcp
#environment:
 # - ENABLE_SERVER_LOAD_LATEST=false
 # - SAVE_NAME=latest
volumes:
  - /xxx/marcel/s1:/factorio
restart: always

### Factorio-Server (Marcel - S2) ca. 4 GB RAM
  factorio-server-s2:
image: factoriotools/factorio:latest
container_name: factorio-marcel-s2
ports:
  - 34198:34198/udp
  - 27016:27015/tcp
environment:
  - PORT=34198
  - UPDATE_MODS_ON_START=true
 # - ENABLE_SERVER_LOAD_LATEST=false
 # - SAVE_NAME=latest
volumes:
  - /xxx/marcel/s2:/factorio
restart: always


### Vanilla 1.15.2 Server, ggf. Spigot/Forge 2GB:6GB
  vanilla-mc-test:
image: itzg/minecraft-server
container_name: vanilla-mc
ports:
  - 25565:25565
environment:
  - EULA=true
  - VERSION=1.15.2
  - INT_MEMORY=2G
  - MAX_MEMORY=3G
restart: always
volumes:
  - /xxx/mcvanillalatest:/data

### Spigot-Server 2GB:4GB
  spigot-server-test:
image: itzg/minecraft-server
container_name: spigot-server-test
expose:
  - 80
ports:
  - 8123:8123
  - 25566:25565
environment:
  - EULA=true
  - VERSION=1.15.2
  - TYPE=PAPER
  - INIT_MEMORY=2G
  - MAX_MEMORY=4G
  - tty=true
  - stdin=true
restart: always
labels: 
  traefik.enable: "true"
  traefik.port: 80
  traefik.http.routers.spigot-server-test.rule: Host(`xxx`)
  traefik.http.routers.spigot-server-test.entrypoints: http
  traefik.http.routers.spigot-server-test.middlewares: redirect@file
  traefik.http.routers.spigot-server-tests.rule: Host(`xxx`)
  traefik.http.routers.spigot-server-tests.entrypoints: https
  traefik.http.routers.spigot-server-tests.tls.certresolve: mytlschallenge
  traefik.http.services.spigot-server-test.loadbalancer.server.port: 80
volumes:
  - /xxx/1.15.2-spigot/test:/data
networks:
  - traefik

networks:
  traefik:
external:
  name: traefik

First of all, split all your products in seperate Stacks. This is much easier to manage. One big monolitic stacks isn’t the best practice.

Then, create a new entrypoint for the desired ports --entrypoints.xxx.adress and expose the ports --ports.

Well, we don’t using swarm because it is only one root server and all things data related between containers, like pma and mariadb are handled internaly so that I am not in need of exposing port 3306 (for now).

The problem here is docker self, becuase they are not be able to implement a simple “include: service.yml” option, which would make it less dirty and all would smoothly be spletted into sperate files per service.

And after all, it is smth. like a playgorund for both of us, because we are also experimenting with docker before we are going with it into production mode :wink:
If you have any ideas how to clean it up or how we could exclude some services into gitlab over only one repro but with multiple CI/CD support (which is also not possible because it is also not implemented but smth. which should have been there since there first release).

If the mentioned problems weren’t there, it would be easier to solve some problems but for now, we must fallback to a structure like this one because some developers are to lazy to implement such important stuff and no, we are not going to implement any workarrounds on our side, since it’s not our fault/problem that such important functionality is missing.

And sorry for this little rage but since I am also a developer I listen to that, what is wished from the users/community and as long as the wish is possible and fine, it will get implemented. This should be a rule for every developer, if he wants to save his users/community. Hope, that this is understandable :wink:

Hey, you can create overlay networks and connect your services to this network. You don’t have to expose the ports public.

Yeah, there is a simple way for variable nesting in docker-composer, but I think thats not the way you are searching for.

In gitlab-ci you can use multiple stages for each deployment if you want to use a single repository. There are a lot of tools for it.

Would you give me a few examples, what could be done better so that I can choose between them?
We currently have one network, called traefik and from what I now, we are also using overlay 2

Well then, I am going to port my TS now :slight_smile:

Ok, smth is going horrible wrong with your TS 3 Docker Image, because I can set any kind of database it uses all the time it’s own internal IP (172.20.0.8) instead to connect to the DB-Container (172.20.0.6) even when TS3SERVER_DB_HOST=172.20.0.6 or mdb

Maybe smth. is forcing a connection over localhost?

EDIT: FUUUU … Sorry, but who from the developers defaults to localhost when using a passwordfile where the password is stored in instead of hardcoding it?

I’ll open a bugreport just right now, because reading out a file with stored password has to be supported because it is much more safe :wink: