Created
July 22, 2020 11:21
-
-
Save oz-urabe/208289a6de7f76ccf7c3709b5b83e760 to your computer and use it in GitHub Desktop.
autoscaling group に running 中の EC2 インスタンスから 自動で起動設定をAttachするスクリプト
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env php | |
<?php | |
$list = [ | |
'stage' => [ | |
'web' => [ | |
'namelike' => 'stage-web', | |
'autoscaling_group' => 'stage-web-autoscaling', | |
'launch_namelike' => 'stage-web-launch', | |
'instance_type' => 't3.micro', | |
'key_name' => 'stage', | |
'security_groups' => 'sg-0dce82de47bea0926', | |
'iam_instance_profile' => 'stage-web-role', | |
], | |
'admin-web' => [ | |
'namelike' => 'stage-admin-web', | |
'autoscaling_group' => 'stage-admin-web-autoscaling', | |
'launch_namelike' => 'stage-admin-web-launch', | |
'instance_type' => 't3.micro', | |
'key_name' => 'stage', | |
'security_groups' => 'sg-0dce82de47bea0926', | |
'iam_instance_profile' => 'stage-admin-web-role', | |
], | |
'pointback' => [ | |
'namelike' => 'stage-pointback', | |
'autoscaling_group' => 'stage-pointback-autoscaling', | |
'launch_namelike' => 'stage-pointback-launch', | |
'instance_type' => 't3.micro', | |
'key_name' => 'stage', | |
'security_groups' => 'sg-0dce82de47bea0926', | |
'iam_instance_profile' => 'stage-pointback-role', | |
], | |
'batch' => [ | |
'namelike' => 'stage-batch', | |
'autoscaling_group' => 'stage-batch-autoscaling', | |
'launch_namelike' => 'stage-batch-launch', | |
'instance_type' => 't3.micro', | |
'key_name' => 'stage', | |
'security_groups' => 'sg-0efd262caed4fdae6', | |
'iam_instance_profile' => 'stage-batch-role', | |
], | |
], | |
'prod' => [ | |
'web' => [ | |
'namelike' => 'prod-web', | |
'autoscaling_group' => 'prod-web-autoscaling', | |
'launch_namelike' => 'prod-web-launch', | |
'instance_type' => 'm5.large', | |
'key_name' => 'prod', | |
'security_groups' => 'sg-8faef0d139d0af', | |
'iam_instance_profile' => 'prod-web-role', | |
], | |
'admin-web' => [ | |
'namelike' => 'prod-admin-web', | |
'autoscaling_group' => 'prod-admin-web-autoscaling', | |
'launch_namelike' => 'prod-admin-web-launch', | |
'instance_type' => 't3.micro', | |
'key_name' => 'prod', | |
'security_groups' => 'sg-8faef0d139d0af', | |
'iam_instance_profile' => 'prod-admin-web-role', | |
], | |
'pointback' => [ | |
'namelike' => 'prod-pointback', | |
'autoscaling_group' => 'prod-pointback-autoscaling', | |
'launch_namelike' => 'prod-pointback-launch', | |
'instance_type' => 'm5.large', | |
'key_name' => 'prod', | |
'security_groups' => 'sg-8faef0d139d0af', | |
'iam_instance_profile' => 'prod-pointback-role', | |
], | |
'batch' => [ | |
'namelike' => 'prod-batch', | |
'autoscaling_group' => 'prod-batch-autoscaling', | |
'launch_namelike' => 'prod-batch-launch', | |
'instance_type' => 'm5.large', | |
'key_name' => 'prod', | |
'security_groups' => 'sg-0d5dd968bbe19cbf8', | |
'iam_instance_profile' => 'prod-batch-role', | |
], | |
], | |
]; | |
$cmd = new Command('my_normal_log', 'my_error_log'); | |
if ($argc !== 3) { | |
my_error_log('引数は2つ指定してください。第一引数-ENV stage, prod 第二引数-環境名 web, admin-web, pointback, batch. or all', true); | |
} | |
$env = strtolower($argv[1]); | |
$resource = strtolower($argv[2]); | |
if (!isset($list[$env])) { | |
my_error_log(' 定義されていない ENV です $env="'.$env.'"', true); | |
} | |
if (!isset($list[$env][$resource]) && $resource !== 'all') { | |
my_error_log(' 定義されていない 環境 です $resource="'.$resource.'"', true); | |
} | |
foreach (($resource === 'all' ? $list[$env] : [$resource => $list[$env][$resource]]) as $name => $params) { | |
$instanceId = $ymd = $command = $amiId = $newLcName = $launchList = $lcName = null; | |
$command =<<<'COMMAND' | |
aws ec2 describe-instances --region ap-northeast-1 \ | |
| jq -r '.Reservations[].Instances[] | select(.Tags[].Key == "aws:autoscaling:groupName") | select(.Tags[].Value == "%s") | select(.State.Name == "running") |.InstanceId'|head -1 | |
COMMAND; | |
$command = sprintf($command, $params['autoscaling_group']); | |
my_normal_log('該当インスタンスいずれか一つ取得'); | |
$instanceId = trim($cmd->run($command)); | |
my_normal_log('command result .. '.$instanceId); | |
if (!$instanceId) { | |
my_error_log('アクティブなインスタンスがありません'); | |
continue; | |
} | |
$ymd = date('YmdHis'); | |
$command =<<<'COMMAND' | |
aws ec2 create-image --region ap-northeast-1 --instance-id %s --no-reboot --name %s | jq -r ".ImageId" | |
COMMAND; | |
$command = sprintf($command, $instanceId, sprintf('%s_%d', $params['namelike'], $ymd)); | |
my_normal_log('AMI 作成'); | |
$amiId = trim($cmd->run($command)); | |
my_normal_log('command result .. '.$amiId); | |
$command =<<<'COMMAND' | |
aws ec2 create-tags --region ap-northeast-1 --resources %s \ | |
--tags Key=Name,Value=%s Key=Type,Value=autoscaling Key=Environment,Value=%s | |
COMMAND; | |
$command = sprintf($command, $amiId, sprintf('%s_%d', $params['namelike'], $ymd), $env); | |
my_normal_log('AMI Tagging'); | |
$cmd->run($command); | |
my_normal_log('command result .. '.$amiId); | |
$command =<<<'COMMAND' | |
aws ec2 wait image-available --region ap-northeast-1 --image-ids %s | |
COMMAND; | |
$command = sprintf($command, $amiId); | |
my_normal_log('AMI 作成完了待ち'); | |
$cmd->run($command); | |
$newLcName = sprintf('%s-%s', $params['launch_namelike'], $ymd); | |
$command =<<<'COMMAND' | |
aws autoscaling create-launch-configuration \ | |
--region ap-northeast-1 \ | |
--launch-configuration-name %s \ | |
--image-id %s \ | |
--instance-type %s \ | |
--key-name %s \ | |
--security-groups %s \ | |
--instance-monitoring Enabled=true \ | |
--iam-instance-profile %s | |
COMMAND; | |
$command = sprintf( | |
$command, | |
$newLcName, | |
$amiId, | |
$params['instance_type'], | |
$params['key_name'], | |
$params['security_groups'], | |
$params['iam_instance_profile'] | |
); | |
my_normal_log('起動設定 作成'); | |
$cmd->run($command); | |
$command =<<<'COMMAND' | |
aws autoscaling update-auto-scaling-group --region ap-northeast-1 \ | |
--auto-scaling-group-name %s \ | |
--launch-configuration-name %s | |
COMMAND; | |
$command = sprintf($command, $params['autoscaling_group'], $newLcName); | |
my_normal_log('autoscaling group 更新'); | |
$cmd->run($command); | |
$command =<<<'COMMAND' | |
aws autoscaling describe-launch-configurations --region ap-northeast-1 --output json | |
COMMAND; | |
$result = trim($cmd->run($command)); | |
$launchList = json_decode($result, true); | |
if (($code = json_last_error()) !== JSON_ERROR_NONE) { | |
my_error_log('missed. json_decode. raw: '.$result.', code: '.$code); | |
continue; | |
} | |
foreach ($launchList['LaunchConfigurations'] as $launch) { | |
$needle = strtolower($params['launch_namelike']); | |
$lcName = strtolower($launch['LaunchConfigurationName']); | |
if (0 !== strpos($lcName, $needle)) { | |
continue; | |
} | |
if ($lcName === $newLcName) { | |
continue; | |
} | |
$command =<<<'COMMAND' | |
aws autoscaling delete-launch-configuration --region ap-northeast-1 --launch-configuration-name %s | |
COMMAND; | |
$command = sprintf($command, $lcName); | |
my_normal_log($lcName. ' に関連する古い設定を削除します'); | |
$cmd->run($command); | |
$command =<<<'COMMAND' | |
aws ec2 deregister-image --image-id %s | |
COMMAND; | |
$command = sprintf($command, $launch['ImageId']); | |
my_normal_log($lcName. ' に関連する古い AMI の登録を解除します . amiId='.$launch['ImageId']); | |
$cmd->run($command); | |
} | |
} | |
// ---- define function class. | |
class Command | |
{ | |
public function __construct($logCallback = null, $errorCallback = null) | |
{ | |
$this->logCallback = $logCallback; | |
$this->errorCallback = $errorCallback; | |
} | |
public function run($command) | |
{ | |
$this->log(sprintf('execute command "%s"', $command)); | |
$descriptorspec = array( | |
1 => array('pipe', 'w'), // stdout | |
2 => array('pipe', 'w'), // stderr | |
); | |
$process = proc_open($command, $descriptorspec, $pipes); | |
if (!is_resource($process)) { | |
$this->errorLog('Unable to execute the command.'); | |
throw new \RuntimeException('Unable to execute the command.'); | |
} | |
stream_set_blocking($pipes[1], false); | |
stream_set_blocking($pipes[2], false); | |
$output = ''; | |
$err = ''; | |
while (!feof($pipes[1]) || !feof($pipes[2])) { | |
foreach ($pipes as $key => $pipe) { | |
// max 10 M | |
if (!$line = fread($pipe, 1024 * 1024 * 10)) { | |
continue; | |
} | |
if (1 == $key) { | |
// stdout | |
$output .= $line; | |
} else { | |
// stderr | |
$err .= $line; | |
} | |
} | |
usleep(100000); | |
} | |
if ($err) { | |
$this->errorLog($err); | |
} | |
fclose($pipes[1]); | |
fclose($pipes[2]); | |
if (($return = proc_close($process)) > 0) { | |
$this->errorLog('Problem executing command. code: '.$return); | |
throw new \RuntimeException('Problem executing command.', $return); | |
} | |
return $output; | |
} | |
public function log($log) | |
{ | |
if (!is_callable($this->logCallback)) { | |
return false; | |
} | |
call_user_func($this->logCallback, $log); | |
} | |
public function errorLog($log) | |
{ | |
if (!is_callable($this->errorCallback)) { | |
error_log($log); | |
return false; | |
} | |
call_user_func($this->errorCallback, $log); | |
} | |
} | |
function my_normal_log($message) | |
{ | |
echo date('[Y-m-d H:i:s] '), $message, PHP_EOL; | |
} | |
function my_error_log($message, $isStop = false) | |
{ | |
fputs(STDERR, date('[Y-m-d H:i:s] ').$message.PHP_EOL); | |
if ($isStop) { | |
exit(1); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment