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