20210623のAWSに関する記事は17件です。

CloudWatch Logs InsightにてAPI Gatewayのアクセスログ用のクエリを書いてみた

背景 API Gatewayを外部からの窓口とするシステムにて、システムへのアクセス数を集計する必要があったので、CloudWatchに出力しているアクセスログをインプットにAPI Gatewayへのリクエスト数を集計することにした。 アクセスログは、API にアクセスしたユーザーと、呼び出し元が API にアクセスした方法を記録するログで、アクセスが発生する度に以下の形式のログレコードが生成される。 アクセスログの形式 { "requestId":"8d2f5138-019f-449c-bde7-432ff3cb49a1", "ip": "103.4.xxx.xxx", "caller":"-", "user":"-", "requestTime":"13/Feb/2021:07:45:36 +0000", "httpMethod":"GET", "resourcePath":"/hello", "status":"200", "protocol":"HTTP/1.1", "responseLength":"26" } CloudWatchのCloudWatch Logs Insights という機能を利用すると、特定のロググループに対してクエリを実行してログを検索/分析することができる。 やったこと CloudWatch Logs Insightsにて以下の手順でクエリを実行し、結果を出力した。 1. 分析したい期間を指定 2. 分析したいAPI Gatewayのアクセスログのロググループを指定 3. 実行したいクエリを入力して「クエリの実行」をクリック 4. クエリの結果を「結果をエクスポート」から出力 今回は1日ごとのリクエスト数を集計したかったので、以下のクエリを用意した。 fields @message | stats count(*) as count by substr(requestTime,0,11) as date | limit 100 クエリの内容 「fields」ではログイベントから収集したいフィールドを指定。利用したいアクセスログのフィールドは@messagesフィールドだったので「fields @message」と指定 「stats」は集約統計用のコマンド。今回使った「count()」などがサポートされている 「count(*) as count by substr(requestTime,0,11) as date」の部分は、アクセスログのrequestTime項目(例:13/Feb/2021:07:45:36 +0000)の先頭から11文字(13/Feb/2021 の部分)をdateと名付け、dateが同じであるログイベントごとにログイベント数をcountという項目名で集約するという意味。 「limit」では表示したい件数を指定。10000まで指定可能 参考 CloudWatch Logs Insights クエリ構文
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSの勉強してるときよく見る単語集その②

 はじめに その①の続きになります! 内容はざっくりです! よろしくお願いします!(。・ω・)ノ゙  プロキシサーバー  プロキシサーバーとはインターネットへのアクセスを代理で行うサーバーのこと。通常はパソコンやモバイル端末を経由して直接Webサイトへアクセスし、サーバーがデータをブラウザに返すことで画面にサイトが表示される。    これに対してプロキシサーバーを使用するとブラウザで直接Webサイトにアクセスせずにプロキシサーバーにアクセスし、代わりにプロキシサーバーがサイトにアクセスし画面にサイトを表示してくれる。  スキーム  スキームとは体系的な計画・計画を伴う枠組み・体系的な構想・基本的な仕組みなどの意味を持つ英単語。  単純な工程表や組織図のようなものではなく、関係する人や組織、モノ、システムなどの機能や役割、権利や権限、相互の関連性などを挙げ、また、これらの要素間のお金や情報、指示や手続きのなどの流れを体系立てて記述したものを意味する。複雑な場合は図で表すことも多い。  サーバレス  サーバレスとはその言葉の通りサーバーを持たないという考え。サーバーを持たないことでサーバーの管理を不要にし、上のレイヤーのみに集中するシステム開発を実現するという概念。  クラウドの特有の考え方  プロセス  プロセスとは稼働しているプログラミングの一つ一つ、または「工程」「手順」のこと  SSH  SSHとはネットワークを介して別のコンピューターにログインして操作するためのソフトウェアの一つ。  通信が暗号化されるためにインターネットなどを経由して安全にアクセスすることができる。  SSH通信とかね  ハイパーバイザー  ハイパーバイザーとはサーバーの仮想化などで利用されるコンピューターを仮想化するための制御プログラム  代表的なハイパーバイザーとしては、VMwareのvSphereやマイクロソフトのHyper-V、Linuxで使われるKVM(Kernel-based Virtual Machine)などがある。  ハイパーバイザーには、ハードウェア上で直接動作するネイティブハイパーバイザーと、OS上で実行されるホストハイパーバイザーがあります。性能面で優れているのはハードウェア上で直接実行するネイティブハイパーバイザーで、仮想化されたサーバー上でシステムを実行するなど、エンタープライズ用途で広く利用されています。  ITガバナンス  ITガバナンスとは企業などが経営方針にそってIT戦略を策定し、情報システムの導入や運用を組織的に管理・統制する仕組み。  経済産業省では「ITガバナンスとは経営陣がステークホルダのニーズに基づき、組織の価値を高めるために実践する行動であり、情報システムのあるべき姿を示す情報システム戦略の策定及び実現に必要となる組織能力である」と定義している。  おわり  今まで何となくで流してきた単語の意味も少しづつ分かってきました。また明日から仕事がんばろ! (。・ω・)ノ゙バイバイ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

internalのNLBとログ出力用のS3バケットを構築するCloudformaitonの例

private-nlb-httpsという名前のNLBと、ログ出力用のS3バケットです。これを元に設定作るようにシンプルにしてあります。 HTTPSで受けてバックエンドは80で受ける設定です 証明書はACMにアップロード済みを想定しています NLBは2つのサブネットにデプロイすることを想定してたパターンです S3のバケットポリシーはこちらの公式ドキュメントを参考にしています --- AWSTemplateFormatVersion: "2010-09-09" Parameters: NLBName: Type: String NLBTargetGroupName: Type: String VpcId: Type: AWS::EC2::VPC::Id SubnetIdA: Type: AWS::EC2::Subnet::Id IpAddressA: Type: String AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3}) SubnetIdC: Type: AWS::EC2::Subnet::Id IpAddressC: Type: String AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3}) LogBucketName: Type: String ListenerCertificateArn: Type: String Default: arn:aws:acm:ap-northeast-1:123456789012:certificate/xxxxxxxxx Resources: LogBucket: Type: AWS::S3::Bucket Properties: BucketName: !Ref LogBucketName BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 PublicAccessBlockConfiguration: BlockPublicAcls: "True" BlockPublicPolicy: "True" IgnorePublicAcls: "True" RestrictPublicBuckets: "True" # Refs : https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/network/load-balancer-access-logs.html#access-logging-bucket-requirements LogBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: !Ref LogBucketName PolicyDocument: Version: "2012-10-17" Statement: - Sid: AWSLogDeliveryWrite Effect: Allow Principal: Service: delivery.logs.amazonaws.com Action: s3:PutObject Resource: - !Sub arn:aws:s3:::${LogBucket}/AWSLogs/${AWS::AccountId}/* Condition: StringEquals: s3:x-amz-acl: bucket-owner-full-control - Sid: AWSLogDeliveryAclCheck Effect: Allow Principal: Service: delivery.logs.amazonaws.com Action: s3:GetBucketAcl Resource: - !Sub arn:aws:s3:::${LogBucket} InternalNLB: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: !Ref NLBName Type: network Scheme: "internal" LoadBalancerAttributes: - Key: access_logs.s3.enabled Value: true - Key: access_logs.s3.bucket Value: !Ref LogBucket - Key: load_balancing.cross_zone.enabled Value: false SubnetMappings: - SubnetId: !Ref SubnetIdA PrivateIPv4Address: !Ref IpAddressA - SubnetId: !Ref SubnetIdC PrivateIPv4Address: !Ref IpAddressC InternalNLBTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: VpcId: !Ref VpcId Name: !Ref NLBTargetGroupName Protocol: TCP Port: 80 TargetType: ip TargetGroupAttributes: - Key: deregistration_delay.timeout_seconds Value: 60 - Key: deregistration_delay.connection_termination.enabled Value: false - Key: preserve_client_ip.enabled Value: false - Key: proxy_protocol_v2.enabled Value: false - Key: stickiness.enabled Value: false InternalNLBListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - TargetGroupArn: !Ref InternalNLBTargetGroup Type: forward LoadBalancerArn: !Ref InternalNLB Port: 443 Protocol: TLS Certificates: - CertificateArn: !Ref ListenerCertificateArn
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

HTTPS通信でアクセス可能にする

内容 この記事はAWS初学者を導く体系的な動画学習サービス 「AWS CloudTech」の課題カリキュラムで作成しました。 https://aws-cloud-tech.com 前回の記事「独自ドメインを設定する/障害時はSORRYページへ通信を流す」の続きです。 前回の記事 https://qiita.com/zakinicof/items/6c973c1aed9ebdeeb845 前回までの構成はブログサービスにアクセスするのにHTTPで通信をしていました。 このままではセキュリティに問題があるため、よりセキュアなHTTPSで通信できるように設定を変更していきます。 HTTPS通信をするために必要な証明書をAWS Certificate ManagerというAWSで証明書を管理できるサービスを利用します。 AWS Certificate Managerで証明書を発行してELBにアタッチすることでHTTPS通信を可能にしていきます。 その他、ELBのセキュリティグループでHTTPS通信を許可する設定の追加なども行なっていきます。 実施手順 前回の記事の構成がされていることを前提で進めていきます。 準備 EC2インスタンスが2台立ち上がっていることを確認 RDSを削除した場合は、スナップショットから復元しておく。 復元したデータベースのステータスが利用可能になるまで待つ。 前回取得したドメインでブログが閲覧できることを確認しておく。 ロードバランサーでHTTPS通信を受け付ける EC2の画面に移動し、左のメニューからロードバランサーを選択 リスナータブを選択し、リスナーの追加を選択 プロトコル:HTTPSを選択 アクションの追加→転送先と進み、ターゲットグループを選択し、チェックボタンを選択 新しいACM証明書をリクエストを選択 証明書のリクエスト画面でドメイン名を入力して次へ進む。 検証方法の選択:DNS の検証を選択して次へ 確認とリクエストを選択 Route53でのレコードの作成を選択 作成を選択 続行を選択 Route53の画面に移り、更新ボタンを選択、検証用のDNSレコードが追加されていることを確認する。 リスナーの追加画面に戻り、デフォルトのSSL証明書の項目で更新ボタンを選択し、先ほど作成した証明書を選択 右上のリスナーの追加を選択 セキュリティグループの設定 ロードバランサーの画面の詳細タブを選択し、セキュリティグループを選択 ロードバランサー用に作成したセキュリティグループを選択し、インバウンドルールを編集を選択 ルールの追加を選択 タイプ:HTTPSを選択 ソース:0.0.0.0/0を選択 ルールを保存を選択 現在の状態でURLをhttpからhttpsに変更してアクセスすると、WordPressの仕様で表示が崩れてしまうため、EC2にコードを追加することで対応します。 WordPressの対応 ターミナルを開き、SSH接続でEC2にログインする。接続したら権限をルート権限に変更しておく。 cd /var/www/html/でディレクトリを移動 llでwp-config.phpのファイルがあることを確認 vi wp-config.phpでファイルを開く。 編集が必要なのはここまでです!という記述が出てくるまで下にスクロールする。 上記の記述とdefine( 'WP_DEBUG', false );の間に下記のコードを記述する。記述したら保存する。 if($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') { $_SERVER['HTTPS'] = 'on'; $_ENV['HTTPS'] = 'on'; } 同様の手順をもう1台のインスタンスでも実行します。 この後、再度httpsでアクセスすると通常通り表示されるはずですが、この段階でまだ表示が崩れている場合は下記の手順を行います。 ターミナルを開き、SSH接続でEC2にログインする。 mysql -h RDSのエンドポイント名 -u ユーザー名 -pでMySQLにログイン USE データベース名 SELECT * FROM wp_options WHERE option_name IN ('siteurl', 'home');コマンドを実行すると、ELBのDNS名になっていることが確認できます。これを、https://[独自ドメイン名]に変更します。 UPDATE wp_options SET option_value = 'https://[独自ドメイン名]' WHERE option_name IN ('siteurl', 'home'); を実行 再度、SELECT * FROM wp_options WHERE option_name IN ('siteurl', 'home');コマンドを実行し、URLが更新されていることを確認 ブログにhttps://[独自ドメイン名]でアクセスし、正常にブログが表示されていることを確認する。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CloudFormationでEC2インスタンスがALBのヘルスチェックに合格したらスタックの更新を続行する方法

