kamal 1.5.2 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/lib/kamal/cli/accessory.rb +30 -24
  3. data/lib/kamal/cli/app/boot.rb +70 -18
  4. data/lib/kamal/cli/app/prepare_assets.rb +1 -1
  5. data/lib/kamal/cli/app.rb +60 -47
  6. data/lib/kamal/cli/base.rb +26 -28
  7. data/lib/kamal/cli/build/clone.rb +61 -0
  8. data/lib/kamal/cli/build.rb +64 -53
  9. data/lib/kamal/cli/env.rb +5 -5
  10. data/lib/kamal/cli/healthcheck/barrier.rb +31 -0
  11. data/lib/kamal/cli/healthcheck/error.rb +2 -0
  12. data/lib/kamal/cli/healthcheck/poller.rb +6 -7
  13. data/lib/kamal/cli/main.rb +49 -44
  14. data/lib/kamal/cli/prune.rb +3 -3
  15. data/lib/kamal/cli/registry.rb +9 -10
  16. data/lib/kamal/cli/server.rb +39 -15
  17. data/lib/kamal/cli/templates/sample_hooks/docker-setup.sample +1 -1
  18. data/lib/kamal/cli/traefik.rb +13 -11
  19. data/lib/kamal/cli.rb +1 -1
  20. data/lib/kamal/commander.rb +6 -6
  21. data/lib/kamal/commands/accessory.rb +4 -4
  22. data/lib/kamal/commands/app/containers.rb +8 -0
  23. data/lib/kamal/commands/app/execution.rb +3 -3
  24. data/lib/kamal/commands/app/logging.rb +5 -5
  25. data/lib/kamal/commands/app.rb +6 -5
  26. data/lib/kamal/commands/base.rb +2 -3
  27. data/lib/kamal/commands/builder/base.rb +19 -12
  28. data/lib/kamal/commands/builder/clone.rb +28 -0
  29. data/lib/kamal/commands/builder/multiarch/remote.rb +10 -0
  30. data/lib/kamal/commands/builder/multiarch.rb +13 -9
  31. data/lib/kamal/commands/builder/native/cached.rb +14 -6
  32. data/lib/kamal/commands/builder/native/remote.rb +17 -9
  33. data/lib/kamal/commands/builder/native.rb +6 -7
  34. data/lib/kamal/commands/builder.rb +19 -11
  35. data/lib/kamal/commands/registry.rb +4 -13
  36. data/lib/kamal/commands/traefik.rb +8 -47
  37. data/lib/kamal/configuration/accessory.rb +30 -41
  38. data/lib/kamal/configuration/boot.rb +9 -4
  39. data/lib/kamal/configuration/builder.rb +61 -30
  40. data/lib/kamal/configuration/docs/accessory.yml +90 -0
  41. data/lib/kamal/configuration/docs/boot.yml +19 -0
  42. data/lib/kamal/configuration/docs/builder.yml +107 -0
  43. data/lib/kamal/configuration/docs/configuration.yml +157 -0
  44. data/lib/kamal/configuration/docs/env.yml +72 -0
  45. data/lib/kamal/configuration/docs/healthcheck.yml +59 -0
  46. data/lib/kamal/configuration/docs/logging.yml +21 -0
  47. data/lib/kamal/configuration/docs/registry.yml +49 -0
  48. data/lib/kamal/configuration/docs/role.yml +52 -0
  49. data/lib/kamal/configuration/docs/servers.yml +27 -0
  50. data/lib/kamal/configuration/docs/ssh.yml +46 -0
  51. data/lib/kamal/configuration/docs/sshkit.yml +23 -0
  52. data/lib/kamal/configuration/docs/traefik.yml +62 -0
  53. data/lib/kamal/configuration/env/tag.rb +12 -0
  54. data/lib/kamal/configuration/env.rb +10 -14
  55. data/lib/kamal/configuration/healthcheck.rb +63 -0
  56. data/lib/kamal/configuration/logging.rb +33 -0
  57. data/lib/kamal/configuration/registry.rb +31 -0
  58. data/lib/kamal/configuration/role.rb +72 -61
  59. data/lib/kamal/configuration/servers.rb +18 -0
  60. data/lib/kamal/configuration/ssh.rb +11 -8
  61. data/lib/kamal/configuration/sshkit.rb +9 -7
  62. data/lib/kamal/configuration/traefik.rb +60 -0
  63. data/lib/kamal/configuration/validation.rb +27 -0
  64. data/lib/kamal/configuration/validator/accessory.rb +9 -0
  65. data/lib/kamal/configuration/validator/builder.rb +9 -0
  66. data/lib/kamal/configuration/validator/env.rb +54 -0
  67. data/lib/kamal/configuration/validator/registry.rb +25 -0
  68. data/lib/kamal/configuration/validator/role.rb +11 -0
  69. data/lib/kamal/configuration/validator/servers.rb +7 -0
  70. data/lib/kamal/configuration/validator.rb +140 -0
  71. data/lib/kamal/configuration.rb +50 -63
  72. data/lib/kamal/git.rb +4 -0
  73. data/lib/kamal/sshkit_with_ext.rb +36 -0
  74. data/lib/kamal/version.rb +1 -1
  75. data/lib/kamal.rb +2 -0
  76. metadata +64 -9
  77. data/lib/kamal/cli/healthcheck.rb +0 -21
  78. data/lib/kamal/commands/healthcheck.rb +0 -59
