20210608のAWSに関する記事は18件です。

KCLについてまとめる①

KCLとは KCLはアプリケーションロジックとKinesis Data Stream(KDS)を仲介し、以下を行う。 ストリームに接続 ストリーム内のシャードを列挙 リースを使用して、シャードとそのワーカーとの関連付けを調整 レコードプロセッサで管理する各シャードのレコードプロセッサをインスタンス化 データストリームからデータレコードを取得 対応するレコードプロセッサにレコードを送信 処理されたレコードのチェックポイントを作成 ワーカーインスタンス数が変更された場合、またはリシャードが発生した場合、シャードワーカー関連(リース)の調停を実施 KCLはJavaで動いている→アプリプログラムをPythonで書く場合、KCL for Pythonをインストールし、MultiLangDaemonを利用する。 Kinesisはシャードという概念によって分散処理が可能になっているが、分散処理を行うインスタンス間の連携や ストリーミングデータをどこまで処理したかの管理は自分で実装するのは大変なので、その面倒な部分をやってくれ、 アプリロジックに集中できるということですかね。 KCLのバージョン KCLの現在サポートされているバージョンはKCL1.x、KCL2.x。 KCL2.xのみで拡張ファンアウトが利用可能でデフォルトで拡張ファンアウトが設定される。 追加で料金がかかるが、ストリームに対して複数のコンシューマがいる場合や、低レイテンシが求められる場合に使用する。  拡張ファンアウトとは ストリームからデータを受け取る他のコンシューマーと競合しない→1つのストリームに対して複数のコンシューマがいることによる最大読み取り性能の超過の心配がない コンシューマーは、シャードあたり1秒間に最大2MBのデータのスループットで、ストリームからレコードを受け取る ストリームはデータレコードを拡張ファンアウトを使用するコンシューマーに送信するため、コンシューマーはデータをポーリングする必要がない 拡張ファンアウトの流れ ストリームのコンシューマーとして自身を登録 KCL はシャードを列挙して、SubscribeToShard APIを使用してそれらにサブスクライブする。 リーステーブルを作成し、分散アプリケーションのチェックポイントと状態管理を行う。 おわりに 次回はKCLの概念についてまとめる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

KCLについてまとめる

KCLとは KCLはアプリケーションロジックとKinesis Data Stream(KDS)を仲介し、以下を行う。 ストリームに接続 ストリーム内のシャードを列挙 リースを使用して、シャードとそのワーカーとの関連付けを調整 レコードプロセッサで管理する各シャードのレコードプロセッサをインスタンス化 データストリームからデータレコードを取得 対応するレコードプロセッサにレコードを送信 処理されたレコードのチェックポイントを作成 ワーカーインスタンス数が変更された場合、またはリシャードが発生した場合、シャードワーカー関連(リース)の調停を実施 KCLはJavaで動いている→アプリプログラムをPythonで書く場合、KCL for Pythonをインストールし、MultiLangDaemonを利用する。 Kinesisはシャードという概念によって分散処理が可能になっているが、分散処理を行うインスタンス間の連携や ストリーミングデータをどこまで処理したかの管理は自分で実装するのは大変なので、その面倒な部分をやってくれ、 アプリロジックに集中できるということですかね。 KCLのバージョン KCLの現在サポートされているバージョンはKCL1.x、KCL2.x。 KCL2.xのみで拡張ファンアウトが利用可能でデフォルトで拡張ファンアウトが設定される。 追加で料金がかかるが、ストリームに対して複数のコンシューマがいる場合や、低レイテンシが求められる場合に使用する。  拡張ファンアウトとは ストリームからデータを受け取る他のコンシューマーと競合しない→1つのストリームに対して複数のコンシューマがいることによる最大読み取り性能の超過の心配がない コンシューマーは、シャードあたり1秒間に最大2MBのデータのスループットで、ストリームからレコードを受け取る ストリームはデータレコードを拡張ファンアウトを使用するコンシューマーに送信するため、コンシューマーはデータをポーリングする必要がない 拡張ファンアウトの流れ ストリームのコンシューマーとして自身を登録 KCL はシャードを列挙して、SubscribeToShard APIを使用してそれらにサブスクライブする。 リーステーブルを作成し、分散アプリケーションのチェックポイントと状態管理を行う。 おわりに 次回はKCLの概念についてまとめる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS CloudFrontのアクセスを一律リダイレクトするように設定できるまでの話

