Merge pull request #580 from happyscribe/feat/no-web
Allow Kamal to run without traefik
This commit is contained in:
@@ -3,6 +3,7 @@ class Kamal::Cli::Healthcheck < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "perform", "Health check current app version"
|
desc "perform", "Health check current app version"
|
||||||
def perform
|
def perform
|
||||||
|
raise "The primary host is not configured to run Traefik" unless KAMAL.config.role(KAMAL.config.primary_role).running_traefik?
|
||||||
on(KAMAL.primary_host) do
|
on(KAMAL.primary_host) do
|
||||||
begin
|
begin
|
||||||
execute *KAMAL.healthcheck.run
|
execute *KAMAL.healthcheck.run
|
||||||
|
|||||||
@@ -38,8 +38,10 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
say "Ensure Traefik is running...", :magenta
|
say "Ensure Traefik is running...", :magenta
|
||||||
invoke "kamal:cli:traefik:boot", [], invoke_options
|
invoke "kamal:cli:traefik:boot", [], invoke_options
|
||||||
|
|
||||||
say "Ensure app can pass healthcheck...", :magenta
|
if KAMAL.config.role(KAMAL.config.primary_role).running_traefik?
|
||||||
invoke "kamal:cli:healthcheck:perform", [], invoke_options
|
say "Ensure app can pass healthcheck...", :magenta
|
||||||
|
invoke "kamal:cli:healthcheck:perform", [], invoke_options
|
||||||
|
end
|
||||||
|
|
||||||
say "Detect stale containers...", :magenta
|
say "Detect stale containers...", :magenta
|
||||||
invoke "kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true)
|
invoke "kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true)
|
||||||
|
|||||||
@@ -84,13 +84,12 @@ registry:
|
|||||||
# limit: 10 # Can also specify as a percentage of total hosts, such as "25%"
|
# limit: 10 # Can also specify as a percentage of total hosts, such as "25%"
|
||||||
# wait: 2
|
# wait: 2
|
||||||
|
|
||||||
# Configure the role used to determine the primary_web_host. This host takes
|
# Configure the role used to determine the primary_host. This host takes
|
||||||
# deploy locks, runs health checks during the deploy, and follow logs, etc.
|
# deploy locks, runs health checks during the deploy, and follow logs, etc.
|
||||||
# This role should have traefik enabled.
|
|
||||||
#
|
#
|
||||||
# Caution: there's no support for role renaming yet, so be careful to cleanup
|
# Caution: there's no support for role renaming yet, so be careful to cleanup
|
||||||
# the previous role on the deployed hosts.
|
# the previous role on the deployed hosts.
|
||||||
# primary_web_role: web
|
# primary_role: web
|
||||||
|
|
||||||
# Controls if we abort when see a role with no hosts. Disabling this may be
|
# Controls if we abort when see a role with no hosts. Disabling this may be
|
||||||
# useful for more complex deploy configurations.
|
# useful for more complex deploy configurations.
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class Kamal::Commander
|
|||||||
attr_reader :specific_roles, :specific_hosts
|
attr_reader :specific_roles, :specific_hosts
|
||||||
|
|
||||||
def specific_primary!
|
def specific_primary!
|
||||||
self.specific_hosts = [ config.primary_web_host ]
|
self.specific_hosts = [ config.primary_host ]
|
||||||
end
|
end
|
||||||
|
|
||||||
def specific_roles=(role_names)
|
def specific_roles=(role_names)
|
||||||
@@ -36,7 +36,7 @@ class Kamal::Commander
|
|||||||
end
|
end
|
||||||
|
|
||||||
def primary_host
|
def primary_host
|
||||||
specific_hosts&.first || specific_roles&.first&.primary_host || config.primary_web_host
|
specific_hosts&.first || specific_roles&.first&.primary_host || config.primary_host
|
||||||
end
|
end
|
||||||
|
|
||||||
def primary_role
|
def primary_role
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
class Kamal::Commands::Healthcheck < Kamal::Commands::Base
|
class Kamal::Commands::Healthcheck < Kamal::Commands::Base
|
||||||
|
|
||||||
def run
|
def run
|
||||||
web = config.role(config.primary_web_role)
|
primary = config.role(config.primary_role)
|
||||||
|
|
||||||
docker :run,
|
docker :run,
|
||||||
"--detach",
|
"--detach",
|
||||||
@@ -9,12 +9,12 @@ class Kamal::Commands::Healthcheck < Kamal::Commands::Base
|
|||||||
"--publish", "#{exposed_port}:#{config.healthcheck["port"]}",
|
"--publish", "#{exposed_port}:#{config.healthcheck["port"]}",
|
||||||
"--label", "service=#{config.healthcheck_service}",
|
"--label", "service=#{config.healthcheck_service}",
|
||||||
"-e", "KAMAL_CONTAINER_NAME=\"#{config.healthcheck_service}\"",
|
"-e", "KAMAL_CONTAINER_NAME=\"#{config.healthcheck_service}\"",
|
||||||
*web.env_args,
|
*primary.env_args,
|
||||||
*web.health_check_args(cord: false),
|
*primary.health_check_args(cord: false),
|
||||||
*config.volume_args,
|
*config.volume_args,
|
||||||
*web.option_args,
|
*primary.option_args,
|
||||||
config.absolute_image,
|
config.absolute_image,
|
||||||
web.cmd
|
primary.cmd
|
||||||
end
|
end
|
||||||
|
|
||||||
def status
|
def status
|
||||||
|
|||||||
@@ -91,8 +91,8 @@ class Kamal::Configuration
|
|||||||
roles.flat_map(&:hosts).uniq
|
roles.flat_map(&:hosts).uniq
|
||||||
end
|
end
|
||||||
|
|
||||||
def primary_web_host
|
def primary_host
|
||||||
role(primary_web_role)&.primary_host
|
role(primary_role)&.primary_host
|
||||||
end
|
end
|
||||||
|
|
||||||
def traefik_roles
|
def traefik_roles
|
||||||
@@ -208,8 +208,8 @@ class Kamal::Configuration
|
|||||||
raw_config.asset_path
|
raw_config.asset_path
|
||||||
end
|
end
|
||||||
|
|
||||||
def primary_web_role
|
def primary_role
|
||||||
raw_config.primary_web_role || "web"
|
raw_config.primary_role || "web"
|
||||||
end
|
end
|
||||||
|
|
||||||
def allow_empty_roles?
|
def allow_empty_roles?
|
||||||
@@ -225,7 +225,7 @@ class Kamal::Configuration
|
|||||||
{
|
{
|
||||||
roles: role_names,
|
roles: role_names,
|
||||||
hosts: all_hosts,
|
hosts: all_hosts,
|
||||||
primary_host: primary_web_host,
|
primary_host: primary_host,
|
||||||
version: version,
|
version: version,
|
||||||
repository: repository,
|
repository: repository,
|
||||||
absolute_image: absolute_image,
|
absolute_image: absolute_image,
|
||||||
@@ -264,16 +264,12 @@ class Kamal::Configuration
|
|||||||
raise ArgumentError, "You must specify a password for the registry in config/deploy.yml (or set the ENV variable if that's used)"
|
raise ArgumentError, "You must specify a password for the registry in config/deploy.yml (or set the ENV variable if that's used)"
|
||||||
end
|
end
|
||||||
|
|
||||||
unless role_names.include?(primary_web_role)
|
unless role_names.include?(primary_role)
|
||||||
raise ArgumentError, "The primary_web_role #{primary_web_role} isn't defined"
|
raise ArgumentError, "The primary_role #{primary_role} isn't defined"
|
||||||
end
|
end
|
||||||
|
|
||||||
unless traefik_role_names.include?(primary_web_role)
|
if role(primary_role).hosts.empty?
|
||||||
raise ArgumentError, "Role #{primary_web_role} needs to have traefik enabled"
|
raise ArgumentError, "No servers specified for the #{primary_role} primary_role"
|
||||||
end
|
|
||||||
|
|
||||||
if role(primary_web_role).hosts.empty?
|
|
||||||
raise ArgumentError, "No servers specified for the #{primary_web_role} primary_web_role"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
unless allow_empty_roles?
|
unless allow_empty_roles?
|
||||||
|
|||||||
@@ -93,7 +93,15 @@ class Kamal::Configuration::Role
|
|||||||
|
|
||||||
|
|
||||||
def running_traefik?
|
def running_traefik?
|
||||||
name.web? || specializations["traefik"]
|
if specializations["traefik"].nil?
|
||||||
|
primary?
|
||||||
|
else
|
||||||
|
specializations["traefik"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def primary?
|
||||||
|
@config.primary_role == name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -64,9 +64,19 @@ class CliHealthcheckTest < CliTestCase
|
|||||||
end
|
end
|
||||||
assert_match "container not ready (unhealthy)", exception.message
|
assert_match "container not ready (unhealthy)", exception.message
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "raises an exception if primary does not have traefik" do
|
||||||
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).never
|
||||||
|
|
||||||
|
exception = assert_raises do
|
||||||
|
run_command("perform", config_file: "test/fixtures/deploy_workers_only.yml")
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal "The primary host is not configured to run Traefik", exception.message
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def run_command(*command)
|
def run_command(*command, config_file: "test/fixtures/deploy_with_accessories.yml")
|
||||||
stdouted { Kamal::Cli::Healthcheck.start([*command, "-c", "test/fixtures/deploy_with_accessories.yml"]) }
|
stdouted { Kamal::Cli::Healthcheck.start([*command, "-c", config_file]) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -122,6 +122,21 @@ class CliMainTest < CliTestCase
|
|||||||
refute_match /Running the post-deploy hook.../, output
|
refute_match /Running the post-deploy hook.../, output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "deploy without healthcheck if primary host doesn't have traefik" do
|
||||||
|
invoke_options = { "config_file" => "test/fixtures/deploy_workers_only.yml", "version" => "999", "skip_hooks" => false }
|
||||||
|
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:healthcheck:perform", [], invoke_options).never
|
||||||
|
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:login", [], invoke_options)
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:build:deliver", [], invoke_options)
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:traefik:boot", [], invoke_options)
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true))
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:boot", [], invoke_options)
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:prune:all", [], invoke_options)
|
||||||
|
|
||||||
|
run_command("deploy", config_file: "deploy_workers_only")
|
||||||
|
end
|
||||||
|
|
||||||
test "deploy with missing secrets" do
|
test "deploy with missing secrets" do
|
||||||
invoke_options = { "config_file" => "test/fixtures/deploy_with_secrets.yml", "version" => "999", "skip_hooks" => false }
|
invoke_options = { "config_file" => "test/fixtures/deploy_with_secrets.yml", "version" => "999", "skip_hooks" => false }
|
||||||
|
|||||||
@@ -58,9 +58,9 @@ class ConfigurationTest < ActiveSupport::TestCase
|
|||||||
assert_equal [ "1.1.1.1", "1.1.1.2", "1.1.1.3" ], @config_with_roles.all_hosts
|
assert_equal [ "1.1.1.1", "1.1.1.2", "1.1.1.3" ], @config_with_roles.all_hosts
|
||||||
end
|
end
|
||||||
|
|
||||||
test "primary web host" do
|
test "primary host" do
|
||||||
assert_equal "1.1.1.1", @config.primary_web_host
|
assert_equal "1.1.1.1", @config.primary_host
|
||||||
assert_equal "1.1.1.1", @config_with_roles.primary_web_host
|
assert_equal "1.1.1.1", @config_with_roles.primary_host
|
||||||
end
|
end
|
||||||
|
|
||||||
test "traefik hosts" do
|
test "traefik hosts" do
|
||||||
@@ -289,27 +289,23 @@ class ConfigurationTest < ActiveSupport::TestCase
|
|||||||
assert_equal "foo", Kamal::Configuration.new(@deploy.merge!(asset_path: "foo")).asset_path
|
assert_equal "foo", Kamal::Configuration.new(@deploy.merge!(asset_path: "foo")).asset_path
|
||||||
end
|
end
|
||||||
|
|
||||||
test "primary web role" do
|
test "primary role" do
|
||||||
assert_equal "web", @config.primary_web_role
|
assert_equal "web", @config.primary_role
|
||||||
|
|
||||||
config = Kamal::Configuration.new(@deploy_with_roles.deep_merge({
|
config = Kamal::Configuration.new(@deploy_with_roles.deep_merge({
|
||||||
servers: { "alternate_web" => { "hosts" => [ "1.1.1.4", "1.1.1.5" ] , "traefik" => true } },
|
servers: { "alternate_web" => { "hosts" => [ "1.1.1.4", "1.1.1.5" ] } },
|
||||||
primary_web_role: "alternate_web" } ))
|
primary_role: "alternate_web" } ))
|
||||||
|
|
||||||
assert_equal "alternate_web", config.primary_web_role
|
|
||||||
assert_equal "1.1.1.4", config.primary_web_host
|
assert_equal "alternate_web", config.primary_role
|
||||||
|
assert_equal "1.1.1.4", config.primary_host
|
||||||
|
assert config.role(:alternate_web).primary?
|
||||||
|
assert config.role(:alternate_web).running_traefik?
|
||||||
end
|
end
|
||||||
|
|
||||||
test "primary web role no traefik" do
|
test "primary role missing" do
|
||||||
error = assert_raises(ArgumentError) do
|
error = assert_raises(ArgumentError) do
|
||||||
Kamal::Configuration.new(@deploy_with_roles.merge(primary_web_role: "workers"))
|
Kamal::Configuration.new(@deploy.merge(primary_role: "bar"))
|
||||||
end
|
|
||||||
assert_match /workers needs to have traefik enabled/, error.message
|
|
||||||
end
|
|
||||||
|
|
||||||
test "primary web role missing" do
|
|
||||||
error = assert_raises(ArgumentError) do
|
|
||||||
Kamal::Configuration.new(@deploy.merge(primary_web_role: "bar"))
|
|
||||||
end
|
end
|
||||||
assert_match /bar isn't defined/, error.message
|
assert_match /bar isn't defined/, error.message
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -17,4 +17,4 @@ registry:
|
|||||||
server: registry.digitalocean.com
|
server: registry.digitalocean.com
|
||||||
username: user
|
username: user
|
||||||
password: pw
|
password: pw
|
||||||
primary_web_role: web_tokyo
|
primary_role: web_tokyo
|
||||||
|
|||||||
12
test/fixtures/deploy_workers_only.yml
vendored
Normal file
12
test/fixtures/deploy_workers_only.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
service: app
|
||||||
|
image: dhh/app
|
||||||
|
servers:
|
||||||
|
workers:
|
||||||
|
traefik: false
|
||||||
|
hosts:
|
||||||
|
- 1.1.1.1
|
||||||
|
- 1.1.1.2
|
||||||
|
primary_role: workers
|
||||||
|
registry:
|
||||||
|
username: user
|
||||||
|
password: pw
|
||||||
Reference in New Issue
Block a user