Start before stopping and longer timeouts
This commit is contained in:
@@ -10,13 +10,17 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
|
|||||||
execute *MRSK.auditor.record("Booted app version #{version}"), verbosity: :debug
|
execute *MRSK.auditor.record("Booted app version #{version}"), verbosity: :debug
|
||||||
|
|
||||||
begin
|
begin
|
||||||
execute *MRSK.app.stop, raise_on_non_zero_exit: false
|
old_version = capture_with_info(*MRSK.app.current_running_version).strip
|
||||||
execute *MRSK.app.run(role: role.name)
|
execute *MRSK.app.run(role: role.name)
|
||||||
|
sleep 10
|
||||||
|
execute *MRSK.app.stop(version: old_version), raise_on_non_zero_exit: false if old_version.present?
|
||||||
|
|
||||||
rescue SSHKit::Command::Failed => e
|
rescue SSHKit::Command::Failed => e
|
||||||
if e.message =~ /already in use/
|
if e.message =~ /already in use/
|
||||||
error "Rebooting container with same version already deployed on #{host}"
|
error "Rebooting container with same version #{version} already deployed on #{host}"
|
||||||
execute *MRSK.auditor.record("Rebooted app version #{version}"), verbosity: :debug
|
execute *MRSK.auditor.record("Rebooted app version #{version}"), verbosity: :debug
|
||||||
|
|
||||||
|
execute *MRSK.app.stop(version: version)
|
||||||
execute *MRSK.app.remove_container(version: version)
|
execute *MRSK.app.remove_container(version: version)
|
||||||
execute *MRSK.app.run(role: role.name)
|
execute *MRSK.app.run(role: role.name)
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
class Mrsk::Cli::Healthcheck < Mrsk::Cli::Base
|
class Mrsk::Cli::Healthcheck < Mrsk::Cli::Base
|
||||||
MAX_ATTEMPTS = 5
|
MAX_ATTEMPTS = 7
|
||||||
|
|
||||||
class HealthcheckError < StandardError; end
|
class HealthcheckError < StandardError; end
|
||||||
|
|
||||||
|
|||||||
@@ -55,11 +55,14 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base
|
|||||||
MRSK.version = version
|
MRSK.version = version
|
||||||
|
|
||||||
if container_name_available?(MRSK.config.service_with_version)
|
if container_name_available?(MRSK.config.service_with_version)
|
||||||
say "Stop current version, then start version #{version}...", :magenta
|
say "Start version #{version}, then stop the old version...", :magenta
|
||||||
|
|
||||||
on(MRSK.hosts) do |host|
|
on(MRSK.hosts) do |host|
|
||||||
execute *MRSK.app.stop, raise_on_non_zero_exit: false
|
old_version = capture_with_info(*MRSK.app.current_running_version).strip.presence
|
||||||
|
|
||||||
execute *MRSK.app.start
|
execute *MRSK.app.start
|
||||||
|
sleep 10
|
||||||
|
execute *MRSK.app.stop(version: old_version), raise_on_non_zero_exit: false
|
||||||
end
|
end
|
||||||
|
|
||||||
audit_broadcast "Rolled back app to version #{version}"
|
audit_broadcast "Rolled back app to version #{version}"
|
||||||
|
|||||||
@@ -18,8 +18,10 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
|||||||
docker :start, service_with_version
|
docker :start, service_with_version
|
||||||
end
|
end
|
||||||
|
|
||||||
def stop
|
def stop(version: nil)
|
||||||
pipe current_container_id, xargs(docker(:stop))
|
pipe \
|
||||||
|
version ? container_id_for_version(version) : current_container_id,
|
||||||
|
xargs(docker(:stop))
|
||||||
end
|
end
|
||||||
|
|
||||||
def info
|
def info
|
||||||
@@ -132,6 +134,10 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def container_id_for_version(version)
|
||||||
|
container_id_for(container_name: service_with_version(version))
|
||||||
|
end
|
||||||
|
|
||||||
def service_filter
|
def service_filter
|
||||||
[ "--filter", "label=service=#{config.service}" ]
|
[ "--filter", "label=service=#{config.service}" ]
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class Mrsk::Configuration::Role
|
|||||||
"traefik.http.routers.#{config.service}.rule" => "PathPrefix(`/`)",
|
"traefik.http.routers.#{config.service}.rule" => "PathPrefix(`/`)",
|
||||||
"traefik.http.services.#{config.service}.loadbalancer.healthcheck.path" => config.healthcheck["path"],
|
"traefik.http.services.#{config.service}.loadbalancer.healthcheck.path" => config.healthcheck["path"],
|
||||||
"traefik.http.services.#{config.service}.loadbalancer.healthcheck.interval" => "1s",
|
"traefik.http.services.#{config.service}.loadbalancer.healthcheck.interval" => "1s",
|
||||||
"traefik.http.middlewares.#{config.service}.retry.attempts" => "3",
|
"traefik.http.middlewares.#{config.service}.retry.attempts" => "5",
|
||||||
"traefik.http.middlewares.#{config.service}.retry.initialinterval" => "500ms"
|
"traefik.http.middlewares.#{config.service}.retry.initialinterval" => "500ms"
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -2,7 +2,16 @@ require_relative "cli_test_case"
|
|||||||
|
|
||||||
class CliAppTest < CliTestCase
|
class CliAppTest < CliTestCase
|
||||||
test "boot" do
|
test "boot" do
|
||||||
assert_match /Running docker run --detach --restart unless-stopped/, run_command("boot")
|
# Stub current version fetch
|
||||||
|
SSHKit::Backend::Abstract.any_instance.stubs(:capture)
|
||||||
|
.returns("999") # new version
|
||||||
|
.then
|
||||||
|
.returns("123") # old version
|
||||||
|
|
||||||
|
run_command("boot").tap do |output|
|
||||||
|
assert_match /docker run --detach --restart unless-stopped/, output
|
||||||
|
assert_match /docker container ls --all --filter name=app-123 --quiet | xargs docker stop/, output
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "boot will reboot if same version is already running" do
|
test "boot will reboot if same version is already running" do
|
||||||
@@ -11,12 +20,17 @@ class CliAppTest < CliTestCase
|
|||||||
# Prevent expected failures from outputting to terminal
|
# Prevent expected failures from outputting to terminal
|
||||||
Thread.report_on_exception = false
|
Thread.report_on_exception = false
|
||||||
|
|
||||||
MRSK.app.stubs(:run).raises(SSHKit::Command::Failed.new("already in use")).then.returns([ :docker, :run ])
|
MRSK.app.stubs(:run)
|
||||||
|
.raises(SSHKit::Command::Failed.new("already in use"))
|
||||||
|
.then
|
||||||
|
.raises(SSHKit::Command::Failed.new("already in use"))
|
||||||
|
.then
|
||||||
|
.returns([ :docker, :run ])
|
||||||
|
|
||||||
run_command("boot").tap do |output|
|
run_command("boot").tap do |output|
|
||||||
assert_match /Rebooting container with same version already deployed/, output # Can't start what's already running
|
assert_match /Rebooting container with same version 999 already deployed/, output # Can't start what's already running
|
||||||
assert_match /docker ps --quiet --filter label=service=app \| xargs docker stop/, output # Stop what's running
|
assert_match /docker container ls --all --filter name=app-999 --quiet | xargs docker container rm/, output # Stop old running
|
||||||
assert_match /docker container ls --all --filter name=app-999 --quiet \| xargs docker container rm/, output # Remove old container
|
assert_match /docker container ls --all --filter name=app-999 --quiet | xargs docker container rm/, output # Remove old container
|
||||||
assert_match /docker run/, output # Start new container
|
assert_match /docker run/, output # Start new container
|
||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
test "run" do
|
test "run" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --detach --restart unless-stopped --log-opt max-size=10m --name app-999 -e RAILS_MASTER_KEY=\"456\" --label service=\"app\" --label role=\"web\" --label traefik.http.routers.app.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.services.app.loadbalancer.healthcheck.path=\"/up\" --label traefik.http.services.app.loadbalancer.healthcheck.interval=\"1s\" --label traefik.http.middlewares.app.retry.attempts=\"3\" --label traefik.http.middlewares.app.retry.initialinterval=\"500ms\" dhh/app:999",
|
"docker run --detach --restart unless-stopped --log-opt max-size=10m --name app-999 -e RAILS_MASTER_KEY=\"456\" --label service=\"app\" --label role=\"web\" --label traefik.http.routers.app.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.services.app.loadbalancer.healthcheck.path=\"/up\" --label traefik.http.services.app.loadbalancer.healthcheck.interval=\"1s\" --label traefik.http.middlewares.app.retry.attempts=\"5\" --label traefik.http.middlewares.app.retry.initialinterval=\"500ms\" dhh/app:999",
|
||||||
@app.run.join(" ")
|
@app.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
@config[:volumes] = ["/local/path:/container/path" ]
|
@config[:volumes] = ["/local/path:/container/path" ]
|
||||||
|
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --detach --restart unless-stopped --log-opt max-size=10m --name app-999 -e RAILS_MASTER_KEY=\"456\" --volume /local/path:/container/path --label service=\"app\" --label role=\"web\" --label traefik.http.routers.app.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.services.app.loadbalancer.healthcheck.path=\"/up\" --label traefik.http.services.app.loadbalancer.healthcheck.interval=\"1s\" --label traefik.http.middlewares.app.retry.attempts=\"3\" --label traefik.http.middlewares.app.retry.initialinterval=\"500ms\" dhh/app:999",
|
"docker run --detach --restart unless-stopped --log-opt max-size=10m --name app-999 -e RAILS_MASTER_KEY=\"456\" --volume /local/path:/container/path --label service=\"app\" --label role=\"web\" --label traefik.http.routers.app.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.services.app.loadbalancer.healthcheck.path=\"/up\" --label traefik.http.services.app.loadbalancer.healthcheck.interval=\"1s\" --label traefik.http.middlewares.app.retry.attempts=\"5\" --label traefik.http.middlewares.app.retry.initialinterval=\"500ms\" dhh/app:999",
|
||||||
@app.run.join(" ")
|
@app.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
@config[:healthcheck] = { "path" => "/healthz" }
|
@config[:healthcheck] = { "path" => "/healthz" }
|
||||||
|
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --detach --restart unless-stopped --log-opt max-size=10m --name app-999 -e RAILS_MASTER_KEY=\"456\" --label service=\"app\" --label role=\"web\" --label traefik.http.routers.app.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.services.app.loadbalancer.healthcheck.path=\"/healthz\" --label traefik.http.services.app.loadbalancer.healthcheck.interval=\"1s\" --label traefik.http.middlewares.app.retry.attempts=\"3\" --label traefik.http.middlewares.app.retry.initialinterval=\"500ms\" dhh/app:999",
|
"docker run --detach --restart unless-stopped --log-opt max-size=10m --name app-999 -e RAILS_MASTER_KEY=\"456\" --label service=\"app\" --label role=\"web\" --label traefik.http.routers.app.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.services.app.loadbalancer.healthcheck.path=\"/healthz\" --label traefik.http.services.app.loadbalancer.healthcheck.interval=\"1s\" --label traefik.http.middlewares.app.retry.attempts=\"5\" --label traefik.http.middlewares.app.retry.initialinterval=\"500ms\" dhh/app:999",
|
||||||
@app.run.join(" ")
|
@app.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class ConfigurationRoleTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "special label args for web" do
|
test "special label args for web" do
|
||||||
assert_equal [ "--label", "service=\"app\"", "--label", "role=\"web\"", "--label", "traefik.http.routers.app.rule=\"PathPrefix(\\`/\\`)\"", "--label", "traefik.http.services.app.loadbalancer.healthcheck.path=\"/up\"", "--label", "traefik.http.services.app.loadbalancer.healthcheck.interval=\"1s\"", "--label", "traefik.http.middlewares.app.retry.attempts=\"3\"", "--label", "traefik.http.middlewares.app.retry.initialinterval=\"500ms\""], @config.role(:web).label_args
|
assert_equal [ "--label", "service=\"app\"", "--label", "role=\"web\"", "--label", "traefik.http.routers.app.rule=\"PathPrefix(\\`/\\`)\"", "--label", "traefik.http.services.app.loadbalancer.healthcheck.path=\"/up\"", "--label", "traefik.http.services.app.loadbalancer.healthcheck.interval=\"1s\"", "--label", "traefik.http.middlewares.app.retry.attempts=\"5\"", "--label", "traefik.http.middlewares.app.retry.initialinterval=\"500ms\""], @config.role(:web).label_args
|
||||||
end
|
end
|
||||||
|
|
||||||
test "custom labels" do
|
test "custom labels" do
|
||||||
@@ -66,7 +66,7 @@ class ConfigurationRoleTest < ActiveSupport::TestCase
|
|||||||
c[:servers]["beta"] = { "traefik" => "true", "hosts" => [ "1.1.1.5" ] }
|
c[:servers]["beta"] = { "traefik" => "true", "hosts" => [ "1.1.1.5" ] }
|
||||||
})
|
})
|
||||||
|
|
||||||
assert_equal [ "--label", "service=\"app\"", "--label", "role=\"beta\"", "--label", "traefik.http.routers.app.rule=\"PathPrefix(\\`/\\`)\"", "--label", "traefik.http.services.app.loadbalancer.healthcheck.path=\"/up\"", "--label", "traefik.http.services.app.loadbalancer.healthcheck.interval=\"1s\"", "--label", "traefik.http.middlewares.app.retry.attempts=\"3\"", "--label", "traefik.http.middlewares.app.retry.initialinterval=\"500ms\"" ], config.role(:beta).label_args
|
assert_equal [ "--label", "service=\"app\"", "--label", "role=\"beta\"", "--label", "traefik.http.routers.app.rule=\"PathPrefix(\\`/\\`)\"", "--label", "traefik.http.services.app.loadbalancer.healthcheck.path=\"/up\"", "--label", "traefik.http.services.app.loadbalancer.healthcheck.interval=\"1s\"", "--label", "traefik.http.middlewares.app.retry.attempts=\"5\"", "--label", "traefik.http.middlewares.app.retry.initialinterval=\"500ms\"" ], config.role(:beta).label_args
|
||||||
end
|
end
|
||||||
|
|
||||||
test "env overwritten by role" do
|
test "env overwritten by role" do
|
||||||
|
|||||||
Reference in New Issue
Block a user