Skip to content

Instantly share code, notes, and snippets.

@oz-urabe
Created July 22, 2020 11:21
Show Gist options
  • Save oz-urabe/208289a6de7f76ccf7c3709b5b83e760 to your computer and use it in GitHub Desktop.
Save oz-urabe/208289a6de7f76ccf7c3709b5b83e760 to your computer and use it in GitHub Desktop.
autoscaling group に running 中の EC2 インスタンスから 自動で起動設定をAttachするスクリプト
#!/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