mrsk 0.10.1 → 0.12.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 +130 -18
- data/lib/mrsk/cli/app.rb +58 -16
- data/lib/mrsk/cli/base.rb +39 -18
- data/lib/mrsk/cli/build.rb +23 -1
- data/lib/mrsk/cli/healthcheck.rb +3 -34
- data/lib/mrsk/cli/lock.rb +2 -2
- data/lib/mrsk/cli/main.rb +58 -25
- data/lib/mrsk/cli/prune.rb +2 -2
- data/lib/mrsk/cli/server.rb +13 -9
- data/lib/mrsk/cli/traefik.rb +5 -2
- data/lib/mrsk/cli.rb +1 -0
- data/lib/mrsk/commander.rb +24 -3
- data/lib/mrsk/commands/app.rb +25 -12
- data/lib/mrsk/commands/base.rb +3 -1
- data/lib/mrsk/commands/builder/base.rb +10 -3
- data/lib/mrsk/commands/builder.rb +21 -1
- data/lib/mrsk/commands/docker.rb +21 -0
- data/lib/mrsk/commands/healthcheck.rb +3 -2
- data/lib/mrsk/commands/prune.rb +12 -4
- data/lib/mrsk/commands/registry.rb +1 -1
- data/lib/mrsk/commands/traefik.rb +16 -3
- data/lib/mrsk/configuration/boot.rb +20 -0
- data/lib/mrsk/configuration/role.rb +30 -6
- data/lib/mrsk/configuration.rb +7 -1
- data/lib/mrsk/sshkit_with_ext.rb +2 -2
- data/lib/mrsk/utils/healthcheck_poller.rb +39 -0
- data/lib/mrsk/utils/sensitive.rb +19 -0
- data/lib/mrsk/utils.rb +41 -8
- data/lib/mrsk/version.rb +1 -1
- metadata +21 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a09720b016119167213b3c1aab02e56c5e3de0eaa09dc39996d55931048e3e5
|
4
|
+
data.tar.gz: 7b435e7ff711c7267cb3f1771d56791fe76c1fb62950daeeacfe923288c314e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de31f5f7e47e1f93446603e48a9a1760fca96bc41ee6dfec0660030fb0fbcdcb3fb4145d4b81fda9c3f4eef5de0a205f54e67e7bb27c91d7ebd0c93c3f5d0c57
|
7
|
+
data.tar.gz: 48d36ec263b4ccfd3729059eb85f340717b17406f88e8281955e948fcfe9c30ffe081bad01977e6f9836ecd480361cf94f15cdfe79aa7477c18a6fb6ad9b97bb
|
data/README.md
CHANGED
@@ -6,6 +6,8 @@ Watch the screencast: https://www.youtube.com/watch?v=LL1cV2FXZ5I
|
|
6
6
|
|
7
7
|
Join us on Discord: https://discord.gg/YgHVT7GCXS
|
8
8
|
|
9
|
+
Ask questions: https://github.com/mrsked/mrsk/discussions
|
10
|
+
|
9
11
|
## Installation
|
10
12
|
|
11
13
|
If you have a Ruby environment available, you can install MRSK globally with:
|
@@ -14,13 +16,13 @@ If you have a Ruby environment available, you can install MRSK globally with:
|
|
14
16
|
gem install mrsk
|
15
17
|
```
|
16
18
|
|
17
|
-
...otherwise, you can run a dockerized version via an alias (add this to your
|
19
|
+
...otherwise, you can run a dockerized version via an alias (add this to your .bashrc or similar to simplify re-use):
|
18
20
|
|
19
21
|
```sh
|
20
22
|
alias mrsk='docker run --rm -it -v $HOME/.ssh:/root/.ssh -v /var/run/docker.sock:/var/run/docker.sock -v ${PWD}/:/workdir ghcr.io/mrsked/mrsk'
|
21
23
|
```
|
22
24
|
|
23
|
-
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:
|
25
|
+
Then, inside your app directory, run `mrsk init` (or `mrsk init --bundle` within Rails 7+ apps where you want a bin/mrsk binstub). Now edit the new file `config/deploy.yml`. It could look as simple as this:
|
24
26
|
|
25
27
|
```yaml
|
26
28
|
service: hey
|
@@ -191,6 +193,15 @@ ssh:
|
|
191
193
|
user: app
|
192
194
|
```
|
193
195
|
|
196
|
+
If you are using non-root user, you need to bootstrap your servers manually, before using them with MRSK. On Ubuntu, you'd do:
|
197
|
+
|
198
|
+
```bash
|
199
|
+
sudo apt update
|
200
|
+
sudo apt upgrade -y
|
201
|
+
sudo apt install -y docker.io curl git
|
202
|
+
sudo usermod -a -G docker ubuntu
|
203
|
+
```
|
204
|
+
|
194
205
|
### Using a proxy SSH host
|
195
206
|
|
196
207
|
If you need to connect to server through a proxy host, you can use `ssh/proxy`:
|
@@ -207,6 +218,13 @@ ssh:
|
|
207
218
|
proxy: "app@192.168.0.1"
|
208
219
|
```
|
209
220
|
|
221
|
+
Also if you need specific proxy command to connect to the server:
|
222
|
+
|
223
|
+
```yaml
|
224
|
+
ssh:
|
225
|
+
proxy_command: aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p' --region=us-east-1 ## ssh via aws ssm
|
226
|
+
```
|
227
|
+
|
210
228
|
### Using env variables
|
211
229
|
|
212
230
|
You can inject env variables into the app containers using `env`:
|
@@ -288,8 +306,9 @@ You can specialize the default Traefik rules by setting labels on the containers
|
|
288
306
|
|
289
307
|
```yaml
|
290
308
|
labels:
|
291
|
-
traefik.http.routers.hey.rule: Host(`app.hey.com`)
|
309
|
+
traefik.http.routers.hey-web.rule: Host(`app.hey.com`)
|
292
310
|
```
|
311
|
+
Traefik rules are in the "service-role-destination" format. The default role will be `web` if no rule is specified. If the destination is not specified, it is not included. To give an example, the above rule would become "traefik.http.routers.hey-web.rule" if it was for the "staging" destination.
|
293
312
|
|
294
313
|
Note: The backticks are needed to ensure the rule is passed in correctly and not treated as command substitution by Bash!
|
295
314
|
|
@@ -312,6 +331,21 @@ servers:
|
|
312
331
|
my-label: "50"
|
313
332
|
```
|
314
333
|
|
334
|
+
### Using shell expansion
|
335
|
+
|
336
|
+
You can use shell expansion to interpolate values from the host machine into labels and env variables with the `${}` syntax.
|
337
|
+
Anything within the curly braces will be executed on the host machine and the result will be interpolated into the label or env variable.
|
338
|
+
|
339
|
+
```yaml
|
340
|
+
labels:
|
341
|
+
host-machine: "${cat /etc/hostname}"
|
342
|
+
|
343
|
+
env:
|
344
|
+
HOST_DEPLOYMENT_DIR: "${PWD}"
|
345
|
+
```
|
346
|
+
|
347
|
+
Note: Any other occurrence of `$` will be escaped to prevent unwanted shell expansion!
|
348
|
+
|
315
349
|
### Using container options
|
316
350
|
|
317
351
|
You can specialize the options used to start containers using the `options` definitions:
|
@@ -439,9 +473,9 @@ RUN --mount=type=secret,id=GITHUB_TOKEN \
|
|
439
473
|
rm -rf /usr/local/bundle/cache
|
440
474
|
```
|
441
475
|
|
442
|
-
###
|
476
|
+
### Traefik command arguments
|
443
477
|
|
444
|
-
|
478
|
+
Customize the Traefik command line using `args`:
|
445
479
|
|
446
480
|
```yaml
|
447
481
|
traefik:
|
@@ -450,37 +484,70 @@ traefik:
|
|
450
484
|
accesslog.format: json
|
451
485
|
```
|
452
486
|
|
453
|
-
This
|
487
|
+
This starts the Traefik container with `--accesslog=true --accesslog.format=json` arguments.
|
454
488
|
|
455
|
-
### Traefik
|
489
|
+
### Traefik host port binding
|
456
490
|
|
457
|
-
|
491
|
+
Traefik binds to port 80 by default. Specify an alternative port using `host_port`:
|
458
492
|
|
459
493
|
```yaml
|
460
494
|
traefik:
|
461
495
|
host_port: 8080
|
462
496
|
```
|
463
497
|
|
464
|
-
###
|
498
|
+
### Traefik version, upgrades, and custom images
|
465
499
|
|
466
|
-
|
500
|
+
MRSK runs the traefik:v2.9 image to track Traefik 2.9.x releases.
|
501
|
+
|
502
|
+
To pin Traefik to a specific version or an image published to your registry,
|
503
|
+
specify `image`:
|
504
|
+
|
505
|
+
```yaml
|
506
|
+
traefik:
|
507
|
+
image: traefik:v2.10.0-rc1
|
508
|
+
```
|
509
|
+
|
510
|
+
This is useful for downgrading Traefik if there's an unexpected breaking
|
511
|
+
change in a minor version release, upgrading Traefik to test forthcoming
|
512
|
+
releases, or running your own Traefik-derived image.
|
513
|
+
|
514
|
+
MRSK has not been tested for compatibility with Traefik 3 betas. Please do!
|
515
|
+
|
516
|
+
### Traefik container configuration
|
517
|
+
|
518
|
+
Pass additional Docker configuration for the Traefik container using `options`:
|
467
519
|
|
468
520
|
```yaml
|
469
521
|
traefik:
|
470
522
|
options:
|
471
523
|
publish:
|
472
|
-
|
524
|
+
- 8080:8080
|
473
525
|
volumes:
|
474
|
-
|
526
|
+
- /tmp/example.json:/tmp/example.json
|
475
527
|
memory: 512m
|
476
528
|
```
|
477
529
|
|
478
|
-
This
|
530
|
+
This starts the Traefik container with `--volume /tmp/example.json:/tmp/example.json --publish 8080:8080 --memory 512m` arguments to `docker run`.
|
531
|
+
|
532
|
+
### Traefik container labels
|
533
|
+
|
534
|
+
Add labels to Traefik Docker container.
|
479
535
|
|
536
|
+
```yaml
|
537
|
+
traefik:
|
538
|
+
labels:
|
539
|
+
traefik.enable: true
|
540
|
+
traefik.http.routers.dashboard.rule: Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))
|
541
|
+
traefik.http.routers.dashboard.service: api@internal
|
542
|
+
traefik.http.routers.dashboard.middlewares: auth
|
543
|
+
traefik.http.middlewares.auth.basicauth.users: test:$2y$05$H2o72tMaO.TwY1wNQUV1K.fhjRgLHRDWohFvUZOJHBEtUXNKrqUKi # test:password
|
544
|
+
```
|
545
|
+
|
546
|
+
This labels Traefik container with `--label traefik.http.routers.dashboard.middlewares=\"auth\"` and so on.
|
480
547
|
|
481
|
-
###
|
548
|
+
### Traefik alternate entrypoints
|
482
549
|
|
483
|
-
You can configure multiple entrypoints for
|
550
|
+
You can configure multiple entrypoints for Traefik like so:
|
484
551
|
|
485
552
|
```yaml
|
486
553
|
service: myservice
|
@@ -540,7 +607,7 @@ accessories:
|
|
540
607
|
memory: "2GB"
|
541
608
|
redis:
|
542
609
|
image: redis:latest
|
543
|
-
|
610
|
+
roles:
|
544
611
|
- web
|
545
612
|
port: "36379:6379"
|
546
613
|
volumes:
|
@@ -610,18 +677,45 @@ That'll post a line like follows to a preconfigured chatbot in Basecamp:
|
|
610
677
|
[My App] [dhh] Rolled back to version d264c4e92470ad1bd18590f04466787262f605de
|
611
678
|
```
|
612
679
|
|
613
|
-
###
|
680
|
+
### Healthcheck
|
681
|
+
|
682
|
+
MRSK uses Docker healtchecks to check the health of your application during deployment. Traefik uses this same healthcheck status to determine when a container is ready to receive traffic.
|
614
683
|
|
615
|
-
|
684
|
+
The healthcheck defaults to testing the HTTP response to the path `/up` on port 3000, up to 7 times. You can tailor this behaviour with the `healthcheck` setting:
|
616
685
|
|
617
686
|
```yaml
|
618
687
|
healthcheck:
|
619
688
|
path: /healthz
|
620
689
|
port: 4000
|
690
|
+
max_attempts: 7
|
621
691
|
```
|
622
692
|
|
623
693
|
This will ensure your application is configured with a traefik label for the healthcheck against `/healthz` and that the pre-deploy healthcheck that MRSK performs is done against the same path on port 4000.
|
624
694
|
|
695
|
+
You can also specify a custom healthcheck command, which is useful for non-HTTP services:
|
696
|
+
|
697
|
+
```yaml
|
698
|
+
healthcheck:
|
699
|
+
cmd: /bin/check_health
|
700
|
+
```
|
701
|
+
|
702
|
+
The top-level healthcheck configuration applies to all services that use
|
703
|
+
Traefik, by default. You can also specialize the configuration at the role
|
704
|
+
level:
|
705
|
+
|
706
|
+
```yaml
|
707
|
+
servers:
|
708
|
+
job:
|
709
|
+
hosts: ...
|
710
|
+
cmd: bin/jobs
|
711
|
+
healthcheck:
|
712
|
+
cmd: bin/check
|
713
|
+
```
|
714
|
+
|
715
|
+
The healthcheck allows for an optional `max_attempts` setting, which will attempt the healthcheck up to the specified number of times before failing the deploy. This is useful for applications that take a while to start up. The default is 7.
|
716
|
+
|
717
|
+
Note that the HTTP health checks assume that the `curl` command is avilable inside the container. If that's not the case, use the healthcheck's `cmd` option to specify an alternative check that the container supports.
|
718
|
+
|
625
719
|
## Commands
|
626
720
|
|
627
721
|
### Running commands on servers
|
@@ -761,6 +855,24 @@ mrsk lock acquire -m "Doing maintanence"
|
|
761
855
|
mrsk lock release
|
762
856
|
```
|
763
857
|
|
858
|
+
## Rolling deployments
|
859
|
+
|
860
|
+
When deploying to large numbers of hosts, you might prefer not to restart your services on every host at the same time.
|
861
|
+
|
862
|
+
MRSK's default is to boot new containers on all hosts in parallel. But you can control this by configuring `boot/limit` and `boot/wait` as options:
|
863
|
+
|
864
|
+
```yaml
|
865
|
+
service: myservice
|
866
|
+
|
867
|
+
boot:
|
868
|
+
limit: 10 # Can also specify as a percentage of total hosts, such as "25%"
|
869
|
+
wait: 2
|
870
|
+
```
|
871
|
+
|
872
|
+
When `limit` is specified, containers will be booted on, at most, `limit` hosts at once. MRSK will pause for `wait` seconds between batches.
|
873
|
+
|
874
|
+
These settings only apply when booting containers (using `mrsk deploy`, or `mrsk app boot`). For other commands, MRSK continues to run commands in parallel across all hosts.
|
875
|
+
|
764
876
|
## Stage of development
|
765
877
|
|
766
878
|
This is beta software. Commands may still move around. But we're live in production at [37signals](https://37signals.com).
|
data/lib/mrsk/cli/app.rb
CHANGED
@@ -6,27 +6,33 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
|
|
6
6
|
using_version(version_or_latest) do |version|
|
7
7
|
say "Start container with version #{version} using a #{MRSK.config.readiness_delay}s readiness delay (or reboot if already running)...", :magenta
|
8
8
|
|
9
|
-
|
9
|
+
on(MRSK.hosts) do
|
10
|
+
execute *MRSK.auditor.record("Tagging #{MRSK.config.absolute_image} as the latest image"), verbosity: :debug
|
11
|
+
execute *MRSK.app.tag_current_as_latest
|
12
|
+
end
|
10
13
|
|
11
|
-
on(MRSK.hosts) do |host|
|
14
|
+
on(MRSK.hosts, **MRSK.boot_strategy) do |host|
|
12
15
|
roles = MRSK.roles_on(host)
|
13
16
|
|
14
17
|
roles.each do |role|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
old_version = capture_with_info(*MRSK.app(role: role).current_running_version).strip
|
26
|
-
execute *MRSK.app(role: role).run
|
27
|
-
sleep MRSK.config.readiness_delay
|
28
|
-
execute *MRSK.app(role: role).stop(version: old_version), raise_on_non_zero_exit: false if old_version.present?
|
18
|
+
app = MRSK.app(role: role)
|
19
|
+
auditor = MRSK.auditor(role: role)
|
20
|
+
|
21
|
+
execute *auditor.record("Booted app version #{version}"), verbosity: :debug
|
22
|
+
|
23
|
+
if capture_with_info(*app.container_id_for_version(version), raise_on_non_zero_exit: false).present?
|
24
|
+
tmp_version = "#{version}_#{SecureRandom.hex(8)}"
|
25
|
+
info "Renaming container #{version} to #{tmp_version} as already deployed on #{host}"
|
26
|
+
execute *auditor.record("Renaming container #{version} to #{tmp_version}"), verbosity: :debug
|
27
|
+
execute *app.rename_container(version: version, new_version: tmp_version)
|
29
28
|
end
|
29
|
+
|
30
|
+
old_version = capture_with_info(*app.current_running_version, raise_on_non_zero_exit: false).strip
|
31
|
+
execute *app.run
|
32
|
+
|
33
|
+
Mrsk::Utils::HealthcheckPoller.wait_for_healthy(pause_after_ready: true) { capture_with_info(*app.status(version: version)) }
|
34
|
+
|
35
|
+
execute *app.stop(version: old_version), raise_on_non_zero_exit: false if old_version.present?
|
30
36
|
end
|
31
37
|
end
|
32
38
|
end
|
@@ -124,6 +130,31 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
|
|
124
130
|
on(MRSK.hosts) { |host| puts_by_host host, capture_with_info(*MRSK.app.list_containers) }
|
125
131
|
end
|
126
132
|
|
133
|
+
desc "stale_containers", "Detect app stale containers"
|
134
|
+
option :stop, aliases: "-s", type: :boolean, default: false, desc: "Stop the stale containers found"
|
135
|
+
def stale_containers
|
136
|
+
with_lock do
|
137
|
+
stop = options[:stop]
|
138
|
+
|
139
|
+
cli = self
|
140
|
+
|
141
|
+
on(MRSK.hosts) do |host|
|
142
|
+
roles = MRSK.roles_on(host)
|
143
|
+
|
144
|
+
roles.each do |role|
|
145
|
+
cli.send(:stale_versions, host: host, role: role).each do |version|
|
146
|
+
if stop
|
147
|
+
puts_by_host host, "Stopping stale container for role #{role} with version #{version}"
|
148
|
+
execute *MRSK.app(role: role).stop(version: version), raise_on_non_zero_exit: false
|
149
|
+
else
|
150
|
+
puts_by_host host, "Detected stale container for role #{role} with version #{version} (use `mrsk app stale_containers --stop` to stop)"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
127
158
|
desc "images", "Show app images on servers"
|
128
159
|
def images
|
129
160
|
on(MRSK.hosts) { |host| puts_by_host host, capture_with_info(*MRSK.app.list_images) }
|
@@ -240,6 +271,17 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
|
|
240
271
|
version.presence
|
241
272
|
end
|
242
273
|
|
274
|
+
def stale_versions(host:, role:)
|
275
|
+
versions = nil
|
276
|
+
on(host) do
|
277
|
+
versions = \
|
278
|
+
capture_with_info(*MRSK.app(role: role).list_versions, raise_on_non_zero_exit: false)
|
279
|
+
.split("\n")
|
280
|
+
.drop(1)
|
281
|
+
end
|
282
|
+
versions
|
283
|
+
end
|
284
|
+
|
243
285
|
def version_or_latest
|
244
286
|
options[:version] || "latest"
|
245
287
|
end
|
data/lib/mrsk/cli/base.rb
CHANGED
@@ -6,8 +6,6 @@ module Mrsk::Cli
|
|
6
6
|
class Base < Thor
|
7
7
|
include SSHKit::DSL
|
8
8
|
|
9
|
-
class LockError < StandardError; end
|
10
|
-
|
11
9
|
def self.exit_on_failure?() true end
|
12
10
|
|
13
11
|
class_option :verbose, type: :boolean, aliases: "-v", desc: "Detailed logging"
|
@@ -79,32 +77,55 @@ module Mrsk::Cli
|
|
79
77
|
end
|
80
78
|
|
81
79
|
def with_lock
|
82
|
-
|
80
|
+
if MRSK.holding_lock?
|
81
|
+
yield
|
82
|
+
else
|
83
|
+
acquire_lock
|
84
|
+
|
85
|
+
begin
|
86
|
+
yield
|
87
|
+
rescue
|
88
|
+
if MRSK.hold_lock_on_error?
|
89
|
+
error " \e[31mDeploy lock was not released\e[0m"
|
90
|
+
else
|
91
|
+
release_lock
|
92
|
+
end
|
93
|
+
|
94
|
+
raise
|
95
|
+
end
|
83
96
|
|
84
|
-
|
85
|
-
|
86
|
-
release_lock
|
97
|
+
release_lock
|
98
|
+
end
|
87
99
|
end
|
88
100
|
|
89
101
|
def acquire_lock
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
MRSK.lock_count += 1
|
102
|
+
say "Acquiring the deploy lock"
|
103
|
+
on(MRSK.primary_host) { execute *MRSK.lock.acquire("Automatic deploy lock", MRSK.config.version) }
|
104
|
+
|
105
|
+
MRSK.holding_lock = true
|
95
106
|
rescue SSHKit::Runner::ExecuteError => e
|
96
107
|
if e.message =~ /cannot create directory/
|
97
|
-
|
108
|
+
on(MRSK.primary_host) { execute *MRSK.lock.status }
|
109
|
+
raise LockError, "Deploy lock found"
|
110
|
+
else
|
111
|
+
raise e
|
98
112
|
end
|
99
|
-
|
100
|
-
raise LockError, "Deploy lock found"
|
101
113
|
end
|
102
114
|
|
103
115
|
def release_lock
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
116
|
+
say "Releasing the deploy lock"
|
117
|
+
on(MRSK.primary_host) { execute *MRSK.lock.release }
|
118
|
+
|
119
|
+
MRSK.holding_lock = false
|
120
|
+
end
|
121
|
+
|
122
|
+
def hold_lock_on_error
|
123
|
+
if MRSK.hold_lock_on_error?
|
124
|
+
yield
|
125
|
+
else
|
126
|
+
MRSK.hold_lock_on_error = true
|
127
|
+
yield
|
128
|
+
MRSK.hold_lock_on_error = false
|
108
129
|
end
|
109
130
|
end
|
110
131
|
end
|
data/lib/mrsk/cli/build.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
class Mrsk::Cli::Build < Mrsk::Cli::Base
|
2
|
+
class BuildError < StandardError; end
|
3
|
+
|
2
4
|
desc "deliver", "Build app and push app image to registry then pull image on servers"
|
3
5
|
def deliver
|
4
6
|
with_lock do
|
@@ -14,7 +16,9 @@ class Mrsk::Cli::Build < Mrsk::Cli::Base
|
|
14
16
|
|
15
17
|
run_locally do
|
16
18
|
begin
|
17
|
-
|
19
|
+
if cli.verify_local_dependencies
|
20
|
+
MRSK.with_verbosity(:debug) { execute *MRSK.builder.push }
|
21
|
+
end
|
18
22
|
rescue SSHKit::Command::Failed => e
|
19
23
|
if e.message =~ /(no builder)|(no such file or directory)/
|
20
24
|
error "Missing compatible builder, so creating a new one first"
|
@@ -77,4 +81,22 @@ class Mrsk::Cli::Build < Mrsk::Cli::Base
|
|
77
81
|
puts capture(*MRSK.builder.info)
|
78
82
|
end
|
79
83
|
end
|
84
|
+
|
85
|
+
|
86
|
+
desc "", "" # Really a private method, but needed to be invoked from #push
|
87
|
+
def verify_local_dependencies
|
88
|
+
run_locally do
|
89
|
+
begin
|
90
|
+
execute *MRSK.builder.ensure_local_dependencies_installed
|
91
|
+
rescue SSHKit::Command::Failed => e
|
92
|
+
build_error = e.message =~ /command not found/ ?
|
93
|
+
"Docker is not installed locally" :
|
94
|
+
"Docker buildx plugin is not installed locally"
|
95
|
+
|
96
|
+
raise BuildError, build_error
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
true
|
101
|
+
end
|
80
102
|
end
|
data/lib/mrsk/cli/healthcheck.rb
CHANGED
@@ -1,8 +1,4 @@
|
|
1
1
|
class Mrsk::Cli::Healthcheck < Mrsk::Cli::Base
|
2
|
-
MAX_ATTEMPTS = 7
|
3
|
-
|
4
|
-
class HealthcheckError < StandardError; end
|
5
|
-
|
6
2
|
default_command :perform
|
7
3
|
|
8
4
|
desc "perform", "Health check current app version"
|
@@ -10,37 +6,10 @@ class Mrsk::Cli::Healthcheck < Mrsk::Cli::Base
|
|
10
6
|
on(MRSK.primary_host) do
|
11
7
|
begin
|
12
8
|
execute *MRSK.healthcheck.run
|
13
|
-
|
14
|
-
|
15
|
-
attempt = 1
|
16
|
-
|
17
|
-
begin
|
18
|
-
status = capture_with_info(*MRSK.healthcheck.curl)
|
19
|
-
|
20
|
-
if status == "200"
|
21
|
-
info "#{target} succeeded with 200 OK!"
|
22
|
-
else
|
23
|
-
raise HealthcheckError, "#{target} failed with status #{status}"
|
24
|
-
end
|
25
|
-
rescue SSHKit::Command::Failed
|
26
|
-
if attempt <= MAX_ATTEMPTS
|
27
|
-
info "#{target} failed to respond, retrying in #{attempt}s..."
|
28
|
-
sleep attempt
|
29
|
-
attempt += 1
|
30
|
-
|
31
|
-
retry
|
32
|
-
else
|
33
|
-
raise
|
34
|
-
end
|
35
|
-
end
|
36
|
-
rescue SSHKit::Command::Failed, HealthcheckError => e
|
9
|
+
Mrsk::Utils::HealthcheckPoller.wait_for_healthy { capture_with_info(*MRSK.healthcheck.status) }
|
10
|
+
rescue Mrsk::Utils::HealthcheckPoller::HealthcheckError => e
|
37
11
|
error capture_with_info(*MRSK.healthcheck.logs)
|
38
|
-
|
39
|
-
if e.message =~ /curl/
|
40
|
-
raise SSHKit::Command::Failed, "#{target} failed to return 200 OK!"
|
41
|
-
else
|
42
|
-
raise
|
43
|
-
end
|
12
|
+
raise
|
44
13
|
ensure
|
45
14
|
execute *MRSK.healthcheck.stop, raise_on_non_zero_exit: false
|
46
15
|
execute *MRSK.healthcheck.remove, raise_on_non_zero_exit: false
|
data/lib/mrsk/cli/lock.rb
CHANGED
@@ -12,7 +12,7 @@ class Mrsk::Cli::Lock < Mrsk::Cli::Base
|
|
12
12
|
message = options[:message]
|
13
13
|
handle_missing_lock do
|
14
14
|
on(MRSK.primary_host) { execute *MRSK.lock.acquire(message, MRSK.config.version) }
|
15
|
-
say "
|
15
|
+
say "Acquired the deploy lock"
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -20,7 +20,7 @@ class Mrsk::Cli::Lock < Mrsk::Cli::Base
|
|
20
20
|
def release
|
21
21
|
handle_missing_lock do
|
22
22
|
on(MRSK.primary_host) { execute *MRSK.lock.release }
|
23
|
-
say "
|
23
|
+
say "Released the deploy lock"
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|