mrsk 0.0.3 → 0.1.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 +32 -43
- data/bin/mrsk +5 -0
- data/lib/mrsk/cli/app.rb +97 -0
- data/lib/mrsk/cli/base.rb +27 -0
- data/lib/mrsk/cli/build.rb +53 -0
- data/lib/mrsk/cli/main.rb +99 -0
- data/lib/mrsk/cli/prune.rb +19 -0
- data/lib/mrsk/cli/registry.rb +14 -0
- data/lib/mrsk/cli/server.rb +8 -0
- data/lib/mrsk/cli/templates/deploy.yml +17 -0
- data/lib/mrsk/cli/traefik.rb +44 -0
- data/lib/mrsk/cli.rb +9 -0
- data/lib/mrsk/commander.rb +5 -4
- data/lib/mrsk/commands/app.rb +4 -4
- data/lib/mrsk/commands/builder/multiarch/remote.rb +9 -4
- data/lib/mrsk/commands/builder/multiarch.rb +7 -2
- data/lib/mrsk/configuration.rb +3 -1
- data/lib/mrsk/version.rb +1 -1
- data/lib/mrsk.rb +0 -1
- metadata +33 -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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 45be50e3f2f3c5c629b1ec46ee23394b1913c758385ee431d44553506f40cc01
|
4
|
+
data.tar.gz: fe11053be553d9af7d090b03b019dd09d1578bed94050b6be5699f99f6711be8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6eee63c66d3f6585c2ac142d78ffdf952b141073793a8f8dd8d7b1551fbd5a1a98f12c590e83517f8e52e1ac58b07ebd48b55571ebe66c3c8a2ec677c47ef00d
|
7
|
+
data.tar.gz: f46b8fc945be5c43427f7bf2300cbd95e80e30598fd8294e327f83253b25430937d44c255c8edb1d6b0fce613224acb367972bbeef125e7615293c83c23ddb2c
|
data/README.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# MRSK
|
2
2
|
|
3
|
-
MRSK
|
3
|
+
MRSK deploys Rails 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
|
-
|
7
|
+
Install MRSK globally with `gem install mrsk`. Then, inside your app directory, run `mrsk install`. Now edit the new file `config/deploy.yml`. It could look as simple as this:
|
8
8
|
|
9
9
|
```yaml
|
10
10
|
service: hey
|
@@ -13,34 +13,27 @@ servers:
|
|
13
13
|
- 192.168.0.1
|
14
14
|
- 192.168.0.2
|
15
15
|
registry:
|
16
|
-
username:
|
17
|
-
password: <%=
|
18
|
-
```
|
19
|
-
|
20
|
-
Then ensure your encrypted credentials have the registry username + password by editing them with `rails credentials:edit`:
|
21
|
-
|
22
|
-
```
|
23
|
-
registry:
|
24
|
-
username: real-user-name
|
25
|
-
password: real-registry-password-or-token
|
16
|
+
username: registry-user-name
|
17
|
+
password: <%= ENV["MRSK_REGISTRY_PASSWORD"] %>
|
26
18
|
```
|
27
19
|
|
28
20
|
Now you're ready to deploy a multi-arch image to the servers:
|
29
21
|
|
30
22
|
```
|
31
|
-
|
23
|
+
mrsk deploy
|
32
24
|
```
|
33
25
|
|
34
26
|
This will:
|
35
27
|
|
36
|
-
1.
|
37
|
-
2.
|
38
|
-
3.
|
39
|
-
4.
|
40
|
-
5.
|
41
|
-
6.
|
42
|
-
7.
|
43
|
-
8.
|
28
|
+
1. Install Docker on any server that might be missing it (using apt-get)
|
29
|
+
2. Log into the registry both locally and remotely
|
30
|
+
3. Build the image using the standard Dockerfile in the root of the application.
|
31
|
+
4. Push the image to the registry.
|
32
|
+
5. Pull the image from the registry on the servers.
|
33
|
+
6. Ensure Traefik is running and accepting traffic on port 80.
|
34
|
+
7. Stop any containers running a previous versions of the app.
|
35
|
+
8. Start a new container with the version of the app that matches the current git version hash.
|
36
|
+
9. Prune unused images and stopped containers to ensure servers don't fill up.
|
44
37
|
|
45
38
|
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.
|
46
39
|
|
@@ -53,8 +46,8 @@ The default registry for Docker is Docker Hub. If you'd like to use a different
|
|
53
46
|
```yaml
|
54
47
|
registry:
|
55
48
|
server: registry.digitalocean.com
|
56
|
-
username:
|
57
|
-
password: <%=
|
49
|
+
username: registry-user-name
|
50
|
+
password: <%= ENV["MRSK_REGISTRY_PASSWORD"] %>
|
58
51
|
```
|
59
52
|
|
60
53
|
### Using a different SSH user than root
|
@@ -141,7 +134,7 @@ builder:
|
|
141
134
|
|
142
135
|
Note: You must have Docker running on the remote host being used as a builder.
|
143
136
|
|
144
|
-
With that configuration in place, you can setup the local/remote configuration using
|
137
|
+
With that configuration in place, you can setup the local/remote configuration using `mrsk build create`. If you wish to remove the contexts and buildx instances again, you can run `mrsk build remove`. If you had already built using the standard emulation setup, run `mrsk build remove` before doing `mrsk build remote`.
|
145
138
|
|
146
139
|
### Configuring native builder when multi-arch isn't needed
|
147
140
|
|
@@ -156,11 +149,11 @@ builder:
|
|
156
149
|
|
157
150
|
### Remote execution
|
158
151
|
|
159
|
-
If you need to execute commands inside the Rails containers, you can use
|
152
|
+
If you need to execute commands inside the Rails containers, you can use `mrsk app exec`, `mrsk app exec --once`, `mrsk app runner`, and `mrsk app runner --once`. Examples:
|
160
153
|
|
161
154
|
```bash
|
162
155
|
# Runs command on all servers
|
163
|
-
|
156
|
+
mrsk app exec 'ruby -v'
|
164
157
|
App Host: xxx.xxx.xxx.xxx
|
165
158
|
ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e) [x86_64-linux]
|
166
159
|
|
@@ -168,11 +161,11 @@ App Host: xxx.xxx.xxx.xxx
|
|
168
161
|
ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e) [x86_64-linux]
|
169
162
|
|
170
163
|
# Runs command on first server
|
171
|
-
|
164
|
+
mrsk app exec --once 'cat .ruby-version'
|
172
165
|
3.1.3
|
173
166
|
|
174
167
|
# Runs Rails command on all servers
|
175
|
-
|
168
|
+
mrsk app exec 'bin/rails about'
|
176
169
|
App Host: xxx.xxx.xxx.xxx
|
177
170
|
About your application's environment
|
178
171
|
Rails version 7.1.0.alpha
|
@@ -197,19 +190,18 @@ Environment production
|
|
197
190
|
Database adapter sqlite3
|
198
191
|
Database schema version 20221231233303
|
199
192
|
|
200
|
-
# Runs Rails
|
201
|
-
|
202
|
-
|
203
|
-
Current version: 20221231233303
|
193
|
+
# Runs Rails runner on first server
|
194
|
+
mrsk app runner 'puts Rails.application.config.time_zone'
|
195
|
+
UTC
|
204
196
|
```
|
205
197
|
|
206
198
|
### Running a Rails console on the primary host
|
207
199
|
|
208
|
-
If you need to interact with the production console for the app, you can use
|
200
|
+
If you need to interact with the production console for the app, you can use `mrsk app console`, which will start a Rails console session on the primary host. You can start the console on a different host using `mrsk app console --host 192.168.0.2`. Be mindful that this is a live wire! Any changes made to the production database will take effect immeditately.
|
209
201
|
|
210
202
|
### Inspecting
|
211
203
|
|
212
|
-
You can see the state of your servers by running
|
204
|
+
You can see the state of your servers by running `mrsk details`. It'll show something like this:
|
213
205
|
|
214
206
|
```
|
215
207
|
Traefik Host: xxx.xxx.xxx.xxx
|
@@ -229,11 +221,11 @@ CONTAINER ID IMAGE
|
|
229
221
|
1d3c91ed1f55 registry.digitalocean.com/user/app:6ef8a6a84c525b123c5245345a8483f86d05a123 "/rails/bin/docker-e…" 13 minutes ago Up 13 minutes 3000/tcp chat-6ef8a6a84c525b123c5245345a8483f86d05a123
|
230
222
|
```
|
231
223
|
|
232
|
-
You can also see just info for app containers with
|
224
|
+
You can also see just info for app containers with `mrsk app details` or just for Traefik with `mrsk traefik details`.
|
233
225
|
|
234
226
|
### Rollback
|
235
227
|
|
236
|
-
If you've discovered a bad deploy, you can quickly rollback by reactivating the old, paused container image. You can see what old containers are available for rollback by running
|
228
|
+
If you've discovered a bad deploy, you can quickly rollback by reactivating the old, paused container image. You can see what old containers are available for rollback by running `mrsk app containers`. It'll give you a presentation similar to `mrsk app details`, but include all the old containers as well. Showing something like this:
|
237
229
|
|
238
230
|
```
|
239
231
|
App Host: 164.92.105.119
|
@@ -247,20 +239,17 @@ badb1aa51db4 registry.digitalocean.com/user/app:6ef8a6a84c525b123c5245345a8483
|
|
247
239
|
6f170d1172ae registry.digitalocean.com/user/app:e5d9d7c2b898289dfbc5f7f1334140d984eedae4 "/rails/bin/docker-e…" 31 minutes ago Exited (1) 27 minutes ago chat-e5d9d7c2b898289dfbc5f7f1334140d984eedae4
|
248
240
|
```
|
249
241
|
|
250
|
-
From the example above, we can see that `e5d9d7c2b898289dfbc5f7f1334140d984eedae4` was the last version, so it's available as a rollback target. We can perform this rollback by running
|
242
|
+
From the example above, we can see that `e5d9d7c2b898289dfbc5f7f1334140d984eedae4` was the last version, so it's available as a rollback target. We can perform this rollback by running `mrsk rollback e5d9d7c2b898289dfbc5f7f1334140d984eedae4`. That'll stop `6ef8a6a84c525b123c5245345a8483f86d05a123` and then start `e5d9d7c2b898289dfbc5f7f1334140d984eedae4`. Because the old container is still available, this is very quick. Nothing to download from the registry.
|
251
243
|
|
252
|
-
Note that by default old containers are pruned after 3 days when you run
|
244
|
+
Note that by default old containers are pruned after 3 days when you run `mrsk deploy`.
|
253
245
|
|
254
246
|
### Removing
|
255
247
|
|
256
|
-
If you wish to remove the entire application, including Traefik, containers, images, and registry session, you can run
|
248
|
+
If you wish to remove the entire application, including Traefik, containers, images, and registry session, you can run `mrsk remove`. This will leave the servers clean.
|
257
249
|
|
258
250
|
## Stage of development
|
259
251
|
|
260
|
-
This is alpha software. Lots of stuff is missing.
|
261
|
-
|
262
|
-
- Adapterize commands to work with Podman and other container runners
|
263
|
-
- Integrate with cloud CI pipelines
|
252
|
+
This is alpha software. Lots of stuff is missing. Lots of stuff will keep moving around for a while.
|
264
253
|
|
265
254
|
## License
|
266
255
|
|
data/bin/mrsk
ADDED
data/lib/mrsk/cli/app.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require "mrsk/cli/base"
|
2
|
+
|
3
|
+
class Mrsk::Cli::App < Mrsk::Cli::Base
|
4
|
+
desc "boot", "Boot app on servers (or start them if they've already been booted)"
|
5
|
+
def boot
|
6
|
+
MRSK.config.roles.each do |role|
|
7
|
+
on(role.hosts) do |host|
|
8
|
+
begin
|
9
|
+
execute *MRSK.app.run(role: role.name)
|
10
|
+
rescue SSHKit::Command::Failed => e
|
11
|
+
if e.message =~ /already in use/
|
12
|
+
error "Container with same version already deployed on #{host}, starting that instead"
|
13
|
+
execute *MRSK.app.start, host: host
|
14
|
+
else
|
15
|
+
raise
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "start", "Start existing app on servers (use --version=<git-hash> to designate specific version)"
|
23
|
+
option :version, desc: "Defaults to the most recent git-hash in local repository"
|
24
|
+
def start
|
25
|
+
if (version = options[:version]).present?
|
26
|
+
on(MRSK.config.hosts) { execute *MRSK.app.start(version: version) }
|
27
|
+
else
|
28
|
+
on(MRSK.config.hosts) { execute *MRSK.app.start, raise_on_non_zero_exit: false }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "stop", "Stop app on servers"
|
33
|
+
def stop
|
34
|
+
on(MRSK.config.hosts) { execute *MRSK.app.stop, raise_on_non_zero_exit: false }
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "details", "Display details about app containers"
|
38
|
+
def details
|
39
|
+
on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.info, verbosity: Logger::INFO) + "\n\n" }
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "exec [CMD]", "Execute a custom task on servers passed in as CMD='bin/rake some:task'"
|
43
|
+
option :once, type: :boolean, default: false
|
44
|
+
def exec(cmd)
|
45
|
+
if options[:once]
|
46
|
+
on(MRSK.config.primary_host) { puts capture(*MRSK.app.exec(cmd), verbosity: Logger::INFO) }
|
47
|
+
else
|
48
|
+
on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.exec(cmd), verbosity: Logger::INFO) + "\n\n" }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "console", "Start Rails Console on primary host"
|
53
|
+
option :host, desc: "Start console on a different host"
|
54
|
+
def console
|
55
|
+
host = options[:host] || MRSK.config.primary_host
|
56
|
+
|
57
|
+
run_locally do
|
58
|
+
puts "Launching Rails console on #{host}..."
|
59
|
+
exec MRSK.app.console(host: host)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
desc "runner [EXPRESSION]", "Execute Rails runner with given expression"
|
64
|
+
option :once, type: :boolean, default: false, desc:
|
65
|
+
def runner(expression)
|
66
|
+
if options[:once]
|
67
|
+
on(MRSK.config.primary_host) { puts capture(*MRSK.app.exec("bin/rails", "runner", "'#{expression}'"), verbosity: Logger::INFO) }
|
68
|
+
else
|
69
|
+
on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.exec("bin/rails", "runner", "'#{expression}'"), verbosity: Logger::INFO) + "\n\n" }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
desc "containers", "List all the app containers currently on servers"
|
74
|
+
def containers
|
75
|
+
on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.list_containers, verbosity: Logger::INFO) + "\n\n" }
|
76
|
+
end
|
77
|
+
|
78
|
+
desc "logs", "Show last 100 log lines from app on servers"
|
79
|
+
def logs
|
80
|
+
# FIXME: Catch when app containers aren't running
|
81
|
+
on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.logs) + "\n\n" }
|
82
|
+
end
|
83
|
+
|
84
|
+
desc "remove", "Remove app containers and images from servers"
|
85
|
+
option :only, default: "", desc: "Use 'containers' or 'images'"
|
86
|
+
def remove
|
87
|
+
case options[:only]
|
88
|
+
when "containers"
|
89
|
+
on(MRSK.config.hosts) { execute *MRSK.app.remove_containers }
|
90
|
+
when "images"
|
91
|
+
on(MRSK.config.hosts) { execute *MRSK.app.remove_images }
|
92
|
+
else
|
93
|
+
on(MRSK.config.hosts) { execute *MRSK.app.remove_containers }
|
94
|
+
on(MRSK.config.hosts) { execute *MRSK.app.remove_images }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "sshkit"
|
3
|
+
require "sshkit/dsl"
|
4
|
+
|
5
|
+
module Mrsk::Cli
|
6
|
+
class Base < Thor
|
7
|
+
include SSHKit::DSL
|
8
|
+
|
9
|
+
def self.exit_on_failure?() true end
|
10
|
+
|
11
|
+
class_option :verbose, type: :boolean, aliases: "-v", desc: "Detailed logging"
|
12
|
+
|
13
|
+
def initialize(*)
|
14
|
+
super
|
15
|
+
MRSK.verbose = options[:verbose]
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def print_runtime
|
20
|
+
started_at = Time.now
|
21
|
+
yield
|
22
|
+
ensure
|
23
|
+
runtime = Time.now - started_at
|
24
|
+
puts " Finished all in #{sprintf("%.1f seconds", runtime)}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
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
|
+
run_locally do
|
13
|
+
begin
|
14
|
+
debug "Using builder: #{MRSK.builder.name}"
|
15
|
+
info "Building image may take a while (run with --verbose for progress logging)"
|
16
|
+
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
|
+
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.config.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} (#{MRSK.builder.target.class.name})"
|
50
|
+
puts capture(*MRSK.builder.info)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require "mrsk/cli/base"
|
2
|
+
|
3
|
+
require "mrsk/cli/app"
|
4
|
+
require "mrsk/cli/build"
|
5
|
+
require "mrsk/cli/prune"
|
6
|
+
require "mrsk/cli/registry"
|
7
|
+
require "mrsk/cli/server"
|
8
|
+
require "mrsk/cli/traefik"
|
9
|
+
|
10
|
+
class Mrsk::Cli::Main < Mrsk::Cli::Base
|
11
|
+
desc "deploy", "Deploy the app to servers"
|
12
|
+
def deploy
|
13
|
+
print_runtime do
|
14
|
+
invoke "mrsk:cli:server:bootstrap"
|
15
|
+
invoke "mrsk:cli:registry:login"
|
16
|
+
invoke "mrsk:cli:build:deliver"
|
17
|
+
invoke "mrsk:cli:traefik:boot"
|
18
|
+
invoke "mrsk:cli:app:stop"
|
19
|
+
invoke "mrsk:cli:app:boot"
|
20
|
+
invoke "mrsk:cli:prune:all"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "redeploy", "Deploy new version of the app to servers (without bootstrapping servers, starting Traefik, pruning, and registry login)"
|
25
|
+
def redeploy
|
26
|
+
print_runtime do
|
27
|
+
invoke "mrsk:cli:build:deliver"
|
28
|
+
invoke "mrsk:cli:app:stop"
|
29
|
+
invoke "mrsk:cli:app:boot"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "rollback [VERSION]", "Rollback the app to VERSION (that must already be on servers)"
|
34
|
+
def rollback(version)
|
35
|
+
on(MRSK.config.hosts) do
|
36
|
+
execute *MRSK.app.stop, raise_on_non_zero_exit: false
|
37
|
+
execute *MRSK.app.start(version: version)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "details", "Display details about Traefik and app containers"
|
42
|
+
def details
|
43
|
+
invoke "mrsk:cli:traefik:details"
|
44
|
+
invoke "mrsk:cli:app:details"
|
45
|
+
end
|
46
|
+
|
47
|
+
desc "install", "Create config stub in config/deploy.yml and binstub in bin/mrsk"
|
48
|
+
option :skip_binstub, type: :boolean, default: false, desc: "Skip adding MRSK to the Gemfile and creating bin/mrsk binstub"
|
49
|
+
def install
|
50
|
+
require "fileutils"
|
51
|
+
|
52
|
+
if (deploy_file = Pathname.new(File.expand_path("config/deploy.yml"))).exist?
|
53
|
+
puts "Config file already exists in config/deploy.yml (remove first to create a new one)"
|
54
|
+
else
|
55
|
+
FileUtils.cp_r Pathname.new(File.expand_path("templates/deploy.yml", __dir__)), deploy_file
|
56
|
+
puts "Created configuration file in config/deploy.yml"
|
57
|
+
end
|
58
|
+
|
59
|
+
unless options[:skip_binstub]
|
60
|
+
if (binstub = Pathname.new(File.expand_path("bin/mrsk"))).exist?
|
61
|
+
puts "Binstub already exists in bin/mrsk (remove first to create a new one)"
|
62
|
+
else
|
63
|
+
`bundle add mrsk`
|
64
|
+
`bundle binstubs mrsk`
|
65
|
+
puts "Created binstub file in bin/mrsk"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
desc "remove", "Remove Traefik, app, and registry session from servers"
|
71
|
+
def remove
|
72
|
+
invoke "mrsk:cli:traefik:remove"
|
73
|
+
invoke "mrsk:cli:app:remove"
|
74
|
+
invoke "mrsk:cli:registry:logout"
|
75
|
+
end
|
76
|
+
|
77
|
+
desc "version", "Display the MRSK version"
|
78
|
+
def version
|
79
|
+
puts Mrsk::VERSION
|
80
|
+
end
|
81
|
+
|
82
|
+
desc "app", "Manage the application"
|
83
|
+
subcommand "app", Mrsk::Cli::App
|
84
|
+
|
85
|
+
desc "build", "Build the application image"
|
86
|
+
subcommand "build", Mrsk::Cli::Build
|
87
|
+
|
88
|
+
desc "prune", "Prune old application images and containers"
|
89
|
+
subcommand "prune", Mrsk::Cli::Prune
|
90
|
+
|
91
|
+
desc "registry", "Login and out of the image registry"
|
92
|
+
subcommand "registry", Mrsk::Cli::Registry
|
93
|
+
|
94
|
+
desc "server", "Bootstrap servers with Docker"
|
95
|
+
subcommand "server", Mrsk::Cli::Server
|
96
|
+
|
97
|
+
desc "traefik", "Manage the Traefik load balancer"
|
98
|
+
subcommand "traefik", Mrsk::Cli::Traefik
|
99
|
+
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.config.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.config.hosts) { execute *MRSK.prune.containers }
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,14 @@
|
|
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.config.hosts) { execute *MRSK.registry.login }
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "logout", "Logout of the registry remotely"
|
11
|
+
def logout
|
12
|
+
on(MRSK.config.hosts) { execute *MRSK.registry.logout }
|
13
|
+
end
|
14
|
+
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,44 @@
|
|
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.config.role(:web).hosts) { execute *MRSK.traefik.run, raise_on_non_zero_exit: false }
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "start", "Start existing Traefik on servers"
|
10
|
+
def start
|
11
|
+
on(MRSK.config.role(:web).hosts) { execute *MRSK.traefik.start, raise_on_non_zero_exit: false }
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "stop", "Stop Traefik on servers"
|
15
|
+
def stop
|
16
|
+
on(MRSK.config.role(:web).hosts) { execute *MRSK.traefik.stop, raise_on_non_zero_exit: false }
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "restart", "Restart Traefik on servers"
|
20
|
+
def restart
|
21
|
+
invoke :stop
|
22
|
+
invoke :start
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "details", "Display details about Traefik containers from servers"
|
26
|
+
def details
|
27
|
+
on(MRSK.config.role(:web).hosts) { |host| puts "Traefik Host: #{host}\n" + capture(*MRSK.traefik.info, verbosity: Logger::INFO) + "\n\n" }
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "logs", "Show last 100 log lines from Traefik on servers"
|
31
|
+
def logs
|
32
|
+
on(MRSK.config.hosts) { |host| puts "Traefik Host: #{host}\n" + capture(*MRSK.traefik.logs) + "\n\n" }
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "remove", "Remove Traefik container and image from servers"
|
36
|
+
def remove
|
37
|
+
invoke :stop
|
38
|
+
|
39
|
+
on(MRSK.config.role(:web).hosts) do
|
40
|
+
execute *MRSK.traefik.remove_container
|
41
|
+
execute *MRSK.traefik.remove_image
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/mrsk/cli.rb
ADDED
data/lib/mrsk/commander.rb
CHANGED
@@ -6,14 +6,15 @@ require "mrsk/commands/traefik"
|
|
6
6
|
require "mrsk/commands/registry"
|
7
7
|
|
8
8
|
class Mrsk::Commander
|
9
|
-
attr_reader :
|
9
|
+
attr_reader :config
|
10
|
+
attr_accessor :verbose
|
10
11
|
|
11
|
-
def initialize(config_file
|
12
|
-
@config_file
|
12
|
+
def initialize(config_file:)
|
13
|
+
@config_file = config_file
|
13
14
|
end
|
14
15
|
|
15
16
|
def config
|
16
|
-
@config ||= Mrsk::Configuration.load_file(config_file).tap { |config| setup_with(config) }
|
17
|
+
@config ||= Mrsk::Configuration.load_file(@config_file).tap { |config| setup_with(config) }
|
17
18
|
end
|
18
19
|
|
19
20
|
|
data/lib/mrsk/commands/app.rb
CHANGED
@@ -15,8 +15,8 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
|
15
15
|
role.cmd
|
16
16
|
end
|
17
17
|
|
18
|
-
def start
|
19
|
-
docker :start, config.
|
18
|
+
def start(version: config.version)
|
19
|
+
docker :start, "#{config.service}-#{version}"
|
20
20
|
end
|
21
21
|
|
22
22
|
def stop
|
@@ -40,8 +40,8 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
|
40
40
|
*command
|
41
41
|
end
|
42
42
|
|
43
|
-
def console
|
44
|
-
"ssh -t #{config.ssh_user}@#{
|
43
|
+
def console(host: config.primary_host)
|
44
|
+
"ssh -t #{config.ssh_user}@#{host} '#{exec("bin/rails", "c", interactive: true).join(" ")}'"
|
45
45
|
end
|
46
46
|
|
47
47
|
def list_containers
|
@@ -16,11 +16,11 @@ class Mrsk::Commands::Builder::Multiarch::Remote < Mrsk::Commands::Builder::Mult
|
|
16
16
|
|
17
17
|
private
|
18
18
|
def create_local_buildx
|
19
|
-
docker :buildx, :create, "--use", "--name",
|
19
|
+
docker :buildx, :create, "--use", "--name", builder_name, builder_name_with_arch(local["arch"]), "--platform", "linux/#{local["arch"]}"
|
20
20
|
end
|
21
21
|
|
22
22
|
def append_remote_buildx
|
23
|
-
docker :buildx, :create, "--append", "--name",
|
23
|
+
docker :buildx, :create, "--append", "--name", builder_name, builder_name_with_arch(remote["arch"]), "--platform", "linux/#{remote["arch"]}"
|
24
24
|
end
|
25
25
|
|
26
26
|
def create_contexts
|
@@ -30,7 +30,7 @@ class Mrsk::Commands::Builder::Multiarch::Remote < Mrsk::Commands::Builder::Mult
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def create_context(arch, host)
|
33
|
-
docker :context, :create,
|
33
|
+
docker :context, :create, builder_name_with_arch(arch), "--description", "'#{builder_name} #{arch} native host'", "--docker", "'host=#{host}'"
|
34
34
|
end
|
35
35
|
|
36
36
|
def remove_contexts
|
@@ -40,7 +40,7 @@ class Mrsk::Commands::Builder::Multiarch::Remote < Mrsk::Commands::Builder::Mult
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def remove_context(arch)
|
43
|
-
docker :context, :rm,
|
43
|
+
docker :context, :rm, builder_name_with_arch(arch)
|
44
44
|
end
|
45
45
|
|
46
46
|
def local
|
@@ -50,4 +50,9 @@ class Mrsk::Commands::Builder::Multiarch::Remote < Mrsk::Commands::Builder::Mult
|
|
50
50
|
def remote
|
51
51
|
config.builder["remote"]
|
52
52
|
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def builder_name_with_arch(arch)
|
56
|
+
"#{builder_name}-#{arch}"
|
57
|
+
end
|
53
58
|
end
|
@@ -2,11 +2,11 @@ require "mrsk/commands/base"
|
|
2
2
|
|
3
3
|
class Mrsk::Commands::Builder::Multiarch < Mrsk::Commands::Base
|
4
4
|
def create
|
5
|
-
docker :buildx, :create, "--use", "--name",
|
5
|
+
docker :buildx, :create, "--use", "--name", builder_name
|
6
6
|
end
|
7
7
|
|
8
8
|
def remove
|
9
|
-
docker :buildx, :rm,
|
9
|
+
docker :buildx, :rm, builder_name
|
10
10
|
end
|
11
11
|
|
12
12
|
def push
|
@@ -22,4 +22,9 @@ class Mrsk::Commands::Builder::Multiarch < Mrsk::Commands::Base
|
|
22
22
|
docker(:context, :ls),
|
23
23
|
docker(:buildx, :ls)
|
24
24
|
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def builder_name
|
28
|
+
"mrsk-#{config.service}"
|
29
|
+
end
|
25
30
|
end
|
data/lib/mrsk/configuration.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require "active_support/ordered_options"
|
2
2
|
require "active_support/core_ext/string/inquiry"
|
3
|
+
require "active_support/core_ext/module/delegation"
|
4
|
+
require "pathname"
|
3
5
|
require "erb"
|
4
6
|
|
5
7
|
class Mrsk::Configuration
|
@@ -91,7 +93,7 @@ class Mrsk::Configuration
|
|
91
93
|
end
|
92
94
|
|
93
95
|
def master_key
|
94
|
-
ENV["RAILS_MASTER_KEY"] || File.read(
|
96
|
+
ENV["RAILS_MASTER_KEY"] || File.read(Pathname.new(File.expand_path("config/master.key")))
|
95
97
|
end
|
96
98
|
|
97
99
|
|
data/lib/mrsk/version.rb
CHANGED
data/lib/mrsk.rb
CHANGED
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mrsk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
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-01-
|
11
|
+
date: 2023-01-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: activesupport
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 7.0
|
19
|
+
version: '7.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 7.0
|
26
|
+
version: '7.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: sshkit
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,15 +38,41 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.21'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: thor
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.2'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.2'
|
41
55
|
description:
|
42
56
|
email: dhh@hey.com
|
43
|
-
executables:
|
57
|
+
executables:
|
58
|
+
- mrsk
|
44
59
|
extensions: []
|
45
60
|
extra_rdoc_files: []
|
46
61
|
files:
|
47
62
|
- MIT-LICENSE
|
48
63
|
- README.md
|
64
|
+
- bin/mrsk
|
49
65
|
- lib/mrsk.rb
|
66
|
+
- lib/mrsk/cli.rb
|
67
|
+
- lib/mrsk/cli/app.rb
|
68
|
+
- lib/mrsk/cli/base.rb
|
69
|
+
- lib/mrsk/cli/build.rb
|
70
|
+
- lib/mrsk/cli/main.rb
|
71
|
+
- lib/mrsk/cli/prune.rb
|
72
|
+
- lib/mrsk/cli/registry.rb
|
73
|
+
- lib/mrsk/cli/server.rb
|
74
|
+
- lib/mrsk/cli/templates/deploy.yml
|
75
|
+
- lib/mrsk/cli/traefik.rb
|
50
76
|
- lib/mrsk/commander.rb
|
51
77
|
- lib/mrsk/commands.rb
|
52
78
|
- lib/mrsk/commands/app.rb
|
@@ -60,18 +86,7 @@ files:
|
|
60
86
|
- lib/mrsk/commands/traefik.rb
|
61
87
|
- lib/mrsk/configuration.rb
|
62
88
|
- lib/mrsk/configuration/role.rb
|
63
|
-
- lib/mrsk/engine.rb
|
64
89
|
- lib/mrsk/version.rb
|
65
|
-
- lib/tasks/mrsk/app.rake
|
66
|
-
- lib/tasks/mrsk/build.rake
|
67
|
-
- lib/tasks/mrsk/mrsk.rake
|
68
|
-
- lib/tasks/mrsk/prune.rake
|
69
|
-
- lib/tasks/mrsk/registry.rake
|
70
|
-
- lib/tasks/mrsk/server.rake
|
71
|
-
- lib/tasks/mrsk/setup.rb
|
72
|
-
- lib/tasks/mrsk/templates/deploy.yml
|
73
|
-
- lib/tasks/mrsk/templates/mrsk
|
74
|
-
- lib/tasks/mrsk/traefik.rake
|
75
90
|
homepage: https://github.com/rails/mrsk
|
76
91
|
licenses:
|
77
92
|
- MIT
|
@@ -94,5 +109,5 @@ requirements: []
|
|
94
109
|
rubygems_version: 3.4.1
|
95
110
|
signing_key:
|
96
111
|
specification_version: 4
|
97
|
-
summary: Deploy
|
112
|
+
summary: Deploy Rails apps in containers to servers running Docker with zero downtime.
|
98
113
|
test_files: []
|
data/lib/mrsk/engine.rb
DELETED
data/lib/tasks/mrsk/app.rake
DELETED
@@ -1,97 +0,0 @@
|
|
1
|
-
require_relative "setup"
|
2
|
-
|
3
|
-
namespace :mrsk do
|
4
|
-
namespace :app do
|
5
|
-
desc "Run app on servers (or start them if they've already been run)"
|
6
|
-
task :run do
|
7
|
-
MRSK.config.roles.each do |role|
|
8
|
-
on(role.hosts) do |host|
|
9
|
-
begin
|
10
|
-
execute *MRSK.app.run(role: role.name)
|
11
|
-
rescue SSHKit::Command::Failed => e
|
12
|
-
if e.message =~ /already in use/
|
13
|
-
error "Container with same version already deployed on #{host}, starting that instead"
|
14
|
-
execute *MRSK.app.start, host: host
|
15
|
-
else
|
16
|
-
raise
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
desc "Start existing app on servers (use VERSION=<git-hash> to designate which version)"
|
24
|
-
task :start do
|
25
|
-
on(MRSK.config.hosts) { execute *MRSK.app.start, raise_on_non_zero_exit: false }
|
26
|
-
end
|
27
|
-
|
28
|
-
desc "Stop app on servers"
|
29
|
-
task :stop do
|
30
|
-
on(MRSK.config.hosts) { execute *MRSK.app.stop, raise_on_non_zero_exit: false }
|
31
|
-
end
|
32
|
-
|
33
|
-
desc "Start app on servers (use VERSION=<git-hash> to designate which version)"
|
34
|
-
task restart: %i[ stop start ]
|
35
|
-
|
36
|
-
desc "Display information about app containers"
|
37
|
-
task :info do
|
38
|
-
on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.info) + "\n\n" }
|
39
|
-
end
|
40
|
-
|
41
|
-
desc "Execute a custom task on servers passed in as CMD='bin/rake some:task'"
|
42
|
-
task :exec do
|
43
|
-
on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.exec(ENV["CMD"])) + "\n\n" }
|
44
|
-
end
|
45
|
-
|
46
|
-
desc "Start Rails Console on primary host"
|
47
|
-
task :console do
|
48
|
-
puts "Launching Rails console on #{MRSK.config.primary_host}..."
|
49
|
-
exec app.console
|
50
|
-
end
|
51
|
-
|
52
|
-
namespace :exec do
|
53
|
-
desc "Execute Rails command on servers, like CMD='runner \"puts %(Hello World)\""
|
54
|
-
task :rails do
|
55
|
-
on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.exec("bin/rails", ENV["CMD"])) + "\n\n" }
|
56
|
-
end
|
57
|
-
|
58
|
-
desc "Execute a custom task on the first defined server"
|
59
|
-
task :once do
|
60
|
-
on(MRSK.config.primary_host) { puts capture(*MRSK.app.exec(ENV["CMD"])) }
|
61
|
-
end
|
62
|
-
|
63
|
-
namespace :once do
|
64
|
-
desc "Execute Rails command on the first defined server, like CMD='runner \"puts %(Hello World)\""
|
65
|
-
task :rails do
|
66
|
-
on(MRSK.config.primary_host) { puts capture(*MRSK.app.exec("bin/rails", ENV["CMD"])) }
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
desc "List all the app containers currently on servers"
|
72
|
-
task :containers do
|
73
|
-
on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.list_containers) + "\n\n" }
|
74
|
-
end
|
75
|
-
|
76
|
-
desc "Show last 100 log lines from app on servers"
|
77
|
-
task :logs do
|
78
|
-
# FIXME: Catch when app containers aren't running
|
79
|
-
on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.logs) + "\n\n" }
|
80
|
-
end
|
81
|
-
|
82
|
-
desc "Remove app containers and images from servers"
|
83
|
-
task remove: %w[ remove:containers remove:images ]
|
84
|
-
|
85
|
-
namespace :remove do
|
86
|
-
desc "Remove app containers from servers"
|
87
|
-
task :containers do
|
88
|
-
on(MRSK.config.hosts) { execute *MRSK.app.remove_containers }
|
89
|
-
end
|
90
|
-
|
91
|
-
desc "Remove app images from servers"
|
92
|
-
task :images do
|
93
|
-
on(MRSK.config.hosts) { execute *MRSK.app.remove_images }
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
data/lib/tasks/mrsk/build.rake
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
require_relative "setup"
|
2
|
-
|
3
|
-
namespace :mrsk do
|
4
|
-
namespace :build do
|
5
|
-
desc "Deliver a newly built app image to servers"
|
6
|
-
task deliver: %i[ push pull ]
|
7
|
-
|
8
|
-
desc "Build locally and push app image to registry"
|
9
|
-
task :push do
|
10
|
-
run_locally do
|
11
|
-
begin
|
12
|
-
debug "Using builder: #{MRSK.builder.name}"
|
13
|
-
info "Building image may take a while (run with VERBOSE=1 for progress logging)"
|
14
|
-
execute *MRSK.builder.push
|
15
|
-
rescue SSHKit::Command::Failed => e
|
16
|
-
error "Missing compatible builder, so creating a new one first"
|
17
|
-
execute *MRSK.builder.create
|
18
|
-
execute *MRSK.builder.push
|
19
|
-
end
|
20
|
-
end unless ENV["VERSION"]
|
21
|
-
end
|
22
|
-
|
23
|
-
desc "Pull app image from the registry onto servers"
|
24
|
-
task :pull do
|
25
|
-
on(MRSK.config.hosts) { execute *MRSK.builder.pull }
|
26
|
-
end
|
27
|
-
|
28
|
-
desc "Create a local build setup"
|
29
|
-
task :create do
|
30
|
-
run_locally do
|
31
|
-
debug "Using builder: #{MRSK.builder.name}"
|
32
|
-
execute *MRSK.builder.create
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
desc "Remove local build setup"
|
37
|
-
task :remove do
|
38
|
-
run_locally do
|
39
|
-
debug "Using builder: #{MRSK.builder.name}"
|
40
|
-
execute *MRSK.builder.remove
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
desc "Show the name of the configured builder"
|
45
|
-
task :info do
|
46
|
-
run_locally do
|
47
|
-
puts "Builder: #{MRSK.builder.name} (#{MRSK.builder.target.class.name})"
|
48
|
-
puts capture(*MRSK.builder.info)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
data/lib/tasks/mrsk/mrsk.rake
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
require_relative "setup"
|
2
|
-
|
3
|
-
namespace :mrsk do
|
4
|
-
desc "Deploy app for the first time to a fresh server"
|
5
|
-
task fresh: %w[ server:bootstrap registry:login build:deliver traefik:run app:stop app:run ]
|
6
|
-
|
7
|
-
desc "Push the latest version of the app, ensure Traefik is running, then restart app"
|
8
|
-
task deploy: %w[ registry:login build:deliver traefik:run app:stop app:run prune ]
|
9
|
-
|
10
|
-
desc "Rollback to VERSION=x that was already run as a container on servers"
|
11
|
-
task rollback: %w[ app:restart ]
|
12
|
-
|
13
|
-
desc "Display information about Traefik and app containers"
|
14
|
-
task info: %w[ traefik:info app:info ]
|
15
|
-
|
16
|
-
desc "Create config stub in config/deploy.yml"
|
17
|
-
task :init do
|
18
|
-
require "fileutils"
|
19
|
-
|
20
|
-
if (deploy_file = Rails.root.join("config/deploy.yml")).exist?
|
21
|
-
puts "Config file already exists in config/deploy.yml (remove first to create a new one)"
|
22
|
-
else
|
23
|
-
FileUtils.cp_r Pathname.new(File.expand_path("templates/deploy.yml", __dir__)), deploy_file
|
24
|
-
puts "Created configuration file in config/deploy.yml"
|
25
|
-
end
|
26
|
-
|
27
|
-
if (binstub = Rails.root.join("bin/mrsk")).exist?
|
28
|
-
puts "Binstub already exists in bin/mrsk (remove first to create a new one)"
|
29
|
-
else
|
30
|
-
FileUtils.cp_r Pathname.new(File.expand_path("templates/mrsk", __dir__)), binstub
|
31
|
-
puts "Created binstub file in bin/mrsk"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
desc "Remove Traefik, app, and registry session from servers"
|
36
|
-
task remove: %w[ traefik:remove app:remove registry:logout ]
|
37
|
-
end
|
data/lib/tasks/mrsk/prune.rake
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
require_relative "setup"
|
2
|
-
|
3
|
-
namespace :mrsk do
|
4
|
-
desc "Prune unused images and stopped containers"
|
5
|
-
task prune: %w[ prune:containers prune:images ]
|
6
|
-
|
7
|
-
namespace :prune do
|
8
|
-
desc "Prune unused images older than 30 days"
|
9
|
-
task :images do
|
10
|
-
on(MRSK.config.hosts) { MRSK.verbosity(:debug) { execute *MRSK.prune.images } }
|
11
|
-
end
|
12
|
-
|
13
|
-
desc "Prune stopped containers for the service older than 3 days"
|
14
|
-
task :containers do
|
15
|
-
on(MRSK.config.hosts) { MRSK.verbosity(:debug) { execute *MRSK.prune.containers } }
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
require_relative "setup"
|
2
|
-
|
3
|
-
namespace :mrsk do
|
4
|
-
namespace :registry do
|
5
|
-
desc "Login to the registry locally and remotely"
|
6
|
-
task :login do
|
7
|
-
run_locally { execute *MRSK.registry.login }
|
8
|
-
on(MRSK.config.hosts) { execute *MRSK.registry.login }
|
9
|
-
end
|
10
|
-
|
11
|
-
desc "Logout of the registry remotely"
|
12
|
-
task :logout do
|
13
|
-
on(MRSK.config.hosts) { execute *MRSK.registry.logout }
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
data/lib/tasks/mrsk/server.rake
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
require_relative "setup"
|
2
|
-
|
3
|
-
namespace :mrsk do
|
4
|
-
namespace :server do
|
5
|
-
desc "Setup Docker on the remote servers"
|
6
|
-
task :bootstrap do
|
7
|
-
# FIXME: Detect when apt-get is not available and use the appropriate alternative
|
8
|
-
on(MRSK.config.hosts) { execute "apt-get install docker.io -y" }
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
data/lib/tasks/mrsk/setup.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
# Name of your application will be used for 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
|
-
# All the servers targeted for deploy. You can reference a single server for a command by using SERVERS=192.168.0.1
|
9
|
-
servers:
|
10
|
-
- 192.168.0.1
|
11
|
-
|
12
|
-
# The following envs are made available to the container when started
|
13
|
-
env:
|
14
|
-
# Remember never to put passwords or tokens directly into this file, use encrypted credentials
|
15
|
-
# REDIS_URL: redis://x/y
|
16
|
-
|
17
|
-
# Where your images will be hosted
|
18
|
-
registry:
|
19
|
-
# Specify the registry server, if you're not using Docker Hub
|
20
|
-
# server: registry.digitalocean.com / ghcr.io / ...
|
21
|
-
|
22
|
-
# Set credentials with bin/rails credentials:edit
|
23
|
-
username: my-user
|
24
|
-
password: my-password-should-go-in-credentials
|
data/lib/tasks/mrsk/traefik.rake
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
require_relative "setup"
|
2
|
-
|
3
|
-
namespace :mrsk do
|
4
|
-
namespace :traefik do
|
5
|
-
desc "Run Traefik on servers"
|
6
|
-
task :run do
|
7
|
-
on(MRSK.config.role(:web).hosts) { execute *MRSK.traefik.run, raise_on_non_zero_exit: false }
|
8
|
-
end
|
9
|
-
|
10
|
-
desc "Start existing Traefik on servers"
|
11
|
-
task :start do
|
12
|
-
on(MRSK.config.role(:web).hosts) { execute *MRSK.traefik.start, raise_on_non_zero_exit: false }
|
13
|
-
end
|
14
|
-
|
15
|
-
desc "Stop Traefik on servers"
|
16
|
-
task :stop do
|
17
|
-
on(MRSK.config.role(:web).hosts) { execute *MRSK.traefik.stop, raise_on_non_zero_exit: false }
|
18
|
-
end
|
19
|
-
|
20
|
-
desc "Restart Traefik on servers"
|
21
|
-
task restart: %i[ stop start ]
|
22
|
-
|
23
|
-
desc "Display information about Traefik containers from servers"
|
24
|
-
task :info do
|
25
|
-
on(MRSK.config.role(:web).hosts) { |host| puts "Traefik Host: #{host}\n" + capture(*MRSK.traefik.info) + "\n\n" }
|
26
|
-
end
|
27
|
-
|
28
|
-
desc "Show last 100 log lines from Traefik on servers"
|
29
|
-
task :logs do
|
30
|
-
on(MRSK.config.hosts) { |host| puts "Traefik Host: #{host}\n" + capture(*MRSK.traefik.logs) + "\n\n" }
|
31
|
-
end
|
32
|
-
|
33
|
-
desc "Remove Traefik container and image from servers"
|
34
|
-
task remove: %i[ stop ] do
|
35
|
-
on(MRSK.config.role(:web).hosts) do
|
36
|
-
execute *MRSK.traefik.remove_container
|
37
|
-
execute *MRSK.traefik.remove_image
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|