こんにちは
インフラの戸田です。
ブログのタイトルで(Autoscaling編)と言っていますが、そんなに続かないと思います(どなたか続いて)
では、本題にいきます。
経緯
とあるサービスのEC2をAutoscalingを使った構成に変更しました。
Autoscalingに変更して数日たったある日 「Autoscalingのグループの設定変えるの手順めんどくさいね」という話が隣の席から聞こえました。(たぶん)
最初の手順は、
- AMIの作成
- インスタンス作成
- 設定の変更はansibleで実行
- その後AMIを作成
- 起動設定を作成
- インスタンスイメージの選択
- IAM Roleの設定
- UserDataの設定
- セキュリティグループの設定
- Autoscalingグループの変更
- どのVPC、どのサブネットに置くか
- ALBの紐づけ
- スケーリングポリシーの設定
- タグの設定
一見少ないように思う方もいるかもしれませんが、staging環境とproduction環境があるため、二回同じようなことをしなくてはなりません。(この時点でめんどくさい)
また、頻繁にインスタンスを入れ替えることになった際は、上記の手順を何度も繰り返さないといけません。(想像したくない)
調べると、Cloudformaitonで更新する時は、Update Policyという設定があります。
Update Policyとは、RollingUpdateやReplaceUpdateといった手法でリソースに対する更新を処理する方法を指定する属性です。
詳しくは公式リンク を見て頂けると幸いです。手動では設定することができないことがわかりました。
CloudFormationの情報を話すと「コード化して、運用を楽にしよう。」ということになりました!
使うもの
- gitlab-ci.yml
- CloudFormation
- AWSのアクセスキーとシークレットキー
- AMIID
- PRIVATE_TOKEN
事前準備
AWSのアクセスキーとシークレットキー
IAMからアクセスキーとシークレットキーを作成し、GitLab-CIのVariablesに登録します。
GitLabのPRIVATE_TOKENの取得
APIの権限が付いたPersonal access tokenを作成します。
作成したトークンをAWSアクセスキー同様GitLab-CIのVariablesに登録します。
やること
今回は上記に書いた手順の2(起動設定を作成)と3(Autoscalingグループの変更)をCloudFormationで行います。
※1のAMI作成に関してはPackerを使って作成しています。こちらもGitLab-Ciを使って、自動で生成していますが、今回は一部の処理のみ紹介します。
更にGitLab-CIを使って、特定のブランチにMergeするとCloudFormationを実行して、インスタンスの入れ替えを行います。
フロー
フロー図
例えば
- nginxのconfigファイルを変更
- Masterにマージ
- AMIを作成(Staging)
- cfnでインスタンスの切り替え(Staging)
- 問題ないか確認
- AMIを作成(Production)
- cfnでインスタンスの切り替え(Production)
といったフローになります。
AMIIDについて
上記で書いたPackerの一部の処理について紹介します。
PackerでAMIを作成した際、AMIIDをPacker自身は保持をしています。
その保持したAMIIDをこの後行うCloudFormationで使うため、GitLab-CI内でGitLab-CIのVariablesに変数として登録します。
gitlab-ci.ymlでの処理
- curl --request PUT --header PRIVATE-TOKEN:$PRIVATE_TOKEN "https://gitlab.example.com/api/v4/projects/<projectID>/variables/STAGING_AMIID" --form "value=$AMIID"
CloudFormation
実行するCloudFormationに関しては以下をご覧ください
CloudFormation (抜粋)
--- AWSTemplateFormatVersion: 2010-09-09 Parameters: AZ1: Type: AWS::EC2::AvailabilityZone::Name Description: select availability zone AZ2: Type: AWS::EC2::AvailabilityZone::Name Description: select availability zone IAMRole: Type: String Description: select IAMRole Arn WebInstanceType: Description: WebServer EC2 instance type Type: String ConstraintDescription: must be a valid EC2 instance type. WebAMIID: Type: AWS::EC2::Image::Id Description: AMI ID for Springboard Instance WebInstanceMaxSize: Type: String Description: AutoScaling Instance Max Size WebInstanceMinSize: Type: String Description: AutoScaling Instance Min Size WebHealthCheckGracePeriod: Type: String Description: AutoScaling Instance HealthCheckGracePeriod KeyName: Description: Name of an existing EC2 KeyPair to enable RDP access to the instances Type: 'AWS::EC2::KeyPair::KeyName' ConstraintDescription: must be the name of an existing EC2 KeyPair. ProjectName: Type: String Description: Project name for tag Stage: Type: String WebSubnetAID: Type: AWS::EC2::Subnet::Id Description: select SubnetID_A WebSubnetCID: Type: AWS::EC2::Subnet::Id Description: select SubnetID_C TargetGroupArn: Type: String Description: select TargetGroup WebSecurityGroup: Type: AWS::EC2::SecurityGroup::Id Description: select securitygroup Resources: WebEC2InstanceLaunchConfiguration: Type: AWS::AutoScaling::LaunchConfiguration Properties: ImageId: !Ref WebAMIID InstanceType: !Ref WebInstanceType IamInstanceProfile: !Ref IAMRole KeyName: !Ref KeyName SecurityGroups: - !Ref WebSecurityGroup WebEC2InstanceAutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: AvailabilityZones: - !Ref AZ1 - !Ref AZ2 DesiredCapacity: !Ref WebInstanceMinSize HealthCheckGracePeriod: !Ref WebHealthCheckGracePeriod HealthCheckType: ELB LaunchConfigurationName: !Ref WebEC2InstanceLaunchConfiguration MaxSize: !Ref WebInstanceMaxSize MinSize: !Ref WebInstanceMinSize TargetGroupARNs: - !Ref TargetGroupArn Tags: - Key: environment Value: !Ref Stage PropagateAtLaunch: 'true' - Key: role Value: web PropagateAtLaunch: 'true' VPCZoneIdentifier: - !Ref WebSubnetAID - !Ref WebSubnetCID CreationPolicy: ResourceSignal: Timeout: PT20M UpdatePolicy: AutoScalingReplacingUpdate: WillReplace: 'true' ScaleOutPolicy: Type: AWS::AutoScaling::ScalingPolicy Properties: AdjustmentType: ChangeInCapacity AutoScalingGroupName: !Ref WebEC2InstanceAutoScalingGroup PolicyType: StepScaling StepAdjustments: - ScalingAdjustment: 1 MetricIntervalLowerBound: 0 MetricIntervalUpperBound: 30.0 - ScalingAdjustment: 1 MetricIntervalLowerBound: 30.0 ScaleInPolicy: Type: AWS::AutoScaling::ScalingPolicy Properties: AdjustmentType: PercentChangeInCapacity AutoScalingGroupName: !Ref WebEC2InstanceAutoScalingGroup PolicyType: SimpleScaling ScalingAdjustment: -50 CPUAlarmHigh: Type: AWS::CloudWatch::Alarm Properties: EvaluationPeriods: 1 Statistic: Average Threshold: 60 Period: 300 AlarmActions: - !Ref ScaleOutPolicy Namespace: AWS/EC2 Dimensions: - Name: AutoScalingGroupName Value: !Ref WebEC2InstanceAutoScalingGroup ComparisonOperator: GreaterThanOrEqualToThreshold MetricName: CPUUtilization CPUAlarmLow: Type: AWS::CloudWatch::Alarm Properties: EvaluationPeriods: 1 Statistic: Average Threshold: 10 Period: 300 AlarmActions: - !Ref ScaleInPolicy Namespace: AWS/EC2 Dimensions: - Name: AutoScalingGroupName Value: !Ref WebEC2InstanceAutoScalingGroup ComparisonOperator: LessThanOrEqualToThreshold MetricName: CPUUtilization
このCloudFormationでは、CPUの使用率をトリガーにして増減するAutoscalingになります。
例えば、CPU使用率が80%を超えた場合、一台インスタンスを追加する。
もし、CPU使用率が10%を下回った場合、稼働しているインスタンスの半分を削除する。
パラメーターに関して、変更可能なcloudformatinになります。
※削除している部分は、UserDataの記述になります。
GitLab-CI
gitlab-ci.ymlでCloudFormationを実行している部分のみ抜粋しています。
また、Cloudformatinを実行するシェルに関しては、Autoscalingに合わせた仕様のため省略させていただきます。
.gitlab-ci.yml(抜粋)
--- stages: - depoly update_autoscaling_staging: stage: depoly image: python:latest before_script: - apt-get update - apt-get install -y jq - pip install awscli script: - echo $STAGING_AMI - "aws cli をラッピングしたシェルを使ってデプロイをします。" only: - release-cfn-staging update_autoscaling_productiom: stage: depoly image: python:latest before_script: - apt-get update - apt-get install -y jq - pip install awscli script: - echo $PRODUCTION_AMI -"aws cli をラッピングしたシェルを使ってデプロイをします。" only: - release-cfn-production
まとめ
GitLabとInfrastructure as Codeを組み合わせすると運用が楽になります!!
Infrastructure as Codeはよきものです
以上となります。 最後までご覧いただきありがとうございます。