mrsk 0.10.1 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|