ecs_deploy 2.0.0 → 2.1.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/.github/workflows/test.yml +1 -1
- data/README.md +3 -0
- data/lib/ecs_deploy/capistrano.rb +3 -0
- data/lib/ecs_deploy/configuration.rb +3 -1
- data/lib/ecs_deploy/task_definition.rb +71 -4
- data/lib/ecs_deploy/version.rb +1 -1
- data/lib/ecs_deploy.rb +2 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ffd7f96436519805879cb2793cffbe33cf991a6f17109904f014cf35b5f51fe8
|
|
4
|
+
data.tar.gz: 8085faa308fe594cab25202e3cefbcddca7553775b0bd484f4c5ecdfc5db95f5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dc6488543f3b0ca040de988a5a2e8df5241ed0c01e2f7e11ad52fce9450f0a9d967685202718c9db87ee4834062faad002d0e17adb7e0b6262a5710f1eeaecf7
|
|
7
|
+
data.tar.gz: b5a11acbafb0b6153961f91b4ef6237248ba484f055fea5092b03cf9f1f70f25519fca19629dd3e72cad44f8bcc349137bee6fcbb64bf0d52a6b5e91d74d5f56
|
data/.github/workflows/test.yml
CHANGED
|
@@ -14,7 +14,7 @@ jobs:
|
|
|
14
14
|
steps:
|
|
15
15
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
16
16
|
- name: Set up Ruby
|
|
17
|
-
uses: ruby/setup-ruby@
|
|
17
|
+
uses: ruby/setup-ruby@d45b1a4e94b71acab930e56e79c6aa188764e7f9 # v1.316.0
|
|
18
18
|
with:
|
|
19
19
|
ruby-version: ${{ matrix.ruby-version }}
|
|
20
20
|
bundler-cache: true
|
data/README.md
CHANGED
|
@@ -30,10 +30,13 @@ set :ecs_deploy_wait_timeout, 600 # default: 300
|
|
|
30
30
|
set :ecs_wait_until_services_stable_max_attempts, 40 # optional
|
|
31
31
|
set :ecs_wait_until_services_stable_delay, 15 # optional
|
|
32
32
|
set :ecs_client_params, { retry_mode: "standard", max_attempts: 10 } # default: {}
|
|
33
|
+
set :ecs_docker_buildx_env, { "DOCKER_CONFIG" => "/path/to/docker/config" } # optional. Env vars for the `docker buildx` command used by use_digest. Merged with each task's docker_buildx_env (the per-task one takes precedence). default: {}
|
|
33
34
|
|
|
34
35
|
set :ecs_tasks, [
|
|
35
36
|
{
|
|
36
37
|
name: "myapp-#{fetch(:rails_env)}",
|
|
38
|
+
use_digest: true, # optional. When true, each container_definitions[].image is rewritten to a digest reference (registry/repo@sha256:...) resolved via `docker buildx imagetools inspect` at registration time. Requires the `docker` CLI with buildx on the deploy host; resolution failure aborts the deploy.
|
|
39
|
+
docker_buildx_env: { "DOCKER_CONFIG" => "/path/to/docker/config" }, # optional. Env vars for the `docker buildx` command. Merged on top of :ecs_docker_buildx_env.
|
|
37
40
|
container_definitions: [
|
|
38
41
|
{
|
|
39
42
|
name: "myapp",
|
|
@@ -11,6 +11,7 @@ namespace :ecs do
|
|
|
11
11
|
c.ecs_wait_until_services_stable_max_attempts = fetch(:ecs_wait_until_services_stable_max_attempts) if fetch(:ecs_wait_until_services_stable_max_attempts)
|
|
12
12
|
c.ecs_wait_until_services_stable_delay = fetch(:ecs_wait_until_services_stable_delay) if fetch(:ecs_wait_until_services_stable_delay)
|
|
13
13
|
c.ecs_client_params = fetch(:ecs_client_params) if fetch(:ecs_client_params)
|
|
14
|
+
c.docker_buildx_env = fetch(:ecs_docker_buildx_env) if fetch(:ecs_docker_buildx_env)
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
if ENV["TARGET_CLUSTER"]
|
|
@@ -32,6 +33,8 @@ namespace :ecs do
|
|
|
32
33
|
task_definition = EcsDeploy::TaskDefinition.new(
|
|
33
34
|
region: region,
|
|
34
35
|
task_definition_name: t[:name],
|
|
36
|
+
use_digest: t[:use_digest],
|
|
37
|
+
docker_buildx_env: t[:docker_buildx_env],
|
|
35
38
|
container_definitions: t[:container_definitions],
|
|
36
39
|
task_role_arn: t[:task_role_arn],
|
|
37
40
|
execution_role_arn: t[:execution_role_arn],
|
|
@@ -9,7 +9,8 @@ module EcsDeploy
|
|
|
9
9
|
:ecs_service_role,
|
|
10
10
|
:ecs_wait_until_services_stable_max_attempts,
|
|
11
11
|
:ecs_wait_until_services_stable_delay,
|
|
12
|
-
:ecs_client_params
|
|
12
|
+
:ecs_client_params,
|
|
13
|
+
:docker_buildx_env
|
|
13
14
|
|
|
14
15
|
def initialize
|
|
15
16
|
@log_level = :info
|
|
@@ -18,6 +19,7 @@ module EcsDeploy
|
|
|
18
19
|
@ecs_wait_until_services_stable_max_attempts = 40
|
|
19
20
|
@ecs_wait_until_services_stable_delay = 15
|
|
20
21
|
@ecs_client_params = {}
|
|
22
|
+
@docker_buildx_env = {}
|
|
21
23
|
end
|
|
22
24
|
end
|
|
23
25
|
end
|
|
@@ -1,5 +1,18 @@
|
|
|
1
|
+
require "open3"
|
|
2
|
+
|
|
1
3
|
module EcsDeploy
|
|
2
4
|
class TaskDefinition
|
|
5
|
+
DIGEST_SUFFIX = /@sha256:[0-9a-f]{64}\z/
|
|
6
|
+
DIGEST_FORMAT = /\Asha256:[0-9a-f]{64}\z/
|
|
7
|
+
|
|
8
|
+
# Process-wide cache of resolved digests keyed by image reference,
|
|
9
|
+
# so the same image is only inspected via docker once per process.
|
|
10
|
+
@digest_cache = {}
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
attr_reader :digest_cache
|
|
14
|
+
end
|
|
15
|
+
|
|
3
16
|
def self.deregister(arn, region: nil)
|
|
4
17
|
region ||= EcsDeploy.config.default_region
|
|
5
18
|
params ||= EcsDeploy.config.ecs_client_params
|
|
@@ -10,8 +23,12 @@ module EcsDeploy
|
|
|
10
23
|
EcsDeploy.logger.info "deregistered task definition [#{arn}] [#{client.config.region}] [#{Paint['OK', :green]}]"
|
|
11
24
|
end
|
|
12
25
|
|
|
13
|
-
def initialize(task_definition_name:, region: nil, **options)
|
|
26
|
+
def initialize(task_definition_name:, region: nil, use_digest: false, docker_buildx_env: nil, **options)
|
|
14
27
|
@task_definition_name = task_definition_name
|
|
28
|
+
@use_digest = use_digest
|
|
29
|
+
@docker_buildx_env = (EcsDeploy.config.docker_buildx_env || {})
|
|
30
|
+
.merge(docker_buildx_env || {})
|
|
31
|
+
.map { |k, v| [k.to_s, v&.to_s] }.to_h
|
|
15
32
|
region ||= EcsDeploy.config.default_region
|
|
16
33
|
params ||= EcsDeploy.config.ecs_client_params
|
|
17
34
|
|
|
@@ -49,11 +66,61 @@ module EcsDeploy
|
|
|
49
66
|
end
|
|
50
67
|
|
|
51
68
|
def register
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
)
|
|
69
|
+
options = @options.merge(family: @task_definition_name)
|
|
70
|
+
options[:container_definitions] = apply_digests(options[:container_definitions]) if @use_digest
|
|
71
|
+
res = @client.register_task_definition(options)
|
|
55
72
|
EcsDeploy.logger.info "registered task definition [#{@task_definition_name}] [#{@region}] [#{Paint['OK', :green]}]"
|
|
56
73
|
res.task_definition
|
|
57
74
|
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def apply_digests(container_definitions)
|
|
79
|
+
(container_definitions || []).map do |cd|
|
|
80
|
+
image = cd[:image]
|
|
81
|
+
next cd if image.nil? || image.empty?
|
|
82
|
+
|
|
83
|
+
resolved = resolve_image_with_digest(image)
|
|
84
|
+
EcsDeploy.logger.info "resolved image [#{image}] -> [#{resolved}]" if resolved != image
|
|
85
|
+
cd.merge(image: resolved)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def resolve_image_with_digest(image)
|
|
90
|
+
return image if image =~ DIGEST_SUFFIX
|
|
91
|
+
|
|
92
|
+
"#{repository_without_tag(image)}@#{fetch_manifest_digest(image)}"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# "registry:5000/ns/repo:tag" -> "registry:5000/ns/repo"
|
|
96
|
+
# "registry:5000/ns/repo" -> "registry:5000/ns/repo"
|
|
97
|
+
# "repo:tag" -> "repo"
|
|
98
|
+
def repository_without_tag(image)
|
|
99
|
+
name_start = (idx = image.rindex("/")) ? idx + 1 : 0
|
|
100
|
+
colon = image.index(":", name_start)
|
|
101
|
+
colon ? image[0...colon] : image
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def fetch_manifest_digest(image)
|
|
105
|
+
cache = self.class.digest_cache
|
|
106
|
+
if (cached = cache[image])
|
|
107
|
+
EcsDeploy.logger.debug "using cached digest for #{image}: #{cached}"
|
|
108
|
+
return cached
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
EcsDeploy.logger.debug "docker buildx imagetools inspect --format '{{.Manifest.Digest}}' #{image}"
|
|
112
|
+
stdout, stderr, status =
|
|
113
|
+
Open3.capture3(@docker_buildx_env, "docker", "buildx", "imagetools", "inspect", "--format", "{{.Manifest.Digest}}", image)
|
|
114
|
+
unless status.success?
|
|
115
|
+
raise EcsDeploy::Error, "docker buildx imagetools inspect failed for '#{image}': #{stderr.strip}"
|
|
116
|
+
end
|
|
117
|
+
digest = stdout.strip
|
|
118
|
+
unless digest =~ DIGEST_FORMAT
|
|
119
|
+
raise EcsDeploy::Error, "Unexpected digest for '#{image}': #{digest.inspect}"
|
|
120
|
+
end
|
|
121
|
+
cache[image] = digest
|
|
122
|
+
rescue Errno::ENOENT => e
|
|
123
|
+
raise EcsDeploy::Error, "docker command not found: #{e.message}"
|
|
124
|
+
end
|
|
58
125
|
end
|
|
59
126
|
end
|
data/lib/ecs_deploy/version.rb
CHANGED
data/lib/ecs_deploy.rb
CHANGED