mrsk 0.0.3 → 0.2.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.
- checksums.yaml +4 -4
- data/README.md +193 -77
- data/bin/mrsk +5 -0
- data/lib/mrsk/cli/accessory.rb +85 -0
- data/lib/mrsk/cli/app.rb +123 -0
- data/lib/mrsk/cli/base.rb +48 -0
- data/lib/mrsk/cli/build.rb +53 -0
- data/lib/mrsk/cli/main.rb +110 -0
- data/lib/mrsk/cli/prune.rb +19 -0
- data/lib/mrsk/cli/registry.rb +18 -0
- data/lib/mrsk/cli/server.rb +8 -0
- data/lib/mrsk/cli/templates/deploy.yml +17 -0
- data/lib/mrsk/cli/traefik.rb +77 -0
- data/lib/mrsk/cli.rb +9 -0
- data/lib/mrsk/commander.rb +45 -5
- data/lib/mrsk/commands/accessory.rb +61 -0
- data/lib/mrsk/commands/app.rb +50 -10
- data/lib/mrsk/commands/base.rb +13 -9
- data/lib/mrsk/commands/builder/base.rb +26 -0
- data/lib/mrsk/commands/builder/multiarch/remote.rb +12 -4
- data/lib/mrsk/commands/builder/multiarch.rb +17 -9
- data/lib/mrsk/commands/builder/native/remote.rb +71 -0
- data/lib/mrsk/commands/builder/native.rb +3 -7
- data/lib/mrsk/commands/builder.rb +11 -7
- data/lib/mrsk/commands/traefik.rb +13 -3
- data/lib/mrsk/configuration/accessory.rb +60 -0
- data/lib/mrsk/configuration/role.rb +46 -14
- data/lib/mrsk/configuration.rb +86 -43
- data/lib/mrsk/sshkit_with_ext.rb +12 -0
- data/lib/mrsk/utils.rb +29 -0
- data/lib/mrsk/version.rb +1 -1
- data/lib/mrsk.rb +0 -1
- metadata +40 -18
- data/lib/mrsk/engine.rb +0 -4
- data/lib/tasks/mrsk/app.rake +0 -97
- data/lib/tasks/mrsk/build.rake +0 -52
- data/lib/tasks/mrsk/mrsk.rake +0 -37
- data/lib/tasks/mrsk/prune.rake +0 -18
- data/lib/tasks/mrsk/registry.rake +0 -16
- data/lib/tasks/mrsk/server.rake +0 -11
- data/lib/tasks/mrsk/setup.rb +0 -6
- data/lib/tasks/mrsk/templates/deploy.yml +0 -24
- data/lib/tasks/mrsk/templates/mrsk +0 -8
- data/lib/tasks/mrsk/traefik.rake +0 -41
@@ -0,0 +1,48 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "mrsk/sshkit_with_ext"
|
3
|
+
|
4
|
+
module Mrsk::Cli
|
5
|
+
class Base < Thor
|
6
|
+
include SSHKit::DSL
|
7
|
+
|
8
|
+
def self.exit_on_failure?() true end
|
9
|
+
|
10
|
+
class_option :verbose, type: :boolean, aliases: "-v", desc: "Detailed logging"
|
11
|
+
|
12
|
+
class_option :version, desc: "Run commands against a specific app version"
|
13
|
+
|
14
|
+
class_option :primary, type: :boolean, aliases: "-p", desc: "Run commands only on primary host instead of all"
|
15
|
+
class_option :hosts, aliases: "-h", desc: "Run commands on these hosts instead of all (separate by comma)"
|
16
|
+
class_option :roles, aliases: "-r", desc: "Run commands on these roles instead of all (separate by comma)"
|
17
|
+
|
18
|
+
class_option :config_file, aliases: "-c", default: "config/deploy.yml", desc: "Path to config file (default: config/deploy.yml)"
|
19
|
+
class_option :destination, aliases: "-d", desc: "Specify destination to be used for config file (west -> deploy.west.yml)"
|
20
|
+
|
21
|
+
def initialize(*)
|
22
|
+
super
|
23
|
+
initialize_commander(options)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def initialize_commander(options)
|
28
|
+
MRSK.tap do |commander|
|
29
|
+
commander.config_file = Pathname.new(File.expand_path(options[:config_file]))
|
30
|
+
commander.destination = options[:destination]
|
31
|
+
commander.verbose = options[:verbose]
|
32
|
+
commander.version = options[:version]
|
33
|
+
|
34
|
+
commander.specific_hosts = options[:hosts]&.split(",")
|
35
|
+
commander.specific_roles = options[:roles]&.split(",")
|
36
|
+
commander.specific_primary! if options[:primary]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def print_runtime
|
41
|
+
started_at = Time.now
|
42
|
+
yield
|
43
|
+
ensure
|
44
|
+
runtime = Time.now - started_at
|
45
|
+
puts " Finished all in #{sprintf("%.1f seconds", runtime)}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "mrsk/cli/base"
|
2
|
+
|
3
|
+
class Mrsk::Cli::Build < Mrsk::Cli::Base
|
4
|
+
desc "deliver", "Deliver a newly built app image to servers"
|
5
|
+
def deliver
|
6
|
+
invoke :push
|
7
|
+
invoke :pull
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "push", "Build locally and push app image to registry"
|
11
|
+
def push
|
12
|
+
verbose = options[:verbose]
|
13
|
+
|
14
|
+
run_locally do
|
15
|
+
begin
|
16
|
+
MRSK.verbosity(:debug) { execute *MRSK.builder.push }
|
17
|
+
rescue SSHKit::Command::Failed => e
|
18
|
+
error "Missing compatible builder, so creating a new one first"
|
19
|
+
execute *MRSK.builder.create
|
20
|
+
MRSK.verbosity(:debug) { execute *MRSK.builder.push }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "pull", "Pull app image from the registry onto servers"
|
26
|
+
def pull
|
27
|
+
on(MRSK.hosts) { execute *MRSK.builder.pull }
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "create", "Create a local build setup"
|
31
|
+
def create
|
32
|
+
run_locally do
|
33
|
+
debug "Using builder: #{MRSK.builder.name}"
|
34
|
+
execute *MRSK.builder.create
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "remove", "Remove local build setup"
|
39
|
+
def remove
|
40
|
+
run_locally do
|
41
|
+
debug "Using builder: #{MRSK.builder.name}"
|
42
|
+
execute *MRSK.builder.remove
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "details", "Show the name of the configured builder"
|
47
|
+
def details
|
48
|
+
run_locally do
|
49
|
+
puts "Builder: #{MRSK.builder.name}"
|
50
|
+
puts capture(*MRSK.builder.info)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require "mrsk/cli/base"
|
2
|
+
|
3
|
+
require "mrsk/cli/accessory"
|
4
|
+
require "mrsk/cli/app"
|
5
|
+
require "mrsk/cli/build"
|
6
|
+
require "mrsk/cli/prune"
|
7
|
+
require "mrsk/cli/registry"
|
8
|
+
require "mrsk/cli/server"
|
9
|
+
require "mrsk/cli/traefik"
|
10
|
+
|
11
|
+
class Mrsk::Cli::Main < Mrsk::Cli::Base
|
12
|
+
desc "deploy", "Deploy the app to servers"
|
13
|
+
def deploy
|
14
|
+
print_runtime do
|
15
|
+
invoke "mrsk:cli:server:bootstrap"
|
16
|
+
invoke "mrsk:cli:registry:login"
|
17
|
+
invoke "mrsk:cli:build:deliver"
|
18
|
+
invoke "mrsk:cli:traefik:boot"
|
19
|
+
invoke "mrsk:cli:app:stop"
|
20
|
+
invoke "mrsk:cli:app:boot"
|
21
|
+
invoke "mrsk:cli:prune:all"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "redeploy", "Deploy new version of the app to servers (without bootstrapping servers, starting Traefik, pruning, and registry login)"
|
26
|
+
def redeploy
|
27
|
+
print_runtime do
|
28
|
+
invoke "mrsk:cli:build:deliver"
|
29
|
+
invoke "mrsk:cli:app:stop"
|
30
|
+
invoke "mrsk:cli:app:boot"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "rollback [VERSION]", "Rollback the app to VERSION (that must already be on servers)"
|
35
|
+
def rollback(version)
|
36
|
+
on(MRSK.hosts) do
|
37
|
+
execute *MRSK.app.stop, raise_on_non_zero_exit: false
|
38
|
+
execute *MRSK.app.start(version: version)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "details", "Display details about Traefik and app containers"
|
43
|
+
def details
|
44
|
+
invoke "mrsk:cli:traefik:details"
|
45
|
+
invoke "mrsk:cli:app:details"
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "config", "Show combined config"
|
49
|
+
def config
|
50
|
+
run_locally do
|
51
|
+
pp MRSK.config.to_h
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
desc "install", "Create config stub in config/deploy.yml and binstub in bin/mrsk"
|
56
|
+
option :skip_binstub, type: :boolean, default: false, desc: "Skip adding MRSK to the Gemfile and creating bin/mrsk binstub"
|
57
|
+
def install
|
58
|
+
require "fileutils"
|
59
|
+
|
60
|
+
if (deploy_file = Pathname.new(File.expand_path("config/deploy.yml"))).exist?
|
61
|
+
puts "Config file already exists in config/deploy.yml (remove first to create a new one)"
|
62
|
+
else
|
63
|
+
FileUtils.cp_r Pathname.new(File.expand_path("templates/deploy.yml", __dir__)), deploy_file
|
64
|
+
puts "Created configuration file in config/deploy.yml"
|
65
|
+
end
|
66
|
+
|
67
|
+
unless options[:skip_binstub]
|
68
|
+
if (binstub = Pathname.new(File.expand_path("bin/mrsk"))).exist?
|
69
|
+
puts "Binstub already exists in bin/mrsk (remove first to create a new one)"
|
70
|
+
else
|
71
|
+
`bundle add mrsk`
|
72
|
+
`bundle binstubs mrsk`
|
73
|
+
puts "Created binstub file in bin/mrsk"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
desc "remove", "Remove Traefik, app, and registry session from servers"
|
79
|
+
def remove
|
80
|
+
invoke "mrsk:cli:traefik:remove"
|
81
|
+
invoke "mrsk:cli:app:remove"
|
82
|
+
invoke "mrsk:cli:registry:logout"
|
83
|
+
end
|
84
|
+
|
85
|
+
desc "version", "Display the MRSK version"
|
86
|
+
def version
|
87
|
+
puts Mrsk::VERSION
|
88
|
+
end
|
89
|
+
|
90
|
+
desc "accessory", "Manage the accessories"
|
91
|
+
subcommand "accessory", Mrsk::Cli::Accessory
|
92
|
+
|
93
|
+
desc "app", "Manage the application"
|
94
|
+
subcommand "app", Mrsk::Cli::App
|
95
|
+
|
96
|
+
desc "build", "Build the application image"
|
97
|
+
subcommand "build", Mrsk::Cli::Build
|
98
|
+
|
99
|
+
desc "prune", "Prune old application images and containers"
|
100
|
+
subcommand "prune", Mrsk::Cli::Prune
|
101
|
+
|
102
|
+
desc "registry", "Login and out of the image registry"
|
103
|
+
subcommand "registry", Mrsk::Cli::Registry
|
104
|
+
|
105
|
+
desc "server", "Bootstrap servers with Docker"
|
106
|
+
subcommand "server", Mrsk::Cli::Server
|
107
|
+
|
108
|
+
desc "traefik", "Manage the Traefik load balancer"
|
109
|
+
subcommand "traefik", Mrsk::Cli::Traefik
|
110
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "mrsk/cli/base"
|
2
|
+
|
3
|
+
class Mrsk::Cli::Prune < Mrsk::Cli::Base
|
4
|
+
desc "all", "Prune unused images and stopped containers"
|
5
|
+
def all
|
6
|
+
invoke :containers
|
7
|
+
invoke :images
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "images", "Prune unused images older than 30 days"
|
11
|
+
def images
|
12
|
+
on(MRSK.hosts) { execute *MRSK.prune.images }
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "containers", "Prune stopped containers for the service older than 3 days"
|
16
|
+
def containers
|
17
|
+
on(MRSK.hosts) { execute *MRSK.prune.containers }
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "mrsk/cli/base"
|
2
|
+
|
3
|
+
class Mrsk::Cli::Registry < Mrsk::Cli::Base
|
4
|
+
desc "login", "Login to the registry locally and remotely"
|
5
|
+
def login
|
6
|
+
run_locally { execute *MRSK.registry.login }
|
7
|
+
on(MRSK.hosts) { execute *MRSK.registry.login }
|
8
|
+
rescue ArgumentError => e
|
9
|
+
puts e.message
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "logout", "Logout of the registry remotely"
|
13
|
+
def logout
|
14
|
+
on(MRSK.hosts) { execute *MRSK.registry.logout }
|
15
|
+
rescue ArgumentError => e
|
16
|
+
puts e.message
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Name of your application. Used to uniquely configuring Traefik and app containers.
|
2
|
+
# Your Dockerfile should set LABEL service=the-same-value to ensure image pruning works.
|
3
|
+
service: my-app
|
4
|
+
|
5
|
+
# Name of the container image.
|
6
|
+
image: user/my-app
|
7
|
+
|
8
|
+
# Deploy to these servers.
|
9
|
+
servers:
|
10
|
+
- 192.168.0.1
|
11
|
+
|
12
|
+
# Credentials for your image host.
|
13
|
+
registry:
|
14
|
+
# Specify the registry server, if you're not using Docker Hub
|
15
|
+
# server: registry.digitalocean.com / ghcr.io / ...
|
16
|
+
username: my-user
|
17
|
+
password: my-password-should-go-somewhere-safe
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require "mrsk/cli/base"
|
2
|
+
|
3
|
+
class Mrsk::Cli::Traefik < Mrsk::Cli::Base
|
4
|
+
desc "boot", "Boot Traefik on servers"
|
5
|
+
def boot
|
6
|
+
on(MRSK.traefik_hosts) { execute *MRSK.traefik.run, raise_on_non_zero_exit: false }
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "reboot", "Reboot Traefik on servers (stop container, remove container, start new container)"
|
10
|
+
def reboot
|
11
|
+
invoke :stop
|
12
|
+
invoke :remove_container
|
13
|
+
invoke :boot
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "start", "Start existing Traefik on servers"
|
17
|
+
def start
|
18
|
+
on(MRSK.traefik_hosts) { execute *MRSK.traefik.start, raise_on_non_zero_exit: false }
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "stop", "Stop Traefik on servers"
|
22
|
+
def stop
|
23
|
+
on(MRSK.traefik_hosts) { execute *MRSK.traefik.stop, raise_on_non_zero_exit: false }
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "restart", "Restart Traefik on servers"
|
27
|
+
def restart
|
28
|
+
invoke :stop
|
29
|
+
invoke :start
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "details", "Display details about Traefik containers from servers"
|
33
|
+
def details
|
34
|
+
on(MRSK.traefik_hosts) { |host| puts_by_host host, capture_with_info(*MRSK.traefik.info), type: "Traefik" }
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "logs", "Show log lines from Traefik on servers"
|
38
|
+
option :since, aliases: "-s", desc: "Show logs since timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes)"
|
39
|
+
option :lines, type: :numeric, aliases: "-n", desc: "Number of log lines to pull from each server"
|
40
|
+
option :grep, aliases: "-g", desc: "Show lines with grep match only (use this to fetch specific requests by id)"
|
41
|
+
option :follow, aliases: "-f", desc: "Follow logs on primary server (or specific host set by --hosts)"
|
42
|
+
def logs
|
43
|
+
grep = options[:grep]
|
44
|
+
|
45
|
+
if options[:follow]
|
46
|
+
run_locally do
|
47
|
+
info "Following logs on #{MRSK.primary_host}..."
|
48
|
+
info MRSK.traefik.follow_logs(host: MRSK.primary_host, grep: grep)
|
49
|
+
exec MRSK.traefik.follow_logs(host: MRSK.primary_host, grep: grep)
|
50
|
+
end
|
51
|
+
else
|
52
|
+
since = options[:since]
|
53
|
+
lines = options[:lines]
|
54
|
+
|
55
|
+
on(MRSK.traefik_hosts) do |host|
|
56
|
+
puts_by_host host, capture(*MRSK.traefik.logs(since: since, lines: lines, grep: grep)), type: "Traefik"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
desc "remove", "Remove Traefik container and image from servers"
|
62
|
+
def remove
|
63
|
+
invoke :stop
|
64
|
+
invoke :remove_container
|
65
|
+
invoke :remove_image
|
66
|
+
end
|
67
|
+
|
68
|
+
desc "remove_container", "Remove Traefik container from servers"
|
69
|
+
def remove_container
|
70
|
+
on(MRSK.traefik_hosts) { execute *MRSK.traefik.remove_container }
|
71
|
+
end
|
72
|
+
|
73
|
+
desc "remove_container", "Remove Traefik image from servers"
|
74
|
+
def remove_image
|
75
|
+
on(MRSK.traefik_hosts) { execute *MRSK.traefik.remove_image }
|
76
|
+
end
|
77
|
+
end
|
data/lib/mrsk/cli.rb
ADDED
data/lib/mrsk/commander.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
+
require "active_support/core_ext/enumerable"
|
2
|
+
|
1
3
|
require "mrsk/configuration"
|
4
|
+
require "mrsk/commands/accessory"
|
2
5
|
require "mrsk/commands/app"
|
3
6
|
require "mrsk/commands/builder"
|
4
7
|
require "mrsk/commands/prune"
|
@@ -6,14 +9,43 @@ require "mrsk/commands/traefik"
|
|
6
9
|
require "mrsk/commands/registry"
|
7
10
|
|
8
11
|
class Mrsk::Commander
|
9
|
-
|
12
|
+
attr_accessor :config_file, :destination, :verbose, :version
|
10
13
|
|
11
|
-
def initialize(config_file
|
12
|
-
@config_file, @verbose = config_file, verbose
|
14
|
+
def initialize(config_file: nil, destination: nil, verbose: false)
|
15
|
+
@config_file, @destination, @verbose = config_file, destination, verbose
|
13
16
|
end
|
14
17
|
|
15
18
|
def config
|
16
|
-
@config ||=
|
19
|
+
@config ||= \
|
20
|
+
Mrsk::Configuration
|
21
|
+
.create_from(config_file, destination: destination, version: cascading_version)
|
22
|
+
.tap { |config| configure_sshkit_with(config) }
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_accessor :specific_hosts
|
26
|
+
|
27
|
+
def specific_primary!
|
28
|
+
self.specific_hosts = [ config.primary_web_host ]
|
29
|
+
end
|
30
|
+
|
31
|
+
def specific_roles=(role_names)
|
32
|
+
self.specific_hosts = config.roles.select { |r| role_names.include?(r.name) }.flat_map(&:hosts) if role_names.present?
|
33
|
+
end
|
34
|
+
|
35
|
+
def primary_host
|
36
|
+
specific_hosts&.sole || config.primary_web_host
|
37
|
+
end
|
38
|
+
|
39
|
+
def hosts
|
40
|
+
specific_hosts || config.all_hosts
|
41
|
+
end
|
42
|
+
|
43
|
+
def traefik_hosts
|
44
|
+
specific_hosts || config.traefik_hosts
|
45
|
+
end
|
46
|
+
|
47
|
+
def accessory_hosts
|
48
|
+
specific_hosts || config.accessories.collect(&:host)
|
17
49
|
end
|
18
50
|
|
19
51
|
|
@@ -37,6 +69,10 @@ class Mrsk::Commander
|
|
37
69
|
@prune ||= Mrsk::Commands::Prune.new(config)
|
38
70
|
end
|
39
71
|
|
72
|
+
def accessory(name)
|
73
|
+
(@accessories ||= {})[name] ||= Mrsk::Commands::Accessory.new(config, name: name)
|
74
|
+
end
|
75
|
+
|
40
76
|
|
41
77
|
def verbosity(level)
|
42
78
|
old_level = SSHKit.config.output_verbosity
|
@@ -47,8 +83,12 @@ class Mrsk::Commander
|
|
47
83
|
end
|
48
84
|
|
49
85
|
private
|
86
|
+
def cascading_version
|
87
|
+
version.presence || ENV["VERSION"] || `git rev-parse HEAD`.strip
|
88
|
+
end
|
89
|
+
|
50
90
|
# Lazy setup of SSHKit
|
51
|
-
def
|
91
|
+
def configure_sshkit_with(config)
|
52
92
|
SSHKit::Backend::Netssh.configure { |ssh| ssh.ssh_options = config.ssh_options }
|
53
93
|
SSHKit.config.command_map[:docker] = "docker" # No need to use /usr/bin/env, just clogs up the logs
|
54
94
|
SSHKit.config.output_verbosity = :debug if verbose
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require "mrsk/commands/base"
|
2
|
+
|
3
|
+
class Mrsk::Commands::Accessory < Mrsk::Commands::Base
|
4
|
+
attr_reader :accessory_config
|
5
|
+
delegate :service_name, :image, :host, :port, :env_args, :volume_args, :label_args, to: :accessory_config
|
6
|
+
|
7
|
+
def initialize(config, name:)
|
8
|
+
super(config)
|
9
|
+
@accessory_config = config.accessory(name)
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
docker :run,
|
14
|
+
"--name", service_name,
|
15
|
+
"-d",
|
16
|
+
"--restart", "unless-stopped",
|
17
|
+
"-p", port,
|
18
|
+
*env_args,
|
19
|
+
*volume_args,
|
20
|
+
*label_args,
|
21
|
+
image
|
22
|
+
end
|
23
|
+
|
24
|
+
def start
|
25
|
+
docker :container, :start, service_name
|
26
|
+
end
|
27
|
+
|
28
|
+
def stop
|
29
|
+
docker :container, :stop, service_name
|
30
|
+
end
|
31
|
+
|
32
|
+
def info
|
33
|
+
docker :ps, *service_filter
|
34
|
+
end
|
35
|
+
|
36
|
+
def logs(since: nil, lines: nil, grep: nil)
|
37
|
+
pipe \
|
38
|
+
docker(:logs, service_name, (" --since #{since}" if since), (" -n #{lines}" if lines), "-t", "2>&1"),
|
39
|
+
("grep '#{grep}'" if grep)
|
40
|
+
end
|
41
|
+
|
42
|
+
def follow_logs(grep: nil)
|
43
|
+
run_over_ssh pipe(
|
44
|
+
docker(:logs, service_name, "-t", "-n", "10", "-f", "2>&1"),
|
45
|
+
("grep '#{grep}'" if grep)
|
46
|
+
).join(" "), host: host
|
47
|
+
end
|
48
|
+
|
49
|
+
def remove_container
|
50
|
+
docker :container, :prune, "-f", *service_filter
|
51
|
+
end
|
52
|
+
|
53
|
+
def remove_image
|
54
|
+
docker :image, :prune, "-a", "-f", *service_filter
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def service_filter
|
59
|
+
[ "--filter", "label=service=#{service_name}" ]
|
60
|
+
end
|
61
|
+
end
|
data/lib/mrsk/commands/app.rb
CHANGED
@@ -8,40 +8,72 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
|
8
8
|
"-d",
|
9
9
|
"--restart unless-stopped",
|
10
10
|
"--name", config.service_with_version,
|
11
|
-
|
12
|
-
*
|
11
|
+
*rails_master_key_arg,
|
12
|
+
*role.env_args,
|
13
|
+
*config.volume_args,
|
13
14
|
*role.label_args,
|
14
15
|
config.absolute_image,
|
15
16
|
role.cmd
|
16
17
|
end
|
17
18
|
|
18
|
-
def start
|
19
|
-
docker :start, config.
|
19
|
+
def start(version: config.version)
|
20
|
+
docker :start, "#{config.service}-#{version}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def current_container_id
|
24
|
+
docker :ps, "-q", *service_filter
|
20
25
|
end
|
21
26
|
|
22
27
|
def stop
|
23
|
-
|
28
|
+
pipe current_container_id, "xargs docker stop"
|
24
29
|
end
|
25
30
|
|
26
31
|
def info
|
27
32
|
docker :ps, *service_filter
|
28
33
|
end
|
29
34
|
|
30
|
-
def logs
|
31
|
-
|
35
|
+
def logs(since: nil, lines: nil, grep: nil)
|
36
|
+
pipe \
|
37
|
+
current_container_id,
|
38
|
+
"xargs docker logs#{" --since #{since}" if since}#{" -n #{lines}" if lines} -t 2>&1",
|
39
|
+
("grep '#{grep}'" if grep)
|
32
40
|
end
|
33
41
|
|
34
42
|
def exec(*command, interactive: false)
|
35
43
|
docker :exec,
|
36
44
|
("-it" if interactive),
|
37
|
-
|
45
|
+
*rails_master_key_arg,
|
38
46
|
*config.env_args,
|
47
|
+
*config.volume_args,
|
39
48
|
config.service_with_version,
|
40
49
|
*command
|
41
50
|
end
|
42
51
|
|
43
|
-
def
|
44
|
-
|
52
|
+
def run_exec(*command, interactive: false)
|
53
|
+
docker :run,
|
54
|
+
("-it" if interactive),
|
55
|
+
"--rm",
|
56
|
+
*rails_master_key_arg,
|
57
|
+
*config.env_args,
|
58
|
+
*config.volume_args,
|
59
|
+
config.absolute_image,
|
60
|
+
*command
|
61
|
+
end
|
62
|
+
|
63
|
+
def follow_logs(host:, grep: nil)
|
64
|
+
run_over_ssh pipe(
|
65
|
+
current_container_id,
|
66
|
+
"xargs docker logs -t -n 10 -f 2>&1",
|
67
|
+
("grep '#{grep}'" if grep)
|
68
|
+
).join(" "), host: host
|
69
|
+
end
|
70
|
+
|
71
|
+
def console(host:)
|
72
|
+
exec_over_ssh "bin/rails", "c", host: host
|
73
|
+
end
|
74
|
+
|
75
|
+
def bash(host:)
|
76
|
+
exec_over_ssh "bash", host: host
|
45
77
|
end
|
46
78
|
|
47
79
|
def list_containers
|
@@ -57,7 +89,15 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
|
57
89
|
end
|
58
90
|
|
59
91
|
private
|
92
|
+
def exec_over_ssh(*command, host:)
|
93
|
+
run_over_ssh run_exec(*command, interactive: true).join(" "), host: host
|
94
|
+
end
|
95
|
+
|
60
96
|
def service_filter
|
61
97
|
[ "--filter", "label=service=#{config.service}" ]
|
62
98
|
end
|
99
|
+
|
100
|
+
def rails_master_key_arg
|
101
|
+
[ "-e", redact("RAILS_MASTER_KEY=#{config.master_key}") ]
|
102
|
+
end
|
63
103
|
end
|
data/lib/mrsk/commands/base.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
require "sshkit"
|
2
|
-
|
3
1
|
module Mrsk::Commands
|
4
2
|
class Base
|
3
|
+
delegate :redact, to: Mrsk::Utils
|
4
|
+
|
5
5
|
attr_accessor :config
|
6
6
|
|
7
7
|
def initialize(config)
|
@@ -9,19 +9,23 @@ module Mrsk::Commands
|
|
9
9
|
end
|
10
10
|
|
11
11
|
private
|
12
|
-
def combine(*commands)
|
12
|
+
def combine(*commands, by: "&&")
|
13
13
|
commands
|
14
|
-
.
|
15
|
-
.
|
14
|
+
.compact
|
15
|
+
.collect { |command| Array(command) + [ by ] }.flatten # Join commands
|
16
|
+
.tap { |commands| commands.pop } # Remove trailing combiner
|
17
|
+
end
|
18
|
+
|
19
|
+
def pipe(*commands)
|
20
|
+
combine *commands, by: "|"
|
16
21
|
end
|
17
22
|
|
18
23
|
def docker(*args)
|
19
24
|
args.compact.unshift :docker
|
20
25
|
end
|
21
26
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
end
|
27
|
+
def run_over_ssh(command, host:)
|
28
|
+
"ssh -t #{config.ssh_user}@#{host} '#{command}'"
|
29
|
+
end
|
26
30
|
end
|
27
31
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "mrsk/commands/base"
|
2
|
+
|
3
|
+
class Mrsk::Commands::Builder::Base < Mrsk::Commands::Base
|
4
|
+
delegate :argumentize, to: Mrsk::Utils
|
5
|
+
|
6
|
+
def pull
|
7
|
+
docker :pull, config.absolute_image
|
8
|
+
end
|
9
|
+
|
10
|
+
def build_args
|
11
|
+
argumentize "--build-arg", args, redacted: true
|
12
|
+
end
|
13
|
+
|
14
|
+
def build_secrets
|
15
|
+
argumentize "--secret", secrets.collect { |secret| [ "id", secret ] }
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def args
|
20
|
+
(config.builder && config.builder["args"]) || {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def secrets
|
24
|
+
(config.builder && config.builder["secrets"]) || []
|
25
|
+
end
|
26
|
+
end
|