diff --git a/README.md b/README.md index 17b65b28..9e95ab0d 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,33 @@ servers: Traefik will only be installed and run on the servers in the `web` role (and on all servers if no roles are defined). +### Adding custom container labels + +You can specialize the default Traefik rules by setting custom labels on the containers that are being started: + +``` +labels: + traefik.http.routers.hey.rule: 'Host(`app.hey.com`)' +``` + +This allows you to run multiple applications on the same server sharing the same Traefik instance and port. + +The labels can even be applied on a per-role basis: + +```yaml +servers: + web: + - 192.168.0.1 + - 192.168.0.2 + job: + hosts: + - 192.168.0.3 + - 192.168.0.4 + cmd: bin/jobs + labels: + my-custom-label: "50" +``` + ## Commands ### Remote execution diff --git a/lib/mrsk/configuration.rb b/lib/mrsk/configuration.rb index 21178413..e85a67d8 100644 --- a/lib/mrsk/configuration.rb +++ b/lib/mrsk/configuration.rb @@ -3,7 +3,7 @@ require "active_support/core_ext/string/inquiry" require "erb" class Mrsk::Configuration - delegate :service, :image, :servers, :env, :registry, to: :config, allow_nil: true + delegate :service, :image, :servers, :env, :labels, :registry, to: :config, allow_nil: true class << self def load_file(file) diff --git a/lib/mrsk/configuration/role.rb b/lib/mrsk/configuration/role.rb index 6a623bab..9051a571 100644 --- a/lib/mrsk/configuration/role.rb +++ b/lib/mrsk/configuration/role.rb @@ -11,6 +11,14 @@ class Mrsk::Configuration::Role @hosts ||= extract_hosts_from_config end + def labels + if name.web? + default_labels.merge(traefik_labels).merge(custom_labels) + else + default_labels.merge(custom_labels) + end + end + def label_args argumentize "--label", labels end @@ -31,14 +39,6 @@ class Mrsk::Configuration::Role end end - def labels - if name.web? - default_labels.merge(traefik_labels) - else - default_labels - end - end - def default_labels { "service" => config.service, "role" => name } end @@ -53,6 +53,13 @@ class Mrsk::Configuration::Role } end + def custom_labels + Hash.new.tap do |labels| + labels.merge!(config.labels) if config.labels.present? + labels.merge!(specializations["labels"]) if specializations["labels"].present? + end + end + def specializations if config.servers.is_a?(Array) || config.servers[name].is_a?(Array) { } diff --git a/test/configuration_role_test.rb b/test/configuration_role_test.rb index 83bb4e02..a0b00c75 100644 --- a/test/configuration_role_test.rb +++ b/test/configuration_role_test.rb @@ -30,6 +30,11 @@ class ConfigurationRoleTest < ActiveSupport::TestCase assert_equal [ "1.1.1.3", "1.1.1.4" ], @config_with_roles.role(:workers).hosts end + test "cmd" do + assert_nil @config.role(:web).cmd + assert_equal "bin/jobs", @config_with_roles.role(:workers).cmd + end + test "label args" do assert_equal [ "--label", "service=app", "--label", "role=workers" ], @config_with_roles.role(:workers).label_args end @@ -38,8 +43,19 @@ class ConfigurationRoleTest < ActiveSupport::TestCase assert_equal [ "--label", "service=app", "--label", "role=web", "--label", "traefik.http.routers.app.rule='PathPrefix(`/`)'", "--label", "traefik.http.services.app.loadbalancer.healthcheck.path=/up", "--label", "traefik.http.services.app.loadbalancer.healthcheck.interval=1s", "--label", "traefik.http.middlewares.app.retry.attempts=3", "--label", "traefik.http.middlewares.app.retry.initialinterval=500ms"], @config.role(:web).label_args end - test "cmd" do - assert_nil @config.role(:web).cmd - assert_equal "bin/jobs", @config_with_roles.role(:workers).cmd + test "custom labels" do + @deploy[:labels] = { "my.custom.label" => "50" } + assert_equal "50", @config.role(:web).labels["my.custom.label"] + end + + test "custom labels via role specialization" do + @deploy_with_roles[:labels] = { "my.custom.label" => "50" } + @deploy_with_roles[:servers]["workers"]["labels"] = { "my.custom.label" => "70" } + assert_equal "70", @config_with_roles.role(:workers).labels["my.custom.label"] + end + + test "overwriting default traefik label" do + @deploy[:labels] = { "traefik.http.routers.app.rule" => "'Host(`example.com`) || (Host(`example.org`) && Path(`/traefik`))'" } + assert_equal "'Host(`example.com`) || (Host(`example.org`) && Path(`/traefik`))'", @config.role(:web).labels["traefik.http.routers.app.rule"] end end