kamal 0.16.1 → 1.0.0
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/app.rb +38 -11
- data/lib/kamal/cli/base.rb +8 -0
- data/lib/kamal/cli/build.rb +18 -1
- data/lib/kamal/cli/env.rb +56 -0
- data/lib/kamal/cli/healthcheck/poller.rb +64 -0
- data/lib/kamal/cli/healthcheck.rb +2 -2
- data/lib/kamal/cli/lock.rb +12 -3
- data/lib/kamal/cli/main.rb +14 -3
- data/lib/kamal/cli/prune.rb +3 -2
- data/lib/kamal/cli/server.rb +2 -0
- data/lib/kamal/cli/templates/deploy.yml +12 -1
- data/lib/kamal/commander.rb +21 -8
- data/lib/kamal/commands/accessory.rb +8 -8
- data/lib/kamal/commands/app/assets.rb +51 -0
- data/lib/kamal/commands/app/containers.rb +23 -0
- data/lib/kamal/commands/app/cord.rb +22 -0
- data/lib/kamal/commands/app/execution.rb +27 -0
- data/lib/kamal/commands/app/images.rb +13 -0
- data/lib/kamal/commands/app/logging.rb +18 -0
- data/lib/kamal/commands/app.rb +17 -91
- data/lib/kamal/commands/auditor.rb +3 -1
- data/lib/kamal/commands/base.rb +12 -0
- data/lib/kamal/commands/builder/base.rb +6 -0
- data/lib/kamal/commands/builder.rb +1 -1
- data/lib/kamal/commands/healthcheck.rb +15 -12
- data/lib/kamal/commands/lock.rb +2 -2
- data/lib/kamal/commands/prune.rb +11 -3
- data/lib/kamal/commands/server.rb +5 -0
- data/lib/kamal/commands/traefik.rb +21 -7
- data/lib/kamal/configuration/accessory.rb +14 -2
- data/lib/kamal/configuration/role.rb +112 -19
- data/lib/kamal/configuration/ssh.rb +1 -1
- data/lib/kamal/configuration/volume.rb +22 -0
- data/lib/kamal/configuration.rb +79 -43
- data/lib/kamal/env_file.rb +41 -0
- data/lib/kamal/git.rb +19 -0
- data/lib/kamal/utils.rb +0 -39
- data/lib/kamal/version.rb +1 -1
- metadata +15 -4
- data/lib/kamal/utils/healthcheck_poller.rb +0 -39
@@ -0,0 +1,27 @@
|
|
1
|
+
module Kamal::Commands::App::Execution
|
2
|
+
def execute_in_existing_container(*command, interactive: false)
|
3
|
+
docker :exec,
|
4
|
+
("-it" if interactive),
|
5
|
+
container_name,
|
6
|
+
*command
|
7
|
+
end
|
8
|
+
|
9
|
+
def execute_in_new_container(*command, interactive: false)
|
10
|
+
docker :run,
|
11
|
+
("-it" if interactive),
|
12
|
+
"--rm",
|
13
|
+
*role_config&.env_args,
|
14
|
+
*config.volume_args,
|
15
|
+
*role_config&.option_args,
|
16
|
+
config.absolute_image,
|
17
|
+
*command
|
18
|
+
end
|
19
|
+
|
20
|
+
def execute_in_existing_container_over_ssh(*command, host:)
|
21
|
+
run_over_ssh execute_in_existing_container(*command, interactive: true), host: host
|
22
|
+
end
|
23
|
+
|
24
|
+
def execute_in_new_container_over_ssh(*command, host:)
|
25
|
+
run_over_ssh execute_in_new_container(*command, interactive: true), host: host
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Kamal::Commands::App::Images
|
2
|
+
def list_images
|
3
|
+
docker :image, :ls, config.repository
|
4
|
+
end
|
5
|
+
|
6
|
+
def remove_images
|
7
|
+
docker :image, :prune, "--all", "--force", *filter_args
|
8
|
+
end
|
9
|
+
|
10
|
+
def tag_current_image_as_latest
|
11
|
+
docker :tag, config.absolute_image, config.latest_image
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Kamal::Commands::App::Logging
|
2
|
+
def logs(since: nil, lines: nil, grep: nil)
|
3
|
+
pipe \
|
4
|
+
current_running_container_id,
|
5
|
+
"xargs docker logs#{" --since #{since}" if since}#{" --tail #{lines}" if lines} 2>&1",
|
6
|
+
("grep '#{grep}'" if grep)
|
7
|
+
end
|
8
|
+
|
9
|
+
def follow_logs(host:, grep: nil)
|
10
|
+
run_over_ssh \
|
11
|
+
pipe(
|
12
|
+
current_running_container_id,
|
13
|
+
"xargs docker logs --timestamps --tail 10 --follow 2>&1",
|
14
|
+
(%(grep "#{grep}") if grep)
|
15
|
+
),
|
16
|
+
host: host
|
17
|
+
end
|
18
|
+
end
|
data/lib/kamal/commands/app.rb
CHANGED
@@ -1,34 +1,32 @@
|
|
1
1
|
class Kamal::Commands::App < Kamal::Commands::Base
|
2
|
+
include Assets, Containers, Cord, Execution, Images, Logging
|
3
|
+
|
2
4
|
ACTIVE_DOCKER_STATUSES = [ :running, :restarting ]
|
3
5
|
|
4
|
-
attr_reader :role
|
6
|
+
attr_reader :role, :role_config
|
5
7
|
|
6
8
|
def initialize(config, role: nil)
|
7
9
|
super(config)
|
8
10
|
@role = role
|
9
|
-
|
10
|
-
|
11
|
-
def start_or_run(hostname: nil)
|
12
|
-
combine start, run(hostname: hostname), by: "||"
|
11
|
+
@role_config = config.role(self.role)
|
13
12
|
end
|
14
13
|
|
15
14
|
def run(hostname: nil)
|
16
|
-
role = config.role(self.role)
|
17
|
-
|
18
15
|
docker :run,
|
19
16
|
"--detach",
|
20
17
|
"--restart unless-stopped",
|
21
18
|
"--name", container_name,
|
22
19
|
*(["--hostname", hostname] if hostname),
|
23
20
|
"-e", "KAMAL_CONTAINER_NAME=\"#{container_name}\"",
|
24
|
-
*
|
25
|
-
*
|
21
|
+
*role_config.env_args,
|
22
|
+
*role_config.health_check_args,
|
26
23
|
*config.logging_args,
|
27
24
|
*config.volume_args,
|
28
|
-
*
|
29
|
-
*
|
25
|
+
*role_config.asset_volume_args,
|
26
|
+
*role_config.label_args,
|
27
|
+
*role_config.option_args,
|
30
28
|
config.absolute_image,
|
31
|
-
|
29
|
+
role_config.cmd
|
32
30
|
end
|
33
31
|
|
34
32
|
def start
|
@@ -50,53 +48,6 @@ class Kamal::Commands::App < Kamal::Commands::Base
|
|
50
48
|
end
|
51
49
|
|
52
50
|
|
53
|
-
def logs(since: nil, lines: nil, grep: nil)
|
54
|
-
pipe \
|
55
|
-
current_running_container_id,
|
56
|
-
"xargs docker logs#{" --since #{since}" if since}#{" --tail #{lines}" if lines} 2>&1",
|
57
|
-
("grep '#{grep}'" if grep)
|
58
|
-
end
|
59
|
-
|
60
|
-
def follow_logs(host:, grep: nil)
|
61
|
-
run_over_ssh \
|
62
|
-
pipe(
|
63
|
-
current_running_container_id,
|
64
|
-
"xargs docker logs --timestamps --tail 10 --follow 2>&1",
|
65
|
-
(%(grep "#{grep}") if grep)
|
66
|
-
),
|
67
|
-
host: host
|
68
|
-
end
|
69
|
-
|
70
|
-
|
71
|
-
def execute_in_existing_container(*command, interactive: false)
|
72
|
-
docker :exec,
|
73
|
-
("-it" if interactive),
|
74
|
-
container_name,
|
75
|
-
*command
|
76
|
-
end
|
77
|
-
|
78
|
-
def execute_in_new_container(*command, interactive: false)
|
79
|
-
role = config.role(self.role)
|
80
|
-
|
81
|
-
docker :run,
|
82
|
-
("-it" if interactive),
|
83
|
-
"--rm",
|
84
|
-
*config.env_args,
|
85
|
-
*config.volume_args,
|
86
|
-
*role&.option_args,
|
87
|
-
config.absolute_image,
|
88
|
-
*command
|
89
|
-
end
|
90
|
-
|
91
|
-
def execute_in_existing_container_over_ssh(*command, host:)
|
92
|
-
run_over_ssh execute_in_existing_container(*command, interactive: true), host: host
|
93
|
-
end
|
94
|
-
|
95
|
-
def execute_in_new_container_over_ssh(*command, host:)
|
96
|
-
run_over_ssh execute_in_new_container(*command, interactive: true), host: host
|
97
|
-
end
|
98
|
-
|
99
|
-
|
100
51
|
def current_running_container_id
|
101
52
|
docker :ps, "--quiet", *filter_args(statuses: ACTIVE_DOCKER_STATUSES), "--latest"
|
102
53
|
end
|
@@ -112,47 +63,22 @@ class Kamal::Commands::App < Kamal::Commands::Base
|
|
112
63
|
def list_versions(*docker_args, statuses: nil)
|
113
64
|
pipe \
|
114
65
|
docker(:ps, *filter_args(statuses: statuses), *docker_args, "--format", '"{{.Names}}"'),
|
115
|
-
%(while read line; do echo ${line##{
|
116
|
-
end
|
117
|
-
|
118
|
-
def list_containers
|
119
|
-
docker :container, :ls, "--all", *filter_args
|
120
|
-
end
|
121
|
-
|
122
|
-
def list_container_names
|
123
|
-
[ *list_containers, "--format", "'{{ .Names }}'" ]
|
66
|
+
%(while read line; do echo ${line##{role_config.container_prefix}-}; done) # Extract SHA from "service-role-dest-SHA"
|
124
67
|
end
|
125
68
|
|
126
|
-
def remove_container(version:)
|
127
|
-
pipe \
|
128
|
-
container_id_for(container_name: container_name(version)),
|
129
|
-
xargs(docker(:container, :rm))
|
130
|
-
end
|
131
|
-
|
132
|
-
def rename_container(version:, new_version:)
|
133
|
-
docker :rename, container_name(version), container_name(new_version)
|
134
|
-
end
|
135
|
-
|
136
|
-
def remove_containers
|
137
|
-
docker :container, :prune, "--force", *filter_args
|
138
|
-
end
|
139
|
-
|
140
|
-
def list_images
|
141
|
-
docker :image, :ls, config.repository
|
142
|
-
end
|
143
69
|
|
144
|
-
def
|
145
|
-
|
70
|
+
def make_env_directory
|
71
|
+
make_directory role_config.host_env_directory
|
146
72
|
end
|
147
73
|
|
148
|
-
def
|
149
|
-
|
74
|
+
def remove_env_file
|
75
|
+
[ :rm, "-f", role_config.host_env_file_path ]
|
150
76
|
end
|
151
77
|
|
152
78
|
|
153
79
|
private
|
154
80
|
def container_name(version = nil)
|
155
|
-
[
|
81
|
+
[ role_config.container_prefix, version || config.version ].compact.join("-")
|
156
82
|
end
|
157
83
|
|
158
84
|
def filter_args(statuses: nil)
|
@@ -160,7 +86,7 @@ class Kamal::Commands::App < Kamal::Commands::Base
|
|
160
86
|
end
|
161
87
|
|
162
88
|
def service_role_dest
|
163
|
-
[config.service, role, config.destination].compact.join("-")
|
89
|
+
[ config.service, role, config.destination ].compact.join("-")
|
164
90
|
end
|
165
91
|
|
166
92
|
def filters(statuses: nil)
|
@@ -19,7 +19,9 @@ class Kamal::Commands::Auditor < Kamal::Commands::Base
|
|
19
19
|
|
20
20
|
private
|
21
21
|
def audit_log_file
|
22
|
-
[
|
22
|
+
file = [ config.service, config.destination, "audit.log" ].compact.join("-")
|
23
|
+
|
24
|
+
"#{config.run_directory}/#{file}"
|
23
25
|
end
|
24
26
|
|
25
27
|
def audit_tags(**details)
|
data/lib/kamal/commands/base.rb
CHANGED
@@ -26,6 +26,18 @@ module Kamal::Commands
|
|
26
26
|
docker :container, :ls, *("--all" unless only_running), "--filter", "name=^#{container_name}$", "--quiet"
|
27
27
|
end
|
28
28
|
|
29
|
+
def make_directory_for(remote_file)
|
30
|
+
make_directory Pathname.new(remote_file).dirname.to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
def make_directory(path)
|
34
|
+
[ :mkdir, "-p", path ]
|
35
|
+
end
|
36
|
+
|
37
|
+
def remove_directory(path)
|
38
|
+
[ :rm, "-r", path ]
|
39
|
+
end
|
40
|
+
|
29
41
|
private
|
30
42
|
def combine(*commands, by: "&&")
|
31
43
|
commands
|
@@ -21,6 +21,12 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
|
|
21
21
|
config.builder.context
|
22
22
|
end
|
23
23
|
|
24
|
+
def validate_image
|
25
|
+
pipe \
|
26
|
+
docker(:inspect, "-f", "'{{ .Config.Labels.service }}'", config.absolute_image),
|
27
|
+
[:grep, "-x", config.service, "||", "(echo \"Image #{config.absolute_image} is missing the `service` label\" && exit 1)"]
|
28
|
+
end
|
29
|
+
|
24
30
|
|
25
31
|
private
|
26
32
|
def build_tags
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require "active_support/core_ext/string/filters"
|
2
2
|
|
3
3
|
class Kamal::Commands::Builder < Kamal::Commands::Base
|
4
|
-
delegate :create, :remove, :push, :clean, :pull, :info, to: :target
|
4
|
+
delegate :create, :remove, :push, :clean, :pull, :info, :validate_image, to: :target
|
5
5
|
|
6
6
|
def name
|
7
7
|
target.class.to_s.remove("Kamal::Commands::Builder::").underscore.inquiry
|
@@ -1,5 +1,4 @@
|
|
1
1
|
class Kamal::Commands::Healthcheck < Kamal::Commands::Base
|
2
|
-
EXPOSED_PORT = 3999
|
3
2
|
|
4
3
|
def run
|
5
4
|
web = config.role(:web)
|
@@ -7,11 +6,11 @@ class Kamal::Commands::Healthcheck < Kamal::Commands::Base
|
|
7
6
|
docker :run,
|
8
7
|
"--detach",
|
9
8
|
"--name", container_name_with_version,
|
10
|
-
"--publish", "#{
|
11
|
-
"--label", "service=#{
|
12
|
-
"-e", "KAMAL_CONTAINER_NAME=\"#{
|
9
|
+
"--publish", "#{exposed_port}:#{config.healthcheck["port"]}",
|
10
|
+
"--label", "service=#{config.healthcheck_service}",
|
11
|
+
"-e", "KAMAL_CONTAINER_NAME=\"#{config.healthcheck_service}\"",
|
13
12
|
*web.env_args,
|
14
|
-
*web.health_check_args,
|
13
|
+
*web.health_check_args(cord: false),
|
15
14
|
*config.volume_args,
|
16
15
|
*web.option_args,
|
17
16
|
config.absolute_image,
|
@@ -27,7 +26,7 @@ class Kamal::Commands::Healthcheck < Kamal::Commands::Base
|
|
27
26
|
end
|
28
27
|
|
29
28
|
def logs
|
30
|
-
pipe container_id, xargs(docker(:logs, "--tail",
|
29
|
+
pipe container_id, xargs(docker(:logs, "--tail", log_lines, "2>&1"))
|
31
30
|
end
|
32
31
|
|
33
32
|
def stop
|
@@ -39,12 +38,8 @@ class Kamal::Commands::Healthcheck < Kamal::Commands::Base
|
|
39
38
|
end
|
40
39
|
|
41
40
|
private
|
42
|
-
def container_name
|
43
|
-
[ "healthcheck", config.service, config.destination ].compact.join("-")
|
44
|
-
end
|
45
|
-
|
46
41
|
def container_name_with_version
|
47
|
-
"#{
|
42
|
+
"#{config.healthcheck_service}-#{config.version}"
|
48
43
|
end
|
49
44
|
|
50
45
|
def container_id
|
@@ -52,6 +47,14 @@ class Kamal::Commands::Healthcheck < Kamal::Commands::Base
|
|
52
47
|
end
|
53
48
|
|
54
49
|
def health_url
|
55
|
-
"http://localhost:#{
|
50
|
+
"http://localhost:#{exposed_port}#{config.healthcheck["path"]}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def exposed_port
|
54
|
+
config.healthcheck["exposed_port"]
|
55
|
+
end
|
56
|
+
|
57
|
+
def log_lines
|
58
|
+
config.healthcheck["log_lines"]
|
56
59
|
end
|
57
60
|
end
|
data/lib/kamal/commands/lock.rb
CHANGED
@@ -40,7 +40,7 @@ class Kamal::Commands::Lock < Kamal::Commands::Base
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def lock_dir
|
43
|
-
"
|
43
|
+
"#{config.run_directory}/lock-#{config.service}"
|
44
44
|
end
|
45
45
|
|
46
46
|
def lock_details_file
|
@@ -56,7 +56,7 @@ class Kamal::Commands::Lock < Kamal::Commands::Base
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def locked_by
|
59
|
-
|
59
|
+
Kamal::Git.user_name
|
60
60
|
rescue Errno::ENOENT
|
61
61
|
"Unknown"
|
62
62
|
end
|
data/lib/kamal/commands/prune.rb
CHANGED
@@ -3,7 +3,7 @@ require "active_support/core_ext/numeric/time"
|
|
3
3
|
|
4
4
|
class Kamal::Commands::Prune < Kamal::Commands::Base
|
5
5
|
def dangling_images
|
6
|
-
docker :image, :prune, "--force", "--filter", "label=service=#{config.service}"
|
6
|
+
docker :image, :prune, "--force", "--filter", "label=service=#{config.service}"
|
7
7
|
end
|
8
8
|
|
9
9
|
def tagged_images
|
@@ -13,13 +13,17 @@ class Kamal::Commands::Prune < Kamal::Commands::Base
|
|
13
13
|
"while read image tag; do docker rmi $tag; done"
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
16
|
+
def app_containers(keep_last: 5)
|
17
17
|
pipe \
|
18
18
|
docker(:ps, "-q", "-a", *service_filter, *stopped_containers_filters),
|
19
19
|
"tail -n +#{keep_last + 1}",
|
20
20
|
"while read container_id; do docker rm $container_id; done"
|
21
21
|
end
|
22
22
|
|
23
|
+
def healthcheck_containers
|
24
|
+
docker :container, :prune, "--force", *healthcheck_service_filter
|
25
|
+
end
|
26
|
+
|
23
27
|
private
|
24
28
|
def stopped_containers_filters
|
25
29
|
[ "created", "exited", "dead" ].flat_map { |status| ["--filter", "status=#{status}"] }
|
@@ -35,4 +39,8 @@ class Kamal::Commands::Prune < Kamal::Commands::Base
|
|
35
39
|
def service_filter
|
36
40
|
[ "--filter", "label=service=#{config.service}" ]
|
37
41
|
end
|
38
|
-
|
42
|
+
|
43
|
+
def healthcheck_service_filter
|
44
|
+
[ "--filter", "label=service=#{config.healthcheck_service}" ]
|
45
|
+
end
|
46
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class Kamal::Commands::Traefik < Kamal::Commands::Base
|
2
|
-
delegate :argumentize, :
|
2
|
+
delegate :argumentize, :optionize, to: Kamal::Utils
|
3
3
|
|
4
4
|
DEFAULT_IMAGE = "traefik:v2.9"
|
5
5
|
CONTAINER_PORT = 80
|
@@ -63,6 +63,22 @@ class Kamal::Commands::Traefik < Kamal::Commands::Base
|
|
63
63
|
"#{host_port}:#{CONTAINER_PORT}"
|
64
64
|
end
|
65
65
|
|
66
|
+
def env_file
|
67
|
+
Kamal::EnvFile.new(config.traefik.fetch("env", {}))
|
68
|
+
end
|
69
|
+
|
70
|
+
def host_env_file_path
|
71
|
+
File.join host_env_directory, "traefik.env"
|
72
|
+
end
|
73
|
+
|
74
|
+
def make_env_directory
|
75
|
+
make_directory(host_env_directory)
|
76
|
+
end
|
77
|
+
|
78
|
+
def remove_env_file
|
79
|
+
[:rm, "-f", host_env_file_path]
|
80
|
+
end
|
81
|
+
|
66
82
|
private
|
67
83
|
def publish_args
|
68
84
|
argumentize "--publish", port unless config.traefik["publish"] == false
|
@@ -73,13 +89,11 @@ class Kamal::Commands::Traefik < Kamal::Commands::Base
|
|
73
89
|
end
|
74
90
|
|
75
91
|
def env_args
|
76
|
-
|
92
|
+
argumentize "--env-file", host_env_file_path
|
93
|
+
end
|
77
94
|
|
78
|
-
|
79
|
-
|
80
|
-
else
|
81
|
-
[]
|
82
|
-
end
|
95
|
+
def host_env_directory
|
96
|
+
File.join config.host_env_directory, "traefik"
|
83
97
|
end
|
84
98
|
|
85
99
|
def labels
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class Kamal::Configuration::Accessory
|
2
|
-
delegate :argumentize, :
|
2
|
+
delegate :argumentize, :optionize, to: Kamal::Utils
|
3
3
|
|
4
4
|
attr_accessor :name, :specifics
|
5
5
|
|
@@ -45,8 +45,20 @@ class Kamal::Configuration::Accessory
|
|
45
45
|
specifics["env"] || {}
|
46
46
|
end
|
47
47
|
|
48
|
+
def env_file
|
49
|
+
Kamal::EnvFile.new(env)
|
50
|
+
end
|
51
|
+
|
52
|
+
def host_env_directory
|
53
|
+
File.join config.host_env_directory, "accessories"
|
54
|
+
end
|
55
|
+
|
56
|
+
def host_env_file_path
|
57
|
+
File.join host_env_directory, "#{service_name}.env"
|
58
|
+
end
|
59
|
+
|
48
60
|
def env_args
|
49
|
-
|
61
|
+
argumentize "--env-file", host_env_file_path
|
50
62
|
end
|
51
63
|
|
52
64
|
def files
|
@@ -1,5 +1,6 @@
|
|
1
1
|
class Kamal::Configuration::Role
|
2
|
-
|
2
|
+
CORD_FILE = "cord"
|
3
|
+
delegate :argumentize, :optionize, to: Kamal::Utils
|
3
4
|
|
4
5
|
attr_accessor :name
|
5
6
|
|
@@ -15,6 +16,18 @@ class Kamal::Configuration::Role
|
|
15
16
|
@hosts ||= extract_hosts_from_config
|
16
17
|
end
|
17
18
|
|
19
|
+
def cmd
|
20
|
+
specializations["cmd"]
|
21
|
+
end
|
22
|
+
|
23
|
+
def option_args
|
24
|
+
if args = specializations["options"]
|
25
|
+
optionize args
|
26
|
+
else
|
27
|
+
[]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
18
31
|
def labels
|
19
32
|
default_labels.merge(traefik_labels).merge(custom_labels)
|
20
33
|
end
|
@@ -23,6 +36,7 @@ class Kamal::Configuration::Role
|
|
23
36
|
argumentize "--label", labels
|
24
37
|
end
|
25
38
|
|
39
|
+
|
26
40
|
def env
|
27
41
|
if config.env && config.env["secret"]
|
28
42
|
merged_env_with_secrets
|
@@ -31,46 +45,117 @@ class Kamal::Configuration::Role
|
|
31
45
|
end
|
32
46
|
end
|
33
47
|
|
48
|
+
def env_file
|
49
|
+
Kamal::EnvFile.new(env)
|
50
|
+
end
|
51
|
+
|
52
|
+
def host_env_directory
|
53
|
+
File.join config.host_env_directory, "roles"
|
54
|
+
end
|
55
|
+
|
56
|
+
def host_env_file_path
|
57
|
+
File.join host_env_directory, "#{[config.service, name, config.destination].compact.join("-")}.env"
|
58
|
+
end
|
59
|
+
|
34
60
|
def env_args
|
35
|
-
|
61
|
+
argumentize "--env-file", host_env_file_path
|
62
|
+
end
|
63
|
+
|
64
|
+
def asset_volume_args
|
65
|
+
asset_volume&.docker_args
|
36
66
|
end
|
37
67
|
|
38
|
-
|
68
|
+
|
69
|
+
def health_check_args(cord: true)
|
39
70
|
if health_check_cmd.present?
|
40
|
-
|
71
|
+
if cord && uses_cord?
|
72
|
+
optionize({ "health-cmd" => health_check_cmd_with_cord, "health-interval" => health_check_interval })
|
73
|
+
.concat(cord_volume.docker_args)
|
74
|
+
else
|
75
|
+
optionize({ "health-cmd" => health_check_cmd, "health-interval" => health_check_interval })
|
76
|
+
end
|
41
77
|
else
|
42
78
|
[]
|
43
79
|
end
|
44
80
|
end
|
45
81
|
|
46
82
|
def health_check_cmd
|
47
|
-
|
48
|
-
|
83
|
+
health_check_options["cmd"] || http_health_check(port: health_check_options["port"], path: health_check_options["path"])
|
84
|
+
end
|
49
85
|
|
50
|
-
|
86
|
+
def health_check_cmd_with_cord
|
87
|
+
"(#{health_check_cmd}) && (stat #{cord_container_file} > /dev/null || exit 1)"
|
51
88
|
end
|
52
89
|
|
53
90
|
def health_check_interval
|
54
|
-
|
55
|
-
|
91
|
+
health_check_options["interval"] || "1s"
|
92
|
+
end
|
93
|
+
|
56
94
|
|
57
|
-
|
95
|
+
def running_traefik?
|
96
|
+
name.web? || specializations["traefik"]
|
58
97
|
end
|
59
98
|
|
60
|
-
|
61
|
-
|
99
|
+
|
100
|
+
def uses_cord?
|
101
|
+
running_traefik? && cord_volume && health_check_cmd.present?
|
62
102
|
end
|
63
103
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
104
|
+
def cord_host_directory
|
105
|
+
File.join config.run_directory_as_docker_volume, "cords", [container_prefix, config.run_id].join("-")
|
106
|
+
end
|
107
|
+
|
108
|
+
def cord_volume
|
109
|
+
if (cord = health_check_options["cord"])
|
110
|
+
@cord_volume ||= Kamal::Configuration::Volume.new \
|
111
|
+
host_path: File.join(config.run_directory, "cords", [container_prefix, config.run_id].join("-")),
|
112
|
+
container_path: cord
|
69
113
|
end
|
70
114
|
end
|
71
115
|
|
72
|
-
def
|
73
|
-
|
116
|
+
def cord_host_file
|
117
|
+
File.join cord_volume.host_path, CORD_FILE
|
118
|
+
end
|
119
|
+
|
120
|
+
def cord_container_directory
|
121
|
+
health_check_options.fetch("cord", nil)
|
122
|
+
end
|
123
|
+
|
124
|
+
def cord_container_file
|
125
|
+
File.join cord_volume.container_path, CORD_FILE
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
def container_name(version = nil)
|
130
|
+
[ container_prefix, version || config.version ].compact.join("-")
|
131
|
+
end
|
132
|
+
|
133
|
+
def container_prefix
|
134
|
+
[ config.service, name, config.destination ].compact.join("-")
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
def asset_path
|
139
|
+
specializations["asset_path"] || config.asset_path
|
140
|
+
end
|
141
|
+
|
142
|
+
def assets?
|
143
|
+
asset_path.present? && running_traefik?
|
144
|
+
end
|
145
|
+
|
146
|
+
def asset_volume(version = nil)
|
147
|
+
if assets?
|
148
|
+
Kamal::Configuration::Volume.new \
|
149
|
+
host_path: asset_volume_path(version), container_path: asset_path
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def asset_extracted_path(version = nil)
|
154
|
+
File.join config.run_directory, "assets", "extracted", container_name(version)
|
155
|
+
end
|
156
|
+
|
157
|
+
def asset_volume_path(version = nil)
|
158
|
+
File.join config.run_directory, "assets", "volumes", container_name(version)
|
74
159
|
end
|
75
160
|
|
76
161
|
private
|
@@ -152,4 +237,12 @@ class Kamal::Configuration::Role
|
|
152
237
|
def http_health_check(port:, path:)
|
153
238
|
"curl -f #{URI.join("http://localhost:#{port}", path)} || exit 1" if path.present? || port.present?
|
154
239
|
end
|
240
|
+
|
241
|
+
def health_check_options
|
242
|
+
@health_check_options ||= begin
|
243
|
+
options = specializations["healthcheck"] || {}
|
244
|
+
options = config.healthcheck.merge(options) if running_traefik?
|
245
|
+
options
|
246
|
+
end
|
247
|
+
end
|
155
248
|
end
|
@@ -18,7 +18,7 @@ class Kamal::Configuration::Ssh
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def options
|
21
|
-
{ user: user, proxy: proxy,
|
21
|
+
{ user: user, proxy: proxy, logger: logger, keepalive: true, keepalive_interval: 30 }.compact
|
22
22
|
end
|
23
23
|
|
24
24
|
def to_h
|