kamal 1.8.3 → 2.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 (130) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/kamal/cli/accessory.rb +92 -38
  4. data/lib/kamal/cli/alias/command.rb +10 -0
  5. data/lib/kamal/cli/app/{prepare_assets.rb → assets.rb} +1 -1
  6. data/lib/kamal/cli/app/boot.rb +23 -16
  7. data/lib/kamal/cli/app/error_pages.rb +33 -0
  8. data/lib/kamal/cli/app/ssl_certificates.rb +28 -0
  9. data/lib/kamal/cli/app.rb +132 -30
  10. data/lib/kamal/cli/base.rb +57 -53
  11. data/lib/kamal/cli/build.rb +81 -38
  12. data/lib/kamal/cli/healthcheck/barrier.rb +2 -0
  13. data/lib/kamal/cli/healthcheck/poller.rb +18 -39
  14. data/lib/kamal/cli/lock.rb +2 -3
  15. data/lib/kamal/cli/main.rb +60 -59
  16. data/lib/kamal/cli/proxy.rb +290 -0
  17. data/lib/kamal/cli/prune.rb +0 -1
  18. data/lib/kamal/cli/registry.rb +2 -0
  19. data/lib/kamal/cli/secrets.rb +49 -0
  20. data/lib/kamal/cli/server.rb +6 -5
  21. data/lib/kamal/cli/templates/deploy.yml +53 -53
  22. data/lib/kamal/cli/templates/sample_hooks/docker-setup.sample +2 -12
  23. data/lib/kamal/cli/templates/sample_hooks/post-app-boot.sample +3 -0
  24. data/lib/kamal/cli/templates/sample_hooks/post-deploy.sample +1 -1
  25. data/lib/kamal/cli/templates/sample_hooks/post-proxy-reboot.sample +3 -0
  26. data/lib/kamal/cli/templates/sample_hooks/pre-app-boot.sample +3 -0
  27. data/lib/kamal/cli/templates/sample_hooks/pre-build.sample +1 -1
  28. data/lib/kamal/cli/templates/sample_hooks/pre-connect.sample +1 -1
  29. data/lib/kamal/cli/templates/sample_hooks/pre-deploy.sample +19 -6
  30. data/lib/kamal/cli/templates/sample_hooks/pre-proxy-reboot.sample +3 -0
  31. data/lib/kamal/cli/templates/secrets +17 -0
  32. data/lib/kamal/cli.rb +2 -0
  33. data/lib/kamal/commander/specifics.rb +19 -6
  34. data/lib/kamal/commander.rb +39 -32
  35. data/lib/kamal/commands/accessory/proxy.rb +16 -0
  36. data/lib/kamal/commands/accessory.rb +19 -19
  37. data/lib/kamal/commands/app/assets.rb +10 -10
  38. data/lib/kamal/commands/app/containers.rb +2 -2
  39. data/lib/kamal/commands/app/error_pages.rb +9 -0
  40. data/lib/kamal/commands/app/execution.rb +7 -4
  41. data/lib/kamal/commands/app/images.rb +1 -1
  42. data/lib/kamal/commands/app/logging.rb +16 -6
  43. data/lib/kamal/commands/app/proxy.rb +32 -0
  44. data/lib/kamal/commands/app.rb +25 -24
  45. data/lib/kamal/commands/auditor.rb +12 -3
  46. data/lib/kamal/commands/base.rb +54 -8
  47. data/lib/kamal/commands/builder/base.rb +46 -16
  48. data/lib/kamal/commands/builder/clone.rb +16 -14
  49. data/lib/kamal/commands/builder/cloud.rb +22 -0
  50. data/lib/kamal/commands/builder/hybrid.rb +21 -0
  51. data/lib/kamal/commands/builder/local.rb +14 -0
  52. data/lib/kamal/commands/builder/pack.rb +46 -0
  53. data/lib/kamal/commands/builder/remote.rb +63 -0
  54. data/lib/kamal/commands/builder.rb +21 -45
  55. data/lib/kamal/commands/docker.rb +4 -0
  56. data/lib/kamal/commands/hook.rb +8 -2
  57. data/lib/kamal/commands/lock.rb +2 -6
  58. data/lib/kamal/commands/proxy.rb +127 -0
  59. data/lib/kamal/commands/prune.rb +1 -9
  60. data/lib/kamal/commands/registry.rb +9 -7
  61. data/lib/kamal/commands/server.rb +11 -1
  62. data/lib/kamal/configuration/accessory.rb +89 -12
  63. data/lib/kamal/configuration/alias.rb +15 -0
  64. data/lib/kamal/configuration/builder.rb +73 -15
  65. data/lib/kamal/configuration/docs/accessory.yml +53 -15
  66. data/lib/kamal/configuration/docs/alias.yml +26 -0
  67. data/lib/kamal/configuration/docs/boot.yml +3 -3
  68. data/lib/kamal/configuration/docs/builder.yml +63 -38
  69. data/lib/kamal/configuration/docs/configuration.yml +62 -46
  70. data/lib/kamal/configuration/docs/env.yml +61 -17
  71. data/lib/kamal/configuration/docs/logging.yml +3 -3
  72. data/lib/kamal/configuration/docs/proxy.yml +168 -0
  73. data/lib/kamal/configuration/docs/registry.yml +20 -13
  74. data/lib/kamal/configuration/docs/role.yml +14 -13
  75. data/lib/kamal/configuration/docs/servers.yml +2 -2
  76. data/lib/kamal/configuration/docs/ssh.yml +23 -19
  77. data/lib/kamal/configuration/docs/sshkit.yml +4 -4
  78. data/lib/kamal/configuration/env/tag.rb +4 -3
  79. data/lib/kamal/configuration/env.rb +19 -17
  80. data/lib/kamal/configuration/proxy/boot.rb +129 -0
  81. data/lib/kamal/configuration/proxy.rb +124 -0
  82. data/lib/kamal/configuration/registry.rb +7 -6
  83. data/lib/kamal/configuration/role.rb +69 -98
  84. data/lib/kamal/configuration/servers.rb +8 -1
  85. data/lib/kamal/configuration/validator/accessory.rb +6 -2
  86. data/lib/kamal/configuration/validator/alias.rb +15 -0
  87. data/lib/kamal/configuration/validator/builder.rb +6 -0
  88. data/lib/kamal/configuration/validator/proxy.rb +25 -0
  89. data/lib/kamal/configuration/validator/role.rb +3 -1
  90. data/lib/kamal/configuration/validator/servers.rb +1 -1
  91. data/lib/kamal/configuration/validator.rb +62 -24
  92. data/lib/kamal/configuration.rb +96 -50
  93. data/lib/kamal/docker.rb +30 -0
  94. data/lib/kamal/env_file.rb +7 -1
  95. data/lib/kamal/git.rb +10 -0
  96. data/lib/kamal/secrets/adapters/aws_secrets_manager.rb +51 -0
  97. data/lib/kamal/secrets/adapters/base.rb +33 -0
  98. data/lib/kamal/secrets/adapters/bitwarden.rb +81 -0
  99. data/lib/kamal/secrets/adapters/bitwarden_secrets_manager.rb +66 -0
  100. data/lib/kamal/secrets/adapters/doppler.rb +57 -0
  101. data/lib/kamal/secrets/adapters/enpass.rb +71 -0
  102. data/lib/kamal/secrets/adapters/gcp_secret_manager.rb +112 -0
  103. data/lib/kamal/secrets/adapters/last_pass.rb +40 -0
  104. data/lib/kamal/secrets/adapters/one_password.rb +104 -0
  105. data/lib/kamal/secrets/adapters/passbolt.rb +130 -0
  106. data/lib/kamal/secrets/adapters/test.rb +14 -0
  107. data/lib/kamal/secrets/adapters.rb +16 -0
  108. data/lib/kamal/secrets/dotenv/inline_command_substitution.rb +33 -0
  109. data/lib/kamal/secrets.rb +42 -0
  110. data/lib/kamal/sshkit_with_ext.rb +1 -0
  111. data/lib/kamal/utils.rb +30 -0
  112. data/lib/kamal/version.rb +1 -1
  113. data/lib/kamal.rb +3 -1
  114. metadata +63 -36
  115. data/lib/kamal/cli/env.rb +0 -54
  116. data/lib/kamal/cli/templates/sample_hooks/post-traefik-reboot.sample +0 -3
  117. data/lib/kamal/cli/templates/sample_hooks/pre-traefik-reboot.sample +0 -3
  118. data/lib/kamal/cli/templates/template.env +0 -2
  119. data/lib/kamal/cli/traefik.rb +0 -122
  120. data/lib/kamal/commands/app/cord.rb +0 -22
  121. data/lib/kamal/commands/builder/multiarch/remote.rb +0 -65
  122. data/lib/kamal/commands/builder/multiarch.rb +0 -41
  123. data/lib/kamal/commands/builder/native/cached.rb +0 -25
  124. data/lib/kamal/commands/builder/native/remote.rb +0 -67
  125. data/lib/kamal/commands/builder/native.rb +0 -20
  126. data/lib/kamal/commands/traefik.rb +0 -85
  127. data/lib/kamal/configuration/docs/healthcheck.yml +0 -59
  128. data/lib/kamal/configuration/docs/traefik.yml +0 -62
  129. data/lib/kamal/configuration/healthcheck.rb +0 -63
  130. data/lib/kamal/configuration/traefik.rb +0 -60