@@ -1,19 +1,6 @@
1
1
  class Kamal::Commands::Traefik < Kamal::Commands::Base
2
2
  delegate :argumentize, :optionize, to: Kamal::Utils
3
-
4
- DEFAULT_IMAGE = "traefik:v2.10"
5
- CONTAINER_PORT = 80
6
- DEFAULT_ARGS = {
7
- "log.level" => "DEBUG"
8
- }
9
- DEFAULT_LABELS = {
10
- # These ensure we serve a 502 rather than a 404 if no containers are available
11
- "traefik.http.routers.catchall.entryPoints" => "http",
12
- "traefik.http.routers.catchall.rule" => "PathPrefix(`/`)",
13
- "traefik.http.routers.catchall.service" => "unavailable",
14
- "traefik.http.routers.catchall.priority" => 1,
15
- "traefik.http.services.unavailable.loadbalancer.server.port" => "0"
16
- }
3
+ delegate :port, :publish?, :labels, :env, :image, :options, :args, to: :"config.traefik"
17
4
 
18
5
  def run
19
6
  docker :run, "--name traefik",
@@ -46,16 +33,16 @@ class Kamal::Commands::Traefik < Kamal::Commands::Base
46
33
  docker :ps, "--filter", "name=^traefik$"
47
34
  end
48
35
 
49
- def logs(since: nil, lines: nil, grep: nil)
36
+ def logs(since: nil, lines: nil, grep: nil, grep_options: nil)
50
37
  pipe \
51
38
  docker(:logs, "traefik", (" --since #{since}" if since), (" --tail #{lines}" if lines), "--timestamps", "2>&1"),
