Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22e7243b10 | ||
|
|
259a018d5a | ||
|
|
a82e88d5c9 | ||
|
|
d6459e869a | ||
|
|
ad21c7e984 | ||
|
|
87965281a3 | ||
|
|
dca96eafaa | ||
|
|
7b1439c3c6 | ||
|
|
b9e5ce7ca7 | ||
|
|
f62c1a50c4 | ||
|
|
2c1d6ed891 |
@@ -1,7 +1,7 @@
|
|||||||
PATH
|
PATH
|
||||||
remote: .
|
remote: .
|
||||||
specs:
|
specs:
|
||||||
kamal (2.6.0)
|
kamal (2.6.1)
|
||||||
activesupport (>= 7.0)
|
activesupport (>= 7.0)
|
||||||
base64 (~> 0.2)
|
base64 (~> 0.2)
|
||||||
bcrypt_pbkdf (~> 1.0)
|
bcrypt_pbkdf (~> 1.0)
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|||||||
def push
|
def push
|
||||||
cli = self
|
cli = self
|
||||||
|
|
||||||
|
# Ensure pre-connect hooks run before the build, they may needed for a remote builder
|
||||||
|
# or the pre-build hooks.
|
||||||
|
pre_connect_if_required
|
||||||
|
|
||||||
ensure_docker_installed
|
ensure_docker_installed
|
||||||
login_to_registry_locally
|
login_to_registry_locally
|
||||||
|
|
||||||
|
|||||||
@@ -120,18 +120,6 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|||||||
execute *KAMAL.proxy.ensure_apps_config_directory
|
execute *KAMAL.proxy.ensure_apps_config_directory
|
||||||
|
|
||||||
execute *KAMAL.proxy.run
|
execute *KAMAL.proxy.run
|
||||||
|
|
||||||
KAMAL.roles_on(host).select(&:running_proxy?).each do |role|
|
|
||||||
app = KAMAL.app(role: role, host: host)
|
|
||||||
|
|
||||||
version = capture_with_info(*app.current_running_version, raise_on_non_zero_exit: false).strip
|
|
||||||
endpoint = capture_with_info(*app.container_id_for_version(version)).strip
|
|
||||||
|
|
||||||
if endpoint.present?
|
|
||||||
info "Deploying #{endpoint} for role `#{role}` on #{host}..."
|
|
||||||
execute *app.deploy(target: endpoint)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
run_hook "post-proxy-reboot", hosts: host_list
|
run_hook "post-proxy-reboot", hosts: host_list
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class Kamal::Commander::Specifics
|
|||||||
@primary_role = primary_or_first_role(roles_on(primary_host))
|
@primary_role = primary_or_first_role(roles_on(primary_host))
|
||||||
|
|
||||||
stable_sort!(roles) { |role| role == primary_role ? 0 : 1 }
|
stable_sort!(roles) { |role| role == primary_role ? 0 : 1 }
|
||||||
stable_sort!(hosts) { |host| roles_on(host).any? { |role| role == primary_role } ? 0 : 1 }
|
sort_primary_role_hosts_first!(hosts)
|
||||||
end
|
end
|
||||||
|
|
||||||
def roles_on(host)
|
def roles_on(host)
|
||||||
@@ -19,7 +19,7 @@ class Kamal::Commander::Specifics
|
|||||||
end
|
end
|
||||||
|
|
||||||
def app_hosts
|
def app_hosts
|
||||||
config.app_hosts & specified_hosts
|
@app_hosts ||= sort_primary_role_hosts_first!(config.app_hosts & specified_hosts)
|
||||||
end
|
end
|
||||||
|
|
||||||
def proxy_hosts
|
def proxy_hosts
|
||||||
@@ -55,4 +55,8 @@ class Kamal::Commander::Specifics
|
|||||||
specified_hosts
|
specified_hosts
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def sort_primary_role_hosts_first!(hosts)
|
||||||
|
stable_sort!(hosts) { |host| roles_on(host).any? { |role| role == primary_role } ? 0 : 1 }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class Kamal::Configuration
|
|||||||
@env = Env.new(config: @raw_config.env || {}, secrets: secrets)
|
@env = Env.new(config: @raw_config.env || {}, secrets: secrets)
|
||||||
|
|
||||||
@logging = Logging.new(logging_config: @raw_config.logging)
|
@logging = Logging.new(logging_config: @raw_config.logging)
|
||||||
@proxy = Proxy.new(config: self, proxy_config: @raw_config.key?(:proxy) ? @raw_config.proxy : {})
|
@proxy = Proxy.new(config: self, proxy_config: @raw_config.proxy)
|
||||||
@proxy_boot = Proxy::Boot.new(config: self)
|
@proxy_boot = Proxy::Boot.new(config: self)
|
||||||
@ssh = Ssh.new(config: self)
|
@ssh = Ssh.new(config: self)
|
||||||
@sshkit = Sshkit.new(config: self)
|
@sshkit = Sshkit.new(config: self)
|
||||||
|
|||||||
@@ -10,11 +10,6 @@
|
|||||||
# They are application-specific, so they are not shared when multiple applications
|
# They are application-specific, so they are not shared when multiple applications
|
||||||
# run on the same proxy.
|
# run on the same proxy.
|
||||||
#
|
#
|
||||||
# The proxy is enabled by default on the primary role but can be disabled by
|
|
||||||
# setting `proxy: false`.
|
|
||||||
#
|
|
||||||
# It is disabled by default on all other roles but can be enabled by setting
|
|
||||||
# `proxy: true` or providing a proxy configuration.
|
|
||||||
proxy:
|
proxy:
|
||||||
|
|
||||||
# Hosts
|
# Hosts
|
||||||
@@ -113,3 +108,30 @@ proxy:
|
|||||||
response_headers:
|
response_headers:
|
||||||
- X-Request-ID
|
- X-Request-ID
|
||||||
- X-Request-Start
|
- X-Request-Start
|
||||||
|
|
||||||
|
# Enabling/disabling the proxy on roles
|
||||||
|
#
|
||||||
|
# The proxy is enabled by default on the primary role but can be disabled by
|
||||||
|
# setting `proxy: false` in the primary role's configuration.
|
||||||
|
#
|
||||||
|
# ```yaml
|
||||||
|
# servers:
|
||||||
|
# web:
|
||||||
|
# hosts:
|
||||||
|
# - ...
|
||||||
|
# proxy: false
|
||||||
|
# ```
|
||||||
|
#
|
||||||
|
# It is disabled by default on all other roles but can be enabled by setting
|
||||||
|
# `proxy: true` or providing a proxy configuration for that role.
|
||||||
|
#
|
||||||
|
# ```yaml
|
||||||
|
# servers:
|
||||||
|
# web:
|
||||||
|
# hosts:
|
||||||
|
# - ...
|
||||||
|
# web2:
|
||||||
|
# hosts:
|
||||||
|
# - ...
|
||||||
|
# proxy: true
|
||||||
|
# ```
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ class Kamal::Configuration::Proxy
|
|||||||
def initialize(config:, proxy_config:, context: "proxy")
|
def initialize(config:, proxy_config:, context: "proxy")
|
||||||
@config = config
|
@config = config
|
||||||
@proxy_config = proxy_config
|
@proxy_config = proxy_config
|
||||||
|
@proxy_config = {} if @proxy_config.nil?
|
||||||
validate! @proxy_config, with: Kamal::Configuration::Validator::Proxy, context: context
|
validate! @proxy_config, with: Kamal::Configuration::Validator::Proxy, context: context
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
module Kamal
|
module Kamal
|
||||||
VERSION = "2.6.0"
|
VERSION = "2.6.1"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class CliBuildTest < CliTestCase
|
|||||||
.returns("")
|
.returns("")
|
||||||
|
|
||||||
run_command("push", "--verbose").tap do |output|
|
run_command("push", "--verbose").tap do |output|
|
||||||
|
assert_hook_ran "pre-connect", output
|
||||||
assert_hook_ran "pre-build", output
|
assert_hook_ran "pre-build", output
|
||||||
assert_match /Cloning repo into build directory/, output
|
assert_match /Cloning repo into build directory/, output
|
||||||
assert_match /git -C #{Dir.tmpdir}\/kamal-clones\/app-#{pwd_sha} clone #{Dir.pwd}/, output
|
assert_match /git -C #{Dir.tmpdir}\/kamal-clones\/app-#{pwd_sha} clone #{Dir.pwd}/, output
|
||||||
|
|||||||
@@ -44,42 +44,20 @@ class CliProxyTest < CliTestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "reboot" do
|
test "reboot" do
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
|
|
||||||
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-web-123$", "--quiet")
|
|
||||||
.returns("abcdefabcdef")
|
|
||||||
.at_least_once
|
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
|
|
||||||
.with { |*args| args[0..1] == [ :sh, "-c" ] }
|
|
||||||
.returns("123")
|
|
||||||
.at_least_once
|
|
||||||
|
|
||||||
run_command("reboot", "-y").tap do |output|
|
run_command("reboot", "-y").tap do |output|
|
||||||
assert_match "docker container stop kamal-proxy on 1.1.1.1", output
|
assert_match "docker container stop kamal-proxy on 1.1.1.1", output
|
||||||
assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on 1.1.1.1", output
|
assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on 1.1.1.1", output
|
||||||
assert_match "mkdir -p .kamal/proxy/apps-config on 1.1.1.1", output
|
assert_match "mkdir -p .kamal/proxy/apps-config on 1.1.1.1", output
|
||||||
assert_match "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION}\") $(cat .kamal/proxy/run_command 2> /dev/null || echo \"\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $(pwd)/.kamal/proxy/apps-config:/home/kamal-proxy/.apps-config on 1.1.1.1", output
|
assert_match "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION}\") $(cat .kamal/proxy/run_command 2> /dev/null || echo \"\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $(pwd)/.kamal/proxy/apps-config:/home/kamal-proxy/.apps-config on 1.1.1.1", output
|
||||||
assert_match "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"abcdefabcdef:80\" --deploy-timeout=\"6s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\" on 1.1.1.1", output
|
|
||||||
|
|
||||||
assert_match "docker container stop kamal-proxy on 1.1.1.2", output
|
assert_match "docker container stop kamal-proxy on 1.1.1.2", output
|
||||||
assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on 1.1.1.2", output
|
assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on 1.1.1.2", output
|
||||||
assert_match "mkdir -p .kamal/proxy/apps-config on 1.1.1.1", output
|
assert_match "mkdir -p .kamal/proxy/apps-config on 1.1.1.1", output
|
||||||
assert_match "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION}\") $(cat .kamal/proxy/run_command 2> /dev/null || echo \"\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $(pwd)/.kamal/proxy/apps-config:/home/kamal-proxy/.apps-config on 1.1.1.2", output
|
assert_match "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION}\") $(cat .kamal/proxy/run_command 2> /dev/null || echo \"\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $(pwd)/.kamal/proxy/apps-config:/home/kamal-proxy/.apps-config on 1.1.1.2", output
|
||||||
assert_match "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"abcdefabcdef:80\" --deploy-timeout=\"6s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\" on 1.1.1.2", output
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "reboot --rolling" do
|
test "reboot --rolling" do
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
|
|
||||||
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-web-123$", "--quiet")
|
|
||||||
.returns("abcdefabcdef")
|
|
||||||
.at_least_once
|
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
|
|
||||||
.with { |*args| args[0..1] == [ :sh, "-c" ] }
|
|
||||||
.returns("123")
|
|
||||||
.at_least_once
|
|
||||||
|
|
||||||
run_command("reboot", "--rolling", "-y").tap do |output|
|
run_command("reboot", "--rolling", "-y").tap do |output|
|
||||||
assert_match "Running docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on 1.1.1.1", output
|
assert_match "Running docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on 1.1.1.1", output
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -149,6 +149,12 @@ class CommanderTest < ActiveSupport::TestCase
|
|||||||
assert_equal [], @kamal.accessory_hosts
|
assert_equal [], @kamal.accessory_hosts
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "primary role hosts are first" do
|
||||||
|
configure_with(:deploy_with_roles_workers_primary)
|
||||||
|
assert_equal [ "1.1.1.1", "1.1.1.2", "1.1.1.3", "1.1.1.4" ], @kamal.hosts
|
||||||
|
assert_equal [ "1.1.1.1", "1.1.1.2", "1.1.1.3", "1.1.1.4" ], @kamal.app_hosts
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def configure_with(variant)
|
def configure_with(variant)
|
||||||
@kamal = Kamal::Commander.new.tap do |kamal|
|
@kamal = Kamal::Commander.new.tap do |kamal|
|
||||||
|
|||||||
19
test/fixtures/deploy_with_roles_workers_primary.yml
vendored
Normal file
19
test/fixtures/deploy_with_roles_workers_primary.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
service: app
|
||||||
|
image: dhh/app
|
||||||
|
servers:
|
||||||
|
workers:
|
||||||
|
- 1.1.1.1
|
||||||
|
- 1.1.1.2
|
||||||
|
web:
|
||||||
|
- 1.1.1.3
|
||||||
|
- 1.1.1.4
|
||||||
|
env:
|
||||||
|
REDIS_URL: redis://x/y
|
||||||
|
registry:
|
||||||
|
server: registry.digitalocean.com
|
||||||
|
username: user
|
||||||
|
password: pw
|
||||||
|
builder:
|
||||||
|
arch: amd64
|
||||||
|
deploy_timeout: 1
|
||||||
|
primary_role: workers
|
||||||
Reference in New Issue
Block a user