結論 AWS::CloudFormation::Initを使いましょう! ということなのですが、ここで出てくるcfn-initやらcfn-signalにかなりハマったので、調査した結果と実際の使用方法を紹介します。 きっかけ とあるプロジェクトで、 「EC2がALBのヘルスチェックでhealthyになるまで更新を一時停止したい」 という目的がありました。 なぜ? CloudFormationによるAuto Scalingグループの置換更新で起動したEC2インスタンスにアクセスできなかったためです。 問題は、 「ALBのヘルスチェックの結果に関わらず、CloudFormationの更新が完了する」 ということでした。 具体的には、新しく起動したEC2インスタンスに対するALBのヘルスチェックの結果がunhealthyなのに、古いAuto ScalingグループとEC2インスタンスがCloudFormationにより終了してしまうという挙動です。Auto Scalingグループ内のEC2インスタンスの数は常時1台という要件なので、複数台を1台ずつ更新するというローリングアップデートも使用できませんでした。 イメージ ざっくりしたイメージですが、やっていることはこんなかんじです。 問題のパターン 更新リクエストを受けたCloudFormationは新しいAuto Scalingグループを起動し、Auto ScalingグループがEC2起動、ALBに登録を実施 新しいEC2が起動したら、ALBのヘルスチェックの結果にかかわらず、CloudFormationは古いAuto Scalingグループ削除を開始 古いグループの削除が完了したら、CloudFormationは更新完了通知をSNSからChatbot経由でSlackに送信 3の時点で新しいEC2がALBのヘルスチェックをクリアしていないと、Developerはアクセスできません。 また、Auto Scalingグループのヘルスチェックの猶予期間を超えてもヘルスチェックをクリアしない場合、EC2は異常と判断され、新しいEC2が起動します。2台目がヘルスチェックを猶予期間内にクリアできればアクセスできるようなりますが、何度やってもクリアできない場合は終了→起動の無限ループが発生します。 上記より、 「ALBのヘルスチェックの結果に関わらず、CloudFormationの更新が完了する」 ことが問題だと判断し、対応を考えました。 解決パターン 上記の問題を解決するために、以下の挙動を目指しました。 - EC2がALBのヘルスチェックでhealthyになったらCloudFormationによる更新を続行 - 一定時間内にhealthyにならなかったらCloudFormationによる更新を中断してロールバックする これにより、 - 更新完了通知が届いた時点で新しいEC2にアクセスできる - 更新が失敗した場合でも古いEC2は保持されているので、アクセスが失われることはなくなる となり、新旧どちらにもアクセスできなくなるという事態は防げます。 しかし、1つだけ課題があります。 「一時的に2台のインスタンスにアクセスできる時間が発生する」 ということです。 ただし、これは後述するメンテナンス画面により解決しました。 解決手順 CloudFormationテンプレートファイルの修正 カスタムAMIからユーザーデータを実行する設定 ALBリスナールールの追加と自動切換え CloudFormationテンプレートファイルの修正 以下の修正を行いました。 1. Auto Scalingグループの更新方法の修正 2. 起動テンプレートにユーザーデータを追記 3. Auto ScalingグループにAWS::CloudFormation::Initを追記 1. Auto Scalingグループの更新方法の修正 もともとAuto Scalingグループの更新は以下のような設定でした。 "UpdatePolicy": { "AutoScalingReplacingUpdate": { "WillReplace": "true" } }, "CreationPolicy": { "ResourceSignal": { "Count": 0 } } 変更後は以下のようになりました。 "UpdatePolicy": { "AutoScalingReplacingUpdate": { "WillReplace": "true" } }, "CreationPolicy": { "ResourceSignal": { "Count": 1, //変更 "Timeout": "PT15M" //追記 } } この変更により、起動したEC2から成功シグナルが15分以内に送信されなければロールバックするという挙動になります。 詳しくはUpdatePolicy 属性 - AWS CloudFormation、CreationPolicy 属性 - AWS CloudFormationをご覧ください。 2. 起動テンプレートにユーザーデータを追記 こちらを参考に"Type": "AWS::EC2::LaunchTemplate"に以下を追記しました。 "UserData": { "Fn::Base64": { "Fn::Join": [ "", [ "<script>\n", "cfn-init.exe -v -s ", { "Ref": "AWS::StackId" }, " -r <Auto Scalingグループの論理ID>", " --configsets <cfn-initで実行するconfigSets名>", " --region ", { "Ref": "AWS::Region" }, "\n", "cfn-signal.exe -e %ERRORLEVEL% --stack ", { "Ref": "AWS::StackId" }, " --resource <Auto Scalingグループの論理ID> --region ", { "Ref": "AWS::Region" }, " --success true", "\n", "</script>", "<persist>true</persist>" ] ] } }, 上記により以下のような挙動になります。 - UserDataがcfn-init.exeを呼び出す - configsetsで後述のAWS::CloudFormation::Init内の処理を実行する - 処理が完了したらcfn-signal.exeで成功シグナルを送信する - CloudFormationは成功シグナルを受け取ったら、Auto Scalingグループは更新完了と判断して後続の更新を行う。 3. Auto ScalingグループにAWS::CloudFormation::Initを追記 こちらを参考に、"Type": "AWS::AutoScaling::AutoScalingGroup"に以下を追記しました。 "Metadata": { "AWS::CloudFormation::Init": { "configSets": { "HealthCheck": ["verify_instance_health"] }, "verify_instance_health": { "files": { "C:\\cfn\\healthcheck.ps1": { "content": { "Fn::Join": [ "", [ "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8", "\n", "$data = Invoke-WebRequest http://169.254.169.254/latest/meta-data/instance-id -UseBasicParsing", "\n", "$id = $data.Content", "\n", "$state = Get-ELB2TargetHealth -<ターゲットグループのARN> -Target @{Id=$id} -Select TargetHealthDescriptions.TargetHealth.State", "\n", "echo $state >> C:\\cfn\\state.log", "\n", "while ($state -ne \"healthy\") {", "$state = Get-ELB2TargetHealth -<ターゲットグループのARN> -Target @{Id=$id} -Select TargetHealthDescriptions.TargetHealth.State", "\n", "echo $state >> C:\\cfn\\state.log", "\n", "Start-Sleep -s 10", "\n", "}", "\n", "echo \"done\" >> C:\\cfn\\state.log" ] ] } } }, "commands": { "ELBHealthCheck": { "command": "powershell.exe -ExecutionPolicy Bypass C:\\cfn\\healthcheck.ps1", "waitAfterCompletion": 0 } } } } }, 上記により以下のような挙動になります。 - 先述のcfn-init.exeにより実行される - C:\cfn\にhealthcheck.ps1というPowerShellファイルを作成 - ファイルには以下のスクリプトが記述される - スクリプトについて詳しくはこちらをご覧ください。 healthcheck.ps1 # UTF8にエンコード [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 # 起動したEC2インスタンス自身のIDを取得 $data = Invoke-WebRequest http://169.254.169.254/latest/meta-data/instance-id -UseBasicParsing $id = $data.Content # ALBによるヘルスチェックの結果を取得 $state = Get-ELB2TargetHealth -TargetGroupArn <ターゲットグループのARN> -Target @{Id = $id} -Select TargetHealthDescriptions.TargetHealth.State echo $state >> C:\cfn\state.log # ヘルスチェックをクリアするまで10秒ごとに結果を取得 while ($state -ne "healthy") { $state = Get-ELB2TargetHealth -TargetGroupArn <ターゲットグループのARN> -Target @{Id = $id } -Select TargetHealthDescriptions.TargetHealth.State Start-Sleep -s 10 echo $state >> C:\cfn\state.log } echo "done" >> C:\cfn\state.log healthcheck.ps1が実行される カスタムAMIからユーザーデータを実行する設定 詳しくはこちらをご覧ください。 ALBリスナールールの追加と自動切換え 詳しくはこちらにまとめましたが、以下の手順を実施しました。 1. ALBのリスナールールにメンテナンスページを追加 2. リスナールールを切り替えるLambda関数を作成 3. CloudFormation → SNS → Lambda → ALBの経路で自動切換え まとめ 今回はEC2インスタンスの起動が完了したらスタックの更新を続行する方法を紹介しました。 cfn-init、cfn-signalだけでなくPowerShellスクリプトの作成やカスタムAMIからユーザーデータを実行する方法など、ハマりまくりました。改めて以下にポイントをまとめておきます。 - CreationPolicyでCountとTimeoutを指定する - ユーザーデータからcfn-init.exeを呼び出す - cfn-init.exeからAWS::CloudFormation::Initの処理を実行する - AWS::CloudFormation::Initの処理が終了したらcfn-signalを送信する - スクリプトは頑張って作る - カスタムAMIからユーザーデータを実行できるように設定する - ALBのリスナールールでメンテナンス画面を表示する 今後何かの参考になれば幸いです。 参考資料 AWS::CloudFormation::Init - AWS CloudFormation Auto Scaling インスタンスのヘルスチェック - Amazon EC2 Auto Scaling (日本語) UpdatePolicy 属性 - AWS CloudFormation CreationPolicy 属性 - AWS CloudFormation AWS CloudFormation の Amazon EC2 Windows インスタンスから送信される CREATE_COMPLETE シグナルのトラブルシューティング aws-cloudformation-templates/AutoScalingRollingUpdates.yaml at master · awslabs/aws-cloudformation-templates · GitHub
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ALBのヘルスチェック結果を確認するPowerShellスクリプトを書いてみた

CloudFormationからEC2インスタンスを起動する際、ALBのヘルスチェックをクリアするまで後続の処理を止めておきたいというときに作成したスクリプトです。 PowerShellの超初心者が書いた内容ですが、参考になれば幸いです。 スクリプト HealthCheck.ps1 # UTF8にエンコード [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 # 起動したEC2インスタンス自身のIDを取得 $data = Invoke-WebRequest http://169.254.169.254/latest/meta-data/instance-id -UseBasicParsing $id = $data.Content # ALBによるヘルスチェックの結果を取得 $state = Get-ELB2TargetHealth -TargetGroupArn <ターゲットグループのARN> -Target @{Id = $id} -Select TargetHealthDescriptions.TargetHealth.State echo $state >> C:\cfn\state.log # ヘルスチェックをクリアするまで10秒ごとに結果を取得 while ($state -ne "healthy") { $state = Get-ELB2TargetHealth -TargetGroupArn <ターゲットグループのARN> -Target @{Id = $id } -Select TargetHealthDescriptions.TargetHealth.State Start-Sleep -s 10 echo $state >> C:\cfn\state.log } echo "done" >> C:\cfn\state.log エンコード スクリプトの冒頭に [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 を記述することでUTF8にエンコードしています。 ユーザーデータ実行時にUTF8じゃないとエラーが発生したので以下の記事を参考にして記載しました。 cfn-initの実行時に「Unhandled exception during build: ‘utf8’ codec can’t decode byte…」のエラーが出る件について | DevelopersIO 自身のIDを取得 http://169.254.169.254/latest/meta-data/instance-id 上記でインスタンスのメタデータのうち、インスタンスIDを取得しています。 メタデータについて詳しくは以下のドキュメントをご覧下さい。 インスタンスメタデータの取得 - Amazon Elastic Compute Cloud インスタンスメタデータのカテゴリ - Amazon Elastic Compute Cloud PowerShellではcurlの代わりにInvoke-WebRequestを使うようなので、これでメタデータのURLにリクエストしています。 また、-UseBasicParsingのオプションは、EC2 Windows Server2019のデフォルトブラウザであるIEからのリクエスト時に付与しないとリクエストが通らなかったので付与しています。 EC2 user-data を使ってNAME Tagを設定する(Windows) | Oji-Cloud Invoke-WebRequest http://169.254.169.254/latest/meta-data/instance-id -UseBasicParsingにリクエストすると、以下のレスポンスが返ってきます。 StatusCode : 200 StatusDescription : OK Content : i-07a427e54c9465742 RawContent : HTTP/1.0 200 OK Connection: keep-alive Accept-Ranges: bytes Content-Length: 19 Content-Type: text/plain Date: Thu, 15 Apr 2021 08:23:09 GMT Last-Modified: Thu, 15 Apr 2021 08:13:06 GMT Server: ... Forms : Headers : {[Connection, keep-alive], [Accept-Ranges, bytes], [Content-Length, 19], [Content-Type, text/plain]...} Images : {} InputFields : {} Links : {} ParsedHtml : RawContentLength : 19 上記のうち、ContentにインスタンスIDが記載されているので、一度レスポンスを$dataに入れてから、$id = $data.ContentでインスタンスIDのみを取得しています。 ALBによるヘルスチェックの結果を取得 Get-ELB2TargetHealthというAPIでヘルスチェックの結果を取得しています。 PowerShellではAWS CLIの代わりにAWS Tools for PowerShellを使用します。 詳しくはこちらをご覧ください。 各種APIについてはAWS Tools for PowerShell Referenceで確認できます。 Get-ELB2TargetHealthについてはこちらで確認できます。 -TargetGroupArn ALBのターゲットグループのARNです。 記述例:-TargetGroupArn <ターゲットグループのARN> -Target ヘルスチェックの結果を取得するインスタンスを指定できます。 記述例:@{Id = "i-0bcc62df9872bd0f7" } 実際のスクリプトでは$id = $data.Contentで取得したインスタンスIDを$idという変数に入れ、@{Id = $id}でインスタンスIDを指定しています。 -Select レスポンスの値から任意の値を選択して取得します。 レスポンス内容はAPIにより異なるので、上記のドキュメントを参照してください。 実際のスクリプトでは-Select TargetHealthDescriptions.TargetHealth.Stateでヘルスチェックの結果の値(healthyやunhealthy)のみ取得しています。 ループ処理 while ($state -ne "healthy") { $state = Get-ELB2TargetHealth -TargetGroupArn <ターゲットグループのARN> -Target @{Id = $id } -Select TargetHealthDescriptions.TargetHealth.State Start-Sleep -s 10 echo $state >> C:\cfn\state.log } ($state -ne "healthy")でヘルスチェックをクリアするまでループする。 Start-Sleep -s 10で10秒処理を止める→10秒ごとにループする リクエストは前述の内容と同様 echo $state >> C:\cfn\state.log スクリプトが実行されたかどうかの確認のためにログファイルにヘルスチェックの結果を書き込んでいます。 使用方法 EC2インスタンスのユーザーデータにスクリプトを記述することで、インスタンス起動時にスクリプトが実行されます。 Windowsのユーザーデータについて詳しくはこちらをご覧ください。 また、カスタムAMIからの起動時や再起動時にもユーザーデータを実行する場合はこちらをご覧ください。 ユースケース CloudFormationでの更新時 CloudFormationからAuto Scalingグループを作成し、Auto Scalingグループ内で起動するEC2インスタンスがALBのヘルスチェックをクリアしたら、CloudFormationの更新を続行します。詳しくはこちらをご覧ください。 まとめ 今回はALBのヘルスチェック結果を確認するPowerShellスクリプトを作成したので紹介しました。 自分自身がPowerShellの超初心者なので、もっとよい記述方法があるかもしれませんが、ひとまず期待する動作は確認できたのでこちらを使用しています。 もっと書けるようになればインスタンス起動時の初期設定も自動でできるので、機会があれば別のスクリプトも作成してみたいと思います。 参考資料 cfn-initの実行時に「Unhandled exception during build: ‘utf8’ codec can’t decode byte…」のエラーが出る件について | DevelopersIO インスタンスメタデータの取得 - Amazon Elastic Compute Cloud インスタンスメタデータのカテゴリ - Amazon Elastic Compute Cloud EC2 user-data を使ってNAME Tagを設定する(Windows) | Oji-Cloud AWS Tools for PowerShell とは何ですか? - AWS Tools for PowerShell AWS Tools for PowerShell Reference ElasticLoadBalancingV2: Get-ELB2TargetHealth Cmdlet | AWS Tools for PowerShell Windows インスタンスでの起動時のコマンドの実行 - Amazon Elastic Compute Cloud
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ALBのリスナールールを自動で切り替えて、更新中だけメンテナンス画面を表示する方法

CloudFormationによるリリース時にメンテナンス画面とEC2のサイトを自動で切り替えるために、ALBによるリスナールールを使用しました。CloudFormationからでなくても自動切り替えは可能だと思うので、参考になれば幸いです。 経緯 Auto Scalingグループ内のEC2インスタンスが常時1台という要件のもと、CloudFormationによるリリース時に、一時的にALB配下に2台のEC2インスタンスが起動するタイミングがあり、新旧どちらのインスタンスにも接続できてしまう状況が発生しました。これを解決するために、リリース中(CloudFormationによる更新中)はメンテナンス画面を表示し、更新が完了したら新しいEC2に接続するという挙動を目指しました。更新が完了した時点で古いEC2インスタンスはALBから登録解除されているので、更新完了後は新しいEC2インスタンスにのみ接続されるようになります。 構成図 かなりざっくりですが、リソースの流れとしては上記がすべてです。 ALBのリスナールールの順序の入れ替えはLambdaからAPIで行います。 設定 各リソースにおける設定を紹介します。 CloudFormation スタック作成時や更新時の通知先にSNSトピックを指定できるので、この機能を利用します。 SNS SNSから処理を担当するLambda関数と連携します。 Lambdaについてはこちらにまとめてありますので参考までにご覧ください。 ALB リスナールールを作成します。 とりあえずALBのコンソールまで移動しましょう。 ALBコンソールで対象のロードバランサーを選択して「リスナー」タブを選択し、「ルールの表示/編集」をクリックします。 何も設定しなければデフォルトアクションのみとなっています。 今回はターゲットグループへの転送ルールと固定レスポンスを返すルールを作成します。 画面上部の追加アイコンをクリックし、「ルールの挿入」をクリックします。 IF条件を指定します。「パス」を選択し、*ですべてのリクエストを指定します。 THENでアクションの追加をクリックし、「転送先」にターゲットグループを指定します。 これで、ターゲットグループへの転送ルールができました。一度「保存」をクリックしましょう。 続いて、メンテナンス画面用の固定レスポンスを返すルールを作成します。 IF条件は先ほどと同様にパスが*ですべてのリクエストです。 THENは、「固定レスポンスを返す」を選択し、レスポンスコードで200を返します。 Content-Typeはtext/htmlを選択し、レスポンス本文にメンテナンス画面用のhtmlを貼り付けます。 ちなみに今回貼り付けたhtmlは以下のようなシンプルな画面です。 index.html <!DOCTYPE html> <html> <head> <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> <title>システムメンテナンスのお知らせ</title> </head> <body> <div style="width: 640px; margin: 50px auto"> <div style="border: 1px solid #ccc; padding: 30px; margin-top: 30px"> <h2 style="color: #f00">システムメンテナンスのお知らせ</h2> <p> いつもご利用いただき、ありがとうございます。<br /> このたびサービス向上のため、システムメンテナンスを実施いたします。<br /> お客さまには大変ご迷惑をおかけいたしますが、何卒ご了承いただけますようよろしくお願い申し上げます。 </p> <p>ご不便をおかけいたしますがよろしくお願い申し上げます。</p> </div> </div> </body> </html> 設定できたら「保存」をクリックします。 ルールは優先順位の高いほうから評価されるため、この順位の入れ替えを使ってメンテナンス画面との切り替えを行います。 とりあえずターゲットグループへの転送ルールを1番にしておきます。 これでルールの追加が完了しました。 実際にALBにアクセスするとEC2に転送されていることがわかります。 それではコンソール上で優先順位を入れ替えてみましょう。 固定レスポンスを1番にしてみます。 再度ALBにアクセスしてみると、今度はメンテナンス画面が表示されました。 こんなかんじでルールの優先順位を変更することで表示を切り替えることができます。 以上のようにコンソールから切り替えることもできますが、SetRulePriorities APIを使えば自動切り替えができるので、後述するLambdaからAPIで切り替えます。 Lambda ALBのリスナールールを切り替える処理を記述します。 詳しくはこちらにまとめてありますので参考までにご覧ください。 まとめ 今回はALBのリスナールールを自動で切り替えることで、EC2のサイトとメンテナンスページを自動で切り替える方法を紹介しました。 APIで切り替えられるので、フロントエンドからAPI GatewayからLambdaを起動すれば、ボタンによる切り替えも可能です。リリース時以外にも想定外の障害時にすぐに切り替えることもできます。切り替えにかかる時間は10~20秒ほどだったので、これを許容できるかどうかにもよるかと思いますが、参考になれば幸いです。 参考資料 Application Load Balancer のリスナールール - Elastic Load Balancing AWS まだS3でSorryページを表示してる? | 技術者のブログ SetRulePriorities - Elastic Load Balancing
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ALBのリスナールールを自動で切り替えるLambda関数

SetRulePriorities APIを使用して、ALBのリスナールールを自動で切り替える関数です。 CloudFormationからSNS経由で通知を受け取り、CloudFormationによる更新中はメンテンナンス画面を表示し、更新が完了したらEC2のサイトを表示するというルールの切り替えを行います。 概要 ランタイム:Node 14.x アクセス権限: AWSLambdaBasicExecutionRole ELB v2 SetRulePriorities(カスタムポリシーで選択する) 環境変数 LogicalResourceId : 更新するCloudFormationスタック名 ForwardRuleArn : ターゲットグループへの転送ルールのARN MaintenanceRuleArn : メンテナンス用の固定レスポンスを返すルールのARN ソース index.js const AWS = require('aws-sdk'); AWS.config.update({ region: 'ap-northeast-1' }); AWS.config.apiVersions = { elbv2: '2015-12-01', // other service API versions }; const elbv2 = new AWS.ELBv2(); exports.handler = async (event) => { console.log(JSON.stringify(event, null, 2)); const messages = event.Records[0].Sns.Message.split('\n'); //リソースの論理IDを取得 const logicalResourceId = messages .find((message) => { return message.includes('LogicalResourceId'); }) .replace(/LogicalResourceId=|\'/g, ''); console.log(logicalResourceId); if (logicalResourceId !== process.env.LogicalResourceId) { return; } //更新状況を取得 const resourceStatus = messages .find((message) => { return message.includes('ResourceStatus='); }) .replace(/ResourceStatus=|\'/g, ''); console.log(resourceStatus); let params = ''; if (resourceStatus === 'UPDATE_IN_PROGRESS') { params = { RulePriorities: [ /* required */ { Priority: 1, RuleArn: process.env.MaintenanceRuleArn, }, { Priority: 2, RuleArn: process.env.ForwardRuleArn, }, /* more items */ ], }; } else if ( resourceStatus === 'UPDATE_COMPLETE' || resourceStatus === 'UPDATE_ROLLBACK_COMPLETE' ) { params = { RulePriorities: [ /* required */ { Priority: 1, RuleArn: process.env.ForwardRuleArn, }, { Priority: 2, RuleArn: process.env.MaintenanceRuleArn, }, /* more items */ ], }; } else { return; } try { const result = await elbv2.setRulePriorities(params).promise(); console.log(JSON.stringify(result, null, 2)); } catch (err) { console.log(err); } }; eventの中身 CloudFormationからSNS経由で飛んでくる情報はeventに入っていますが、実際には以下のような情報が入っています。 { "Records": [ { "EventSource": "aws:sns", "EventVersion": "1.0", "EventSubscriptionArn": "arn:aws:sns:ap-northeast-1:467964259659:Study_Topic_NotifyCloudFormationEvent:986df782-8a51-45e7-b523-9bd396c5ebf3", "Sns": { "Type": "Notification", "MessageId": "d255cf45-5bc0-5286-af38-97b50ae294b0", "TopicArn": "arn:aws:sns:ap-northeast-1:467964259659:Study_Topic_NotifyCloudFormationEvent", "Subject": "AWS CloudFormation Notification", "Message": "StackId='arn:aws:cloudformation:ap-northeast-1:467964259659:stack/StudyRelease/2fc47fe0-8ab6-11eb-b4b5-0e9ed3f1b3df'\nTimestamp='2021-04-14T02:09:38.195Z'\nEventId='77321280-9cc6-11eb-bae0-0a1871fe28bb'\nLogicalResourceId='StudyRelease'\nNamespace='467964259659'\nPhysicalResourceId='arn:aws:cloudformation:ap-northeast-1:467964259659:stack/StudyRelease/2fc47fe0-8ab6-11eb-b4b5-0e9ed3f1b3df'\nPrincipalId='AROAWZ5GX5VF6AF2NRDU6:tnet_admin_119503'\nResourceProperties='null'\nResourceStatus='UPDATE_ROLLBACK_COMPLETE'\nResourceStatusReason=''\nResourceType='AWS::CloudFormation::Stack'\nStackName='StudyRelease'\nClientRequestToken='Console-ExecuteChangeSet-6ed7afc4-c02a-bac3-48e8-dea1b25a96b9'\n", "Timestamp": "2021-04-14T02:09:38.250Z", "SignatureVersion": "1", "Signature": "JrKCtXJEL6aNAZStjXVRfFYHEHYPM63zVPgAf929WKD+2AlB3YUuMc4ZtFg4ly2DDN+ilOzCcCAs5i+fUaGDF8dkSmQS34L7ikCmJPVVXrabam8yZ8CP9lcn2bbTUCYCb75ec9cdDqE3c0Snp6fCKB/ZgkMMCV7w4TTdMzNAHyldjseWu/1goxq91q6X9dOcSYVoV5GuNrI0kQOfRKJQOguWCYV8Ze7uXFJ5frmUrcD/xb3eRNnzCNjAe3pvTqNPVU6RgLO2fIfTq6Qlo+NSweQZ7niJvrEQ+X+uugnWAoFKz7tqO+mehsifFeS2K/oJDvz9XmOC0EAOWF3rDgukuw==", "SigningCertUrl": "https://sns.ap-northeast-1.amazonaws.com/SimpleNotificationService-010a507c1833636cd94bdb98bd93083a.pem", "UnsubscribeUrl": "https://sns.ap-northeast-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:ap-northeast-1:467964259659:Study_Topic_NotifyCloudFormationEvent:986df782-8a51-45e7-b523-9bd396c5ebf3", "MessageAttributes": {} } } ] } 処理の最初の方で、Messageから必要な情報のみを取得しています。 CloudFormationからの通知内容の判定 CloudFormationからはスタック自体の更新情報の他にもリソースごとの更新情報も飛んできます。 この関数の処理の目的は、 「スタックの更新が開始されたらメンテナンス画面を表示し、スタックの更新が完了したらサイトを表示するようルールの順序を変更する」 ことなので、必要な情報はスタック名とスタックの更新状況の2つです。 まずはスタック名が含まれているかを判定します。 if (logicalResourceId !== process.env.LogicalResourceId) { return; } 続いて更新状況の判定です。 更新中(UPDATE_IN_PROGRESS)ならメンテ画面を表示するルールを1に設定します。 更新完了(UPDATE_COMPLETE)またはロールバック完了(UPDATE_ROLLBACK_COMPLETE)ならサイトを表示するルールを1に設定します。 if (resourceStatus === 'UPDATE_IN_PROGRESS') { params = { RulePriorities: [ /* required */ { Priority: 1, RuleArn: process.env.MaintenanceRuleArn, }, { Priority: 2, RuleArn: process.env.ForwardRuleArn, }, /* more items */ ], }; } else if ( resourceStatus === 'UPDATE_COMPLETE' || resourceStatus === 'UPDATE_ROLLBACK_COMPLETE' ) { params = { RulePriorities: [ /* required */ { Priority: 1, RuleArn: process.env.ForwardRuleArn, }, { Priority: 2, RuleArn: process.env.MaintenanceRuleArn, }, /* more items */ ], }; } else { return; } ALBへ設定変更リクエスト リクエストにはSetRulePriorities APIを使用します。 パラメーターの詳細はドキュメントをご覧ください。 この関数では優先順位であるPriorityとALBリスナールールのARNであるRuleArnを設定しています。 まとめ 今回はALBのリスナールールを自動で切り替える関数を紹介しました。 現状はCloudFormationの通知機能から発火させていますが、他にもEventBridgeのスケジュール実行や、フロントエンドからボタンでの切り替えなどもできると思うので、参考にして頂ければ幸いです。 参考資料 SetRulePriorities - Elastic Load Balancing
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Lambda関数のCloudwatchEventsトリガー一覧を取得する

はじめに 最近、Lambda関数のトリガー画面が少し変わりました。 以前まではCloudwatch Eventsをトリガーに設定していた場合は、そのトリガーが有効なのか、無効なのかが表示されていました。 現在はその有効・無効が表示されなくなったので、元々設定されていたトリガーの状態がひと目でわからなくなりました。。 AWSCLIからCloudwatchEventsトリガーの一覧を取得する 現在、どのトリガーが有効かをマネジメントコンソール上から判断できるのはできますが、Cloudwatch Eventsのルール数や元々設定していたトリガーが多いとかなり面倒です。1 2 AWSCLIで有効なCloudwatchEventsトリガーの一覧は下記で取得できます。 aws events list-rule-names-by-target --target-arn 関数のARN # 例 # 末尾latestはエイリアス名 aws events list-rule-names-by-target --target-arn arn:aws:lambda:ap-northeast-1:123456789012:function:MYFUNCTION:latest おわりに Lambdaのトリガーなのでaws lambda xxで情報が取れると思ってましたが、違いました。 DynamoDB Streamsだとaws lambda list-event-source-mappingsで取れるんですが。。 今後は元々設定していた無効トリガーを削除して、有効なトリガーだけ表示されている、という状態を作らないと困惑しそうです。 トリガー画面から判断する場合、トリガーを一つ選択したとき、有効化ボタンが活性になれば無効、非活性であれば有効 ↩ CloudwatchEventsのルールを選択し、ターゲットに対象Lambdaがあれば有効 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

NginxのアクセスログからELBのヘルスチェックを除外する方法

方法 /etc/nginx/nginx.confのhttpモジュールを以下のように編集。 http { /* 省略 */ map $http_user_agent $log_ua { ~ELB-HealthChecker 0; default 1; } access_log /var/log/nginx/access.log main if=$log_ua; /* 省略 */ }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[ Rails & Nuxt ] AWS ECSを使ってデプロイをする

No. タイトル 1 Dockerで開発環境を構築する 2 ログイン認証を機能を実装する 3 記事投稿機能を実装する 4 AWS ECSを使ってデプロイする 5 Circle CIを使って自動テスト•デプロイをする はじめに Rails & Nuxtでポートフォリオを作成するシリーズの第4弾になります。 全5部構成でDocker,CircleCI,AWS等のモダンな技術を組み込んだ作品を完成させる予定です。 本章ではAWSのECSを利用してアプリのデプロイを行います。 以下、完成イメージ 事前学習 ↓AWSのネットワークの仕組みについて ↓ECSについて VPC作成 最初にリージョンを東京に切り替えておいて下さい。 name CIDRブロック sample-vpc 10.20.0.0/16 サブネット作成 後に作成するロードバランサーではサブネットが2つ必要な為、Nuxt,Rails,RDSでそれぞれ2つずつサブネットを用意します。 name CIDRブロック Region/AZ sample-front-subnet-1a 10.20.1.0/24 ap-northeast-1a sample-front-subnet-1c 10.20.2.0/24 ap-northeast-1c sample-back-subnet-1a 10.20.3.0/24 ap-northeast-1a sample-back-subnet-1c 10.20.4.0/24 ap-northeast-1c sample-rds-subnet-1a 10.20.5.0/24 ap-northeast-1a sample-rds-subnet-1c 10.20.6.0/24 ap-northeast-1c IGWの作成 VPC > インターネットゲートウェイより、sample-igwという名前でIGW作成。 その後、[アクション] > [VPCにアタッチ]でsample-vpcに関連づける。 ルートテーブルの作成 VPC > ルートテーブル > [ルートテーブルの作成]より作成画面に移ります。 name sample-front-route sample-back-route sample-rds-route IGW,サブネット,ルートテーブルの関連付け ルートテーブル > アクション > ルートを編集 > ルートを追加より、frontとbackのルートテーブルに対して、0.0.0.0に先ほど作ったIGWを関連付ける。 ルートテーブル > アクション > サブネットの関連付けを編集 より以下の表のように関連付け サブネット ルートテーブル sample-front-subnet-1a sample-front-route sample-front-subnet-1c sample-front-route sample-back-subnet-1a sample-back-route sample-back-subnet-1c sample-back-route sample-rds-subnet-1a sample-rds-route sample-rds-subnet-1c sample-rds-route セキュリティグループの作成 セキュリティグループ名 タイプ プロトコル ポート範囲 ソース sample-front-sg HTTP TCP 80 0.0.0.0/0 SSH TCP 22 My IPアドレス HTTPS TCP 443 0.0.0.0/0 カスタム TCP 3000 0.0.0.0/0 sample-back-sg カスタム TCP 8000 0.0.0.0/0 HTTPS TCP 443 0.0.0.0/0 sample-rds-sg MYSQL/Aurora TCP 3306 0.0.0.0/0 Route53 ドメインの取得 お名前.comより、ドメインの取得をします。Route53からでも取得可能ですが、値段が高いです。 あくまで練習用なので、適当に安いドメイン(.xyzとか)を取得すればOKです。 お名前.comでのドメイン取得方法については、以下を参照してください。 今回は下記を取得したという前提で進めていきます。 ドメイン名 役割 sample.com front sample-api.com back ホストゾーンの作成 Route53 > ホストゾーン > [ホストゾーンの作成] ホストゾーン詳細より、NSレコードの値/トラフィックのルーティング先をコピーして下さい。 お名前.comのネームサーバにNSレコードの値を登録 先ほどコピーしたNSレコードをお名前.comのDNSサーバーに登録します。 $: dig sample.com(取得したドメイン) +short NS 上記コマンドをターミナルから打ち、無事登録したNSレコードが表示されていれば反映されています。 ACMを使ってドメインに証明書を発行する sample.comとsample-api.comについて、それぞれSSL証明書を取得します。 ACM > 証明書のリクエスト > パブリック証明書のリクエストを選択。 ドメイン名 sample.com or sample-api.com 検証方法 DNS検証 タグ なし リクエスト後、検証画面に移るので、Route53でのレコード作成を押します。 そして、しばらくして(30分くらい)検証保留中から、発行済みステータスとなれば成功です。 RDSの作成 サブネットグループの作成 RDS > サブネットグループ > [DBサブネットグループを作成] RDSの作成にはサブネットグループが必要なので、先に作成しておきます。 サブネットはsample-rds-subnet1aとsample-rds-subnet1cを選択 グループ名はsample-subnet-groupとします。 RDSの作成・設定 設定 備考 作成方法 標準作成 エンジンのタイプ Maria バージョン 10.4.3 テンプレート 無料利用枠 DB インスタンス識別子 sample-rds マスターユーザー名 sample(任意) マスターパスワード samplepassword(任意) DB インスタンスクラス情報 db.t2.micro ストレージタイプ 汎用SSD ストレージ割り当て 20 VPC 先ほど作ったVPC(sample-vpc) サブネットグループ 先ほど作ったグループ(sample-subnet-group) 既存のVPCセキュリティグループ 先ほど作ったグループ(sample-rds-sg) アベイラビリティゾーン 指定なし 最初のデータベース名 app_production あとはデフォでOKです。 しばらくすると利用可能ステータスとなるので、そうしたらRDS作成完了です。 database.yml、credentials.yml.encの修正 ./back/config/database.yml production: <<: *default     database: app_production host: <%= Rails.application.credentials.rds[:host] %> username: <%= Rails.application.credentials.rds[:username] %> password: <%= Rails.application.credentials.rds[:password] %> これらの値は知られたくないので、credentials.yml内に環境変数として定義します。 $: docker-compose run -e EDITOR="vi" back rails credentials:edit ----------------------------------- rds: host: エンドポイント #RDS詳細画面のエンドポイントの欄の値 username: sample #設定したユーザーネーム password: samplepassword #設定したパスワード エンドポイントは↓の値をコピーしてください。 ロードバランサーの作成 EC2 > ロードバランサー > [ロードバランサーの作成]より作成画面へ移ります。 ロードバランサーの設定 front 種類の選択 Application Load Balancer ロードバランサーの設定 名前 sample-front スキーム インターネット向け IPアドレスタイプ ipv4 リスナー HTTP & HTTPS VPC sample-vpc アベイラビリティゾーン sample-subnet-front1a & 1c セキュリティ設定の構成 証明書タイプ ACM から証明書を選択する 証明書の名前 sample.com セキュリティポリシー デフォルト セキュリティグループ sample-front-sg ターゲットグループ 名前 sample-front-tg ターゲットの種類 インスタンス プロトコル HTTP ポート 8000 プロトコルバージョン HTTP 1.1 ヘルスチェック プロトコル HTTP パス / ターゲットの登録 スキップ back 種類の選択 Application Load Balancer ロードバランサーの設定 名前 sample-back スキーム インターネット向け IPアドレスタイプ ipv4 リスナー HTTP & HTTPS VPC sample-vpc アベイラビリティゾーン sample-subnet-back1a & 1c セキュリティ設定の構成 証明書タイプ ACM から証明書を選択する 証明書の名前 sample-api.com セキュリティポリシー デフォルト セキュリティグループ sample-back-sg ターゲットグループ 名前 sample-back-tg ターゲットの種類 インスタンス プロトコル HTTP ポート 3000 プロトコルバージョン HTTP 1.1 ヘルスチェック プロトコル HTTP パス / ターゲットの登録 スキップ ※ヘルスチェックのパスを"/"としていますが、ルートパスに何かしら200レスポンスを返すページを用意しておいて下さい。しないとエラーになります。 ターゲットはECSに登録した際に自動で追加されます。 Route53にAレコードを追加 Route53 > ホストゾーン > [レコードを作成] - レコードタイプ: A - 値: エイリアス - エンドポイント: Application Load Balancer - リージョン: 東京 - ロードバランサー: sample-front または sample-back sample.comとsample-api.com両方のドメインで行って下さい アプリを本番環境用に変更 AWSにデプロイするにあたり、本番環境用にいくつかファイルを変更します。 書き換えるのが面倒ならば、Dockerfile.dev,Dockerfile.proなど環境毎に分けて作成すると良いかもです。 back/Dockerfile FROM ruby:2.6.3-alpine3.10 ENV RUNTIME_PACKAGES="linux-headers libxml2-dev make gcc libc-dev nodejs tzdata mysql-dev mysql-client yarn" \ DEV_PACKAGES="build-base curl-dev" \ HOME="/app" \ LANG=C.UTF-8 \ TZ=Asia/Tokyo WORKDIR ${HOME} COPY Gemfile ${HOME}/Gemfile COPY Gemfile.lock ${HOME}/Gemfile.lock RUN apk update && \ apk upgrade && \ apk add --update --no-cache ${RUNTIME_PACKAGES} && \ apk add --update --virtual build-dependencies --no-cache ${DEV_PACKAGES} && \ bundle install -j4 && \ apk del build-dependencies && \ rm -rf /usr/local/bundle/cache/* \ /usr/local/share/.cache/* \ /var/cache/* \ /tmp/* \ /usr/lib/mysqld* \ /usr/bin/mysql* ADD . ${HOME} EXPOSE 8000 CMD ["bundle", "exec", "rails", "s", "-b", "0.0.0.0", "-p", "8000", "-e", "production"] front/Dockerfile FROM node:16.3.0-alpine ENV HOME="/app" \ LANG=C.UTF-8 \ TZ=Asia/Tokyo ENV HOST 0.0.0.0 WORKDIR ${HOME} RUN apk update && \ apk upgrade && \ npm install -g n && \ yarn install &&\ rm -rf /var/cache/apk/* ADD . ${HOME} EXPOSE 3000 RUN yarn run build CMD ["yarn", "start"] ./front/nuxt.config.js axios: { //baseURL: "http://localhost:3000", //ベストプラクティスとしてはURLを環境変数で設定した方が良いですが、今回は手直しします。 baseURL: "https://sample-api.com" }, ECRにリポジトリを作成・イメージのプッシュ ECRの作成・設定 ECR > [レポジトリの作成]よりレポジトリを作成します。 可視設定はプライベート、レポジトリ名はsample-front,sample-backとします。 作成後[プッシュコマンドの表示]を押すとコマンドが表示されるので、それに従いターミナルで実行します。尚、このコマンドを実行するにはAWS-CLIの事前インストールが必要なので、やっておきましょう。 実行後、ECRレポジトリ内にイメージが追加されたのを確認して下さい。 ECSの作成・設定 以下、個人的な用語整理 クラスター: ECSの適用範囲を決める タスク定義: docker-compose.yml タスク: docker-compose.ymlによって作成されたコンテナ群 サービス:クラスターとタスク定義を紐付ける ECSクラスターの作成 ECS > クラスター > [クラスターの作成]より作成画面に移ります。 クラスターテンプレート EC2 Linux + ネットワーキング クラスター名 sample-cluster プロビジョニングモデル オンデマンドインスタンス EC2 インスタンスタイプ t3.small インスタンス数 1 EC2 AMI ID* Amazon Linux2 ボリュームサイズ デフォ値 キーペア 任意 (無しにするとSSH接続でデバックできません) VPC sample-vpc サブネット sample-front-subnet1a & 1c パブリック IP の自動割り当て 適用 セキュリティグループ sample-front-sg コンテナインスタンスの IAM ロール デフォ値 タスク定義の作成 ECS > タスク定義 > [新しいタスク定義の作成]より作成画面に移ります。 front 設定 Value 起動タイプの互換性 EC2 タスク定義名 sample-front タスクロール ecsTaskExecutionRole ネットワークモード ホスト タスク実行ロール ecsTaskExecutionRole タスクメモリ (MiB) 700 タスク CPU (単位) 256 コンテナ名 sample-front イメージURL ECR sample-frontレポジトリのURI ポート 8000 back 設定 Value タスク定義名 sample-back タスクロール ecsTaskExecutionRole ネットワークモード ホスト タスク実行ロール ecsTaskExecutionRole タスクメモリ (MiB) 700 タスク CPU (単位) 256 コンテナの追加 コンテナ名 sample-back イメージURL ECR sample-backレポジトリのURI ポート 3000 サービスの作成 ECS > クラスター > sample-service >作成より作成画面に移ります。 front 設定 Value 起動タイプ EC2 タスク定義 sample-front サービス名 sample-front-service サービスタイプ REPLICA タスクの数 1 次のステップ ロードバランシングの種類 Application Load Balancer ヘルスチェックの猶予期間 30 サービス用の IAM ロールの選択 ecsServiceRole ロードバランサー名 sample-front ロードバランサーに追加 ターゲットグループ名 sample-front-tg Service Auto Scaling サービスの必要数を直接調整しない back 設定 備考 起動タイプ EC2 タスク定義 sample サービス名 sample-back-service サービスタイプ REPLICA タスクの数 1 次のステップ ロードバランシングの種類 Application Load Balancer ヘルスチェックの猶予期間 30 サービス用の IAM ロールの選択 ecsServiceRole ロードバランサー名 sample-back ロードバランサーに追加 ターゲットグループ名 sample-back-tg Service Auto Scaling サービスの必要数を直接調整しない 以上で完了です。最後に少しだけやることがあります。 コンテナ内に入ってdb:migrateする EC2インスタンスの中にssh接続し、その上でdockerコンテナ内に入り込みrails db:migrateします。 RDSを作成時に初期DBとして[app_production]を設定したため、db:createの必要ありません。 ssh -i {pemファイル} ec2-user@{インスタンスのpublicIP} EC2インスタンス内 docker ps で、現在起動しているコンテナが表示されます。 railsを起動しているコンテナのCONTAINER IDを指定して、以下コマンドを打つと、Dockerコンテナ内部に入れます。 EC2インスタンス内 docker exec -it {CONTAINER ID} sh ここで、環境を指定してdb:migrateします。 Dockerコンテナ内 rails db:migrate RAILS_ENV=production 起動確認 https://sample.comにアクセスすると、ホーム画面が表示されると思います! うまくいかない場合... 記入ミス等、ケアレスミスしてないか見直す 英語の記事がないか調べてみる docker logs {コンテナid}でエラー原因を探る タスク詳細画面でエラー原因を見てみる などなど...
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS 認定セキュリティ–専門知識(SCS-C01)取得するまでにやったこと

はじめに DX 技術本部の yu-yama です。 AWS 認定セキュリティ–専門知識(SCS-C01)を取得したので取得までの流れを記します。 受験前の AWS 経験 AWS 経験は 4, 5 年で、コアサービスは開発側/運用側一通り触っており、以下の認定を取得しています。 SAA (2020年6月) AWS 認定ソリューションアーキテクトアソシエイト(SAA-C02)取得するまでにやったこと DVA (2021年1月) AWS 認定 デベロッパー – アソシエイト(DVA-C01)取得するまでにやったこと SOA (2021年2月) AWS 認定 SysOps アドミニストレーター – アソシエイト(SOA-C01)取得するまでにやったこと SAP (2021年4 月) AWS 認定ソリューションアーキテクト – プロフェッショナル(SAP-C01)取得するまでにやったこと DOP(2021年5月) AWS 認定 DevOps エンジニア – プロフェッショナル(DOP-C01)取得するまでにやったこと 学習期間 4 週間弱 学習の流れ 試験ガイドを確認 AWS-Certified-Security-Specialty_Exam-Guide.pdf 分野ごとの比重を見て、特に問われるところを確認します。 インフラストラクチャのセキュリティ が沢山でそう。 分野 1: インシデント対応 12% 分野 2: ログ収集と監視 20% 分野 3: インフラストラクチャのセキュリティ 26% 分野 4: ID とアクセスの管理 20% 分野 5: データ保護 22% 試験の詳細を確認 プロフェッショナル資格より 10 問減って、時間も 10 分短くなっています。 形式:65 問 時間:170 分 合格体験記確認 先人のやったことを確認し、どのような問題が出るか、どのような解き方をするか、どの問題集が良いか、どのような学習の仕方をするかを確認します。 合格記 | AWS WEB 問題集で学習しよう 1週間で問題集を2周して合格 アソシエイトと同程度の難易度 Web問題集と要点整理から攻略する『AWS認定 セキュリティ-専門知識』 SAPと比べると難易度は低い IAMポリシーやKMSに関する問題が多く出題 Amazon Inspector や AWS Security Hub AWSのベストプラクティスに従った解答を選択すればOK 時間が余る Macie AWS 認定セキュリティ - 専門知識 (AWS Certified Security - Specialty) に合格した - Qiita AWS 認定セキュリティスペシャリティ試験合格へ向けてやったこと | DevelopersIO こちらの要点整理から攻略する『AWS認定 セキュリティ-専門知識』は必読です。神です。試験範囲がくまなく網羅されておりかつ解説がとてもわかりやすく学習が非常に捗りました。 AWS Certified Security - Specialty に合格したよ! - Qiita 1. まずはセキュリティ認定がどのくらいの難易度でどのようにAWSについて聞かれるかを把握するためExam Readiness: AWS Certified Security - Specialty (Japanese)を一周しました。 2. その後出題範囲のサービスについて確認するため要点整理から攻略する『AWS認定 セキュリティ-専門知識』こちらを読ませて頂きました。ここで全てを理解しようとはせず、「ふむふむ、あ〜〜完全に理解したわ」くらいになればOKです。 3. その後模擬試験を通じてBlackbeltや各サービスのユーザガイド、開発者ガイドを読み込み知識の補完を行いました。その際に公式ドキュメントから忘れそうなことを下記のようにコピペしてメモりながらあとで見返せるようにしていました。 4. 認定試験前に自身でまとめたものを確認して終わり! だいたい試験の1ヶ月くらい前から勉強を初めて、全部で15〜20時間くらい費やしました。 AWS Certified Security Specialty 合格記録 - Qiita 今回はProfessionalの資格の知識が有効だったため、試験対策としての学習時間は20-25時間程度でした。 丁度AWS WEB 問題集で学習しよう の有効期限が切れたため、各所で評判の良い要点整理から攻略する『AWS 認定 セキュリティ-専門知識』 | NRI ネットコム株式会社 を購入して試験に備えることにしました。 Exam Readiness: AWS Certified Security - Specialty (Japanese) | AWS トレーニングと認定 何はともあれ公式の無料デジタルトレーニングを受けて試験の雰囲気とポイントを掴みます。 要点整理から攻略する『AWS 認定 セキュリティ-専門知識』 | NRI ネットコム株式会社 にて学習 1 ページから順に進める...ということはせず、最終章に付いている練習問題(全40問)から解き始めました。 1問ごとに問題を解いて解答を確認して解説を読む。 → (理解が浅いと感じた場合)書籍の参考ページ1を読む。 → 次の問題へ。 という進め方を行い、一通り受けたところで受験してみることにしました。 模擬試験 受けてません。 本番 試験問題は 65問 170分です。プロフェッショナル資格2はタイムキープして 1 問何分と解き進めましたが、セキュリティ資格は問題&回答選択肢ちゃんと読んで解答しても時間が余る印象を受けました。残時間を意識しなくて進めても問題ないと思います。 前の回答で 2問まで絞れたが分からずチェックした箇所が、後の問題文で1つに絞れるというケースがありました。全体整合性を取りつつ進めましょう。 さいごに 思っていたより深いことを問われたため、自分がやった学習方法では浅かったように感じました。 4週間前の自分に伝えられるなら以下のやり方を薦めます。 1. 要点整理から攻略する『AWS 認定 セキュリティ-専門知識』 | NRI ネットコム株式会社 にて学習 最後に付いている練習問題(全 40 問)から解く。 問題を解いて解答を確認して解説を読む。 解答全てについて書籍の参考ページ1を読む。 → 次の問題へ。 2. BlackBelt サービス別資料 | AWS クラウドサービス活用資料集 を読む 以下のサービスについて押さえておく - VPC - VPC フローログ - ELB、SG や ACL - Amazon S3 - データアクセス保護 - デフォルト暗号化 - Amazon S3 Glacier - Amazon RDS, DynamoDB - 転送中のデータ保護 - 保管中の保護 - Amazon Cognito - KMS - キーポリシー - IAM - IAM ポリシー - IAM Permissions boundary(アクセス権限の境界) - AWS WAF - AWS Shield - WAFとの使い分け - CloudFront - 署名付き URL, 署名付き Cookie の使い分け - AWS Organizations - SCPの使い方 - Systems Manager - GuardDuty - Secrets Manager - Amazon Macie - Inspector - Security Hub - CIS AWS Foundations ベンチマーク標準 - Cloud HSM - CertificateManager - CloudTrail - マルチアカウントからのログの集約方法 - Trusted Advisor - AWS Config - マルチアカウントからのデータの集約方法 解答に参考ページが記載されていて飛びやすくて good です。 ↩ AWS 認定ソリューションアーキテクト – プロフェッショナルやAWS 認定 DevOps エンジニア – プロフェッショナル ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初めてのTerraform

初めてのTerraform 背景 お仕事でTerraformを使うことになりました。 CloudFormationも使ったことがないのに...とちょっと戸惑いました。 ですがIaCを実践で身につける良いチャンスです。 お仕事で取り扱うまえに、まずは予習をしてみます。 目標 TerraformでAWSにEC2インスタンスを構築する 環境 これまで愛用していたaws-cliが利用可能なDockerコンテナにTerraformをインストールし、Dockerコンテナから実行します。 参考 ・ Install Terraform ・ 10分で理解するTerraform ・ AWSでTerraformに入門 ファイル構成 terraform └terraform.tfvars └variables.tf └ec2.tf 手順 環境構築 Dockerfileに以下を追加し、コンテナを再構築しました。 # install terraform RUN apt-get update && apt-get install -y gnupg software-properties-common curl RUN curl -fsSL https://apt.releases.hashicorp.com/gpg | apt-key add - RUN apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main" RUN apt-get update && apt-get install terraform 変数定義ファイル「terraform.tfvars」 各定義ファイルに変数を直接記述する方法もありますが、汎用性を持たせるために変数を外出しにする方法を採用してみました。 「terraform.tfvars」というファイル名で変数を定義しておけばterraform実行時に自動的に読み込んでくれるようです。 今回、aws接続に必要なアクセスキーとシークレットキーを定義しました。 aws_access_key = "xxxxxxxxxx" aws_secret_key = "xxxxxxxxxx" 環境設定ファイル「variables.tf」 こちらのファイルには接続する環境の情報を記述するようです。 サイトによっては「main.tf」というファイルで作成されている方もいました。 今回はアクセスキーとシークレットキーは別ファイルで定義された変数から読み込むようにしました。 リージョンも外出しにしても良かったのですが、変数定義のバリエーションを確認したいため、リージョンはこのファイルの先頭で変数定義を行い、実際はアクセスキーやシークレットキーのように変数から値を読み込むような使用方法を試してみました。 variable "aws_access_key" {} variable "aws_secret_key" {} variable "region" { default = "us-west-2" } provider "aws" { access_key = "${var.aws_access_key}" secret_key = "${var.aws_secret_key}" region = "${var.region}" } EC2インスタンス作成用定義ファイル「ec2.tf」 今回はとにかく動かしてみることを目的にしていますので、簡単そうなEC2のインスタンスを構築してみます。 使用するamiはUbuntu 20.04を使用してみます。 構築台数は1台、サイズはt2.microで構築します。 resource "aws_instance" "xxxxxxxxxx_tf-ec2" { count = 1 ami = "ami-03d5c68bab01f3496" # Ubuntu 20.04 LTS official ami instance_type = "t2.micro" tags = { Name = "${format("xxxxxxxxxx_tf-ec2-%02d", count.index + 1)}" } } terraformの初期設定 上記ファイルを格納しているフォルダで初期設定コマンドを実行します。 このコマンドを実行することでterraformが使用するファイルが認識されるようになるよです。 gitコマンドを使う前に実行する「git init」によく似ています。 # terraform init Initializing the backend... Initializing provider plugins... - Reusing previous version of hashicorp/aws from the dependency lock file - Using previously-installed hashicorp/aws v2.70.0 Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary. ログ出力設定 どうやってログを確認するのか確認したところ、どうやら実行前に以下の設定を行っておくと良いらしいです。 $ export TF_LOG=1 $ export TF_LOG_PATH='./terraform.log' 「terraform apply」実行後に、「cat terraform.log」でログを確認できるようです。 terraformの実行計画を事前に確認する 実際に構築する前に、どのような内容で構築されるのかを確認することができるようです。 ここで出力された結果をよく見て、意図した内容かを確認しておくのが良さそうです。 構築前のレビューの材料にも使えそうな情報でした。 # terraform plan Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # aws_instance.xxxxxxxxxx_tf-ec2[0] will be created + resource "aws_instance" "xxxxxxxxxx_tf-ec2" { : : : Plan: 1 to add, 0 to change, 0 to destroy. ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now. terraformで実際に構築してみる 内容を確認したら、実際に構築してみます。 planを実行したときのような情報が出力されますが、最後に構築してもよいか問われますので「yes」と入力してエンターを押下します。 # terraform apply Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # aws_instance.xxxxxxxxxx_tf-ec2[0] will be created + resource "aws_instance" "xxxxxxxxxx_tf-ec2" { : : : Plan: 1 to add, 0 to change, 0 to destroy. Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes aws_instance.xxxxxxxxxx_tf-ec2[0]: Creating... aws_instance.xxxxxxxxxx_tf-ec2[0]: Still creating... [10s elapsed] : : : Apply complete! Resources: 1 added, 0 changed, 0 destroyed. terraformの実行結果を確認 実行結果をコマンドでも確認することができるようです。 # terraform show # aws_instance.xxxxxxxxxx_tf-ec2[0]: resource "aws_instance" "xxxxxxxxxx_tf-ec2" { ami = "ami-03d5c68bab01f3496" arn = "arn:aws:ec2:us-west-2:854542366722:instance/i-0e75162145dc7f328" associate_public_ip_address = true availability_zone = "us-west-2a" 念のためにAWS Management Consoleでも確認してみる コマンドでも確認しましたが、念のためにManagement Consoleにログインして確認してみます。 確かに構築できているようです。 terraformで構築した環境をすべて削除する 今回は構築してみることが目的ですし、費用削減のために今構築した環境を削除します。 今回はDestroyコマンドを使い一括で削除しましたが、個別に削除できるのかどうかは別途調査が必要です。 # terraform destroy aws_instance.xxxxxxxxxx_tf-ec2[0]: Refreshing state... [id=i-0e75162145dc7f328] Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: - destroy Terraform will perform the following actions: # aws_instance.xxxxxxxxxx_tf-ec2[0] will be destroyed - resource "aws_instance" "xxxxxxxxxx_tf-ec2" { : : : Plan: 0 to add, 0 to change, 1 to destroy. Do you really want to destroy all resources? Terraform will destroy all your managed infrastructure, as shown above. There is no undo. Only 'yes' will be accepted to confirm. Enter a value: yes aws_instance.xxxxxxxxxx_tf-ec2[0]: Destroying... [id=i-0e75162145dc7f328] aws_instance.xxxxxxxxxx_tf-ec2[0]: Still destroying... [id=i-0e75162145dc7f328, 10s elapsed] aws_instance.xxxxxxxxxx_tf-ec2[0]: Still destroying... [id=i-0e75162145dc7f328, 20s elapsed] : : : Destroy complete! Resources: 1 destroyed. 念のためにAWS Management Consoleでも確認してみる 当然の結果ではありますが、ちゃんとインスタンスは削除されていました。 おわりに 今回は非常に簡単な内容のEC2インスタンスを1つ構築するだけでしたが、IaCの一端に触れることできました。 Terraformのテンプレートファイルはこちらでも公開されているので、自分が構築したい環境に応じて値を修正し実行することで環境を構築できそうです。 指定する情報はテンプレートに直接記述せず、変数化し、汎用性を上げると良いと思います。 Docs overview | hashicorp/aws | Terraform Registry 今はローカルにあるファイルですが、gitLabなどに登録し、そこからcloneして実行するような環境もできれば作ってみたいと思いました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Serverless Application Model (SAM) のすゝめ

はじめに 内部の業務改善の一環として、ちょっとしたWEBアプリを作りました。 その際にSAMを利用したのですが、バックエンド構築を爆速を実施でき、感動したので、この記事ではSAMやらIaCの事を書こうかと思います。 システム構成とモチベーション 超簡略のシステム図はこのような感じ。 フロント Next.jsのSSG (Static Site Generator ) によるStaticコンテンツ生成 + S3ホスト (※)社内ホストなのでCloudFrontといったCDN連携は無し バックエンド SAM(API Gateway & Lambda) DB Aurora Serverless v1 (※) v2 はまだPreview。。 本システムのモチベーションはALLサーバレスで構築!です 何故サーバレスにこだわるのかって? インフラのメンテしなくていい!サーバレスだと従量課金なので安い!ビジネスロジック開発に集中できる! これに尽きるかと思います。 ( 深夜にメンテするなんて嫌なのです。夜にわちゃわちゃ作業なんてしたくないのです。。用意されているものは使い倒していきましょう) ところで、AWSでサーバレス!と言ったら先ず思い浮かぶのはLambdaではないでしょうか? しかし、マネジメントコンソールでLambda開発していては諸々不便です。 マネジメントコンソール上からLambda叩いて問題なさそうならAPI Gateway を接続して〜〜なんてやっていたらめちゃ時間がかかります。(そして事故る匂いがプンプンします) そして何より、フロント・バックエンド・DBでコーディング期間は3週間。。納期は何としてでも間に合わせなければなりません そんな時に私は思いました「せや、SAM使ってローカル開発したらええやんけ。デプロイも楽やし」 そもそもSAMって? SAMは Serverless Application Model の略称で、その名の如くサーバレス(Lambda、API Gateway、DynamoDB...etc)に特化した開発フレームワークです。 ガリガリ開発している中で、個人的にSAMの導入でうれしかったこと3点を上げてみました。 SAM導入で嬉しいことTop3 ローカルで実環境相当のAPI Gateway ⇔ Lambda の挙動がエミュレートができる テンプレート化できる(CloudFormationの拡張、という位置付け) デプロイが楽 (sam deploy コマンドで一撃) 1.ローカルで実環境相当のAPI Gateway ⇔ Lambda の挙動がエミュレートができる もうこれだけでも導入の価値はありますよね。 SAMが裏でDockerコンテナを立ち上げて環境をエミュレートしてくれるので、バグやらをある程度手元でシューティングしてからAWS環境へリフトできます。 マネジメントコンソール上で0からポチポチデバッグは辛すぎます。トレースも辛い。。 ローカルで動かしてみるとこんな感じ。 きちんとエミュレートされてますね!良き 2.テンプレート化できる いわゆるIaC ( Infrastructure as Code ) というやつですね。 テンプレートファイルにLambda関数の設定やランタイムの設定、実行トリガー など諸々の情報を記載することができます。 SAMの裏でCloudFormationスタックが立ち上がるので、あれ?今どのバージョンがデプロイされているんだっけ? みたいな事が減ります。 また、別スタックとしてデプロイしてあげることで、同じ環境をポカンと立ち上げることができます。間違えてバルスしてしまっても安心ですね。素敵 sam init してもろもろ入力してあげると右のようなテンプレートyamlが出来上がる。 よくよく眺めてみると ネイティブのCloudFormationと若干違うけど、直感的で見やすいですね あとはこのテンプレートに関数を追加したり認証を追加したりして拡張していきましょう。 (samビルドすると、samテンプレートからCFnテンプレートへのコンバート処理が走るらしい) 3.デプロイが楽 手動だと、sam deploy コマンド一発で現行リソースとの差分検知、失敗したらロールバックまでできます。 ちなみにCodeCommit、CodePipelineと連携してあげると、mainブランチにコミットが入ったら自動ビルド&自動デプロイ なんて事もできます。 sam deploy、mainブランチコミットしたら、コーヒーでも飲んでボーッとしている間にデプロイが終わっています。いい時代になったもんです。。 2.テンプレート化できるで作った SAMテンプレートをデプロイしてあげると、、 CloudFormationスタックが立ち上がり、、 API Gateway ⇔ Lambda の部分もちゃんとデプロイされていますね!いやぁ、これは楽だ。。 (※)SAMの更に深い情報はAWSサービスカットの資料をご覧ください https://d1.awsstatic.com/webinars/jp/pdf/services/20190814_AWS-Blackbelt_SAM_rev.pdf まとめ SAMでのIaC導入は少し学習コストがあるのですが、yamlテンプレートのお作法さえ理解してしまえば、 爆速で開発ができる、環境デプロイ時に動かない、バージョン管理が破綻した のような本質的ではない苦行から開放されるので、とても良いなあと思いました。 そして、どれだけ打鍵しようがローカル環境なので無料です。お財布に優しい! AWSでサーバレス構成でシステム作る!という時は選択肢の一つとして検討しても良いかもしれません (CloudFormationでもLambdaやらAPI Gatewayはデプロイできるっちゃあできるのですが、S3にソースコードのZipをアップしないといけないので、若干手間。。) おまけ SAMテンプレートはCFnテンプレートの拡張なので、IAM Roleといったリソースを定義しても sam deploy でのデプロイ対象となります。 今回作ったシステムではXrayトレースをONにして環境構築していたので、RoleやらLayerをまとめてビルドしていました。 yamlファイルを少し書き換えるだけで様々なことが自動化できるなんて、IaC素晴らしいですね、目指せヤムラー そしてX-ray、かなり細かくトレースできていて見ていて楽しい。。 yamlの抜粋版はこんな感じ Tracing: Activeの部分でX-Rayトレースを有効化しています。 Resources: LambdaRole: Type: AWS::IAM::Role Properties: Path: / RoleName: 'LambdaSAMRole' AssumeRolePolicyDocument: Statement: - Effect: "Allow" Principal: Service: - "lambda.amazonaws.com" Action: - "sts:AssumeRole" MaxSessionDuration: 3600 ManagedPolicyArns: - 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole' - 'arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole' - 'arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess' FunctionLayer: Type: AWS::Serverless::LayerVersion Properties: Description: Layer description ContentUri: 'FunctionLayer/' CompatibleRuntimes: - python3.8 Metadata: BuildMethod: python3.8 LoginFunction: Type: AWS::Serverless::Function Properties: Role: !GetAtt LambdaRole.Arn CodeUri: LoginFunction/ Handler: app.lambda_handler Runtime: python3.8 Tracing: Active Layers: - !Ref FunctionLayer Events: login: Type: Api Properties: RestApiId: !Ref RestApi Path: /api/login Method: POST
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

独自ドメインを設定する / 障害時はSORRYページへ通信を流す

内容 この記事はAWS初学者を導く体系的な動画学習サービス 「AWS CloudTech」の課題カリキュラムで作成しました。 https://aws-cloud-tech.com 前回の「スケーラビリティのあるブログサービスを構築する」のレッスンに引き続き、今回はRoute53とS3の機能を使い、独自ドメインを設定と障害時にSORRYページへ通信を流すという設定を行なっていきたいと思います。 前回の記事 現状は、クライアントのブラウザのURL欄にロードバランサーのドメイン名を入力すると、ロードバランサーまでアクセスでき、ブログが表示される状態です。 今回は、まずFreenomというサービスを利用して無料のドメインを取得します。 取得したドメインでアクセスできるようにRoute53に設定変更を加えていきます。 Route53は外部のサービスで取得したドメインも設定ができます。 その後、フェイルオーバールーティングの設定を行います。 S3にHTMLファイルをアップロードして、S3の静的ウェブサイトホスティング機能でSorryサイトを作成します。 プライマリの通信に問題が発生した場合は、セカンダリに通信を流す設定を行います。 実施手順 前回の記事の構成がされていることを前提で進めていきます。 準備 EC2インスタンスが2台立ち上がっていることを確認 RDSを削除した場合は、スナップショットから復元しておく。 復元したデータベースのステータスが利用可能になるまで待つ。 ロードバランサーのIPアドレスでブログが閲覧できることを確認しておく。 ドメインの取得とRoute53の設定 今回は無料でドメインを取得できるFreenomというサービスを利用します。 Freenom https://www.freenom.com/ja/index.html Freenomにアクセスし、新しい無料ドメインを探しますと表示されている検索窓から希望するドメイン名を検索する。 検索結果が表示されるので、一覧の中から今すぐ入手!を選択 今すぐ入手!が選択となったらチェックアウトを選択 Periodで使用する期間を選択(12ヶ月までは無料) Continueを選択 ログインしていない場合はGoogleのアカウントなどと紐づけておく。 ログイン後、右上のタブから名前を選択、view cartを選択すると、カートの中身が表示されるので、利用規約確認のチェックボックスにチェックをいれ、Complete Orderを選択 画面が切り替わるので、上部のServicesタブからMy Domainsを選択 入手したドメインのManage Domainを選択 Management ToolsタブからNameserversを選択 Use custom nameservers (enter below)のラジオボタンをチェック ネームサーバーの記入箇所が出てくるので開いたままにしておく。 現状だと、Freenomの方でDNSレコードの設定などの作業が必要になるので、ドメインの管理サーバーをRoute53のネームサーバーに書き換えます。 Route53の画面を開き、ホストゾーンの作成を選択 ドメイン名:先ほど入手したドメイン名を入力 ホストゾーンの作成を選択 レコードの値/トラフィックのルーティング先の4つの値を1つずつ先ほどのFreenomのネームサーバーの記入箇所にコピーする。 Change Nameserversを選択 上記の作業は、「取得したドメインは、Route53で管理します。」とFreenomに教えてあげているイメージになります。 取得したドメインとロードバランサーを紐づける Route53のホストゾーンから作成したドメイン名を選択し、レコードを作成を選択 ルーティングポリシーはシンプルルーティングを選択して次へ進む。 シンプルなレコードを定義を選択 レコード名を入力 値/トラフィックのルーティング先:Application Load BalancerとClassic Load Balancerへのエイリアスを選択 リージョンは東京を選択 シンプルなレコードを定義を選択 レコードを作成を選択 取得したドメイン名をブラウザのURL欄に貼り付けて、ブログにアクセスできることを確認する。 S3バケットの作成 S3の静的ウェブサイトホスティング機能でSorryサイトを作成します。 S3バケットの名前をドメインの名前と同じにする必要があるので注意しましょう。 S3の画面に移動し、バケットを作成を選択 バケット名にはドメイン名を入力 パブリックアクセスをすべてブロックのチェックを外す。 現在の設定により、このバケットとバケット内のオブジェクトが公開される可能性があることを承認します。にチェックをつける。 バケットを作成を選択 Sorryページの設定 作成したバケットを選択 アップロードを選択 ファイルを追加とフォルダを追加を選択して表示させたいファイルやフォルダを選択 アップロードを選択 閉じるを選択 プロパティタブを選択 下にスクロールすると静的ウェブサイトホスティングの項目があるので編集を選択 静的ウェブサイトホスティング:有効にするにチェックをつける。 インデックスドキュメントを入力(HTMLファイルの名前) エラードキュメントを入力(error.htmlでOK) 変更の保存を選択 アクセス許可タブを選択 バケットポリシーの項目の編集を選択 AWS公式サイトのバケットポリシーのサンプルコードをコピーしてペースト(https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/WebsiteAccessPermissionsReqd.html) サンプルコードでBucket-Nameとなっている箇所をバケット名に変更する。 変更の保存を選択 プロパティタブの静的ウェブサイトホスティングからバケットウェブサイトエンドポイントを選択し、Sorryページが表示されることを確認する。 フェイルオーバールーティングの設定 プライマリの通信に異常があった場合にセカンダリとしてSorryページが表示されるように設定します。 Route53を開き、レコード名がドメイン名のものを選択し、レコードを編集を選択 ルーティングポリシー:フェイルオーバーに変更 フェイルオーバーレコードタイプ:プライマリを選択 レコードIDを入力(例. LB-P) 保存を選択 続いてセカンダリ用のRoute53のDNSレコードを作成します。 レコードを作成を選択 フェイルオーバーを選択して次へ レコード名はプライマリと合わせる。 TTL (秒)はテストなので60としておく。 フェイルオーバーレコードを定義を選択 値/トラフィックのルーティング先:S3 ウェブサイトエンドポイントへのエイリアスを選択 リージョンは東京を選択 S3バケットの項目は先ほど作成したバケットを選択 フェイルオーバーレコードタイプ:セカンダリを選択 レコードIDを入力(例. LB-S) フェイルオーバーレコードを定義を選択 レコードを作成を選択 設定した機能を確認 一度取得したドメイン名でアクセスして問題なく閲覧できることを確認 サービスに障害が発生したと仮定して、EC2インスタンスを2台とも停止させる。 インスタンス停止後に再度アクセスしてSorryページが表示されることを確認する。 EC2インスタンスを2台とも起動させる。 インスタンス起動後に再度アクセスして通常のページが閲覧できることを確認できればOK
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ゲーム開発するにあたってやることをまとめる。

前回の記事の続きから、ゲーム開発をしたいと思い、特にクラウドでの部分を勉強したいと思うので、その備忘録を書くことになりました。 必要な物 AWS
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

goofys の --use-content-type オプションが限られた拡張子でしか有効にならない問題の解消方法

問題 Amazon Linux 2 上で goofys を使ってマウントした S3 バケットにファイルをアップロードし、これを直接ダウンロードさせる場合、 S3 オブジェクト保存時に指定された Content-Type 設定が利用される。 しかし、何のオプションも渡さずに goofys で S3 オブジェクトをマウントした場合、デフォルト値として binary/octet-stream が利用されてしまい、予期せぬ挙動が起こることがある。 例えば PDF ファイルが binary/octet-stream 形式だと、ブラウザによっては別ページで開かずにダウンロードしてしまう。 これを解消するために、goofys の実行時に --use-content-type オプションを利用することができる。 少し古いが、以下の記事を参照。 これを付けておけばOKと思っていたのだが、メジャーな拡張子、例えば .mp3 のファイルをアップロードした場合にContentTypeが識別されず、binary/octet-stream になってしまう状況に直面した(ただし、.jpg などの一部の拡張子は image/jpeg として設定されるなど、正常に識別される時もあった)。 この問題の解決方法を探る。 原因と解決策 このあたりを読めばわかるのだが、拡張子から ContentType を推論するのには /etc/mime.types ファイルを利用している(先の DevelopersIO の記事にもちゃんと書いてある)。 しかし、記事執筆時点でレコメンドされる Amazon Linux 2 (amzn2-ami-hvm-2.0.20210525.0-x86_64-gp2, ap-northeast-1 の場合は ami-001f026eaf69770b4 ) この辞書ファイルがデフォルトで入っていない。 $ ls /etc/mime.types ls: cannot access /etc/mime.types: No such file or directory なので、これを手動でインストールしてやる必要がある。 yum provides で引いてみると、幸い、amzn2-core にあるので、mailcap をインストールした後にファイルをチェック。 $ sudo yum provides /etc/mime.types Loaded plugins: extras_suggestions, langpacks, priorities, update-motd mailcap-2.1.41-2.amzn2.noarch : Helper application and MIME type associations for file types Repo : amzn2-core Matched from: Filename : /etc/mime.types $ sudo yum -y install mailcap (インストールの過程は略) # コンテンツの中身を確認 $ head -n 30 /etc/mime.types # This is a comment. I love comments. -*- indent-tabs-mode: t -*- # This file controls what Internet media types are sent to the client for # given file extension(s). Sending the correct media type to the client # is important so they know how to handle the content of the file. # Extra types can either be added here or by using an AddType directive # in your config files. For more information about Internet media types, # please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type # registry is at <http://www.iana.org/assignments/media-types/>. # IANA types # MIME typeExtensions application/1d-interleaved-parityfec application/3gpp-ims+xml application/activemessage application/andrew-insetez application/applefile application/atom+xmlatom application/atomcat+xmlatomcat application/atomdeleted+xmlatomdeleted application/atomicmail application/atomsvc+xmlatomsvc application/auth-policy+xmlapxml application/batch-SMTP application/beep+xml application/calendar+xmlxcs application/call-completion application/cals-1840 application/ccmp+xmlccmp これをインストールした後に goofys を再起動してファイルをマウントされたバケットに goofys 経由でコピーすれば、拡張子に応じた ContentType が S3 上のオブジェクトに反映されるようになった。 デフォルトで入っていないケースもあるようなので、 goofys 経由でファイルをアップロードする場合は、ちゃんと /etc/mime.types があるか否かをチェックする癖をつけた方がよいかもしれない。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む