kamal 2.0.0.alpha → 2.0.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/kamal/cli/accessory.rb +44 -20
- data/lib/kamal/cli/app/boot.rb +22 -16
- data/lib/kamal/cli/app.rb +37 -3
- data/lib/kamal/cli/base.rb +9 -48
- data/lib/kamal/cli/build.rb +8 -3
- data/lib/kamal/cli/healthcheck/barrier.rb +2 -0
- data/lib/kamal/cli/healthcheck/poller.rb +18 -39
- data/lib/kamal/cli/lock.rb +2 -3
- data/lib/kamal/cli/main.rb +54 -51
- data/lib/kamal/cli/proxy.rb +224 -0
- data/lib/kamal/cli/prune.rb +0 -1
- data/lib/kamal/cli/secrets.rb +36 -0
- data/lib/kamal/cli/server.rb +0 -2
- data/lib/kamal/cli/templates/deploy.yml +0 -11
- data/lib/kamal/cli/templates/sample_hooks/post-proxy-reboot.sample +3 -0
- data/lib/kamal/cli/templates/secrets +16 -0
- data/lib/kamal/cli.rb +1 -0
- data/lib/kamal/commander/specifics.rb +3 -3
- data/lib/kamal/commander.rb +17 -9
- data/lib/kamal/commands/accessory.rb +7 -7
- data/lib/kamal/commands/app/assets.rb +8 -8
- data/lib/kamal/commands/app/proxy.rb +16 -0
- data/lib/kamal/commands/app.rb +7 -15
- data/lib/kamal/commands/auditor.rb +6 -3
- data/lib/kamal/commands/base.rb +8 -0
- data/lib/kamal/commands/builder/base.rb +2 -6
- data/lib/kamal/commands/builder/hybrid.rb +1 -1
- data/lib/kamal/commands/builder/remote.rb +27 -4
- data/lib/kamal/commands/builder.rb +1 -1
- data/lib/kamal/commands/docker.rb +4 -0
- data/lib/kamal/commands/hook.rb +5 -2
- data/lib/kamal/commands/lock.rb +2 -6
- data/lib/kamal/commands/proxy.rb +77 -0
- data/lib/kamal/commands/prune.rb +1 -9
- data/lib/kamal/commands/server.rb +11 -1
- data/lib/kamal/configuration/accessory.rb +14 -2
- data/lib/kamal/configuration/builder.rb +9 -3
- data/lib/kamal/configuration/docs/builder.yml +20 -10
- data/lib/kamal/configuration/docs/configuration.yml +16 -16
- data/lib/kamal/configuration/docs/env.yml +10 -11
- data/lib/kamal/configuration/docs/proxy.yml +100 -0
- data/lib/kamal/configuration/docs/registry.yml +4 -2
- data/lib/kamal/configuration/docs/role.yml +3 -5
- data/lib/kamal/configuration/env/tag.rb +4 -3
- data/lib/kamal/configuration/env.rb +10 -17
- data/lib/kamal/configuration/proxy.rb +66 -0
- data/lib/kamal/configuration/registry.rb +3 -2
- data/lib/kamal/configuration/role.rb +63 -94
- data/lib/kamal/configuration/validator/builder.rb +2 -0
- data/lib/kamal/configuration/validator/proxy.rb +11 -0
- data/lib/kamal/configuration/validator.rb +3 -1
- data/lib/kamal/configuration.rb +90 -33
- data/lib/kamal/env_file.rb +4 -0
- data/lib/kamal/secrets/adapters/base.rb +18 -0
- data/lib/kamal/secrets/adapters/bitwarden.rb +64 -0
- data/lib/kamal/secrets/adapters/last_pass.rb +30 -0
- data/lib/kamal/secrets/adapters/one_password.rb +61 -0
- data/lib/kamal/secrets/adapters/test.rb +10 -0
- data/lib/kamal/secrets/adapters.rb +14 -0
- data/lib/kamal/secrets/dotenv/inline_command_substitution.rb +32 -0
- data/lib/kamal/secrets.rb +37 -0
- data/lib/kamal/sshkit_with_ext.rb +1 -0
- data/lib/kamal/utils.rb +12 -0
- data/lib/kamal/version.rb +1 -1
- data/lib/kamal.rb +3 -1
- metadata +23 -16
- data/lib/kamal/cli/env.rb +0 -54
- data/lib/kamal/cli/templates/sample_hooks/post-traefik-reboot.sample +0 -3
- data/lib/kamal/cli/templates/template.env +0 -2
- data/lib/kamal/cli/traefik.rb +0 -122
- data/lib/kamal/commands/app/cord.rb +0 -22
- data/lib/kamal/commands/traefik.rb +0 -85
- data/lib/kamal/configuration/docs/healthcheck.yml +0 -59
- data/lib/kamal/configuration/docs/traefik.yml +0 -62
- data/lib/kamal/configuration/healthcheck.rb +0 -63
- data/lib/kamal/configuration/traefik.rb +0 -60
- /data/lib/kamal/cli/templates/sample_hooks/{pre-traefik-reboot.sample → pre-proxy-reboot.sample} +0 -0
@@ -0,0 +1,100 @@
|
|
1
|
+
# Proxy
|
2
|
+
#
|
3
|
+
# Kamal uses [kamal-proxy](https://github.com/basecamp/kamal-proxy) to provide
|
4
|
+
# gapless deployments. It runs on ports 80 and 443 and forwards requests to the
|
5
|
+
# application container.
|
6
|
+
#
|
7
|
+
# The proxy is configured in the root configuration under `proxy`. These are
|
8
|
+
# options that are set when deploying the application, not when booting the proxy
|
9
|
+
#
|
10
|
+
# They are application specific, so are not shared when multiple applications
|
11
|
+
# run on the same proxy.
|
12
|
+
#
|
13
|
+
# The proxy is enabled by default on the primary role, but can be disabled by
|
14
|
+
# setting `proxy: false`.
|
15
|
+
#
|
16
|
+
# It is disabled by default on all other roles, but can be enabled by setting
|
17
|
+
# `proxy: true`, or providing a proxy configuration.
|
18
|
+
proxy:
|
19
|
+
|
20
|
+
# Host
|
21
|
+
#
|
22
|
+
# The hosts that will be used to serve the app. The proxy will only route requests
|
23
|
+
# to this host to your app.
|
24
|
+
#
|
25
|
+
# If no hosts are set, then all requests will be forwarded, except for matching
|
26
|
+
# requests for other apps deployed on that server that do have a host set.
|
27
|
+
host: foo.example.com
|
28
|
+
|
29
|
+
# App port
|
30
|
+
#
|
31
|
+
# The port the application container is exposed on
|
32
|
+
#
|
33
|
+
# Defaults to 80
|
34
|
+
app_port: 3000
|
35
|
+
|
36
|
+
# SSL
|
37
|
+
#
|
38
|
+
# kamal-proxy can provide automatic HTTPS for your application via Let's Encrypt.
|
39
|
+
#
|
40
|
+
# This requires that we are deploying to a one server and the host option is set.
|
41
|
+
# The host value must point to the server we are deploying to and port 443 must be
|
42
|
+
# open for the Let's Encrypt challenge to succeed.
|
43
|
+
#
|
44
|
+
# Defaults to false
|
45
|
+
ssl: true
|
46
|
+
|
47
|
+
# Response timeout
|
48
|
+
#
|
49
|
+
# How long to wait for requests to complete before timing out, defaults to 30 seconds
|
50
|
+
response_timeout: 10s
|
51
|
+
|
52
|
+
# Healthcheck
|
53
|
+
#
|
54
|
+
# When deploying, the proxy will by default hit /up once every second until we hit
|
55
|
+
# the deploy timeout, with a 5 second timeout for each request.
|
56
|
+
#
|
57
|
+
# Once the app is up, the proxy will stop hitting the healthcheck endpoint.
|
58
|
+
healthcheck:
|
59
|
+
interval: 3
|
60
|
+
path: /health
|
61
|
+
timeout: 3
|
62
|
+
|
63
|
+
# Buffering
|
64
|
+
#
|
65
|
+
# Whether to buffer request and response bodies in the proxy
|
66
|
+
#
|
67
|
+
# By default buffering is enabled with a max request body size of 1GB and no limit
|
68
|
+
# for response size.
|
69
|
+
#
|
70
|
+
# You can also set the memory limit for buffering, which defaults to 1MB, anything
|
71
|
+
# larger than that is written to disk.
|
72
|
+
buffering:
|
73
|
+
requests: true
|
74
|
+
responses: true
|
75
|
+
max_request_body: 40_000_000
|
76
|
+
max_response_body: 0
|
77
|
+
memory: 2_000_000
|
78
|
+
|
79
|
+
# Logging
|
80
|
+
#
|
81
|
+
# Configure request logging for the proxy
|
82
|
+
# You can specify request and response headers to log.
|
83
|
+
# By default, Cache-Control, Last-Modified and User-Agent request headers are logged
|
84
|
+
logging:
|
85
|
+
request_headers:
|
86
|
+
- Cache-Control
|
87
|
+
- X-Forwarded-Proto
|
88
|
+
response_headers:
|
89
|
+
- X-Request-ID
|
90
|
+
- X-Request-Start
|
91
|
+
|
92
|
+
# Forward headers
|
93
|
+
#
|
94
|
+
# Whether to forward the X-Forwarded-For and X-Forwarded-Proto headers (defaults to false)
|
95
|
+
#
|
96
|
+
# If you are behind a trusted proxy, you can set this to true to forward the headers.
|
97
|
+
#
|
98
|
+
# By default kamal-proxy will not forward the headers the ssl option is set to true, and
|
99
|
+
# will forward them if it is set to false.
|
100
|
+
forward_headers: true
|
@@ -27,11 +27,13 @@ registry:
|
|
27
27
|
# and [set up roles and permissions](https://cloud.google.com/artifact-registry/docs/access-control#permissions).
|
28
28
|
# Normally, assigning a roles/artifactregistry.writer role should be sufficient.
|
29
29
|
#
|
30
|
-
# Once the service account is ready, you need to generate and download a JSON key
|
30
|
+
# Once the service account is ready, you need to generate and download a JSON key and base64 encode it:
|
31
31
|
#
|
32
32
|
# ```shell
|
33
|
-
#
|
33
|
+
# base64 -i /path/to/key.json | tr -d "\\n")
|
34
34
|
# ```
|
35
|
+
# You'll then need to set the KAMAL_REGISTRY_PASSWORD secret to that value.
|
36
|
+
#
|
35
37
|
# Use the env variable as password along with _json_key_base64 as username.
|
36
38
|
# Here’s the final configuration:
|
37
39
|
|
@@ -26,7 +26,7 @@ servers:
|
|
26
26
|
#
|
27
27
|
# When there are other options to set, the list of hosts goes under the `hosts` key
|
28
28
|
#
|
29
|
-
# By default only the primary role uses
|
29
|
+
# By default only the primary role uses a proxy, but you can set `proxy` to change
|
30
30
|
# it.
|
31
31
|
#
|
32
32
|
# You can also set a custom cmd to run in the container, and overwrite other settings
|
@@ -35,18 +35,16 @@ servers:
|
|
35
35
|
hosts:
|
36
36
|
- 172.1.0.3
|
37
37
|
- 172.1.0.4: experiment1
|
38
|
-
traefik: true
|
39
38
|
cmd: "bin/jobs"
|
40
39
|
options:
|
41
40
|
memory: 2g
|
42
41
|
cpus: 4
|
43
|
-
healthcheck:
|
44
|
-
...
|
45
42
|
logging:
|
46
43
|
...
|
44
|
+
proxy:
|
45
|
+
...
|
47
46
|
labels:
|
48
47
|
my-label: workers
|
49
48
|
env:
|
50
49
|
...
|
51
50
|
asset_path: /public
|
52
|
-
|
@@ -1,12 +1,13 @@
|
|
1
1
|
class Kamal::Configuration::Env::Tag
|
2
|
-
attr_reader :name, :config
|
2
|
+
attr_reader :name, :config, :secrets
|
3
3
|
|
4
|
-
def initialize(name, config:)
|
4
|
+
def initialize(name, config:, secrets:)
|
5
5
|
@name = name
|
6
6
|
@config = config
|
7
|
+
@secrets = secrets
|
7
8
|
end
|
8
9
|
|
9
10
|
def env
|
10
|
-
Kamal::Configuration::Env.new(config: config)
|
11
|
+
Kamal::Configuration::Env.new(config: config, secrets: secrets)
|
11
12
|
end
|
12
13
|
end
|
@@ -1,36 +1,29 @@
|
|
1
1
|
class Kamal::Configuration::Env
|
2
2
|
include Kamal::Configuration::Validation
|
3
3
|
|
4
|
-
attr_reader :
|
4
|
+
attr_reader :context, :secrets
|
5
|
+
attr_reader :clear, :secret_keys
|
5
6
|
delegate :argumentize, to: Kamal::Utils
|
6
7
|
|
7
|
-
def initialize(config:,
|
8
|
+
def initialize(config:, secrets:, context: "env")
|
8
9
|
@clear = config.fetch("clear", config.key?("secret") || config.key?("tags") ? {} : config)
|
9
|
-
@
|
10
|
-
@
|
10
|
+
@secrets = secrets
|
11
|
+
@secret_keys = config.fetch("secret", [])
|
11
12
|
@context = context
|
12
13
|
validate! config, context: context, with: Kamal::Configuration::Validator::Env
|
13
14
|
end
|
14
15
|
|
15
|
-
def
|
16
|
-
|
16
|
+
def clear_args
|
17
|
+
argumentize("--env", clear)
|
17
18
|
end
|
18
19
|
|
19
20
|
def secrets_io
|
20
|
-
|
21
|
-
end
|
22
|
-
|
23
|
-
def secrets
|
24
|
-
@secrets ||= secrets_keys.to_h { |key| [ key, ENV.fetch(key) ] }
|
25
|
-
end
|
26
|
-
|
27
|
-
def secrets_directory
|
28
|
-
File.dirname(secrets_file)
|
21
|
+
Kamal::EnvFile.new(secret_keys.to_h { |key| [ key, secrets[key] ] }).to_io
|
29
22
|
end
|
30
23
|
|
31
24
|
def merge(other)
|
32
25
|
self.class.new \
|
33
|
-
config: { "clear" => clear.merge(other.clear), "secret" =>
|
34
|
-
|
26
|
+
config: { "clear" => clear.merge(other.clear), "secret" => secret_keys | other.secret_keys },
|
27
|
+
secrets: secrets
|
35
28
|
end
|
36
29
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
class Kamal::Configuration::Proxy
|
2
|
+
include Kamal::Configuration::Validation
|
3
|
+
|
4
|
+
DEFAULT_LOG_REQUEST_HEADERS = [ "Cache-Control", "Last-Modified", "User-Agent" ]
|
5
|
+
CONTAINER_NAME = "kamal-proxy"
|
6
|
+
|
7
|
+
delegate :argumentize, :optionize, to: Kamal::Utils
|
8
|
+
|
9
|
+
attr_reader :config, :proxy_config
|
10
|
+
|
11
|
+
def initialize(config:, proxy_config:, context: "proxy")
|
12
|
+
@config = config
|
13
|
+
@proxy_config = proxy_config
|
14
|
+
validate! @proxy_config, with: Kamal::Configuration::Validator::Proxy, context: context
|
15
|
+
end
|
16
|
+
|
17
|
+
def app_port
|
18
|
+
proxy_config.fetch("app_port", 80)
|
19
|
+
end
|
20
|
+
|
21
|
+
def ssl?
|
22
|
+
proxy_config.fetch("ssl", false)
|
23
|
+
end
|
24
|
+
|
25
|
+
def host
|
26
|
+
proxy_config["host"]
|
27
|
+
end
|
28
|
+
|
29
|
+
def deploy_options
|
30
|
+
{
|
31
|
+
host: proxy_config["host"],
|
32
|
+
tls: proxy_config["ssl"],
|
33
|
+
"deploy-timeout": seconds_duration(config.deploy_timeout),
|
34
|
+
"drain-timeout": seconds_duration(config.drain_timeout),
|
35
|
+
"health-check-interval": seconds_duration(proxy_config.dig("healthcheck", "interval")),
|
36
|
+
"health-check-timeout": seconds_duration(proxy_config.dig("healthcheck", "timeout")),
|
37
|
+
"health-check-path": proxy_config.dig("healthcheck", "path"),
|
38
|
+
"target-timeout": seconds_duration(proxy_config["response_timeout"]),
|
39
|
+
"buffer-requests": proxy_config.fetch("buffering", { "requests": true }).fetch("requests", true),
|
40
|
+
"buffer-responses": proxy_config.fetch("buffering", { "responses": true }).fetch("responses", true),
|
41
|
+
"buffer-memory": proxy_config.dig("buffering", "memory"),
|
42
|
+
"max-request-body": proxy_config.dig("buffering", "max_request_body"),
|
43
|
+
"max-response-body": proxy_config.dig("buffering", "max_response_body"),
|
44
|
+
"forward-headers": proxy_config.dig("forward_headers"),
|
45
|
+
"log-request-header": proxy_config.dig("logging", "request_headers") || DEFAULT_LOG_REQUEST_HEADERS,
|
46
|
+
"log-response-header": proxy_config.dig("logging", "response_headers")
|
47
|
+
}.compact
|
48
|
+
end
|
49
|
+
|
50
|
+
def deploy_command_args(target:)
|
51
|
+
optionize ({ target: "#{target}:#{app_port}" }).merge(deploy_options)
|
52
|
+
end
|
53
|
+
|
54
|
+
def remove_command_args(target:)
|
55
|
+
optionize({ target: "#{target}:#{app_port}" })
|
56
|
+
end
|
57
|
+
|
58
|
+
def merge(other)
|
59
|
+
self.class.new config: config, proxy_config: proxy_config.deep_merge(other.proxy_config)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
def seconds_duration(value)
|
64
|
+
value ? "#{value}s" : nil
|
65
|
+
end
|
66
|
+
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
class Kamal::Configuration::Registry
|
2
2
|
include Kamal::Configuration::Validation
|
3
3
|
|
4
|
-
attr_reader :registry_config
|
4
|
+
attr_reader :registry_config, :secrets
|
5
5
|
|
6
6
|
def initialize(config:)
|
7
7
|
@registry_config = config.raw_config.registry || {}
|
8
|
+
@secrets = config.secrets
|
8
9
|
validate! registry_config, with: Kamal::Configuration::Validator::Registry
|
9
10
|
end
|
10
11
|
|
@@ -23,7 +24,7 @@ class Kamal::Configuration::Registry
|
|
23
24
|
private
|
24
25
|
def lookup(key)
|
25
26
|
if registry_config[key].is_a?(Array)
|
26
|
-
|
27
|
+
secrets[registry_config[key].first]
|
27
28
|
else
|
28
29
|
registry_config[key]
|
29
30
|
end
|
@@ -1,10 +1,9 @@
|
|
1
1
|
class Kamal::Configuration::Role
|
2
2
|
include Kamal::Configuration::Validation
|
3
3
|
|
4
|
-
CORD_FILE = "cord"
|
5
4
|
delegate :argumentize, :optionize, to: Kamal::Utils
|
6
5
|
|
7
|
-
attr_reader :name, :config, :specialized_env, :specialized_logging, :
|
6
|
+
attr_reader :name, :config, :specialized_env, :specialized_logging, :specialized_proxy
|
8
7
|
|
9
8
|
alias to_s name
|
10
9
|
|
@@ -18,16 +17,14 @@ class Kamal::Configuration::Role
|
|
18
17
|
|
19
18
|
@specialized_env = Kamal::Configuration::Env.new \
|
20
19
|
config: specializations.fetch("env", {}),
|
21
|
-
|
20
|
+
secrets: config.secrets,
|
22
21
|
context: "servers/#{name}/env"
|
23
22
|
|
24
23
|
@specialized_logging = Kamal::Configuration::Logging.new \
|
25
24
|
logging_config: specializations.fetch("logging", {}),
|
26
25
|
context: "servers/#{name}/logging"
|
27
26
|
|
28
|
-
|
29
|
-
healthcheck_config: specializations.fetch("healthcheck", {}),
|
30
|
-
context: "servers/#{name}/healthcheck"
|
27
|
+
initialize_specialized_proxy
|
31
28
|
end
|
32
29
|
|
33
30
|
def primary_host
|
@@ -55,7 +52,7 @@ class Kamal::Configuration::Role
|
|
55
52
|
end
|
56
53
|
|
57
54
|
def labels
|
58
|
-
default_labels.merge(
|
55
|
+
default_labels.merge(custom_labels)
|
59
56
|
end
|
60
57
|
|
61
58
|
def label_args
|
@@ -70,87 +67,53 @@ class Kamal::Configuration::Role
|
|
70
67
|
@logging ||= config.logging.merge(specialized_logging)
|
71
68
|
end
|
72
69
|
|
73
|
-
|
74
|
-
|
75
|
-
@envs ||= {}
|
76
|
-
@envs[host] ||= [ config.env, specialized_env, *env_tags(host).map(&:env) ].reduce(:merge)
|
70
|
+
def proxy
|
71
|
+
@proxy ||= config.proxy.merge(specialized_proxy) if running_proxy?
|
77
72
|
end
|
78
73
|
|
79
|
-
def
|
80
|
-
|
74
|
+
def running_proxy?
|
75
|
+
@running_proxy
|
81
76
|
end
|
82
77
|
|
83
|
-
def
|
84
|
-
|
78
|
+
def ssl?
|
79
|
+
running_proxy? && proxy.ssl?
|
85
80
|
end
|
86
81
|
|
82
|
+
def stop_args
|
83
|
+
# When deploying with the proxy, kamal-proxy will drain request before returning so we don't need to wait.
|
84
|
+
timeout = running_proxy? ? nil : config.drain_timeout
|
87
85
|
|
88
|
-
|
89
|
-
if running_traefik? || healthcheck.set_port_or_path?
|
90
|
-
if cord && uses_cord?
|
91
|
-
optionize({ "health-cmd" => health_check_cmd_with_cord, "health-interval" => healthcheck.interval })
|
92
|
-
.concat(cord_volume.docker_args)
|
93
|
-
else
|
94
|
-
optionize({ "health-cmd" => healthcheck.cmd, "health-interval" => healthcheck.interval })
|
95
|
-
end
|
96
|
-
else
|
97
|
-
[]
|
98
|
-
end
|
86
|
+
[ *argumentize("-t", timeout) ]
|
99
87
|
end
|
100
88
|
|
101
|
-
def
|
102
|
-
@
|
103
|
-
|
104
|
-
config.healthcheck.merge(specialized_healthcheck)
|
105
|
-
else
|
106
|
-
specialized_healthcheck
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def health_check_cmd_with_cord
|
111
|
-
"(#{healthcheck.cmd}) && (stat #{cord_container_file} > /dev/null || exit 1)"
|
112
|
-
end
|
113
|
-
|
114
|
-
|
115
|
-
def running_traefik?
|
116
|
-
if specializations["traefik"].nil?
|
117
|
-
primary?
|
118
|
-
else
|
119
|
-
specializations["traefik"]
|
120
|
-
end
|
89
|
+
def env(host)
|
90
|
+
@envs ||= {}
|
91
|
+
@envs[host] ||= [ config.env, specialized_env, *env_tags(host).map(&:env) ].reduce(:merge)
|
121
92
|
end
|
122
93
|
|
123
|
-
def
|
124
|
-
|
94
|
+
def env_args(host)
|
95
|
+
[ *env(host).clear_args, *argumentize("--env-file", secrets_path) ]
|
125
96
|
end
|
126
97
|
|
127
|
-
|
128
|
-
|
129
|
-
running_traefik? && cord_volume && healthcheck.cmd.present?
|
98
|
+
def env_directory
|
99
|
+
File.join(config.env_directory, "roles")
|
130
100
|
end
|
131
101
|
|
132
|
-
def
|
133
|
-
|
102
|
+
def secrets_io(host)
|
103
|
+
env(host).secrets_io
|
134
104
|
end
|
135
105
|
|
136
|
-
def
|
137
|
-
|
138
|
-
@cord_volume ||= Kamal::Configuration::Volume.new \
|
139
|
-
host_path: File.join(config.run_directory, "cords", [ container_prefix, config.run_id ].join("-")),
|
140
|
-
container_path: cord
|
141
|
-
end
|
106
|
+
def secrets_path
|
107
|
+
File.join(config.env_directory, "roles", "#{name}.env")
|
142
108
|
end
|
143
109
|
|
144
|
-
def
|
145
|
-
|
110
|
+
def asset_volume_args
|
111
|
+
asset_volume&.docker_args
|
146
112
|
end
|
147
113
|
|
148
|
-
def cord_container_directory
|
149
|
-
health_check_options.fetch("cord", nil)
|
150
|
-
end
|
151
114
|
|
152
|
-
def
|
153
|
-
|
115
|
+
def primary?
|
116
|
+
name == @config.primary_role_name
|
154
117
|
end
|
155
118
|
|
156
119
|
|
@@ -168,25 +131,52 @@ class Kamal::Configuration::Role
|
|
168
131
|
end
|
169
132
|
|
170
133
|
def assets?
|
171
|
-
asset_path.present? &&
|
134
|
+
asset_path.present? && running_proxy?
|
172
135
|
end
|
173
136
|
|
174
|
-
def asset_volume(version =
|
137
|
+
def asset_volume(version = config.version)
|
175
138
|
if assets?
|
176
139
|
Kamal::Configuration::Volume.new \
|
177
|
-
host_path:
|
140
|
+
host_path: asset_volume_directory(version), container_path: asset_path
|
178
141
|
end
|
179
142
|
end
|
180
143
|
|
181
|
-
def
|
182
|
-
File.join config.
|
144
|
+
def asset_extracted_directory(version = config.version)
|
145
|
+
File.join config.assets_directory, "extracted", [ name, version ].join("-")
|
183
146
|
end
|
184
147
|
|
185
|
-
def
|
186
|
-
File.join config.
|
148
|
+
def asset_volume_directory(version = config.version)
|
149
|
+
File.join config.assets_directory, "volumes", [ name, version ].join("-")
|
150
|
+
end
|
151
|
+
|
152
|
+
def ensure_one_host_for_ssl
|
153
|
+
if running_proxy? && proxy.ssl? && hosts.size > 1
|
154
|
+
raise Kamal::ConfigurationError, "SSL is only supported on a single server, found #{hosts.size} servers for role #{name}"
|
155
|
+
end
|
187
156
|
end
|
188
157
|
|
189
158
|
private
|
159
|
+
def initialize_specialized_proxy
|
160
|
+
proxy_specializations = specializations["proxy"]
|
161
|
+
|
162
|
+
if primary?
|
163
|
+
# only false means no proxy for non-primary roles
|
164
|
+
@running_proxy = proxy_specializations != false
|
165
|
+
else
|
166
|
+
# false and nil both mean no proxy for non-primary roles
|
167
|
+
@running_proxy = !!proxy_specializations
|
168
|
+
end
|
169
|
+
|
170
|
+
if running_proxy?
|
171
|
+
proxy_config = proxy_specializations == true || proxy_specializations.nil? ? {} : proxy_specializations
|
172
|
+
|
173
|
+
@specialized_proxy = Kamal::Configuration::Proxy.new \
|
174
|
+
config: config,
|
175
|
+
proxy_config: proxy_config,
|
176
|
+
context: "servers/#{name}/proxy"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
190
180
|
def tagged_hosts
|
191
181
|
{}.tap do |tagged_hosts|
|
192
182
|
extract_hosts_from_config.map do |host_config|
|
@@ -221,27 +211,6 @@ class Kamal::Configuration::Role
|
|
221
211
|
end
|
222
212
|
end
|
223
213
|
|
224
|
-
def traefik_labels
|
225
|
-
if running_traefik?
|
226
|
-
{
|
227
|
-
# Setting a service property ensures that the generated service name will be consistent between versions
|
228
|
-
"traefik.http.services.#{traefik_service}.loadbalancer.server.scheme" => "http",
|
229
|
-
|
230
|
-
"traefik.http.routers.#{traefik_service}.rule" => "PathPrefix(`/`)",
|
231
|
-
"traefik.http.routers.#{traefik_service}.priority" => "2",
|
232
|
-
"traefik.http.middlewares.#{traefik_service}-retry.retry.attempts" => "5",
|
233
|
-
"traefik.http.middlewares.#{traefik_service}-retry.retry.initialinterval" => "500ms",
|
234
|
-
"traefik.http.routers.#{traefik_service}.middlewares" => "#{traefik_service}-retry@docker"
|
235
|
-
}
|
236
|
-
else
|
237
|
-
{}
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
def traefik_service
|
242
|
-
container_prefix
|
243
|
-
end
|
244
|
-
|
245
214
|
def custom_labels
|
246
215
|
Hash.new.tap do |labels|
|
247
216
|
labels.merge!(config.labels) if config.labels.present?
|
@@ -7,5 +7,7 @@ class Kamal::Configuration::Validator::Builder < Kamal::Configuration::Validator
|
|
7
7
|
end
|
8
8
|
|
9
9
|
error "Builder arch not set" unless config["arch"].present?
|
10
|
+
|
11
|
+
error "Cannot disable local builds, no remote is set" if config["local"] == false && config["remote"].blank?
|
10
12
|
end
|
11
13
|
end
|
@@ -24,7 +24,9 @@ class Kamal::Configuration::Validator
|
|
24
24
|
example_value = example[key]
|
25
25
|
|
26
26
|
if example_value == "..."
|
27
|
-
|
27
|
+
unless key.to_s == "proxy" && boolean?(value.class)
|
28
|
+
validate_type! value, *(Array if key == :servers), Hash
|
29
|
+
end
|
28
30
|
elsif key == "hosts"
|
29
31
|
validate_servers! value
|
30
32
|
elsif example_value.is_a?(Array)
|