From 4c542930c56ff1ab92fb15c97c7b926c6b9343ce Mon Sep 17 00:00:00 2001 From: Stephen van Beek Date: Wed, 15 Mar 2023 15:37:10 +0000 Subject: [PATCH] Allow arbitrary docker options for traefik --- README.md | 34 +++++++++++----------------------- lib/mrsk/commands/traefik.rb | 21 +++++++-------------- lib/mrsk/utils.rb | 10 ++++++++-- test/commands/traefik_test.rb | 14 +++++++------- 4 files changed, 33 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index da56ed0a..1293e9da 100644 --- a/README.md +++ b/README.md @@ -428,33 +428,24 @@ traefik: ### Configure docker options for traefik -We allow users to override the published ports and bound volumes for the traefik container like so: - -```yaml -traefik: - options: - publish: - - 9000 - - 80 - volumes: - - /tmp/example:/tmp/example -``` - -Note, this fully overrides any defaults. If you choose to do this, then you'll like need to start out by copying the -default configuration: +We allow users to pass additional docker options to the trafik container like ```yaml traefik: options: publish: - - 80 + - 8080:8080 volumes: - - /var/run/docker.sock:/var/run/docker.sock - args: - entrypoints.web.address: ':80' + - /tmp/example.json:/tmp/example.json + memory: 512m ``` -A more complete example including entrypoints would be: +This will start the traefik container with a command like: `docker run ... --volume /tmp/example.json:/tmp/example.json --publish 8080:8080 ` + + +### Configure alternate entrypoints for traefik + +You can configure multiple entrypoints for traefik like so: ```yaml service: myservice @@ -469,10 +460,7 @@ labels: traefik: options: publish: - - 80 - - 9000 - volumes: - - /var/run/docker.sock:/var/run/docker.sock + - 9000:9000 args: entrypoints.web.address: ':80' entrypoints.otherentrypoint.address: ':9000' diff --git a/lib/mrsk/commands/traefik.rb b/lib/mrsk/commands/traefik.rb index f6017004..e09c527b 100644 --- a/lib/mrsk/commands/traefik.rb +++ b/lib/mrsk/commands/traefik.rb @@ -8,8 +8,9 @@ class Mrsk::Commands::Traefik < Mrsk::Commands::Base "--detach", "--restart", "unless-stopped", "--log-opt", "max-size=#{MAX_LOG_SIZE}", - *published_ports, - *volumes, + "--publish", port, + "--volume", "/var/run/docker.sock:/var/run/docker.sock", + *docker_option_args, "traefik", "--providers.docker", "--log.level=DEBUG", @@ -54,19 +55,11 @@ class Mrsk::Commands::Traefik < Mrsk::Commands::Base end private - def published_ports - if ports = config.raw_config.dig(:traefik, "options", "publish") - ports.collect { |value| "--publish #{value}:#{value}" }.compact + def docker_option_args + if args = config.raw_config.dig(:traefik, "options") + optionize args else - ["--publish #{port}"] - end - end - - def volumes - if volumes = config.raw_config.dig(:traefik, "options", "volumes") - volumes.collect { |value| "--volume #{value}" }.compact - else - ["--volume /var/run/docker.sock:/var/run/docker.sock"] + [] end end diff --git a/lib/mrsk/utils.rb b/lib/mrsk/utils.rb index 1e763250..249e2ded 100644 --- a/lib/mrsk/utils.rb +++ b/lib/mrsk/utils.rb @@ -25,15 +25,21 @@ module Mrsk::Utils # Returns a list of shell-dashed option arguments. If the value is true, it's treated like a value-less option. def optionize(args, with: nil) + flattened_args = flatten_args args options = if with - args.collect { |(key, value)| value == true ? "--#{key}" : "--#{key}#{with}#{escape_shell_value(value)}" } + flattened_args.collect { |(key, value)| value == true ? "--#{key}" : "--#{key}#{with}#{escape_shell_value(value)}" } else - args.collect { |(key, value)| [ "--#{key}", value == true ? nil : escape_shell_value(value) ] } + flattened_args.collect { |(key, value)| [ "--#{key}", value == true ? nil : escape_shell_value(value) ] } end options.flatten.compact end + # Flattens a one-to-many structure into an array of two-element arrays each containing a key-value pair + def flatten_args(args) + args.flat_map { |key, value| value.respond_to?('map') ? value.map { |entry| [key, entry] }: [[key, value]] } + end + # Copied from SSHKit::Backend::Abstract#redact to be available inside Commands classes def redact(arg) # Used in execute_command to hide redact() args a user passes in arg.to_s.extend(SSHKit::Redaction) # to_s due to our inability to extend Integer, etc diff --git a/test/commands/traefik_test.rb b/test/commands/traefik_test.rb index 1d0cf17a..f2b67f91 100644 --- a/test/commands/traefik_test.rb +++ b/test/commands/traefik_test.rb @@ -24,9 +24,9 @@ class CommandsTraefikTest < ActiveSupport::TestCase "docker run --name traefik --detach --restart unless-stopped --log-opt max-size=10m --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock traefik --providers.docker --log.level=DEBUG --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"", new_command.run.join(" ") - @config[:traefik]["options"] = {"publish" => [9000, 9001]} + @config[:traefik]["options"] = {"publish" => %w[9000:9000 9001:9001]} assert_equal \ - "docker run --name traefik --detach --restart unless-stopped --log-opt max-size=10m --publish 9000:9000 --publish 9001:9001 --volume /var/run/docker.sock:/var/run/docker.sock traefik --providers.docker --log.level=DEBUG --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"", + "docker run --name traefik --detach --restart unless-stopped --log-opt max-size=10m --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --publish \"9000:9000\" --publish \"9001:9001\" traefik --providers.docker --log.level=DEBUG --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"", new_command.run.join(" ") end @@ -35,20 +35,20 @@ class CommandsTraefikTest < ActiveSupport::TestCase "docker run --name traefik --detach --restart unless-stopped --log-opt max-size=10m --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock traefik --providers.docker --log.level=DEBUG --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"", new_command.run.join(" ") - @config[:traefik]["options"] = {"volumes" => %w[/var/run/docker.sock:/var/run/docker.sock ./letsencrypt/acme.json:/letsencrypt/acme.json] } + @config[:traefik]["options"] = {"volume" => %w[./letsencrypt/acme.json:/letsencrypt/acme.json] } assert_equal \ - "docker run --name traefik --detach --restart unless-stopped --log-opt max-size=10m --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --volume ./letsencrypt/acme.json:/letsencrypt/acme.json traefik --providers.docker --log.level=DEBUG --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"", + "docker run --name traefik --detach --restart unless-stopped --log-opt max-size=10m --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --volume \"./letsencrypt/acme.json:/letsencrypt/acme.json\" traefik --providers.docker --log.level=DEBUG --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"", new_command.run.join(" ") end - test "run with ports and volumes configured" do + test "run with several options configured" do assert_equal \ "docker run --name traefik --detach --restart unless-stopped --log-opt max-size=10m --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock traefik --providers.docker --log.level=DEBUG --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"", new_command.run.join(" ") - @config[:traefik]["options"] = {"volumes" => %w[/var/run/docker.sock:/var/run/docker.sock ./letsencrypt/acme.json:/letsencrypt/acme.json], "publish" => [80, 8080] } + @config[:traefik]["options"] = {"volume" => %w[./letsencrypt/acme.json:/letsencrypt/acme.json], "publish" => %w[8080:8080], "memory" => "512m"} assert_equal \ - "docker run --name traefik --detach --restart unless-stopped --log-opt max-size=10m --publish 80:80 --publish 8080:8080 --volume /var/run/docker.sock:/var/run/docker.sock --volume ./letsencrypt/acme.json:/letsencrypt/acme.json traefik --providers.docker --log.level=DEBUG --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"", + "docker run --name traefik --detach --restart unless-stopped --log-opt max-size=10m --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --volume \"./letsencrypt/acme.json:/letsencrypt/acme.json\" --publish \"8080:8080\" --memory \"512m\" traefik --providers.docker --log.level=DEBUG --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"", new_command.run.join(" ") end