From 487fcd4cea6d6f2d5dc89b1fe8645c9f9d4fda31 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 9 Mar 2023 11:00:52 +0100 Subject: [PATCH 1/5] Only used for traefik --- lib/mrsk/commands/base.rb | 2 +- lib/mrsk/commands/traefik.rb | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/mrsk/commands/base.rb b/lib/mrsk/commands/base.rb index a9815c91..e453dddc 100644 --- a/lib/mrsk/commands/base.rb +++ b/lib/mrsk/commands/base.rb @@ -1,6 +1,6 @@ module Mrsk::Commands class Base - delegate :redact, :argumentize_for_cmd, to: Mrsk::Utils + delegate :redact, to: Mrsk::Utils MAX_LOG_SIZE = "10m" diff --git a/lib/mrsk/commands/traefik.rb b/lib/mrsk/commands/traefik.rb index 34e9c907..22c29b15 100644 --- a/lib/mrsk/commands/traefik.rb +++ b/lib/mrsk/commands/traefik.rb @@ -1,4 +1,6 @@ class Mrsk::Commands::Traefik < Mrsk::Commands::Base + delegate :argumentize_for_cmd, to: Mrsk::Utils + CONTAINER_PORT = 80 def run From 98a14f617310c312a0096ece5e69f7e7bfeb3975 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 9 Mar 2023 11:01:06 +0100 Subject: [PATCH 2/5] Add cmd args for roles --- lib/mrsk/commands/app.rb | 3 ++- lib/mrsk/configuration/role.rb | 10 +++++++++- test/commands/app_test.rb | 9 +++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/lib/mrsk/commands/app.rb b/lib/mrsk/commands/app.rb index 4b1de91a..eecc8233 100644 --- a/lib/mrsk/commands/app.rb +++ b/lib/mrsk/commands/app.rb @@ -11,7 +11,8 @@ class Mrsk::Commands::App < Mrsk::Commands::Base *config.volume_args, *role.label_args, config.absolute_image, - role.cmd + role.cmd, + *role.cmd_args end def start diff --git a/lib/mrsk/configuration/role.rb b/lib/mrsk/configuration/role.rb index 1795649b..a0d7b5c0 100644 --- a/lib/mrsk/configuration/role.rb +++ b/lib/mrsk/configuration/role.rb @@ -1,5 +1,5 @@ class Mrsk::Configuration::Role - delegate :argumentize, :argumentize_env_with_secrets, to: Mrsk::Utils + delegate :argumentize, :argumentize_env_with_secrets, :argumentize_for_cmd, to: Mrsk::Utils attr_accessor :name @@ -35,6 +35,14 @@ class Mrsk::Configuration::Role specializations["cmd"] end + def cmd_args + if args = specializations["args"] + argumentize_for_cmd args + else + [] + end + end + def running_traefik? name.web? || specializations["traefik"] end diff --git a/test/commands/app_test.rb b/test/commands/app_test.rb index a62ab80c..8113dac0 100644 --- a/test/commands/app_test.rb +++ b/test/commands/app_test.rb @@ -34,6 +34,15 @@ class CommandsAppTest < ActiveSupport::TestCase @app.run.join(" ") end + test "run with cmd args" do + @config[:servers] = { "web" => [ "1.1.1.1" ], "jobs" => { "hosts" => [ "1.1.1.2" ], "cmd" => "bin/jobs", "args" => { "mount" => "somewhere" } } } + @app = Mrsk::Commands::App.new Mrsk::Configuration.new(@config).tap { |c| c.version = "999" } + + assert_equal \ + "docker run --detach --restart unless-stopped --log-opt max-size=10m --name app-999 -e RAILS_MASTER_KEY=\"456\" --label service=\"app\" --label role=\"jobs\" dhh/app:999 bin/jobs --mount \"somewhere\"", + @app.run(role: :jobs).join(" ") + end + test "start" do assert_equal \ "docker start app-999", From d3f07d6313d861ad74ba32402df5be6d39c3e520 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 9 Mar 2023 11:09:19 +0100 Subject: [PATCH 3/5] Allow custom options per role --- lib/mrsk/commands/app.rb | 4 ++-- lib/mrsk/commands/traefik.rb | 8 ++++---- lib/mrsk/configuration/role.rb | 8 ++++---- lib/mrsk/utils.rb | 4 ++-- test/commands/app_test.rb | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/mrsk/commands/app.rb b/lib/mrsk/commands/app.rb index eecc8233..72c8c4dd 100644 --- a/lib/mrsk/commands/app.rb +++ b/lib/mrsk/commands/app.rb @@ -10,9 +10,9 @@ class Mrsk::Commands::App < Mrsk::Commands::Base *role.env_args, *config.volume_args, *role.label_args, + *role.option_args, config.absolute_image, - role.cmd, - *role.cmd_args + role.cmd end def start diff --git a/lib/mrsk/commands/traefik.rb b/lib/mrsk/commands/traefik.rb index 22c29b15..ee22e64b 100644 --- a/lib/mrsk/commands/traefik.rb +++ b/lib/mrsk/commands/traefik.rb @@ -1,5 +1,5 @@ class Mrsk::Commands::Traefik < Mrsk::Commands::Base - delegate :argumentize_for_cmd, to: Mrsk::Utils + delegate :optionize, to: Mrsk::Utils CONTAINER_PORT = 80 @@ -13,7 +13,7 @@ class Mrsk::Commands::Traefik < Mrsk::Commands::Base "traefik", "--providers.docker", "--log.level=DEBUG", - *cmd_args + *cmd_option_args end def start @@ -54,9 +54,9 @@ class Mrsk::Commands::Traefik < Mrsk::Commands::Base end private - def cmd_args + def cmd_option_args if args = config.raw_config.dig(:traefik, "args") - argumentize_for_cmd args + optionize args else [] end diff --git a/lib/mrsk/configuration/role.rb b/lib/mrsk/configuration/role.rb index a0d7b5c0..69d84be3 100644 --- a/lib/mrsk/configuration/role.rb +++ b/lib/mrsk/configuration/role.rb @@ -1,5 +1,5 @@ class Mrsk::Configuration::Role - delegate :argumentize, :argumentize_env_with_secrets, :argumentize_for_cmd, to: Mrsk::Utils + delegate :argumentize, :argumentize_env_with_secrets, :optionize, to: Mrsk::Utils attr_accessor :name @@ -35,9 +35,9 @@ class Mrsk::Configuration::Role specializations["cmd"] end - def cmd_args - if args = specializations["args"] - argumentize_for_cmd args + def option_args + if args = specializations["options"] + optionize args else [] end diff --git a/lib/mrsk/utils.rb b/lib/mrsk/utils.rb index 62a193ea..b9b24596 100644 --- a/lib/mrsk/utils.rb +++ b/lib/mrsk/utils.rb @@ -23,8 +23,8 @@ module Mrsk::Utils end end - # Returns a list of shell-dashed arguments to be used to start a command. - def argumentize_for_cmd(args) + # Returns a list of shell-dashed option arguments. + def optionize(args) args.collect { |(key, value)| [ "--#{key}", escape_shell_value(value) ] }.flatten end diff --git a/test/commands/app_test.rb b/test/commands/app_test.rb index 8113dac0..c392e5e7 100644 --- a/test/commands/app_test.rb +++ b/test/commands/app_test.rb @@ -34,12 +34,12 @@ class CommandsAppTest < ActiveSupport::TestCase @app.run.join(" ") end - test "run with cmd args" do - @config[:servers] = { "web" => [ "1.1.1.1" ], "jobs" => { "hosts" => [ "1.1.1.2" ], "cmd" => "bin/jobs", "args" => { "mount" => "somewhere" } } } + test "run with custom options" do + @config[:servers] = { "web" => [ "1.1.1.1" ], "jobs" => { "hosts" => [ "1.1.1.2" ], "cmd" => "bin/jobs", "options" => { "mount" => "somewhere" } } } @app = Mrsk::Commands::App.new Mrsk::Configuration.new(@config).tap { |c| c.version = "999" } assert_equal \ - "docker run --detach --restart unless-stopped --log-opt max-size=10m --name app-999 -e RAILS_MASTER_KEY=\"456\" --label service=\"app\" --label role=\"jobs\" dhh/app:999 bin/jobs --mount \"somewhere\"", + "docker run --detach --restart unless-stopped --log-opt max-size=10m --name app-999 -e RAILS_MASTER_KEY=\"456\" --label service=\"app\" --label role=\"jobs\" --mount \"somewhere\" dhh/app:999 bin/jobs", @app.run(role: :jobs).join(" ") end From 1f784176b7bbfed4891f6420c6c6240ab6950911 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 9 Mar 2023 11:17:28 +0100 Subject: [PATCH 4/5] Allow value-less options with true --- lib/mrsk/utils.rb | 4 ++-- test/commands/app_test.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/mrsk/utils.rb b/lib/mrsk/utils.rb index b9b24596..d8860f1a 100644 --- a/lib/mrsk/utils.rb +++ b/lib/mrsk/utils.rb @@ -23,9 +23,9 @@ module Mrsk::Utils end end - # Returns a list of shell-dashed option arguments. + # Returns a list of shell-dashed option arguments. If the value is true, it's treated like a value-less option. def optionize(args) - args.collect { |(key, value)| [ "--#{key}", escape_shell_value(value) ] }.flatten + args.collect { |(key, value)| [ "--#{key}", value == true ? nil : escape_shell_value(value) ] }.flatten.compact end # Copied from SSHKit::Backend::Abstract#redact to be available inside Commands classes diff --git a/test/commands/app_test.rb b/test/commands/app_test.rb index c392e5e7..da436bcb 100644 --- a/test/commands/app_test.rb +++ b/test/commands/app_test.rb @@ -35,11 +35,11 @@ class CommandsAppTest < ActiveSupport::TestCase end test "run with custom options" do - @config[:servers] = { "web" => [ "1.1.1.1" ], "jobs" => { "hosts" => [ "1.1.1.2" ], "cmd" => "bin/jobs", "options" => { "mount" => "somewhere" } } } + @config[:servers] = { "web" => [ "1.1.1.1" ], "jobs" => { "hosts" => [ "1.1.1.2" ], "cmd" => "bin/jobs", "options" => { "mount" => "somewhere", "cap-add" => true } } } @app = Mrsk::Commands::App.new Mrsk::Configuration.new(@config).tap { |c| c.version = "999" } assert_equal \ - "docker run --detach --restart unless-stopped --log-opt max-size=10m --name app-999 -e RAILS_MASTER_KEY=\"456\" --label service=\"app\" --label role=\"jobs\" --mount \"somewhere\" dhh/app:999 bin/jobs", + "docker run --detach --restart unless-stopped --log-opt max-size=10m --name app-999 -e RAILS_MASTER_KEY=\"456\" --label service=\"app\" --label role=\"jobs\" --mount \"somewhere\" --cap-add dhh/app:999 bin/jobs", @app.run(role: :jobs).join(" ") end From 64cc081f109249318069ebae90937a2577337d97 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 9 Mar 2023 11:20:28 +0100 Subject: [PATCH 5/5] Explain container options --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index 286a0b6e..f54dc3e4 100644 --- a/README.md +++ b/README.md @@ -282,6 +282,27 @@ servers: my-label: "50" ``` +### Using container options + +You can specialize the options used to start containers using the `options` definitions: + +```yaml +servers: + web: + - 192.168.0.1 + - 192.168.0.2 + job: + hosts: + - 192.168.0.3 + - 192.168.0.4 + cmd: bin/jobs + options: + cap-add: true + cpu-count: 4 +``` + +That'll start the job containers with `docker run ... --cap-add --cpu-count 4 ...`. + ### Using remote builder for native multi-arch If you're developing on ARM64 (like Apple Silicon), but you want to deploy on AMD64 (x86 64-bit), you can use multi-architecture images. By default, MRSK will setup a local buildx configuration that does this through QEMU emulation. But this can be quite slow, especially on the first build.