kamal 1.5.2 → 1.7.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.
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