hako 0.16.0 → 0.17.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/examples/hello-autoscaling.yml +56 -0
- data/examples/hello.yml +1 -1
- data/lib/hako/schedulers/ecs.rb +17 -0
- data/lib/hako/schedulers/ecs_autoscaling.rb +129 -0
- data/lib/hako/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee95e37d80652b4fab57fff012c2b40e0b8ee5d2
|
4
|
+
data.tar.gz: 30ddde0b682e1dc63d1119c1de91c7bb2dc3dacf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 59d03d5f2422b3fb21dcc20db36cc850a49ac6fab2af338b94db6946a6a0b01fa8d2ffdb2252a7e8b12be245de4899e391182d082d07a54d4e43ed150f8e2e6a
|
7
|
+
data.tar.gz: d8cc1d44728b3c9a64287a9e82d6633fb24bca4ff3a638a1b540251d5df02d05dd3c4be0849c4d8c5ac0bfce6be5a5d5a06b54c95abcde33dc162a6af435bb92
|
@@ -0,0 +1,56 @@
|
|
1
|
+
scheduler:
|
2
|
+
type: ecs
|
3
|
+
region: ap-northeast-1
|
4
|
+
cluster: eagletmt
|
5
|
+
desired_count: 2
|
6
|
+
role: ecsServiceRole
|
7
|
+
elb:
|
8
|
+
listeners:
|
9
|
+
- load_balancer_port: 80
|
10
|
+
protocol: HTTP
|
11
|
+
subnets:
|
12
|
+
- subnet-XXXXXXXX
|
13
|
+
- subnet-YYYYYYYY
|
14
|
+
security_groups:
|
15
|
+
- sg-ZZZZZZZZ
|
16
|
+
autoscaling:
|
17
|
+
role_arn: arn:aws:iam::012345678901:role/ecsAutoscaleRole
|
18
|
+
min_capacity: 1
|
19
|
+
max_capacity: 4
|
20
|
+
policies:
|
21
|
+
# Add one task when ecs-scaling-out-hello-autoscaling-service is in alarm state
|
22
|
+
- alarms: [ecs-scaling-out-hello-autoscaling-service]
|
23
|
+
cooldown: 300
|
24
|
+
adjustment_type: ChangeInCapacity
|
25
|
+
scaling_adjustment: 1
|
26
|
+
metric_interval_lower_bound: 0
|
27
|
+
metric_aggregation_type: Average
|
28
|
+
# Remove one task when ecs-scaling-in-hello-autoscaling-service is in alarm state
|
29
|
+
- alarms: [ecs-scaling-in-hello-autoscaling-service]
|
30
|
+
cooldown: 300
|
31
|
+
adjustment_type: ChangeInCapacity
|
32
|
+
scaling_adjustment: 1
|
33
|
+
metric_interval_upper_bound: 0
|
34
|
+
metric_aggregation_type: Average
|
35
|
+
app:
|
36
|
+
image: ryotarai/hello-sinatra
|
37
|
+
memory: 128
|
38
|
+
cpu: 256
|
39
|
+
port: 3000
|
40
|
+
env:
|
41
|
+
$providers:
|
42
|
+
- type: file
|
43
|
+
path: hello.env
|
44
|
+
PORT: 3000
|
45
|
+
MESSAGE: '#{username}-san'
|
46
|
+
additional_containers:
|
47
|
+
front:
|
48
|
+
image_tag: hako-nginx
|
49
|
+
memory: 32
|
50
|
+
cpu: 32
|
51
|
+
scripts:
|
52
|
+
- <<: !include front.yml
|
53
|
+
locations:
|
54
|
+
/:
|
55
|
+
allow_only_from:
|
56
|
+
- 10.0.0.0/24
|
data/examples/hello.yml
CHANGED
data/lib/hako/schedulers/ecs.rb
CHANGED
@@ -4,6 +4,7 @@ require 'hako'
|
|
4
4
|
require 'hako/scheduler'
|
5
5
|
require 'hako/schedulers/ecs_definition_comparator'
|
6
6
|
require 'hako/schedulers/ecs_elb'
|
7
|
+
require 'hako/schedulers/ecs_autoscaling'
|
7
8
|
|
8
9
|
module Hako
|
9
10
|
module Schedulers
|
@@ -21,6 +22,9 @@ module Hako
|
|
21
22
|
@role = options.fetch('role', nil)
|
22
23
|
@task_role_arn = options.fetch('task_role_arn', nil)
|
23
24
|
@ecs_elb_options = options.fetch('elb', nil)
|
25
|
+
if options.key?('autoscaling')
|
26
|
+
@autoscaling = EcsAutoscaling.new(options.fetch('autoscaling'), dry_run: @dry_run)
|
27
|
+
end
|
24
28
|
@started_at = nil
|
25
29
|
@container_instance_arn = nil
|
26
30
|
end
|
@@ -39,6 +43,9 @@ module Hako
|
|
39
43
|
definitions.each do |d|
|
40
44
|
Hako.logger.info "Add container #{d}"
|
41
45
|
end
|
46
|
+
if @autoscaling
|
47
|
+
@autoscaling.apply(Aws::ECS::Types::Service.new(cluster_arn: @cluster, service_name: @app_id))
|
48
|
+
end
|
42
49
|
else
|
43
50
|
task_definition = register_task_definition(definitions)
|
44
51
|
if task_definition == :noop
|
@@ -50,8 +57,14 @@ module Hako
|
|
50
57
|
service = create_or_update_service(task_definition.task_definition_arn, front_port)
|
51
58
|
if service == :noop
|
52
59
|
Hako.logger.info "Service isn't changed"
|
60
|
+
if @autoscaling
|
61
|
+
@autoscaling.apply(describe_service)
|
62
|
+
end
|
53
63
|
else
|
54
64
|
Hako.logger.info "Updated service: #{service.service_arn}"
|
65
|
+
if @autoscaling
|
66
|
+
@autoscaling.apply(service)
|
67
|
+
end
|
55
68
|
wait_for_ready(service)
|
56
69
|
end
|
57
70
|
Hako.logger.info 'Deployment completed'
|
@@ -532,6 +545,10 @@ module Hako
|
|
532
545
|
desired_count: @desired_count,
|
533
546
|
task_definition: task_definition_arn,
|
534
547
|
}
|
548
|
+
if @autoscaling
|
549
|
+
# Keep current desired_count if autoscaling is enabled
|
550
|
+
params[:desired_count] = service.desired_count
|
551
|
+
end
|
535
552
|
if service_changed?(service, params)
|
536
553
|
ecs_client.update_service(params).service
|
537
554
|
else
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'hako'
|
3
|
+
require 'hako/error'
|
4
|
+
|
5
|
+
module Hako
|
6
|
+
module Schedulers
|
7
|
+
class EcsAutoscaling
|
8
|
+
def initialize(options, dry_run:)
|
9
|
+
@dry_run = dry_run
|
10
|
+
@role_arn = required_option(options, 'role_arn')
|
11
|
+
@min_capacity = required_option(options, 'min_capacity')
|
12
|
+
@max_capacity = required_option(options, 'max_capacity')
|
13
|
+
@policies = required_option(options, 'policies').map { |r| Policy.new(r) }
|
14
|
+
end
|
15
|
+
|
16
|
+
PUT_METRIC_ALARM_OPTIONS = %i[
|
17
|
+
alarm_name alarm_description actions_enabled ok_actions alarm_actions
|
18
|
+
insufficient_data_actions metric_name namespace statistic dimensions
|
19
|
+
period unit evaluation_periods threshold comparison_operator
|
20
|
+
].freeze
|
21
|
+
|
22
|
+
# @param [Aws::ECS::Types::Service] service
|
23
|
+
# @return [nil]
|
24
|
+
def apply(service)
|
25
|
+
resource_id = "service/#{service.cluster_arn.slice(%r{[^/]+\z}, 0)}/#{service.service_name}"
|
26
|
+
service_namespace = 'ecs'
|
27
|
+
scalable_dimension = 'ecs:service:DesiredCount'
|
28
|
+
|
29
|
+
Hako.logger.info("Registering scalable target to #{resource_id}")
|
30
|
+
unless @dry_run
|
31
|
+
autoscaling_client.register_scalable_target(
|
32
|
+
service_namespace: service_namespace,
|
33
|
+
resource_id: resource_id,
|
34
|
+
scalable_dimension: scalable_dimension,
|
35
|
+
min_capacity: @min_capacity,
|
36
|
+
max_capacity: @max_capacity,
|
37
|
+
role_arn: @role_arn,
|
38
|
+
)
|
39
|
+
end
|
40
|
+
@policies.each do |policy|
|
41
|
+
Hako.logger.info("Configuring scaling policy #{policy.name}")
|
42
|
+
if @dry_run
|
43
|
+
policy.alarms.each do |alarm_name|
|
44
|
+
Hako.logger.info("Configuring #{alarm_name}'s alarm_action")
|
45
|
+
end
|
46
|
+
else
|
47
|
+
policy_arn = autoscaling_client.put_scaling_policy(
|
48
|
+
policy_name: policy.name,
|
49
|
+
service_namespace: service_namespace,
|
50
|
+
resource_id: resource_id,
|
51
|
+
scalable_dimension: scalable_dimension,
|
52
|
+
policy_type: 'StepScaling',
|
53
|
+
step_scaling_policy_configuration: {
|
54
|
+
adjustment_type: policy.adjustment_type,
|
55
|
+
step_adjustments: [
|
56
|
+
{
|
57
|
+
scaling_adjustment: policy.scaling_adjustment,
|
58
|
+
metric_interval_lower_bound: policy.metric_interval_lower_bound,
|
59
|
+
metric_interval_upper_bound: policy.metric_interval_upper_bound,
|
60
|
+
},
|
61
|
+
],
|
62
|
+
cooldown: policy.cooldown,
|
63
|
+
metric_aggregation_type: policy.metric_aggregation_type,
|
64
|
+
},
|
65
|
+
).policy_arn
|
66
|
+
|
67
|
+
alarms = cw_client.describe_alarms(alarm_names: policy.alarms).flat_map(&:metric_alarms).map { |a| [a.alarm_name, a] }.to_h
|
68
|
+
policy.alarms.each do |alarm_name|
|
69
|
+
alarm = alarms.fetch(alarm_name) { raise Error.new("Alarm #{alarm_name} does not exist") }
|
70
|
+
Hako.logger.info("Updating #{alarm_name}'s alarm_actions from #{alarm.alarm_actions} to #{[policy_arn]}")
|
71
|
+
params = PUT_METRIC_ALARM_OPTIONS.map { |key| [key, alarm.public_send(key)] }.to_h
|
72
|
+
params[:alarm_actions] = [policy_arn]
|
73
|
+
cw_client.put_metric_alarm(params)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
nil
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
# @param [Hash] options
|
83
|
+
# @param [String] key
|
84
|
+
# @return [Object]
|
85
|
+
def required_option(options, key)
|
86
|
+
options.fetch(key) { raise Error.new("scheduler.autoscaling.#{key} must be set") }
|
87
|
+
end
|
88
|
+
|
89
|
+
# @return [Aws::ApplicationAutoScaling]
|
90
|
+
def autoscaling_client
|
91
|
+
@autoscaling_client ||= Aws::ApplicationAutoScaling::Client.new
|
92
|
+
end
|
93
|
+
|
94
|
+
# @return [Aws::CloudWatch::Client]
|
95
|
+
def cw_client
|
96
|
+
@cw_client ||= Aws::CloudWatch::Client.new
|
97
|
+
end
|
98
|
+
|
99
|
+
class Policy
|
100
|
+
attr_reader :alarms, :cooldown, :adjustment_type, :scaling_adjustment, :metric_interval_lower_bound, :metric_interval_upper_bound, :metric_aggregation_type
|
101
|
+
|
102
|
+
# @param [Hash] options
|
103
|
+
def initialize(options)
|
104
|
+
@alarms = required_option(options, 'alarms')
|
105
|
+
@cooldown = required_option(options, 'cooldown')
|
106
|
+
@adjustment_type = required_option(options, 'adjustment_type')
|
107
|
+
@scaling_adjustment = required_option(options, 'scaling_adjustment')
|
108
|
+
@metric_interval_lower_bound = options.fetch('metric_interval_lower_bound', nil)
|
109
|
+
@metric_interval_upper_bound = options.fetch('metric_interval_upper_bound', nil)
|
110
|
+
@metric_aggregation_type = required_option(options, 'metric_aggregation_type')
|
111
|
+
end
|
112
|
+
|
113
|
+
# @return [String]
|
114
|
+
def name
|
115
|
+
alarms.join('-and-')
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
# @param [Hash] options
|
121
|
+
# @param [String] key
|
122
|
+
# @return [Object]
|
123
|
+
def required_option(options, key)
|
124
|
+
options.fetch(key) { raise Error.new("scheduler.autoscaling.policies.#{key} must be set") }
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
data/lib/hako/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hako
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.17.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kohei Suzuki
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-07-
|
11
|
+
date: 2016-07-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk
|
@@ -114,6 +114,7 @@ files:
|
|
114
114
|
- bin/console
|
115
115
|
- bin/setup
|
116
116
|
- examples/front.yml
|
117
|
+
- examples/hello-autoscaling.yml
|
117
118
|
- examples/hello-lb.yml
|
118
119
|
- examples/hello.env
|
119
120
|
- examples/hello.yml
|
@@ -135,6 +136,7 @@ files:
|
|
135
136
|
- lib/hako/scheduler.rb
|
136
137
|
- lib/hako/schedulers.rb
|
137
138
|
- lib/hako/schedulers/ecs.rb
|
139
|
+
- lib/hako/schedulers/ecs_autoscaling.rb
|
138
140
|
- lib/hako/schedulers/ecs_definition_comparator.rb
|
139
141
|
- lib/hako/schedulers/ecs_elb.rb
|
140
142
|
- lib/hako/script.rb
|