indocker 0.5.1 → 0.5.3
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/Gemfile.lock +1 -1
- data/lib/indocker/container_deployer.rb +57 -52
- data/lib/indocker/launchers/configuration_deployer.rb +14 -21
- data/lib/indocker/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 738373105e7204366594f9789bc989e5c83453bc209fe0053485ef239156cc7a
|
|
4
|
+
data.tar.gz: 63dc5708eee2e75caab7a4bfaa8ac9c0e80c73fb46fbca987215d28309f07d86
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 477f6ae6ffd9fa9087743f06e354d751af669e803c4f9f5a7ee74c820bbfb5872674c379a0a006d46200f5fe174bf7f1779b088df093b6dfeabe51c2fcd3e7b9
|
|
7
|
+
data.tar.gz: 355bee8644ae9e6e478cc878f41ee26c3f73bcf31c951561dc80fdc2c4bdde162e1d3d0bd387633d74501767c2b089a3f7cb20610795c5a6d2808a2b61dd079f
|
data/Gemfile.lock
CHANGED
|
@@ -20,29 +20,29 @@ class Indocker::ContainerDeployer
|
|
|
20
20
|
def deploy(container, force_restart, skip_force_restart, progress)
|
|
21
21
|
return if @deployed_containers[container]
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
23
|
+
exit_codes =
|
|
24
|
+
if deploy_servers_in_parallel?(container)
|
|
25
|
+
# Stateless containers: deploy to all servers at once.
|
|
26
|
+
threads = container.servers.map do |server|
|
|
27
|
+
Thread.new do
|
|
28
|
+
deploy_to_server(container, server, force_restart, skip_force_restart, progress)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
threads.map(&:value)
|
|
33
|
+
else
|
|
34
|
+
# Rolling deploy: one server at a time. Containers with rolling-restart
|
|
35
|
+
# hooks (e.g. draining/enabling an nginx upstream) sit behind a load
|
|
36
|
+
# balancer, so all of their servers must not restart simultaneously —
|
|
37
|
+
# otherwise there is a moment with no live backend (502s). Deploying
|
|
38
|
+
# server by server keeps the rest of the fleet serving.
|
|
39
|
+
container.servers.map do |server|
|
|
37
40
|
deploy_to_server(container, server, force_restart, skip_force_restart, progress)
|
|
38
41
|
end
|
|
39
42
|
end
|
|
40
43
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if results.any? { |exit_code| exit_code != 0 }
|
|
44
|
-
exit 1
|
|
45
|
-
end
|
|
44
|
+
if exit_codes.any? { |exit_code| exit_code != 0 }
|
|
45
|
+
exit 1
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
@deployed_containers[container] = true
|
|
@@ -56,52 +56,57 @@ class Indocker::ContainerDeployer
|
|
|
56
56
|
|
|
57
57
|
private
|
|
58
58
|
|
|
59
|
+
# Whether the container may be deployed to all of its servers concurrently.
|
|
60
|
+
# An explicit :parallel_deploy start option wins; otherwise a container is
|
|
61
|
+
# deployed in parallel only when it has no rolling-restart hooks (containers
|
|
62
|
+
# with before/after start hooks are drained at a load balancer and must roll
|
|
63
|
+
# across servers one at a time).
|
|
64
|
+
def deploy_servers_in_parallel?(container)
|
|
65
|
+
option = container.get_start_option(:parallel_deploy)
|
|
66
|
+
return option unless option.nil?
|
|
67
|
+
|
|
68
|
+
container.before_start_proc.nil? && container.after_start_proc.nil?
|
|
69
|
+
end
|
|
70
|
+
|
|
59
71
|
# Runs a single container deployment on a single server. Returns the remote
|
|
60
|
-
# exit code (0 on success).
|
|
61
|
-
#
|
|
62
|
-
#
|
|
72
|
+
# exit code (0 on success).
|
|
73
|
+
#
|
|
74
|
+
# Per-server exclusion: only one container deploys on a given server at a time,
|
|
75
|
+
# so several container types don't spike CPU/memory by starting at once on the
|
|
76
|
+
# same host. Each invocation holds only its own server's lock, so concurrent
|
|
77
|
+
# deployments can't deadlock.
|
|
63
78
|
def deploy_to_server(container, server, force_restart, skip_force_restart, progress)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
79
|
+
server_lock(server).synchronize do
|
|
80
|
+
progress.start_deploying_container(container, server)
|
|
81
|
+
|
|
82
|
+
deploy_server = @server_pool.create_connection!(server)
|
|
83
|
+
@logger.info("Deploying container: #{container.name.to_s.green} to #{server.user}@#{server.host}")
|
|
84
|
+
|
|
85
|
+
result = deploy_server
|
|
86
|
+
.run_container_remotely(
|
|
87
|
+
configuration_name: Indocker.configuration_name,
|
|
88
|
+
container_name: container.name,
|
|
89
|
+
force_restart: force_restart && !skip_force_restart.include?(container.name)
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
if result.exit_code == 0
|
|
93
|
+
@logger.info("Container deployment to #{server.user}@#{server.host} finished: #{container.name.to_s.green}")
|
|
94
|
+
progress.finish_deploying_container(container, server)
|
|
95
|
+
end
|
|
68
96
|
|
|
69
|
-
|
|
70
|
-
.run_container_remotely(
|
|
71
|
-
configuration_name: Indocker.configuration_name,
|
|
72
|
-
container_name: container.name,
|
|
73
|
-
force_restart: force_restart && !skip_force_restart.include?(container.name)
|
|
74
|
-
)
|
|
97
|
+
deploy_server.close_session
|
|
75
98
|
|
|
76
|
-
|
|
77
|
-
@logger.info("Container deployment to #{server.user}@#{server.host} finished: #{container.name.to_s.green}")
|
|
78
|
-
progress.finish_deploying_container(container, server)
|
|
99
|
+
result.exit_code
|
|
79
100
|
end
|
|
80
|
-
|
|
81
|
-
deploy_server.close_session
|
|
82
|
-
|
|
83
|
-
result.exit_code
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def server_lock_key(server)
|
|
87
|
-
[server.host, server.port, server.user]
|
|
88
101
|
end
|
|
89
102
|
|
|
90
103
|
# Returns a process-wide singleton Mutex for the given server, so the same lock
|
|
91
104
|
# is shared across every container targeting that server.
|
|
92
105
|
def server_lock(server)
|
|
93
|
-
key =
|
|
106
|
+
key = [server.host, server.port, server.user]
|
|
94
107
|
|
|
95
108
|
@server_locks_mutex.synchronize do
|
|
96
109
|
@server_locks[key] ||= Mutex.new
|
|
97
110
|
end
|
|
98
111
|
end
|
|
99
|
-
|
|
100
|
-
def with_locks(locks, &block)
|
|
101
|
-
if locks.empty?
|
|
102
|
-
block.call
|
|
103
|
-
else
|
|
104
|
-
locks.first.synchronize { with_locks(locks.drop(1), &block) }
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
112
|
end
|
|
@@ -302,34 +302,28 @@ class Indocker::Launchers::ConfigurationDeployer
|
|
|
302
302
|
# container to the deploy stage — so the next image is already building while
|
|
303
303
|
# the previous container deploys.
|
|
304
304
|
#
|
|
305
|
-
# The consumer
|
|
306
|
-
#
|
|
307
|
-
#
|
|
308
|
-
#
|
|
305
|
+
# The consumer deploys containers strictly one at a time, in the order they
|
|
306
|
+
# were built (which is dependency order, so depends_on is respected). Only a
|
|
307
|
+
# single container is ever restarting across the whole fleet at any moment —
|
|
308
|
+
# the invariant the original sequential deploy guaranteed. This matters for
|
|
309
|
+
# zero-downtime web apps: deploying several containers concurrently can flap an
|
|
310
|
+
# app's health (its health check depends on backends that would be restarting
|
|
311
|
+
# in parallel), leaving nginx with a live-but-unhealthy upstream and serving
|
|
312
|
+
# 502s during the deploy.
|
|
313
|
+
#
|
|
314
|
+
# Only image builds run ahead of deploys (below) — that is where the pipeline
|
|
315
|
+
# speedup comes from. A single container still fans out to its own servers in
|
|
316
|
+
# parallel (see ContainerDeployer), so multi-server containers stay fast.
|
|
309
317
|
def pipeline_build_and_deploy(configuration, deployer, build_server_pool, containers,
|
|
310
318
|
skip_build, skip_deploy, force_restart, skip_force_restart)
|
|
311
319
|
|
|
312
320
|
ordered_containers = build_deploy_order(containers)
|
|
313
321
|
|
|
314
|
-
deploy_queue
|
|
315
|
-
deploy_threads = {}
|
|
322
|
+
deploy_queue = Queue.new
|
|
316
323
|
|
|
317
324
|
consumer = Thread.new do
|
|
318
325
|
while (container = deploy_queue.pop) != :done
|
|
319
|
-
|
|
320
|
-
# dependents, so their deploy threads already exist here.
|
|
321
|
-
dependency_threads = container
|
|
322
|
-
.dependent_containers
|
|
323
|
-
.map { |dependency| deploy_threads[dependency] }
|
|
324
|
-
.compact
|
|
325
|
-
|
|
326
|
-
# Pass container/dependency_threads as thread arguments so each thread
|
|
327
|
-
# captures its own value — the shared loop variables get reassigned on
|
|
328
|
-
# the next iteration (eventually to :done) before these threads run.
|
|
329
|
-
deploy_threads[container] = Thread.new(container, dependency_threads) do |container, dependency_threads|
|
|
330
|
-
dependency_threads.each(&:join)
|
|
331
|
-
deploy_container(deployer, container, force_restart, skip_force_restart)
|
|
332
|
-
end
|
|
326
|
+
deploy_container(deployer, container, force_restart, skip_force_restart)
|
|
333
327
|
end
|
|
334
328
|
end
|
|
335
329
|
|
|
@@ -351,7 +345,6 @@ class Indocker::Launchers::ConfigurationDeployer
|
|
|
351
345
|
|
|
352
346
|
deploy_queue.push(:done)
|
|
353
347
|
consumer.join
|
|
354
|
-
deploy_threads.values.each(&:join)
|
|
355
348
|
end
|
|
356
349
|
|
|
357
350
|
# Returns the containers to deploy in dependency order (each container's
|
data/lib/indocker/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: indocker
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ruslan Gatiyatov
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: exe
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2026-07-
|
|
12
|
+
date: 2026-07-07 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: net-ssh
|