kamal 2.4.0 → 2.5.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/lib/kamal/cli/accessory.rb +1 -1
- data/lib/kamal/cli/alias/command.rb +1 -0
- data/lib/kamal/cli/app.rb +15 -3
- data/lib/kamal/cli/base.rb +16 -1
- data/lib/kamal/cli/build.rb +36 -14
- data/lib/kamal/cli/main.rb +4 -3
- data/lib/kamal/cli/proxy.rb +2 -4
- data/lib/kamal/cli/registry.rb +2 -0
- data/lib/kamal/cli/templates/deploy.yml +2 -2
- data/lib/kamal/cli/templates/sample_hooks/post-app-boot.sample +3 -0
- data/lib/kamal/cli/templates/sample_hooks/pre-app-boot.sample +3 -0
- data/lib/kamal/cli.rb +1 -0
- data/lib/kamal/commander.rb +16 -25
- data/lib/kamal/commands/accessory.rb +1 -5
- data/lib/kamal/commands/app/assets.rb +4 -4
- data/lib/kamal/commands/base.rb +14 -0
- data/lib/kamal/commands/builder/base.rb +12 -5
- data/lib/kamal/commands/builder/cloud.rb +22 -0
- data/lib/kamal/commands/builder.rb +6 -20
- data/lib/kamal/commands/registry.rb +9 -7
- data/lib/kamal/configuration/accessory.rb +36 -19
- data/lib/kamal/configuration/builder.rb +4 -0
- data/lib/kamal/configuration/docs/accessory.yml +20 -1
- data/lib/kamal/configuration/docs/builder.yml +3 -0
- data/lib/kamal/configuration/registry.rb +6 -6
- data/lib/kamal/configuration/role.rb +6 -6
- data/lib/kamal/configuration/validator/role.rb +1 -1
- data/lib/kamal/configuration.rb +29 -12
- data/lib/kamal/docker.rb +30 -0
- data/lib/kamal/git.rb +10 -0
- data/lib/kamal/secrets/adapters/aws_secrets_manager.rb +12 -4
- data/lib/kamal/secrets/adapters/base.rb +5 -2
- data/lib/kamal/secrets/adapters/bitwarden.rb +2 -2
- data/lib/kamal/secrets/adapters/bitwarden_secrets_manager.rb +72 -0
- data/lib/kamal/secrets/adapters/doppler.rb +15 -11
- data/lib/kamal/secrets/adapters/enpass.rb +71 -0
- data/lib/kamal/secrets/adapters/gcp_secret_manager.rb +112 -0
- data/lib/kamal/secrets/adapters/last_pass.rb +3 -2
- data/lib/kamal/secrets/adapters/one_password.rb +2 -2
- data/lib/kamal/secrets/adapters/test.rb +2 -2
- data/lib/kamal/secrets/adapters.rb +2 -0
- data/lib/kamal/version.rb +1 -1
- metadata +10 -4
- data/lib/kamal/secrets/adapters/test_optional_account.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '01499d423cd415dea520fe78d0e5f17b0d67d3ef2d241e56abb84e2deaeb3f65'
|
4
|
+
data.tar.gz: 826b542e67f360b9d019d886a454fff796b73cda57b5e201edc2981e5059a1dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bbc7aa2632e0e5810666cb6d93ce698461fd3290dd5813c11bb88dd9faa4d6f7f015140c24a928b588df34316b814aec6ce710cbb4a28aa19713cc3420c15ae3
|
7
|
+
data.tar.gz: 2c818511055983038c9cbc9674a6f9c122de98296e27bf47441b02f3f9474176416e07cf1928bfc5b333648e51bb9ff4d857249173df82127e2ed29a124a97a7
|
data/lib/kamal/cli/accessory.rb
CHANGED
@@ -292,7 +292,7 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|
292
292
|
def prepare(name)
|
293
293
|
with_accessory(name) do |accessory, hosts|
|
294
294
|
on(hosts) do
|
295
|
-
execute *KAMAL.registry.login
|
295
|
+
execute *KAMAL.registry.login(registry_config: accessory.registry)
|
296
296
|
execute *KAMAL.docker.create_network
|
297
297
|
rescue SSHKit::Command::Failed => e
|
298
298
|
raise unless e.message.include?("already exists")
|
data/lib/kamal/cli/app.rb
CHANGED
@@ -16,10 +16,18 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|
16
16
|
# Primary hosts and roles are returned first, so they can open the barrier
|
17
17
|
barrier = Kamal::Cli::Healthcheck::Barrier.new
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
host_boot_groups.each do |hosts|
|
20
|
+
host_list = Array(hosts).join(",")
|
21
|
+
run_hook "pre-app-boot", hosts: host_list
|
22
|
+
|
23
|
+
on(hosts) do |host|
|
24
|
+
KAMAL.roles_on(host).each do |role|
|
25
|
+
Kamal::Cli::App::Boot.new(host, role, self, version, barrier).run
|
26
|
+
end
|
22
27
|
end
|
28
|
+
|
29
|
+
run_hook "post-app-boot", hosts: host_list
|
30
|
+
sleep KAMAL.config.boot.wait if KAMAL.config.boot.wait
|
23
31
|
end
|
24
32
|
|
25
33
|
# Tag once the app booted on all hosts
|
@@ -340,4 +348,8 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|
340
348
|
yield
|
341
349
|
end
|
342
350
|
end
|
351
|
+
|
352
|
+
def host_boot_groups
|
353
|
+
KAMAL.config.boot.limit ? KAMAL.hosts.each_slice(KAMAL.config.boot.limit).to_a : [ KAMAL.hosts ]
|
354
|
+
end
|
343
355
|
end
|
data/lib/kamal/cli/base.rb
CHANGED
@@ -5,7 +5,7 @@ module Kamal::Cli
|
|
5
5
|
class Base < Thor
|
6
6
|
include SSHKit::DSL
|
7
7
|
|
8
|
-
def self.exit_on_failure?()
|
8
|
+
def self.exit_on_failure?() true end
|
9
9
|
def self.dynamic_command_class() Kamal::Cli::Alias::Command end
|
10
10
|
|
11
11
|
class_option :verbose, type: :boolean, aliases: "-v", desc: "Detailed logging"
|
@@ -30,6 +30,7 @@ module Kamal::Cli
|
|
30
30
|
else
|
31
31
|
super
|
32
32
|
end
|
33
|
+
|
33
34
|
initialize_commander unless KAMAL.configured?
|
34
35
|
end
|
35
36
|
|
@@ -194,5 +195,19 @@ module Kamal::Cli
|
|
194
195
|
ENV.clear
|
195
196
|
ENV.update(current_env)
|
196
197
|
end
|
198
|
+
|
199
|
+
def ensure_docker_installed
|
200
|
+
run_locally do
|
201
|
+
begin
|
202
|
+
execute *KAMAL.builder.ensure_docker_installed
|
203
|
+
rescue SSHKit::Command::Failed => e
|
204
|
+
error = e.message =~ /command not found/ ?
|
205
|
+
"Docker is not installed locally" :
|
206
|
+
"Docker buildx plugin is not installed locally"
|
207
|
+
|
208
|
+
raise DependencyError, error
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
197
212
|
end
|
198
213
|
end
|
data/lib/kamal/cli/build.rb
CHANGED
@@ -5,15 +5,16 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|
5
5
|
|
6
6
|
desc "deliver", "Build app and push app image to registry then pull image on servers"
|
7
7
|
def deliver
|
8
|
-
push
|
9
|
-
pull
|
8
|
+
invoke :push
|
9
|
+
invoke :pull
|
10
10
|
end
|
11
11
|
|
12
12
|
desc "push", "Build and push app image to registry"
|
13
|
+
option :output, type: :string, default: "registry", banner: "export_type", desc: "Exported type for the build result, and may be any exported type supported by 'buildx --output'."
|
13
14
|
def push
|
14
15
|
cli = self
|
15
16
|
|
16
|
-
|
17
|
+
ensure_docker_installed
|
17
18
|
run_hook "pre-build"
|
18
19
|
|
19
20
|
uncommitted_changes = Kamal::Git.uncommitted_changes
|
@@ -49,7 +50,7 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|
49
50
|
end
|
50
51
|
|
51
52
|
# Get the command here to ensure the Dir.chdir doesn't interfere with it
|
52
|
-
push = KAMAL.builder.push
|
53
|
+
push = KAMAL.builder.push(cli.options[:output])
|
53
54
|
|
54
55
|
KAMAL.with_verbosity(:debug) do
|
55
56
|
Dir.chdir(KAMAL.config.builder.build_directory) { execute *push }
|
@@ -108,21 +109,42 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|
108
109
|
end
|
109
110
|
end
|
110
111
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
112
|
+
desc "dev", "Build using the working directory, tag it as dirty, and push to local image store."
|
113
|
+
option :output, type: :string, default: "docker", banner: "export_type", desc: "Exported type for the build result, and may be any exported type supported by 'buildx --output'."
|
114
|
+
def dev
|
115
|
+
cli = self
|
116
|
+
|
117
|
+
ensure_docker_installed
|
118
|
+
|
119
|
+
docker_included_files = Set.new(Kamal::Docker.included_files)
|
120
|
+
git_uncommitted_files = Set.new(Kamal::Git.uncommitted_files)
|
121
|
+
git_untracked_files = Set.new(Kamal::Git.untracked_files)
|
122
|
+
|
123
|
+
docker_uncommitted_files = docker_included_files & git_uncommitted_files
|
124
|
+
if docker_uncommitted_files.any?
|
125
|
+
say "WARNING: Files with uncommitted changes will be present in the dev container:", :yellow
|
126
|
+
docker_uncommitted_files.sort.each { |f| say " #{f}", :yellow }
|
127
|
+
say
|
128
|
+
end
|
129
|
+
|
130
|
+
docker_untracked_files = docker_included_files & git_untracked_files
|
131
|
+
if docker_untracked_files.any?
|
132
|
+
say "WARNING: Untracked files will be present in the dev container:", :yellow
|
133
|
+
docker_untracked_files.sort.each { |f| say " #{f}", :yellow }
|
134
|
+
say
|
135
|
+
end
|
120
136
|
|
121
|
-
|
137
|
+
with_env(KAMAL.config.builder.secrets) do
|
138
|
+
run_locally do
|
139
|
+
build = KAMAL.builder.push(cli.options[:output], tag_as_dirty: true)
|
140
|
+
KAMAL.with_verbosity(:debug) do
|
141
|
+
execute(*build)
|
122
142
|
end
|
123
143
|
end
|
124
144
|
end
|
145
|
+
end
|
125
146
|
|
147
|
+
private
|
126
148
|
def connect_to_remote_host(remote_host)
|
127
149
|
remote_uri = URI.parse(remote_host)
|
128
150
|
if remote_uri.scheme == "ssh"
|
data/lib/kamal/cli/main.rb
CHANGED
@@ -9,15 +9,14 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
9
9
|
say "Ensure Docker is installed...", :magenta
|
10
10
|
invoke "kamal:cli:server:bootstrap", [], invoke_options
|
11
11
|
|
12
|
-
|
13
|
-
deploy
|
12
|
+
deploy(boot_accessories: true)
|
14
13
|
end
|
15
14
|
end
|
16
15
|
end
|
17
16
|
|
18
17
|
desc "deploy", "Deploy app to servers"
|
19
18
|
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
20
|
-
def deploy
|
19
|
+
def deploy(boot_accessories: false)
|
21
20
|
runtime = print_runtime do
|
22
21
|
invoke_options = deploy_options
|
23
22
|
|
@@ -38,6 +37,8 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
38
37
|
say "Ensure kamal-proxy is running...", :magenta
|
39
38
|
invoke "kamal:cli:proxy:boot", [], invoke_options
|
40
39
|
|
40
|
+
invoke "kamal:cli:accessory:boot", [ "all" ], invoke_options if boot_accessories
|
41
|
+
|
41
42
|
say "Detect stale containers...", :magenta
|
42
43
|
invoke "kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true)
|
43
44
|
|
data/lib/kamal/cli/proxy.rb
CHANGED
@@ -23,6 +23,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
23
23
|
|
24
24
|
desc "boot_config <set|get|reset>", "Manage kamal-proxy boot configuration"
|
25
25
|
option :publish, type: :boolean, default: true, desc: "Publish the proxy ports on the host"
|
26
|
+
option :publish_host_ip, type: :string, repeatable: true, default: nil, desc: "Host IP address to bind HTTP/HTTPS traffic to. Defaults to all interfaces"
|
26
27
|
option :http_port, type: :numeric, default: Kamal::Configuration::PROXY_HTTP_PORT, desc: "HTTP port to publish on the host"
|
27
28
|
option :https_port, type: :numeric, default: Kamal::Configuration::PROXY_HTTPS_PORT, desc: "HTTPS port to publish on the host"
|
28
29
|
option :log_max_size, type: :string, default: Kamal::Configuration::PROXY_LOG_MAX_SIZE, desc: "Max size of proxy logs"
|
@@ -31,7 +32,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
31
32
|
case subcommand
|
32
33
|
when "set"
|
33
34
|
boot_options = [
|
34
|
-
*(KAMAL.config.proxy_publish_args(options[:http_port], options[:https_port]) if options[:publish]),
|
35
|
+
*(KAMAL.config.proxy_publish_args(options[:http_port], options[:https_port], options[:publish_host_ip]) if options[:publish]),
|
35
36
|
*(KAMAL.config.proxy_logging_args(options[:log_max_size])),
|
36
37
|
*options[:docker_options].map { |option| "--#{option}" }
|
37
38
|
]
|
@@ -67,9 +68,6 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
67
68
|
execute *KAMAL.auditor.record("Rebooted proxy"), verbosity: :debug
|
68
69
|
execute *KAMAL.registry.login
|
69
70
|
|
70
|
-
"Stopping and removing Traefik on #{host}, if running..."
|
71
|
-
execute *KAMAL.proxy.cleanup_traefik
|
72
|
-
|
73
71
|
"Stopping and removing kamal-proxy on #{host}, if running..."
|
74
72
|
execute *KAMAL.proxy.stop, raise_on_non_zero_exit: false
|
75
73
|
execute *KAMAL.proxy.remove_container
|
data/lib/kamal/cli/registry.rb
CHANGED
@@ -3,6 +3,8 @@ class Kamal::Cli::Registry < Kamal::Cli::Base
|
|
3
3
|
option :skip_local, aliases: "-L", type: :boolean, default: false, desc: "Skip local login"
|
4
4
|
option :skip_remote, aliases: "-R", type: :boolean, default: false, desc: "Skip remote login"
|
5
5
|
def login
|
6
|
+
ensure_docker_installed
|
7
|
+
|
6
8
|
run_locally { execute *KAMAL.registry.login } unless options[:skip_local]
|
7
9
|
on(KAMAL.hosts) { execute *KAMAL.registry.login } unless options[:skip_remote]
|
8
10
|
end
|
@@ -38,7 +38,7 @@ builder:
|
|
38
38
|
arch: amd64
|
39
39
|
# Pass in additional build args needed for your Dockerfile.
|
40
40
|
# args:
|
41
|
-
# RUBY_VERSION: <%=
|
41
|
+
# RUBY_VERSION: <%= ENV["RBENV_VERSION"] || ENV["rvm_ruby_string"] || "#{RUBY_ENGINE}-#{RUBY_ENGINE_VERSION}" %>
|
42
42
|
|
43
43
|
# Inject ENV variables into containers (secrets come from .kamal/secrets).
|
44
44
|
#
|
@@ -49,7 +49,7 @@ builder:
|
|
49
49
|
# - RAILS_MASTER_KEY
|
50
50
|
|
51
51
|
# Aliases are triggered with "bin/kamal <alias>". You can overwrite arguments on invocation:
|
52
|
-
# "bin/kamal logs -r job" will tail logs from the first server in the job section.
|
52
|
+
# "bin/kamal app logs -r job" will tail logs from the first server in the job section.
|
53
53
|
#
|
54
54
|
# aliases:
|
55
55
|
# shell: app exec --interactive --reuse "bash"
|
data/lib/kamal/cli.rb
CHANGED
data/lib/kamal/commander.rb
CHANGED
@@ -4,13 +4,20 @@ require "active_support/core_ext/object/blank"
|
|
4
4
|
|
5
5
|
class Kamal::Commander
|
6
6
|
attr_accessor :verbosity, :holding_lock, :connected
|
7
|
+
attr_reader :specific_roles, :specific_hosts
|
7
8
|
delegate :hosts, :roles, :primary_host, :primary_role, :roles_on, :proxy_hosts, :accessory_hosts, to: :specifics
|
8
9
|
|
9
10
|
def initialize
|
11
|
+
reset
|
12
|
+
end
|
13
|
+
|
14
|
+
def reset
|
10
15
|
self.verbosity = :info
|
11
16
|
self.holding_lock = false
|
12
17
|
self.connected = false
|
13
|
-
@specifics = nil
|
18
|
+
@specifics = @specific_roles = @specific_hosts = nil
|
19
|
+
@config = @config_kwargs = nil
|
20
|
+
@commands = {}
|
14
21
|
end
|
15
22
|
|
16
23
|
def config
|
@@ -28,8 +35,6 @@ class Kamal::Commander
|
|
28
35
|
@config || @config_kwargs
|
29
36
|
end
|
30
37
|
|
31
|
-
attr_reader :specific_roles, :specific_hosts
|
32
|
-
|
33
38
|
def specific_primary!
|
34
39
|
@specifics = nil
|
35
40
|
if specific_roles.present?
|
@@ -76,11 +81,6 @@ class Kamal::Commander
|
|
76
81
|
config.accessories&.collect(&:name) || []
|
77
82
|
end
|
78
83
|
|
79
|
-
def accessories_on(host)
|
80
|
-
config.accessories.select { |accessory| accessory.hosts.include?(host.to_s) }.map(&:name)
|
81
|
-
end
|
82
|
-
|
83
|
-
|
84
84
|
def app(role: nil, host: nil)
|
85
85
|
Kamal::Commands::App.new(config, role: role, host: host)
|
86
86
|
end
|
@@ -94,42 +94,41 @@ class Kamal::Commander
|
|
94
94
|
end
|
95
95
|
|
96
96
|
def builder
|
97
|
-
@builder ||= Kamal::Commands::Builder.new(config)
|
97
|
+
@commands[:builder] ||= Kamal::Commands::Builder.new(config)
|
98
98
|
end
|
99
99
|
|
100
100
|
def docker
|
101
|
-
@docker ||= Kamal::Commands::Docker.new(config)
|
101
|
+
@commands[:docker] ||= Kamal::Commands::Docker.new(config)
|
102
102
|
end
|
103
103
|
|
104
104
|
def hook
|
105
|
-
@hook ||= Kamal::Commands::Hook.new(config)
|
105
|
+
@commands[:hook] ||= Kamal::Commands::Hook.new(config)
|
106
106
|
end
|
107
107
|
|
108
108
|
def lock
|
109
|
-
@lock ||= Kamal::Commands::Lock.new(config)
|
109
|
+
@commands[:lock] ||= Kamal::Commands::Lock.new(config)
|
110
110
|
end
|
111
111
|
|
112
112
|
def proxy
|
113
|
-
@proxy ||= Kamal::Commands::Proxy.new(config)
|
113
|
+
@commands[:proxy] ||= Kamal::Commands::Proxy.new(config)
|
114
114
|
end
|
115
115
|
|
116
116
|
def prune
|
117
|
-
@prune ||= Kamal::Commands::Prune.new(config)
|
117
|
+
@commands[:prune] ||= Kamal::Commands::Prune.new(config)
|
118
118
|
end
|
119
119
|
|
120
120
|
def registry
|
121
|
-
@registry ||= Kamal::Commands::Registry.new(config)
|
121
|
+
@commands[:registry] ||= Kamal::Commands::Registry.new(config)
|
122
122
|
end
|
123
123
|
|
124
124
|
def server
|
125
|
-
@server ||= Kamal::Commands::Server.new(config)
|
125
|
+
@commands[:server] ||= Kamal::Commands::Server.new(config)
|
126
126
|
end
|
127
127
|
|
128
128
|
def alias(name)
|
129
129
|
config.aliases[name]
|
130
130
|
end
|
131
131
|
|
132
|
-
|
133
132
|
def with_verbosity(level)
|
134
133
|
old_level = self.verbosity
|
135
134
|
|
@@ -142,14 +141,6 @@ class Kamal::Commander
|
|
142
141
|
SSHKit.config.output_verbosity = old_level
|
143
142
|
end
|
144
143
|
|
145
|
-
def boot_strategy
|
146
|
-
if config.boot.limit.present?
|
147
|
-
{ in: :groups, limit: config.boot.limit, wait: config.boot.wait }
|
148
|
-
else
|
149
|
-
{}
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
144
|
def holding_lock?
|
154
145
|
self.holding_lock
|
155
146
|
end
|
@@ -4,11 +4,10 @@ class Kamal::Commands::Accessory < Kamal::Commands::Base
|
|
4
4
|
attr_reader :accessory_config
|
5
5
|
delegate :service_name, :image, :hosts, :port, :files, :directories, :cmd,
|
6
6
|
:network_args, :publish_args, :env_args, :volume_args, :label_args, :option_args,
|
7
|
-
:secrets_io, :secrets_path, :env_directory, :proxy, :running_proxy?,
|
7
|
+
:secrets_io, :secrets_path, :env_directory, :proxy, :running_proxy?, :registry,
|
8
8
|
to: :accessory_config
|
9
9
|
delegate :proxy_container_name, to: :config
|
10
10
|
|
11
|
-
|
12
11
|
def initialize(config, name:)
|
13
12
|
super(config)
|
14
13
|
@accessory_config = config.accessory(name)
|
@@ -42,7 +41,6 @@ class Kamal::Commands::Accessory < Kamal::Commands::Base
|
|
42
41
|
docker :ps, *service_filter
|
43
42
|
end
|
44
43
|
|
45
|
-
|
46
44
|
def logs(timestamps: true, since: nil, lines: nil, grep: nil, grep_options: nil)
|
47
45
|
pipe \
|
48
46
|
docker(:logs, service_name, (" --since #{since}" if since), (" --tail #{lines}" if lines), ("--timestamps" if timestamps), "2>&1"),
|
@@ -56,7 +54,6 @@ class Kamal::Commands::Accessory < Kamal::Commands::Base
|
|
56
54
|
(%(grep "#{grep}"#{" #{grep_options}" if grep_options}) if grep)
|
57
55
|
end
|
58
56
|
|
59
|
-
|
60
57
|
def execute_in_existing_container(*command, interactive: false)
|
61
58
|
docker :exec,
|
62
59
|
("-it" if interactive),
|
@@ -87,7 +84,6 @@ class Kamal::Commands::Accessory < Kamal::Commands::Base
|
|
87
84
|
super command, host: hosts.first
|
88
85
|
end
|
89
86
|
|
90
|
-
|
91
87
|
def ensure_local_file_present(local_file)
|
92
88
|
if !local_file.is_a?(StringIO) && !Pathname.new(local_file).exist?
|
93
89
|
raise "Missing file: #{local_file}"
|
@@ -4,10 +4,10 @@ module Kamal::Commands::App::Assets
|
|
4
4
|
|
5
5
|
combine \
|
6
6
|
make_directory(role.asset_extracted_directory),
|
7
|
-
[ *docker(:
|
8
|
-
docker(:
|
9
|
-
docker(:cp, "-L", "#{asset_container}:#{role.asset_path}/.", role.asset_extracted_directory),
|
10
|
-
docker(:
|
7
|
+
[ *docker(:container, :rm, asset_container, "2> /dev/null"), "|| true" ],
|
8
|
+
docker(:container, :create, "--name", asset_container, config.absolute_image),
|
9
|
+
docker(:container, :cp, "-L", "#{asset_container}:#{role.asset_path}/.", role.asset_extracted_directory),
|
10
|
+
docker(:container, :rm, asset_container),
|
11
11
|
by: "&&"
|
12
12
|
end
|
13
13
|
|
data/lib/kamal/commands/base.rb
CHANGED
@@ -34,6 +34,12 @@ module Kamal::Commands
|
|
34
34
|
[ :rm, path ]
|
35
35
|
end
|
36
36
|
|
37
|
+
def ensure_docker_installed
|
38
|
+
combine \
|
39
|
+
ensure_local_docker_installed,
|
40
|
+
ensure_local_buildx_installed
|
41
|
+
end
|
42
|
+
|
37
43
|
private
|
38
44
|
def combine(*commands, by: "&&")
|
39
45
|
commands
|
@@ -104,5 +110,13 @@ module Kamal::Commands
|
|
104
110
|
" -i #{key}"
|
105
111
|
end
|
106
112
|
end
|
113
|
+
|
114
|
+
def ensure_local_docker_installed
|
115
|
+
docker "--version"
|
116
|
+
end
|
117
|
+
|
118
|
+
def ensure_local_buildx_installed
|
119
|
+
docker :buildx, "version"
|
120
|
+
end
|
107
121
|
end
|
108
122
|
end
|
@@ -13,11 +13,12 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
|
|
13
13
|
docker :image, :rm, "--force", config.absolute_image
|
14
14
|
end
|
15
15
|
|
16
|
-
def push
|
16
|
+
def push(export_action = "registry", tag_as_dirty: false)
|
17
17
|
docker :buildx, :build,
|
18
|
-
"--
|
18
|
+
"--output=type=#{export_action}",
|
19
19
|
*platform_options(arches),
|
20
20
|
*([ "--builder", builder_name ] unless docker_driver?),
|
21
|
+
*build_tag_options(tag_as_dirty: tag_as_dirty),
|
21
22
|
*build_options,
|
22
23
|
build_context
|
23
24
|
end
|
@@ -37,7 +38,7 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
|
|
37
38
|
end
|
38
39
|
|
39
40
|
def build_options
|
40
|
-
[ *
|
41
|
+
[ *build_cache, *build_labels, *build_args, *build_secrets, *build_dockerfile, *build_target, *build_ssh, *builder_provenance, *builder_sbom ]
|
41
42
|
end
|
42
43
|
|
43
44
|
def build_context
|
@@ -58,8 +59,14 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
|
|
58
59
|
end
|
59
60
|
|
60
61
|
private
|
61
|
-
def
|
62
|
-
[
|
62
|
+
def build_tag_names(tag_as_dirty: false)
|
63
|
+
tag_names = [ config.absolute_image, config.latest_image ]
|
64
|
+
tag_names.map! { |t| "#{t}-dirty" } if tag_as_dirty
|
65
|
+
tag_names
|
66
|
+
end
|
67
|
+
|
68
|
+
def build_tag_options(tag_as_dirty: false)
|
69
|
+
build_tag_names(tag_as_dirty: tag_as_dirty).flat_map { |name| [ "-t", name ] }
|
63
70
|
end
|
64
71
|
|
65
72
|
def build_cache
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Kamal::Commands::Builder::Cloud < Kamal::Commands::Builder::Base
|
2
|
+
# Expects `driver` to be of format "cloud docker-org-name/builder-name"
|
3
|
+
|
4
|
+
def create
|
5
|
+
docker :buildx, :create, "--driver", driver
|
6
|
+
end
|
7
|
+
|
8
|
+
def remove
|
9
|
+
docker :buildx, :rm, builder_name
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def builder_name
|
14
|
+
driver.gsub(/[ \/]/, "-")
|
15
|
+
end
|
16
|
+
|
17
|
+
def inspect_buildx
|
18
|
+
pipe \
|
19
|
+
docker(:buildx, :inspect, builder_name),
|
20
|
+
grep("-q", "Endpoint:.*cloud://.*")
|
21
|
+
end
|
22
|
+
end
|
@@ -1,8 +1,8 @@
|
|
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, :inspect_builder, :validate_image, :first_mirror, to: :target
|
5
|
-
delegate :local?, :remote?, to: "config.builder"
|
4
|
+
delegate :create, :remove, :dev, :push, :clean, :pull, :info, :inspect_builder, :validate_image, :first_mirror, to: :target
|
5
|
+
delegate :local?, :remote?, :cloud?, to: "config.builder"
|
6
6
|
|
7
7
|
include Clone
|
8
8
|
|
@@ -17,6 +17,8 @@ class Kamal::Commands::Builder < Kamal::Commands::Base
|
|
17
17
|
else
|
18
18
|
remote
|
19
19
|
end
|
20
|
+
elsif cloud?
|
21
|
+
cloud
|
20
22
|
else
|
21
23
|
local
|
22
24
|
end
|
@@ -34,23 +36,7 @@ class Kamal::Commands::Builder < Kamal::Commands::Base
|
|
34
36
|
@hybrid ||= Kamal::Commands::Builder::Hybrid.new(config)
|
35
37
|
end
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
-
if name.native?
|
40
|
-
ensure_local_docker_installed
|
41
|
-
else
|
42
|
-
combine \
|
43
|
-
ensure_local_docker_installed,
|
44
|
-
ensure_local_buildx_installed
|
45
|
-
end
|
39
|
+
def cloud
|
40
|
+
@cloud ||= Kamal::Commands::Builder::Cloud.new(config)
|
46
41
|
end
|
47
|
-
|
48
|
-
private
|
49
|
-
def ensure_local_docker_installed
|
50
|
-
docker "--version"
|
51
|
-
end
|
52
|
-
|
53
|
-
def ensure_local_buildx_installed
|
54
|
-
docker :buildx, "version"
|
55
|
-
end
|
56
42
|
end
|
@@ -1,14 +1,16 @@
|
|
1
1
|
class Kamal::Commands::Registry < Kamal::Commands::Base
|
2
|
-
|
2
|
+
def login(registry_config: nil)
|
3
|
+
registry_config ||= config.registry
|
3
4
|
|
4
|
-
def login
|
5
5
|
docker :login,
|
6
|
-
|
7
|
-
"-u", sensitive(Kamal::Utils.escape_shell_value(
|
8
|
-
"-p", sensitive(Kamal::Utils.escape_shell_value(
|
6
|
+
registry_config.server,
|
7
|
+
"-u", sensitive(Kamal::Utils.escape_shell_value(registry_config.username)),
|
8
|
+
"-p", sensitive(Kamal::Utils.escape_shell_value(registry_config.password))
|
9
9
|
end
|
10
10
|
|
11
|
-
def logout
|
12
|
-
|
11
|
+
def logout(registry_config: nil)
|
12
|
+
registry_config ||= config.registry
|
13
|
+
|
14
|
+
docker :logout, registry_config.server
|
13
15
|
end
|
14
16
|
end
|