52
- ("grep '#{grep}'" if grep)
39
+ ("grep '#{grep}'#{" #{grep_options}" if grep_options}" if grep)
53
40
  end
54
41
 
55
- def follow_logs(host:, grep: nil)
42
+ def follow_logs(host:, grep: nil, grep_options: nil)
56
43
  run_over_ssh pipe(
57
44
  docker(:logs, "traefik", "--timestamps", "--tail", "10", "--follow", "2>&1"),
58
- (%(grep "#{grep}") if grep)
45
+ (%(grep "#{grep}"#{" #{grep_options}" if grep_options}) if grep)
59
46
  ).join(" "), host: host
60
47
  end
61
48
 
@@ -67,16 +54,6 @@ class Kamal::Commands::Traefik < Kamal::Commands::Base
67
54
  docker :image, :prune, "--all", "--force", "--filter", "label=org.opencontainers.image.title=Traefik"
68
55
  end
69
56
 
70
- def port
71
- "#{host_port}:#{CONTAINER_PORT}"
72
- end
73
-
74
- def env
75
- Kamal::Configuration::Env.from_config \
76
- config: config.traefik.fetch("env", {}),
77
- secrets_file: File.join(config.host_env_directory, "traefik", "traefik.env")
78
- end
79
-
80
57
  def make_env_directory
81
58
  make_directory(env.secrets_directory)
82
59
  end
@@ -87,7 +64,7 @@ class Kamal::Commands::Traefik < Kamal::Commands::Base
87
64
 
88
65
  private
89
66
  def publish_args
90
- argumentize "--publish", port unless config.traefik["publish"] == false
67
+ argumentize "--publish", port if publish?
91
68
  end
92
69
 
93
70
  def label_args
@@ -98,27 +75,11 @@ class Kamal::Commands::Traefik < Kamal::Commands::Base
98
75
  env.args
99
76
  end
100
77
 
101
- def labels
102
- DEFAULT_LABELS.merge(config.traefik["labels"] || {})
103
- end
104
-
105
- def image
106
- config.traefik.fetch("image") { DEFAULT_IMAGE }
107
- end
108
-
109
78
  def docker_options_args
110
- optionize(config.traefik["options"] || {})
79
+ optionize(options)
111
80
  end
112
81
 
113
82
  def cmd_option_args
114
- if args = config.traefik["args"]
115
- optionize DEFAULT_ARGS.merge(args), with: "="
116
- else
117
- optionize DEFAULT_ARGS, with: "="
118
- end
119
- end
120
-
121
- def host_port
122
- config.traefik["host_port"] || CONTAINER_PORT
83
+ optionize args, with: "="
123
84
  end
124
85
  end
@@ -1,30 +1,39 @@
1
1
  class Kamal::Configuration::Accessory
2
+ include Kamal::Configuration::Validation
3
+
2
4
  delegate :argumentize, :optionize, to: Kamal::Utils
3
5
 
4
- attr_accessor :name, :specifics
6
+ attr_reader :name, :accessory_config, :env
5
7
 
6
8
  def initialize(name, config:)
7
- @name, @config, @specifics = name.inquiry, config, config.raw_config["accessories"][name]
9
+ @name, @config, @accessory_config = name.inquiry, config, config.raw_config["accessories"][name]
10
+
11
+ validate! \
12
+ accessory_config,
13
+ example: validation_yml["accessories"]["mysql"],
14
+ context: "accessories/#{name}",
15
+ with: Kamal::Configuration::Validator::Accessory
16
+
17
+ @env = Kamal::Configuration::Env.new \
18
+ config: accessory_config.fetch("env", {}),
19
+ secrets_file: File.join(config.host_env_directory, "accessories", "#{service_name}.env"),
20
+ context: "accessories/#{name}/env"
8
21
  end
9
22
 
10
23
  def service_name
11
- specifics["service"] || "#{config.service}-#{name}"
24
+ accessory_config["service"] || "#{config.service}-#{name}"
12
25
  end
13
26
 
14
27
  def image
15
- specifics["image"]
28
+ accessory_config["image"]
16
29
  end
17
30
 
18
31
  def hosts
19
- if (specifics.keys & [ "host", "hosts", "roles" ]).size != 1
20
- raise ArgumentError, "Specify one of `host`, `hosts` or `roles` for accessory `#{name}`"
21
- end
22
-
23
32
  hosts_from_host || hosts_from_hosts || hosts_from_roles
24
33
  end
25
34
 
26
35
  def port
27
- if port = specifics["port"]&.to_s
36
+ if port = accessory_config["port"]&.to_s
28
37
  port.include?(":") ? port : "#{port}:#{port}"
29
38
  end
30
39
  end
@@ -34,32 +43,26 @@ class Kamal::Configuration::Accessory
34
43
  end
35
44
 
36
45
  def labels
37
- default_labels.merge(specifics["labels"] || {})
46
+ default_labels.merge(accessory_config["labels"] || {})
38
47
  end
39
48
 
40
49
  def label_args
41
50
  argumentize "--label", labels
42
51
  end
43
52
 
44
- def env
45
- Kamal::Configuration::Env.from_config \
46
- config: specifics.fetch("env", {}),
47
- secrets_file: File.join(config.host_env_directory, "accessories", "#{service_name}.env")
48
- end
49
-
50
53
  def env_args
51
54
  env.args
52
55
  end
53
56
 
54
57
  def files
55
- specifics["files"]&.to_h do |local_to_remote_mapping|
58
+ accessory_config["files"]&.to_h do |local_to_remote_mapping|
56
59
  local_file, remote_file = local_to_remote_mapping.split(":")
57
60
  [ expand_local_file(local_file), expand_remote_file(remote_file) ]
58
61
  end || {}
59
62
  end
60
63
 
61
64
  def directories
62
- specifics["directories"]&.to_h do |host_to_container_mapping|
65
+ accessory_config["directories"]&.to_h do |host_to_container_mapping|
63
66
  host_path, container_path = host_to_container_mapping.split(":")
64
67
  [ expand_host_path(host_path), container_path ]
65
68
  end || {}
@@ -74,7 +77,7 @@ class Kamal::Configuration::Accessory
74
77
  end
75
78
 
76
79
  def option_args
77
- if args = specifics["options"]
80
+ if args = accessory_config["options"]
78
81
  optionize args
79
82
  else
80
83
  []
@@ -82,7 +85,7 @@ class Kamal::Configuration::Accessory
82
85
  end
83
86
 
84
87
  def cmd
85
- specifics["cmd"]
88
+ accessory_config["cmd"]
86
89
  end
87
90
 
88
91
  private
@@ -116,18 +119,18 @@ class Kamal::Configuration::Accessory
116
119
  end
117
120
 
118
121
  def specific_volumes
119
- specifics["volumes"] || []
122
+ accessory_config["volumes"] || []
120
123
  end
121
124
 
122
125
  def remote_files_as_volumes
123
- specifics["files"]&.collect do |local_to_remote_mapping|
126
+ accessory_config["files"]&.collect do |local_to_remote_mapping|
124
127
  _, remote_file = local_to_remote_mapping.split(":")
125
128
  "#{service_data_directory + remote_file}:#{remote_file}"
126
129
  end || []
127
130
  end
128
131
 
129
132
  def remote_directories_as_volumes
130
- specifics["directories"]&.collect do |host_to_container_mapping|
133
+ accessory_config["directories"]&.collect do |host_to_container_mapping|
131
134
  host_path, container_path = host_to_container_mapping.split(":")
132
135
  [ expand_host_path(host_path), container_path ].join(":")
133
136
  end || []
@@ -146,30 +149,16 @@ class Kamal::Configuration::Accessory
146
149
  end
147
150
 
148
151
  def hosts_from_host
149
- if specifics.key?("host")
150
- host = specifics["host"]
151
- if host
152
- [ host ]
153
- else
154
- raise ArgumentError, "Missing host for accessory `#{name}`"
155
- end
156
- end
152
+ [ accessory_config["host"] ] if accessory_config.key?("host")
157
153
  end
158
154
 
159
155
  def hosts_from_hosts
160
- if specifics.key?("hosts")
161
- hosts = specifics["hosts"]
162
- if hosts.is_a?(Array)
163
- hosts
164
- else
165
- raise ArgumentError, "Hosts should be an Array for accessory `#{name}`"
166
- end
167
- end
156
+ accessory_config["hosts"] if accessory_config.key?("hosts")
168
157
  end
169
158
 
170
159
  def hosts_from_roles
171
- if specifics.key?("roles")
172
- specifics["roles"].flat_map { |role| config.role(role).hosts }
160
+ if accessory_config.key?("roles")
161
+ accessory_config["roles"].flat_map { |role| config.role(role).hosts }
173
162
  end
174
163
  end
175
164
  end
@@ -1,20 +1,25 @@
1
1
  class Kamal::Configuration::Boot
2
+ include Kamal::Configuration::Validation
3
+
4
+ attr_reader :boot_config, :host_count
5
+
2
6
  def initialize(config:)
3
- @options = config.raw_config.boot || {}
7
+ @boot_config = config.raw_config.boot || {}
4
8
  @host_count = config.all_hosts.count
9
+ validate! boot_config
5
10
  end
6
11
 
7
12
  def limit
8
- limit = @options["limit"]
13
+ limit = boot_config["limit"]
9
14
 
10
15
  if limit.to_s.end_with?("%")
11
- [ @host_count * limit.to_i / 100, 1 ].max
16
+ [ host_count * limit.to_i / 100, 1 ].max
12
17
  else
13
18
  limit
14
19
  end
15
20
  end
16
21
 
17
22
  def wait
18
- @options["wait"]
23
+ boot_config["wait"]
19
24
  end
20
25
  end
@@ -1,67 +1,79 @@
1
1
  class Kamal::Configuration::Builder
2
+ include Kamal::Configuration::Validation
3
+
4
+ attr_reader :config, :builder_config
5
+ delegate :image, :service, to: :config
6
+ delegate :server, to: :"config.registry"
7
+
2
8
  def initialize(config:)
3
- @options = config.raw_config.builder || {}
9
+ @config = config
10
+ @builder_config = config.raw_config.builder || {}
4
11
  @image = config.image
5
- @server = config.registry["server"]
12
+ @server = config.registry.server
13
+ @service = config.service
6
14
 
7
- valid?
15
+ validate! builder_config, with: Kamal::Configuration::Validator::Builder
8
16
  end
9
17
 
10
18
  def to_h
11
- @options
19
+ builder_config
12
20
  end
13
21
 
14
22
  def multiarch?
15
- @options["multiarch"] != false
23
+ builder_config["multiarch"] != false
16
24
  end
17
25
 
18
26
  def local?
19
- !!@options["local"]
27
+ !!builder_config["local"]
20
28
  end
21
29
 
22
30
  def remote?
23
- !!@options["remote"]
31
+ !!builder_config["remote"]
24
32
  end
25
33
 
26
34
  def cached?
27
- !!@options["cache"]
35
+ !!builder_config["cache"]
28
36
  end
29
37
 
30
38
  def args
31
- @options["args"] || {}
39
+ builder_config["args"] || {}
32
40
  end
33
41
 
34
42
  def secrets
35
- @options["secrets"] || []
43
+ builder_config["secrets"] || []
36
44
  end
37
45
 
38
46
  def dockerfile
39
- @options["dockerfile"] || "Dockerfile"
47
+ builder_config["dockerfile"] || "Dockerfile"
48
+ end
49
+
50
+ def target
51
+ builder_config["target"]
40
52
  end
41
53
 
42
54
  def context
43
- @options["context"] || (git_archive? ? "-" : ".")
55
+ builder_config["context"] || "."
44
56
  end
45
57
 
46
58
  def local_arch
47
- @options["local"]["arch"] if local?
59
+ builder_config["local"]["arch"] if local?
48
60
  end
49
61
 
50
62
  def local_host
51
- @options["local"]["host"] if local?
63
+ builder_config["local"]["host"] if local?
52
64
  end
53
65
 
54
66
  def remote_arch
55
- @options["remote"]["arch"] if remote?
67
+ builder_config["remote"]["arch"] if remote?
56
68
  end
57
69
 
58
70
  def remote_host
59
- @options["remote"]["host"] if remote?
71
+ builder_config["remote"]["host"] if remote?
60
72
  end
61
73
 
62
74
  def cache_from
63
75
  if cached?
64
- case @options["cache"]["type"]
76
+ case builder_config["cache"]["type"]
65
77
  when "gha"
66
78
  cache_from_config_for_gha
67
79
  when "registry"
@@ -72,7 +84,7 @@ class Kamal::Configuration::Builder
72
84
 
73
85
  def cache_to
74
86
  if cached?
75
- case @options["cache"]["type"]
87
+ case builder_config["cache"]["type"]
76
88
  when "gha"
77
89
  cache_to_config_for_gha
78
90
  when "registry"
@@ -82,26 +94,33 @@ class Kamal::Configuration::Builder
82
94
  end
83
95
 
84
96
  def ssh
85
- @options["ssh"]
97
+ builder_config["ssh"]
86
98
  end
87
99
 
88
- def git_archive?
89
- Kamal::Git.used? && @options["context"].nil?
100
+ def git_clone?
101
+ Kamal::Git.used? && builder_config["context"].nil?
90
102
  end
91
103
 
92
- private
93
- def valid?
94
- if @options["cache"] && @options["cache"]["type"]
95
- raise ArgumentError, "Invalid cache type: #{@options["cache"]["type"]}" unless [ "gha", "registry" ].include?(@options["cache"]["type"])
104
+ def clone_directory
105
+ @clone_directory ||= File.join Dir.tmpdir, "kamal-clones", [ service, pwd_sha ].compact.join("-")
106
+ end
107
+
108
+ def build_directory
109
+ @build_directory ||=
110
+ if git_clone?
111
+ File.join clone_directory, repo_basename, repo_relative_pwd
112
+ else
113
+ "."
96
114
  end
97
- end
115
+ end
98
116
 
117
+ private
99
118
  def cache_image
100
- @options["cache"]&.fetch("image", nil) || "#{@image}-build-cache"
119
+ builder_config["cache"]&.fetch("image", nil) || "#{image}-build-cache"
101
120
  end
102
121
 
103
122
  def cache_image_ref
104
- [ @server, cache_image ].compact.join("/")
123
+ [ server, cache_image ].compact.join("/")
105
124
  end
106
125
 
107
126
  def cache_from_config_for_gha
@@ -113,10 +132,22 @@ class Kamal::Configuration::Builder
113
132
  end
114
133
 
115
134
  def cache_to_config_for_gha
116
- [ "type=gha", @options["cache"]&.fetch("options", nil) ].compact.join(",")
135
+ [ "type=gha", builder_config["cache"]&.fetch("options", nil) ].compact.join(",")
117
136
  end
118
137
 
119
138
  def cache_to_config_for_registry
120
- [ "type=registry", @options["cache"]&.fetch("options", nil), "ref=#{cache_image_ref}" ].compact.join(",")
139
+ [ "type=registry", builder_config["cache"]&.fetch("options", nil), "ref=#{cache_image_ref}" ].compact.join(",")
140
+ end
141
+
142
+ def repo_basename
143
+ File.basename(Kamal::Git.root)
144
+ end
145
+
146
+ def repo_relative_pwd
147
+ Dir.pwd.delete_prefix(Kamal::Git.root)
148
+ end
149
+
150
+ def pwd_sha
151
+ Digest::SHA256.hexdigest(Dir.pwd)[0..12]
121
152
  end
122
153
  end
@@ -0,0 +1,90 @@
1
+ # Accessories
2
+ #
3
+ # Accessories can be booted on a single host, a list of hosts, or on specific roles.
4
+ # The hosts do not need to be defined in the Kamal servers configuration.
5
+ #
6
+ # Accessories are managed separately from the main service - they are not updated
7
+ # when you deploy and they do not have zero-downtime deployments.
8
+ #
9
+ # Run `kamal accessory boot <accessory>` to boot an accessory.
10
+ # See `kamal accessory --help` for more information.
11
+
12
+ # Configuring accessories
13
+ #
14
+ # First define the accessory in the `accessories`
15
+ accessories:
16
+ mysql:
17
+
18
+ # Service name
19
+ #
20
+ # This is used in the service label and defaults to `<service>-<accessory>`
21
+ # where `<service>` is the main service name from the root configuration
22
+ service: mysql
23
+
24
+ # Image
25
+ #
26
+ # The Docker image to use, prefix with a registry if not using Docker hub
27
+ image: mysql:8.0
28
+
29
+ # Accessory hosts
30
+ #
31
+ # Specify one of `host`, `hosts` or `roles`
32
+ host: mysql-db1
33
+ hosts:
34
+ - mysql-db1
35
+ - mysql-db2
36
+ roles:
37
+ - mysql
38
+
39
+ # Custom command
40
+ #
41
+ # You can set a custom command to run in the container, if you do not want to use the default
42
+ cmd: "bin/mysqld"
43
+
44
+ # Port mappings
45
+ #
46
+ # See https://docs.docker.com/network/, especially note the warning about the security
47
+ # implications of exposing ports publicly.
48
+ port: "127.0.0.1:3306:3306"
49
+
50
+ # Labels
51
+ labels:
52
+ app: myapp
53
+
54
+ # Options
55
+ # These are passed to the Docker run command in the form `--<name> <value>`
56
+ options:
57
+ restart: always
58
+ cpus: 2
59
+
60
+ # Environment variables
61
+ # See kamal docs env for more information
62
+ env:
63
+ ...
64
+
65
+ # Copying files
66
+ #
67
+ # You can specify files to mount into the container.
68
+ # The format is `local:remote` where `local` is the path to the file on the local machine
69
+ # and `remote` is the path to the file in the container.
70
+ #
71
+ # They will be uploaded from the local repo to the host and then mounted.
72
+ #
73
+ # ERB files will be evaluated before being copied.
74
+ files:
75
+ - config/my.cnf.erb:/etc/mysql/my.cnf
76
+ - config/myoptions.cnf:/etc/mysql/myoptions.cnf
77
+
78
+ # Directories
79
+ #
80
+ # You can specify directories to mount into the container. They will be created on the host
81
+ # before being mounted
82
+ directories:
83
+ - mysql-logs:/var/log/mysql
84
+
85
+ # Volumes
86
+ #
87
+ # Any other volumes to mount, in addition to the files and directories.
88
+ # They are not created or copied before mounting
89
+ volumes:
90
+ - /path/to/mysql-logs:/var/log/mysql
@@ -0,0 +1,19 @@
1
+ # Booting
2
+ #
3
+ # When deploying to large numbers of hosts, you might prefer not to restart your services on every host at the same time.
4
+ #
5
+ # Kamal’s default is to boot new containers on all hosts in parallel. But you can control this with the boot configuration.
6
+
7
+ # Fixed group sizes
8
+ #
9
+ # Here we boot 2 hosts at a time with a 10 second gap between each group.
10
+ boot:
11
+ limit: 2
12
+ wait: 10
13
+
14
+ # Percentage of hosts
15
+ #
16
+ # Here we boot 25% of the hosts at a time with a 2 second gap between each group.
17
+ boot:
18
+ limit: 25%
19
+ wait: 2
@@ -0,0 +1,107 @@
1
+ # Builder
2
+ #
3
+ # The builder configuration controls how the application is built with `docker build` or `docker buildx build`
4
+ #
5
+ # If no configuration is specified, Kamal will:
6
+ # 1. Create a buildx context called `kamal-<service>-multiarch`
7
+ # 2. Use `docker buildx build` to build a multiarch image for linux/amd64,linux/arm64 with that context
8
+ #
9
+ # See https://kamal-deploy.org/docs/configuration/builder-examples/ for more information
10
+
11
+ # Builder options
12
+ #
13
+ # Options go under the builder key in the root configuration.
14
+ builder:
15
+
16
+ # Multiarch
17
+ #
18
+ # Enables multiarch builds, defaults to `true`
19
+ multiarch: false
20
+
21
+ # Local configuration
22
+ #
23
+ # The build configuration for local builds, only used if multiarch is enabled (the default)
24
+ #
25
+ # If there is no remote configuration, by default we build for amd64 and arm64.
26
+ # If you only want to build for one architecture, you can specify it here.
27
+ # The docker socket is optional and uses the default docker host socket when not specified
28
+ local:
29
+ arch: amd64
30
+ host: /var/run/docker.sock
31
+
32
+ # Remote configuration
33
+ #
34
+ # The build configuration for remote builds, also only used if multiarch is enabled.
35
+ # The arch is required and can be either amd64 or arm64.
36
+ remote:
37
+ arch: arm64
38
+ host: ssh://docker@docker-builder
39
+
40
+ # Builder cache
41
+ #
42
+ # The type must be either 'gha' or 'registry'
43
+ #
44
+ # The image is only used for registry cache
45
+ cache:
46
+ type: registry
47
+ options: mode=max
48
+ image: kamal-app-build-cache
49
+
50
+ # Build context
51
+ #
52
+ # If this is not set, then a local git clone of the repo is used.
53
+ # This ensures a clean build with no uncommitted changes.
54
+ #
55
+ # To use the local checkout instead you can set the context to `.`, or a path to another directory.
56
+ context: .
57
+
58
+ # Dockerfile
59
+ #
60
+ # The Dockerfile to use for building, defaults to `Dockerfile`
61
+ dockerfile: Dockerfile.production
62
+
63
+ # Build target
64
+ #
65
+ # If not set, then the default target is used
66
+ target: production
67
+
68
+ # Build Arguments
69
+ #
70
+ # Any additional build arguments, passed to `docker build` with `--build-arg <key>=<value>`
71
+ args:
72
+ ENVIRONMENT: production
73
+
74
+ # Referencing build arguments
75
+ #
76
+ # ```shell
77
+ # ARG RUBY_VERSION
78
+ # FROM ruby:$RUBY_VERSION-slim as base
79
+ # ```
80
+
81
+ # Build secrets
82
+ #
83
+ # Values are read from the environment.
84
+ #
85
+ secrets:
86
+ - SECRET1
87
+ - SECRET2
88
+
89
+ # Referencing Build Secrets
90
+ #
91
+ # ```shell
92
+ # # Copy Gemfiles
93
+ # COPY Gemfile Gemfile.lock ./
94
+ #
95
+ # # Install dependencies, including private repositories via access token
96
+ # # Then remove bundle cache with exposed GITHUB_TOKEN)
97
+ # RUN --mount=type=secret,id=GITHUB_TOKEN \
98
+ # BUNDLE_GITHUB__COM=x-access-token:$(cat /run/secrets/GITHUB_TOKEN) \
99
+ # bundle install && \
100
+ # rm -rf /usr/local/bundle/cache
101
+ # ```
102
+
103
+
104
+ # SSH
105
+ #
106
+ # SSH agent socket or keys to expose to the build
107
+ ssh: default=$SSH_AUTH_SOCK