Corrected docker/swarm discovery from previous refactoring (#446)
This commit is contained in:
@@ -0,0 +1,35 @@
|
|||||||
|
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||||
|
// README at: https://github.com/devcontainers/templates/tree/main/src/go
|
||||||
|
{
|
||||||
|
"name": "Go",
|
||||||
|
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||||
|
"image": "golang:1.24-bookworm",
|
||||||
|
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||||
|
"features": {
|
||||||
|
// For in-docker discovery testing
|
||||||
|
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {}
|
||||||
|
},
|
||||||
|
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||||
|
"forwardPorts": [
|
||||||
|
25565
|
||||||
|
],
|
||||||
|
|
||||||
|
containerEnv: {
|
||||||
|
"GOROOT": "/usr/local/go"
|
||||||
|
},
|
||||||
|
|
||||||
|
// Configure tool-specific properties.
|
||||||
|
"customizations": {
|
||||||
|
"jetbrains": {
|
||||||
|
"backend": "IntelliJ",
|
||||||
|
"plugins": [
|
||||||
|
"org.jetbrains.plugins.go"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"golang.go"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
## Developing Docker discovery on non-Linux
|
||||||
|
|
||||||
|
This works best with the included devcontaner setup, which includes attaching the host's docker socket to the dev container at `/var/run/docker.sock`.
|
||||||
|
|
||||||
|
On Windows, can create the devcontainer using:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
@@ -103,8 +103,6 @@ The [multi-architecture image published at Docker Hub](https://hub.docker.com/re
|
|||||||
The diagram below shows how this `docker-compose.yml` configures two Minecraft server services named `vanilla` and `forge`, which also become the internal network aliases. _Notice those services don't need their ports exposed since the internal networking allows for the inter-container access._
|
The diagram below shows how this `docker-compose.yml` configures two Minecraft server services named `vanilla` and `forge`, which also become the internal network aliases. _Notice those services don't need their ports exposed since the internal networking allows for the inter-container access._
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
version: "3.8"
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
vanilla:
|
vanilla:
|
||||||
image: itzg/minecraft-server
|
image: itzg/minecraft-server
|
||||||
@@ -141,20 +139,21 @@ To test out this example, add these two entries to my "hosts" file:
|
|||||||
|
|
||||||
### Using Docker auto-discovery
|
### Using Docker auto-discovery
|
||||||
|
|
||||||
When running `mc-router` in a Docker environment you can pass the `--in-docker` or `--in-docker-swarm`
|
When running `mc-router` in a Docker environment you can pass the `--in-docker` or `--in-docker-swarm` command-line argument or set the environment variables `IN_DOCKER` or `IN_DOCKER_SWARM` to "true". With that, it will poll the Docker API periodically to find all the running containers/services for Minecraft instances. To enable discovery, you have to set the `mc-router.host` label on the container.
|
||||||
command-line argument and it will poll the Docker API periodically to find all the running
|
|
||||||
containers/services for Minecraft instances. To enable discovery you have to set the `mc-router.host`
|
|
||||||
label on the container. These are the labels scanned:
|
|
||||||
|
|
||||||
- `mc-router.host`: Used to configure the hostname the Minecraft clients would use to
|
When using in Docker, make sure to volume mount the Docker socket into the container, such as
|
||||||
connect to the server. The container/service endpoint will be used as the routed backend. You can
|
|
||||||
use more than one hostname by splitting it with a comma.
|
```yaml
|
||||||
- `mc-router.port`: This value must be set to the port the Minecraft server is listening on.
|
volumes:
|
||||||
The default value is 25565.
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
- `mc-router.default`: Set this to a truthy value to make this server the default backend.
|
```
|
||||||
Please note that `mc-router.host` is still required to be set.
|
|
||||||
- `mc-router.network`: Specify the network you are using for the router if multiple are
|
These are the labels scanned:
|
||||||
present in the container/service. You can either use the network ID, it's full name or an alias.
|
|
||||||
|
- `mc-router.host`: Used to configure the hostname the Minecraft clients would use to connect to the server. The container/service endpoint will be used as the routed backend. You can use more than one hostname by splitting it with a comma.
|
||||||
|
- `mc-router.port`: This value must be set to the port the Minecraft server is listening on. The default value is 25565.
|
||||||
|
- `mc-router.default`: Set this to a truthy value to make this server the default backend. Please note that `mc-router.host` is still required to be set.
|
||||||
|
- `mc-router.network`: Specify the network you are using for the router if multiple are present in the container/service. You can either use the network ID, it's full name or an alias.
|
||||||
|
|
||||||
#### Example Docker deployment
|
#### Example Docker deployment
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ func showVersion() {
|
|||||||
type CliConfig struct {
|
type CliConfig struct {
|
||||||
Version bool `usage:"Output version and exit"`
|
Version bool `usage:"Output version and exit"`
|
||||||
Debug bool `usage:"Enable debug logs"`
|
Debug bool `usage:"Enable debug logs"`
|
||||||
|
Trace bool `usage:"Enable trace logs"`
|
||||||
|
|
||||||
ServerConfig server.Config `flatten:"true"`
|
ServerConfig server.Config `flatten:"true"`
|
||||||
}
|
}
|
||||||
@@ -40,7 +41,10 @@ func main() {
|
|||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cliConfig.Debug {
|
if cliConfig.Trace {
|
||||||
|
logrus.SetLevel(logrus.TraceLevel)
|
||||||
|
logrus.Trace("Trace logs enabled")
|
||||||
|
} else if cliConfig.Debug {
|
||||||
logrus.SetLevel(logrus.DebugLevel)
|
logrus.SetLevel(logrus.DebugLevel)
|
||||||
logrus.Debug("Debug logs enabled")
|
logrus.Debug("Debug logs enabled")
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 175 KiB |
@@ -0,0 +1,23 @@
|
|||||||
|
services:
|
||||||
|
router:
|
||||||
|
image: itzg/mc-router
|
||||||
|
environment:
|
||||||
|
IN_DOCKER: true
|
||||||
|
ports:
|
||||||
|
- "25565:25565"
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
vanilla:
|
||||||
|
image: itzg/minecraft-server
|
||||||
|
environment:
|
||||||
|
EULA: "TRUE"
|
||||||
|
labels:
|
||||||
|
mc-router.host: "vanilla.example.com"
|
||||||
|
paper:
|
||||||
|
image: itzg/minecraft-server
|
||||||
|
environment:
|
||||||
|
EULA: "TRUE"
|
||||||
|
TYPE: PAPER
|
||||||
|
labels:
|
||||||
|
mc-router.host: "paper.example.com"
|
||||||
|
|
||||||
+5
-13
@@ -15,8 +15,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type IDockerWatcher interface {
|
type IDockerWatcher interface {
|
||||||
Start(socket string, timeoutSeconds int, refreshIntervalSeconds int, autoScaleUp bool, autoScaleDown bool) error
|
Start(ctx context.Context, socket string, timeoutSeconds int, refreshIntervalSeconds int, autoScaleUp bool, autoScaleDown bool) error
|
||||||
Stop()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -34,7 +33,6 @@ type dockerWatcherImpl struct {
|
|||||||
autoScaleUp bool
|
autoScaleUp bool
|
||||||
autoScaleDown bool
|
autoScaleDown bool
|
||||||
client *client.Client
|
client *client.Client
|
||||||
contextCancel context.CancelFunc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *dockerWatcherImpl) makeWakerFunc(_ *routableContainer) ScalerFunc {
|
func (w *dockerWatcherImpl) makeWakerFunc(_ *routableContainer) ScalerFunc {
|
||||||
@@ -57,7 +55,7 @@ func (w *dockerWatcherImpl) makeSleeperFunc(_ *routableContainer) ScalerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *dockerWatcherImpl) Start(socket string, timeoutSeconds int, refreshIntervalSeconds int, autoScaleUp bool, autoScaleDown bool) error {
|
func (w *dockerWatcherImpl) Start(ctx context.Context, socket string, timeoutSeconds int, refreshIntervalSeconds int, autoScaleUp bool, autoScaleDown bool) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
w.autoScaleUp = autoScaleUp
|
w.autoScaleUp = autoScaleUp
|
||||||
@@ -83,9 +81,7 @@ func (w *dockerWatcherImpl) Start(socket string, timeoutSeconds int, refreshInte
|
|||||||
ticker := time.NewTicker(refreshInterval)
|
ticker := time.NewTicker(refreshInterval)
|
||||||
containerMap := map[string]*routableContainer{}
|
containerMap := map[string]*routableContainer{}
|
||||||
|
|
||||||
var ctx context.Context
|
logrus.Trace("Performing initial listing of Docker containers")
|
||||||
ctx, w.contextCancel = context.WithCancel(context.Background())
|
|
||||||
|
|
||||||
initialContainers, err := w.listContainers(ctx)
|
initialContainers, err := w.listContainers(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -104,6 +100,7 @@ func (w *dockerWatcherImpl) Start(socket string, timeoutSeconds int, refreshInte
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
|
logrus.Trace("Listing Docker containers")
|
||||||
containers, err := w.listContainers(ctx)
|
containers, err := w.listContainers(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).Error("Docker failed to list containers")
|
logrus.WithError(err).Error("Docker failed to list containers")
|
||||||
@@ -145,6 +142,7 @@ func (w *dockerWatcherImpl) Start(socket string, timeoutSeconds int, refreshInte
|
|||||||
}
|
}
|
||||||
|
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
logrus.Debug("Stopping Docker monitoring")
|
||||||
ticker.Stop()
|
ticker.Stop()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -303,12 +301,6 @@ func (w *dockerWatcherImpl) parseContainerData(container *dockertypes.Container)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *dockerWatcherImpl) Stop() {
|
|
||||||
if w.contextCancel != nil {
|
|
||||||
w.contextCancel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type routableContainer struct {
|
type routableContainer struct {
|
||||||
externalContainerName string
|
externalContainerName string
|
||||||
containerEndpoint string
|
containerEndpoint string
|
||||||
|
|||||||
+3
-12
@@ -26,7 +26,6 @@ type dockerSwarmWatcherImpl struct {
|
|||||||
autoScaleUp bool
|
autoScaleUp bool
|
||||||
autoScaleDown bool
|
autoScaleDown bool
|
||||||
client *client.Client
|
client *client.Client
|
||||||
contextCancel context.CancelFunc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *dockerSwarmWatcherImpl) makeWakerFunc(_ *routableService) ScalerFunc {
|
func (w *dockerSwarmWatcherImpl) makeWakerFunc(_ *routableService) ScalerFunc {
|
||||||
@@ -49,7 +48,7 @@ func (w *dockerSwarmWatcherImpl) makeSleeperFunc(_ *routableService) ScalerFunc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *dockerSwarmWatcherImpl) Start(socket string, timeoutSeconds int, refreshIntervalSeconds int, autoScaleUp bool, autoScaleDown bool) error {
|
func (w *dockerSwarmWatcherImpl) Start(ctx context.Context, socket string, timeoutSeconds int, refreshIntervalSeconds int, autoScaleUp bool, autoScaleDown bool) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
w.autoScaleUp = autoScaleUp
|
w.autoScaleUp = autoScaleUp
|
||||||
@@ -75,9 +74,7 @@ func (w *dockerSwarmWatcherImpl) Start(socket string, timeoutSeconds int, refres
|
|||||||
ticker := time.NewTicker(refreshInterval)
|
ticker := time.NewTicker(refreshInterval)
|
||||||
serviceMap := map[string]*routableService{}
|
serviceMap := map[string]*routableService{}
|
||||||
|
|
||||||
var ctx context.Context
|
logrus.Trace("Performing initial listing of Docker containers")
|
||||||
ctx, w.contextCancel = context.WithCancel(context.Background())
|
|
||||||
|
|
||||||
initialServices, err := w.listServices(ctx)
|
initialServices, err := w.listServices(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -99,7 +96,7 @@ func (w *dockerSwarmWatcherImpl) Start(socket string, timeoutSeconds int, refres
|
|||||||
services, err := w.listServices(ctx)
|
services, err := w.listServices(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).Error("Docker failed to list services")
|
logrus.WithError(err).Error("Docker failed to list services")
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
visited := map[string]struct{}{}
|
visited := map[string]struct{}{}
|
||||||
@@ -332,9 +329,3 @@ func (w *dockerSwarmWatcherImpl) parseServiceData(service *swarm.Service, networ
|
|||||||
ok = true
|
ok = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *dockerSwarmWatcherImpl) Stop() {
|
|
||||||
if w.contextCancel != nil {
|
|
||||||
w.contextCancel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+2
-6
@@ -142,21 +142,17 @@ func NewServer(ctx context.Context, config *Config) (*Server, error) {
|
|||||||
|
|
||||||
// TODO convert to RouteFinder
|
// TODO convert to RouteFinder
|
||||||
if config.InDocker {
|
if config.InDocker {
|
||||||
err = DockerWatcher.Start(config.DockerSocket, config.DockerTimeout, config.DockerRefreshInterval, config.AutoScale.Up, config.AutoScale.Down)
|
err = DockerWatcher.Start(ctx, config.DockerSocket, config.DockerTimeout, config.DockerRefreshInterval, config.AutoScale.Up, config.AutoScale.Down)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not start docker integration: %w", err)
|
return nil, fmt.Errorf("could not start docker integration: %w", err)
|
||||||
} else {
|
|
||||||
defer DockerWatcher.Stop()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO convert to RouteFinder
|
// TODO convert to RouteFinder
|
||||||
if config.InDockerSwarm {
|
if config.InDockerSwarm {
|
||||||
err = DockerSwarmWatcher.Start(config.DockerSocket, config.DockerTimeout, config.DockerRefreshInterval, config.AutoScale.Up, config.AutoScale.Down)
|
err = DockerSwarmWatcher.Start(ctx, config.DockerSocket, config.DockerTimeout, config.DockerRefreshInterval, config.AutoScale.Up, config.AutoScale.Down)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not start docker swarm integration: %w", err)
|
return nil, fmt.Errorf("could not start docker swarm integration: %w", err)
|
||||||
} else {
|
|
||||||
defer DockerSwarmWatcher.Stop()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user