mrsk 0.5.1 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +48 -15
- data/bin/mrsk +1 -2
- data/lib/mrsk/cli/accessory.rb +1 -2
- data/lib/mrsk/cli/app.rb +6 -16
- data/lib/mrsk/cli/base.rb +10 -0
- data/lib/mrsk/cli/build.rb +1 -3
- data/lib/mrsk/cli/main.rb +20 -14
- data/lib/mrsk/cli/prune.rb +0 -2
- data/lib/mrsk/cli/registry.rb +0 -2
- data/lib/mrsk/cli/server.rb +0 -2
- data/lib/mrsk/cli/templates/template.env +2 -0
- data/lib/mrsk/cli/traefik.rb +0 -2
- data/lib/mrsk/cli.rb +0 -4
- data/lib/mrsk/commander.rb +10 -11
- data/lib/mrsk/commands/accessory.rb +7 -9
- data/lib/mrsk/commands/app.rb +9 -19
- data/lib/mrsk/commands/auditor.rb +5 -2
- data/lib/mrsk/commands/base.rb +5 -2
- data/lib/mrsk/commands/builder/base.rb +0 -2
- data/lib/mrsk/commands/builder/multiarch/remote.rb +0 -2
- data/lib/mrsk/commands/builder/multiarch.rb +0 -2
- data/lib/mrsk/commands/builder/native/remote.rb +0 -2
- data/lib/mrsk/commands/builder/native.rb +1 -3
- data/lib/mrsk/commands/builder.rb +0 -7
- data/lib/mrsk/commands/prune.rb +0 -1
- data/lib/mrsk/commands/registry.rb +0 -2
- data/lib/mrsk/commands/traefik.rb +0 -2
- data/lib/mrsk/configuration/role.rb +6 -1
- data/lib/mrsk/configuration.rb +13 -11
- data/lib/mrsk/version.rb +1 -1
- data/lib/mrsk.rb +6 -2
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 957bd15fa5ddbd2b63c0f264cb92ccb3288ba956d0ba371fcfa752bd75604e6c
|
4
|
+
data.tar.gz: 14826e53ee7534b3a25efe4671e7325486e377f4313cbe991348d119059070b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8020ed616daa525d17cec2d638abb7707a0daae8acf320f72a488609d8eaee64a65f708b17aa84f9d87e939f8e608298a31cbbe090f34000885d6a5702cf601a
|
7
|
+
data.tar.gz: 4e1a952fa22de6cba2c71983686d274b1d4fab3153b2db40859a4a3d03b49ac9676ee0d782892a812c55a39788d39c55b948456d59a43dea462c0106b777e6aa
|
data/README.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# MRSK
|
2
2
|
|
3
|
-
MRSK deploys
|
3
|
+
MRSK deploys web apps in containers to servers running Docker with zero downtime. It uses the dynamic reverse-proxy Traefik to hold requests while the new application container is started and the old one is stopped. It works seamlessly across multiple hosts, using SSHKit to execute commands.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
7
|
-
Install MRSK globally with `gem install mrsk`. Then, inside your app directory, run `mrsk
|
7
|
+
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:
|
8
8
|
|
9
9
|
```yaml
|
10
10
|
service: hey
|
@@ -15,12 +15,17 @@ servers:
|
|
15
15
|
registry:
|
16
16
|
username: registry-user-name
|
17
17
|
password: <%= ENV.fetch("MRSK_REGISTRY_PASSWORD") %>
|
18
|
+
env:
|
19
|
+
secret:
|
20
|
+
- RAILS_MASTER_KEY
|
18
21
|
```
|
19
22
|
|
20
|
-
|
23
|
+
Then edit your `.env` file to add your registry password as `MRSK_REGISTRY_PASSWORD` (and your `RAILS_MASTER_KEY` for production with a Rails app).
|
24
|
+
|
25
|
+
Now you're ready to deploy to the servers:
|
21
26
|
|
22
27
|
```
|
23
|
-
|
28
|
+
mrsk deploy
|
24
29
|
```
|
25
30
|
|
26
31
|
This will:
|
@@ -38,12 +43,14 @@ This will:
|
|
38
43
|
|
39
44
|
Voila! All the servers are now serving the app on port 80. If you're just running a single server, you're ready to go. If you're running multiple servers, you need to put a load balancer in front of them.
|
40
45
|
|
41
|
-
## Why not just run Capistrano or
|
46
|
+
## Why not just run Capistrano, Kubernetes or Docker Swarm?
|
42
47
|
|
43
48
|
MRSK basically is Capistrano for Containers, which allow us to use vanilla servers as the hosts. No need to ensure that the servers have just the right version of Ruby or other dependencies you need. That all lives in the Docker image now. You can boot a brand new Ubuntu (or whatever) server, add it to the deploy servers of MRSK, and it'll be auto-provisioned with Docker, and run right away. Docker's layer caching also allows for quicker deployments with less mucking about on the server. And the images built for MRSK can be used for CI or later introspection.
|
44
49
|
|
45
50
|
Kubernetes is a beast. Running it yourself on your own hardware is not for the faint of heart. It's a fine option if you want to run on someone else's platform, like Render or Fly, but if you'd like the freedom to move between cloud and your own hardware, or even mix the two, MRSK is much simpler. You can see everything that's going on, it's just basic Docker commands being called.
|
46
51
|
|
52
|
+
Docker Swarm is much simpler than Kubernetes, but it's still built on the same declarative model that uses state reconciliation. MRSK is intentionally designed to around imperative commands, like Capistrano.
|
53
|
+
|
47
54
|
## Configuration
|
48
55
|
|
49
56
|
### Using .env file to load required environment variables
|
@@ -68,10 +75,27 @@ registry:
|
|
68
75
|
|
69
76
|
### Using a different SSH user than root
|
70
77
|
|
71
|
-
The default SSH user is root, but you can change it using `
|
78
|
+
The default SSH user is root, but you can change it using `ssh/user`:
|
79
|
+
|
80
|
+
```yaml
|
81
|
+
ssh:
|
82
|
+
user: app
|
83
|
+
```
|
84
|
+
|
85
|
+
### Using a proxy SSH host
|
86
|
+
|
87
|
+
If you need to connect to server through a proxy host, you can use `ssh/proxy`:
|
88
|
+
|
89
|
+
```yaml
|
90
|
+
ssh:
|
91
|
+
proxy: "192.168.0.1" # defaults to root as the user
|
92
|
+
```
|
93
|
+
|
94
|
+
Or with specific user:
|
72
95
|
|
73
96
|
```yaml
|
74
|
-
|
97
|
+
ssh:
|
98
|
+
proxy: "app@192.168.0.1"
|
75
99
|
```
|
76
100
|
|
77
101
|
### Using env variables
|
@@ -265,14 +289,6 @@ ARG RUBY_VERSION
|
|
265
289
|
FROM ruby:$RUBY_VERSION-slim as base
|
266
290
|
```
|
267
291
|
|
268
|
-
### Using without RAILS_MASTER_KEY
|
269
|
-
|
270
|
-
If you're using MRSK with older Rails apps that predate RAILS_MASTER_KEY, or with a non-Rails app, you can skip the default usage and reference:
|
271
|
-
|
272
|
-
```yaml
|
273
|
-
skip_master_key: true
|
274
|
-
```
|
275
|
-
|
276
292
|
### Using accessories for database, cache, search services
|
277
293
|
|
278
294
|
You can manage your accessory services via MRSK as well. The services will build off public images, and will not be automatically updated when you deploy:
|
@@ -300,6 +316,23 @@ accessories:
|
|
300
316
|
|
301
317
|
Now run `mrsk accessory start mysql` to start the MySQL server on 1.1.1.3. See `mrsk accessory` for all the commands possible.
|
302
318
|
|
319
|
+
### Using a generated .env file
|
320
|
+
|
321
|
+
If you're using a centralized secret store, like 1Password, you can create `.env.erb` as a template which looks up the secrets. Example of a .env.erb file:
|
322
|
+
|
323
|
+
```erb
|
324
|
+
<% if (session_token = `op signin --account my-one-password-account --raw`.strip) != "" %># Generated by mrsk envify
|
325
|
+
GITHUB_TOKEN=<%= `gh config get -h github.com oauth_token`.strip %>
|
326
|
+
MRSK_REGISTRY_PASSWORD=<%= `op read "op://Vault/Docker Hub/password" -n --session #{session_token}` %>
|
327
|
+
RAILS_MASTER_KEY=<%= `op read "op://Vault/My App/RAILS_MASTER_SECRET" -n --session #{session_token}` %>
|
328
|
+
MYSQL_ROOT_PASSWORD=<%= `op read "op://Vault/My App/MYSQL_ROOT_PASSWORD" -n --session #{session_token}` %>
|
329
|
+
<% else raise ArgumentError, "Session token missing" end %>
|
330
|
+
```
|
331
|
+
|
332
|
+
This template can safely be checked into git. Then everyone deploying the app can run `mrsk envify` when they setup the app for the first time or passwords change to get the correct `.env` file.
|
333
|
+
|
334
|
+
If you need separate env variables for different destinations, you can set them with `.env.destination.erb` for the template, which will generate `.env.staging` when run with `mrsk envify -d staging`.
|
335
|
+
|
303
336
|
## Commands
|
304
337
|
|
305
338
|
### Running commands on servers
|
data/bin/mrsk
CHANGED
data/lib/mrsk/cli/accessory.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require "mrsk/cli/base"
|
2
|
-
|
3
1
|
class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
4
2
|
desc "boot [NAME]", "Boot accessory service on host (use NAME=all to boot all accessories)"
|
5
3
|
def boot(name)
|
@@ -9,6 +7,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|
9
7
|
with_accessory(name) do |accessory|
|
10
8
|
directories(name)
|
11
9
|
upload(name)
|
10
|
+
|
12
11
|
on(accessory.host) do
|
13
12
|
execute *MRSK.auditor.record("accessory #{name} boot"), verbosity: :debug
|
14
13
|
execute *accessory.run
|
data/lib/mrsk/cli/app.rb
CHANGED
@@ -1,13 +1,6 @@
|
|
1
|
-
require "mrsk/cli/base"
|
2
|
-
|
3
1
|
class Mrsk::Cli::App < Mrsk::Cli::Base
|
4
2
|
desc "boot", "Boot app on servers (or reboot app if already running)"
|
5
3
|
def boot
|
6
|
-
cli = self
|
7
|
-
|
8
|
-
say "Ensure no other version of the app is running...", :magenta
|
9
|
-
stop
|
10
|
-
|
11
4
|
say "Get most recent version available as an image...", :magenta unless options[:version]
|
12
5
|
using_version(options[:version] || most_recent_version_available) do |version|
|
13
6
|
say "Start container with version #{version} (or reboot if already running)...", :magenta
|
@@ -17,12 +10,14 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
|
|
17
10
|
execute *MRSK.auditor.record("app boot version #{version}"), verbosity: :debug
|
18
11
|
|
19
12
|
begin
|
13
|
+
execute *MRSK.app.stop, raise_on_non_zero_exit: false
|
20
14
|
execute *MRSK.app.run(role: role.name)
|
21
15
|
rescue SSHKit::Command::Failed => e
|
22
16
|
if e.message =~ /already in use/
|
23
17
|
error "Rebooting container with same version already deployed on #{host}"
|
18
|
+
execute *MRSK.auditor.record("app rebooted with version #{version}"), verbosity: :debug
|
24
19
|
|
25
|
-
|
20
|
+
execute *MRSK.app.remove_container(version: version)
|
26
21
|
execute *MRSK.app.run(role: role.name)
|
27
22
|
else
|
28
23
|
raise
|
@@ -40,7 +35,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
|
|
40
35
|
execute *MRSK.app.start, raise_on_non_zero_exit: false
|
41
36
|
end
|
42
37
|
end
|
43
|
-
|
38
|
+
|
44
39
|
desc "stop", "Stop app on servers"
|
45
40
|
def stop
|
46
41
|
on(MRSK.hosts) do
|
@@ -48,12 +43,12 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
|
|
48
43
|
execute *MRSK.app.stop, raise_on_non_zero_exit: false
|
49
44
|
end
|
50
45
|
end
|
51
|
-
|
46
|
+
|
52
47
|
desc "details", "Display details about app containers"
|
53
48
|
def details
|
54
49
|
on(MRSK.hosts) { |host| puts_by_host host, capture_with_info(*MRSK.app.info) }
|
55
50
|
end
|
56
|
-
|
51
|
+
|
57
52
|
desc "exec [CMD]", "Execute a custom command on servers"
|
58
53
|
option :interactive, aliases: "-i", type: :boolean, default: false, desc: "Execute command over ssh for an interactive shell (use for console/bash)"
|
59
54
|
option :reuse, type: :boolean, default: false, desc: "Reuse currently running container instead of starting a new one"
|
@@ -106,11 +101,6 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
|
|
106
101
|
on(MRSK.hosts) { |host| puts_by_host host, capture_with_info(*MRSK.app.list_images) }
|
107
102
|
end
|
108
103
|
|
109
|
-
desc "current", "Return the current running container ID"
|
110
|
-
def current
|
111
|
-
on(MRSK.hosts) { |host| puts_by_host host, capture_with_info(*MRSK.app.current_container_id) }
|
112
|
-
end
|
113
|
-
|
114
104
|
desc "logs", "Show lines from app on servers"
|
115
105
|
option :since, aliases: "-s", desc: "Show logs since timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes)"
|
116
106
|
option :lines, type: :numeric, aliases: "-n", desc: "Number of log lines to pull from each server"
|
data/lib/mrsk/cli/base.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "thor"
|
2
|
+
require "dotenv"
|
2
3
|
require "mrsk/sshkit_with_ext"
|
3
4
|
|
4
5
|
module Mrsk::Cli
|
@@ -21,10 +22,19 @@ module Mrsk::Cli
|
|
21
22
|
|
22
23
|
def initialize(*)
|
23
24
|
super
|
25
|
+
load_envs
|
24
26
|
initialize_commander(options)
|
25
27
|
end
|
26
28
|
|
27
29
|
private
|
30
|
+
def load_envs
|
31
|
+
if destination = options[:destination]
|
32
|
+
Dotenv.load(".env.#{destination}", ".env")
|
33
|
+
else
|
34
|
+
Dotenv.load(".env")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
28
38
|
def initialize_commander(options)
|
29
39
|
MRSK.tap do |commander|
|
30
40
|
commander.config_file = Pathname.new(File.expand_path(options[:config_file]))
|
data/lib/mrsk/cli/build.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require "mrsk/cli/base"
|
2
|
-
|
3
1
|
class Mrsk::Cli::Build < Mrsk::Cli::Base
|
4
2
|
desc "deliver", "Deliver a newly built app image to servers"
|
5
3
|
def deliver
|
@@ -11,7 +9,7 @@ class Mrsk::Cli::Build < Mrsk::Cli::Base
|
|
11
9
|
def push
|
12
10
|
cli = self
|
13
11
|
|
14
|
-
run_locally do
|
12
|
+
run_locally do
|
15
13
|
begin
|
16
14
|
MRSK.with_verbosity(:debug) { execute *MRSK.builder.push }
|
17
15
|
rescue SSHKit::Command::Failed => e
|
data/lib/mrsk/cli/main.rb
CHANGED
@@ -1,13 +1,3 @@
|
|
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
1
|
class Mrsk::Cli::Main < Mrsk::Cli::Base
|
12
2
|
desc "setup", "Setup all accessories and deploy the app to servers"
|
13
3
|
def setup
|
@@ -84,22 +74,29 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base
|
|
84
74
|
end
|
85
75
|
end
|
86
76
|
|
87
|
-
desc "
|
88
|
-
option :
|
89
|
-
def
|
77
|
+
desc "init", "Create config stub in config/deploy.yml and env stub in .env"
|
78
|
+
option :bundle, type: :boolean, default: false, desc: "Add MRSK to the Gemfile and create a bin/mrsk binstub"
|
79
|
+
def init
|
90
80
|
require "fileutils"
|
91
81
|
|
92
82
|
if (deploy_file = Pathname.new(File.expand_path("config/deploy.yml"))).exist?
|
93
83
|
puts "Config file already exists in config/deploy.yml (remove first to create a new one)"
|
94
84
|
else
|
85
|
+
FileUtils.mkdir_p deploy_file.dirname
|
95
86
|
FileUtils.cp_r Pathname.new(File.expand_path("templates/deploy.yml", __dir__)), deploy_file
|
96
87
|
puts "Created configuration file in config/deploy.yml"
|
97
88
|
end
|
98
89
|
|
99
|
-
unless
|
90
|
+
unless (deploy_file = Pathname.new(File.expand_path(".env"))).exist?
|
91
|
+
FileUtils.cp_r Pathname.new(File.expand_path("templates/template.env", __dir__)), deploy_file
|
92
|
+
puts "Created .env file"
|
93
|
+
end
|
94
|
+
|
95
|
+
if options[:bundle]
|
100
96
|
if (binstub = Pathname.new(File.expand_path("bin/mrsk"))).exist?
|
101
97
|
puts "Binstub already exists in bin/mrsk (remove first to create a new one)"
|
102
98
|
else
|
99
|
+
puts "Adding MRSK to Gemfile and bundle..."
|
103
100
|
`bundle add mrsk`
|
104
101
|
`bundle binstubs mrsk`
|
105
102
|
puts "Created binstub file in bin/mrsk"
|
@@ -107,6 +104,15 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base
|
|
107
104
|
end
|
108
105
|
end
|
109
106
|
|
107
|
+
desc "envify", "Create .env by evaluating .env.erb (or .env.staging.erb -> .env.staging when using -d staging)"
|
108
|
+
def envify
|
109
|
+
if destination = options[:destination]
|
110
|
+
File.write(".env.#{destination}", ERB.new(IO.read(Pathname.new(File.expand_path(".env.#{destination}.erb")))).result)
|
111
|
+
else
|
112
|
+
File.write(".env", ERB.new(IO.read(Pathname.new(File.expand_path(".env.erb")))).result)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
110
116
|
desc "remove", "Remove Traefik, app, and registry session from servers"
|
111
117
|
def remove
|
112
118
|
invoke "mrsk:cli:traefik:remove"
|
data/lib/mrsk/cli/prune.rb
CHANGED
data/lib/mrsk/cli/registry.rb
CHANGED
data/lib/mrsk/cli/server.rb
CHANGED
data/lib/mrsk/cli/traefik.rb
CHANGED
data/lib/mrsk/cli.rb
CHANGED
data/lib/mrsk/commander.rb
CHANGED
@@ -1,14 +1,5 @@
|
|
1
1
|
require "active_support/core_ext/enumerable"
|
2
2
|
|
3
|
-
require "mrsk/configuration"
|
4
|
-
require "mrsk/commands/accessory"
|
5
|
-
require "mrsk/commands/app"
|
6
|
-
require "mrsk/commands/auditor"
|
7
|
-
require "mrsk/commands/builder"
|
8
|
-
require "mrsk/commands/prune"
|
9
|
-
require "mrsk/commands/traefik"
|
10
|
-
require "mrsk/commands/registry"
|
11
|
-
|
12
3
|
class Mrsk::Commander
|
13
4
|
attr_accessor :config_file, :destination, :verbosity, :version
|
14
5
|
|
@@ -83,7 +74,7 @@ class Mrsk::Commander
|
|
83
74
|
end
|
84
75
|
|
85
76
|
|
86
|
-
def with_verbosity(level)
|
77
|
+
def with_verbosity(level)
|
87
78
|
old_level = SSHKit.config.output_verbosity
|
88
79
|
SSHKit.config.output_verbosity = level
|
89
80
|
yield
|
@@ -100,7 +91,15 @@ class Mrsk::Commander
|
|
100
91
|
|
101
92
|
private
|
102
93
|
def cascading_version
|
103
|
-
version.presence || ENV["VERSION"] ||
|
94
|
+
version.presence || ENV["VERSION"] || current_commit_hash
|
95
|
+
end
|
96
|
+
|
97
|
+
def current_commit_hash
|
98
|
+
if system("git rev-parse")
|
99
|
+
`git rev-parse HEAD`.strip
|
100
|
+
else
|
101
|
+
raise "Can't use commit hash as version, no git repository found in #{Dir.pwd}"
|
102
|
+
end
|
104
103
|
end
|
105
104
|
|
106
105
|
# Lazy setup of SSHKit
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require "mrsk/commands/base"
|
2
|
-
|
3
1
|
class Mrsk::Commands::Accessory < Mrsk::Commands::Base
|
4
2
|
attr_reader :accessory_config
|
5
3
|
delegate :service_name, :image, :host, :port, :files, :directories, :env_args, :volume_args, :label_args, to: :accessory_config
|
@@ -10,7 +8,7 @@ class Mrsk::Commands::Accessory < Mrsk::Commands::Base
|
|
10
8
|
end
|
11
9
|
|
12
10
|
def run
|
13
|
-
docker :run,
|
11
|
+
docker :run,
|
14
12
|
"--name", service_name,
|
15
13
|
"-d",
|
16
14
|
"--restart", "unless-stopped",
|
@@ -41,10 +39,10 @@ class Mrsk::Commands::Accessory < Mrsk::Commands::Base
|
|
41
39
|
end
|
42
40
|
|
43
41
|
def follow_logs(grep: nil)
|
44
|
-
run_over_ssh
|
45
|
-
|
46
|
-
|
47
|
-
|
42
|
+
run_over_ssh \
|
43
|
+
pipe \
|
44
|
+
docker(:logs, service_name, "-t", "-n", "10", "-f", "2>&1"),
|
45
|
+
(%(grep "#{grep}") if grep)
|
48
46
|
end
|
49
47
|
|
50
48
|
|
@@ -66,11 +64,11 @@ class Mrsk::Commands::Accessory < Mrsk::Commands::Base
|
|
66
64
|
end
|
67
65
|
|
68
66
|
def execute_in_existing_container_over_ssh(*command)
|
69
|
-
run_over_ssh execute_in_existing_container(*command, interactive: true)
|
67
|
+
run_over_ssh execute_in_existing_container(*command, interactive: true)
|
70
68
|
end
|
71
69
|
|
72
70
|
def execute_in_new_container_over_ssh(*command)
|
73
|
-
run_over_ssh execute_in_new_container(*command, interactive: true)
|
71
|
+
run_over_ssh execute_in_new_container(*command, interactive: true)
|
74
72
|
end
|
75
73
|
|
76
74
|
def run_over_ssh(command)
|
data/lib/mrsk/commands/app.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require "mrsk/commands/base"
|
2
|
-
|
3
1
|
class Mrsk::Commands::App < Mrsk::Commands::Base
|
4
2
|
def run(role: :web)
|
5
3
|
role = config.role(role)
|
@@ -8,7 +6,6 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
|
8
6
|
"-d",
|
9
7
|
"--restart unless-stopped",
|
10
8
|
"--name", service_with_version,
|
11
|
-
*rails_master_key_arg,
|
12
9
|
*role.env_args,
|
13
10
|
*config.volume_args,
|
14
11
|
*role.label_args,
|
@@ -37,11 +34,13 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
|
37
34
|
end
|
38
35
|
|
39
36
|
def follow_logs(host:, grep: nil)
|
40
|
-
run_over_ssh
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
37
|
+
run_over_ssh \
|
38
|
+
pipe(
|
39
|
+
current_container_id,
|
40
|
+
"xargs docker logs -t -n 10 -f 2>&1",
|
41
|
+
(%(grep "#{grep}") if grep)
|
42
|
+
),
|
43
|
+
host: host
|
45
44
|
end
|
46
45
|
|
47
46
|
|
@@ -56,7 +55,6 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
|
56
55
|
docker :run,
|
57
56
|
("-it" if interactive),
|
58
57
|
"--rm",
|
59
|
-
*rails_master_key_arg,
|
60
58
|
*config.env_args,
|
61
59
|
*config.volume_args,
|
62
60
|
config.absolute_image,
|
@@ -64,11 +62,11 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
|
64
62
|
end
|
65
63
|
|
66
64
|
def execute_in_existing_container_over_ssh(*command, host:)
|
67
|
-
run_over_ssh execute_in_existing_container(*command, interactive: true)
|
65
|
+
run_over_ssh execute_in_existing_container(*command, interactive: true), host: host
|
68
66
|
end
|
69
67
|
|
70
68
|
def execute_in_new_container_over_ssh(*command, host:)
|
71
|
-
run_over_ssh execute_in_new_container(*command, interactive: true)
|
69
|
+
run_over_ssh execute_in_new_container(*command, interactive: true), host: host
|
72
70
|
end
|
73
71
|
|
74
72
|
|
@@ -130,12 +128,4 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
|
130
128
|
def service_filter
|
131
129
|
[ "--filter", "label=service=#{config.service}" ]
|
132
130
|
end
|
133
|
-
|
134
|
-
def rails_master_key_arg
|
135
|
-
if master_key = config.master_key
|
136
|
-
[ "-e", redact("RAILS_MASTER_KEY=#{master_key}") ]
|
137
|
-
else
|
138
|
-
[]
|
139
|
-
end
|
140
|
-
end
|
141
131
|
end
|
@@ -1,10 +1,9 @@
|
|
1
1
|
require "active_support/core_ext/time/conversions"
|
2
|
-
require "mrsk/commands/base"
|
3
2
|
|
4
3
|
class Mrsk::Commands::Auditor < Mrsk::Commands::Base
|
5
4
|
def record(line)
|
6
5
|
append \
|
7
|
-
[ :echo,
|
6
|
+
[ :echo, tagged_line(line) ],
|
8
7
|
audit_log_file
|
9
8
|
end
|
10
9
|
|
@@ -17,6 +16,10 @@ class Mrsk::Commands::Auditor < Mrsk::Commands::Base
|
|
17
16
|
"mrsk-#{config.service}-audit.log"
|
18
17
|
end
|
19
18
|
|
19
|
+
def tagged_line(line)
|
20
|
+
"'#{tags} #{line}'"
|
21
|
+
end
|
22
|
+
|
20
23
|
def tags
|
21
24
|
"[#{timestamp}] [#{performer}]"
|
22
25
|
end
|
data/lib/mrsk/commands/base.rb
CHANGED
@@ -8,8 +8,11 @@ module Mrsk::Commands
|
|
8
8
|
@config = config
|
9
9
|
end
|
10
10
|
|
11
|
-
def run_over_ssh(command, host:)
|
12
|
-
"ssh
|
11
|
+
def run_over_ssh(*command, host:)
|
12
|
+
"ssh".tap do |cmd|
|
13
|
+
cmd << " -J #{config.ssh_proxy.jump_proxies}" if config.ssh_proxy
|
14
|
+
cmd << " -t #{config.ssh_user}@#{host} '#{command.join(" ")}'"
|
15
|
+
end
|
13
16
|
end
|
14
17
|
|
15
18
|
private
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require "mrsk/commands/builder/base"
|
2
|
-
|
3
1
|
class Mrsk::Commands::Builder::Native < Mrsk::Commands::Builder::Base
|
4
2
|
def create
|
5
3
|
# No-op on native
|
@@ -11,7 +9,7 @@ class Mrsk::Commands::Builder::Native < Mrsk::Commands::Builder::Base
|
|
11
9
|
|
12
10
|
def push
|
13
11
|
combine \
|
14
|
-
docker(:build, "-t", *build_args, *build_secrets,
|
12
|
+
docker(:build, "-t", config.absolute_image, *build_args, *build_secrets, "."),
|
15
13
|
docker(:push, config.absolute_image)
|
16
14
|
end
|
17
15
|
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require "mrsk/commands/base"
|
2
|
-
|
3
1
|
class Mrsk::Commands::Builder < Mrsk::Commands::Base
|
4
2
|
delegate :create, :remove, :push, :pull, :info, to: :target
|
5
3
|
|
@@ -36,8 +34,3 @@ class Mrsk::Commands::Builder < Mrsk::Commands::Base
|
|
36
34
|
@multiarch_remote ||= Mrsk::Commands::Builder::Multiarch::Remote.new(config)
|
37
35
|
end
|
38
36
|
end
|
39
|
-
|
40
|
-
require "mrsk/commands/builder/native"
|
41
|
-
require "mrsk/commands/builder/native/remote"
|
42
|
-
require "mrsk/commands/builder/multiarch"
|
43
|
-
require "mrsk/commands/builder/multiarch/remote"
|
data/lib/mrsk/commands/prune.rb
CHANGED
@@ -96,7 +96,12 @@ class Mrsk::Configuration::Role
|
|
96
96
|
def merged_env_with_secrets
|
97
97
|
merged_env.tap do |new_env|
|
98
98
|
new_env["secret"] = Array(config.env["secret"]) + Array(specialized_env["secret"])
|
99
|
-
|
99
|
+
|
100
|
+
# If there's no secret/clear split, everything is clear
|
101
|
+
clear_app_env = config.env["secret"] ? Array(config.env["clear"]) : Array(config.env["clear"] || config.env)
|
102
|
+
clear_role_env = specialized_env["secret"] ? Array(specialized_env["clear"]) : Array(specialized_env["clear"] || specialized_env)
|
103
|
+
|
104
|
+
new_env["clear"] = (clear_app_env + clear_role_env).uniq
|
100
105
|
end
|
101
106
|
end
|
102
107
|
end
|
data/lib/mrsk/configuration.rb
CHANGED
@@ -3,7 +3,7 @@ require "active_support/core_ext/string/inquiry"
|
|
3
3
|
require "active_support/core_ext/module/delegation"
|
4
4
|
require "pathname"
|
5
5
|
require "erb"
|
6
|
-
require "
|
6
|
+
require "net/ssh/proxy/jump"
|
7
7
|
|
8
8
|
class Mrsk::Configuration
|
9
9
|
delegate :service, :image, :servers, :env, :labels, :registry, :builder, to: :raw_config, allow_nil: true
|
@@ -104,17 +104,22 @@ class Mrsk::Configuration
|
|
104
104
|
end
|
105
105
|
|
106
106
|
def ssh_user
|
107
|
-
raw_config.
|
107
|
+
if raw_config.ssh.present?
|
108
|
+
raw_config.ssh["user"] || "root"
|
109
|
+
else
|
110
|
+
"root"
|
111
|
+
end
|
108
112
|
end
|
109
113
|
|
110
|
-
def
|
111
|
-
|
114
|
+
def ssh_proxy
|
115
|
+
if raw_config.ssh.present? && raw_config.ssh["proxy"]
|
116
|
+
Net::SSH::Proxy::Jump.new \
|
117
|
+
raw_config.ssh["proxy"].include?("@") ? raw_config.ssh["proxy"] : "root@#{raw_config.ssh["proxy"]}"
|
118
|
+
end
|
112
119
|
end
|
113
120
|
|
114
|
-
def
|
115
|
-
|
116
|
-
ENV["RAILS_MASTER_KEY"] || File.read(Pathname.new(File.expand_path("config/master.key")))
|
117
|
-
end
|
121
|
+
def ssh_options
|
122
|
+
{ user: ssh_user, proxy: ssh_proxy, auth_methods: [ "publickey" ] }.compact
|
118
123
|
end
|
119
124
|
|
120
125
|
|
@@ -171,6 +176,3 @@ class Mrsk::Configuration
|
|
171
176
|
raw_config.servers.is_a?(Array) ? [ "web" ] : raw_config.servers.keys.sort
|
172
177
|
end
|
173
178
|
end
|
174
|
-
|
175
|
-
require "mrsk/configuration/role"
|
176
|
-
require "mrsk/configuration/accessory"
|
data/lib/mrsk/version.rb
CHANGED
data/lib/mrsk.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mrsk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-02-
|
11
|
+
date: 2023-02-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '2.8'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: zeitwerk
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.5'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.5'
|
69
83
|
description:
|
70
84
|
email: dhh@hey.com
|
71
85
|
executables:
|
@@ -87,6 +101,7 @@ files:
|
|
87
101
|
- lib/mrsk/cli/registry.rb
|
88
102
|
- lib/mrsk/cli/server.rb
|
89
103
|
- lib/mrsk/cli/templates/deploy.yml
|
104
|
+
- lib/mrsk/cli/templates/template.env
|
90
105
|
- lib/mrsk/cli/traefik.rb
|
91
106
|
- lib/mrsk/commander.rb
|
92
107
|
- lib/mrsk/commands.rb
|
@@ -131,5 +146,5 @@ requirements: []
|
|
131
146
|
rubygems_version: 3.4.6
|
132
147
|
signing_key:
|
133
148
|
specification_version: 4
|
134
|
-
summary: Deploy
|
149
|
+
summary: Deploy web apps in containers to servers running Docker with zero downtime.
|
135
150
|
test_files: []
|