Compare commits
1 Commits
1-9-stable
...
dot-kamal-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70096160c9 |
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -3,7 +3,6 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- 1-9-stable
|
|
||||||
pull_request:
|
pull_request:
|
||||||
jobs:
|
jobs:
|
||||||
rubocop:
|
rubocop:
|
||||||
@@ -31,9 +30,6 @@ jobs:
|
|||||||
gemfile:
|
gemfile:
|
||||||
- Gemfile
|
- Gemfile
|
||||||
- gemfiles/rails_edge.gemfile
|
- gemfiles/rails_edge.gemfile
|
||||||
exclude:
|
|
||||||
- ruby-version: "3.1"
|
|
||||||
gemfile: gemfiles/rails_edge.gemfile
|
|
||||||
name: ${{ format('Tests (Ruby {0})', matrix.ruby-version) }}
|
name: ${{ format('Tests (Ruby {0})', matrix.ruby-version) }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|||||||
1
.github/workflows/docker-publish.yml
vendored
1
.github/workflows/docker-publish.yml
vendored
@@ -51,4 +51,5 @@ jobs:
|
|||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
push: true
|
||||||
tags: |
|
tags: |
|
||||||
|
ghcr.io/basecamp/kamal:latest
|
||||||
ghcr.io/basecamp/kamal:${{ steps.version-tag.outputs.value }}
|
ghcr.io/basecamp/kamal:${{ steps.version-tag.outputs.value }}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ WORKDIR /workdir
|
|||||||
|
|
||||||
# Tell git it's safe to access /workdir/.git even if
|
# Tell git it's safe to access /workdir/.git even if
|
||||||
# the directory is owned by a different user
|
# the directory is owned by a different user
|
||||||
RUN git config --global --add safe.directory '*'
|
RUN git config --global --add safe.directory /workdir
|
||||||
|
|
||||||
# Set the entrypoint to run the installed binary in /workdir
|
# Set the entrypoint to run the installed binary in /workdir
|
||||||
# Example: docker run -it -v "$PWD:/workdir" kamal init
|
# Example: docker run -it -v "$PWD:/workdir" kamal init
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
PATH
|
PATH
|
||||||
remote: .
|
remote: .
|
||||||
specs:
|
specs:
|
||||||
kamal (1.9.3)
|
kamal (1.8.1)
|
||||||
activesupport (>= 7.0)
|
activesupport (>= 7.0)
|
||||||
base64 (~> 0.2)
|
base64 (~> 0.2)
|
||||||
bcrypt_pbkdf (~> 1.0)
|
bcrypt_pbkdf (~> 1.0)
|
||||||
@@ -78,11 +78,11 @@ GEM
|
|||||||
net-sftp (4.0.0)
|
net-sftp (4.0.0)
|
||||||
net-ssh (>= 5.0.0, < 8.0.0)
|
net-ssh (>= 5.0.0, < 8.0.0)
|
||||||
net-ssh (7.2.1)
|
net-ssh (7.2.1)
|
||||||
nokogiri (1.18.8-arm64-darwin)
|
nokogiri (1.16.0-arm64-darwin)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.18.8-x86_64-darwin)
|
nokogiri (1.16.0-x86_64-darwin)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.18.8-x86_64-linux-gnu)
|
nokogiri (1.16.0-x86_64-linux)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
parallel (1.24.0)
|
parallel (1.24.0)
|
||||||
parser (3.3.0.5)
|
parser (3.3.0.5)
|
||||||
|
|||||||
@@ -222,25 +222,6 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "downgrade", "Downgrade accessories from Kamal 2 to 1.9"
|
|
||||||
option :rolling, type: :boolean, default: false, desc: "Upgrade one host at a time"
|
|
||||||
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
|
||||||
def downgrade(name)
|
|
||||||
confirming "This will restart all accessories" do
|
|
||||||
with_lock do
|
|
||||||
host_groups = options[:rolling] ? KAMAL.accessory_hosts : [ KAMAL.accessory_hosts ]
|
|
||||||
host_groups.each do |hosts|
|
|
||||||
host_list = Array(hosts).join(",")
|
|
||||||
KAMAL.with_specific_hosts(hosts) do
|
|
||||||
say "Downgrading #{name} accessories on #{host_list}...", :magenta
|
|
||||||
reboot name
|
|
||||||
say "Downgraded #{name} accessories on #{host_list}...", :magenta
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
def with_accessory(name)
|
def with_accessory(name)
|
||||||
if KAMAL.config.accessory(name)
|
if KAMAL.config.accessory(name)
|
||||||
|
|||||||
@@ -37,9 +37,22 @@ module Kamal::Cli
|
|||||||
|
|
||||||
def load_env
|
def load_env
|
||||||
if destination = options[:destination]
|
if destination = options[:destination]
|
||||||
Dotenv.overload(".env", ".env.#{destination}")
|
if File.exist?(".kamal/env.#{destination}") || File.exist?(".kamal/env")
|
||||||
|
Dotenv.load(".kamal/env.#{destination}", ".kamal/env")
|
||||||
else
|
else
|
||||||
Dotenv.overload(".env")
|
loading_files = [ (".env" if File.exist?(".env")), (".env.#{destination}" if File.exist?(".env.#{destination}")) ].compact
|
||||||
|
if loading_files.any?
|
||||||
|
warn "Loading #{loading_files.join(" and ")} from the project root, use .kamal/env* instead"
|
||||||
|
Dotenv.load(".env.#{destination}", ".env")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if File.exist?(".kamal/env")
|
||||||
|
Dotenv.load(".kamal/env")
|
||||||
|
elsif File.exist?(".env")
|
||||||
|
warn "Loading .env from the project root is deprecated, use .kamal/env instead"
|
||||||
|
Dotenv.load(".env")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -206,10 +219,6 @@ module Kamal::Cli
|
|||||||
instance_variable_get("@_invocations").first
|
instance_variable_get("@_invocations").first
|
||||||
end
|
end
|
||||||
|
|
||||||
def reset_invocation(cli_class)
|
|
||||||
instance_variable_get("@_invocations")[cli_class].pop
|
|
||||||
end
|
|
||||||
|
|
||||||
def ensure_run_and_locks_directory
|
def ensure_run_and_locks_directory
|
||||||
on(KAMAL.hosts) do
|
on(KAMAL.hosts) do
|
||||||
execute(*KAMAL.server.ensure_run_directory)
|
execute(*KAMAL.server.ensure_run_directory)
|
||||||
|
|||||||
@@ -182,6 +182,15 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
desc "envify", "Create .env by evaluating .env.erb (or .env.staging.erb -> .env.staging when using -d staging)"
|
desc "envify", "Create .env by evaluating .env.erb (or .env.staging.erb -> .env.staging when using -d staging)"
|
||||||
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip .env file push"
|
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip .env file push"
|
||||||
def envify
|
def envify
|
||||||
|
if destination = options[:destination]
|
||||||
|
env_template_path = ".kamal/env.#{destination}.erb"
|
||||||
|
env_path = ".kamal/env.#{destination}"
|
||||||
|
else
|
||||||
|
env_template_path = ".kamal/env.erb"
|
||||||
|
env_path = ".kamal/env"
|
||||||
|
end
|
||||||
|
|
||||||
|
unless Pathname.new(File.expand_path(env_template_path)).exist?
|
||||||
if destination = options[:destination]
|
if destination = options[:destination]
|
||||||
env_template_path = ".env.#{destination}.erb"
|
env_template_path = ".env.#{destination}.erb"
|
||||||
env_path = ".env.#{destination}"
|
env_path = ".env.#{destination}"
|
||||||
@@ -190,6 +199,11 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
env_path = ".env"
|
env_path = ".env"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if Pathname.new(File.expand_path(env_template_path)).exist?
|
||||||
|
warn "Loading #{env_template_path} from the project root is deprecated, use .kamal/env[.<DESTINATION>].erb instead"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if Pathname.new(File.expand_path(env_template_path)).exist?
|
if Pathname.new(File.expand_path(env_template_path)).exist?
|
||||||
# Ensure existing env doesn't pollute template evaluation
|
# Ensure existing env doesn't pollute template evaluation
|
||||||
content = with_original_env { ERB.new(File.read(env_template_path), trim_mode: "-").result }
|
content = with_original_env { ERB.new(File.read(env_template_path), trim_mode: "-").result }
|
||||||
@@ -217,37 +231,6 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "downgrade", "Downgrade from Kamal 2 to 1.9"
|
|
||||||
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
|
||||||
option :rolling, type: :boolean, default: false, desc: "Downgrade one host at a time"
|
|
||||||
def downgrade
|
|
||||||
confirming "This will replace Traefik with kamal-proxy and restart all accessories" do
|
|
||||||
with_lock do
|
|
||||||
if options[:rolling]
|
|
||||||
(KAMAL.hosts | KAMAL.accessory_hosts).each do |host|
|
|
||||||
KAMAL.with_specific_hosts(host) do
|
|
||||||
say "Downgrading #{host}...", :magenta
|
|
||||||
if KAMAL.hosts.include?(host)
|
|
||||||
invoke "kamal:cli:traefik:downgrade", [], options.merge(confirmed: true, rolling: false)
|
|
||||||
reset_invocation(Kamal::Cli::Traefik)
|
|
||||||
end
|
|
||||||
if KAMAL.accessory_hosts.include?(host)
|
|
||||||
invoke "kamal:cli:accessory:downgrade", [ "all" ], options.merge(confirmed: true, rolling: false)
|
|
||||||
reset_invocation(Kamal::Cli::Accessory)
|
|
||||||
end
|
|
||||||
say "Downgraded #{host}", :magenta
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
say "Downgrading all hosts...", :magenta
|
|
||||||
invoke "kamal:cli:traefik:downgrade", [], options.merge(confirmed: true)
|
|
||||||
invoke "kamal:cli:accessory:downgrade", [ "all" ], options.merge(confirmed: true)
|
|
||||||
say "Downgraded all hosts", :magenta
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "version", "Show Kamal version"
|
desc "version", "Show Kamal version"
|
||||||
def version
|
def version
|
||||||
puts Kamal::VERSION
|
puts Kamal::VERSION
|
||||||
|
|||||||
@@ -119,44 +119,4 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "downgrade", "Downgrade to Traefik on servers (stop container, remove container, start new container, reboot app)"
|
|
||||||
option :rolling, type: :boolean, default: false, desc: "Reboot proxy on hosts in sequence, rather than in parallel"
|
|
||||||
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
|
||||||
def downgrade
|
|
||||||
invoke_options = { "version" => KAMAL.config.latest_tag }.merge(options)
|
|
||||||
|
|
||||||
confirming "This will cause a brief outage on each host. Are you sure?" do
|
|
||||||
host_groups = options[:rolling] ? KAMAL.hosts : [ KAMAL.hosts ]
|
|
||||||
host_groups.each do |hosts|
|
|
||||||
host_list = Array(hosts).join(",")
|
|
||||||
say "Downgrading to Traefik on #{host_list}...", :magenta
|
|
||||||
run_hook "pre-traefik-reboot", hosts: host_list
|
|
||||||
on(hosts) do |host|
|
|
||||||
execute *KAMAL.auditor.record("Rebooted Traefik"), verbosity: :debug
|
|
||||||
execute *KAMAL.registry.login
|
|
||||||
|
|
||||||
"Stopping and removing kamal-proxy on #{host}, if running..."
|
|
||||||
execute *KAMAL.traefik.cleanup_kamal_proxy
|
|
||||||
|
|
||||||
"Stopping and removing Traefik on #{host}, if running..."
|
|
||||||
execute *KAMAL.traefik.stop, raise_on_non_zero_exit: false
|
|
||||||
execute *KAMAL.traefik.remove_container
|
|
||||||
execute *KAMAL.traefik.remove_image
|
|
||||||
end
|
|
||||||
|
|
||||||
KAMAL.with_specific_hosts(hosts) do
|
|
||||||
invoke "kamal:cli:traefik:boot", [], invoke_options
|
|
||||||
reset_invocation(Kamal::Cli::Traefik)
|
|
||||||
invoke "kamal:cli:app:boot", [], invoke_options
|
|
||||||
reset_invocation(Kamal::Cli::App)
|
|
||||||
invoke "kamal:cli:prune:all", [], invoke_options
|
|
||||||
reset_invocation(Kamal::Cli::Prune)
|
|
||||||
end
|
|
||||||
|
|
||||||
run_hook "post-traefik-reboot", hosts: host_list
|
|
||||||
say "Downgraded to Traefik on #{host_list}", :magenta
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -56,13 +56,6 @@ class Kamal::Commander
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def with_specific_hosts(hosts)
|
|
||||||
original_hosts, self.specific_hosts = specific_hosts, hosts
|
|
||||||
yield
|
|
||||||
ensure
|
|
||||||
self.specific_hosts = original_hosts
|
|
||||||
end
|
|
||||||
|
|
||||||
def accessory_names
|
def accessory_names
|
||||||
config.accessories&.collect(&:name) || []
|
config.accessories&.collect(&:name) || []
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class Kamal::Commander::Specifics
|
|||||||
end
|
end
|
||||||
|
|
||||||
def accessory_hosts
|
def accessory_hosts
|
||||||
config.accessories.flat_map(&:hosts) & specified_hosts
|
specific_hosts || config.accessories.flat_map(&:hosts)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ module Kamal::Commands::Builder::Clone
|
|||||||
end
|
end
|
||||||
|
|
||||||
def clone
|
def clone
|
||||||
git :clone, Kamal::Git.root, "--recurse-submodules", path: clone_directory
|
git :clone, Kamal::Git.root, path: clone_directory
|
||||||
end
|
end
|
||||||
|
|
||||||
def clone_reset_steps
|
def clone_reset_steps
|
||||||
@@ -14,8 +14,7 @@ module Kamal::Commands::Builder::Clone
|
|||||||
git(:remote, "set-url", :origin, Kamal::Git.root, path: build_directory),
|
git(:remote, "set-url", :origin, Kamal::Git.root, path: build_directory),
|
||||||
git(:fetch, :origin, path: build_directory),
|
git(:fetch, :origin, path: build_directory),
|
||||||
git(:reset, "--hard", Kamal::Git.revision, path: build_directory),
|
git(:reset, "--hard", Kamal::Git.revision, path: build_directory),
|
||||||
git(:clean, "-fdx", path: build_directory),
|
git(:clean, "-fdx", path: build_directory)
|
||||||
git(:submodule, :update, "--init", path: build_directory)
|
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -58,8 +58,4 @@ class Kamal::Commands::Builder::Multiarch::Remote < Kamal::Commands::Builder::Mu
|
|||||||
def remove_context(arch)
|
def remove_context(arch)
|
||||||
docker :context, :rm, builder_name_with_arch(arch)
|
docker :context, :rm, builder_name_with_arch(arch)
|
||||||
end
|
end
|
||||||
|
|
||||||
def platform_names
|
|
||||||
"linux/#{local_arch},linux/#{remote_arch}"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -62,15 +62,6 @@ class Kamal::Commands::Traefik < Kamal::Commands::Base
|
|||||||
[ :rm, "-f", env.secrets_file ]
|
[ :rm, "-f", env.secrets_file ]
|
||||||
end
|
end
|
||||||
|
|
||||||
def cleanup_kamal_proxy
|
|
||||||
chain \
|
|
||||||
docker(:container, :stop, "kamal-proxy"),
|
|
||||||
combine(
|
|
||||||
docker(:container, :prune, "--force", "--filter", "label=org.opencontainers.image.title=kamal-proxy"),
|
|
||||||
docker(:image, :prune, "--all", "--force", "--filter", "label=org.opencontainers.image.title=kamal-proxy")
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
def publish_args
|
def publish_args
|
||||||
argumentize "--publish", port if publish?
|
argumentize "--publish", port if publish?
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ env:
|
|||||||
# To pass the secrets you should list them under the `secret` key. When you do this the
|
# To pass the secrets you should list them under the `secret` key. When you do this the
|
||||||
# other variables need to be moved under the `clear` key.
|
# other variables need to be moved under the `clear` key.
|
||||||
#
|
#
|
||||||
# Unlike clear values, secrets are not passed directly to the container,
|
# Unlike clear valies, secrets are not passed directly to the container,
|
||||||
# but are stored in an env file on the host
|
# but are stored in an env file on the host
|
||||||
# The file is not updated when deploying, only when running `kamal envify` or `kamal env push`.
|
# The file is not updated when deploying, only when running `kamal envify` or `kamal env push`.
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ traefik:
|
|||||||
|
|
||||||
# Image
|
# Image
|
||||||
#
|
#
|
||||||
# The Traefik image to use, defaults to `traefik:v2.11`
|
# The Traefik image to use, defaults to `traefik:v2.10`
|
||||||
image: traefik:v2.11
|
image: traefik:v2.9
|
||||||
|
|
||||||
# Host port
|
# Host port
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
class Kamal::Configuration::Traefik
|
class Kamal::Configuration::Traefik
|
||||||
DEFAULT_IMAGE = "traefik:v2.11"
|
DEFAULT_IMAGE = "traefik:v2.10"
|
||||||
CONTAINER_PORT = 80
|
CONTAINER_PORT = 80
|
||||||
DEFAULT_ARGS = {
|
DEFAULT_ARGS = {
|
||||||
"log.level" => "DEBUG"
|
"log.level" => "DEBUG"
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
module Kamal
|
module Kamal
|
||||||
VERSION = "1.9.3"
|
VERSION = "1.8.1"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -209,24 +209,6 @@ class CliAccessoryTest < CliTestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "downgrade" do
|
|
||||||
run_command("downgrade", "-y", "all").tap do |output|
|
|
||||||
assert_match "Downgrading all accessories on 1.1.1.3,1.1.1.1,1.1.1.2...", output
|
|
||||||
assert_match "docker container stop app-mysql on 1.1.1.3", output
|
|
||||||
assert_match "docker run --name app-mysql --detach --restart unless-stopped --log-opt max-size=\"10m\" --publish 3306:3306 --env-file .kamal/env/accessories/app-mysql.env --env MYSQL_ROOT_HOST=\"%\" --volume $PWD/app-mysql/etc/mysql/my.cnf:/etc/mysql/my.cnf --volume $PWD/app-mysql/data:/var/lib/mysql --label service=\"app-mysql\" mysql:5.7 on 1.1.1.3", output
|
|
||||||
assert_match "Downgraded all accessories on 1.1.1.3,1.1.1.1,1.1.1.2", output
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test "downgrade rolling" do
|
|
||||||
run_command("downgrade", "--rolling", "-y", "all").tap do |output|
|
|
||||||
assert_match "Downgrading all accessories on 1.1.1.3...", output
|
|
||||||
assert_match "docker container stop app-mysql on 1.1.1.3", output
|
|
||||||
assert_match "docker run --name app-mysql --detach --restart unless-stopped --log-opt max-size=\"10m\" --publish 3306:3306 --env-file .kamal/env/accessories/app-mysql.env --env MYSQL_ROOT_HOST=\"%\" --volume $PWD/app-mysql/etc/mysql/my.cnf:/etc/mysql/my.cnf --volume $PWD/app-mysql/data:/var/lib/mysql --label service=\"app-mysql\" mysql:5.7 on 1.1.1.3", output
|
|
||||||
assert_match "Downgraded all accessories on 1.1.1.3", output
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
def run_command(*command)
|
def run_command(*command)
|
||||||
stdouted { Kamal::Cli::Accessory.start([ *command, "-c", "test/fixtures/deploy_with_accessories.yml" ]) }
|
stdouted { Kamal::Cli::Accessory.start([ *command, "-c", "test/fixtures/deploy_with_accessories.yml" ]) }
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class CliBuildTest < CliTestCase
|
|||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:docker, "--version", "&&", :docker, :buildx, "version")
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:docker, "--version", "&&", :docker, :buildx, "version")
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute)
|
SSHKit::Backend::Abstract.any_instance.expects(:execute)
|
||||||
.with(:git, "-C", "#{Dir.tmpdir}/kamal-clones/app-#{pwd_sha}", :clone, Dir.pwd, "--recurse-submodules")
|
.with(:git, "-C", "#{Dir.tmpdir}/kamal-clones/app-#{pwd_sha}", :clone, Dir.pwd)
|
||||||
.raises(SSHKit::Command::Failed.new("fatal: destination path 'kamal' already exists and is not an empty directory"))
|
.raises(SSHKit::Command::Failed.new("fatal: destination path 'kamal' already exists and is not an empty directory"))
|
||||||
.then
|
.then
|
||||||
.returns(true)
|
.returns(true)
|
||||||
@@ -50,7 +50,6 @@ class CliBuildTest < CliTestCase
|
|||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:git, "-C", build_directory, :fetch, :origin)
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:git, "-C", build_directory, :fetch, :origin)
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:git, "-C", build_directory, :reset, "--hard", Kamal::Git.revision)
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:git, "-C", build_directory, :reset, "--hard", Kamal::Git.revision)
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:git, "-C", build_directory, :clean, "-fdx")
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:git, "-C", build_directory, :clean, "-fdx")
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:git, "-C", build_directory, :submodule, :update, "--init")
|
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute)
|
SSHKit::Backend::Abstract.any_instance.expects(:execute)
|
||||||
.with(:docker, :buildx, :build, "--push", "--platform", "linux/amd64,linux/arm64", "--builder", "kamal-app-multiarch", "-t", "dhh/app:999", "-t", "dhh/app:latest", "--label", "service=\"app\"", "--file", "Dockerfile", ".")
|
.with(:docker, :buildx, :build, "--push", "--platform", "linux/amd64,linux/arm64", "--builder", "kamal-app-multiarch", "-t", "dhh/app:999", "-t", "dhh/app:latest", "--label", "service=\"app\"", "--file", "Dockerfile", ".")
|
||||||
@@ -89,7 +88,7 @@ class CliBuildTest < CliTestCase
|
|||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:docker, "--version", "&&", :docker, :buildx, "version")
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:docker, "--version", "&&", :docker, :buildx, "version")
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute)
|
SSHKit::Backend::Abstract.any_instance.expects(:execute)
|
||||||
.with(:git, "-C", "#{Dir.tmpdir}/kamal-clones/app-#{pwd_sha}", :clone, Dir.pwd, "--recurse-submodules")
|
.with(:git, "-C", "#{Dir.tmpdir}/kamal-clones/app-#{pwd_sha}", :clone, Dir.pwd)
|
||||||
.raises(SSHKit::Command::Failed.new("fatal: destination path 'kamal' already exists and is not an empty directory"))
|
.raises(SSHKit::Command::Failed.new("fatal: destination path 'kamal' already exists and is not an empty directory"))
|
||||||
.then
|
.then
|
||||||
.returns(true)
|
.returns(true)
|
||||||
|
|||||||
@@ -447,9 +447,9 @@ class CliMainTest < CliTestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "envify" do
|
test "envify" do
|
||||||
with_test_dotenv(".env.erb": "HELLO=<%= 'world' %>") do
|
with_test_env_files("env.erb": "HELLO=<%= 'world' %>") do
|
||||||
run_command("envify")
|
run_command("envify")
|
||||||
assert_equal("HELLO=world", File.read(".env"))
|
assert_equal("HELLO=world", File.read(".kamal/env"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -461,68 +461,35 @@ class CliMainTest < CliTestCase
|
|||||||
<% end -%>
|
<% end -%>
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
with_test_dotenv(".env.erb": file) do
|
with_test_env_files("env.erb": file) do
|
||||||
run_command("envify")
|
run_command("envify")
|
||||||
assert_equal("HELLO=world\nKEY=value\n", File.read(".env"))
|
assert_equal("HELLO=world\nKEY=value\n", File.read(".kamal/env"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "envify with destination" do
|
test "envify with destination" do
|
||||||
with_test_dotenv(".env.world.erb": "HELLO=<%= 'world' %>") do
|
with_test_env_files("env.world.erb": "HELLO=<%= 'world' %>") do
|
||||||
run_command("envify", "-d", "world", config_file: "deploy_for_dest")
|
run_command("envify", "-d", "world", config_file: "deploy_for_dest")
|
||||||
assert_equal "HELLO=world", File.read(".env.world")
|
assert_equal "HELLO=world", File.read(".kamal/env.world")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "envify with skip_push" do
|
test "envify with skip_push" do
|
||||||
Pathname.any_instance.expects(:exist?).returns(true).times(1)
|
Pathname.any_instance.expects(:exist?).returns(true).times(2)
|
||||||
File.expects(:read).with(".env.erb").returns("HELLO=<%= 'world' %>")
|
File.expects(:read).with(".kamal/env.erb").returns("HELLO=<%= 'world' %>")
|
||||||
File.expects(:write).with(".env", "HELLO=world", perm: 0600)
|
File.expects(:write).with(".kamal/env", "HELLO=world", perm: 0600)
|
||||||
|
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:env:push").never
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:env:push").never
|
||||||
run_command("envify", "--skip-push")
|
run_command("envify", "--skip-push")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "envify with clean env" do
|
test "envify with clean env" do
|
||||||
with_test_dotenv(".env": "HELLO=already", ".env.erb": "HELLO=<%= ENV.fetch 'HELLO', 'never' %>") do
|
with_test_env_files("env": "HELLO=already", "env.erb": "HELLO=<%= ENV.fetch 'HELLO', 'never' %>") do
|
||||||
run_command("envify", "--skip-push")
|
run_command("envify", "--skip-push")
|
||||||
assert_equal "HELLO=never", File.read(".env")
|
assert_equal "HELLO=never", File.read(".kamal/env")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "env files overwrite shell environment variables" do
|
|
||||||
ENV["TEST_VAR"] = "shell_value"
|
|
||||||
ENV["AWS_ACCESS_KEY_ID"] = "local_dev_key"
|
|
||||||
|
|
||||||
with_test_dotenv(".env": "TEST_VAR=dotenv_value\nAWS_ACCESS_KEY_ID=production_key") do
|
|
||||||
# Create a simple CLI command instance to trigger load_env
|
|
||||||
Kamal::Cli::Main.new.send(:load_env)
|
|
||||||
|
|
||||||
assert_equal "dotenv_value", ENV["TEST_VAR"]
|
|
||||||
assert_equal "production_key", ENV["AWS_ACCESS_KEY_ID"]
|
|
||||||
end
|
|
||||||
ensure
|
|
||||||
ENV.delete("TEST_VAR")
|
|
||||||
ENV.delete("AWS_ACCESS_KEY_ID")
|
|
||||||
end
|
|
||||||
|
|
||||||
test "destination env files overwrite base env files" do
|
|
||||||
ENV["TEST_VAR"] = "shell_value"
|
|
||||||
|
|
||||||
with_test_dotenv(".env": "TEST_VAR=base_value\nBASE_ONLY=base", ".env.world": "TEST_VAR=world_value\nWORLD_ONLY=world") do
|
|
||||||
# Create CLI command with destination to trigger load_env
|
|
||||||
Kamal::Cli::Main.new([], { destination: "world" }).send(:load_env)
|
|
||||||
|
|
||||||
assert_equal "world_value", ENV["TEST_VAR"]
|
|
||||||
assert_equal "base", ENV["BASE_ONLY"]
|
|
||||||
assert_equal "world", ENV["WORLD_ONLY"]
|
|
||||||
end
|
|
||||||
ensure
|
|
||||||
ENV.delete("TEST_VAR")
|
|
||||||
ENV.delete("BASE_ONLY")
|
|
||||||
ENV.delete("WORLD_ONLY")
|
|
||||||
end
|
|
||||||
|
|
||||||
test "remove with confirmation" do
|
test "remove with confirmation" do
|
||||||
run_command("remove", "-y", config_file: "deploy_with_accessories").tap do |output|
|
run_command("remove", "-y", config_file: "deploy_with_accessories").tap do |output|
|
||||||
assert_match /docker container stop traefik/, output
|
assert_match /docker container stop traefik/, output
|
||||||
@@ -570,49 +537,24 @@ class CliMainTest < CliTestCase
|
|||||||
assert_equal Kamal::VERSION, version
|
assert_equal Kamal::VERSION, version
|
||||||
end
|
end
|
||||||
|
|
||||||
test "downgrade" do
|
|
||||||
invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_hooks" => false, "confirmed" => true, "rolling" => false }
|
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:traefik:downgrade", [], invoke_options)
|
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:accessory:downgrade", [ "all" ], invoke_options)
|
|
||||||
|
|
||||||
run_command("downgrade", "-y", config_file: "deploy_with_accessories").tap do |output|
|
|
||||||
assert_match "Downgrading all hosts...", output
|
|
||||||
assert_match "Downgraded all hosts", output
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test "downgrade rolling" do
|
|
||||||
invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_hooks" => false, "confirmed" => true, "rolling" => false }
|
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:traefik:downgrade", [], invoke_options).times(4)
|
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:accessory:downgrade", [ "all" ], invoke_options).times(3)
|
|
||||||
|
|
||||||
run_command("downgrade", "--rolling", "-y", config_file: "deploy_with_accessories").tap do |output|
|
|
||||||
assert_match "Downgrading 1.1.1.1...", output
|
|
||||||
assert_match "Downgraded 1.1.1.1", output
|
|
||||||
assert_match "Downgrading 1.1.1.2...", output
|
|
||||||
assert_match "Downgraded 1.1.1.2", output
|
|
||||||
assert_match "Downgrading 1.1.1.3...", output
|
|
||||||
assert_match "Downgraded 1.1.1.3", output
|
|
||||||
assert_match "Downgrading 1.1.1.4...", output
|
|
||||||
assert_match "Downgraded 1.1.1.4", output
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
def run_command(*command, config_file: "deploy_simple")
|
def run_command(*command, config_file: "deploy_simple")
|
||||||
stdouted { Kamal::Cli::Main.start([ *command, "-c", "test/fixtures/#{config_file}.yml" ]) }
|
stdouted { Kamal::Cli::Main.start([ *command, "-c", "test/fixtures/#{config_file}.yml" ]) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def with_test_dotenv(**files)
|
def with_test_env_files(**files)
|
||||||
Dir.mktmpdir do |dir|
|
Dir.mktmpdir do |dir|
|
||||||
fixtures_dup = File.join(dir, "test")
|
fixtures_dup = File.join(dir, "test")
|
||||||
FileUtils.mkdir_p(fixtures_dup)
|
FileUtils.mkdir_p(fixtures_dup)
|
||||||
FileUtils.cp_r("test/fixtures/", fixtures_dup)
|
FileUtils.cp_r("test/fixtures/", fixtures_dup)
|
||||||
|
|
||||||
Dir.chdir(dir) do
|
Dir.chdir(dir) do
|
||||||
|
FileUtils.mkdir_p(".kamal")
|
||||||
|
Dir.chdir(".kamal") do
|
||||||
files.each do |filename, contents|
|
files.each do |filename, contents|
|
||||||
File.binwrite(filename.to_s, contents)
|
File.binwrite(filename.to_s, contents)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
yield
|
yield
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -103,90 +103,6 @@ class CliTraefikTest < CliTestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "downgrade" do
|
|
||||||
Object.any_instance.stubs(:sleep)
|
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
|
||||||
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-web-latest$", "--quiet", raise_on_non_zero_exit: false)
|
|
||||||
.returns("12345678")
|
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
|
||||||
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-workers-latest$", "--quiet", raise_on_non_zero_exit: false)
|
|
||||||
.returns("12345678")
|
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
|
||||||
.with { |*args| args[0..1] == [ :sh, "-c" ] }
|
|
||||||
.returns("123") # old version
|
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
|
||||||
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-web-latest$", "--quiet", "|", :xargs, :docker, :inspect, "--format", "'{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'")
|
|
||||||
.returns("running") # health check
|
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
|
||||||
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-workers-latest$", "--quiet", "|", :xargs, :docker, :inspect, "--format", "'{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'")
|
|
||||||
.returns("running").at_least_once # workers health check
|
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
|
||||||
.with(:docker, :inspect, "-f '{{ range .Mounts }}{{printf \"%s %s\\n\" .Source .Destination}}{{ end }}'", "app-web-123", "|", :awk, "'$2 == \"/tmp/kamal-cord\" {print $1}'", raise_on_non_zero_exit: false)
|
|
||||||
.returns("") # old version
|
|
||||||
|
|
||||||
run_command("downgrade", "-y").tap do |output|
|
|
||||||
assert_match "Downgrading to Traefik on 1.1.1.1,1.1.1.2,1.1.1.3,1.1.1.4...", output
|
|
||||||
assert_match "docker login -u [REDACTED] -p [REDACTED]", output
|
|
||||||
assert_match "docker container stop kamal-proxy ; docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy && docker image prune --all --force --filter label=org.opencontainers.image.title=kamal-proxy", output
|
|
||||||
assert_match "docker container stop traefik", output
|
|
||||||
assert_match "docker container prune --force --filter label=org.opencontainers.image.title=Traefik", output
|
|
||||||
assert_match "docker image prune --all --force --filter label=org.opencontainers.image.title=Traefik", output
|
|
||||||
assert_match "/usr/bin/env mkdir -p .kamal", output
|
|
||||||
assert_match "docker login -u [REDACTED] -p [REDACTED]", output
|
|
||||||
assert_match "docker container start traefik || docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --label traefik.http.routers.catchall.entryPoints=\"http\" --label traefik.http.routers.catchall.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.catchall.service=\"unavailable\" --label traefik.http.routers.catchall.priority=\"1\" --label traefik.http.services.unavailable.loadbalancer.server.port=\"0\" traefik:v2.11 --providers.docker --log.level=\"DEBUG\"", output
|
|
||||||
assert_match "/usr/bin/env mkdir -p .kamal", output
|
|
||||||
assert_match %r{docker rename app-web-latest app-web-latest_replaced_.*}, output
|
|
||||||
assert_match %r{docker run --detach --restart unless-stopped --name app-web-latest --hostname 1.1.1.1-.* -e KAMAL_CONTAINER_NAME="app-web-latest" -e KAMAL_VERSION="latest" --env-file .kamal/env/roles/app-web.env --health-cmd}, output
|
|
||||||
assert_match "docker tag dhh/app:latest dhh/app:latest", output
|
|
||||||
assert_match "/usr/bin/env mkdir -p .kamal", output
|
|
||||||
assert_match "docker ps -q -a --filter label=service=app --filter status=created --filter status=exited --filter status=dead | tail -n +6 | while read container_id; do docker rm $container_id; done", output
|
|
||||||
assert_match "docker image prune --force --filter label=service=app", output
|
|
||||||
assert_match "Downgraded to Traefik on 1.1.1.1,1.1.1.2,1.1.1.3,1.1.1.4", output
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test "downgrade rolling" do
|
|
||||||
Object.any_instance.stubs(:sleep)
|
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
|
||||||
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-web-latest$", "--quiet", raise_on_non_zero_exit: false)
|
|
||||||
.returns("12345678")
|
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
|
||||||
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-workers-latest$", "--quiet", raise_on_non_zero_exit: false)
|
|
||||||
.returns("12345678")
|
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
|
||||||
.with { |*args| args[0..1] == [ :sh, "-c" ] }
|
|
||||||
.returns("123") # old version
|
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
|
||||||
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-web-latest$", "--quiet", "|", :xargs, :docker, :inspect, "--format", "'{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'")
|
|
||||||
.returns("running") # health check
|
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
|
||||||
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-workers-latest$", "--quiet", "|", :xargs, :docker, :inspect, "--format", "'{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'")
|
|
||||||
.returns("running").at_least_once # workers health check
|
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
|
||||||
.with(:docker, :inspect, "-f '{{ range .Mounts }}{{printf \"%s %s\\n\" .Source .Destination}}{{ end }}'", "app-web-123", "|", :awk, "'$2 == \"/tmp/kamal-cord\" {print $1}'", raise_on_non_zero_exit: false)
|
|
||||||
.returns("") # old version
|
|
||||||
|
|
||||||
run_command("downgrade", "--rolling", "-y",).tap do |output|
|
|
||||||
%w[1.1.1.1 1.1.1.2 1.1.1.3 1.1.1.4].each do |host|
|
|
||||||
assert_match "Downgrading to Traefik on #{host}...", output
|
|
||||||
assert_match "docker container stop kamal-proxy ; docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy && docker image prune --all --force --filter label=org.opencontainers.image.title=kamal-proxy", output
|
|
||||||
assert_match "Downgraded to Traefik on #{host}", output
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
def run_command(*command)
|
def run_command(*command)
|
||||||
stdouted { Kamal::Cli::Traefik.start([ *command, "-c", "test/fixtures/deploy_with_accessories.yml" ]) }
|
stdouted { Kamal::Cli::Traefik.start([ *command, "-c", "test/fixtures/deploy_with_accessories.yml" ]) }
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ class CommandsBuilderTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "target multiarch remote when local and remote is set" do
|
test "target multiarch remote when local and remote is set" do
|
||||||
builder = new_builder_command(builder: { "local" => { "arch" => "arm64" }, "remote" => { "arch" => "amd64" }, "cache" => { "type" => "gha" } })
|
builder = new_builder_command(builder: { "local" => {}, "remote" => {}, "cache" => { "type" => "gha" } })
|
||||||
assert_equal "multiarch/remote", builder.name
|
assert_equal "multiarch/remote", builder.name
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker buildx build --push --platform linux/arm64,linux/amd64 --builder kamal-app-multiarch-remote -t dhh/app:123 -t dhh/app:latest --cache-to type=gha --cache-from type=gha --label service=\"app\" --file Dockerfile .",
|
"docker buildx build --push --platform linux/amd64,linux/arm64 --builder kamal-app-multiarch-remote -t dhh/app:123 -t dhh/app:latest --cache-to type=gha --cache-from type=gha --label service=\"app\" --file Dockerfile .",
|
||||||
builder.push.join(" ")
|
builder.push.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ services:
|
|||||||
context: docker/registry
|
context: docker/registry
|
||||||
environment:
|
environment:
|
||||||
- REGISTRY_HTTP_ADDR=0.0.0.0:4443
|
- REGISTRY_HTTP_ADDR=0.0.0.0:4443
|
||||||
|
- REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt
|
||||||
|
- REGISTRY_HTTP_TLS_KEY=/certs/domain.key
|
||||||
volumes:
|
volumes:
|
||||||
- shared:/shared
|
- shared:/shared
|
||||||
- registry:/var/lib/registry/
|
- registry:/var/lib/registry/
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ COPY app_with_roles/ app_with_roles/
|
|||||||
|
|
||||||
RUN rm -rf /root/.ssh
|
RUN rm -rf /root/.ssh
|
||||||
RUN ln -s /shared/ssh /root/.ssh
|
RUN ln -s /shared/ssh /root/.ssh
|
||||||
|
RUN mkdir -p /etc/docker/certs.d/registry:4443 && ln -s /shared/certs/domain.crt /etc/docker/certs.d/registry:4443/ca.crt
|
||||||
|
|
||||||
RUN git config --global user.email "deployer@example.com"
|
RUN git config --global user.email "deployer@example.com"
|
||||||
RUN git config --global user.name "Deployer"
|
RUN git config --global user.name "Deployer"
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ traefik:
|
|||||||
args:
|
args:
|
||||||
accesslog: true
|
accesslog: true
|
||||||
accesslog.format: json
|
accesslog.format: json
|
||||||
image: registry:4443/traefik:v2.11
|
image: registry:4443/traefik:v2.10
|
||||||
accessories:
|
accessories:
|
||||||
busybox:
|
busybox:
|
||||||
service: custom-busybox
|
service: custom-busybox
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ traefik:
|
|||||||
args:
|
args:
|
||||||
accesslog: true
|
accesslog: true
|
||||||
accesslog.format: json
|
accesslog.format: json
|
||||||
image: registry:4443/traefik:v2.11
|
image: registry:4443/traefik:v2.10
|
||||||
accessories:
|
accessories:
|
||||||
busybox:
|
busybox:
|
||||||
service: custom-busybox
|
service: custom-busybox
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
dockerd --max-concurrent-downloads 1 --insecure-registry registry:4443 &
|
dockerd --max-concurrent-downloads 1 &
|
||||||
|
|
||||||
exec sleep infinity
|
exec sleep infinity
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ push_image_to_registry_4443() {
|
|||||||
|
|
||||||
install_kamal
|
install_kamal
|
||||||
push_image_to_registry_4443 nginx 1-alpine-slim
|
push_image_to_registry_4443 nginx 1-alpine-slim
|
||||||
push_image_to_registry_4443 traefik v2.11
|
push_image_to_registry_4443 traefik v2.10
|
||||||
push_image_to_registry_4443 busybox 1.36.0
|
push_image_to_registry_4443 busybox 1.36.0
|
||||||
|
|
||||||
# .ssh is on a shared volume that persists between runs. Clean it up as the
|
# .ssh is on a shared volume that persists between runs. Clean it up as the
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM registry:3
|
FROM registry
|
||||||
|
|
||||||
COPY boot.sh .
|
COPY boot.sh .
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
exec /entrypoint.sh /etc/distribution/config.yml
|
while [ ! -f /certs/domain.crt ]; do sleep 1; done
|
||||||
|
|
||||||
|
exec /entrypoint.sh /etc/docker/registry/config.yml
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ RUN mkdir ssh && \
|
|||||||
COPY registry-dns.conf .
|
COPY registry-dns.conf .
|
||||||
COPY boot.sh .
|
COPY boot.sh .
|
||||||
|
|
||||||
|
RUN mkdir certs && openssl req -newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key -x509 -days 365 -out certs/domain.crt -subj '/CN=registry' -extensions EXT -config registry-dns.conf
|
||||||
|
|
||||||
HEALTHCHECK --interval=1s CMD pgrep sleep
|
HEALTHCHECK --interval=1s CMD pgrep sleep
|
||||||
|
|
||||||
CMD ["./boot.sh"]
|
CMD ["./boot.sh"]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ WORKDIR /work
|
|||||||
RUN apt-get update --fix-missing && apt-get -y install openssh-client openssh-server docker.io
|
RUN apt-get update --fix-missing && apt-get -y install openssh-client openssh-server docker.io
|
||||||
|
|
||||||
RUN mkdir /root/.ssh && ln -s /shared/ssh/id_rsa.pub /root/.ssh/authorized_keys
|
RUN mkdir /root/.ssh && ln -s /shared/ssh/id_rsa.pub /root/.ssh/authorized_keys
|
||||||
|
RUN mkdir -p /etc/docker/certs.d/registry:4443 && ln -s /shared/certs/domain.crt /etc/docker/certs.d/registry:4443/ca.crt
|
||||||
|
|
||||||
RUN echo "HOST_TOKEN=abcd" >> /etc/environment
|
RUN echo "HOST_TOKEN=abcd" >> /etc/environment
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ while [ ! -f /root/.ssh/authorized_keys ]; do echo "Waiting for ssh keys"; sleep
|
|||||||
|
|
||||||
service ssh restart
|
service ssh restart
|
||||||
|
|
||||||
dockerd --max-concurrent-downloads 1 --insecure-registry registry:4443 &
|
dockerd --max-concurrent-downloads 1 &
|
||||||
|
|
||||||
exec sleep infinity
|
exec sleep infinity
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class MainTest < IntegrationTest
|
|||||||
assert_match /Traefik Host: vm2/, details
|
assert_match /Traefik Host: vm2/, details
|
||||||
assert_match /App Host: vm1/, details
|
assert_match /App Host: vm1/, details
|
||||||
assert_match /App Host: vm2/, details
|
assert_match /App Host: vm2/, details
|
||||||
assert_match /traefik:v2.11/, details
|
assert_match /traefik:v2.10/, details
|
||||||
assert_match /registry:4443\/app:#{first_version}/, details
|
assert_match /registry:4443\/app:#{first_version}/, details
|
||||||
|
|
||||||
audit = kamal :audit, capture: true
|
audit = kamal :audit, capture: true
|
||||||
@@ -97,7 +97,7 @@ class MainTest < IntegrationTest
|
|||||||
|
|
||||||
private
|
private
|
||||||
def assert_local_env_file(contents)
|
def assert_local_env_file(contents)
|
||||||
assert_equal contents, deployer_exec("cat .env", capture: true)
|
assert_equal contents, deployer_exec("cat .kamal/env", capture: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def assert_envs(version:)
|
def assert_envs(version:)
|
||||||
@@ -127,7 +127,7 @@ class MainTest < IntegrationTest
|
|||||||
end
|
end
|
||||||
|
|
||||||
def remove_local_env_file
|
def remove_local_env_file
|
||||||
deployer_exec("rm .env")
|
deployer_exec("rm .kamal/env")
|
||||||
end
|
end
|
||||||
|
|
||||||
def assert_remote_env_file(contents, vm:)
|
def assert_remote_env_file(contents, vm:)
|
||||||
|
|||||||
@@ -52,11 +52,11 @@ class TraefikTest < IntegrationTest
|
|||||||
|
|
||||||
private
|
private
|
||||||
def assert_traefik_running
|
def assert_traefik_running
|
||||||
assert_match /traefik:v2.11 "\/entrypoint.sh/, traefik_details
|
assert_match /traefik:v2.10 "\/entrypoint.sh/, traefik_details
|
||||||
end
|
end
|
||||||
|
|
||||||
def assert_traefik_not_running
|
def assert_traefik_not_running
|
||||||
assert_no_match /traefik:v2.11 "\/entrypoint.sh/, traefik_details
|
assert_no_match /traefik:v2.10 "\/entrypoint.sh/, traefik_details
|
||||||
end
|
end
|
||||||
|
|
||||||
def traefik_details
|
def traefik_details
|
||||||
|
|||||||
Reference in New Issue
Block a user