@@ -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
@@ -1,85 +0,0 @@
1
- class Kamal::Commands::Traefik < Kamal::Commands::Base
2
- delegate :argumentize, :optionize, to: Kamal::Utils
3
- delegate :port, :publish?, :labels, :env, :image, :options, :args, to: :"config.traefik"
4
-
5
- def run
6
- docker :run, "--name traefik",
7
- "--detach",
8
- "--restart", "unless-stopped",
9
- *publish_args,
10
- "--volume", "/var/run/docker.sock:/var/run/docker.sock",
11
- *env_args,
12
- *config.logging_args,
13
- *label_args,
14
- *docker_options_args,
15
- image,
16
- "--providers.docker",
17
- *cmd_option_args
18
- end
19
-
20
- def start
21
- docker :container, :start, "traefik"
22
- end
23
-
24
- def stop
25
- docker :container, :stop, "traefik"
26
- end
27
-
28
- def start_or_run
29
- any start, run
30
- end
31
-
32
- def info
33
- docker :ps, "--filter", "name=^traefik$"
34
- end
35
-
36
- def logs(since: nil, lines: nil, grep: nil, grep_options: nil)
37
- pipe \
38
- docker(:logs, "traefik", (" --since #{since}" if since), (" --tail #{lines}" if lines), "--timestamps", "2>&1"),
39
- ("grep '#{grep}'#{" #{grep_options}" if grep_options}" if grep)
40
- end
41
-
42
- def follow_logs(host:, grep: nil, grep_options: nil)
43
- run_over_ssh pipe(
44
- docker(:logs, "traefik", "--timestamps", "--tail", "10", "--follow", "2>&1"),
45
- (%(grep "#{grep}"#{" #{grep_options}" if grep_options}) if grep)
46
- ).join(" "), host: host
47
- end
48
-
49
- def remove_container
50
- docker :container, :prune, "--force", "--filter", "label=org.opencontainers.image.title=Traefik"
51
- end
52
-
53
- def remove_image
54
- docker :image, :prune, "--all", "--force", "--filter", "label=org.opencontainers.image.title=Traefik"
55
- end
56
-
57
- def make_env_directory
58
- make_directory(env.secrets_directory)
59
- end
60
-
61
- def remove_env_file
62
- [ :rm, "-f", env.secrets_file ]
63
- end
64
-
65
- private
66
- def publish_args
67
- argumentize "--publish", port if publish?
68
- end
69
-
70
- def label_args
71
- argumentize "--label", labels
72
- end
73
-
74
- def env_args
75
- env.args
76
- end
77
-
78
- def docker_options_args
79
- optionize(options)
80
- end
81
-
82
- def cmd_option_args
83
- optionize args, with: "="
84
- end
85
- end
@@ -1,59 +0,0 @@
1
- # Healthcheck configuration
2
- #
3
- # On roles that are running Traefik, Kamal will supply a default healthcheck to `docker run`.
4
- # For other roles, by default no healthcheck is supplied.
5
- #
6
- # If no healthcheck is supplied and the image does not define one, they we wait for the container
7
- # to reach a running state and then pause for the readiness delay.
8
- #
9
- # The default healthcheck is `curl -f http://localhost:<port>/<path>`, so it assumes that `curl`
10
- # is available within the container.
11
-
12
- # Healthcheck options
13
- #
14
- # These go under the `healthcheck` key in the root or role configuration.
15
- healthcheck:
16
-
17
- # Command
18
- #
19
- # The command to run, defaults to `curl -f http://localhost:<port>/<path>` on roles running Traefik
20
- cmd: "curl -f http://localhost"
21
-
22
- # Interval
23
- #
24
- # The Docker healthcheck interval, defaults to `1s`
25
- interval: 10s
26
-
27
- # Max attempts
28
- #
29
- # The maximum number of times we poll the container to see if it is healthy, defaults to `7`
30
- # Each check is separated by an increasing interval starting with 1 second.
31
- max_attempts: 3
32
-
33
- # Port
34
- #
35
- # The port to use in the healthcheck, defaults to `3000`
36
- port: "80"
37
-
38
- # Path
39
- #
40
- # The path to use in the healthcheck, defaults to `/up`
41
- path: /health
42
-
43
- # Cords for zero-downtime deployments
44
- #
45
- # The cord file is used for zero-downtime deployments. The healthcheck is augmented with a check
46
- # for the existance of the file. This allows us to delete the file and force the container to
47
- # become unhealthy, causing Traefik to stop routing traffic to it.
48
- #
49
- # Kamal mounts a volume at this location and creates the file before starting the container.
50
- # You can set the value to `false` to disable the cord file, but this loses the zero-downtime
51
- # guarantee.
52
- #
53
- # The default value is `/tmp/kamal-cord`
54
- cord: /cord
55
-
56
- # Log lines
57
- #
58
- # Number of lines to log from the container when the healthcheck fails, defaults to `50`
59
- log_lines: 100
@@ -1,62 +0,0 @@
1
- # Traefik
2
- #
3
- # Traefik is a reverse proxy, used by Kamal for zero-downtime deployments.
4
- #
5
- # We start an instance on the hosts in it's own container.
6
- #
7
- # During a deployment:
8
- # 1. We start a new container which Traefik automatically detects due to the labels we have applied
9
- # 2. Traefik starts routing traffic to the new container
10
- # 3. We force the old container to fail it's healthcheck, causing Traefik to stop routing traffic to it
11
- # 4. We stop the old container
12
-
13
- # Traefik settings
14
- #
15
- # Traekik is configured in the root configuration under `traefik`.
16
- traefik:
17
-
18
- # Image
19
- #
20
- # The Traefik image to use, defaults to `traefik:v2.10`
21
- image: traefik:v2.9
22
-
23
- # Host port
24
- #
25
- # The host port to publish the Traefik container on, defaults to `80`
26
- host_port: "8080"
27
-
28
- # Disabling publishing
29
- #
30
- # To avoid publishing the Traefik container, set this to `false`
31
- publish: false
32
-
33
- # Labels
34
- #
35
- # Additional labels to apply to the Traefik container
36
- labels:
37
- traefik.http.routers.catchall.entryPoints: http
38
- traefik.http.routers.catchall.rule: PathPrefix(`/`)
39
- traefik.http.routers.catchall.service: unavailable
40
- traefik.http.routers.catchall.priority: "1"
41
- traefik.http.services.unavailable.loadbalancer.server.port: "0"
42
-
43
- # Arguments
44
- #
45
- # Additional arguments to pass to the Traefik container
46
- args:
47
- entryPoints.http.address: ":80"
48
- entryPoints.http.forwardedHeaders.insecure: true
49
- accesslog: true
50
- accesslog.format: json
51
-
52
- # Options
53
- #
54
- # Additional options to pass to `docker run`
55
- options:
56
- cpus: 2
57
-
58
- # Environment variables
59
- #
60
- # See kamal docs env
61
- env:
62
- ...
@@ -1,63 +0,0 @@
1
- class Kamal::Configuration::Healthcheck
2
- include Kamal::Configuration::Validation
3
-
4
- attr_reader :healthcheck_config
5
-
6
- def initialize(healthcheck_config:, context: "healthcheck")
7
- @healthcheck_config = healthcheck_config || {}
8
- validate! @healthcheck_config, context: context
9
- end
10
-
11
- def merge(other)
12
- self.class.new healthcheck_config: healthcheck_config.deep_merge(other.healthcheck_config)
13
- end
14
-
15
- def cmd
16
- healthcheck_config.fetch("cmd", http_health_check)
17
- end
18
-
19
- def port
20
- healthcheck_config.fetch("port", 3000)
21
- end
22
-
23
- def path
24
- healthcheck_config.fetch("path", "/up")
25
- end
26
-
27
- def max_attempts
28
- healthcheck_config.fetch("max_attempts", 7)
29
- end
30
-
31
- def interval
32
- healthcheck_config.fetch("interval", "1s")
33
- end
34
-
35
- def cord
36
- healthcheck_config.fetch("cord", "/tmp/kamal-cord")
37
- end
38
-
39
- def log_lines
40
- healthcheck_config.fetch("log_lines", 50)
41
- end
42
-
43
- def set_port_or_path?
44
- healthcheck_config["port"].present? || healthcheck_config["path"].present?
45
- end
46
-
47
- def to_h
48
- {
49
- "cmd" => cmd,
50
- "interval" => interval,
51
- "max_attempts" => max_attempts,
52
- "port" => port,
53
- "path" => path,
54
- "cord" => cord,
55
- "log_lines" => log_lines
56
- }
57
- end
58
-
59
- private
60
- def http_health_check
61
- "curl -f #{URI.join("http://localhost:#{port}", path)} || exit 1" if path.present? || port.present?
62
- end
63
- end
@@ -1,60 +0,0 @@
1
- class Kamal::Configuration::Traefik
2
- DEFAULT_IMAGE = "traefik:v2.10"
3
- CONTAINER_PORT = 80
4
- DEFAULT_ARGS = {
5
- "log.level" => "DEBUG"
6
- }
7
- DEFAULT_LABELS = {
8
- # These ensure we serve a 502 rather than a 404 if no containers are available
9
- "traefik.http.routers.catchall.entryPoints" => "http",
10
- "traefik.http.routers.catchall.rule" => "PathPrefix(`/`)",
11
- "traefik.http.routers.catchall.service" => "unavailable",
12
- "traefik.http.routers.catchall.priority" => 1,
13
- "traefik.http.services.unavailable.loadbalancer.server.port" => "0"
14
- }
15
-
16
- include Kamal::Configuration::Validation
17
-
18
- attr_reader :config, :traefik_config
19
-
20
- def initialize(config:)
21
- @config = config
22
- @traefik_config = config.raw_config.traefik || {}
23
- validate! traefik_config
24
- end
25
-
26
- def publish?
27
- traefik_config["publish"] != false
28
- end
29
-
30
- def labels
31
- DEFAULT_LABELS.merge(traefik_config["labels"] || {})
32
- end
33
-
34
- def env
35
- Kamal::Configuration::Env.new \
36
- config: traefik_config.fetch("env", {}),
37
- secrets_file: File.join(config.host_env_directory, "traefik", "traefik.env"),
38
- context: "traefik/env"
39
- end
40
-
41
- def host_port
42
- traefik_config.fetch("host_port", CONTAINER_PORT)
43
- end
44
-
45
- def options
46
- traefik_config.fetch("options", {})
47
- end
48
-
49
- def port
50
- "#{host_port}:#{CONTAINER_PORT}"
51
- end
52
-
53
- def args
54
- DEFAULT_ARGS.merge(traefik_config.fetch("args", {}))
55
- end
56
-
57
- def image
58
- traefik_config.fetch("image", DEFAULT_IMAGE)
59
- end
60
- end