hako 1.6.2 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -1
- data/README.md +15 -0
- data/docs/ecs-task-notification.md +24 -0
- data/examples/put-ecs-container-status-to-s3/index.js +40 -0
- data/examples/put-ecs-container-status-to-s3/package.json +7 -0
- data/lib/hako/schedulers/ecs.rb +34 -3
- data/lib/hako/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f81c77dc43aeaaf63eaf41066e2988b3402a7ab4
|
4
|
+
data.tar.gz: e7d8de4361f7b24ca5aa1b8a3dfa8a9de9cdfaed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ae3dd38326c2d3533f18b774b70282f93d1338d8b2a17bfd7383d2bcf62d2b2cc48fa2918c9051ba0a3ca59ad62de84a167d65f35be9c18f074ef953a64128f5
|
7
|
+
data.tar.gz: f559ea0ab2183dfd04f324f9507475e4887fe1a8f130c214a3b1270c52adbebdcfd7310f6b5f19bc12cfd46c1abf286fe239642f8f3f9641b66a8a49fdb069d5
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,10 @@
|
|
1
|
-
# 1.
|
1
|
+
# 1.7.0 (2017-08-29)
|
2
|
+
## New features
|
3
|
+
- Add experimental `autoscaling_topic_for_oneshot` option to ECS scheduler
|
4
|
+
- It publishes scale-out request to SNS topic.
|
5
|
+
- Administrators is expected to receive SNS event and initiate scale-out.
|
6
|
+
|
7
|
+
# 1.6.2 (2017-07-11)
|
2
8
|
## Bug fixes
|
3
9
|
- Exclude unusable instances when checking remaining capacity
|
4
10
|
|
data/README.md
CHANGED
@@ -50,6 +50,21 @@ I, [2016-05-02T13:07:12.959116 #10961] INFO -- : Updated service: arn:aws:ecs:a
|
|
50
50
|
I, [2016-05-02T13:08:27.280686 #10961] INFO -- : Deployment completed
|
51
51
|
```
|
52
52
|
|
53
|
+
Run oneshot command.
|
54
|
+
|
55
|
+
```
|
56
|
+
% hako oneshot examples/hello.yml date
|
57
|
+
I, [2017-07-18T18:14:06.099763 #6627] INFO -- : Task definition isn't changed: arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:task-definition/hello-oneshot:32
|
58
|
+
I, [2017-07-18T18:14:06.147062 #6627] INFO -- : Started task: arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:task/01234567-89ab-cdef-0123-456789abcdef
|
59
|
+
I, [2017-07-18T18:14:06.193860 #6627] INFO -- : Container instance is arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:container-instance/01234567-89ab-cdef-0123-456789abcdef (i-0123456789abcdef0)
|
60
|
+
I, [2017-07-18T18:14:37.826389 #6627] INFO -- : Started at 2017-07-18 18:14:37 +0900
|
61
|
+
I, [2017-07-18T18:14:37.826482 #6627] INFO -- : Stopped at 2017-07-18 18:14:37 +0900 (reason: Essential container in task exited)
|
62
|
+
I, [2017-07-18T18:14:37.826520 #6627] INFO -- : Oneshot task finished
|
63
|
+
I, [2017-07-18T18:14:37.826548 #6627] INFO -- : app has stopped with exit_code=0
|
64
|
+
```
|
65
|
+
|
66
|
+
See also [docs/ecs-task-notification.md](docs/ecs-task-notification.md).
|
67
|
+
|
53
68
|
## Front image
|
54
69
|
The front container receives these environment variables.
|
55
70
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# ECS task notification
|
2
|
+
In ECS scheduler, `hako oneshot` supports multiple methods of detecting task finish.
|
3
|
+
|
4
|
+
## ecs:DescribeTasks (default)
|
5
|
+
Use [DescribeTasks](http://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_DescribeTasks.html) API to get the task status.
|
6
|
+
This method can be used without any preparation or configuration, but the DescribeTasks API can return "Rate exceeded" error when there's several running `hako oneshot` processes.
|
7
|
+
|
8
|
+
## s3:GetObject
|
9
|
+
Amazon ECS has integration with Amazon CloudWatch Events. The integration notifies ECS task state changes to AWS Lambda, Amazon SNS, Amazon SQS, and so on.
|
10
|
+
http://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs_cwe_events.html#ecs_task_events
|
11
|
+
|
12
|
+
Amazon S3 is a good storage for polling, so connecting CloudWatch Events to AWS Lambda and put the payload to S3 is more scalable than ecs:DescribeTasks.
|
13
|
+
|
14
|
+
The example implementation of AWS Lambda can be found in [../examples/put-ecs-container-status-to-s3](../examples/put-ecs-container-status-to-s3) directory.
|
15
|
+
|
16
|
+
To enable task notification with S3, you have to configure scheduler in YAML.
|
17
|
+
|
18
|
+
```yaml
|
19
|
+
scheduler:
|
20
|
+
type: ecs
|
21
|
+
oneshot_notification_prefix: 's3://ecs-task-notifications/task_statuses?region=ap-northeast-1'
|
22
|
+
```
|
23
|
+
|
24
|
+
It uses ecs-task-notifications bucket in ap-northeast-1 region.
|
@@ -0,0 +1,40 @@
|
|
1
|
+
const AWS = require('aws-sdk');
|
2
|
+
|
3
|
+
const BUCKET = 'ecs-task-notifications';
|
4
|
+
|
5
|
+
exports.handler = (event, context, callback) => {
|
6
|
+
const s3 = new AWS.S3();
|
7
|
+
// console.log(JSON.stringify(event, null, 2));
|
8
|
+
const taskArn = event.detail.taskArn;
|
9
|
+
if (event.detail.lastStatus === 'RUNNING' && event.detail.containers.every((container) => container.lastStatus === 'RUNNING')) {
|
10
|
+
console.log(`${taskArn} started`);
|
11
|
+
s3.putObject({
|
12
|
+
Bucket: BUCKET,
|
13
|
+
Key: `task_statuses/${taskArn}/started.json`,
|
14
|
+
Body: JSON.stringify(event),
|
15
|
+
}, (err, data) => {
|
16
|
+
if (err) {
|
17
|
+
console.log(err);
|
18
|
+
callback(err);
|
19
|
+
} else {
|
20
|
+
callback(null, 'Started');
|
21
|
+
}
|
22
|
+
});
|
23
|
+
} else if (event.detail.lastStatus === 'STOPPED') {
|
24
|
+
console.log(`${taskArn} stopped`);
|
25
|
+
s3.putObject({
|
26
|
+
Bucket: BUCKET,
|
27
|
+
Key: `task_statuses/${taskArn}/stopped.json`,
|
28
|
+
Body: JSON.stringify(event),
|
29
|
+
}, (err, data) => {
|
30
|
+
if (err) {
|
31
|
+
console.log(err);
|
32
|
+
callback(err);
|
33
|
+
} else {
|
34
|
+
callback(null, 'Stopped');
|
35
|
+
}
|
36
|
+
});
|
37
|
+
} else {
|
38
|
+
callback(null, 'Skipped');
|
39
|
+
}
|
40
|
+
};
|
data/lib/hako/schedulers/ecs.rb
CHANGED
@@ -38,6 +38,10 @@ module Hako
|
|
38
38
|
@autoscaling = EcsAutoscaling.new(options.fetch('autoscaling'), dry_run: @dry_run)
|
39
39
|
end
|
40
40
|
@autoscaling_group_for_oneshot = options.fetch('autoscaling_group_for_oneshot', nil)
|
41
|
+
@autoscaling_topic_for_oneshot = options.fetch('autoscaling_topic_for_oneshot', nil)
|
42
|
+
if @autoscaling_topic_for_oneshot && !@autoscaling_group_for_oneshot
|
43
|
+
validation_error!('autoscaling_group_for_oneshot must be set when autoscaling_topic_for_oneshot is set')
|
44
|
+
end
|
41
45
|
@oneshot_notification_prefix = options.fetch('oneshot_notification_prefix', nil)
|
42
46
|
@deployment_configuration = {}
|
43
47
|
%i[maximum_percent minimum_healthy_percent].each do |key|
|
@@ -638,7 +642,7 @@ module Hako
|
|
638
642
|
|
639
643
|
# @param [Aws::ECS::Types::Task] task
|
640
644
|
# @return [Hash<String, Aws::ECS::Types::Container>]
|
641
|
-
#
|
645
|
+
# Get stopped container status from S3.
|
642
646
|
# The advantage is scalability; ecs:DescribeTasks is heavily
|
643
647
|
# rate-limited, but s3:GetObject is much more scalable.
|
644
648
|
# The JSON is supposed to be stored from Amazon ECS Event Stream.
|
@@ -854,8 +858,6 @@ module Hako
|
|
854
858
|
raise "Unable to find rollback target. #{task_definition.task_definition_arn} is INACTIVE?"
|
855
859
|
end
|
856
860
|
|
857
|
-
MIN_ASG_INTERVAL = 1
|
858
|
-
MAX_ASG_INTERVAL = 120
|
859
861
|
# @param [Aws::ECS::Types::TaskDefinition] task_definition
|
860
862
|
# @return [Boolean] true if the capacity is reserved
|
861
863
|
def on_no_tasks_started(task_definition)
|
@@ -863,6 +865,35 @@ module Hako
|
|
863
865
|
return false
|
864
866
|
end
|
865
867
|
|
868
|
+
if @autoscaling_topic_for_oneshot
|
869
|
+
try_scale_out_with_sns(task_definition)
|
870
|
+
else
|
871
|
+
try_scale_out_with_as(task_definition)
|
872
|
+
end
|
873
|
+
end
|
874
|
+
|
875
|
+
RUN_TASK_INTERVAL = 10
|
876
|
+
def try_scale_out_with_sns(task_definition)
|
877
|
+
required_cpu, required_memory = task_definition.container_definitions.inject([0, 0]) { |(cpu, memory), d| [cpu + d.cpu, memory + d.memory] }
|
878
|
+
@hako_task_id ||= SecureRandom.uuid
|
879
|
+
message = JSON.dump(
|
880
|
+
group_name: @autoscaling_group_for_oneshot,
|
881
|
+
cluster: @cluster,
|
882
|
+
cpu: required_cpu,
|
883
|
+
memory: required_memory,
|
884
|
+
hako_task_id: @hako_task_id,
|
885
|
+
)
|
886
|
+
Hako.logger.info("Unable to start tasks. Publish message to #{@autoscaling_topic_for_oneshot}: #{message}")
|
887
|
+
sns_client = Aws::SNS::Client.new
|
888
|
+
resp = sns_client.publish(topic_arn: @autoscaling_topic_for_oneshot, message: message)
|
889
|
+
Hako.logger.info("Sent message_id=#{resp.message_id}")
|
890
|
+
sleep(RUN_TASK_INTERVAL)
|
891
|
+
true
|
892
|
+
end
|
893
|
+
|
894
|
+
MIN_ASG_INTERVAL = 1
|
895
|
+
MAX_ASG_INTERVAL = 120
|
896
|
+
def try_scale_out_with_as(task_definition)
|
866
897
|
autoscaling = Aws::AutoScaling::Client.new
|
867
898
|
interval = MIN_ASG_INTERVAL
|
868
899
|
Hako.logger.info("Unable to start tasks. Start trying scaling out '#{@autoscaling_group_for_oneshot}'")
|
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: 1.
|
4
|
+
version: 1.7.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: 2017-
|
11
|
+
date: 2017-08-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk
|
@@ -143,6 +143,7 @@ files:
|
|
143
143
|
- Rakefile
|
144
144
|
- bin/console
|
145
145
|
- bin/setup
|
146
|
+
- docs/ecs-task-notification.md
|
146
147
|
- examples/create_aws_cloud_watch_logs_log_group.yml
|
147
148
|
- examples/front.yml
|
148
149
|
- examples/hello-autoscaling-group.yml
|
@@ -153,6 +154,8 @@ files:
|
|
153
154
|
- examples/hello-privileged-app.yml
|
154
155
|
- examples/hello.env
|
155
156
|
- examples/hello.yml
|
157
|
+
- examples/put-ecs-container-status-to-s3/index.js
|
158
|
+
- examples/put-ecs-container-status-to-s3/package.json
|
156
159
|
- exe/hako
|
157
160
|
- hako.gemspec
|
158
161
|
- lib/hako.rb
|