Merge branch 'main' into global-logging-config
This commit is contained in:
16
README.md
16
README.md
@@ -8,7 +8,19 @@ Join us on Discord: https://discord.gg/YgHVT7GCXS
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Install MRSK globally with `gem install mrsk`. Then, inside your app directory, run `mrsk init` (or `mrsk init --bundle` within Rails apps where you want a bin/mrsk binstub). Now edit the new file `config/deploy.yml`. It could look as simple as this:
|
If you have a Ruby environment available, you can install MRSK globally with:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
gem install mrsk
|
||||||
|
```
|
||||||
|
|
||||||
|
...otherwise, you can run a dockerized version via an alias (add this to your ${SHELL}rc to simplify re-use):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
alias mrsk='docker run --rm -it -v $HOME/.ssh:/root/.ssh -v /var/run/docker.sock:/var/run/docker.sock -v ${PWD}/:/workdir ghcr.io/mrsked/mrsk'
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, inside your app directory, run `mrsk init` (or `mrsk init --bundle` within Rails apps where you want a bin/mrsk binstub). Now edit the new file `config/deploy.yml`. It could look as simple as this:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
service: hey
|
service: hey
|
||||||
@@ -36,7 +48,7 @@ mrsk deploy
|
|||||||
This will:
|
This will:
|
||||||
|
|
||||||
1. Connect to the servers over SSH (using root by default, authenticated by your ssh key)
|
1. Connect to the servers over SSH (using root by default, authenticated by your ssh key)
|
||||||
2. Install Docker on any server that might be missing it (using apt-get)
|
2. Install Docker on any server that might be missing it (using apt-get): root access is needed via ssh for this.
|
||||||
3. Log into the registry both locally and remotely
|
3. Log into the registry both locally and remotely
|
||||||
4. Build the image using the standard Dockerfile in the root of the application.
|
4. Build the image using the standard Dockerfile in the root of the application.
|
||||||
5. Push the image to the registry.
|
5. Push the image to the registry.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
|
|||||||
desc "boot", "Boot app on servers (or reboot app if already running)"
|
desc "boot", "Boot app on servers (or reboot app if already running)"
|
||||||
def boot
|
def boot
|
||||||
say "Get most recent version available as an image...", :magenta unless options[:version]
|
say "Get most recent version available as an image...", :magenta unless options[:version]
|
||||||
using_version(options[:version] || most_recent_version_available) do |version|
|
using_version(version_or_latest) do |version|
|
||||||
say "Start container with version #{version} using a #{MRSK.config.readiness_delay}s readiness delay (or reboot if already running)...", :magenta
|
say "Start container with version #{version} using a #{MRSK.config.readiness_delay}s readiness delay (or reboot if already running)...", :magenta
|
||||||
|
|
||||||
cli = self
|
cli = self
|
||||||
@@ -70,7 +70,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
|
|||||||
|
|
||||||
when options[:interactive]
|
when options[:interactive]
|
||||||
say "Get most recent version available as an image...", :magenta unless options[:version]
|
say "Get most recent version available as an image...", :magenta unless options[:version]
|
||||||
using_version(options[:version] || most_recent_version_available) do |version|
|
using_version(version_or_latest) do |version|
|
||||||
say "Launching interactive command with version #{version} via SSH from new container on #{MRSK.primary_host}...", :magenta
|
say "Launching interactive command with version #{version} via SSH from new container on #{MRSK.primary_host}...", :magenta
|
||||||
run_locally { exec MRSK.app.execute_in_new_container_over_ssh(cmd, host: MRSK.primary_host) }
|
run_locally { exec MRSK.app.execute_in_new_container_over_ssh(cmd, host: MRSK.primary_host) }
|
||||||
end
|
end
|
||||||
@@ -88,7 +88,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
|
|||||||
|
|
||||||
else
|
else
|
||||||
say "Get most recent version available as an image...", :magenta unless options[:version]
|
say "Get most recent version available as an image...", :magenta unless options[:version]
|
||||||
using_version(options[:version] || most_recent_version_available) do |version|
|
using_version(version_or_latest) do |version|
|
||||||
say "Launching command with version #{version} from new container...", :magenta
|
say "Launching command with version #{version} from new container...", :magenta
|
||||||
on(MRSK.hosts) do |host|
|
on(MRSK.hosts) do |host|
|
||||||
execute *MRSK.auditor.record("Executed cmd '#{cmd}' on app version #{version}"), verbosity: :debug
|
execute *MRSK.auditor.record("Executed cmd '#{cmd}' on app version #{version}"), verbosity: :debug
|
||||||
@@ -189,20 +189,13 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def most_recent_version_available(host: MRSK.primary_host)
|
|
||||||
version = nil
|
|
||||||
on(host) { version = capture_with_info(*MRSK.app.most_recent_version_from_available_images).strip }
|
|
||||||
|
|
||||||
if version == "<none>"
|
|
||||||
raise "Most recent image available was not tagged with a version (returned <none>)"
|
|
||||||
else
|
|
||||||
version.presence
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def current_running_version(host: MRSK.primary_host)
|
def current_running_version(host: MRSK.primary_host)
|
||||||
version = nil
|
version = nil
|
||||||
on(host) { version = capture_with_info(*MRSK.app.current_running_version).strip }
|
on(host) { version = capture_with_info(*MRSK.app.current_running_version).strip }
|
||||||
version.presence
|
version.presence
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def version_or_latest
|
||||||
|
options[:version] || "latest"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base
|
|||||||
desc "deploy", "Deploy app to servers"
|
desc "deploy", "Deploy app to servers"
|
||||||
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
||||||
def deploy
|
def deploy
|
||||||
invoke_options = options.without(:skip_push)
|
invoke_options = deploy_options
|
||||||
|
|
||||||
runtime = print_runtime do
|
runtime = print_runtime do
|
||||||
say "Ensure curl and Docker are installed...", :magenta
|
say "Ensure curl and Docker are installed...", :magenta
|
||||||
@@ -46,7 +46,7 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base
|
|||||||
desc "redeploy", "Deploy app to servers without bootstrapping servers, starting Traefik, pruning, and registry login"
|
desc "redeploy", "Deploy app to servers without bootstrapping servers, starting Traefik, pruning, and registry login"
|
||||||
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
||||||
def redeploy
|
def redeploy
|
||||||
invoke_options = options.without(:skip_push)
|
invoke_options = deploy_options
|
||||||
|
|
||||||
runtime = print_runtime do
|
runtime = print_runtime do
|
||||||
if options[:skip_push]
|
if options[:skip_push]
|
||||||
@@ -207,6 +207,10 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base
|
|||||||
Array(container_names).include?(container_name)
|
Array(container_names).include?(container_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def deploy_options
|
||||||
|
{ "version" => MRSK.config.version }.merge(options.without("skip_push"))
|
||||||
|
end
|
||||||
|
|
||||||
def service_version(version = MRSK.config.abbreviated_version)
|
def service_version(version = MRSK.config.abbreviated_version)
|
||||||
[ MRSK.config.service, version ].compact.join("@")
|
[ MRSK.config.service, version ].compact.join("@")
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ class Mrsk::Commands::Accessory < Mrsk::Commands::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def remove_image
|
def remove_image
|
||||||
docker :image, :prune, "--all", "--force", *service_filter
|
docker :image, :rm, "--force", image
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -87,19 +87,6 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
|||||||
"tail -n 1"
|
"tail -n 1"
|
||||||
end
|
end
|
||||||
|
|
||||||
def most_recent_version_from_available_images
|
|
||||||
pipe \
|
|
||||||
docker(:image, :ls, "--format", '"{{.Tag}}"', config.repository),
|
|
||||||
"head -n 1"
|
|
||||||
end
|
|
||||||
|
|
||||||
def all_versions_from_available_containers
|
|
||||||
pipe \
|
|
||||||
docker(:image, :ls, "--format", '"{{.Tag}}"', config.repository),
|
|
||||||
"head -n 1"
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
def list_containers
|
def list_containers
|
||||||
docker :container, :ls, "--all", *filter_args
|
docker :container, :ls, "--all", *filter_args
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ class Mrsk::Commands::Builder::Base < Mrsk::Commands::Base
|
|||||||
|
|
||||||
def pull
|
def pull
|
||||||
docker :pull, config.absolute_image
|
docker :pull, config.absolute_image
|
||||||
|
docker :pull, config.latest_image
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_options
|
def build_options
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ class CliAccessoryTest < CliTestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "remove_image" do
|
test "remove_image" do
|
||||||
assert_match "docker image prune --all --force --filter label=service=app-mysql", run_command("remove_image", "mysql")
|
assert_match "docker image rm --force mysql", run_command("remove_image", "mysql")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "remove_service_directory" do
|
test "remove_service_directory" do
|
||||||
|
|||||||
@@ -28,9 +28,8 @@ class CliAppTest < CliTestCase
|
|||||||
.returns([ :docker, :run ])
|
.returns([ :docker, :run ])
|
||||||
|
|
||||||
run_command("boot").tap do |output|
|
run_command("boot").tap do |output|
|
||||||
assert_match "Rebooting container with same version 999 already deployed", output # Can't start what's already running
|
assert_match "Rebooting container with same version latest already deployed", output # Can't start what's already 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-latest --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
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class CliBuildTest < CliTestCase
|
|||||||
test "pull" do
|
test "pull" do
|
||||||
run_command("pull").tap do |output|
|
run_command("pull").tap do |output|
|
||||||
assert_match /docker image rm --force dhh\/app:999/, output
|
assert_match /docker image rm --force dhh\/app:999/, output
|
||||||
assert_match /docker pull dhh\/app:999/, output
|
assert_match /docker pull dhh\/app:latest/, output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class CliMainTest < CliTestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "deploy" do
|
test "deploy" do
|
||||||
invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_broadcast" => false, "skip_push" => false }
|
invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_broadcast" => false, "version" => "999" }
|
||||||
|
|
||||||
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:server:bootstrap", [], invoke_options)
|
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:server:bootstrap", [], invoke_options)
|
||||||
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:registry:login", [], invoke_options)
|
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:registry:login", [], invoke_options)
|
||||||
@@ -31,7 +31,7 @@ class CliMainTest < CliTestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "deploy with skip_push" do
|
test "deploy with skip_push" do
|
||||||
invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_broadcast" => false, "skip_push" => true }
|
invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_broadcast" => false, "version" => "999" }
|
||||||
|
|
||||||
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:server:bootstrap", [], invoke_options)
|
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:server:bootstrap", [], invoke_options)
|
||||||
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:registry:login", [], invoke_options)
|
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:registry:login", [], invoke_options)
|
||||||
@@ -52,7 +52,7 @@ class CliMainTest < CliTestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "redeploy" do
|
test "redeploy" do
|
||||||
invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_broadcast" => false, "skip_push" => false}
|
invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_broadcast" => false, "version" => "999" }
|
||||||
|
|
||||||
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:build:deliver", [], invoke_options)
|
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:build:deliver", [], invoke_options)
|
||||||
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:healthcheck:perform", [], invoke_options)
|
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:healthcheck:perform", [], invoke_options)
|
||||||
@@ -65,7 +65,7 @@ class CliMainTest < CliTestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "redeploy with skip_push" do
|
test "redeploy with skip_push" do
|
||||||
invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_broadcast" => false, "skip_push" => true }
|
invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_broadcast" => false, "version" => "999" }
|
||||||
|
|
||||||
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:build:pull", [], invoke_options)
|
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:build:pull", [], invoke_options)
|
||||||
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:healthcheck:perform", [], invoke_options)
|
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:healthcheck:perform", [], invoke_options)
|
||||||
@@ -235,12 +235,12 @@ class CliMainTest < CliTestCase
|
|||||||
|
|
||||||
assert_match /docker container stop app-mysql/, output
|
assert_match /docker container stop app-mysql/, output
|
||||||
assert_match /docker container prune --force --filter label=service=app-mysql/, output
|
assert_match /docker container prune --force --filter label=service=app-mysql/, output
|
||||||
assert_match /docker image prune --all --force --filter label=service=app-mysql/, output
|
assert_match /docker image rm --force mysql/, output
|
||||||
assert_match /rm -rf app-mysql/, output
|
assert_match /rm -rf app-mysql/, output
|
||||||
|
|
||||||
assert_match /docker container stop app-redis/, output
|
assert_match /docker container stop app-redis/, output
|
||||||
assert_match /docker container prune --force --filter label=service=app-redis/, output
|
assert_match /docker container prune --force --filter label=service=app-redis/, output
|
||||||
assert_match /docker image prune --all --force --filter label=service=app-redis/, output
|
assert_match /docker image rm --force redis/, output
|
||||||
assert_match /rm -rf app-redis/, output
|
assert_match /rm -rf app-redis/, output
|
||||||
|
|
||||||
assert_match /docker logout/, output
|
assert_match /docker logout/, output
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ class CommandsAccessoryTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
test "remove image" do
|
test "remove image" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker image prune --all --force --filter label=service=app-mysql",
|
"docker image rm --force private.registry/mysql:8.0",
|
||||||
new_command(:mysql).remove_image.join(" ")
|
new_command(:mysql).remove_image.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -197,12 +197,6 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
new_command.current_running_version.join(" ")
|
new_command.current_running_version.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "most_recent_version_from_available_images" do
|
|
||||||
assert_equal \
|
|
||||||
"docker image ls --format \"{{.Tag}}\" dhh/app | head -n 1",
|
|
||||||
new_command.most_recent_version_from_available_images.join(" ")
|
|
||||||
end
|
|
||||||
|
|
||||||
test "list_containers" do
|
test "list_containers" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker container ls --all --filter label=service=app",
|
"docker container ls --all --filter label=service=app",
|
||||||
|
|||||||
Reference in New Issue
Block a user