背景 この間、運営している2つのメディアサイトを統合させたくて、AWSのCloudFrontで配信している古いサイトから外部のサイトに移行する必要があった。 old.example.comはCloudFrontを使ってS3に入っているコンテンツを配信しているサイト new.example.comはAWS外でホスティングしているサイト 古いサイトのページはアクセス数が少ないため、内容は移行せずold.example.com/*に来たアクセスを一律new.example.com/homeにリダイレクトするのが今回の要件。 なお、AWSのリソースや設定はTerraformで管理している。 やったことその① HostNameとReplaceKeyWithでURLを完全に書き換える まずはリダイレクトの基本設定として、RoutingRulesにRedirectRuleを追加する。 ReplaceKeyWithを使ってすべてのリクエストを同じURLにリダイレクトする。そして、今回リダイレクトしたいURLはドメインも違うのでHostNameでリダイレクト先のドメインになる。(外部のドメインになるということは特に意識する必要はない。) website { routing_rules = jsonencode([ { Redirect = { HostName = "new.example.com" HttpRedirectCode = "301" Protocol = "https" ReplaceKeyWith = "home" } } ]) } こうするとドメインもそれ以降のURL(CloudFormationでS3オブジェクトのキーとして使われていた部分)も置き換えられる。 やったことその② IndexDocumentを追加する すべてのリクエストをリダイレクトしているからIndexDocumentはいらないと思っていたけど、 terraform applyをしたら以下のエラーが発生した。 Error: Must specify either index_document or redirect_all_requests_to. どうやらTerraformの使用上、redirect_all_requests_toを使っていない限り、IndexDocumentの設定が必須。 website { index_document = "home" routing_rules = jsonencode([ { Redirect = { HostName = "new.example.com" HttpRedirectCode = "301" Protocol = "https" ReplaceKeyWith = "home" } } ]) } ページを含めて移行していたら、redirect_all_requests_toですべてのリクエストのドメインだけを変えてリダイレクトを設定できるけど、どのリクエストでも固定したページにリダイレクトしたいのでIndexDocumentとして現在の「Default Root Object」のキーを設定することにした。 やったことその③ CloudFrontのOriginを変更する 上記のリダイレクト設定は正しいが、そもそもリダイレクトを使うためにCloudFrontが使っているS3 BucketのURLを変更する必要があるのが分かった。 NG: old-example-files.s3.amazonaws.com OK: old-example-files.s3-website.ap-northeast-1.amazonaws.com (CloudFrontのOrigin設定なのでブラウザに入力するURLと関係ない) origin { - domain_name = aws_s3_bucket.old_example_files.bucket_domain_name + domain_name = aws_s3_bucket.old_example_files.website_endpoint origin_id = "S3-old-example-files" } Terraformの場合、aws_s3_bucketのリソースにwebsite_endpointという属性が使える。 やったことその④ Custom Origin Configを追加する リソースの変更は成功したけど、ブラウザで古いサイトのページにアクセスしてみるとそもそも開かない… When we want to create a CloudFront origin for a S3 static website, we must define a custom_origin_config, otherwise it won't work. Custom Origin Configの設定も必要か。 origin { domain_name = aws_s3_bucket.old_example_files.website_endpoint origin_id = "S3-old-example-files" custom_origin_config { http_port = 80 https_port = 443 origin_protocol_policy = "https-only" origin_ssl_protocols = ["TLSv1.2"] } } やったことその⑤ 使っているAWSリージョンの正しいウェブサイトエンドポイントを使うようにする AWSリージョンによってURLが違うよ、とAWSのドキュメンテーションに書いてあったからTerrraformがよしなにやってくれると思いきや、そうでもなかった… NG: old-example-files.s3-website-ap-northeast-1.amazonaws.com OK: old-example-files.s3-website.ap-northeast-1.amazonaws.com どのリージョンでも、Terraformのwebsite_endpointが生成するのは上の方になる。 リージョンはTerraformの変数として用意して、正しいURLを生成するロジックを自前で実装した。 -domain_name = aws_s3_bucket.old_example_files.website_endpoint +domain_name = "${aws_s3_bucket.old_example_files.bucket}.s3-website.${var.aws_region}.amazonaws.com" ※ ap-northeast-1以外のリージョンを使う予定はなかったけど、他のリージョンも使使いたい場合は適切なロジックを組めばいい。各リージョンのウェブサイトエンドポイントがこちらで確認できる。 やったことその⑥ HTTPステータスによってリダイレクトするように変更する ここまで来てやっとリダイレクトできるようになった ただ、そもそもBucketの中身も消したい…と思った時、この設定ではいけない。S3にファイルがある前提の設定になるので、コンテンツがなくても対応できるように少し変える必要がある。 website { index_document = "home" routing_rules = jsonencode([ { Redirect = { HostName = "new.example.com" HttpRedirectCode = "301" Protocol = "https" ReplaceKeyWith = "home" } + RoutingRuleCondition = { + HttpErrorCodeReturnedEquals = "404" + } } ]) } RoutingRuleConditionを追加することで、リクエストされたオブジェクトが見つからない時だけリダイレクトするように変わる。S3 Bucketのすべてのオブジェクトを削除する予定なので、どのリクエストも404になる。つまり、どのリクエストもリダイレクトされる。 最後に ここまですれば古いサイトへのリクエストはすべて新しいサイトにリダイレクトされるし、古いS3の中身を消してもOK! 1点だけ注意が必要 リダイレクトさせるためにS3のBucket自体とCloudFrontのDistributionが必要になるので、リダイレクトさせたい間はリソースを残し続けないといけない。 リダイレクトをやめて古いサイトを完全に捨てる、ということになったらもちろんこれらのリソースも削除しちゃっても問題ない。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Systems Manager Session Managerが繋がらないときのチェックリスト【プライベートサブネット・NATなし】

はじめに Session Managerを使用した接続で詰まったので、自分用に作成しました。 接続先インスタンスのNW状態やSession Managerの設定は以下を想定しています。 インスタンスはプライベートサブネットに配置 NATなし S3,CloudWatch Losgにロギング インスタンスが上記NW状態の場合、ロギングで使用するサービスのVPCエンドポイントも必要になるので注意 ログはKMSで暗号化 S3はAWSマネージドCMK、CloudWatch LogsはカスタマーマネージドCMK 私の場合、上記3つ目のロギング設定で、CloudWatch LogsのVPCエンドポイントを作成していなかったので接続できませんでした。 コンソール画面でSession ManagerのStart Sessionを始めると、プロンプトが表示されない黒い画面のままずっと変化がない上、エラー文が出ないので困ってしまいました。 本記事の情報は2021.6.8現在の情報ですので、参考にする際はお気をつけください。 チェックリスト チェック項目 確認事項 根拠 エージェント 接続先インスタンスにSSMエージェントがインストールされているか。バージョンは必要とする機能をサポートしているか https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/ssm-agent-technical-details.html#ami-preinstalled-agent インスタンスのIAMロール Session Managerを使用するために必要な権限を有しているか https://docs.aws.amazon.com/systems-manager/latest/userguide/getting-started-create-iam-instance-profile.html インスタンスのセキュリティグループ アウトバウンドは443を許可しているか(宛先:VPCエンドポイントが使用するNWインターフェースのプライベートIPアドレス。もちろんデフォルトの全て許可でも通る) https://aws.amazon.com/jp/premiumsupport/knowledge-center/systems-manager-ec2-instance-not-appear/ VPCエンドポイント 必要なVPCエンドポイントを作成しているか。Session Managerでロギングする場合、S3やCloudWatch LogsのVPCエンドポイントも必要。AWS KMSのエンドポイントは不要(セッションの暗号化を有効化する場合は必要) https://aws.amazon.com/jp/premiumsupport/knowledge-center/ec2-systems-manager-vpc-endpoints/ VPCエンドポイントの場所 適切なVPC、サブネットに作成しているか 同上 VPCエンドポイントのセキュリティグループ インバウンドの443を許可しているか(ソース:インスタンスが存在するVPCのCIDR) 同上 VPCのDNS VPCのDNSホストネームとDNSサポートが有効になっているか 同上 CloudWatch LogsのCMKキーポリシー(CloudWatch LogsでKMSを使用している場合) キーポリシーでCloudWatch Logsをプリンシパルとして暗号・復号等のアクションを許可しているか。していない場合、Session Managerは接続できるがCloudWatch Logsのログが見れない(ログストリームはあるものの、中身が空の状態だった)。 検証した結果 キーポリシー抜粋 { "Effect": "Allow", "Principal": { "Service": "logs.ap-northeast-1.amazonaws.com" }, "Action": [ "kms:Encrypt*", "kms:Decrypt*", "kms:ReEncrypt*", "kms:GenerateDataKey*", "kms:Describe*" ], "Resource": "*", "Condition": { "ArnLike": { "kms:EncryptionContext:aws:logs:arn": "arn:aws:logs:ap-northeast-1:{Account-Id}:log-group:{CloudWatchLogs-LogGroupName}" } } } インスタンスのIAMロール { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ssmmessages:CreateControlChannel", "ssmmessages:CreateDataChannel", "ssmmessages:OpenControlChannel", "ssmmessages:OpenDataChannel", "ssm:UpdateInstanceInformation" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "logs:CreateLogStream", "logs:PutLogEvents", "logs:DescribeLogGroups", "logs:DescribeLogStreams" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "s3:PutObject" ], "Resource": "arn:aws:s3:::{Bucket-Name}/*" }, { "Effect": "Allow", "Action": [ "s3:GetEncryptionConfiguration" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "kms:GenerateDataKey", "kms:Decrypt" ], "Resource": "arn:aws:kms:ap-northeast-1:{Account-Id}:key/xxxxxx-635f-4454-8f2f-xxxxxxxxxxx" } ] } 上記kms:Decryptはセッションデータの暗号化をしなければ不要。 セッションデータの暗号化をする際のアクセス許可は以下のとおりにすればよい。 参考情報 セッションデータを暗号化するとロギングできなくなる https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager.html セッションデータを暗号化して接続すると以下のメッセージが表示される This session is encrypted using AWS KMS. Session Managerのログを配信するS3は他のアカウントのS3でもよい。 チェックリストの"インスタンスのIAMロール"の根拠欄記載のURLに"別のAWSアカウントが所有するAmazon S3バケットにセッションログを出力するには"といった旨の記載がある。 インスタンスのIAMロールの反映は、SSMエージェントが検出するまで待機するか、SSMエージェントを再起動する必要がある https://aws.amazon.com/jp/premiumsupport/knowledge-center/assign-iam-role-ec2-instance/ Session Manager を使用して Amazon EC2 インスタンスに接続できないのはなぜですか? https://aws.amazon.com/jp/premiumsupport/knowledge-center/ssm-session-manager-connect-fail/ AWS Systems Manager Session Manager の問題をトラブルシューティングする方法を教えてください。 https://aws.amazon.com/jp/premiumsupport/knowledge-center/ssm-session-manager-failures/ EC2 Linux インスタンスで Session Manager シェルを bash に変更するにはどうすればよいですか? https://aws.amazon.com/jp/premiumsupport/knowledge-center/ssm-session-manager-change-shell/ Session Manager を使用してインスタンスへのアクセスを制御するにはどうすればよいですか? https://aws.amazon.com/jp/premiumsupport/knowledge-center/ssm-session-manager-control-access/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【小ネタ】S3にアクセスするユーザーを作成する

概要 S3にアクセスするだけのユーザーを作成する方法です。 主に備忘目的で残しています。 1. ポリシーの作成 IAM -> ポリシー -> ポリシーの作成 IAMユーザーに付与するポリシーを作成します。 { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:ListAllMyBuckets", "Resource": "*" }, { "Effect": "Allow", "Action": "s3:*", "Resource": [ "arn:aws:s3:::YOUR-BUCKET-NAME" ] } ] } ※YOUR-BUCKET-NAME 適宜置き換えてください。 ※s3:ListAllMyBuckets CloudBerryでバケットを一覧表示するために権限を与えます。 2. ユーザーを追加 2-1 IAM -> ユーザー -> ユーザーを追加 バケットにアクセスするためのユーザーを作成します。 「プログラムによるアクセス」のみチェックを付けます。 2-2 アクセス許可のステップで「既存のポリシーをアタッチ」を選択し、 先ほど作成したポリシーを選択します。 2-3 CSVをダウンロードして保管しておきます。 CloudBerry からアクセス アクセスキーIDとシークレットアクセスキーを使ってアクセスします。 バケットの一覧が表示されますが、許可したバケット以外は開くことができません。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

作りながら覚えるTerraform入門(4) - EC2編

作りながら覚えるTerraform入門シリーズの第4回です。 今回はEC2関連のリソースを作成してみましょう。EC2にはnginxをインストールして、ブラウザでHTTP接続できるところまでを確認します。 作りながら覚えるTerraform入門シリーズ インストールと初期設定 基本編 VPC編 EC2編 => 今回はコチラ Route53 + ACM編 ELB編 RDS編 今回の学習ポイントは以下です。 データソースの使い方 httpプロバイダーの使い方 ローカル変数の使い方 outputの使い方 キーペアの作成 Terraformには現時点ではキーペアを新規作成する方法はないようです。 aws_key_pairというResourceは存在しますが、既存のキー(公開鍵)をインポートするためのものなので、 ssh-keygenでキーペアを作成 aws_key_pairで公開鍵をインポート という流れになるようです。 今回はコンソール画面から作成します。 IAMロールの作成 EC2に割り当てるIAMロールを作成します。 アタッチするポリシーは管理ポリシーのAdministratorAccess を使います。 iam.tfを作成し、以下のコードを貼り付けます。 iam.tf ################################ # IAM ################################ data "aws_iam_policy" "administrator" { arn = "arn:aws:iam::aws:policy/AdministratorAccess" } data "aws_iam_policy_document" "ec2_assume_role" { statement { actions = ["sts:AssumeRole"] principals { type = "Service" identifiers = ["ec2.amazonaws.com"] } } } resource "aws_iam_instance_profile" "ec2" { name = aws_iam_role.ec2.name role = aws_iam_role.ec2.name } resource "aws_iam_role" "ec2" { name = "${var.prefix}-ec2-role" assume_role_policy = data.aws_iam_policy_document.ec2_assume_role.json } resource "aws_iam_role_policy_attachment" "ec2" { role = aws_iam_role.ec2.name policy_arn = data.aws_iam_policy.administrator.arn } まず、aws_iam_roleでIAMロールを作成しています。 この時、assume_role_policyで信頼されたエンティティ(AssumeRole)を指定します。 コンソール画面で作成する場合は、EC2を選択するだけでOKなのですが、 Terraformで指定する場合はJSON形式で指定します。 Resource: aws_iam_role にあるように直接JSONで記述する方法や、リファレンスにはサンプルがありませんがfile関数で指定する方法もあります。 # 直接記述 resource "aws_iam_role" "test_role" { name = "test_role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = "sts:AssumeRole" Effect = "Allow" Sid = "" Principal = { Service = "ec2.amazonaws.com" } }, ] }) } # file関数で読み込み resource "aws_iam_role" "test_role" { name = "test_role" assume_role_policy = file("./param/AssumeRole.json") } 今回のコードではData Sources (以下、データソース)を利用します。 データソースはあるリソースを読み込むために利用されます。 今回のように初めからコンソール画面で選択できるもの(AssumeRole、IAMポリシー、EC2のAMIなど)や、他のTerraformで管理されているリソースを参照する場合に利用します。書き方はResourceブロックと同じ感じですね。 data "aws_iam_policy_document" "ec2_assume_role" { statement { actions = ["sts:AssumeRole"] principals { type = "Service" identifiers = ["ec2.amazonaws.com"] } } } このデータソースを参照するには data.aws_iam_policy_document.ec2_assume_role.json という形で記述します。これもResourceブロックを参照する時と同じ形式です。 ぱっとみ末尾のjsonが拡張子のように見えるかもしれませんが(私だけ?)、これはidやarnを参照する場合と同じでjsonという「属性」を指定しています。 そして、aws_iam_role_policy_attachmentでIAMロールにポリシーをアタッチしています。 policy_arnで指定する「AdministratorAccess」の管理ポリシーもデータソースを使って読み込んだarnをdata.aws_iam_policy.administrator.arnという形で参照しています。 data "aws_iam_policy" "administrator" { arn = "arn:aws:iam::aws:policy/AdministratorAccess" } : resource "aws_iam_role_policy_attachment" "ec2" { role = aws_iam_role.ec2.name policy_arn = data.aws_iam_policy.administrator.arn } データソースを使わず、以下のように直接「AdministratorAccess」のARNを指定しても構いません。ここでデータソースを使うメリットは正直よくわかっていませんが、おそらく、同じポリシーを複数のIAMロールにアタッチする場合はpolicy_arnにハードコーディングせず、データソースを参照させるほうが保守性が向上するのだと思います。 resource "aws_iam_role_policy_attachment" "ec2" { role = aws_iam_role.ec2.name policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess" # policy_arn = data.aws_iam_policy.administrator.arn } 最後に、インスタンスプロファイルの作成です。 resource "aws_iam_instance_profile" "ec2" { name = aws_iam_role.ec2.name role = aws_iam_role.ec2.name } インスタンスプロファイルは、コンソール画面からIAMロールの作成を行った場合には自動的に作成されてIAMロールと関連付けられますのであまり意識することはありませんが、IAMロールをEC2にアタッチする時のコネクタの役割として必要になります。 セキュリティグループの作成 続いて、セキュリティグループを作成します。 security.tfを作成し、以下のコードを貼り付けます。 ここでは、EC2のセキュリティグループと合わせて、ELB、RDS向けのものも作成しておきます。 security.tf ################################ # Security group ################################ # ELB resource "aws_security_group" "elb_sg" { name = "${var.prefix}-elb-sg" vpc_id = aws_vpc.vpc.id tags = { Name = "${var.prefix}-elb-sg" } } resource "aws_security_group_rule" "in_http_from_all" { type = "ingress" from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] security_group_id = aws_security_group.elb_sg.id } resource "aws_security_group_rule" "in_https_from_all" { type = "ingress" from_port = 443 to_port = 443 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] security_group_id = aws_security_group.elb_sg.id } resource "aws_security_group_rule" "out_all_from_elb" { type = "egress" from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] security_group_id = aws_security_group.elb_sg.id } # EC2 resource "aws_security_group" "web_sg" { name = "${var.prefix}-ec2-sg" vpc_id = aws_vpc.vpc.id tags = { Name = "${var.prefix}-ec2-sg" } } data "http" "ipify" { url = "http://api.ipify.org" } locals { myip = chomp(data.http.ipify.body) allowed_cidr = (var.allowed_cidr == null) ? "${local.myip}/32" : var.allowed_cidr } resource "aws_security_group_rule" "in_ssh_from_myip" { type = "ingress" from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = [local.allowed_cidr] security_group_id = aws_security_group.web_sg.id } resource "aws_security_group_rule" "in_http_from_myip" { type = "ingress" from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = [local.allowed_cidr] security_group_id = aws_security_group.web_sg.id } resource "aws_security_group_rule" "in_http_from_elb" { type = "ingress" from_port = 80 to_port = 80 protocol = "tcp" source_security_group_id = aws_security_group.elb_sg.id security_group_id = aws_security_group.web_sg.id } resource "aws_security_group_rule" "out_all_from_ec2" { type = "egress" from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] security_group_id = aws_security_group.web_sg.id } # RDS resource "aws_security_group" "rds_sg" { name = "${var.prefix}-rds-sg" vpc_id = aws_vpc.vpc.id tags = { Name = "${var.prefix}-rds-sg" } } resource "aws_security_group_rule" "in_mysql_from_ec2" { type = "ingress" from_port = 3306 to_port = 3306 protocol = "tcp" source_security_group_id = aws_security_group.web_sg.id security_group_id = aws_security_group.rds_sg.id } resource "aws_security_group_rule" "in_memcached_from_ec2" { type = "ingress" from_port = 11211 to_port = 11211 protocol = "tcp" source_security_group_id = aws_security_group.web_sg.id security_group_id = aws_security_group.rds_sg.id } コードが縦長ですが、上から順にELB、EC2、RDS向けのセキュリティグループを作成しています。 aws_security_groupで空のセキュリティグループを作成し、 aws_security_group_ruleでingress または egress のルールを追加しています。 ELB、EC2のアウトバウンドルールはすべて許可しています。RDSはなし。 インバウンドルールは次の通りです。※MemcachedはRDSのプラグイン追加に合わせて許可しています。 対象サービス インバウンドルール ELB 外部からのHTTP、HTTPSを許可 EC2 ELBからのHTTP、MyIPからのSSH、HTTPを許可 RDS EC2からのMySQL、Memcached接続を許可 aws_security_group_ruleで接続元にIPレンジを指定する場合はcidr_blocksを使い、セキュリティグループを指定する場合はsource_security_group_idを使います。 EC2のインバウンドルールでは、MyIP、つまり自分のPCのグローバルIPアドレスからのSSH、HTTPを許可するようにしています。グローバルIPアドレスを取得するには、IPアドレスを応答してくれるAPIを実行することで実現できます。今回は、ipifyというサービスを利用しています。 TerraformでHTTPのリクエストを送信するには、HTTP Provider のデータソースを使います。 HTTP Providerを利用するためにprovider.tfの末尾にprovider "http" {}の1行を追加します。 provider.tf : provider "http" {} httpのデータソースでipifyのAPIを実行し、その結果からIPアドレスを取り出してmyipというローカル変数に格納しています。外部から変更されることのないような値は locals ブロックを使ってローカル変数として宣言すると便利です。local.変数名の形で参照できます。 許可するグローバルIPアドレスを個別に変数でも指定できるよう、allowed_cidrでは三項演算子(IF文のようなもの)を使って判定しています。指定されていなければAPI実行結果のMyIPを採用し、変数が指定されていればそのIPを採用します。これは、以下の記事を参考にしています。 Terraformで自分のパブリックIPを使う方法 data "http" "ipify" { url = "http://api.ipify.org" } locals { myip = chomp(data.http.ipify.body) allowed_cidr = (var.allowed_cidr == null) ? "${local.myip}/32" : var.allowed_cidr } グローバルIPアドレスを指定するための変数をvariables.tfに追加します。 variables.tf # EC2 variable "allowed_cidr" { default = null } なお、新しいプロバイダーを追加した場合はterraform initが必要になります。HTTP Providerのプラグインが取得されます。 terraform init Initializing the backend... Initializing provider plugins... - Reusing previous version of hashicorp/aws from the dependency lock file - Finding latest version of hashicorp/http... - Using previously-installed hashicorp/aws v3.44.0 - Installing hashicorp/http v2.1.0... - Installed hashicorp/http v2.1.0 (signed by HashiCorp) : terraform applyを実行して、セキュリティグループが3つ作成されていることを確認しましょう。 EC2の作成 最後に、EC2を2台作成します。 ec2.tfを作成し、以下のコードを貼り付けます。 ec2.tf ################################ # ENI ################################ resource "aws_network_interface" "web_01" { subnet_id = aws_subnet.public_subnet_1a.id private_ips = ["10.0.11.11"] security_groups = [aws_security_group.web_sg.id] tags = { Name = "${var.prefix}-web-01" } } resource "aws_network_interface" "web_02" { subnet_id = aws_subnet.public_subnet_1c.id private_ips = ["10.0.12.11"] security_groups = [aws_security_group.web_sg.id] tags = { Name = "${var.prefix}-web-02" } } まず、EC2に接続するネットワークインターフェイスを作成します。 後述のaws_instanceの中でプライベートIPアドレスやセキュリティグループを指定することもできますが、ENIにNameタグを付ける方法がわからなかったので、先にENIを作成して関連付ける方法をとりました。aws_ec2_tagを使えばあとからタグ付けはできるようです。 AZ-1a、1cそれぞれのサブネットIDを指定し、サブネットの範囲内のIPアドレスをprivate_ipsに指定しています。なお、プライベートIPアドレスは複数持つことができるので["10.0.11.11"]のように角かっこで囲った配列の形式になっています。セキュリティグループはEC2向けのものを指定します。 続いて、EC2インスタンスを作成します。ec2.tfに以下のコードを追加します。 ec2.tf ################################ # EC2 ################################ data "aws_ssm_parameter" "amzn2_latest_ami" { name = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" } resource "aws_instance" "web_01" { ami = data.aws_ssm_parameter.amzn2_latest_ami.value instance_type = "t2.micro" iam_instance_profile = aws_iam_instance_profile.ec2.name disable_api_termination = false monitoring = false user_data = file("./param/userdata.sh") key_name = "${var.prefix}-key" network_interface { network_interface_id = aws_network_interface.web_01.id device_index = 0 } root_block_device { volume_size = 8 volume_type = "gp2" delete_on_termination = true encrypted = false } ebs_block_device { device_name = "/dev/sdf" volume_size = 10 volume_type = "gp2" delete_on_termination = true encrypted = false } tags = { Name = "${var.prefix}-web-01" } volume_tags = { Name = "${var.prefix}-web-01" } } resource "aws_instance" "web_02" { ami = data.aws_ssm_parameter.amzn2_latest_ami.value instance_type = "t2.micro" iam_instance_profile = aws_iam_instance_profile.ec2.name disable_api_termination = false monitoring = false user_data = file("./param/userdata.sh") key_name = "${var.prefix}-key" network_interface { network_interface_id = aws_network_interface.web_02.id device_index = 0 } root_block_device { volume_size = 8 volume_type = "gp2" delete_on_termination = true encrypted = false } ebs_block_device { device_name = "/dev/sdf" volume_size = 10 volume_type = "gp2" delete_on_termination = true encrypted = false } tags = { Name = "${var.prefix}-web-02" } volume_tags = { Name = "${var.prefix}-web-02" } } output "web01_public_ip" { description = "The public IP address assigned to the instanceue" value = aws_instance.web_01.public_ip } output "web02_public_ip" { description = "The public IP address assigned to the instanceue" value = aws_instance.web_02.public_ip } このあたりでそろそろ「コードが冗長なんでループで回す方法ないの?」と思われるかもしれませんが、その方法はまた別途まとめたいと思います。。 データソースのaws_ssm_parameterではAmazonLinux2の最新のAIを取得しています。AMI パブリックパラメータの呼び出し にあるように、AWSのパブリックパラメータを利用するとAmazonLinuxやWindowsServerの最新AMIを取得することができます。 data "aws_ssm_parameter" "amzn2_latest_ami" { name = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" } aws_instanceでEC2インスタンスを作成できますが、この時、予め作成しているキーペア、IAMのインスタンスプロファイル、ネットワークインターフェイスを指定します。 個人的には、EBSボリュームにタグを付与できるvolume_tagsが使える点は驚きました。ENIにも付与できたらいいのに。。 user_dataではEC2起動時に実行するシェルスクリプトをfileで指定しています。paramフォルダの中にuserdata.shを作成します。 mkdir param/ touch param/userdata.sh 作成したuserdata.shに以下のコードを貼り付けます。 userdata.sh #!/bin/bash # Variables AWS_AVAIL_ZONE=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone) && echo $AWS_AVAIL_ZONE AWS_REGION=$(echo "$AWS_AVAIL_ZONE" | sed 's/[a-z]$//') && echo $AWS_REGION INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id) && echo $INSTANCE_ID EC2_NAME=$(aws ec2 describe-instances --region $AWS_REGION --instance-id $INSTANCE_ID \ --query 'Reservations[*].Instances[*].Tags[?Key==`Name`].Value' --output text) && echo $EC2_NAME # Install nginx if not installed nginx -v if [ "$?" -ne 0 ]; then sudo amazon-linux-extras install -y nginx1 sudo systemctl enable nginx sudo systemctl start nginx fi # Install mysql client if not installed mysql --version if [ "$?" -ne 0 ]; then # delete mariadb yum list installed | grep mariadb sudo yum remove mariadb-libs -y # add repo sudo yum install -y https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm # disable mysql5.7 repo and enable mysql8.0 repo sudo yum-config-manager --disable mysql57-community sudo yum-config-manager --enable mysql80-community # install mysql client sudo yum install -y mysql-community-client fi # Create index.html echo "<h1>${EC2_NAME}</h1>" > index.html sudo mv ./index.html /usr/share/nginx/html/ userdata.shでは以下の処理を順番に行っています。 変数の宣言 nginxのインストール MySQLクライアントのインストール index.htmlの作成 変数の宣言では、EC2のメタデータから自身のAZ(リージョン)、インスタンスIDを取得して、AWSCLIのdescribe-instancesコマンドで自身のNameタグの値をEC2_NAMEの変数に格納しています。 取得したEC2_NAMEはindex.htmlのH1タグに書き込んでいるので、ブラウザでHTTPアクセスした際に表示されるHTMLから、接続しているEC2の名前が判別できるようになります。 nginxのインストールは、amazon-linux-extras installで行い、自動起動を有効にしてサービスを開始しています。MySQLクライアントのインストールは、初めから入っているmariadbを削除してからインストールしています。以下の記事などを参考にさせて頂きました。 【AWS EC2】Amazon Linux2にMySQLのclientだけをインストールしてRDSに接続する方法 ec2.tfの最後に登場する output ブロックは、出力結果を表示させるためのものです。outputに続けて出力の識別名を与えて、波括弧の中にdescriptionやvalueを書きます。ここでは、2台のEC2のパブリックIPアドレスを表示させるようにしています。valueにはResourceブロックを参照する場合と同じように<リソースタイプ>.<リソースの識別名>.<属性>という形で出力したい属性を記述します。 ec2.tf output "web01_public_ip" { description = "The public IP address assigned to the instanceue" value = aws_instance.web_01.public_ip } output "web02_public_ip" { description = "The public IP address assigned to the instanceue" value = aws_instance.web_02.public_ip } terraform applyを実行して、EC2が2台作成されていることを確認しましょう。 また、コマンドの最後にoutputで指定した属性が以下のように出力されるはずです。 Outputs: web01_public_ip = "54.250.9.170" web02_public_ip = "18.183.88.247" Outputsの内容はterraform.tfstateにも書き込まれます。 terraform.tfstate "outputs": { "web01_public_ip": { "value": "54.250.9.170", "type": "string" }, "web02_public_ip": { "value": "18.183.88.247", "type": "string" } }, terraform output を実行すると、あとからでもOutputsの内容を確認できます。識別名を指定すれば絞り込むこともできます。 # Outputsの内容をすべて表示 terraform output web01_public_ip = "54.250.9.170" web02_public_ip = "18.183.88.247" # 識別名を指定して表示 terraform output web01_public_ip "54.250.9.170" ブラウザでEC2に接続すると、Nameタグの値が表示されるはずです。 userdataによりnginxのインストール、index.htmlの作成が行われていて、セキュリティグループによりMyIPからのHTTP接続が許可されていることがわかります。 今回は以上です。次回はRoute53 + ACM編ということで、独自ドメインでHTTPS接続するための準備について書いてみたいと思います! 参考リンク Data Sources HTTP Provider Local Values Terraformで自分のパブリックIPを使う方法 AMI パブリックパラメータの呼び出し 【AWS EC2】Amazon Linux2にMySQLのclientだけをインストールしてRDSに接続する方法 Output Values Command: output
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

serverless-frameworkのLayerをローカルで使いたい。

困ったこと serverless-frameworkでLayerを使っていて、 デプロイした後に、AWS Lambdaコンソールで実行すると、動くのに、 ローカルで実行すると動かない問題があった。 解決方法 --dockerオプションを指定することで、解決しました。 裏でDocker-lambdaが起動するみたいです。 Docker-lambda https://github.com/lambci/docker-lambda 手順 最終的な構成はリポジトリ公開しています。 分かりやすいように、node_modulesまでコミットしています。 https://github.com/goda-kazuki/serverless-framework-sample npmの初期化 npm init serverlessのインストール npm install --save-dev serverless プロジェクト作成 npx sls create --template aws-nodejs --name sample --path sample 作成したプロジェクトに移動 cd sample ローカルで実行 npx sls invoke local -f hello レイヤーを追加する mkdir layer mkdir layer/nodejs momentを追加 npm init npm install moment handler.jsにmomentを使うように指定 以下を追加 require('moment') 実行(失敗する) npx sls invoke local -f hello serverless.ymlに以下を追加 functions: hello: handler: handler.hello layers: - { Ref: SampleLambdaLayer } layers: Sample: path: layer description: my sample layer compatibleRuntimes: - nodejs12.x 実行(失敗する) npx sls invoke local -f hello --dockerオプションを追加して実行(成功する) npx sls invoke local -f hello --docker その他 Githubで質問したところ、丁寧に回答いただけました。(感謝) https://github.com/serverless/serverless/issues/9535
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Databricksクラスター設定のベストプラクティス

Best practices: Cluster configuration | Databricks on AWS [2021/6/3時点]の翻訳です。一部加筆しています。 Databricksクイックスタートガイドのコンテンツです。 Databricksは、低いコストでベストなパフォーマンスを得られるようにクラスターを作成、設定する際に数多くのオプションを提供します。しかし、ワークロードに最適な設定を決定する際にこの柔軟性が課題となるケースもあります。ユーザーがクラスターをどのように活用するのかを注意深く検討することは、既存クラスターを設定、新規クラスターを作成する際に設定を選択する際の助けになります。設定を決定する際に検討すべき項目には以下のものがあります。 どのようなタイプのユーザーがクラスターを利用するのか?データサイエンティストはデータエンジニアやデータアナリストとは異なる要件に基づいて、異なるタイプのジョブを実行することになるでしょう。 クラスターでどのようなタイプのワークロードが実行されるか?例えば、バッチの抽出、変換、ロード(ETL)ジョブは分析ワークロードと異なる要件を持つことになるでしょう。 目指すべきサービスレベルアグリーメント(SLA)とは何か? 予算の制約は何か? 本書では、これらの検討に基づいて様々なシナリオにおける推奨設定事項をご説明します。本書ではDatabricksクラスターの特定の機能を議論し、考慮すべき点をご説明します。 設定に対する意思決定に際しては、コストとパフォーマンスのトレードオフが求められるケースがあります。クラスターのコストの主要要素は、クラスターによって消費されるDatabricksユニット(DBU)と、クラスターと実行するのに必要となるインフラリソースのコストとなります。目立たない副次的なコストには、SLAを満たせないことによるビジネスコストや、貧弱なコントロールによって失わられるリソース、従業員の生産性が挙げられます。 クラスターの機能 クラスター設定シナリオの詳細を議論する前に、Databricksクラスターの機能と、それらの機能をどのように活用するかを理解することは重要です。 インスタンスアワー 多くのクラウドプロバイダーにおいては、1時間あたり1台のインスタンスが稼働することが1インスタンスアワーになります。Databricksにおいては、1時間当たりの処理単位である、Databricks Unit(DBU)に基づいて課金されます。1 DBUは、1台のr3.xlarge(メモリー最適化)インスタンス、あるいは1台のc3.2xlarge(計算処理最適化)インスタンスの1時間稼働に相当します。詳細はDatabricksプライシングを参照ください。 例えば、r3.xlargeの1台のドライバーノード、3台のワーカーノードから構成されるDatabricksクラスターを作成し、クラスターを2時間稼働させた場合には、DBUは以下のように計算されます: 合計インスタンスアワー = 合計ノード数(1 + 3) * 時間数 (2) = 8 合計金額 = AWSにおける8台のr3.xlargeインスタンスアワーの費用 + 8 DBU Databricksは秒単位で課金を行います。 オールパーパスクラスターとジョブクラスター クラスターを作成する際に、クラスタータイプをオールパーパスクラスターかジョブクラスターから選択します。オールパーパス(all-purpose)クラスターは複数のユーザーで共有でき、アドホック分析、データ探索、開発においてはベストな選択肢と言えます。処理の実装が完了して本格運用の準備が整ったら、その処理をジョブクラスターで実行するように切り替えます。ジョブクラスターはジョブが終了した際に削除されるので、リソースの利用料とコストを削減することができます。 クラスターモード Databricksでは3つのクラスターモードをサポートしています。Standard、High ConcurrencyとSingle Nodeです。多くの一般的なケースではStandardとSingle Nodeクラスターを使用します。 Standard cluster(標準クラスター)は、大規模データをApache Sparkで処理するのに適しています。 Single Node cluster(シングルノードクラスター)は、小規模データを利用するジョブや、シングルノードの機械学習ライブラリのような非分散のワークロードを行うためのものです。 High Concurrency cluster(ハイコンカレンシークラスター)は、複数のユーザーがリソースを共有したい場合やアドホックなジョブを実行する際に最適です。通常、管理者がハイコンカレンシークラスターを作成します。ハイコンカレンシークラスターではオートスケーリングを活用することをお勧めします。 オンデマンド、スポットインスタンス AWSには二つのインスタンスティアがあります:オンデマンドとスポットです。オンデマンドにおいては、長期のコミットメントなしに秒単位で計算資源を利用しただけの課金が発生します。スポットインスタンスにおいては、余剰のAmazon EC2インスタンスを利用することができ、あなた自身が最大支払額を指定することができます。現在のスポットマーケットプライスが、最大スポット支払額を上回った場合には、スポットインスタンスは停止されます。多くのケースでスポットインスタンスはオンデマンドインスタンスより安価であるため、同じ予算においても、アプリケーションを実行する際にコストを削減することができるため、より高価な計算資源を利用することでスループットを改善することができます。 Databricksにおいては、オンデマンドインスタンスと(カスタムスポットプライスを指定した)スポットインスタンスを組み合わせてクラスターを構成することができ、ユースケースに合わせてクラスターを構築することができます。例えば、下の設定においては、ドライバーノードと4台のワーカーノードはオンデマンドインスタンス、残りの4台のワーカーノードはスポットインスタンス(最大のスポットインスタンスプライスはオンデマンドの100%)として起動すべきと設定しています。 スポットインスタンスの停止が起きたとしてもクラスターの状態保持できるように、Sparkのドライバーノードはオンデマンドインスタンスとして起動することをお勧めします。(ドライバーノードを含む)全てをスポットインスタンスとして起動すると、スポットマーケットの価格変動でドライバーインスタンスが失われると、キャッシュされたデータ、テーブルは削除されてしまいます。 もう一つ注意しなくてはいけない設定項目は、Spot fall back to On-demandです。オンデマンドとスポットから構成されるハイブリッドクラスターを稼働させている際に、スポットインスタンスの獲得に失敗、あるいはスポットインスタンスを失ったとしても、Databrikcsはオンデマンドインスタンスを利用し、期待する性能を実現します。この設定が無いと、クラスターに処理の遅延あるいは処理の失敗が発生し、期待する性能が得られません。ユースケースに対するコスト感度、重要度に応じてオンデマンドとスポットの比率を決定することをお勧めします。 ティップ 適切なインスタンスタイプとリージョンを決定する際には、Amazon Spot Instance Advisorを活用できます。 オートスケーリング オートスケーリングを活用することで、リソース利用量を最適化するためにワークロードに応じて、ワーカーノードの数を自動で増減することができます。オートスケーリングを有効化することで、DatabricksはSparkジョブを実行するのに最適なワーカーの数を自動的に決定します。オートスケーリングを用いることで、ワークロードに適した数のクラスターを気にすることなしに、クラスターの高い利用率を実現できます。これにより二つのメリットを享受することができます: 固定サイズのクラスターと比較して多くのケースでコストを削減できます。 固定サイズのクラスターで能力不足が生じた場合と比較して、オートスケーリングのワークロードは高速に動作します。 spark-submitジョブやいくつかのpythonパッケージなど、いくつかのワークロードはオートスケーリングクラスターとの互換性がありません。 シングルユーザーのオールパーパスクラスターにおいて、最小ワーカー数が少なく設定されている場合、オートスケーリングによって開発や分析がスローダウンするケースがあります。これは実行しているコマンドやクエリーが数分に渡ることがあり、クラスターがアイドル状態になった際にコストを節約するためにスケールダウンが発生するためです。次のコマンドが実行された際には、クラスターマネージャーはスケールアップしようとしますが、クラウドプロバイダーからインスタンスを取得するのに数分を要することがあります。この際、ジョブは不十分なリソースで実行しなくてはならず、結果を主とkするのに時間を要することになります。ワーカーの最小数を引き上げることで改善はできますが、このことはコストも引き上げることになります。これは、コストと性能のバランスを取るべきもう一つの例となります。 Delta Cachingを使用している際には、ノードが削除された際にはノードにキャッシュされたいかなるデータも削除されることに留意してください。ワークロードにおいてキャッシュデータの維持が重要な場合には、固定サイズのクラスターを利用することを検討してください。 ETLワークロードでジョブクラスターを利用している場合、ジョブが当面変更されない場合には適切にクラスターをチューニングすることでサイジングすることができます。しかし、データサイズが増加する際にはオートスケーリングによって柔軟性を手にすることができます。また、最適化されたオートスケーリングによって、長い期間実行されるジョブのクラスターが想定されるより利用されない、他のプロセスの結果を待つ必要がある場合において、コストを削減することができます。繰り返しになりますが、クラスターが適切にスケールアップする際にも微小な遅れが生じる場合が相rます。ジョブに対して厳しいSLAが求められる場合には、固定サイズのクラスターが優れた選択肢かもしれませんし、Databricksのプールを活用してクラスター起動時間を削減した方が良いかもしれません。 Databricksではローカルストレージのオートスケーリングもサポートしています。ローカルストレージのオートスケーリングによって、クラスターのSparkワーカーのディスク空き容量を監視します。ワーカーのディスクの空きが減ってきた際、Databricksは自動的にディスク容量が枯渇する前にマネージドのボリュームを追加します。 プール プールを活用することで、利用可能なインスタンスの群を維持し、クラスターの起動、スケールアップに要する時間を短縮できます。コストを最小化しつつ処理時間を改善するためにプールの活用をお勧めします。 注意 プールのインスタンスがアイドル状態(クラスターにアタッチされていない状態)の間はDBUは消費しませんが、クラウドプロバイダーの課金が発生します。 Databricksランタイムのバージョン オールパーパスクラスターにおいては、最新のDatabricksランタイムを活用することをお勧めします。最新のバージョンを利用することで、最新の最適化、コードとロード済みパッケージの互換性を活用できます。 運用のワークロードを実行するジョブクラスターに関しては、長期サポート(LTS)Databricksランタイムの利用をご検討ください。LTSバージョンを利用することで、互換性に関する問題を回避し、ワークロードをアップグレードする前に包括的なテストが行えます。機械学習やゲノミクスの最新ユースケースを活用する際には、特定のDatabricksランタイムのバージョンの利用を検討ください。 クラスターポリシー Databricksのクラスターポリシーを活用することで、管理者はクラスターの作成、設定に制限をかけることができます。このガイドで議論される推奨事項を活用してください。クラスターポリシーの詳細に関しては、cluster policies best practices guideを参照ください。 自動停止 多くのユーザーはクラスターの利用が終わった際にクラスターを停止しようとは思いません。幸運なことに、特定期間(デフォルトは120分)が経過した後にクラスターは自動で停止します。 管理者はクラスターポリシーを作成する際にデフォルトの設定を変更することができます。設定値を引き下げることで、クラスターのアイドル時間を減らしコストを削減できます。クラスターが停止しされた際には、すべての変数、一時テーブル、キャッシュ、関数、オブジェクトなどすべての状態が失われることに注意してください。クラスターが再起動した際に、これらの状態が復元される必要があるかもしれません。開発者が30分の昼食に席を外した場合、同じ状態に戻すまでに同じ時間を無駄にすることになるかもしれません。 重要! アイドル状態のクラスターはDBUを消費し続け、停止前のアイドル状態のクラウドインスタンスにも課金が発生します。 ガーベージコレクション 本書で議論されている他の話題と比べて目立つものではないかもしれませんが、ガーベージコレクションに注意を払うことで、クラスターのジョブ実行性能を最適化できる可能性があります。大容量のRAMによって、ジョブの性能を改善できるかもしれませんが、ガーベージコレークションの際に遅延を生じる可能性があります。 長期間のガーベージコレクションの影響を最小化するために、それぞれのインスタンスに大容量のRAMを割り当てることを避けてください。ワーカーに対して大容量のメモリーを割り当てることは、長期間のガーベージコレクションを引き起こします。代わりに、小規模のRAMをインスタンスに割り当て、ジョブが大量のメモリを必要とするのであれば、より大量のインスタンスをデプロイするようにしてください。しかし、クラスターのサイジングの検討で議論しているような、多くのシャッフルを必要とするようなワークロードのように、大容量メモリの少数のノードが適しているケースがあります。 クラスターのアクセスコントロール に種類のクラスター権限を設定できます。 ユーザーがクラスターを作成できるかどうかを制御できるAllow Cluster Creation権限 特定のクラスターを利用、編集できるかを設定するクラスターレベルの権限 クラスターの権限設定に関しては、cluster access controlを参照ください。 クラスター作成(Allow Cluster Creation)権限がある、あるいはポリシーの設定に基づいたクラスター作成を許可するクラスターポリシーにアクセスできる場合にはクラスターを作成することができます。クラスターの作成者はオーナーとなり、Can Manage権限を有することになります。これによって、クラスターに対するデータアクセス権限の制約の中で、他のユーザーにクラスターを共有することができます。 一般的なシナリオにおいては、クラスター設定を決定するためにクラスター権限とクラスターポリシーを理解することが重要になります。 クラスタータグ 組織内の異なるグループがクラウドリソースを使う際にクラスタータグを利用することで、容易にコストをモニタリングできます。クラスターを作成する際に、キーバリューの形式でタグを指定することで、DatabricksはインスタンスのEBSなどのクラウドリソースにタグを付与します。詳細はクラスターポリシーにおけるタグの適用を参照ください。 クラスターのサイジングの検討 Databricksにおいては、一つのワーカーノードあたり一つのエグゼキューターが稼働します。このため、Databricksアーキテクチャーの文脈においてはワーカーとエグゼキューターが同じ意味で用いられます。クラスターサイズはワーカーの数で決定されると考えるかもしれませんが、他に考慮すべき要因があります。 トータルのエグゼキューターのコア: 全エグゼキューターのトータルのコア数。この値がクラスターの最大並列実行数を決定します。 トータルのエグゼキューターのメモリー: 全エグゼキューターのトータルのRAM。ディスクに溢れる前にメモリに蓄積できるデータ量を決定します。 エグゼキューターのローカルストレージ: ローカルディスクストレージのタイプと総量。主にシャッフルとキャッシュの際のメモリ溢れ(スピル)が発生した場合に使用されます。 追加で検討すべきことには、上記の要因に影響を与えるワーカーのインスタンスタイプとサイズがあります。クラスターのサイジングをする際には以下を検討してください。 ワークロードはどれだけのデータを消費するのか? ワークロードの計算の複雑性はどの程度か? どこからデータを読み込むのか? 外部ストレージにおいてデータはどのようにパーティショニングされているのか? どれだけの並列性を必要とするのか? これらの疑問に答えることは、ワークロードに最適なクラスター設定を決定するのに役立ちます。狭い変換(入力パーティションが一つの出力パーティションに影響を及ぼす)のみを行うシンプルなETLワークロードにおいては、計算最適化設定に注力します。大量のシャッフルが予想され、メモリーおよびデータ溢れのためのディスクサイズが重要になります。シャッフルが大量に発生するワークロードにおいて、少数の大規模インスタンスはマシン間のデータ転送のネットワークI/Oを削減します。 ワーカーの数とワーカーインスタンスタイプのサイズにはトレードオフの関係があります。40コア、100GBメモリーを持つ2つのワーカーのクラスターは、10コア、25GBメモリーを持つ8台のワーカーと同程度の計算性能、メモリーを有することになります。 同じデータを何度も読み込む場合には、キャッシュの恩恵を受けることができます。Delta Cacheとストレージ最適化設定を検討してください。 クラスターのサイジング例 以下の例では、特定のタイプのワークロードに適したクラスターの推奨設定を説明します。ここでは、避けるべき設定を理由とともに説明します。 データ分析 データ分析においては複数のパーティションからデータを読み込んで処理することが一般的であり、このことはシャッフルを引き起こしまうs。少数のノードのクラスターによって、シャッフルの際のネットワーク、ディスクI/Oを削減することができます。特に一人の分析者をサポートするケースにおいては、以下の図におけるクラスターAが最適な選択肢となります。 クラスターDは、少量のメモリー、ストレージの大量のノードから構成されるため、データの処理の際に大量のシャッフルが発生することになり、最悪の性能をもたらすことになります。 分析ワークロードにおいては、同じデータを繰り返し読み込むケースが多くなりますので、Delta Cacheを有効化して、ストレージ最適化のインスタンスタイプを選択することをお勧めします。 分析ワークロードで推奨する他の機能には以下のものがあります。 利用されない時間が続いた後に、クラスターが停止されるように自動停止を有効化してください。 分析者特有のワークロードに応じてオートスケーリングの活用を検討ください。 事前に定義されたインスタンスタイプ、一貫性のある設定にクラスターを統一できるようにプールの活用を検討ください。 このケースで有用ではない可能性がある機能は以下の通りです。 このケースでは大量データを生成しないのでストレージオートスケーリングは不要です。 クラスターは一人で利用されるので、共有に適したハイコンカレンシークラスターは適していません。 基本的なバッチETL joinや集計などの広い変換を必要としないシンプルなETLジョブにおいては、計算処理最適化クラスターを活用すべきです。このタイプのワークロードにおいては、以下の図のいずれのクラスターも許容できるものとなります。 計算最適化インスタンスタイプがお勧めです。これらは比較的安価であり、このタイプのワークロードは大量のメモリー、ストレージを必要としません。 プールを活用することで、クラスター起動時間を削減し、トータルのジョブパイプライン実行時間を削減できるので、シンプルなETLジョブにおいてもメリットがが生まれます。しかし、このタイプのワークロードは多くの場合、ジョブを実行するのに十分な時間だけ稼働するスケジュールジョブとして実行されるので、この場合プールを活用するメリットはありません。 このケースで有用ではない可能性がある機能は以下の通りです。 データの再読み込みは発生しないためDelta Cachingは不適です。 スケジュールジョブとして実行されるので自動停止は不要です。 計算能力とストレージはユースケースに合わせて事前に設定されるべきなのでオートスケーリングはお勧めしません。 クラスターはシングルジョブとして実行されるので、共有に適したハイコンカレンシークラスターは適していません。 複雑なバッチETL unionや複数テーブルのjoinなどの処理を必要とするより複雑なETLジョブにおいては、シャッフルされるデータ量を最小化することが重要となります。クラスターのワーカー数を削減することでシャッフルを最小化できますので、クラスターDではなく、クラスターAのように少数のクラスターを検討すべきです。 複雑な変換処理は計算資源を多く必要としますので、ワークロードに最適なコアを割り当てるためには、クラスターにノードを追加する必要があるかもしれません。 シンプルなETLジョブと同様、計算最適化のインスタンスタイプをお勧めします。これらは比較的安価であり、このタイプのワークロードは大量のメモリー、ストレージを必要としません。また、シンプルなETLジョブ同様に、クラスターの起動時間を削減し、ジョブパイプライン実行に要するトータルの時間を削減するためにプールの活用を検討ください。 トレーニングのワークロードで推奨する他の機能には以下のものがあります。 利用されない時間が続いた後に、クラスターが停止されるように自動停止を有効化してください。 分析者特有のワークロードに応じてオートスケーリングの活用を検討ください。 事前に定義されたインスタンスタイプ、一貫性のある設定にクラスターを統一できるようにプールの活用を検討ください。 このケースで有用ではない可能性がある機能は以下の通りです。 データの再読み込みは発生しないためDelta Cachingは不適です。 スケジュールジョブとして実行されるので自動停止は不要です。 計算能力とストレージはユースケースに合わせて事前に設定されるべきなのでオートスケーリングはお勧めしません。 クラスターはシングルジョブとして実行されるので、共有に適したハイコンカレンシークラスターは適していません。 機械学習モデルのトレーニング 初回の機械学習モデルのトレーニングは実験的なものであるため、クラスターAのような小規模クラスターがお勧めです。小規模クラスターはシャッフルの影響も軽減します。 ステージが進むなどして、安定性が課題になるのであれば、より規模の大きいクラスターBやクラスターCがお勧めです。 ノード間のデータシャッフルのオーバーヘッドのため大規模なクラスターDはお勧めしません。 同じデータを繰り返し読み込むため、Delta Cachingを有効化したストレージ最適化インスタンスの活用、トレーニングデータのキャッシュがお勧めです。ストレージ最適化インスタンスの計算能力、ストレージサイズが不十分である場合には、GPU最適化ノードの利用を検討ください。この場合、Delta Cachingを利用できないというデメリットがあります。 このケースで有用ではない可能性がある機能は以下の通りです。 クラスターのスケールダウンでデータが失われるのでオートスケーリングはお勧めしません。加えて、特定の機械学習ジョブはすべての利用可能なノードを必要としますので、この場合オートスケーリングを使用すべきではありません。 このケースでは大量データを生成しないのでストレージオートスケーリングは不要です。 クラスターは一人で利用されるので、共有に適したハイコンカレンシークラスターは適していません。 一般的なシナリオ 以下のセクションでは、一般的なクラスターの利用パターンに対する推奨クラスター設定を説明します。 マルチユーザーによるデータ分析、アドホックデータ処理 機械学習のような特定のユースケース スケジュールバッチジョブのサポート マルチユーザークラスター シナリオ データ分析、アドホックのクエリーを行う複数のユーザーに対してデータアクセス手段を提供する必要があります。利用料は時間に応じて変動し、多くのジョブはそれほどリソースを消費しません。ユーザーは多くの場合データに対する読み取りのみが必要で、シンプルなユーザーインタフェースを通じて分析を行い、ダッシュボードを構築したいと考えています。 クラスター提供の推奨アプローチは、オートスケーリングを伴うクラスターを提供するというハイブリッドのアプローチです。ハイブリッドアプローチでは、オンデマンドインスタンスの数とスポットインスタンスの数を定義し、インスタンスの際少数、再代数を指定してオートスケーリングを有効化します。 このクラスターは常時稼働であり、グループのユーザーが利用することができ、負荷に応じてスケールアップ・ダウンします。 ユーザーにはクラスターを開始・停止する権限はありませんが、初期状態から設定されているオンデマンドインスタンスはユーザーからのクエリに即座に反応します。ユーザーのクエリがより多くのキャパシティを必要とした際には、ワークロードに対応できるようにオートスケーリングがより多くのノード(多くはスポットインスタンス)を配置します。 インタラクティブワークフローにおける高負荷クエリの取り扱い - 終了しないクエリを自動的に管理 タスクのプリエンプション - 長期実行クエリと短期実行クエリの共存 ローカルストレージのオートスケーリング - マルチテナントにおけるストレージ枯渇(シャッフル)の回避 このアプローチにより、以下の理由から全体的なコストを削減できます: 共有クラスターモデルの活用 オンデマンド・スポットインスタンスの活用 固定サイズのクラスターではなくオートスケーリングを活用することで不要な課金を回避 特定のワークロード シナリオ データサイエンティストが複雑なデータ探索や機械学習アルゴリズムを実行するといった、組織内の特定のユースケース、チームにクラスターを提供する必要があります。典型的なパターンは、ユーザーは短時間でデータ分析を行うというものです。 このタイプのワークロードにおけるベストなアプローチは、デフォルト値、固定値、設定のレンジを事前定義した設定のクラスターポリシーを作成するというものです。これにはインスタンスの数、インスタンスタイプ、スポットとオンデマンドインスタンスの比率、ロール、インストールすべきライブラリなどが含まれます。クラスターポリシーを活用することでユーザーは高度な要件に対しても、ユースケースに応じた設定を行い迅速にクラスターを起動でき、ポリシーによってコスト、コンプライアンスを制御することができます。 このアプローチは、ユーザーに対してクラスターを起動することのできるより強い権限を与えるものですが、依然として事前に定義した設定の制限をかけることでコストをコントロールすることが可能です。また、このアプローチにおいては、異なるグループのユーザーに対して、異なるデータへのアクセスが許された異なるクラスターを割り当てることも可能です。 このアプローチにおける欠点は、クラスターにおけるあらゆる変更、設定、ライブラリなど全てにおいて管理者の関与が必要となることです。 バッチワークロード シナリオ データ前処理を行う本番ETL処理など、スケジューリングされたバッチジョブに対してクラスターを提供する必要があります。ここでのベストプラクティスはそれぞれのジョブ実行で新規にクラスターを起動するというものです。新規クラスターによるジョブ実行によって、共有クラスターで他の作業と競合することによるSLA違反や処理失敗を避けることができます。ジョブの重要度レベルに応じて、SLAを満足するためにオンデマンドインスタンを使用できますし、コスト低減のためにスポットインスタンスとオンデマンドインスタンスを組み合わせることも可能です。 Databricks 無料トライアル Databricks 無料トライアル
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS RDS なんとなく初見で使ってみた(やった事のまとめ)

動機 前回、下記の記事でざっくりとwebサーバを作ったので、 今度はRDSを利用して、DBサーバを立てることにした。 DB操作に関する知識はほぼなかったので、簡単にDBの作り方を備忘録的にまとめておく 雑記/やったこと RDSについて ●AWSのリレーショナルデータベースサービス いくつかのDBエンジンの中から好きなものを選択可能。(馴染みのあるmysqlを選択) ●セキュリティグループを編集 defaultだと接続できない為、EC2のセキュリティグループに設定。 EC2のwebサーバとローカルPCからmysqlへの接続を許可するルールを追加(portはデフォルト3306) ●接続確認(変数内は可変値) mysql -h ${DB-Endpoint} -P 3306 -u ${username} -p ●mysql workbenchをインストール mysql workbench DBをGUIで操作できるツール。当初phpmyadminを入れるつもりだったが、 mysql v8だと動作するかわからなかったので、AWSのKCに記載があるこちらを選択。 → ドキュメントがあまり見当たらなかったのと、DB構築の知識が足りない為、いったんCLIに慣れてから使うことにする。 mysql コマンド(主要なもの) show databases; → データベースの一覧表示 create database ${DatabaseName} → データベース作成 use ${DatabaseName}; → 使用するデータベースの選択 show tables; → テーブルの一覧表示 create table ${tablename} (${column} ${datatype},${column} ${datatype}…) → テーブルの作成。データ列(カラム)とデータタイプ(文字列、数字など) insert into ${tablename}(${column}) values (${data}) → データの挿入 select ${column} from ${tablename} where ${column} (=/>/<…) 条件値; → データの検索 drop table ${tablename}; → テーブルの削除 drop database ${DatabaseName}; → データベースの削除
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

amplify の権限設定とエラー回避

はじめに この記事は、完全に自分のための備忘録ですが、もし同じエラーに遭遇した人のために記録しておくことにします。 何が起きたのか React アプリを作成していて、ホスティングをどうしようかなやんでいたところ、AWS Amplify が便利そうだったので早速以下の記事を参考にしてホスティングのテストをしてみました。 AWS Amplify Console で素の React アプリをホスティングしてみよう めちゃくちゃ簡単そう! IAM のアクセス権 手順通りにやっていくと、途中で IAM ユーザを作ることになります。専用に IAM ユーザを作るのはいいのですけど、アクセス権限をどうするかが悩みどころ。AdministratorAccess はさすがに躊躇するので、Amplify に特化したアクセス権はないかと探してみると、AdministratorAccess-Amplify ってのがありました。 AdministratorAccess-Amplify { "Version": "2012-10-17", "Statement": [ { "Sid": "CLICloudformationPolicy", "Effect": "Allow", "Action": [ "cloudformation:CreateChangeSet", "cloudformation:CreateStack", "cloudformation:DeleteStack", "cloudformation:DescribeChangeSet", "cloudformation:DescribeStackEvents", "cloudformation:DescribeStackResource", "cloudformation:DescribeStackResources", "cloudformation:DescribeStacks", "cloudformation:ExecuteChangeSet", "cloudformation:GetTemplate", "cloudformation:UpdateStack" ], "Resource": [ "arn:aws:cloudformation:*:*:stack/amplify-*" ] }, { "Sid": "CLIManageviaCFNPolicy", "Effect": "Allow", "Action": [ "iam:CreateRole", "iam:ListRoleTags", "iam:TagRole", "iam:AttachRolePolicy", "iam:CreatePolicy", "iam:DeletePolicy", "iam:DeleteRole", "iam:DeleteRolePolicy", "iam:DetachRolePolicy", "iam:PutRolePolicy", "iam:UpdateRole", "iam:GetRole", "iam:GetPolicy", "iam:GetRolePolicy", "iam:PassRole", "iam:ListPolicyVersions", "appsync:CreateApiKey", "appsync:CreateDataSource", "appsync:CreateFunction", "appsync:CreateResolver", "appsync:CreateType", "appsync:DeleteApiKey", "appsync:DeleteDataSource", "appsync:DeleteFunction", "appsync:DeleteResolver", "appsync:DeleteType", "appsync:GetDataSource", "appsync:GetFunction", "appsync:GetIntrospectionSchema", "appsync:GetResolver", "appsync:GetSchemaCreationStatus", "appsync:GetType", "appsync:GraphQL", "appsync:ListApiKeys", "appsync:ListDataSources", "appsync:ListFunctions", "appsync:ListGraphqlApis", "appsync:ListResolvers", "appsync:ListResolversByFunction", "appsync:ListTypes", "appsync:StartSchemaCreation", "appsync:UpdateApiKey", "appsync:UpdateDataSource", "appsync:UpdateFunction", "appsync:UpdateResolver", "appsync:UpdateType", "appsync:TagResource", "appsync:CreateGraphqlApi", "appsync:DeleteGraphqlApi", "appsync:GetGraphqlApi", "appsync:ListTagsForResource", "appsync:UpdateGraphqlApi", "apigateway:DELETE", "apigateway:GET", "apigateway:PATCH", "apigateway:POST", "apigateway:PUT", "cognito-idp:CreateUserPool", "cognito-identity:CreateIdentityPool", "cognito-identity:DeleteIdentityPool", "cognito-identity:DescribeIdentity", "cognito-identity:DescribeIdentityPool", "cognito-identity:SetIdentityPoolRoles", "cognito-identity:GetIdentityPoolRoles", "cognito-identity:UpdateIdentityPool", "cognito-idp:CreateUserPoolClient", "cognito-idp:DeleteGroup", "cognito-idp:DeleteUserPool", "cognito-idp:DeleteUserPoolClient", "cognito-idp:DescribeUserPool", "cognito-idp:DescribeUserPoolClient", "cognito-idp:ListTagsForResource", "cognito-idp:ListUserPoolClients", "cognito-idp:UpdateUserPoolClient", "cognito-idp:CreateGroup", "cognito-idp:DeleteGroup", "cognito-identity:TagResource", "cognito-idp:TagResource", "cognito-idp:UpdateUserPool", "lambda:AddPermission", "lambda:CreateFunction", "lambda:DeleteFunction", "lambda:GetFunction", "lambda:GetFunctionConfiguration", "lambda:InvokeAsync", "lambda:InvokeFunction", "lambda:RemovePermission", "lambda:UpdateFunctionCode", "lambda:UpdateFunctionConfiguration", "lambda:ListTags", "lambda:TagResource", "lambda:UntagResource", "lambda:DeleteFunction", "lambda:AddLayerVersionPermission", "lambda:CreateEventSourceMapping", "lambda:DeleteEventSourceMapping", "lambda:DeleteLayerVersion", "lambda:GetEventSourceMapping", "lambda:GetLayerVersion", "lambda:ListEventSourceMappings", "lambda:ListLayerVersions", "lambda:PublishLayerVersion", "lambda:RemoveLayerVersionPermission", "dynamodb:CreateTable", "dynamodb:DeleteItem", "dynamodb:DeleteTable", "dynamodb:DescribeContinuousBackups", "dynamodb:DescribeTable", "dynamodb:DescribeTimeToLive", "dynamodb:ListStreams", "dynamodb:PutItem", "dynamodb:TagResource", "dynamodb:ListTagsOfResource", "dynamodb:UpdateContinuousBackups", "dynamodb:UpdateItem", "dynamodb:UpdateTable", "dynamodb:UpdateTimeToLive", "s3:CreateBucket", "s3:ListBucket", "s3:PutBucketAcl", "s3:PutBucketCORS", "s3:PutBucketNotification", "s3:PutBucketPolicy", "s3:PutBucketWebsite", "s3:PutObjectAcl", "cloudfront:CreateCloudFrontOriginAccessIdentity", "cloudfront:CreateDistribution", "cloudfront:DeleteCloudFrontOriginAccessIdentity", "cloudfront:DeleteDistribution", "cloudfront:GetCloudFrontOriginAccessIdentity", "cloudfront:GetCloudFrontOriginAccessIdentityConfig", "cloudfront:GetDistribution", "cloudfront:GetDistributionConfig", "cloudfront:TagResource", "cloudfront:UntagResource", "cloudfront:UpdateCloudFrontOriginAccessIdentity", "cloudfront:UpdateDistribution", "events:DeleteRule", "events:DescribeRule", "events:ListRuleNamesByTarget", "events:PutRule", "events:PutTargets", "events:RemoveTargets", "mobiletargeting:GetApp", "kinesis:AddTagsToStream", "kinesis:CreateStream", "kinesis:DeleteStream", "kinesis:DescribeStream", "kinesis:PutRecords" ], "Resource": "*", "Condition": { "ForAnyValue:StringEquals": { "aws:CalledVia": [ "cloudformation.amazonaws.com" ] } } }, { "Sid": "CLISDKCalls", "Effect": "Allow", "Action": [ "appsync:GetIntrospectionSchema", "appsync:GraphQL", "appsync:UpdateApiKey", "appsync:ListApiKeys", "s3:PutObject", "s3:GetObject", "s3:ListBucket", "s3:ListBucketVersions", "s3:DeleteBucket", "s3:DeleteBucketPolicy", "s3:DeleteBucketWebsite", "s3:DeleteObject", "s3:GetBucketLocation", "s3:ListAllMyBuckets", "sts:AssumeRole", "iam:PutRolePolicy", "iam:CreatePolicy", "iam:AttachRolePolicy", "mobiletargeting:*", "amplify:CreateApp", "amplify:CreateBackendEnvironment", "amplify:GetApp", "amplify:GetBackendEnvironment", "amplify:ListApps", "amplify:ListBackendEnvironments", "amplify:CreateBranch", "amplify:GetBranch", "amplify:UpdateApp", "amplify:ListBranches", "amplify:ListDomainAssociations", "amplify:DeleteBranch", "amplify:DeleteApp", "amplify:DeleteBackendEnvironment", "amplifybackend:*", "cognito-idp:AdminAddUserToGroup", "cognito-idp:AdminCreateUser", "cognito-idp:CreateGroup", "cognito-idp:DeleteGroup", "cognito-idp:DeleteUser", "cognito-idp:ListUsers", "cognito-idp:AdminGetUser", "cognito-idp:ListUsersInGroup", "cognito-idp:AdminDisableUser", "cognito-idp:AdminRemoveUserFromGroup", "cognito-idp:AdminResetUserPassword", "cognito-idp:AdminListGroupsForUser", "cognito-idp:ListGroups", "cognito-idp:AdminDeleteUser", "cognito-idp:AdminListUserAuthEvents", "cognito-idp:AdminDeleteUser", "cognito-idp:AdminConfirmSignUp", "cognito-idp:AdminEnableUser", "cognito-idp:AdminUpdateUserAttributes", "cognito-idp:DescribeIdentityProvider" ], "Resource": "*" } ] } なんかめっちゃ色々設定されているけど、とりあえずこれでいってみましょう。 amplify init で色々エラー しかし、この状態でamplify initを実行するとなにやらエラーがでてしまう。 メッセージの内容を見ると、S3 とか、IAM あたりでのエラーっぽい。 しょうがないので、アクセス権限に以下の2つを追加しましょう。 IAMFullAccess AmazonS3FullAccess 多分、FullAccessなんていらないと思うんですけど、細かく調べるのも面倒なのでね。 さて、これでもう一度 amplify init を実行してみます。 うまくいきましたね。パチパチ。 amplify publish でエラー では先程の手順に従ってamplify add hostingをやってみます。 いいですね。うまくいったようです。 では、さっそくパブリッシュしてみましょう。 amplify publish あー、最後の最後にエラーになりますね。 An error occurred during the publish operation: User: (省略) 色々調べてみると、パブリッシュするためには、Amplify の権限が足りないみたいです。 なので、インラインポリシーでAmplify のすべての権限を付与してみましょう。 さっそくパブリッシュ! しかし、これだと状況は変わりませんでした。 色々悩んだところ、どうも一度amplify initしちゃっているとアクセス権を変えてもだめっぽい。 なので、一度amplify deleteでアプリを消して、再度amplify initからやり直して、無事にパブリッシュができるようになりました(違っているかもしれないので、違っていたら教えて下さい)。 最終的なアクセス権限はこんな感じになりました。 とりあえず、同じ事象にハマっている人のためになれば。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

NLB-EC2構成を取ったときにTCP443にてCONNECT_CR_SRVR_HELLO:wrong version number

概要 AWSでクライアント証明書を使うために、NLB-EC2構成を取ったときに、Curlで叩くとよくわからないエラーCONNECT_CR_SRVR_HELLO:wrong version numberが発生 結論としてはTargetGroupのProxy2をONにしていたためチェックを外して解決した。 現状 NLBはTCP80,443をそれぞれTargetGroupでそのままEC2に流している。 % curl -v --key private.pem --cert cert.crt -k "https://example.jp" * Trying xxx... * TCP_NODELAY set * Connected to example.jp (xxx) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/cert.pem CApath: none * TLSv1.2 (OUT), TLS handshake, Client hello (1): * error:1400410B:SSL routines:CONNECT_CR_SRVR_HELLO:wrong version number * Closing connection 0 curl: (35) error:1400410B:SSL routines:CONNECT_CR_SRVR_HELLO:wrong version number proxy関係で同様のエラーが発生する模様 TargetGroup修正 なぜかProxy protocol v2が有効だったのでチェック外す。 % curl -v --key private.pem --cert cert.crt -k "https://example.jp" * Trying xxx... * TCP_NODELAY set * Connected to example.jp (xxx) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/cert.pem CApath: none * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): 略 < HTTP/1.1 404 Not Found とりあえず正常に通過しました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

運用・監視オペレータがAWS認定ソリューションアーキテクトアソシエイトを4ヶ月で取得した学習方法を公開します!

この記事では運用・監視オペレータがAWS認定ソリューションアーキテクトアソシエイトを4ヶ月で取得した流れや学習方法を紹介します。 AWSの業務未経験でもソリューションアーキテクトアソシエイトを取得することができました! 学習の感想や模擬試験の点数を具体化しながら説明しておりますので最後までご一読いただけますと幸いです。 目次 受験の経緯 私のスペック 学習に使った教材 学習の期間と流れ udemyの講義を2周、本を1周し基礎知識をインプット udemyの模擬試験を受験しながらudemyの講義の3周目を視聴 AWS公式の模擬試験を受験するも得点が低すぎる為、受験を断念 AWS WEB問題集の問題を解く 試験3日前にWEB問題集の模擬試験を受験 本番試験 試験を受けた感想 教材のリンク 受験の経緯 今の業務からステップアップしたいと考えた 運用保守は潰しがきかない技術が身についてしまいがちなので、将来が心配になった 私のスペック 2019年4月 新卒入社 2019年7月 運用・監視オペレータの案件に参画 取得資格は入社前に取った.com Master BASICのみ 学習に使った教材 udemy「これだけでOK! AWS 認定ソリューションアーキテクト – アソシエイト試験突破講座(SAA-C02試験対応版)」 udemy「【SAA-C02版】AWS 認定ソリューションアーキテクト アソシエイト模擬試験問題集(6回分390問)」 AWS WEB問題集で学習しよう この1冊で合格!AWS認定ソリューションアーキテクトアソシエイト&問題集 Black Belt 学習の期間と流れ 1. 学習期間 2020年11月~2021年3月中旬 2. 学習の流れ 開始日 終了日 学習内容 2020/11/1 2020/12/31 udemyの講義を2周、本を1周し基礎知識をインプット         2021/1/1 2021/2/15 udemyの模擬試験を受験しながらudemyの講義の3周目を視聴 2021/2/15 2021/2/16 AWS公式の模擬試験を受験するも得点が低すぎる為、受験を断念 2021/2/17 2021/3/9 AWS WEB問題集の問題を解く 2021/3/8 2021/3/9 試験3日前にWEB問題集の模擬試験を受験し正答率8.5割を叩き出す 2021/3/9 2021/3/12 本番試験で合格 udemyの講義を2周、本を1周し基礎知識をインプット udemyで2周視聴し、基礎知識を身に着けました。 私は監視オペレータしか業務の経験が無かった為、ITの基礎が全く身についておりませんでした。 なので分からない単語は都度調べながら進めました。 お恥ずかしながら基礎から徹底的に勉強し直したかったので、IPアドレスについてから調べました(笑) 1周目はAWSの枠組みを知る為に半分流しながら教材を聞いておりました。なので各AWSサービスの細かい部分まで調べずに基礎的な部分からインプットしました。 また、ハンズオンも並行しながらアウトプットを進めました。 2周目からは各サービスの細かい機能や分からない単語を調べながら学習を進めました。 なので2周目は時間をかけてインプットさせました。 また、本についてはudemyで取り扱われなかった細かいサービスを補う形で使いました。 本も1周しましたが、本はあくまで補助的な役割で利用しました。 Black Beltはほどんど使いませんでした。AWS-SAPといったプロフェッショナル資格を受験する場合は網羅的な理解が必要な為、使用する機会はございますが、SAAレベルでは不要かなと個人的に感じました。 udemyの模擬試験を受験しながらudemyの講義の3周目を視聴 そしてudemyを2周こなしたところでudemyの8回分模擬試験の講座を受けました。 模擬試験はとても難しく得点はとても酷かったです。 また、模擬試験を一定間隔で進めながら上記のudemyの講座も復習を兼ねて視聴しました。 模擬試験は、実力チェックを図る為には良いかなと思いました。 番号 正答率 1 52% 2 58% 3 53% 4 49% 5 56% 6 49% 7 58% AWS公式の模擬試験を受験するも得点が低すぎる為、受験を断念 公式模擬試験の正答率は45%でした。 本当は模擬試験を8割くらい取って2月末に受験を考えておりましたので正直心が折れました。 今のまま受験しても落ちることは目に見えていたので、もう少し準備が必要だと感じました。 AWS WEB問題集の問題を解く 模擬試験がボロボロでいろいろ考えた結果、実践慣れをしていないことが原因だと感じた為、WEB問題集がお勧めという記事を見つけたので試しに購入。 #80~#144を2周やりましたが、試験に近い応用力が身についたと感じました。また、WEB問題集は本番と似たような問題が出題された為、おすすめ。 ただし、基礎がある程度出来てないと何が分からないのか理解できないですし、 WEB問題集の解説は基礎的な用語を解説していないので解説を見てもさっぱり分からないと思います。 udemyで一旦基礎を身に着けてからWEB問題集に取り掛かることをお勧めします。 何周目 平均正答率 1 60% 2 71% 試験3日前にWEB問題集の模擬試験を受験 WEB問題集を2周終わったタイミングでWEB問題集の模擬試験を受けました。 結果は850点を出し、合格圏内でした。 中には暗記している回答もあったので実質の正答率は7.5~8割くらいだが本番の得点とほどんど誤差が無いため、試験に一番近いかなと感じました。 なので本番前にWEB問題集の模擬試験を受けるのはとてもお勧めです! 試験前でとても自信がつきました! 本番試験 そしていよいよ本番試験。 問題文がとにかく長かったです。 国語力のない私はまず問題の理解に時間がかかったので、一通り問題を解いた頃には残り時間が5分しかなかったので見直す時間がありませんでした。 国語力が強い人は少し有利かもしれません。 また、ベンダー系の資格特有ですが問題文をちゃんと翻訳してくれないので分かりにくい部分は英語に直して読むといった工夫も必要です。 個人的な体感の正答率は6.5~7割くらい。 あと一歩及ばずで落ちたと思い。恐る恐る合否のボタンを押しました。。 そしたら「合格」の文字が出てきてとても嬉しかったです! まだ、周りの方で試験を受けている方が居たので大声は出せませんが、本当は喜びのあまり叫びたかったです(笑) 得点は777点でした。 思った以上に得点が高くてびっくりしました! 長い期間準備した甲斐がありました。 試験を受けた感想 「○○はどのサービスですか」といった知識問題はほどんど問われませんでした。 どちらかと言うと「この設問何を求められているのか」を読み解く力が必要になります。 例えば可用性かコスパのどちらかを求められるかで回答が変わってきます。 最後まで問題に目を通すよう注意が必要です。 練習問題を暗記するのではなく問題の選択肢がどこが間違っているのかをキチンと理解することが重要です。 今後はAWSのSOA・DVA・SAPのいずれかの資格取得を目指そうと思います!合格したらまた投稿します♪ 教材のリンク これだけでOK! AWS 認定ソリューションアーキテクト – アソシエイト試験突破講座(SAA-C02試験対応版):https://www.udemy.com/course/aws-associate/ 【SAA-C02版】AWS 認定ソリューションアーキテクト アソシエイト模擬試験問題集(6回分390問): https://www.udemy.com/course/aws-knan/ この1冊で合格! AWS認定ソリューションアーキテクト - アソシエイト テキスト&問題集 単行本 – 2019/7/20: https://www.amazon.co.jp/%E3%81%93%E3%81%AE1%E5%86%8A%E3%81%A7%E5%90%88%E6%A0%BC-AWS%E8%AA%8D%E5%AE%9A%E3%82%BD%E3%83%AA%E3%83%A5%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%88-%E3%82%A2%E3%82%BD%E3%82%B7%E3%82%A8%E3%82%A4%E3%83%88-%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88-%E5%95%8F%E9%A1%8C%E9%9B%86/dp/4046042036 AWS WEB問題集で学習しよう: https://aws.koiwaclub.com/ Black Belt: https://aws.amazon.com/jp/aws-jp-introduction/aws-jp-webinar-service-cut/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS】S3+CloudFront+Route53+ACMでSSL化(https)した静的Webサイトを公開する

概要 本記事では、S3+CloudFront+Route53を利用して、静的サイトを公開する実装手順を紹介します。ACMを使ってSSL証明書を発行し、httpsで公開します。 LP(ランディングページ)、ポートフォリオサイト、シンプルなサイトなどをインターネット上に公開する際に役立ちます。 構成図 本記事の目的 今回のゴールは、以下のhtml,ccs,画像だけのシンプルな静的Webサイトを、独自ドメインを使用してインターネット上に公開することです。 事前準備 AWSのアカウント 公開するファイル(html,css,imageなど) 実装手順 S3で静的Webサイトホスティングをする CloudFront経由でS3のファイルにアクセスする CloudFrontのOAIを使用して、S3への直接アクセスを制限する 独自ドメインを取得し、Route53へ設定する(freenomで無料ドメインを取得します) ACMでSSL証明書を発行する CloudFrontへSSL証明書を設定する Route53にCloudFrontのドメインを紐付ける 独自ドメインにアクセスしてブラウザで確認する S3で静的Webサイトホスティングをする S3は、ストレージサービスだけでなく、静的Webサイトをホスティングできます。 静的Webサイトとは、シンプルなhtml,css,画像,JavaScriptなどで作られたサイトのことです。 バケットにURLを指定すると、誰でもサイトにアクセスできます。 「サービス」から「S3」を起動しましょう。 バケットを作成する バケットを作成するクリックしましょう。 「バケット名」に任意のバケット名を入力しましょう。 今回はtest.co.jpというバケット名を作成します。 ブロックパブリックアクセスをOFFにする パブリックアクセスをすべてブロックのチェックを外しましょう。 「現在の設定により、このバケットとバケット内のオブジェクトが公開される可能性があることを承認します。」にチェックを入れましょう。 ※最終的にS3バケットへの直接アクセスではなく、CloudFront経由の独自ドメインでアクセスするように設定するので、後ほどS3のブロックパブリックアクセスはONします。現段階では、S3で静的WebサイトをホスティングするのでOFFにします。 その他は、デフォルト設定のままでOKなので、バケットを作成をクリックしましょう。 以下のようにバケットが作成されたことを確認しましょう。 ファイルをアップロードする 作成したバケットをクリックしましょう。 以下のような画面に遷移します。 アップロードをクリックしましょう。 ファイルを追加をクリックしましょう。 事前に作成したhtml,css,JavaScriptファイルなどを追加しましょう。 今回、画像は「images」フォルダに格納したので、フォルダの追加をクリックして追加しました。 html,css,画像などが追加されていることを確認しましょう。 確認ができたら、アップロードをクリックしましょう。 アップロードすると、追加したファイルがバケットに入ります。 アップロードが成功すると以下のような画面表示になります。 成功したら、右上の閉じるをクリックしましょう。 以下のように、アップロードしたファイルがバケット内に入っていることを確認しましょう。 静的ウェブサイトホスティングを「有効」にする S3を使用して、静的ウェブサイトのホスティングを有効にします。 プロパティをクリックしましょう。 一番下にスクロールし、静的ウェブサイトホスティングの「編集」をクリックしましょう。 「有効にする」にチェックを入れましょう。 インデックスドキュメントにindex.htmlと入力しましょう。 ※4XXエラーが発生すると表示されるエラードキュメントを指定する場合は、エラードキュメントにerror.htmlなどを入力しましょう。 変更の保存をクリックしましょう。 バケットポリシーを追加する バケットポリシーとは、S3のバケットにアクセスの制限を設定することです。 誰が、何に対して、どうできるのか、できないのかを設定できます。 今回は、バケットへのパブリック読み取りアクセスを許可するバケットポリシーを追加します。これを許可すると、インターネット上から誰でもS3バケットにアクセスできるようになります。 アクセス許可をクリックしましょう。 バケットポリシーから編集をクリックしましょう。 パブリック読み取りアクセスを許可するには、以下のバケットポリシーをコピーし、エディターに貼り付けます。 { "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadGetObject", "Effect": "Allow", "Principal": "*", "Action": [ "s3:GetObject" ], "Resource": [ "arn:aws:s3:::Bucket-Name/*" ] } ] } ResourceのBucket-Nameは、自身で作成したバケット名を指定します。 今回は、test.co.jpがバケット名です。 エディタにバケットポリシーを設定し、バケット名も確認したら変更の保存をクリックしましょう。 バケットウェブサイトエンドポイントからURLを確認する ここまで完了するとエンドポイント(インターネット上に公開されたURL)が発行されます。 URLをクリックして、静的サイトが表示されているか確認します。 「プロパティ」に移動し、「静的ウェブサイトホスティング」にURLが発行されているので、クリックしましょう。 このURLの内容は、http://【バケット名】.s3-website-【リージョン名】.amazonaws.com/となっています。 静的サイトが表示されているか確認しましょう。 以下のように、今回公開するサイトが表示されたら成功です。 以上で、S3で静的Webサイトのホスティング作業が完了しました。 CloudFront経由でS3のファイルにアクセスする 次に、S3バケットへ直接アクセスではなく、CloudFront経由でアクセスできるように設定します。 CloudFrontとは、Webコンテンツの配信が高速化し、安全性の高いコンテンツデリバリーネットワークです。(略してCDNと呼ばれます) 通常、ユーザーはWebサーバーにアクセスして見たいページを取得しますが、CloudFrontdでは、Webサーバーの中身をキャッシュするエッジサーバーを利用します。 エッジサーバーを利用すると、Webサーバーの負担が軽減されるので、レスポンスが高速化されます。 S3でホスティングしたWebサイトと紐付けてよく使われます。 Amazon CloudFrontとは CloudFrontを利用するメリットとS3との違いについて 「サービス」から「CloudFront」を起動しましょう。 Distributionを作成する Create Distributionをクリックしましょう。 Get Startedをクリックしましょう。 オリジンを設定する 以下を参考に設定しましょう。 Origin Domain Name→作成したS3バケットを選択 Restrict Bucket Access→Yes S3バケットへのアクセスを拒否し、CloudFront経由でのみアクセス可能にする Origin Access Identity→Create a New Identity オリジンアクセスアイデンティティ(OAI)を作成する Grant Read Permissions on Bucket→Yes, Update Bucket Policy 作成したOAIをS3のバケットポリシーに自動で記載してくれる http通信だった場合に、httpsにリダイレクトされるように設定しましょう。 Viewer Protocol Policy→Redirect HTTP to HTTPS デフォルトのルートオブジェクトを設定しましょう。 S3の静的Webサイトホスティングのデフォルト設定は、index.htmlを返しますが、CloudFrontのURLへアクセスする際のデフォルト設定では、index.htmlは省略できないので、オブジェクトの名前の指定が必要です。 よって、URLのアクセス時にCloudFrontがindex.htmlをオブジェクトとして返す設定を行います。 Default Root Object→index.htmlと入力しましょう。 他は全てデフォルト設定のままでOKです。 Create Distributionをクリックしましょう。 Distributionが作成できたら、左のタブ1番上のDistributionsをクリックしましょう。 StatusがIn ProgressからDeployedになるのを待ちます。 Deployedになるまでには数分かかります。 In Progressの状態 Deployedの状態 CloudFront経由のURLを確認する StatusがDeployedになったら、Donation NameタブにあるURL(d3XXXXXX36XXXX.cloudfront.net)をコピーし、ブラウザで確認しましょう。 以下のように、今回公開するサイトが表示されたら成功です。 以上でCloudFront経由でS3のファイルにアクセスする設定は完了となります。 CloudFrontのOAIを使用して、S3への直接アクセスを制限する CloudFrontのオリジン設定時に、S3からOAIを使用したCloudFront経由のアクセスを可能にしたので、S3バケットから直接アクセスするのを無効にする設定をします。 ブロックパブリックアクセスをONにする S3のバケットのブロックパブリックアクセスをONに設定することで安全な運用が行えます。 「S3」を起動し、アクセス許可のタブに移動しましょう。 ブロックパブリックアクセス(バケット設定)の編集をクリックしましょう。 パブリックアクセスをすべてブロックにチェックを入れたら、変更の保存をクリックしましょう。 モーダルが開くので、確認と入力ししましょう。 S3バケットポリシーを編集する 現状のバケットポリシーを確認すると、以下のように先程のCloudFrontのオリジン設定時に、OAIを使用したS3へのバケットへのアクセスを許可する設定がすでに追加されています。 確認したら、編集をクリックしましょう。 バケットポリシーの編集画面に遷移されます。 現状のポリシーを確認すると、"Sid": "PublicReadGetObject"という静的WebサイトホスティングでS3バケットのリソースをパブリックへ公開するためのポリシーが設定されています。 このポリシーを削除することで、S3のバケットからの直接アクセスを無効にし、OAIを使用したCloudFront経由のアクセスが可能となります。 以下の範囲を削除しましょう。 もし、"Sid": "PublicReadGetObject"が残った状態でブロックパブリックアクセスをONにすると、CloudFront経由でアクセスした場合、403エラー(閲覧権限なし)になります。 以下のように編集できたら、変更の保存をクリックしましょう。 編集が完了したら下記、3点を確認しましょう。 アクセス許可の概要︰非公開のバケットとオブジェクト ブロックパブリックアクセス(バケット設定)︰パブリックアクセスをすべてブロックが「ON」 バケットポリシー︰OAIを使用したCloudFront経由のアクセスが許可されたポリシー 以上でOAIを使用したCloudFront経由のアクセスを可能にするバケットポリシーの編集は完了になります。 試しに、S3のエンドポイントから直接アクセスしようとすると、403エラーになります。(こうなるのが正常です) 独自ドメインを取得し、Route53へ設定する ドメインを取得する ドメインはRoute53からも入手できますが、費用がかかります。 試験目的の場合は、freenomで無料ドメインを取得できます。 取得方法は割愛します。以下のサイトを参考にしてみましょう。 freenomで無料ドメインを取得する 今回はtestfile.tkという無料ドメインを取得しました。 ホストゾーンを作成する Route53とは、DNS(ドメインネームサービス)です。 インターネット上でドメインを管理・運用するために開発されたシステムのことを指します。 DNSは、https://example.comみたいなURLをIPアドレス(123.456.789.123)に変換します。 ドメインの取得ができたり、Route53でアクセスしたいアドレスを使用したいS3のエンドポイントに紐付けます。 「サービス」からRoute53を起動しましょう。 ホストゾーンの作成をクリックしましょう。 ドメイン名に取得したドメイン名を入力しましょう。 入力したらホストゾーンの作成をクリックしましょう。 完了すると以下のように、NSレコードとSOAレコードが作成されます。 NSレコードが4件作成されるので、freenomのDNS設定をします。 freenom→Sevices→MyDomainに移動しましょう。 Manage Domainをクリックしましょう。 freenomのNameserverとして登録します。 Management Tools→Nameserverをクリックしましょう。 Route53で作成されたNSレコード4件を設定しましょう。 Nameserver設定時、末尾の「.」は不要です。 設定したら、Change Nameserverをクリックしましょう。 以上でドメインの設定とfreenomのDNS設定は完了です。 ACMでSSL証明書を発行する ACM(AWS Certificate Manager)とは、AWSウェブサイトとアプリケーションを保護するhttps通信に必要なSSL証明書の作成、更新などができます。 SSL証明書の作成は無料です。 AWS Certificate Manager とは何ですか? SSL証明書とは、Secure Socket Layerの略です。 ウェブサイトの「運営者の実在性を証明」し、インターネット上でやりとりされるデータの「盗聴」「なりすまし」「改ざん」などを防止するために通信データの暗号化を行います。 SSL化のメリット SSL化することで、悪質な不正アクセスの被害を防げます。 セキュリティ面を強化でき、アクセス権限をもたない人がサーバーや情報システムの内部に侵入しないように防止できます。 「サービス」から「Certificate Manager」を起動しましょう。 CloudFrontにACMで作成したSSL証明書を紐付けるためには、 リージョンを「米国東部 (バージニア北部) us-east-1」にする必要があります。 ビューワーと CloudFront との間で HTTPS を必須にするには、証明書をリクエストまたはインポートする前に AWS Certificate Manager コンソールで AWS リージョンを*米国東部 (バージニア北部) *に変更する必要があります。 引用:CloudFront で SSL/TLS 証明書を使用するための要件 リージョンを「米国東部 (バージニア北部) (us-east-1)」に変更し、今すぐ始めるをクリックしましょう。 証明書を発行する パブリック証明書のリクエストにチェック→証明書のリクエストをクリックしましょう。 取得したいSSL証明書のドメイン名を入力しましょう。 今回は、*.example.comのようにワイルドカード証明書を発行する設定とします。ただし、*.example.comで証明書を発行した場合、example.comといったドメインは保護されません。また、複数のドメインを追加することも可能です。 入力したら、「次へ」をクリックしましょう。 DNSの検証にチェック→「次へ」をクリックしましょう。 タグ名は任意です。空欄でも問題ないです。 とくになければ、「確認」をクリックしましょう。 ドメイン名と「DNS」を確認し、「確定とリクエスト」をクリックしましょう。 検証状態は、「検証保留中」になります。 Route53でのレコード作成をクリックしましょう。 正常にCNAMEレコードがRoute53に追加されると「成功」と表示されます。 CNAMEレコードとは、ドメイン名に別名を指定するためのレコードです。 例えば、example.comなどの現在のレコードに対して、別のドメイン (example.jpなど)やサブドメイン (www.example.comなど) にマッピングします。 この時、www.example.comをcanonical name(正式名)、example.comをaliases(別名)と呼びます。 Route53を起動すると、以下のように検証用のCNAMEレコードが追加されています。 早ければ数分で「発行済み」になります。 ※20分〜30分かかる場合もあるので、気長に待ちましょう。 以上でSSL証明書の発行は完了です。 CloudFrontへSSL証明書を設定する 独自ドメインによるhttps接続の為、CloudFrontの設定をします。 CloudFront→Distribution→該当のDistributionIDをクリックしましょう。 Distributionを編集する 「General」→Editをクリックしましょう。 Alternate Domain Names (CNAMEs)は、www.testfile.tkとします。https://www.testfile.tkでのアクセスを可能にします。 Custom SSL Certificateにチェックします。 先程、ACMで作成した*.testfile.tk(fb1a5....を指定します。 上記以外はそのままの設定でOKなので、「Yes,Edit」をクリックしましょう。 以下のように、設定されていたら成功です。 「Distributions」に戻るとCNAMEsタブに指定したドメインが表示されています。 StatusがIn ProgressからDeployedになるのを待ちます。 以下のようにStatusがDeployedになったら設定は完了です。 ※Deployedになるまでは数分かかります。 以上でCloudFrontへSSL証明書を設定する作業は完了です。 Route53にCloudFrontのドメインを紐付ける 今回は、www.testfile.tkで公開するため、Route53のレコード設定をします。 レコードを作成する Route53→ホストゾーン→ドメイン名(testfile.tk)をクリック→レコードを作成をクリックしましょう。 レコード名 →リダイレクト元のドメイン (CloudFrontでSSL証明書を設定した際に入力したドメイン名) レコードタイプ →A トラフィックのルーティング先 →エイリアスをONにする →「CloudFront ディストリビューションへのエイリアス」を指定 →CloudFrontのDomain Nameを指定 入力ができたら、レコードを作成をクリックしましょう。 作成されると以下のように、Aレコードが作成されます。 以上でRoute53へのドメイン名の紐付け作業は完了です。 独自ドメインにアクセスしてブラウザで確認する 作成したドメイン(https://www.testfile.tk/)をブラウザでアクセスして、静的サイトが表示されるか確認しましょう。 無事表示されたら、成功です! ※今は上記のURLでアクセスできません。 以上で全工程が完了しました! ※テスト目的などの場合は、課金されないようにS3バケットの削除、CloudFrontのDistributionの削除、Route53のホストゾーンの削除(作成から12時間以内にホストゾーンを削除した場合は、月額0.5$の課金対象外です)など忘れずに実施しておきましょう。 番外編 S3バケットのオブジェクトをCloudFrontに即時反映させる方法 S3バケット内のオブジェクト(html,cssなど)を更新したいときに、オブジェクトをバケットにアップロードしても、CloudFrontには即時に反映されません。 なぜなら、CloudFrontはS3オブジェクトのキャッシュを24時間保持しているからです。 デフォルトでは、CloudFront は Amazon S3 からのレスポンスを 24 時間 (86,400 秒間のデフォルト TTL) キャッシュしています。リクエストが エッジロケーションに到着してから24 時間以内に Amazon S3 を提供した場合、Amazon S3 のコンテンツを更新したとしても、CloudFront はキャッシュされたレスポンスを使います。 引用:CloudFront が、Amazon S3 から古いコンテンツを提供し続けるのはなぜですか? その場合の対処法は、CloudFrontのキャッシュをクリアすることでS3からオブジェクトを直接取得でき、ファイルが即時反映されます。 コンソールから「CloudFront」→対象のDistributionsを選択しましょう。 Invalidationsをクリックしましょう。 ※「Invalidation」とは直訳で「無効化」という意味です。 Create Invalidationをクリックすると、モーダルが開きます。 Object PathsにキャッシュをクリアをしたいS3のオブジェクトのパスを指定しましょう。 削除したいオブジェクトのキャッシュをパスで指定します。 今回は、/*と指定します。 これを指定すると、対象のS3バケット内全てのキャッシュがクリアされます。 データを指定したい場合などは、以下のように指定しましょう。 /index.html  /css/* 入力したら、Invalidateをクリックしましょう。 StatusがIn ProgressからCompletedに変われば、キャッシュの削除は完了です。 ブラウザからCoudFrontのURL(d3XXXXXX36XXXX.cloudfront.net)にアクセスし、サイトが更新されたことを確認してみましょう。 独自ドメインの反映までには、時間がかかると思います。 自分の場合は3〜4時間かかりました。 ※※注意事項※※ 無料で 1 か月あたり 1,000 回のパスの無効化が許可されています。パスの無効化が 1 か月あたり 1000 回を超える場合は、「Amazon CloudFront の料金」にある「無効リクエスト」の覧をご参照ください。 引用:CloudFront が、Amazon S3 から古いコンテンツを提供し続けるのはなぜですか? 参考サイト 今回実装するにあたって以下のサイトを参考にさせていただきました。 Amazon S3 での静的ウェブサイトの設定 CloudFrontを使用して、Amazon S3 でホストされた静的ウェブサイトを公開する CloudFront + S3 + Route53で独自ドメインをSSL通信(https)設定をする 無料ドメイン(.tk)とRoute53を利用して0円でHTTPS環境を設定してみた
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS にて ACM の証明書の期限が切れたので、証明書を発行し直した

現在、自分のポートフォリオサイト(WordPress で作成)を AWS EC2 にて運用しております。 かまだひとし公式サイト ドメインは AWS Route 53 で取得し、AWS Certificate Manager(ACM)にて発 行した証明書を使って HTTPS 化を実現しております。 構成としては下記のサイトで紹介されている通りになります。 AWS で Web サイトを HTTPS 化 その 1:ELB(+ACM 発行証明書)→EC2 編 – ナレコム AWS レシピ | AI に強い情報サイト つい先日、AWS の証明書が切れて https サイトにアクセスできなくなり、新たに証明書を発行し直しました。 今回は備忘録としてその手順をまとめます。 きっかけ きっかけは AWS からYour certificate has expiredというタイトルのメールが届いたことです。 実は期限が切れる前に、URGENT Action Required - Your certificate renewalというタイトルのメールが届いていたのですが、確認するのが面倒で無視していました。 メールの内容を一部転載します。 ACM was unable to automatically renew your certificate. The domain validation method for this certificate is email validation. This method requires the domain owner or someone authorized by the domain owner to take one of the following actions before Jun 03, 2021 at 12:00:00 UTC. If no action is taken, the certificate will expire, which might cause your website or application to become unreachable. If you can write records into your DNS configuration, you can replace all of your existing email-validated certificates with DNS-validated certificates. After you add a CNAME record to your DNS configuration, ACM can automatically renew your certificate as long as the record remains in place. You can learn more about DNS validation in the ACM User Guide.[1] If you want to continue using email validation to renew this certificate, the domain owners must use the approval link that was sent in a separate validation request email. The validation email is valid for 3 days. ACM customers can resend the validation email after receiving the first notification or any time up until 3 days after the certificate expires. For more information on how to resend a validation email, refer to the ACM User Guide.[2] If you have questions about this process, contact the AWS Support Center[3]. If you don’t have an AWS support plan, post a new thread in the AWS Certificate Manager discussion forum.[4] [1] https://docs.aws.amazon.com/acm/latest/userguide/gs-acm-validate-dns.html [2] http://docs.aws.amazon.com/acm/latest/userguide/request-domain-validation-email-for-renewal.html [3] https://console.aws.amazon.com/support [4] https://forums.aws.amazon.com/forum.jspa?forumID=206 Sincerely, Amazon Web Services どうやら証明書が自動更新できなかったので、1 か 2 のいずれかのアクションを取ってくださいとのことでした。 DNS 設定にレコードを書き込むことができれば、既存の電子メールで認証された証明書をすべて DNS で認証された証明書に置き換えることができます。DNS 構成に CNAME レコードを追加した後、レコードが残っている限り、ACM は証明書を自動的に更新できます。DNS の検証については、ACM ユーザーガイドで詳しく説明されています[1]。 この証明書を更新するために電子メール検証を継続して使用する場合、ドメイン所有者は別の検証要求メールで送信された承認リンクを使用する必要があります。検証メールの有効期限は 3 日間です。ACM のお客様は最初の通知を受け取った後、または証明書の有効期限が切れる 3 日後までは、いつでも検証メールを再送できます。検証メールの再送方法については、ACM ユーザーガイドをご参照ください[2]。 期限が切れる前なら、いずれかの手順で更新できそうですが、気づいた時には期限が切れていたため、上記の手順では証明書を更新できなくなっていました。 この場合、証明書をもう一度発行し直す必要があります。 ACM で署名のリクエストを行い、発行し直す まず ACM を開き、証明書のリクエストをクリックします。 次に証明書のタイプを選択します。今回はパブリック証明書のリクエストを選択して証明書のリクエストをクリックします。 次にドメイン名を追加します。今回はもともと HTTPS 化していたドメインを入力して次へをクリックします。 次に検証方法を選択します。今回はDNS の検証を選択して次へをクリックします。 次にタグを追加します。今回は何も追加せずにそのまま確認をクリックします。 最後にリクエスト内容を確認します。問題なければ確定とリクエストをクリックします。 最初の画面に戻り、Route 53 でのレコードの作成をクリックします(画像上では既に作成済みのため押せなくなっていますが、本来は押せるはずです)。 しばらく待つと、検証状態が成功となり、状況が発行済みとなるはずです。 これで証明書の発行は完了です。 EC2 にて ELB のリスナーを再追加する まず EC2 のロードバランサーのページを開き、画面下部のリスナータブからリスナーの追加をクリックします。 プロトコルとポートをそれぞれHTTPS、443にします(画像上ではすでに作成済みのため警告が出ていますが、本来は出てこないはずです)。 セキュリティポリシーはELBSecurityPolicy-2016-08(おそらく以前と同じ項目を選択すれば大丈夫です)を選択します。 デフォルトの SSL 証明書は、前項で作成した証明書を選択します。 最後にリスナーの追加をクリックします(画像上では既に作成済みのため押せなくなっていますが、本来は押せるはずです)。 これで証明書が更新され、サイトにもアクセスできるようになっているはずです。 まとめ ACM の証明書の更新手順をまとめました。 AWS はドキュメントがわかりづらいので、きちんと備忘録として残しておいた方がよさそうです。 また、証明書の期限が切れると急にアクセスできなくなります。 英語のメールがきて面倒だなと思ったとしても、ちゃんと目は通しておくべきでした。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

「Amazon TimestreamのデータをGrafanaで可視化してみた | DevelopersIO」をやってみた

はじめに Amazon TimestreamのデータをGrafanaで可視化してみた | DevelopersIOをやってみたときのメモです。 手順 Grafana公式リポジトリからソースコードを取得します。 実際に使用するのは、Dockerfileの1ファイルのみです。 mkdir grafana cd grafana wget https://raw.githubusercontent.com/grafana/grafana/main/packaging/docker/custom/Dockerfile Dockerイメージをビルドします。 docker build \ --build-arg "GRAFANA_VERSION=latest" \ --build-arg "GF_INSTALL_PLUGINS=grafana-timestream-datasource" \ -t grafana-custom -f Dockerfile . Dockerコンテナを起動します。 docker run -d -p 3000:3000 --name=grafana grafana-custom ブラウザでhttp://localhost:3000にアクセスします。 admin/adminでログインします。 Grafanaの画面で、Configuration > Data Sources > Add data source で Amazon Timestreamを選択します。 AWSのアクセスキーとシークレットアクセスキーを入力します。 us-east-1リージョンを選択します。 ※Timestreamは、現時点では、東京リージョンでGAされていません。 次のコマンドでエンドポイントを取得します。 ※https://を補います aws timestream-query describe-endpoints --region us-east-1 Query Editorに次のクエリーを入力します。 SELECT measure_name, measure_value::double AS load, time FROM "sampledb".IoT WHERE measure_name = 'load' ORDER BY time
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Alpine に AWS CLI をインストールする

インストール Alpine には curl が無いのでまずそれをインストールしてから。 glibc が必要なのでそれも入れる。 apk --no-cache add binutils curl curl -sL https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.33-r0/glibc-2.33-r0.apk curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.33-r0/glibc-bin-2.33-r0.apk apk add --no-cache glibc-2.33-r0.apk glibc-bin-2.33-r0.apk curl -sL https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscliv2.zip unzip -q awscliv2.zip aws/install aws --version 参考 Alpine ベースのコンテナイメージで AWS CLI v2 を使う
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CircleCI + Serverless でコンテナ環境を AWS Lambda に自動デプロイ

Lambda で外部ライブラリを使いたいとき 実行環境を Docker イメージにして ECR から実行することで実現できますが、自分でやるのはちょっと面倒です というわけで、CircleCI に任せてしまいましょう やりたいこと ローカルで作った Lambda 用のコンテナを、GitHub の main ブランチにプッシュしたら Lambda へ自動デプロイされるようにしたい フロー GitHub の main ブランチの更新を CircleCI が感知 CircleCI のコンテナ内で Docker イメージをビルド Docker イメージを ECR へプッシュ Serverless が ECR のイメージを使って Lambda へデプロイ 実装 ECR にリポジトリ作成 ECR のプライベートリポジトリを作成しておきます リポジトリ名はCircleCI の環境変数に入れるので控えておいてください IAM ユーザー作成 serverless 用の IAM ユーザーを作成します プログラムによるアクセスを許可し、アクセスキーとシークレットアクセスキーを控えておきましょう CircleCI の環境変数設定 AWS_ACCOUNTID:AWS のアカウントID AWS_ACCESS_KEY_ID:IAM のアクセスキー AWS_SECRET_ACCESS_KEY:IAM のシークレットアクセスキー AWS_DEFAULT_REGION:リージョン FUNC_NAME:先ほど作成した ECR のリポジトリ名と同じにする ファイル構成 project ├── .circleci │ └── serverless.yml ├── app.py ├── Dockerfile ├── requirements.txt └── serverless.yml app.py TensorFlow を入れて動作確認 import tensorflow as tf def handler(event, context): return { 'statusCode': 200, 'body': { 'predict': tf.__version__, } } Dockerfile AWS のパブリックイメージからビルドしていきます FROM public.ecr.aws/lambda/python:3.8 COPY . ${LAMBDA_TASK_ROOT} RUN pip install -r requirements.txt CMD ["app.handler"] requirements.txt 必要なライブラリを書いておきましょう tensorflow==2.5.0 serverless.yml Lambda にデプロイする用の設定を書きます ECR_DIGEST の環境変数は、ECR にプッシュしたとき返ってくるダイジェストを入れておきます プッシュ時に決まるので、その時に環境変数に入れるようにします serverless.yml service: ecr-lambda-test provider: name: aws stage: dev region: ${env:AWS_DEFAULT_REGION} functions: iconow-predict: # ECR のプライベートリポジトリからビルドする image: ${env:AWS_ACCOUNTID}.dkr.ecr.${env:AWS_DEFAULT_REGION}.amazonaws.com/${env:FUNC_NAME}@${env:ECR_DIGEST} memorySize: 2048 timeout: 180 .circleci/config.yml イメージは docker を使用しました これは コンテナ内で Docker ビルドが出来るようにに整えられている Alpine ベースのイメージです 本当は amazon/aws-cli を使いたかったのですが、Docker ビルドがうまくいかなかったのでこちらを採用しています circleci/config.yml version: 2.0 jobs: deploy_lambda_test: docker: - image: docker:latest steps: # GitHub のリポジトリを持ってくる - checkout # Docker でビルドなどを行うためのセットアップ - setup_remote_docker - run: # serverlessをインストール。node が必要なのでそれも込み。あと IAM 情報も登録しておく。 name: serverless install command: | apk add nodejs apk add npm npm install -g serverless serverless config credentials --provider aws --key ${AWS_ACCESS_KEY_ID} --secret ${AWS_SECRET_ACCESS_KEY} - run: # aws cli をインストール。alpine には curl が無いのでまずそれをインストールする。 name: aws install command: | apk --no-cache add binutils curl curl -sL https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.33-r0/glibc-2.33-r0.apk curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.33-r0/glibc-bin-2.33-r0.apk apk add --no-cache glibc-2.33-r0.apk glibc-bin-2.33-r0.apk curl -sL https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscliv2.zip unzip -q awscliv2.zip aws/install aws --version - run: # aws の認証を得る。パブリックイメージとプライベートリポジトリの両方。 name: aws auth command: | aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws aws ecr get-login-password | docker login --username AWS --password-stdin ${AWS_ACCOUNTID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com - run: # ビルドしてデプロイ。ECR にプッシュするとダイジェストが返ってくるので、それを環境変数に追加する。(serverless が使う) name: build image & deploy command: | docker build -t ${FUNC_NAME} . docker tag ${FUNC_NAME} ${AWS_ACCOUNTID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${FUNC_NAME} export ECR_DIGEST=`docker push ${AWS_ACCOUNTID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${FUNC_NAME} | grep digest | cut -d ' ' -f3` echo ${ECR_DIGEST} serverless deploy workflows: version: 2 build_and_deploy: jobs: - deploy_lambda_test: filters: branches: # main ブランチのみ only: main 完成 お疲れ様でした あとは GitHub の main ブランチにプッシュすれば自動的にデプロイされます! GitHub コード全体を上げているので良かったらどうぞ 参考 Alpine ベースのコンテナイメージで AWS CLI v2 を使う
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Lambda で TensorFlow を使う

手段 Lambda は ECR のイメージからコンテナを展開し、その中の関数を使うことができます というわけで以下のフローで実現します TensorFlow が使えるイメージ作成 ECR にプッシュ Lambda にデプロイ ツール Docker AWS CLI serverless(lambdaにデプロイするのに使います。npm install serverlessで導入できます。) 実装 それでは実装していきましょう イメージ作成 以下のような構成を作成します project ├── Dockerfile ├── app.py └── requirements.txt Dockerfile 作成 AWS のパブリックイメージからビルドしていきます FROM public.ecr.aws/lambda/python:3.8 COPY . ${LAMBDA_TASK_ROOT} RUN pip install -r requirements.txt CMD ["app.handler"] requirements.txt 作成 python で必要になるライブラリを書いていきます 今回は TensorFlow が必要なので、こちらを記述します 必要があれば、numpy なども書いておきましょう requirements.txt tensorflow==2.5.0 app.py 作成 今回は TensorFlow を動かしたいだけなので、動作確認だけします app.py import tensorflow as tf def handler(event, context): return { 'statusCode': 200, 'body': { 'predict': tf.__version__, } } ECR にプライベートリポジトリを作成 ECR にプライベートリポジトリを作りましょう 今回は、func1 という名前のリポジトリにしました ECR にプッシュ まずは、パブリックイメージをプルできるように認証を得ておきます $ aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws 次に、プライベートリポジトリにプッシュできるよう認証を得ておきます $ aws ecr get-login-password | docker login --username AWS --password-stdin {アカウントID}.dkr.ecr.{リージョン}.amazonaws.com. その後、イメージを作成してプッシュしましょう プッシュすると、ダイジェストが返ってくるので控えておいてください $ docker build -t func1 . $ docker tag func1 {アカウントID}.dkr.ecr.{リージョン}.amazonaws.com/func1 $ docker push {アカウントID}.dkr.ecr.{リージョン}.amazonaws.com/func1 digest: sha256:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # 控えておく Serverless でデプロイ serverless を使って、lambda にデプロイしていきます serverless.yml 作成 プロジェクト配下に作成します project ├── Dockerfile ├── app.py ├── requirements.txt └── serverless.yml Lambda にデプロイする際の設定を書きます 先ほど控えたダイジェストを使って、ECR にあげたイメージを指定します serverless.yml service: tf-test provider: name: aws stage: dev region: ap-northeast-1 functions: hello: image: {アカウントID}.dkr.ecr.{リージョン}.amazonaws.com/func1@sha256:{ダイジェスト} memorySize: 2048 timeout: 180 serverless を AWS にアクセスできるようにする serverless用に AWS の IAM ユーザーを作成しておきます プログラムによるアクセスにチェックを入れておいてください アクセス権限は AdministratorAccess をアタッチします 作成時に取得したアクセスキーとシークレットアクセスキーで、serverless にアクセス権限を付与します $ serverless config credentials --provider aws --key {アクセスキー} --secret {シークレットアクセスキー} デプロイ 以下のコマンドでデプロイ完了です! $ serverless deploy
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む