kamal 1.8.2 → 2.0.0.alpha
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/alias/command.rb +9 -0
- data/lib/kamal/cli/app.rb +3 -2
- data/lib/kamal/cli/base.rb +10 -3
- data/lib/kamal/cli/build.rb +5 -11
- data/lib/kamal/cli/server.rb +2 -1
- data/lib/kamal/cli/templates/deploy.yml +4 -10
- data/lib/kamal/commander.rb +9 -1
- data/lib/kamal/commands/builder/base.rb +27 -10
- data/lib/kamal/commands/builder/hybrid.rb +21 -0
- data/lib/kamal/commands/builder/local.rb +14 -0
- data/lib/kamal/commands/builder/remote.rb +40 -0
- data/lib/kamal/commands/builder.rb +13 -29
- data/lib/kamal/configuration/alias.rb +15 -0
- data/lib/kamal/configuration/builder.rb +47 -19
- data/lib/kamal/configuration/docs/alias.yml +26 -0
- data/lib/kamal/configuration/docs/builder.yml +15 -22
- data/lib/kamal/configuration/docs/configuration.yml +6 -0
- data/lib/kamal/configuration/validator/alias.rb +15 -0
- data/lib/kamal/configuration/validator/builder.rb +2 -0
- data/lib/kamal/configuration/validator.rb +40 -24
- data/lib/kamal/configuration.rb +2 -1
- data/lib/kamal/utils.rb +16 -0
- data/lib/kamal/version.rb +1 -1
- metadata +12 -10
- data/lib/kamal/commands/builder/multiarch/remote.rb +0 -61
- data/lib/kamal/commands/builder/multiarch.rb +0 -41
- data/lib/kamal/commands/builder/native/cached.rb +0 -25
- data/lib/kamal/commands/builder/native/remote.rb +0 -67
- data/lib/kamal/commands/builder/native.rb +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4df682847a5becbc623450203537d42aa29fb4b001026a6b39ab266913660d4d
|
4
|
+
data.tar.gz: 97ceb4c375f99605f1d874637273168f7274e95c615611d1d324cb0d635523e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 619e959821a7bd1590f0dcf6d3d3956e02c0832a51528b8f15d655ddcfe636a29a6c82fd0080a2d7d3104437368c63f607fd2f61623f230e547693a4accf65ea
|
7
|
+
data.tar.gz: 1733b8db747dd71b1cb41ef7ca359856af278e5fb7ef29b0ed0cb677f67cdc82039246fb836bfd7c4260e992830f9a309315d5f98e83dcc3a2a7c5a2656e47a3
|
data/lib/kamal/cli/app.rb
CHANGED
@@ -71,11 +71,12 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
-
desc "exec [CMD]", "Execute a custom command on servers within the app container (use --help to show options)"
|
74
|
+
desc "exec [CMD...]", "Execute a custom command on servers within the app container (use --help to show options)"
|
75
75
|
option :interactive, aliases: "-i", type: :boolean, default: false, desc: "Execute command over ssh for an interactive shell (use for console/bash)"
|
76
76
|
option :reuse, type: :boolean, default: false, desc: "Reuse currently running container instead of starting a new one"
|
77
77
|
option :env, aliases: "-e", type: :hash, desc: "Set environment variables for the command"
|
78
|
-
def exec(cmd)
|
78
|
+
def exec(*cmd)
|
79
|
+
cmd = Kamal::Utils.join_commands(cmd)
|
79
80
|
env = options[:env]
|
80
81
|
case
|
81
82
|
when options[:interactive] && options[:reuse]
|
data/lib/kamal/cli/base.rb
CHANGED
@@ -6,7 +6,8 @@ module Kamal::Cli
|
|
6
6
|
class Base < Thor
|
7
7
|
include SSHKit::DSL
|
8
8
|
|
9
|
-
def self.exit_on_failure?()
|
9
|
+
def self.exit_on_failure?() false end
|
10
|
+
def self.dynamic_command_class() Kamal::Cli::Alias::Command end
|
10
11
|
|
11
12
|
class_option :verbose, type: :boolean, aliases: "-v", desc: "Detailed logging"
|
12
13
|
class_option :quiet, type: :boolean, aliases: "-q", desc: "Minimal logging"
|
@@ -22,8 +23,14 @@ module Kamal::Cli
|
|
22
23
|
|
23
24
|
class_option :skip_hooks, aliases: "-H", type: :boolean, default: false, desc: "Don't run hooks"
|
24
25
|
|
25
|
-
def initialize(
|
26
|
-
|
26
|
+
def initialize(args = [], local_options = {}, config = {})
|
27
|
+
if config[:current_command].is_a?(Kamal::Cli::Alias::Command)
|
28
|
+
# When Thor generates a dynamic command, it doesn't attempt to parse the arguments.
|
29
|
+
# For our purposes, it means the arguments are passed in args rather than local_options.
|
30
|
+
super([], args, config)
|
31
|
+
else
|
32
|
+
super
|
33
|
+
end
|
27
34
|
@original_env = ENV.to_h.dup
|
28
35
|
load_env
|
29
36
|
initialize_commander(options_with_subcommand_class_options)
|
data/lib/kamal/cli/build.rb
CHANGED
@@ -30,18 +30,9 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|
30
30
|
say "Building with uncommitted changes:\n #{uncommitted_changes}", :yellow
|
31
31
|
end
|
32
32
|
|
33
|
-
# Get the command here to ensure the Dir.chdir doesn't interfere with it
|
34
|
-
push = KAMAL.builder.push
|
35
|
-
|
36
33
|
run_locally do
|
37
34
|
begin
|
38
|
-
|
39
|
-
|
40
|
-
if context_hosts != KAMAL.builder.config_context_hosts
|
41
|
-
warn "Context hosts have changed, so re-creating builder, was: #{context_hosts.join(", ")}], now: #{KAMAL.builder.config_context_hosts.join(", ")}"
|
42
|
-
cli.remove
|
43
|
-
cli.create
|
44
|
-
end
|
35
|
+
execute *KAMAL.builder.buildx_inspect
|
45
36
|
rescue SSHKit::Command::Failed => e
|
46
37
|
if e.message =~ /(context not found|no builder|does not exist)/
|
47
38
|
warn "Missing compatible builder, so creating a new one first"
|
@@ -51,6 +42,9 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|
51
42
|
end
|
52
43
|
end
|
53
44
|
|
45
|
+
# Get the command here to ensure the Dir.chdir doesn't interfere with it
|
46
|
+
push = KAMAL.builder.push
|
47
|
+
|
54
48
|
KAMAL.with_verbosity(:debug) do
|
55
49
|
Dir.chdir(KAMAL.config.builder.build_directory) { execute *push }
|
56
50
|
end
|
@@ -72,7 +66,7 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|
72
66
|
|
73
67
|
desc "create", "Create a build setup"
|
74
68
|
def create
|
75
|
-
if (remote_host = KAMAL.config.builder.
|
69
|
+
if (remote_host = KAMAL.config.builder.remote)
|
76
70
|
connect_to_remote_host(remote_host)
|
77
71
|
end
|
78
72
|
|
data/lib/kamal/cli/server.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
class Kamal::Cli::Server < Kamal::Cli::Base
|
2
2
|
desc "exec", "Run a custom command on the server (use --help to show options)"
|
3
3
|
option :interactive, type: :boolean, aliases: "-i", default: false, desc: "Run the command interactively (use for console/bash)"
|
4
|
-
def exec(cmd)
|
4
|
+
def exec(*cmd)
|
5
|
+
cmd = Kamal::Utils.join_commands(cmd)
|
5
6
|
hosts = KAMAL.hosts | KAMAL.accessory_hosts
|
6
7
|
|
7
8
|
case
|
@@ -18,6 +18,10 @@ registry:
|
|
18
18
|
password:
|
19
19
|
- KAMAL_REGISTRY_PASSWORD
|
20
20
|
|
21
|
+
# Configure builder setup.
|
22
|
+
builder:
|
23
|
+
arch: amd64
|
24
|
+
|
21
25
|
# Inject ENV variables into containers (secrets come from .env).
|
22
26
|
# Remember to run `kamal env push` after making changes!
|
23
27
|
# env:
|
@@ -30,16 +34,6 @@ registry:
|
|
30
34
|
# ssh:
|
31
35
|
# user: app
|
32
36
|
|
33
|
-
# Configure builder setup.
|
34
|
-
# builder:
|
35
|
-
# args:
|
36
|
-
# RUBY_VERSION: 3.2.0
|
37
|
-
# secrets:
|
38
|
-
# - GITHUB_TOKEN
|
39
|
-
# remote:
|
40
|
-
# arch: amd64
|
41
|
-
# host: ssh://app@192.168.0.1
|
42
|
-
|
43
37
|
# Use accessory services (secrets come from .env).
|
44
38
|
# accessories:
|
45
39
|
# db:
|
data/lib/kamal/commander.rb
CHANGED
@@ -27,7 +27,11 @@ class Kamal::Commander
|
|
27
27
|
|
28
28
|
def specific_primary!
|
29
29
|
@specifics = nil
|
30
|
-
|
30
|
+
if specific_roles.present?
|
31
|
+
self.specific_hosts = [ specific_roles.first.primary_host ]
|
32
|
+
else
|
33
|
+
self.specific_hosts = [ config.primary_host ]
|
34
|
+
end
|
31
35
|
end
|
32
36
|
|
33
37
|
def specific_roles=(role_names)
|
@@ -113,6 +117,10 @@ class Kamal::Commander
|
|
113
117
|
@traefik ||= Kamal::Commands::Traefik.new(config)
|
114
118
|
end
|
115
119
|
|
120
|
+
def alias(name)
|
121
|
+
config.aliases[name]
|
122
|
+
end
|
123
|
+
|
116
124
|
|
117
125
|
def with_verbosity(level)
|
118
126
|
old_level = self.verbosity
|
@@ -1,20 +1,41 @@
|
|
1
|
-
|
2
1
|
class Kamal::Commands::Builder::Base < Kamal::Commands::Base
|
3
2
|
class BuilderError < StandardError; end
|
4
3
|
|
5
4
|
ENDPOINT_DOCKER_HOST_INSPECT = "'{{.Endpoints.docker.Host}}'"
|
6
5
|
|
7
6
|
delegate :argumentize, to: Kamal::Utils
|
8
|
-
delegate
|
7
|
+
delegate \
|
8
|
+
:args, :secrets, :dockerfile, :target, :arches, :local_arches, :remote_arches, :remote,
|
9
|
+
:cache_from, :cache_to, :ssh, :driver, :docker_driver?,
|
10
|
+
to: :builder_config
|
9
11
|
|
10
12
|
def clean
|
11
13
|
docker :image, :rm, "--force", config.absolute_image
|
12
14
|
end
|
13
15
|
|
16
|
+
def push
|
17
|
+
docker :buildx, :build,
|
18
|
+
"--push",
|
19
|
+
*platform_options(arches),
|
20
|
+
*([ "--builder", builder_name ] unless docker_driver?),
|
21
|
+
*build_options,
|
22
|
+
build_context
|
23
|
+
end
|
24
|
+
|
14
25
|
def pull
|
15
26
|
docker :pull, config.absolute_image
|
16
27
|
end
|
17
28
|
|
29
|
+
def info
|
30
|
+
combine \
|
31
|
+
docker(:context, :ls),
|
32
|
+
docker(:buildx, :ls)
|
33
|
+
end
|
34
|
+
|
35
|
+
def buildx_inspect
|
36
|
+
docker :buildx, :inspect, builder_name unless docker_driver?
|
37
|
+
end
|
38
|
+
|
18
39
|
def build_options
|
19
40
|
[ *build_tags, *build_cache, *build_labels, *build_args, *build_secrets, *build_dockerfile, *build_target, *build_ssh ]
|
20
41
|
end
|
@@ -32,14 +53,6 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
|
|
32
53
|
)
|
33
54
|
end
|
34
55
|
|
35
|
-
def context_hosts
|
36
|
-
:true
|
37
|
-
end
|
38
|
-
|
39
|
-
def config_context_hosts
|
40
|
-
[]
|
41
|
-
end
|
42
|
-
|
43
56
|
def first_mirror
|
44
57
|
docker(:info, "--format '{{index .RegistryConfig.Mirrors 0}}'")
|
45
58
|
end
|
@@ -91,4 +104,8 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
|
|
91
104
|
def context_host(builder_name)
|
92
105
|
docker :context, :inspect, builder_name, "--format", ENDPOINT_DOCKER_HOST_INSPECT
|
93
106
|
end
|
107
|
+
|
108
|
+
def platform_options(arches)
|
109
|
+
argumentize "--platform", arches.map { |arch| "linux/#{arch}" }.join(",") if arches.any?
|
110
|
+
end
|
94
111
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Kamal::Commands::Builder::Hybrid < Kamal::Commands::Builder::Remote
|
2
|
+
def create
|
3
|
+
combine \
|
4
|
+
create_local_buildx,
|
5
|
+
create_remote_context,
|
6
|
+
append_remote_buildx
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
def builder_name
|
11
|
+
"kamal-hybrid-#{driver}-#{remote.gsub(/[^a-z0-9_-]/, "-")}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_local_buildx
|
15
|
+
docker :buildx, :create, *platform_options(local_arches), "--name", builder_name, "--driver=#{driver}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def append_remote_buildx
|
19
|
+
docker :buildx, :create, *platform_options(remote_arches), "--append", "--name", builder_name, builder_name
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Kamal::Commands::Builder::Local < Kamal::Commands::Builder::Base
|
2
|
+
def create
|
3
|
+
docker :buildx, :create, "--name", builder_name, "--driver=#{driver}" unless docker_driver?
|
4
|
+
end
|
5
|
+
|
6
|
+
def remove
|
7
|
+
docker :buildx, :rm, builder_name unless docker_driver?
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
def builder_name
|
12
|
+
"kamal-local-#{driver}"
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class Kamal::Commands::Builder::Remote < Kamal::Commands::Builder::Base
|
2
|
+
def create
|
3
|
+
chain \
|
4
|
+
create_remote_context,
|
5
|
+
create_buildx
|
6
|
+
end
|
7
|
+
|
8
|
+
def remove
|
9
|
+
chain \
|
10
|
+
remove_remote_context,
|
11
|
+
remove_buildx
|
12
|
+
end
|
13
|
+
|
14
|
+
def info
|
15
|
+
chain \
|
16
|
+
docker(:context, :ls),
|
17
|
+
docker(:buildx, :ls)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def builder_name
|
22
|
+
"kamal-remote-#{driver}-#{remote.gsub(/[^a-z0-9_-]/, "-")}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_remote_context
|
26
|
+
docker :context, :create, builder_name, "--description", "'#{builder_name} host'", "--docker", "'host=#{remote}'"
|
27
|
+
end
|
28
|
+
|
29
|
+
def remove_remote_context
|
30
|
+
docker :context, :rm, builder_name
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_buildx
|
34
|
+
docker :buildx, :create, "--name", builder_name, builder_name
|
35
|
+
end
|
36
|
+
|
37
|
+
def remove_buildx
|
38
|
+
docker :buildx, :rm, builder_name
|
39
|
+
end
|
40
|
+
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, :
|
5
|
-
|
4
|
+
delegate :create, :remove, :push, :clean, :pull, :info, :buildx_inspect, :validate_image, :first_mirror, to: :target
|
5
|
+
delegate :local?, :remote?, to: "config.builder"
|
6
6
|
|
7
7
|
include Clone
|
8
8
|
|
@@ -11,43 +11,27 @@ class Kamal::Commands::Builder < Kamal::Commands::Base
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def target
|
14
|
-
if
|
15
|
-
if
|
16
|
-
|
17
|
-
multiarch_remote
|
18
|
-
else
|
19
|
-
native_remote
|
20
|
-
end
|
14
|
+
if remote?
|
15
|
+
if local?
|
16
|
+
hybrid
|
21
17
|
else
|
22
|
-
|
18
|
+
remote
|
23
19
|
end
|
24
20
|
else
|
25
|
-
|
26
|
-
native_cached
|
27
|
-
else
|
28
|
-
native
|
29
|
-
end
|
21
|
+
local
|
30
22
|
end
|
31
23
|
end
|
32
24
|
|
33
|
-
def
|
34
|
-
@
|
35
|
-
end
|
36
|
-
|
37
|
-
def native_cached
|
38
|
-
@native ||= Kamal::Commands::Builder::Native::Cached.new(config)
|
39
|
-
end
|
40
|
-
|
41
|
-
def native_remote
|
42
|
-
@native ||= Kamal::Commands::Builder::Native::Remote.new(config)
|
25
|
+
def remote
|
26
|
+
@remote ||= Kamal::Commands::Builder::Remote.new(config)
|
43
27
|
end
|
44
28
|
|
45
|
-
def
|
46
|
-
@
|
29
|
+
def local
|
30
|
+
@local ||= Kamal::Commands::Builder::Local.new(config)
|
47
31
|
end
|
48
32
|
|
49
|
-
def
|
50
|
-
@
|
33
|
+
def hybrid
|
34
|
+
@hybrid ||= Kamal::Commands::Builder::Hybrid.new(config)
|
51
35
|
end
|
52
36
|
|
53
37
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Kamal::Configuration::Alias
|
2
|
+
include Kamal::Configuration::Validation
|
3
|
+
|
4
|
+
attr_reader :name, :command
|
5
|
+
|
6
|
+
def initialize(name, config:)
|
7
|
+
@name, @command = name.inquiry, config.raw_config["aliases"][name]
|
8
|
+
|
9
|
+
validate! \
|
10
|
+
command,
|
11
|
+
example: validation_yml["aliases"]["uname"],
|
12
|
+
context: "aliases/#{name}",
|
13
|
+
with: Kamal::Configuration::Validator::Alias
|
14
|
+
end
|
15
|
+
end
|
@@ -19,16 +19,36 @@ class Kamal::Configuration::Builder
|
|
19
19
|
builder_config
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
23
|
-
builder_config["
|
22
|
+
def remote
|
23
|
+
builder_config["remote"]
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
27
|
-
|
26
|
+
def arches
|
27
|
+
Array(builder_config.fetch("arch", default_arch))
|
28
|
+
end
|
29
|
+
|
30
|
+
def local_arches
|
31
|
+
@local_arches ||= if remote
|
32
|
+
arches & [ Kamal::Utils.docker_arch ]
|
33
|
+
else
|
34
|
+
arches
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def remote_arches
|
39
|
+
@remote_arches ||= if remote
|
40
|
+
arches - local_arches
|
41
|
+
else
|
42
|
+
[]
|
43
|
+
end
|
28
44
|
end
|
29
45
|
|
30
46
|
def remote?
|
31
|
-
|
47
|
+
remote_arches.any?
|
48
|
+
end
|
49
|
+
|
50
|
+
def local?
|
51
|
+
arches.empty? || local_arches.any?
|
32
52
|
end
|
33
53
|
|
34
54
|
def cached?
|
@@ -55,20 +75,8 @@ class Kamal::Configuration::Builder
|
|
55
75
|
builder_config["context"] || "."
|
56
76
|
end
|
57
77
|
|
58
|
-
def
|
59
|
-
builder_config
|
60
|
-
end
|
61
|
-
|
62
|
-
def local_host
|
63
|
-
builder_config["local"]["host"] if local?
|
64
|
-
end
|
65
|
-
|
66
|
-
def remote_arch
|
67
|
-
builder_config["remote"]["arch"] if remote?
|
68
|
-
end
|
69
|
-
|
70
|
-
def remote_host
|
71
|
-
builder_config["remote"]["host"] if remote?
|
78
|
+
def driver
|
79
|
+
builder_config.fetch("driver", "docker-container")
|
72
80
|
end
|
73
81
|
|
74
82
|
def cache_from
|
@@ -114,7 +122,23 @@ class Kamal::Configuration::Builder
|
|
114
122
|
end
|
115
123
|
end
|
116
124
|
|
125
|
+
def docker_driver?
|
126
|
+
driver == "docker"
|
127
|
+
end
|
128
|
+
|
117
129
|
private
|
130
|
+
def valid?
|
131
|
+
if docker_driver?
|
132
|
+
raise ArgumentError, "Invalid builder configuration: the `docker` driver does not not support remote builders" if remote
|
133
|
+
raise ArgumentError, "Invalid builder configuration: the `docker` driver does not not support caching" if cached?
|
134
|
+
raise ArgumentError, "Invalid builder configuration: the `docker` driver does not not support multiple arches" if arches.many?
|
135
|
+
end
|
136
|
+
|
137
|
+
if @options["cache"] && @options["cache"]["type"]
|
138
|
+
raise ArgumentError, "Invalid cache type: #{@options["cache"]["type"]}" unless [ "gha", "registry" ].include?(@options["cache"]["type"])
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
118
142
|
def cache_image
|
119
143
|
builder_config["cache"]&.fetch("image", nil) || "#{image}-build-cache"
|
120
144
|
end
|
@@ -150,4 +174,8 @@ class Kamal::Configuration::Builder
|
|
150
174
|
def pwd_sha
|
151
175
|
Digest::SHA256.hexdigest(Dir.pwd)[0..12]
|
152
176
|
end
|
177
|
+
|
178
|
+
def default_arch
|
179
|
+
docker_driver? ? [] : [ "amd64", "arm64" ]
|
180
|
+
end
|
153
181
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Aliases
|
2
|
+
#
|
3
|
+
# Aliases are shortcuts for Kamal commands.
|
4
|
+
#
|
5
|
+
# For example, for a Rails app, you might open a console with:
|
6
|
+
#
|
7
|
+
# ```shell
|
8
|
+
# kamal app exec -i -r console "rails console"
|
9
|
+
# ```
|
10
|
+
#
|
11
|
+
# By defining an alias, like this:
|
12
|
+
aliases:
|
13
|
+
console: app exec -r console -i "rails console"
|
14
|
+
# You can now open the console with:
|
15
|
+
# ```shell
|
16
|
+
# kamal console
|
17
|
+
# ```
|
18
|
+
|
19
|
+
# Configuring aliases
|
20
|
+
#
|
21
|
+
# Aliases are defined in the root config under the alias key
|
22
|
+
#
|
23
|
+
# Each alias is named and can only contain lowercase letters, numbers, dashes and underscores.
|
24
|
+
|
25
|
+
aliases:
|
26
|
+
uname: app exec -p -q -r web "uname -a"
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# Builder
|
2
2
|
#
|
3
|
-
# The builder configuration controls how the application is built with `docker build`
|
3
|
+
# The builder configuration controls how the application is built with `docker build`
|
4
4
|
#
|
5
5
|
# If no configuration is specified, Kamal will:
|
6
|
-
# 1. Create a buildx context called `kamal
|
7
|
-
# 2. Use `docker
|
6
|
+
# 1. Create a buildx context called `kamal-local-docker-container`, using the docker-container driver
|
7
|
+
# 2. Use `docker build` to build a multiarch image for linux/amd64,linux/arm64 with that context
|
8
8
|
#
|
9
9
|
# See https://kamal-deploy.org/docs/configuration/builder-examples/ for more information
|
10
10
|
|
@@ -12,36 +12,29 @@
|
|
12
12
|
#
|
13
13
|
# Options go under the builder key in the root configuration.
|
14
14
|
builder:
|
15
|
-
|
16
|
-
# Multiarch
|
15
|
+
# Driver
|
17
16
|
#
|
18
|
-
#
|
19
|
-
|
17
|
+
# The build driver to use, defaults to `docker-container`
|
18
|
+
driver: docker
|
20
19
|
|
21
|
-
#
|
22
|
-
#
|
23
|
-
# The build configuration for local builds, only used if multiarch is enabled (the default)
|
20
|
+
# Arch
|
24
21
|
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
|
29
|
-
|
30
|
-
host: /var/run/docker.sock
|
22
|
+
# The architectures to build for, defaults to `[ amd64, arm64 ]`
|
23
|
+
# Unless you are using the docker driver, when it defaults to the local architecture
|
24
|
+
# You can set an array or just a single value
|
25
|
+
arch:
|
26
|
+
- amd64
|
31
27
|
|
32
28
|
# Remote configuration
|
33
29
|
#
|
34
|
-
#
|
35
|
-
|
36
|
-
remote:
|
37
|
-
arch: arm64
|
38
|
-
host: ssh://docker@docker-builder
|
30
|
+
# If you have a remote builder, you can configure it here
|
31
|
+
remote: ssh://docker@docker-builder
|
39
32
|
|
40
33
|
# Builder cache
|
41
34
|
#
|
42
35
|
# The type must be either 'gha' or 'registry'
|
43
36
|
#
|
44
|
-
# The image is only used for registry cache
|
37
|
+
# The image is only used for registry cache. Not compatible with the docker driver
|
45
38
|
cache:
|
46
39
|
type: registry
|
47
40
|
options: mode=max
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Kamal::Configuration::Validator::Alias < Kamal::Configuration::Validator
|
2
|
+
def validate!
|
3
|
+
super
|
4
|
+
|
5
|
+
name = context.delete_prefix("aliases/")
|
6
|
+
|
7
|
+
if name !~ /\A[a-z0-9_-]+\z/
|
8
|
+
error "Invalid alias name: '#{name}'. Must only contain lowercase letters, alphanumeric, hyphens and underscores."
|
9
|
+
end
|
10
|
+
|
11
|
+
if Kamal::Cli::Main.commands.include?(name)
|
12
|
+
error "Alias '#{name}' conflicts with a built-in command."
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -5,5 +5,7 @@ class Kamal::Configuration::Validator::Builder < Kamal::Configuration::Validator
|
|
5
5
|
if config["cache"] && config["cache"]["type"]
|
6
6
|
error "Invalid cache type: #{config["cache"]["type"]}" unless [ "gha", "registry" ].include?(config["cache"]["type"])
|
7
7
|
end
|
8
|
+
|
9
|
+
error "Builder arch not set" unless config["arch"].present?
|
8
10
|
end
|
9
11
|
end
|
@@ -13,32 +13,38 @@ class Kamal::Configuration::Validator
|
|
13
13
|
|
14
14
|
private
|
15
15
|
def validate_against_example!(validation_config, example)
|
16
|
-
validate_type! validation_config,
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
16
|
+
validate_type! validation_config, example.class
|
17
|
+
|
18
|
+
if example.class == Hash
|
19
|
+
check_unknown_keys! validation_config, example
|
20
|
+
|
21
|
+
validation_config.each do |key, value|
|
22
|
+
next if extension?(key)
|
23
|
+
with_context(key) do
|
24
|
+
example_value = example[key]
|
25
|
+
|
26
|
+
if example_value == "..."
|
27
|
+
validate_type! value, *(Array if key == :servers), Hash
|
28
|
+
elsif key == "hosts"
|
29
|
+
validate_servers! value
|
30
|
+
elsif example_value.is_a?(Array)
|
31
|
+
if key == "arch"
|
32
|
+
validate_array_of_or_type! value, example_value.first.class
|
33
|
+
else
|
34
|
+
validate_array_of! value, example_value.first.class
|
35
|
+
end
|
36
|
+
elsif example_value.is_a?(Hash)
|
37
|
+
case key.to_s
|
38
|
+
when "options", "args"
|
39
|
+
validate_type! value, Hash
|
40
|
+
when "labels"
|
41
|
+
validate_hash_of! value, example_value.first[1].class
|
42
|
+
else
|
43
|
+
validate_against_example! value, example_value
|
44
|
+
end
|
37
45
|
else
|
38
|
-
|
46
|
+
validate_type! value, example_value.class
|
39
47
|
end
|
40
|
-
else
|
41
|
-
validate_type! value, example_value.class
|
42
48
|
end
|
43
49
|
end
|
44
50
|
end
|
@@ -69,6 +75,16 @@ class Kamal::Configuration::Validator
|
|
69
75
|
value.is_a?(String) || value.is_a?(Symbol) || value.is_a?(Numeric) || value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
70
76
|
end
|
71
77
|
|
78
|
+
def validate_array_of_or_type!(value, type)
|
79
|
+
if value.is_a?(Array)
|
80
|
+
validate_array_of! value, type
|
81
|
+
else
|
82
|
+
validate_type! value, type
|
83
|
+
end
|
84
|
+
rescue Kamal::ConfigurationError
|
85
|
+
type_error(Array, type)
|
86
|
+
end
|
87
|
+
|
72
88
|
def validate_array_of!(array, type)
|
73
89
|
validate_type! array, Array
|
74
90
|
|
data/lib/kamal/configuration.rb
CHANGED
@@ -11,7 +11,7 @@ class Kamal::Configuration
|
|
11
11
|
delegate :argumentize, :optionize, to: Kamal::Utils
|
12
12
|
|
13
13
|
attr_reader :destination, :raw_config
|
14
|
-
attr_reader :accessories, :boot, :builder, :env, :healthcheck, :logging, :traefik, :servers, :ssh, :sshkit, :registry
|
14
|
+
attr_reader :accessories, :aliases, :boot, :builder, :env, :healthcheck, :logging, :traefik, :servers, :ssh, :sshkit, :registry
|
15
15
|
|
16
16
|
include Validation
|
17
17
|
|
@@ -54,6 +54,7 @@ class Kamal::Configuration
|
|
54
54
|
@registry = Registry.new(config: self)
|
55
55
|
|
56
56
|
@accessories = @raw_config.accessories&.keys&.collect { |name| Accessory.new(name, config: self) } || []
|
57
|
+
@aliases = @raw_config.aliases&.keys&.to_h { |name| [ name, Alias.new(name, config: self) ] } || {}
|
57
58
|
@boot = Boot.new(config: self)
|
58
59
|
@builder = Builder.new(config: self)
|
59
60
|
@env = Env.new(config: @raw_config.env || {})
|
data/lib/kamal/utils.rb
CHANGED
@@ -77,4 +77,20 @@ module Kamal::Utils
|
|
77
77
|
def stable_sort!(elements, &block)
|
78
78
|
elements.sort_by!.with_index { |element, index| [ block.call(element), index ] }
|
79
79
|
end
|
80
|
+
|
81
|
+
def join_commands(commands)
|
82
|
+
commands.map(&:strip).join(" ")
|
83
|
+
end
|
84
|
+
|
85
|
+
def docker_arch
|
86
|
+
arch = `docker info --format '{{.Architecture}}'`.strip
|
87
|
+
case arch
|
88
|
+
when /aarch64/
|
89
|
+
"arm64"
|
90
|
+
when /x86_64/
|
91
|
+
"amd64"
|
92
|
+
else
|
93
|
+
arch
|
94
|
+
end
|
95
|
+
end
|
80
96
|
end
|
data/lib/kamal/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kamal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0.alpha
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-09-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -64,14 +64,14 @@ dependencies:
|
|
64
64
|
requirements:
|
65
65
|
- - "~>"
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version: '1.
|
67
|
+
version: '1.3'
|
68
68
|
type: :runtime
|
69
69
|
prerelease: false
|
70
70
|
version_requirements: !ruby/object:Gem::Requirement
|
71
71
|
requirements:
|
72
72
|
- - "~>"
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version: '1.
|
74
|
+
version: '1.3'
|
75
75
|
- !ruby/object:Gem::Dependency
|
76
76
|
name: dotenv
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -211,6 +211,7 @@ files:
|
|
211
211
|
- lib/kamal.rb
|
212
212
|
- lib/kamal/cli.rb
|
213
213
|
- lib/kamal/cli/accessory.rb
|
214
|
+
- lib/kamal/cli/alias/command.rb
|
214
215
|
- lib/kamal/cli/app.rb
|
215
216
|
- lib/kamal/cli/app/boot.rb
|
216
217
|
- lib/kamal/cli/app/prepare_assets.rb
|
@@ -252,11 +253,9 @@ files:
|
|
252
253
|
- lib/kamal/commands/builder.rb
|
253
254
|
- lib/kamal/commands/builder/base.rb
|
254
255
|
- lib/kamal/commands/builder/clone.rb
|
255
|
-
- lib/kamal/commands/builder/
|
256
|
-
- lib/kamal/commands/builder/
|
257
|
-
- lib/kamal/commands/builder/
|
258
|
-
- lib/kamal/commands/builder/native/cached.rb
|
259
|
-
- lib/kamal/commands/builder/native/remote.rb
|
256
|
+
- lib/kamal/commands/builder/hybrid.rb
|
257
|
+
- lib/kamal/commands/builder/local.rb
|
258
|
+
- lib/kamal/commands/builder/remote.rb
|
260
259
|
- lib/kamal/commands/docker.rb
|
261
260
|
- lib/kamal/commands/hook.rb
|
262
261
|
- lib/kamal/commands/lock.rb
|
@@ -266,9 +265,11 @@ files:
|
|
266
265
|
- lib/kamal/commands/traefik.rb
|
267
266
|
- lib/kamal/configuration.rb
|
268
267
|
- lib/kamal/configuration/accessory.rb
|
268
|
+
- lib/kamal/configuration/alias.rb
|
269
269
|
- lib/kamal/configuration/boot.rb
|
270
270
|
- lib/kamal/configuration/builder.rb
|
271
271
|
- lib/kamal/configuration/docs/accessory.yml
|
272
|
+
- lib/kamal/configuration/docs/alias.yml
|
272
273
|
- lib/kamal/configuration/docs/boot.yml
|
273
274
|
- lib/kamal/configuration/docs/builder.yml
|
274
275
|
- lib/kamal/configuration/docs/configuration.yml
|
@@ -294,6 +295,7 @@ files:
|
|
294
295
|
- lib/kamal/configuration/validation.rb
|
295
296
|
- lib/kamal/configuration/validator.rb
|
296
297
|
- lib/kamal/configuration/validator/accessory.rb
|
298
|
+
- lib/kamal/configuration/validator/alias.rb
|
297
299
|
- lib/kamal/configuration/validator/builder.rb
|
298
300
|
- lib/kamal/configuration/validator/configuration.rb
|
299
301
|
- lib/kamal/configuration/validator/env.rb
|
@@ -327,7 +329,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
327
329
|
- !ruby/object:Gem::Version
|
328
330
|
version: '0'
|
329
331
|
requirements: []
|
330
|
-
rubygems_version: 3.5.
|
332
|
+
rubygems_version: 3.5.17
|
331
333
|
signing_key:
|
332
334
|
specification_version: 4
|
333
335
|
summary: Deploy web apps in containers to servers running Docker with zero downtime.
|
@@ -1,61 +0,0 @@
|
|
1
|
-
class Kamal::Commands::Builder::Multiarch::Remote < Kamal::Commands::Builder::Multiarch
|
2
|
-
def create
|
3
|
-
combine \
|
4
|
-
create_contexts,
|
5
|
-
create_local_buildx,
|
6
|
-
append_remote_buildx
|
7
|
-
end
|
8
|
-
|
9
|
-
def remove
|
10
|
-
combine \
|
11
|
-
remove_contexts,
|
12
|
-
super
|
13
|
-
end
|
14
|
-
|
15
|
-
def context_hosts
|
16
|
-
chain \
|
17
|
-
context_host(builder_name_with_arch(local_arch)),
|
18
|
-
context_host(builder_name_with_arch(remote_arch))
|
19
|
-
end
|
20
|
-
|
21
|
-
def config_context_hosts
|
22
|
-
[ local_host, remote_host ].compact
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
def builder_name
|
27
|
-
super + "-remote"
|
28
|
-
end
|
29
|
-
|
30
|
-
def builder_name_with_arch(arch)
|
31
|
-
"#{builder_name}-#{arch}"
|
32
|
-
end
|
33
|
-
|
34
|
-
def create_local_buildx
|
35
|
-
docker :buildx, :create, "--name", builder_name, builder_name_with_arch(local_arch), "--platform", "linux/#{local_arch}"
|
36
|
-
end
|
37
|
-
|
38
|
-
def append_remote_buildx
|
39
|
-
docker :buildx, :create, "--append", "--name", builder_name, builder_name_with_arch(remote_arch), "--platform", "linux/#{remote_arch}"
|
40
|
-
end
|
41
|
-
|
42
|
-
def create_contexts
|
43
|
-
combine \
|
44
|
-
create_context(local_arch, local_host),
|
45
|
-
create_context(remote_arch, remote_host)
|
46
|
-
end
|
47
|
-
|
48
|
-
def create_context(arch, host)
|
49
|
-
docker :context, :create, builder_name_with_arch(arch), "--description", "'#{builder_name} #{arch} native host'", "--docker", "'host=#{host}'"
|
50
|
-
end
|
51
|
-
|
52
|
-
def remove_contexts
|
53
|
-
combine \
|
54
|
-
remove_context(local_arch),
|
55
|
-
remove_context(remote_arch)
|
56
|
-
end
|
57
|
-
|
58
|
-
def remove_context(arch)
|
59
|
-
docker :context, :rm, builder_name_with_arch(arch)
|
60
|
-
end
|
61
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
class Kamal::Commands::Builder::Multiarch < Kamal::Commands::Builder::Base
|
2
|
-
def create
|
3
|
-
docker :buildx, :create, "--use", "--name", builder_name
|
4
|
-
end
|
5
|
-
|
6
|
-
def remove
|
7
|
-
docker :buildx, :rm, builder_name
|
8
|
-
end
|
9
|
-
|
10
|
-
def info
|
11
|
-
combine \
|
12
|
-
docker(:context, :ls),
|
13
|
-
docker(:buildx, :ls)
|
14
|
-
end
|
15
|
-
|
16
|
-
def push
|
17
|
-
docker :buildx, :build,
|
18
|
-
"--push",
|
19
|
-
"--platform", platform_names,
|
20
|
-
"--builder", builder_name,
|
21
|
-
*build_options,
|
22
|
-
build_context
|
23
|
-
end
|
24
|
-
|
25
|
-
def context_hosts
|
26
|
-
docker :buildx, :inspect, builder_name, "> /dev/null"
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
def builder_name
|
31
|
-
"kamal-#{config.service}-multiarch"
|
32
|
-
end
|
33
|
-
|
34
|
-
def platform_names
|
35
|
-
if local_arch
|
36
|
-
"linux/#{local_arch}"
|
37
|
-
else
|
38
|
-
"linux/amd64,linux/arm64"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
class Kamal::Commands::Builder::Native::Cached < Kamal::Commands::Builder::Native
|
2
|
-
def create
|
3
|
-
docker :buildx, :create, "--name", builder_name, "--use", "--driver=docker-container"
|
4
|
-
end
|
5
|
-
|
6
|
-
def remove
|
7
|
-
docker :buildx, :rm, builder_name
|
8
|
-
end
|
9
|
-
|
10
|
-
def push
|
11
|
-
docker :buildx, :build,
|
12
|
-
"--push",
|
13
|
-
*build_options,
|
14
|
-
build_context
|
15
|
-
end
|
16
|
-
|
17
|
-
def context_hosts
|
18
|
-
docker :buildx, :inspect, builder_name, "> /dev/null"
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
def builder_name
|
23
|
-
"kamal-#{config.service}-native-cached"
|
24
|
-
end
|
25
|
-
end
|
@@ -1,67 +0,0 @@
|
|
1
|
-
class Kamal::Commands::Builder::Native::Remote < Kamal::Commands::Builder::Native
|
2
|
-
def create
|
3
|
-
chain \
|
4
|
-
create_context,
|
5
|
-
create_buildx
|
6
|
-
end
|
7
|
-
|
8
|
-
def remove
|
9
|
-
chain \
|
10
|
-
remove_context,
|
11
|
-
remove_buildx
|
12
|
-
end
|
13
|
-
|
14
|
-
def info
|
15
|
-
chain \
|
16
|
-
docker(:context, :ls),
|
17
|
-
docker(:buildx, :ls)
|
18
|
-
end
|
19
|
-
|
20
|
-
def push
|
21
|
-
docker :buildx, :build,
|
22
|
-
"--push",
|
23
|
-
"--platform", platform,
|
24
|
-
"--builder", builder_name,
|
25
|
-
*build_options,
|
26
|
-
build_context
|
27
|
-
end
|
28
|
-
|
29
|
-
def context_hosts
|
30
|
-
context_host(builder_name_with_arch)
|
31
|
-
end
|
32
|
-
|
33
|
-
def config_context_hosts
|
34
|
-
[ remote_host ]
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
|
-
private
|
39
|
-
def builder_name
|
40
|
-
"kamal-#{config.service}-native-remote"
|
41
|
-
end
|
42
|
-
|
43
|
-
def builder_name_with_arch
|
44
|
-
"#{builder_name}-#{remote_arch}"
|
45
|
-
end
|
46
|
-
|
47
|
-
def platform
|
48
|
-
"linux/#{remote_arch}"
|
49
|
-
end
|
50
|
-
|
51
|
-
def create_context
|
52
|
-
docker :context, :create,
|
53
|
-
builder_name_with_arch, "--description", "'#{builder_name} #{remote_arch} native host'", "--docker", "'host=#{remote_host}'"
|
54
|
-
end
|
55
|
-
|
56
|
-
def remove_context
|
57
|
-
docker :context, :rm, builder_name_with_arch
|
58
|
-
end
|
59
|
-
|
60
|
-
def create_buildx
|
61
|
-
docker :buildx, :create, "--name", builder_name, builder_name_with_arch, "--platform", platform
|
62
|
-
end
|
63
|
-
|
64
|
-
def remove_buildx
|
65
|
-
docker :buildx, :rm, builder_name
|
66
|
-
end
|
67
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
class Kamal::Commands::Builder::Native < Kamal::Commands::Builder::Base
|
2
|
-
def create
|
3
|
-
# No-op on native without cache
|
4
|
-
end
|
5
|
-
|
6
|
-
def remove
|
7
|
-
# No-op on native without cache
|
8
|
-
end
|
9
|
-
|
10
|
-
def info
|
11
|
-
# No-op on native
|
12
|
-
end
|
13
|
-
|
14
|
-
def push
|
15
|
-
combine \
|
16
|
-
docker(:build, *build_options, build_context),
|
17
|
-
docker(:push, config.absolute_image),
|
18
|
-
docker(:push, config.latest_image)
|
19
|
-
end
|
20
|
-
end
|