centurion 1.8.10 → 1.9.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/CONTRIBUTORS.md +1 -0
- data/README.md +60 -22
- data/centurion.gemspec +2 -0
- data/lib/centurion/deploy_dsl.rb +19 -9
- data/lib/centurion/docker_server.rb +19 -9
- data/lib/centurion/docker_via_api.rb +60 -33
- data/lib/centurion/docker_via_cli.rb +42 -13
- data/lib/centurion/service.rb +10 -1
- data/lib/centurion/ssh.rb +40 -0
- data/lib/centurion/version.rb +1 -1
- data/spec/deploy_dsl_spec.rb +15 -0
- data/spec/docker_via_api_spec.rb +92 -167
- data/spec/docker_via_cli_spec.rb +57 -39
- data/spec/service_spec.rb +5 -1
- data/spec/spec_helper.rb +13 -0
- metadata +52 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43be6c7bcc352c334aa0e84044443a9f4c6f055a
|
4
|
+
data.tar.gz: 49f52dfe1bc7dc4dfa5e200650f2b786b7c2bdbf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ce70d7443f88d79e17a8e0ce9890ad7104cbf89061cee1f957f84c8016b31ced9712fc4e357127e14e945c9d13df2e871fa57cc4a87a41ff4eda0481f3e70eb
|
7
|
+
data.tar.gz: 362f4d002b00c232d32731fbbfcf5ca069bdd3c8a9902e5ba8f2b28715d6e5cb3f0198974a46fded276f30b642545c6620f380b3181e0ed311ba049af24c4be9
|
data/CONTRIBUTORS.md
CHANGED
data/README.md
CHANGED
@@ -25,9 +25,6 @@ Commercial Docker Registry Providers:
|
|
25
25
|
Open-source:
|
26
26
|
- The [Docker Distribution](https://github.com/docker/distribution) project,
|
27
27
|
built and maintained by Docker. You host this yourself.
|
28
|
-
- (*NEW!*) [Dogestry](https://github.com/dogestry/dogestry) is an
|
29
|
-
s3-backed Docker registry alternative that removes the requirement to set up
|
30
|
-
a centralized registry service or host anything yourself.
|
31
28
|
|
32
29
|
Status
|
33
30
|
------
|
@@ -292,6 +289,25 @@ drop_capability 'SOME_CAPABILITY'
|
|
292
289
|
For more information on which kernel capabilities may be specified, see the
|
293
290
|
[Docker docs](https://docs.docker.com/reference/run/#runtime-privilege-linux-capabilities-and-lxc-configuration).
|
294
291
|
|
292
|
+
### Setting the security options
|
293
|
+
|
294
|
+
Some Docker platforms support container security overlays called `seccomp`.
|
295
|
+
During container creation, you may specify security options to control the
|
296
|
+
seccomp permissions.
|
297
|
+
|
298
|
+
To set a seccomp path:
|
299
|
+
```ruby
|
300
|
+
add_security_opt 'seccomp=/path/to/seccomp/profile.json'
|
301
|
+
```
|
302
|
+
|
303
|
+
Or, to unblock all syscalls in a container:
|
304
|
+
|
305
|
+
```ruby
|
306
|
+
add_security_opt 'seccomp=unconfined'
|
307
|
+
```
|
308
|
+
|
309
|
+
For more information on this argument, see the [Docker docs](https://docs.docker.com/engine/security/seccomp/).
|
310
|
+
|
295
311
|
### Interpolation
|
296
312
|
|
297
313
|
Currently there a couple of special strings for interpolation that can be added
|
@@ -336,13 +352,34 @@ You have to set the following keys:
|
|
336
352
|
|
337
353
|
Modify the paths as appropriate for your cert, ca, and key files.
|
338
354
|
|
355
|
+
### Use SSH to connect *beta*
|
356
|
+
|
357
|
+
If your Docker server does not expose its HTTP service over TCP, you can
|
358
|
+
instead talk to it via SSH.
|
359
|
+
|
360
|
+
This functions by creating a local Unix socket that forwards to the remote
|
361
|
+
Docker Unix socket, so it requires that the user you connect as has access to
|
362
|
+
the Docker socket without any `sudo`. Currently it also assumes that you
|
363
|
+
authenticate via public key, so be sure that you have `ssh-add`ed your key to
|
364
|
+
your SSH agent if it has a passcode.
|
365
|
+
|
366
|
+
You can configure it with a few options:
|
367
|
+
|
368
|
+
```ruby
|
369
|
+
task :common do
|
370
|
+
set :ssh, true # enable ssh connections
|
371
|
+
set :ssh_user, "myuser" # if you want to specify the user to connect as, otherwise your current user
|
372
|
+
set :ssh_log_level, Logger::DEBUG # passed on to net/ssh, can be noisy; defaults to Logger::WARN
|
373
|
+
end
|
374
|
+
```
|
375
|
+
|
339
376
|
Deploying
|
340
377
|
---------
|
341
378
|
|
342
379
|
Centurion supports a number of tasks out of the box that make working with
|
343
380
|
distributed containers easy. Here are some examples:
|
344
381
|
|
345
|
-
###Do a rolling deployment to a fleet of Docker servers
|
382
|
+
### Do a rolling deployment to a fleet of Docker servers
|
346
383
|
|
347
384
|
A rolling deployment will stop and start each container one at a time to make
|
348
385
|
sure that the application stays available from the viewpoint of the load
|
@@ -352,9 +389,9 @@ the root path of the application. The healthcheck endpoint is configurable by ad
|
|
352
389
|
`set(:status_endpoint, '/somewhere/else')` in your config. The status endpoint
|
353
390
|
must respond with a valid response in the 200 status range.
|
354
391
|
|
355
|
-
|
392
|
+
```bash
|
356
393
|
$ bundle exec centurion -p radio-radio -e staging -a rolling_deploy
|
357
|
-
|
394
|
+
```
|
358
395
|
|
359
396
|
**Custom Health Check**:
|
360
397
|
You can use a custom health check by specifying a callable object (anything that
|
@@ -365,7 +402,7 @@ should return a truthy value, falsey otherwise. Here's an example of a custom
|
|
365
402
|
health check that verifies that an elasticsearch node is up and has joined the
|
366
403
|
cluster.
|
367
404
|
|
368
|
-
|
405
|
+
```ruby
|
369
406
|
def cluster_green?(target_server, port, endpoint)
|
370
407
|
response = begin
|
371
408
|
Excon.get("http://#{target_server.hostname}:#{port}#{endpoint}")
|
@@ -386,7 +423,7 @@ task :production => :common do
|
|
386
423
|
host 'es-01.example.com'
|
387
424
|
host 'es-02.example.com'
|
388
425
|
end
|
389
|
-
|
426
|
+
```
|
390
427
|
|
391
428
|
**Rolling Deployment Settings**:
|
392
429
|
You can change the following settings in your config to tune how the rolling
|
@@ -412,35 +449,36 @@ are the same everywhere. Settings are per-project.
|
|
412
449
|
that are. The default is an empty array. If you have non-HTTP services that you
|
413
450
|
want to check, see Custom Health Checks in the previous section.
|
414
451
|
|
415
|
-
###Deploy a project to a fleet of Docker servers
|
452
|
+
### Deploy a project to a fleet of Docker servers
|
416
453
|
|
417
454
|
This will hard stop, then start containers on all the specified hosts. This
|
418
455
|
is not recommended for apps where one endpoint needs to be available at all
|
419
456
|
times. It is fast.
|
420
457
|
|
421
|
-
|
458
|
+
```bash
|
422
459
|
$ bundle exec centurion -p radio-radio -e staging -a deploy
|
423
|
-
|
460
|
+
```
|
424
461
|
|
425
|
-
###Deploy a bash console on a host
|
462
|
+
### Deploy a bash console on a host
|
426
463
|
|
427
464
|
This will give you a command line shell with all of your existing environment
|
428
465
|
passed to the container. The `CMD` from the `Dockerfile` will be replaced
|
429
466
|
with `/bin/bash`. It will use the first host from the host list.
|
430
467
|
|
431
|
-
|
468
|
+
```bash
|
432
469
|
$ bundle exec centurion -p radio-radio -e staging -a deploy_console
|
433
|
-
|
470
|
+
```
|
471
|
+
|
434
472
|
### Repair unhealthy docker containers
|
435
473
|
|
436
474
|
This will preform a health check on each host using rolling deployment
|
437
475
|
health check settings and redeploy to the host if a health check fails.
|
438
476
|
|
439
|
-
|
477
|
+
```bash
|
440
478
|
$ bundle exec centurion -p radio-radio -e staging -a repair
|
441
|
-
|
479
|
+
```
|
442
480
|
|
443
|
-
###List all the tags running on your servers for a particular project
|
481
|
+
### List all the tags running on your servers for a particular project
|
444
482
|
|
445
483
|
Returns a nicely-formatted list of all the current tags and which machines they
|
446
484
|
are running on. Gives a unique list of tags across all hosts as well. This is
|
@@ -451,7 +489,7 @@ goes wrong mid-deploy.
|
|
451
489
|
$ bundle exec centurion -p radio-radio -e staging -a list:running_container_tags
|
452
490
|
```
|
453
491
|
|
454
|
-
###List all the containers currently running for this project
|
492
|
+
### List all the containers currently running for this project
|
455
493
|
|
456
494
|
Returns a (as yet not very nicely formatted) list of all the containers for
|
457
495
|
this project on each of the servers from the config.
|
@@ -460,13 +498,13 @@ this project on each of the servers from the config.
|
|
460
498
|
$ bundle exec centurion -p radio-radio -e staging -a list:running_containers
|
461
499
|
```
|
462
500
|
|
463
|
-
###List registry images
|
501
|
+
### List registry images
|
464
502
|
|
465
503
|
Returns a list of all the images for this project in the registry.
|
466
504
|
|
467
|
-
|
505
|
+
```bash
|
468
506
|
$ bundle exec centurion -p radio-radio -e staging -a list
|
469
|
-
|
507
|
+
```
|
470
508
|
|
471
509
|
### Registry
|
472
510
|
|
@@ -609,4 +647,4 @@ patents, and ideas in that code in our products if we so choose. You also agree
|
|
609
647
|
the code is provided as-is and you provide no warranties as to its fitness or
|
610
648
|
correctness for any purpose
|
611
649
|
|
612
|
-
Copyright (c) 2014-
|
650
|
+
Copyright (c) 2014-2017 New Relic, Inc. All rights reserved.
|
data/centurion.gemspec
CHANGED
@@ -36,6 +36,8 @@ Gem::Specification.new do |spec|
|
|
36
36
|
spec.add_dependency 'trollop'
|
37
37
|
spec.add_dependency 'excon', '~> 0.33'
|
38
38
|
spec.add_dependency 'logger-colors'
|
39
|
+
spec.add_dependency 'net-ssh'
|
40
|
+
spec.add_dependency 'sshkit'
|
39
41
|
|
40
42
|
spec.add_development_dependency 'bundler'
|
41
43
|
spec.add_development_dependency 'rake', '~> 10.5'
|
data/lib/centurion/deploy_dsl.rb
CHANGED
@@ -150,7 +150,7 @@ module Centurion::DeployDSL
|
|
150
150
|
|
151
151
|
def build_server_group
|
152
152
|
hosts, docker_path = fetch(:hosts, []), fetch(:docker_path)
|
153
|
-
Centurion::DockerServerGroup.new(hosts, docker_path,
|
153
|
+
Centurion::DockerServerGroup.new(hosts, docker_path, build_server_params)
|
154
154
|
end
|
155
155
|
|
156
156
|
def validate_options_keys(options, valid_keys)
|
@@ -180,13 +180,23 @@ module Centurion::DeployDSL
|
|
180
180
|
Centurion::DockerViaCli.tls_keys.all? { |key| fetch(key).present? }
|
181
181
|
end
|
182
182
|
|
183
|
-
def
|
184
|
-
|
185
|
-
|
186
|
-
tls
|
187
|
-
tlscacert
|
188
|
-
tlscert
|
189
|
-
tlskey
|
190
|
-
|
183
|
+
def build_server_params
|
184
|
+
opts = {}
|
185
|
+
if fetch(:tlsverify)
|
186
|
+
opts[:tls] = fetch(:tlsverify || tls_paths_available?)
|
187
|
+
opts[:tlscacert] = fetch(:tlscacert)
|
188
|
+
opts[:tlscert] = fetch(:tlscert)
|
189
|
+
opts[:tlskey] = fetch(:tlskey)
|
190
|
+
end
|
191
|
+
|
192
|
+
if fetch(:ssh, false) == true
|
193
|
+
opts[:ssh] = true
|
194
|
+
|
195
|
+
# nil is OK for both of these, defaults applied internally
|
196
|
+
opts[:ssh_user] = fetch(:ssh_user)
|
197
|
+
opts[:ssh_log_level] = fetch(:ssh_log_level)
|
198
|
+
end
|
199
|
+
|
200
|
+
opts
|
191
201
|
end
|
192
202
|
end
|
@@ -18,15 +18,15 @@ class Centurion::DockerServer
|
|
18
18
|
:remove_container, :restart_container
|
19
19
|
def_delegators :docker_via_cli, :pull, :tail, :attach, :exec, :exec_it
|
20
20
|
|
21
|
-
def initialize(host, docker_path,
|
21
|
+
def initialize(host, docker_path, connection_opts = {})
|
22
22
|
@docker_path = docker_path
|
23
23
|
@hostname, @port = host.split(':')
|
24
|
-
@port ||= if
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
@
|
24
|
+
@port ||= if connection_opts[:tls]
|
25
|
+
'2376'
|
26
|
+
else
|
27
|
+
'2375'
|
28
|
+
end
|
29
|
+
@connection_opts = connection_opts
|
30
30
|
end
|
31
31
|
|
32
32
|
def current_tags_for(image)
|
@@ -64,16 +64,26 @@ class Centurion::DockerServer
|
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
|
+
def describe
|
68
|
+
desc = hostname
|
69
|
+
desc += " via TLS" if @connection_opts[:tls]
|
70
|
+
if @connection_opts[:ssh]
|
71
|
+
desc += " via SSH"
|
72
|
+
desc += " user #{@connection_opts[:ssh_user]}" if @connection_opts[:ssh_user]
|
73
|
+
end
|
74
|
+
desc
|
75
|
+
end
|
76
|
+
|
67
77
|
private
|
68
78
|
|
69
79
|
def docker_via_api
|
70
80
|
@docker_via_api ||= Centurion::DockerViaApi.new(@hostname, @port,
|
71
|
-
@
|
81
|
+
@connection_opts, nil)
|
72
82
|
end
|
73
83
|
|
74
84
|
def docker_via_cli
|
75
85
|
@docker_via_cli ||= Centurion::DockerViaCli.new(@hostname, @port,
|
76
|
-
@docker_path, @
|
86
|
+
@docker_path, @connection_opts)
|
77
87
|
end
|
78
88
|
|
79
89
|
def parse_image_tags_for(running_containers)
|
@@ -2,13 +2,21 @@ require 'excon'
|
|
2
2
|
require 'json'
|
3
3
|
require 'uri'
|
4
4
|
require 'securerandom'
|
5
|
+
require 'centurion/ssh'
|
5
6
|
|
6
7
|
module Centurion; end
|
7
8
|
|
8
9
|
class Centurion::DockerViaApi
|
9
|
-
def initialize(hostname, port,
|
10
|
-
@tls_args = default_tls_args(
|
11
|
-
|
10
|
+
def initialize(hostname, port, connection_opts = {}, api_version = nil)
|
11
|
+
@tls_args = default_tls_args(connection_opts[:tls]).merge(connection_opts.reject { |k, v| v.nil? }) # Required by tls_enable?
|
12
|
+
if connection_opts[:ssh]
|
13
|
+
@base_uri = hostname
|
14
|
+
@ssh = true
|
15
|
+
@ssh_user = connection_opts[:ssh_user]
|
16
|
+
@ssh_log_level = connection_opts[:ssh_log_level]
|
17
|
+
else
|
18
|
+
@base_uri = "http#{'s' if tls_enable?}://#{hostname}:#{port}"
|
19
|
+
end
|
12
20
|
api_version ||= "/v1.12"
|
13
21
|
@docker_api_version = api_version
|
14
22
|
configure_excon_globally
|
@@ -17,7 +25,7 @@ class Centurion::DockerViaApi
|
|
17
25
|
def ps(options={})
|
18
26
|
path = @docker_api_version + "/containers/json"
|
19
27
|
path += "?all=1" if options[:all]
|
20
|
-
response =
|
28
|
+
response = with_excon {|e| e.get(path: path)}
|
21
29
|
|
22
30
|
raise unless response.status == 200
|
23
31
|
JSON.load(response.body)
|
@@ -27,61 +35,64 @@ class Centurion::DockerViaApi
|
|
27
35
|
repository = "#{image}:#{tag}"
|
28
36
|
path = @docker_api_version + "/images/#{repository}/json"
|
29
37
|
|
30
|
-
response =
|
31
|
-
|
32
|
-
|
33
|
-
|
38
|
+
response = with_excon do |e|
|
39
|
+
e.get(
|
40
|
+
path: path,
|
41
|
+
headers: {'Accept' => 'application/json'}
|
42
|
+
)
|
43
|
+
end
|
34
44
|
raise response.inspect unless response.status == 200
|
35
45
|
JSON.load(response.body)
|
36
46
|
end
|
37
47
|
|
38
48
|
def remove_container(container_id)
|
39
49
|
path = @docker_api_version + "/containers/#{container_id}"
|
40
|
-
response =
|
41
|
-
|
42
|
-
|
43
|
-
|
50
|
+
response = with_excon do |e|
|
51
|
+
e.delete(
|
52
|
+
path: path,
|
53
|
+
)
|
54
|
+
end
|
44
55
|
raise response.inspect unless response.status == 204
|
45
56
|
true
|
46
57
|
end
|
47
58
|
|
48
59
|
def stop_container(container_id, timeout = 30)
|
49
60
|
path = @docker_api_version + "/containers/#{container_id}/stop?t=#{timeout}"
|
50
|
-
response =
|
51
|
-
|
52
|
-
|
61
|
+
response = with_excon do |e|
|
62
|
+
e.post(
|
63
|
+
path: path,
|
53
64
|
# Wait for both the docker stop timeout AND the kill AND
|
54
65
|
# potentially a very slow HTTP server.
|
55
66
|
read_timeout: timeout + 120
|
56
67
|
)
|
57
|
-
|
68
|
+
end
|
58
69
|
raise response.inspect unless response.status == 204
|
59
70
|
true
|
60
71
|
end
|
61
72
|
|
62
73
|
def create_container(configuration, name = nil)
|
63
74
|
path = @docker_api_version + "/containers/create"
|
64
|
-
response =
|
65
|
-
|
66
|
-
|
67
|
-
query: name ?
|
75
|
+
response = with_excon do |e|
|
76
|
+
e.post(
|
77
|
+
path: path,
|
78
|
+
query: name ? "name=#{name}-#{SecureRandom.hex(7)}" : nil,
|
68
79
|
body: configuration.to_json,
|
69
80
|
headers: { "Content-Type" => "application/json" }
|
70
81
|
)
|
71
|
-
|
82
|
+
end
|
72
83
|
raise response.inspect unless response.status == 201
|
73
84
|
JSON.load(response.body)
|
74
85
|
end
|
75
86
|
|
76
87
|
def start_container(container_id, configuration)
|
77
88
|
path = @docker_api_version + "/containers/#{container_id}/start"
|
78
|
-
response =
|
79
|
-
|
80
|
-
|
89
|
+
response = with_excon do |e|
|
90
|
+
e.post(
|
91
|
+
path: path,
|
81
92
|
body: configuration.to_json,
|
82
93
|
headers: { "Content-Type" => "application/json" }
|
83
94
|
)
|
84
|
-
|
95
|
+
end
|
85
96
|
case response.status
|
86
97
|
when 204
|
87
98
|
true
|
@@ -94,14 +105,14 @@ class Centurion::DockerViaApi
|
|
94
105
|
|
95
106
|
def restart_container(container_id, timeout = 30)
|
96
107
|
path = @docker_api_version + "/containers/#{container_id}/restart?t=#{timeout}"
|
97
|
-
response =
|
98
|
-
|
99
|
-
|
108
|
+
response = with_excon do |e|
|
109
|
+
e.post(
|
110
|
+
path: path,
|
100
111
|
# Wait for both the docker stop timeout AND the kill AND
|
101
112
|
# potentially a very slow HTTP server.
|
102
113
|
read_timeout: timeout + 120
|
103
114
|
)
|
104
|
-
|
115
|
+
end
|
105
116
|
case response.status
|
106
117
|
when 204
|
107
118
|
true
|
@@ -116,10 +127,11 @@ class Centurion::DockerViaApi
|
|
116
127
|
|
117
128
|
def inspect_container(container_id)
|
118
129
|
path = @docker_api_version + "/containers/#{container_id}/json"
|
119
|
-
response =
|
120
|
-
|
121
|
-
|
122
|
-
|
130
|
+
response = with_excon do |e|
|
131
|
+
e.get(
|
132
|
+
path: path,
|
133
|
+
)
|
134
|
+
end
|
123
135
|
raise response.inspect unless response.status == 200
|
124
136
|
JSON.load(response.body)
|
125
137
|
end
|
@@ -172,4 +184,19 @@ class Centurion::DockerViaApi
|
|
172
184
|
{}
|
173
185
|
end
|
174
186
|
end
|
187
|
+
|
188
|
+
def with_excon(&block)
|
189
|
+
if @ssh
|
190
|
+
with_excon_via_ssh(&block)
|
191
|
+
else
|
192
|
+
yield Excon.new(@base_uri, tls_excon_arguments)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def with_excon_via_ssh
|
197
|
+
Centurion::SSH.with_docker_socket(@base_uri, @ssh_user, @ssh_log_level) do |socket|
|
198
|
+
conn = Excon.new('unix:///', socket: socket)
|
199
|
+
yield conn
|
200
|
+
end
|
201
|
+
end
|
175
202
|
end
|