20211126のAWSに関する記事は19件です。

AWS Certified Cloud Practitionerに1週間で合格した話

はじめに 10年以上セキュリティエンジニアとして働いていましたが、訳あって最近インフラのリーダーになりました。会社では主にAWSを利用しているため、勉強がてらAWSの資格を取得したという話です。 ちなみにセキュリティエンジニアの時はAWSを使うことはなくGCPで色々なことをやっていました。AWSを使わなかった理由は、数年前にAmazonアソシエイトを意味不明な理由で垢バンされたからです。。 勉強方法 以下2冊の本を読み込みました。どちらも1年以上前の本ですが特に問題なかったです。 Amazonアソシエイトを垢バンされているためアフィリエイトリンクにはなっておりません。安心してクリックしてください。 以下の本はシンプルにまとまっていて覚えやすい&理解しやすかったです。 3日くらいかけて内容を暗記しました。 次に、上の本1冊だけでは不安だったので以下の本も買いました。 上の本に記載していない内容が多々ありましたので買ってよかったです。 こちらも3日くらいかけて内容を暗記しました。 受験 ピアソンVUEで自宅から受験しました。 楽勝だと思って受験しましたが、見たことない単語がでてきたりいまいち内容が理解できない問題が出てきたりしてもしかして落ちたかも・・と思いながら解いていました。 結果は無事合格できたのですが、運が良かった気もします。 感想 AWS Certified Cloud PractitionerはAWSの入門レベルの資格ですが、この内容を把握するだけでも社内の打ち合わせで話について行けるようになりました。 AWS全体を広く浅く把握するためにはちょうどよい勉強ができたと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[2021年] AWS Certified Cloud Practitionerに本2冊で合格した話

はじめに 10年以上セキュリティエンジニアとして働いていましたが、訳あって最近インフラのリーダーになりました。会社では主にAWSを利用しているため、勉強がてらAWSの資格を取得したという話です。 ちなみにセキュリティエンジニアの時はAWSを使うことはなくGCPで色々なことをやっていました。AWSを使わなかった理由は、数年前にAmazonアソシエイトを意味不明な理由で垢バンされたからです。。 勉強方法 以下2冊の本を読み込みました。どちらも1年以上前の本ですが特に問題なかったです。 Amazonアソシエイトを垢バンされているためアフィリエイトリンクにはなっておりません。安心してクリックしてください。 以下の本はシンプルにまとまっていて覚えやすい&理解しやすかったです。 3日くらいかけて内容を暗記しました。 次に、上の本1冊だけでは不安だったので以下の本も買いました。 上の本に記載していない内容が多々ありましたので買ってよかったです。 こちらも3日くらいかけて内容を暗記しました。 本を読む以外の勉強は一切していません。 AWSに触れることもありませんでした。 受験 ピアソンVUEで自宅から受験しました。 楽勝だと思って受験しましたが、見たことない単語がでてきたりいまいち内容が理解できない問題が出てきたりしてもしかして落ちたかも・・と思いながら解いていました。 結果は無事合格できたのですが、運が良かった気もします。 感想 AWS Certified Cloud PractitionerはAWSの入門レベルの資格ですが、この内容を把握するだけでも社内の打ち合わせで話について行けるようになりました。 AWS全体を広く浅く把握するためにはちょうどよい勉強ができたと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS】素の Cloud9 に Python 3.9 をインストールする

結果何とかなりましたが時間を吸われたので、 備忘録として残します。 1. やりたいこと AWS Cloud9 Python 3.7.10 (既定のバージョン※) を 3.9.0 にアップデートする ※ 2021 年 11 月 24 日 現在 2. 前提 環境 作成してそのままの Cloud9 (Amazon Linux 2) 3. 方法 Python バージョン 3.7.10 からスタートします。 $ python --version Python 3.7.10 3.1. pyenv インストール まず pyenv をインストールします。 $ git clone https://github.com/pyenv/pyenv.git ~/.pyenv # 確認 $ ~/.pyenv/bin/pyenv --version pyenv 2.2.2-1-gf2925393 ~/.bashrc に以下を記載し、 pyenv コマンドへパスを通します。 ~/.bashrc export PATH="$HOME/.pyenv/bin:$PATH" eval "$(pyenv init -)" 変更を適用し、 pyenv コマンドが通ることを確認します。 $ source ~/.bashrc # 確認 $ pyenv --version pyenv 2.2.2-1-gf2925393 $ pyenv versions * system (set by /home/ec2-user/.pyenv/version) インストール可能な Python バージョンを表示してみます。 $ pyenv install --list | grep 3.9.0 3.9.0 上手くいきそうに見えますが、いざインストールすると警告が出てきます。 # インストールした場合、警告が出る $ pyenv install 3.9.0 : WARNING: The Python bz2 extension was not compiled. Missing the bzip2 lib? Installed Python-3.9.0 to /home/ec2-user/.pyenv/versions/3.9.0 bzip2 を確認してみると、既にインストールされています。 $ sudo yum list installed | grep bzip bzip2.x86_64 1.0.6-13.amzn2.0.3 @amzn2-core bzip2-libs.x86_64 1.0.6-13.amzn2.0.3 @amzn2-core 色々調べた結果、足りていないパッケージは bzip2-devel でした。 3.2. bzip2-devel インストール 念のため yum 自体をアップデートしてからインストールします。 # 念のためアップデート $ sudo yum -y update # bzip2-devel をインストール $ sudo yum -y install bzip2-devel : Installed: bzip2-devel.x86_64 0:1.0.6-13.amzn2.0.3 Complete! # 確認 $ sudo yum list installed | grep bzip bzip2.x86_64 1.0.6-13.amzn2.0.3 @amzn2-core bzip2-devel.x86_64 1.0.6-13.amzn2.0.3 @amzn2-core bzip2-libs.x86_64 1.0.6-13.amzn2.0.3 @amzn2-core 入りました。 3.3. Python 3.9.0 インストール 満を持して Python 3.9.0 をインストールします。 $ pyenv install 3.9.0 Downloading Python-3.9.0.tar.xz... -> https://www.python.org/ftp/python/3.9.0/Python-3.9.0.tar.xz Installing Python-3.9.0... Installed Python-3.9.0 to /home/ec2-user/.pyenv/versions/3.9.0 # 確認 $ pyenv versions * system (set by /home/ec2-user/.pyenv/version) 3.9.0 警告が消えました。 3.4. Python 3.9.0 に切り替える pyenv global で Python バージョンを切り替えます。 $ pyenv global 3.9.0 # 確認 $ pyenv versions system * 3.9.0 (set by /home/ec2-user/.pyenv/version) しかし、これだけでは Python バージョンは切り替わりません。 # 切り替わっていない $ python --version Python 3.7.10 $ which python alias python='python3' /usr/bin/python3 # 見つからない $ which python3.9 /usr/bin/which: no python3.9 in (/home/ec2-user/.pyenv/bin:...(省略) Cloud9 ではデフォルトで python コマンドの Alias 設定があるため、切り替わらないようです。 他の記事で見かけるように、 Alias 設定が ~/.bashrc に見当たらず困っていたのですが、 ~/.bash_profile に以下を記載することで解決しました。 ~/.bash_profile export PATH="$HOME/.pyenv/shims:$PATH" 変更を適用します。 $ source ~/.bash_profile # 確認 $ python --version Python 3.9.0 $ which python alias python='python3' ~/.pyenv/shims/python3 # 見つかる! $ which python3.9 ~/.pyenv/shims/python3.9 無事 Python バージョンを 3.9.0 に切り替えることができました。 pip もアップデートします。 $ pip install --upgrade pip : Successfully uninstalled pip-20.2.3 Successfully installed pip-21.3.1 3.5. バージョン確認 $ python --version Python 3.9.0 $ pyenv versions system * 3.9.0 (set by /home/ec2-user/.pyenv/version) $ pip -V pip 21.3.1 from /home/ec2-user/.pyenv/versions/3.9.0/lib/python3.9/site-packages/pip (python 3.9) いい感じになりました! 4. 参考サイト pyenvによる仮想Python環境をAWS Cloud9上で構築する pythonのバージョンが切り替わらない ありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS環境のセキュリティチェックをするためのツールを作った話

この記事について NTTドコモテクニカルジャーナル Vol.29 No.1 "パブリッククラウドの利用に特化したセキュリティチェックツールの開発" の筆者による解説記事です。 AWS上で起こるセキュリティ事故 AWSの東京リージョンのリリースが2011年3月2日ですので、2021年で丸10年が経過したことになります。(ちなみに、この10年の節目である2021年3月2日に日本で二番目のリージョンである大阪リージョンが正式にGAとなったのは有名な話ですね。) 昨今、AWSをはじめとするパブリッククラウド上で企業がシステムを構築することはもはや当たり前になってきました。それにあわせて、AWS上で企業が顧客情報など特に機密性の高い情報を扱うようになってきていますが、当然ながらその際にはセキュリティが非常に重要となります。 セキュリティ対策がうまくできていないと、大規模な情報流出やサービスの停止などの重大なインシデントが発生してしまうかもしれません。特に大規模な事例として、米国Capital One社のシステムから1億人以上の個人情報が流出した事故を記憶している方も多いのではないでしょうか。 こういった事故は、AWSを利用していなかったら発生しなかった、と言えるかもしれません。しかしながら、ビジネスを大きく加速させることができるなど、パブリッククラウドを利用することのメリットが数多いことも事実であり、日本でもこれだけ企業でのクラウド利用が進んでいることがそれを物語っていると思います。もはや2021年現在において、セキュリティだけを理由にしてパブリッククラウドを利用しないという選択肢を取るのは、企業経営的にも適切ではないと考えられるかもしれません。 クラウドでのセキュリティ対策の考え方 パブリッククラウドを使う上で、まず理解しておきたい概念が「責任共有モデル」です。 例えばAWSでEC2を使う場合、AWSが主にデータセンタなどの物理的なファシリティから、物理マシンやネットワークなどのハードウェア、ホストOSや仮想化レイヤの管理までを実施する一方で、ゲストOSやその上で動作するアプリケーションは利用者側が責任をもって管理を行う必要があります。一方で、マネージドサービス(Lambdaなど)を利用すれば、利用者側が責任を負う範囲がより狭くなり、多くの管理をAWSに任せる事が可能となります。 このように、サービスごとにクラウド事業者とその利用者がそれぞれ責任を負う範囲を明確化して分担し,協力して対策を行っていくという考え方が責任共有モデルです。この時、クラウド事業者側がいくら対策を実施していたとしても、利用者側の設定次第では非常に危険な状態を作り出してしまう可能性があるというのを、強く認識しておく必要があります。 その上で、利用者側が責任を負う範囲をより狭くすることで、多くの管理をクラウド事業者側に任せる事が可能となり、その分付加価値の高いアプリケーションやビジネス領域に集中して企業のリソースを投下することができるというわけです。 クラウドの設定状況をチェックする 「利用者側の設定次第では非常に危険な状態を作り出してしまう可能性がある」というのをどうやって防止すれば良いでしょうか。そもそも危険な状態にならないようにAWSがやってくれるのが一番良いですよね。それを実現するための方法の1つがマネージドサービスを使うことなのですが、ではなぜ利用者側にも裁量が残されているかというと、それはもちろんビジネス要件に応じてシステムを作らなければならないからです。つまり、機械的に危険な設定を防止するという仕組みではうまくワークしないということを意味しています。 では、どのように対策をするのが良いのでしょうか。少なくとも、危険な状態となっている可能性が高い設定というのは抽出できそうです。 わかりやすい例では、「AWSのルートユーザーにMFAが設定されていない状態」というのは、AWSを利用していく上ではかなり危険な状態であり、アンチパターンとされています。そして、AWSがこの状態を完全に防止していないのには、MFAを設定されていない状態にあえてする必要性があるユースケースを考慮している(+歴史的な経緯でそうせざるを得ない)のではないかと考えられます。例えば、検証用でAWSアカウントを一度に大量に管理する必要があるケースなどでしょうか(筆者の個人的な考えでは、いかなる場合でもルートユーザにはMFAを設定すべきと思います)。 そして、こういったケースでは最終的には利用者側で危険度を判断し、対処する必要が出てきます。つまり、 予期せず危険な状態になっているので、対策をする。 想定内なので、リスクを受容して期間な状態で使い続ける。 のどちらかを選択することになります。 アセスメントツール「ScanMonster」 セキュリティリスクの可視化と判断をするには、AWSを使う上でのアンチパターンがどのようなものか、それがどれくらい危険なのかを1つ1つ確認していかなければなりません。しかし、AWSを使う全員がAWSのエキスパートではないし、複数のリージョンやアカウントにまたがってたくさんのリソースを網羅的に確認していくのはAWSのエキスパートでも心が折れる作業ですよね。 そこで、セキュリティアセスメントを自動で行うことのできるツール「ScanMonster」を作りました。 複数のAWSアカウントに対して横断的にチェックが可能 チェック結果を一目で確認可能 AWS初心者にもわかりやすいチュートリアルを完備 ScanMonsterでは、これらの特徴で素早く自動的にAWS環境のチェックが可能です。そして、AWSのエキスパートでなくても、チュートリアルを読みながらリスクの把握とアクションの判断を行うことが可能です。 ScanMonsterのアーキテクチャ ScanMonsterは、それ自体をAWS上に立てることにしました。そして、CloudFormationによるIaC化、AWS Lambdaを中心としたフルサーバーレス構成としています。 IaC化により、インフラまで全てがコードで管理されています。開発時には環境構築やテストの時間を短縮することができています。また、丸ごとScanMonsterを別のAWSアカウントに作って、別のチームで使うといったこともできるようになっています。 サーバーレスアーキテクチャを採用したことで、アセスメント実行時以外はほとんど費用の発生を抑えることができています。実際にScanMonsterでは毎月数百円ほどのランニングコストしか発生しておらず、EC2を1台だけ常時起動しているよりも安く抑えることができています。また、この記事中でもあったようにインフラの大部分の管理をAWS側がやってくれるマネージドサービスであるため、その分利用者側で意識しなければいけない責任範囲を少なくすることができています。 皆さんも、AWS上でツールを作成する際には、ぜひIaC・サーバーレスあたりをキーワードに設計してみてはいかがでしょうか。 そして、AWS上でセキュアにシステムを構築・運用していくためのツールは世の中にたくさんあります。AWSからもConfigやSecurity Hubのように同じようなことを実現できるサービスが提供されています。文中でも触れましたが、クラウドセキュリティはツールを入れたら終わりではありません。セキュリティリスクを正確に判断できるように、継続的にクラウドのことを勉強する必要もあります。 日々クラウドに関する知識のアップデートを怠らず、そして、ツールを賢く活用して、一緒に安全なクラウドライフを送っていきましょう。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS CLIで Web サイトを構築、管理、運用する(1日目)

ひとりアドベントカレンダーということで、AWS CLI でいろいろやっちゃうシリーズをお送りします。 当面は、AWS CLIでWebサイトを構築、管理、運用するといった具合です。 1日目の要約 Web サイトをさくっとたてるよ! AWS CLI の準備 このあたりをみて、好きなバージョンとお使いのOSにあった環境設定をしてくださいね。 なんなら、 AWS CloudShell で実行するのも楽でよいと思います。 この記事シリーズは、AWS CloudShell で実行し、実行例を載せています。 バージョン1 https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-cliv1.html バージョン2 https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-cliv2.html 構成図 概要 Amazon Simple Storage Service(Amazon S3)の静的 Web ホスティング機能を AWS CLI で設定、構築する さあ、やってみよう! S3 関係のコマンドの確認 S3 に関する AWS CLI のコマンドは以下の通りです。 s3 ファイルの転送などに使う 高レベル(S3)コマンドともいう s3api S3 の API を操作するのに使う s3control アカウントレベルでの S3 操作・設定を行うコマンド この記事では使いません S3 Bucket を作る S3 Bucket を作成する際、まずはじめに気を付けないとならないのがバケット名の命名規則に準じているかです。 バケット名は 3 ~ 63 文字の長さで、小文字、数字、ピリオド、ダッシュのみを使用できます。 バケット名の各ラベルは、小文字または数字で始まっている必要があります。 バケット名では、アンダースコア、末尾のダッシュ、連続するピリオド、隣接するピリオドとダッシュは使用できません。 バケット名を IP アドレス (198.51.100.24) として書式設定することはできません。 あと、一番大事なのが、ほかの利用者やアカウント含めて被らないようにしないとならないということです。 以下の例では、生成した uuid を用いることで回避できるようにしています。 使用するコマンドは、 s3api create-bucket コマンドです。 BUCKETNAME=`uuidgen` aws s3api create-bucket --bucket ${BUCKETNAME} \ --region ap-northeast-1 \ --create-bucket-configuration LocationConstraint=ap-northeast-1 実行すると以下の様に出力されます。 { "Location": "http://<BUCKETNAME>.s3.amazonaws.com/" } コンテンツを作る 適宜 HTML ファイルを作ってください。見本は以下の通り。 index.html <!DOCTYPE html> <html lang="ja"> <head> <title>Advent calendar 2021</title> </head> <body> <h1>Hello world!!</h1> </body> </html> S3 へコンテンツをアップロードする 作ったコンテンツ(ファイル)を S3 にアップロードします。 ファイルは、カレントディレクトリにある前提で実行例を載せています。 使用するコマンドは s3 cp コマンドです。 # 同じシェルをそのまま使える場合は環境変数を使う aws s3 cp index.html s3://${BUCKETNAME}/index.html # 閉じてしまったなどで使えない場合は、バケット名を自分で指定してください。 #aws s3 cp index.html s3://<BUCKETNAME>/index.html 無事にアップロードできると、以下の様に出力されます。 upload: ./index.html to s3://<BUCKETNAME>/index.html S3 バケットにファイルが格納できたか確認する アップロード時のコマンド出力でアップロードができたことが確認できていますが、念のために、s3 ls コマンドをつかって存在するかも確認します。 # 同じシェルをそのまま使える場合は環境変数を使う aws s3 ls s3://${BUCKETNAME}/ # 閉じてしまったなどで使えない場合は、バケット名を自分で指定してください #aws s3 ls s3://<BUCKETNAME>/ ファイルが格納されていれば、以下の様に出力されます。 YYYY-MM-DD hh:mm:ss 134 index.html S3 バケットに格納されていることが確認できました。 静的 Web ホスティングの設定を有効化する ファイルが格納できたので、次は、お待ちかねの、Web サーバの構築もとい、静的 Web ホスティングの有効化です。 今回は簡単に有効化するため s3 website コマンドで実行します。 細かな設定をしたい場合は、s3api put-bucket-website コマンドを使います。 # 同じシェルをそのまま使える場合は環境変数を使う # コンテンツのファイル名が異なる場合は適宜変更する aws s3 website s3://${BUCKETNAME}/ --index-document index.html # 閉じてしまったなどで使えない場合は、バケット名を自分で指定してください。 #aws s3 website s3://<BUCKETNAME>/ --index-document index.html 正常に終了した場合は、特に応答なしです。 s3api get-bucket-website コマンドを実行することで有効化されているかが確認できます。 # 同じシェルをそのまま使える場合は環境変数を使う aws s3api get-bucket-website --bucket ${BUCKETNAME} # 閉じてしまったなどで使えない場合は、バケット名を自分で指定してください。 #aws s3api get-bucket-website --bucket <BUCKETNAME> 有効化されている場合は、以下が出力されます。 { "IndexDocument": { "Suffix": "index.html" } } これで、対象の S3 バケットの静的 Web ホスティングが有効化されました。 ちなみに、有効化されていない場合は、以下が出力されます。 An error occurred (NoSuchWebsiteConfiguration) when calling the GetBucketWebsite operation: The specified bucket does not have a website configuration でも、実は・・・ 本記事では、東京リージョン(ap-northeast-1)にバケットを作成しているので、以下のURLでアクセスできるようになります。 http://<BUCKETNAME>.s3-website-ap-northeast-1.amazonaws.com しかし、このままではアクセスできないのです。 試しに、curl コマンドを使って上述のURLにアクセスしてみます。 # 同じシェルをそのまま使える場合は環境変数を使う curl http://${BUCKETNAME}.s3-website-ap-northeast-1.amazonaws.com/ # 閉じてしまったなどで使えない場合は、バケット名を自分で指定してください。 #curl http://<BUCKETNAME>.s3-website-ap-northeast-1.amazonaws.com/ すると、以下の様に、HTTP403 Forbidden が返されます。 <html> <head><title>403 Forbidden</title></head> <body> <h1>403 Forbidden</h1> <ul> <li>Code: AccessDenied</li> <li>Message: Access Denied</li> <li>RequestId: **************</li> <li>HostId: ******************************************************</li> </ul> <hr/> </body> </html> これを打開するには、次に実施するコンテンツの公開が必要です。 コンテンツを公開する というわけで、コンテンツの公開を行います。 s3api put-object-acl コマンドを実行します # 同じシェルをそのまま使える場合は環境変数を使う # コンテンツのファイル名が異なる場合は適宜変更する aws s3api put-object-acl --bucket ${BUCKETNAME} --key index.html --acl public-read # 閉じてしまったなどで使えない場合は、バケット名を自分で指定してください。 #aws s3api put-object-acl --bucket <BUCKETNAME> --key index.html --acl public-read このコマンドも特に応答なく完了します。 実行できたら、Webブラウザでアクセス・・・もいいですが、 やはり、curl コマンドで HTML ファイルが表示されるか確認します。 # 同じシェルをそのまま使える場合は環境変数を使う curl http://${BUCKETNAME}.s3-website-ap-northeast-1.amazonaws.com/ # 閉じてしまったなどで使えない場合は、バケット名を自分で指定してください。 #curl http://<BUCKETNAME>.s3-website-ap-northeast-1.amazonaws.com/ すると、以下の様に、作成した HTML ファイルの内容が出力されます。 <!DOCTYPE html> <html lang="ja"> <head> <title>Advent calendar 2021</title> </head> <body> <h1>Hello world!!</h1> </body> </html> AWS CLI (とシェル)だけで Webサイトを構築することができました! まとめ とりあえず、「Web サーバをさくっとたてるよ!」という目標は達成できました。 しかし、このままだと色々と問題があります、2日目以降でそのあたりに触れていきます。 今回使ったコマンド s3api create-bucket s3 cp s3 ls s3 website s3api get-bucket-website s3api put-object-acl
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RDS自動起動停止をlambdaで

はじめに RDSの料金を節約するために夜中に停止して朝起動するジョブを作ります。 RDSの作成 RDS上でテスト対象となるDBを作成します。 DBの情報 "DB識別子": "postgres-db" lambdaの作成 event変数でAction(Start/Stop)と対象のInstanceを取得して、対象DBのステータスを取得したあと起動/停止を行います。 /lambda_function.py import boto3 region = 'ap-northeast-1' def lambda_handler(event, context): rds = boto3.client('rds', region_name=region) action = event["Action"] db_instance = event["Instance"] response = rds.describe_db_instances(DBInstanceIdentifier=db_instance) print( db_instance, 'is', response['DBInstances'][0]['DBInstanceStatus'],'now' ) if action == "Start": rds.start_db_instance(DBInstanceIdentifier=db_instance) print('started your instance: ' + str(db_instance)) elif action == "Stop": rds.stop_db_instance(DBInstanceIdentifier=db_instance) print('stopped your instance: ' + str(db_instance)) else: print('Lamdba function could not be executed.') DB停止用のテストjsonを作成します。 stop-db1 { "Action": "Start", "Instance": "postgres-db" } DB起動用のテストjsonを作成します。 start-db1 { "Action": "Start", "Instance": "postgres-db" } lambda関数にrdsアクセス用のIAMロールを付与します。ロールのアクセスポリシーはビジュアルエディタで作成することができます。 start-stop-rds-db { "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": [ "rds:DescribeDBInstances", "rds:StopDBInstance", "rds:StartDBInstance" ], "Resource": "arn:aws:rds:*:*:db:*" } ] } lambdaのテスト実行 DBの起動と停止をテストしました。どちらも1秒以内にlambdaの処理は終わっていますが、このあと実際にDBが停止や起動するのには数分間くらいかかります。 DBの停止 Test Event Name stop-db1 Response null Function Logs START RequestId: 45ad5172-4e9e-4a7e-8bf9-6692028cad5f Version: $LATEST postgres-db is available now stopped your instance: postgres-db END RequestId: 45ad5172-4e9e-4a7e-8bf9-6692028cad5f REPORT RequestId: 45ad5172-4e9e-4a7e-8bf9-6692028cad5f Duration: 682.01 ms Billed Duration: 683 ms Memory Size: 128 MB Max Memory Used: 68 MB Request ID 45ad5172-4e9e-4a7e-8bf9-6692028cad5f DBの起動 Test Event Name start-db1 Response null Function Logs START RequestId: cbb0861c-31e6-46a7-a120-dface73a52e4 Version: $LATEST postgres-db is stopped now started your instance: postgres-db END RequestId: cbb0861c-31e6-46a7-a120-dface73a52e4 REPORT RequestId: cbb0861c-31e6-46a7-a120-dface73a52e4 Duration: 714.55 ms Billed Duration: 715 ms Memory Size: 128 MB Max Memory Used: 67 MB Request ID cbb0861c-31e6-46a7-a120-dface73a52e4 EventBridge による自動実行 Amazon EventBridgeはジョブスケジューラのように利用できる製品です。定時実行する場合はルールと呼ばれるジョブネットのようなものを作成して、そこに実行したい処理を乗せることができます。 EventBridgeの画面でルールを新規作成します ルール名を入力します。例:Start-RDS パターンは[スケジュール]-[cron式]を選択して、毎日朝8時に起動するように0 23 ? * * *と設定しました。ここは日時をGMTで設定するので分かりづらいですが入力した後にローカルタイムで今後の起動スケジュールが表示されるので想定通りに動くか確認できます。 ターゲットを作成します。 ターゲットの種類は[Lambda関数]を選択します。 機能で先ほど作成したLambda関数を選択します。 入力の設定でJSON形式で引数を渡すことができます。 {"Action": "Start", "Instance": "postgres-db"} ここでターゲットを追加できるので、引数だけ変えていくつものRDSを起動することも可能です。 必要ならタグを設定して[作成]ボタンで作成します。 同様に停止のルールも作成します。 おわりに RDSは少々オンプレやEC2で構築するのに比べて少々割高なイメージがありますが、利用しない時間に止めておくことでうまくペイできる可能性があると思いました。 参考文献
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSまとめ (IPアドレス)

・パブリックIPアドレス- TCP/IPというプロトコルでは通信先の特定にIPアドレス(ネットの住所みたいなもの)を使う。 このIPアドレスは32ビットで構成されるが、「192.168.1.2」のように8ビットずつ区切られたものを10進数に変換し、「.」で区切られた形で表されます。 ちなみに.内で区切られた数字は0~255までの数字で表され、このIPアドレスは重複しては住所の役割を全うしないのでICANNという団体が管理しています。 (しかし、このIPv4のアドレスの在庫が切れたので、新しく出たIPv6に移行するまではNATというIPアドレスを旧友できるシステムを開発したそうです。) ・プライベートアドレス プライベートアドレスとはネットに繋がれていないアドレスのことです。(社内の電話回線など) ・・CIDR表記 IPアドレスのネットワーク部のビット数をIPアドレスの末端につけたもの。 例: 192.168.1.2のIPアドレスがあったとして、この場合ネットワーク部(192.168.1を2進数に直すと24個の数字で表されるので、24ビット)の24という数字をIPアドレスの末端につけた「192.168.1.2/24」がCIDER表記となります。 そしてこのビットというのは2進数で表されるので2のn乗の数になります。 ・サブネットマスク表記 IPアドレスの.内の数字を2進数に直し、ネットワーク部は全て1とし、ホスト部はすべて0としたものがサブネット表記です。 サブネットマスク表記の例:192.168.0.0/255.255.0.0
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS】利用料金の詳細通知&自動化

はじめに この記事は NTT テクノクロス Advent Calendar 2021 の 3日目の記事です。 NTT テクノクロスの井上です。 普段は AWS 関連の業務をしています。 この記事では、 AWS の利用料金通知システム の作成についてご紹介します。 元々、AWS の利用料金を通知する Lambda を動かしていたのですが、 「今月の費用、予算内におさまりそう?」と尋ねられたり、 「どのサービスにいくら費用がかかっているのかも通知してほしい!」 などの要望があり、拡張機能を作成しました。 また、 最近 AWS へ移行するプロジェクトも増えてきたので、 これを機に料金通知システム作成の 自動化 を含めて、記事にまとめることにしました。 概要 通知内容は下記の4つです。 ・ 今月1日から前日までの請求額 ・ 今月1日から前日までの請求額の内訳(サービスごとの請求額) ・ 今月の予測請求額 ・ 前日1日分の利用額 通知内容は、今月1日から前日までの請求額 をデフォルトとして、 他3つは必要に応じて拡張ができるよう作成します。 拡張機能を使うと、 予算内におさまりそうか であったり、どのサービスに費用が集中しているのか が 可視化され、把握しやすくなるので、ぜひ取り入れてみてください。 目次 前提条件 構成 Lambda 関数のコード CloudFormation 通知の確認 1. 前提条件 Cost Explorer が有効化されている SNS トピック、サブスクリプションの設定が完了している 2. 構成 今回作成する機能の アーキテクチャ図 はこちらです。 CloudWatch Events で設定した cron をトリガーに、AWS 利用料金を取得・加工する Lambda を実行させ、SNS でメールを送信する流れとなります。 3. Lambda 関数のコード コードは、前日までの請求額を通知するメインファイル(index.py)と、その他拡張機能を持ったファイル(detail.py)の2つを作成します。 Lambda 関数は、後ほど CloudFormation で作成します。 index.py 前日までの請求額を通知する基本的なコード index.py import boto3 import os import time from datetime import datetime, timedelta, date import detail # 設定日時 def billing_date(): # 月初の日付取得 first_date = date.today().replace(day=1).isoformat() # 当日の日付取得 last_date = date.today().isoformat() # 今日が1日なら「先月1日から今月1日(今日)」までの範囲にする if first_date == last_date: last_month_last_date = datetime.strptime(first_date, '%Y-%m-%d') - timedelta(days=1) last_month_first_date = last_month_last_date.replace(day=1) first_date = last_month_first_date.strftime('%Y-%m-%d') return first_date, last_date # 請求額取得 def get_billing(ce): first_date, last_date = billing_date() response = ce.get_cost_and_usage( TimePeriod={ 'Start': first_date, 'End': last_date }, Granularity='MONTHLY', Metrics=[ 'AmortizedCost' ] ) return { 'start': response['ResultsByTime'][0]['TimePeriod']['Start'], 'end': response['ResultsByTime'][0]['TimePeriod']['End'], 'billing': response['ResultsByTime'][0]['Total']['AmortizedCost']['Amount'], } # メッセージ作成 def create_message(total_billing): total = round(float(total_billing['billing']), 2) sts = boto3.client('sts') id_info = sts.get_caller_identity() account_id = id_info['Account'] subject = f'利用料金:${total} AccountID:{account_id}' today = datetime.strptime(total_billing['end'], '%Y-%m-%d') yesterday = (today - timedelta(days=1)).strftime('%Y/%m/%d') message = [] message.append(f'【{yesterday}時点の請求額】\n ${total:.2f}') return subject, message # メッセージ送信 def send_message(subject, message_list): sns = boto3.client('sns') message = '\n'.join(message_list) retry_num = 3 for i in range(retry_num): try: response = sns.publish( TopicArn = os.environ['Topic'], Subject = subject, Message = message ) break # 送信失敗時は2秒後リトライ except Exception as e: print("送信に失敗しました。リトライ{}/{}".format(i+1, retry_num)) time.sleep(2) return response # main def lambda_handler(event, context): ce = boto3.client('ce') # 請求額取得 total_billing = get_billing(ce) # メッセージ作成 subject, message = create_message(total_billing) ## 拡張用 ## 今月の予測請求額取得 # message = detail.get_estimated_billing(ce, message) ## 1日の請求額(前日からの増加額) # message = detail.get_daily_billing(ce, total_billing, message) ## サービス毎の請求額 # message = detail.get_service_billings(ce, message) # メッセージ送信 send_message(subject, message) detail.py 請求額の内訳(サービスごとの請求額)、今月の予測請求額、前日1日分の利用額を通知する拡張用コード ※ 拡張機能を使用する場合は、下記に注意してください。 拡張する機能に応じて index.py の lambda_handler 内 対応箇所をコメントインする。 detail.py import index from datetime import timedelta, date from dateutil.relativedelta import relativedelta # 今月の予測請求額 def get_estimated_billing(ce, message): # 翌日から来月1日までを設定し予測請求額を取得 next_date = date.today() + timedelta(days=1) next_month = date.today() + relativedelta(months=1) next_month_first_date = next_month.replace(day=1) response = ce.get_cost_forecast( TimePeriod={ 'Start': str(next_date), 'End': str(next_month_first_date) }, Granularity='MONTHLY', Metric='UNBLENDED_COST' ) estimated_billing = round(float(response['Total']['Amount']), 2) # メッセージ追加 message.append(f'【今月の予測請求額】\n ${estimated_billing}') return message # 1日の請求額(前日からの増加額) def get_daily_billing(ce, today_billing, message): first_date = date.today().replace(day=1).isoformat() last_date = (date.today() - timedelta(days=1)).isoformat() # x月3日~月末のみ前日までの請求額を取得 if first_date < last_date: response = ce.get_cost_and_usage( TimePeriod={ 'Start': first_date, 'End': last_date }, Granularity='MONTHLY', Metrics=[ 'AmortizedCost' ] ) yesterday_billing = { 'start': response['ResultsByTime'][0]['TimePeriod']['Start'], 'end': response['ResultsByTime'][0]['TimePeriod']['End'], 'billing': response['ResultsByTime'][0]['Total']['AmortizedCost']['Amount'], } # 1日の請求額算出 daily_billing = round(float(today_billing['billing']) - float(yesterday_billing['billing']), 2) # メッセージ追加 message.append(f'【1日の請求額】\n ${daily_billing}') return message # サービス毎の請求額 def get_service_billings(ce, message): first_date, last_date = index.billing_date() response = ce.get_cost_and_usage( TimePeriod={ 'Start': first_date, 'End': last_date }, Granularity='MONTHLY', Metrics=[ 'AmortizedCost' ], GroupBy=[ { 'Type': 'DIMENSION', 'Key': 'SERVICE' } ] ) # サービス名とその請求額を取得 service_billings = [] for item in response['ResultsByTime'][0]['Groups']: service_billings.append({ 'service_name': item['Keys'][0], 'billing': item['Metrics']['AmortizedCost']['Amount'] }) # メッセージ追加 yesterday = (date.today() - timedelta(days=1)).strftime('%Y/%m/%d') message.append(f'\n【{yesterday}時点の請求額 内訳】') for item in service_billings: service_name = item['service_name'] billing = round(float(item['billing']), 2) # 請求額が$0の場合は内訳を表示しない if billing == 0.0: continue message.append(f' ・{service_name}: ${billing}') return message ※ 作成が完了したら、2ファイルを圧縮(zip化)し、S3 の任意のバケットに格納してください。 4. CloudFormation テンプレート IAM ロール、Lambda 関数、CloudWatch Events を作成するテンプレート Billing_template.yml AWSTemplateFormatVersion: '2010-09-09' Description: "Create Lambda to send billing information." Parameters: Bucketname: Type: String Description: S3Bucketname Filepass: Type: String Description: S3Filepass Topicarn: Type: String Description: SNSTopicarn Resources: BillingIamRole: Type: AWS::IAM::Role Properties: RoleName: Lambda-send-billing-role AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole ManagedPolicyArns: - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" Path: / Policies: - PolicyName: Lambda-send-billing-policy PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - ce:* - sns:CreateTopic - sns:Publish Resource: '*' BillingFunction: Type: AWS::Lambda::Function Properties: Code: S3Bucket: !Ref Bucketname S3Key: !Ref Filepass Description: 'send billing information' FunctionName: 'send-billing-info' Handler: 'index.lambda_handler' Runtime: 'python3.8' Timeout: 30 Environment: Variables: Topic: !Ref Topicarn Role: !GetAtt - BillingIamRole - Arn ScheduledRule: Type: AWS::Events::Rule Properties: Description: "ScheduledRule" ScheduleExpression: 'cron(0 0 * * ? *)' State: ENABLED Targets: - Arn: !GetAtt - 'BillingFunction' - 'Arn' Id: 'TargetFunctionV1' PermissionForEventsToInvokeLambda: Type: AWS::Lambda::Permission Properties: FunctionName: !Ref "BillingFunction" Action: "lambda:InvokeFunction" Principal: "events.amazonaws.com" SourceArn: Fn::GetAtt: - "ScheduledRule" - "Arn" スタック作成 AWS マネジメントコンソールから CloudFormation を選択 [スタックの作成] から [新しいリソースを使用(標準)] を選択 テンプレートの指定 下部 [ファイルの選択] から先ほど作成した yaml ファイルを選択後、[次へ] を押下 スタックの詳細を指定 [Bucketname] :Lambda 関数で実行する zip ファイルを格納したバケット名 [Filepass] :zip ファイルまでのファイルパス [Topicarn] :SNS トピックの ARN 全ての項目を入力したら、[次へ] を押下 スタックオプションは特に設定せず、[次へ] を押下 レビュー(最終確認) 入力したものの誤りがないかを確認し、チェックボックスの内容を承認した後、[スタックの作成] を押下 ※ スタックが作成されるまでに数分かかります。 これで、CloudFormation を使った、AWS 利用料金通知機構の作成は完了です。 5. 通知の確認 CloudFormation テンプレート内の cron 設定日時に 00:00(GMT) を設定した場合、 日本時間 09:00 にメールが届きます。 ※ 変更を加えていなければ 00:00(GMT) です。 通知例 拡張機能を全て使用した場合、このようなメールが届きます。 さいごに 料金通知自体はすでにされている方も多いと思います。 実際、サービスごとの請求額も今月の予測請求額も、マネコンからぽちぽちしていくと確認できます。 なので、今回紹介した方法は、 毎日料金の詳細を確認したい方におすすめできる内容となります。 少しでも参考にしていただけたら嬉しいです。 では、NTTテクノクロス Advent Calendar 2021 の 4日目も、お楽しみください! 参考 AWS利用金額と予測請求金額を日次で自動通知する - Qiita AWSサービス毎の請求額を毎日Slackに通知してみた - Developers.IO
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS SAAの個人的な勉強方法

AWS SAAを昨年3月に取得しました。その際の勉強方法について記載します。 クラウドを知りたいと思い、1年位だらだらと勉強はしていたのですが2回の不合格を経験し、一念発起して取り組みました。 結果3ヶ月で過去の1年間を無かったことにするくらいの知識を身につけられました。 勉強教材リスト Udemy AWS 認定ソリューションアーキテクト アソシエイト模擬試験問題集(6回分390問) ブラックフライデーセール時に1,200円くらいで購入しました。 この問題集は特に難しくSAPの範囲も余裕で出てくるし、複数選択問題の割合が多く不正解になりやすいです。初回は正解率30%位しか取れませんでした。 しかし、演習テストをしていくうちに問題の勘所や何が足りないのかを掴めていけるので、めちゃくちゃ力が付きます。演習テストは全6回あり、それぞれ3周ぐらいしたところで、正解率がほぼ75%超えることが出来ました。 実際の試験もこの問題集レベルが出てくると思っていたのに、出てこず逆にこれでいいの?となるくらいでした。 実務ではSAA試験範囲外の仕事を振られることも多くあるので、やっておいて損はないです。 私は実務中に "これUdemyでやったとこだ" ってなってました。 対策本 徹底攻略 AWS認定 ソリューションアーキテクト − アソシエイト教科書 試験受けるぞと思った時に購入しました。1通り読んで、付属の模擬問題を解いてました。模擬問題は実際の試験よりも優しい印象です。この本だけだと試験時に分からない単語が出てくると思います。 AWS BlackBelt AWS サービス別資料 試験要項を読みSAA対象サービスのスライドを読みました。電車通勤時は立ちっぱで、本が出せないのでスマホにPDFを入れて読んでました。(2021/11/26現在: 徹底攻略の電子書籍版も出ているようです) サービスの概要だけでなく最新のアップデートもあり情報収集にも役立ちました。 やったこと ●勉強時間にコストをかける 家での勉強だとすぐにスマホに手が伸びてしまうので、無駄な時間ばかり過ごしてました。なので、家では勉強しないと割り切り、外で勉強するようにしました。その際、必ず飲み物を購入してました。 購入=コスト=財布ダメージとなるので、時間に対する費用を無意識に刻み、集中力にブーストをかけてました。 昨今のウイルス事情で外出が難しいときもありますが、個人的にはめちゃくちゃおすすめです。 ●紙とペン 私は読むだけではすぐに抜けてしまうので、手を動かして勉強しています。また、問題文が無駄に長いので要約の練習にもなりました。 手書きゆえに1問にかける時間がかかってしまいますが、個人的にはベストな方法でした。 ●1問でも取り組めたら最強 自分を徹底的に甘やかします。仕事の帰りが遅い時、子どもがなかなか寝てくれない時、家事が溜まっている時、etc... 勉強時間が取れないことはよくあります。しかし、継続は力なりです。毎日1問もしくは問題を読むだけでも確実に力はついて行きます。辞めなければ正義です。 ●合格記事は見ない Twitter、Qiita、etc...には "勉強○日で合格" とか "〜に合格して○冠達成" みたいな投稿があります。私はこういう投稿を見ると "自分がもっと出来たる人だったら" とネガティブに考えてしまうので、シャットダウンするようにしています。不合格時は特にすごく落ち込むので普段から切り離しておくのがベターです。 おわりに たとえ不合格となっても正解率分の知識は身についています。継続は力なりです! 頑張りましょう! 参考 コーヒー代 - マクドナルド: Sサイズ 100円 - ドトールコーヒー: ホットS 224円 - スターバックス: ドリップ Short 319円 - ペットボトル(自販機): 160円
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ベクトルタイルを使って星の海を探検する

ガイア計画というものを知りました。 欧州宇宙機関 (ESA) が打ち上げた専用の探査機で全天球の天体を観測してデータを蓄積するプロジェクトで、現在のデータ量は1.8TB、観測された天体の数は約1,900億個だそうです。このデータを利用して全天球の星の地図を作ってみました。  データのダウンロード ガイア計画のデータは以下でアーカイブされていて、自由に利用できます。日本にもミラーサイトがあり国立天文台のウェブサイト jvo.nao.ac.jp からデータをダウンロードできます。今回は作業時点で最も新しい EDR3 (Early Data Research 3) を使いました。 なお、データの利用にあたっては所定のクレジットを併記する必要があり、専用ページで確認できます。 データの加工 GAIA データは gzip 圧縮された単純な CSV としてダウンロードできます。データには天球上での星の位置が含まれていて、それは黄道面を基準に黄経(ecl_lon)、黄緯(ecl_lat)として与えられているようです。今回は web 地図の上に天球を投影しようと思いましたので、赤道面を基準にした位置情報(赤経・赤緯)に変換しました。 この変換は単純な球座標上での回転移動とみなして以下の1次変換でOKということにしました。赤経をα、赤緯をβ、黄経δ、黄緯をγ、黄道傾斜角(地球の自転軸の傾き)をεとすると、以下の連立方程式で (δ, γ) から (α, β) が計算できるはずです。左辺は赤道面を基準にしたxyz座標、右辺は回転行列と黄道面を基準にしたxyz座標の積です。 \begin{eqnarray*} \left( \begin{array}{c} \cos\beta\cos\alpha \\ \cos\beta\sin\alpha \\ \sin\beta \\ \end{array} \right) =\left( \begin{array}{ccc} 1 & 0 & 0 \\ 0 & \cos\epsilon & -\sin\epsilon \\ 0 & \sin\epsilon & \cos\epsilon \\ \end{array} \right) \left( \begin{array}{c} \cos\delta\cos\gamma \\ \cos\delta\sin\gamma \\ \sin\delta \\ \end{array} \right) \end{eqnarray*} これを解くと、 \begin{equation} \alpha=\mathrm{tan}^{-1}\frac{\cos\epsilon\cos\delta\sin\gamma-\sin\epsilon\sin\delta}{\cos\delta\cos\gamma} \end{equation} \begin{equation} \beta=\mathrm{sin}^{-1}(\sin\epsilon\cos\delta\sin\gamma+\cos\epsilon\sin\delta) \end{equation} なお、今回は簡便に黄道傾斜角(地球の自転軸の傾き)として ε = 23.4° を使いました。 注意 結果として後述しますが、この射影変換が間違っているようで、意図した通り天球が平面に展開されませんでした。この件は別途検証しようと思います。 ベクトルタイルの生成 データが次のフォーマットの順に加工されるようにパイプして mbtiles を生成します。 1. csv.gz // 元データ。gzip 圧縮された csv 2. csv // csv 3. GeoJSON // 位置情報フォーマット 4. NDGeoJSONs // 3 を 改行区切りで結合したもの 5. mbtiles // ベクトルタイル 今回は 2 の csv から 3 のGeoJSON を生成するする単純なストリームの処理のみを自作しました。csv のカラムには例えば phot_g_mean_mag のような等級(星の明るさ)などの膨大な観測データがあるのですが、地学の素養がなくデータの意味を十分に理解できませんでした..。このストリームでは、 phot_g_mean_mag は m プロパティとして保存しています。この値は結局使いませんでした。 // bin/build.js const csv = require('csv-parser') // 定数と計算用ユーティリティ const ECL_INC = 23.4 const ang2rad = (ang) => ang * Math.PI / 180 const rad2ang = (rad) => 180 * rad / Math.PI const sin = (ang) => Math.sin(ang2rad(ang)) const cos = (ang) => Math.cos(ang2rad(ang)) const atan = (rad) => rad2ang(Math.atan(rad)) const asin = (rad) => rad2ang(Math.asin(rad)) // 黄道 -> 赤道の座標変換 const ecl2eq = ([lng, lat]) => { const eq_lng = atan(cos(lng) * cos(lat) / (cos(ECL_INC) * cos(lng) * sin(lat) - sin(ECL_INC) * sin(lng))) const eq_lat = asin(sin(ECL_INC) * cos(lng) * sin(lat) + cos(ECL_INC) * sin(lng)) return [eq_lng, eq_lat] } process.stdin .pipe(csv()) .on('data', (chunk) => { const { ecl_lon, ecl_lat, phot_g_mean_mag } = chunk const m = parseFloat(phot_g_mean_mag) const ecl_coord = [parseFloat(ecl_lon), parseFloat(ecl_lat)] if(!ecl_coord[0] || !ecl_coord[1] !m) { return } try { const eq_coord = ecl2eq(ecl_coord); const feature = { type: 'Feature', properties: { m }, geometry: { type: 'Point', coordinates: eq_coord }, } process.stdout.write(JSON.stringify(feature) + '\n') } catch (error) { process.stderr.write(`[failure] ${JSON.stringify(error)}\n`) } }) tippeacanoe は標準入力をサポートしているので、例えば以下のようなコマンドで簡単に mbtiles を生成できます。1つのファイルあたりに約50万個〜90万個ほどの星のデータが入っているようです。 $ find ~/Downloads/GaiaSource_*.csv.gz | \ xargs -I {} sh -c "cat {} | gunzip | node bin/build.js" | \ tippecanoe -zg -o gaia.mbtiles --drop-densest-as-needed なお、実際には S3 にダウンロードしたデータを用いて以下のようなコマンドで複数に分けて処理しました。 # NUMBER_PREFIX は 0 から 7 $ aws s3api list-objects --bucket $GAIA_DOWNLOAD_BUCKET_NAME | \ jq .Contents | jq -r 'map(.Key)[]' | \ grep "GaiaSource_$NUMBER_PREFIX" | \ xargs -t -I {} sh -c "aws s3 cp s3://$GAIA_DOWNLOAD_BUCKET_NAME/{} - | gunzip | node bin/build.js" | \ tippecanoe -zg -o gaia$NUMBER_PREFIX.mbtiles -l gaia --drop-densest-as-needed 生成した 8 つの mbtiles は tippeacanoe の tile-join コマンドで結合します。 $ tile-join -o gaia.mbtiles \ gaia0.mbtiles \ gaia1.mbtiles \ gaia2.mbtiles \ gaia3.mbtiles \ gaia4.mbtiles \ gaia5.mbtiles \ gaia6.mbtiles \ gaia7.mbtiles --no-tile-size-limit ベクトルタイルをホストする tileserver-gl でベクトルタイルを配信します。以下のコマンドで http://localhost:8080/data/gaia.json からベクトルタイルが利用できるようになります。 $ nvm use v10 $ npx tileserver-gl ./gaia.mbtiles ベクトルタイルをレンダリングする タイルを読み込んでレンダリングするための html とスタイルを作成します。 私が属している Geolonia の Embed API を使うと mapboxgl/maplibregl と互換の Map クラスを利用できます。URL に緯度経度をシリアライズする data-hash="on" などの属性が使えるので便利です。 <html> <head> <style> html, body, #map { width: 100%; height: 100%; margin: 0; padding: 0; } </style> </head> <body> <div id="map" data-hash="on"></div> <script src="https://cdn.geolonia.com/v1/embed?geolonia-api-key=YOUR-API-KEY"></script> <script> new window.geolonia.Map({ container: document.getElementById('map'), style: { version: 8, sources: { gaia: { type: 'vector', url: 'http://localhost:8080/data/gaia.json', }, }, layers: [ { id: 'background', type: 'background', paint: { 'background-color': "black" } }, { id: 'stars', type: 'circle', source: 'gaia', 'source-layer': 'gaia', paint: { 'circle-color': '#ffffff', 'circle-radius': 1 } } ] } }) </script> </body> </html> 結果と考察 3,384個、613GB の GZIP ​されたCSV から8つの mbtiles を生成するのに、 AWS EC2 の t3.2xlarge インスタンスを使った処理で概ね24時間かかりました。全ての mbtiles を結合したデータのサイズは 13.5 GB でした。 星の海を探検してみる どうも射影変換が間違っているようで、 -45° から + 45°の範囲にしか星が分布しませんでした。ただ全単射ではありますので、このまま星の分布を眺めたいと思います。 北緯66°と南緯66°付近に集まるラグビーボールの縫い目のような線が出現しました。66°というのはおそらく 90° から黄道傾斜角を引いた値からくるもので、線は8つに分割したデータを tile-join することで出現しているもののように思えます。 ところどころ不自然な角張を持つ疎な領域や密な領域があります。これは元データの欠損や重複に由来しているもののように見えます。 星の集まった銀河のような構造も見えます。 星の密度が薄い場所があります。これは暗黒物質でしょうか。 まとめ 今回使った Gaia EDR3 のようなテラバイト級のデータを手軽にブラウジングするのは大変です。
解決方法として、ベクトルタイルで逐次データをロードできるようにするのは有効なのではないでしょうか。 この記事に関連するソースは以下にあります。 謝辞 This work has made use of data from the European Space Agency (ESA) mission Gaia, processed by the Gaia Data Processing and Analysis Consortium (DPAC). Funding for the DPAC has been provided by national institutions, in particular the institutions participating in the Gaia Multilateral Agreement. このエントリでは、欧州宇宙機関(ESA)のミッション Gaia のデータを利用しており、これは、 Gaia Data Processing and Analysis Consortium (DPAC) が処理を行なったものです。 DPAC への資金は、各国の機関、特に Gaia Multilateral Agreement に参加している機関から提供されています。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MWAA での環境変数設定パターン

設定パターン 網羅的ではないですが、複数あります。以下の5つを試したり紹介だけだったりしていきたいと思います。 ①Airflow UIで設定(GUI) ②DAG内で設定 ③airflow.cfgで設定(マネコン & CLI) ④airflow cliで設定 ⑤Secrets Managerに全振り ①Airflow UIで設定 Airflow UIでの環境変数設定を見ていきます。Airflow UIでのGUI操作になります。 手順 Airflow UIを開き、上部の[Admin]にカーソルを当て、[Variables]をクリック 左下の[+]ボタンをクリックします Key/Valueの形式で入力します。ここではfoo/barを入れました。左下の[Save]をクリックします。 foo/barの環境変数が出来ました。 エクスポート/インポートも出来ます。作成した環境変数にチェックを入れエクスポートします エクスポートしたファイルの中身はこんな感じ variables.json { "foo": "bar" } 環境変数を画面で削除し、エクスポートしたファイルをインポートします。 元のfoo/barが戻ります まとめ GUIでよければ一番手軽です。エクスポート・インポートも出来るし。GUI操作なので自動化は出来ない ②DAG内で設定 環境変数設定のDAGを作っちゃうパターン。 手順 環境変数を書いたJSONファイルを用意します。 variables.json { "red": "liver", "white": "real" } DAGファイルを作成します。 setvar.py import airflow from airflow.models import DAG from airflow.operators.python import PythonOperator import os from airflow.models import Variable import json args = { "owner": "airflow", "start_date": airflow.utils.dates.days_ago(1), "provide_context": False, "email_on_failure": True, "email_on_retry": True, "retries":1, "retry_delay":120 } def setvar_modules(): print("Starting here") with open('/usr/local/airflow/dags/variables.json') as f: data = json.load(f) for key in data: print(key, '->', data[key]) variable = Variable.set(key, data[key]) print("Debugging here") for key in data: print(key, '->', data[key]) variable = Variable.get(key) with DAG( dag_id="set_variables_job", description="set variables DAG", default_args=args, schedule_interval="*/60 * * * *", catchup=False, tags=['setenv'] ) as dag: t1 = PythonOperator( task_id='setvar_task', python_callable=setvar_modules, dag=dag ) t1 JSONファイルとDAGファイルの2つをS3のDAGフォルダにアップします。 数分するとAirflow UIにset_variables_jobのDAGが表示されます。 DAGは最初Pause状態なので、DAG名の左のつまみをクリックしUnpauseします。そうすると自動で実行されます。 次にDAG名をクリックして詳細を確認します。 [Graph View]をクリックし、真ん中の[setvar_task]をクリック この画面が出るので[Log]をクリック ログの表示から環境変数が設定されてることが分かります。variable.getで確認もしてるのでsetした変数がgetできてます Admin->Variablesで確認 設定した環境変数が表示されています まとめ 環境変数セットアップ用のDAGを作るパターンは良いんじゃないかと思います。 環境変数セットのロジックを切り出せてるので、環境変数の設定や修正時は環境変数のJSONとDAGだけ修正すれば良くて、ビジネスロジック側に手を入れなくて済みます。 本来のDAGではないDAGが作られるのがどうかな?とは思いますが、DAGであるので逆に管理運用はしやすいと思う。 ③airflow.cfgで設定(マネコン & CLI) airflow.cfgにカスタムな環境変数を書けます。MWAAでそれを行うやり方。 GUI手順 MWAAの環境の編集で、Airflow設定オプションを追加しましす。ここで入れた値はairflow.cfgに反映されます。 入力した値は、custom.envval/helloworld です 確認のためカスタム環境変数を表示するDAGを作ってS3にアップします。 確認用のDAGなので本来は不要なDAGです。 getvar.py import boto3 import airflow from airflow.models import DAG from airflow.operators.python import PythonOperator from airflow.providers.amazon.aws.operators.athena import AWSAthenaOperator from airflow.utils.task_group import TaskGroup import os args = { "owner": "airflow", "start_date": airflow.utils.dates.days_ago(1), "provide_context": False, "email_on_failure": True, "email_on_retry": True, "retries":1, "retry_delay":120 } def getvar_module(): words = os.getenv("AIRFLOW__CUSTOM__ENVVAL") print("Debugging here") print (words) with DAG( dag_id="get_variables_job2", description="get variables from airflow.cfg DAG", default_args=args, schedule_interval="*/60 * * * *", catchup=False, tags=['getenv'] ) as dag: t1 = PythonOperator(task_id="get_variables_task", python_callable=getvar_module) t1 Airflow UIでDAGをunpauseして実行します。 DAG名をクリックします [Graph View]で表示します ログを確認します。airflow.cfgで設定したカスタム環境変数のhelloworldが表示されてます CLI手順 今回は試しませんが、MWAAの環境作成時に"airflow-configuration-options"で環境変数を設定できそうです。 aws mwaa create-environment --airflow-configuration-options {"custom.envval":"helloworld"} まとめ DAGに環境変数の記述をしないという意味では一番キレイでシンプルだと思います。 ただ、Airflow UIのVariablesに表示されないため可視性は低めかもしれません。見通しがいいという意味だとVariablesに表示されるといいなと思います。でも、どのみちVariablesを直接操作しないならそこまでデメリットではないかもです あと、airflow.cfgに書く場合は「AIRFLOW_CUSTOM_ENVVAL」みたいな書式に従う必要があります。 それと、最大のデメリットがairflow.cfgの修正にはMWAA側の反映にかなり時間が掛ります。手元では10分くらい掛りますた、公式Docには「数分かかる」とあります。よって、時々レベルの頻度で更新が入ったり、更新してすぐに試したい環境変数はなるべくairflow.cfgと切り離した方がいいと思います。 ④Airflow CLI 2.0.2からできるっぽいですね。サンプルコードもありました Airflowの公式Doc的にはこちらのコマンドです airflow variables get [-h] [-d VAL] [-j] [-v] key まとめ 試してないですmm 試してないのに感想ですが、CLIなのでCLI実行環境が必要なので、手頃なコンピューティングがあれば良いいかなと。 Airflowとは別な環境で管理する形になるので、実行環境といい感じに疎結合になったバッチサーバーみたいな基盤があれば良さそう AirflowはAirflowでまとめたいなら前述の手段がいいかも。Airflowでまとめなくてもいいのだけど。 ⑤Secrets Manager全振り 環境変数の保存先にSecrets Managerも使えます。本来は秘匿性が高いDB接続情報(ID/Passwordなど)を保存することに使うAWSのナイスIntegrationですが、環境変数の保存先にも使えます ※注意点は、前述のvariables.getではMWAA(Airflow)のメタストア(MWAA内部のRDS)に保存された値を取得しますが、SecretsManagerを保存先にした場合は、variables.getでSecretsManagerに保存された値を取得します。キーが被っている場合はSecretsManagerが優先されそうです。 英語ですがこちらのブログにこの辺含めて、MWAA+SecretsManagerをすごく丁寧に検証してるので是非ご確認ください。 MWAAでSecrets Managerを使う設定はこちら サンプルコードはこちらですが、variable.getを使う点では②とほとんど同じ感じです。 variable.setはSecrets Managerへの設定操作ということになりますね。 まとめ 試してないですmm 環境変数を入れ先としてはAWSらしい疎結合で、可視性と操作性もいいと思います。Secretでない値を入れるのに若干違和感ありますが、公式ドキュメントにも環境変数の設定手順とあるので利用用途してはアリだと思います。 デメリットとしては、Secrets Manager側にも若干ですがコストがかかる点があるかもしれません。 あと、Airflowで完結したい場合は、別サービスであるSecrets Managerが登場してきてしまいます。ただ、いい感じの結合度なのでmake senseだと思います。 全体まとめ 個人的には「⑤Secrets Manager全振り」でいいと思います(試してないのに一番お勧めmm)。「①環境変数設定DAGにするパターン」もユースケースによってはマッチしそうです。DAGに慣れてれば扱いやすいしMWAAで完結できますね。ほとんど変更がない環境変数であれば「②airflow.cfgで設定」も良いと思います。 参考リンク Airflow 公式Doc: Managing Variables AWS CLI: MWAA CLI MWAA Secrets Manager Integration Airflow CLI: Variables set MWAAでのAirflow CLI
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS SAM ローカルでいろんな角度からhello worldする

やりたいこと サーバーレスな処理を実装するのに備えて、ひとまずSAMを使ってローカル環境にてブラウザやcurlコマンドでhello worldをしたいです。 $ sam --version SAM CLI, version 1.22.0 実装! sam initする sam initして、プロジェクトを新規作成します。 SAMからの質問に対して、下のように答えました。 template: AWS Quick Start Templates package: type: Zip (artifact is a zip uploaded to S3) runtime: ruby2.7 Project name [sam-app]: identify_user quick start application templates: Hello World Example ↓(参考)上記の詳細、質疑応答の全貌。 $ sam init Which template source would you like to use? 1 - AWS Quick Start Templates 2 - Custom Template Location Choice: 1 What package type would you like to use? 1 - Zip (artifact is a zip uploaded to S3) 2 - Image (artifact is an image uploaded to an ECR image repository) Package type: 1 Which runtime would you like to use? 1 - nodejs14.x 2 - python3.8 3 - ruby2.7 4 - go1.x 5 - java11 6 - dotnetcore3.1 7 - nodejs12.x 8 - nodejs10.x 9 - python3.7 10 - python3.6 11 - python2.7 12 - ruby2.5 13 - java8.al2 14 - java8 15 - dotnetcore2.1 Runtime: 3 Project name [sam-app]: identify_user AWS quick start application templates: 1 - Hello World Example 2 - Step Functions Sample App (Stock Trader) Template selection: 1 ----------------------- Generating application: ----------------------- Name: identify_user Runtime: ruby2.7 Dependency Manager: bundler Application Template: hello-world Output Directory: . Next steps can be found in the README file at ./identify_user/README.md Lambdaとtemplate.yamlを編集 Hello worldするためのLambdaとtemplate.yamlを整えます。 この後、AWS Rekognitionで顔認証するという個人的な事情で、LambdaはIdentifyUserFunctionという関数名にしました。 app.rb require 'json' def lambda_handler(event:, context:) message = 'hello world' { statusCode: 200, body: { message: message }.to_json } end template.yaml AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > identify_user Sample SAM Template for identify_user Globals: Function: Runtime: ruby2.7 Timeout: 30 Resources: IdentifyUserFunction: Type: AWS::Serverless::Function Properties: CodeUri: identify_user/ Handler: app.lambda_handler Runtime: ruby2.7 Events: IdentifyUser: Type: Api Properties: Path: /identify_user Method: get ローカルで動作確認 SAMのサーバーをローカルで起動します。(そう、サーバーレスなのに。) ポート番号は指定しないと3000になるのですが、僕の場合はRailsサーバーを3000で動かしていたので、-p 3001とオプションで3001を指定。 sam local start-api -p 3001 ブラウザで動作確認 ブラウザでhttp://127.0.0.1:3001/identify_userにアクセス。 { message: "hello world" } ↑うまく行くとブラウザにこう表示されます。 { message: "Missing Authentication Token" } ↑なんか間違えているとこんなのが帰ってきます。 例えばtemplate.yamlにてLambdaがmethod: postになってるとか curlで動作確認 curlとは?client for urlの略らしいです。 公式? https://curl.se/ e-words https://e-words.jp/w/CURL.html 次にcurlでパラメーターを渡してAPIを呼び出しても、きちんと動作するかを確認していきます。 が、まずはとりまパラーメーター無しでGETでcurlを実行してみます。 とりまパラメーター無しでcurlでhello world curl -X GET http://127.0.0.1:3001/identify_user // {"message":"hello world"}% きちんと返ってきました! 末尾の%がよくわからんが、まぁいいか。。 いよいよcurlでパラメーターを渡してhello world ここでは、メソッドをPOSTに変更します。 なんかよくわからないけど、自分のメモにunixtimeも残ってたのでそれも渡してみます。 app.rb require 'json' def lambda_handler(event:, context:) # 追加。パラーメーターを取得する params = JSON.parse(event['body'], symbolize_names: true) { statusCode: 200, body: { message: params[:message], unixtime: params[:unixtime] }.to_json } end template.yaml Resources: UpdateAttendanceResultFunction: Type: AWS::Serverless::Function Properties: (中略) Events: HelloWorld: Type: Api Properties: Path: /hello_world Method: post # ここをちゃんと変更! で、実行。 curl -X POST --data '{"message":"hello world", "unixtime": 1634532494}' http://127.0.0.1:3001/identify_user // {"message":"hello world","unixtime":1634532494}% きちんと返してくれています。 ちなみにここまでローカルで確認するだけなら、sam deployはもちろん、sam buildも必要ないです。 最後に これはサーバーレスにRekognitionに問い合わせをするという自分の過去の課題のSAM部分です。 Rekognition部分に関しては、弊社ブログにまとめました↓
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSのssmのポートフォワードを並列稼動で起動する。

AWSのEC2を開発機として利用しているが、ssmで接続に慣れてくると、鍵をできるだけ使いたくない。できるだけIPを考えたくない。ポートフォワードで、接続できると良いとなってきた。 asis aws ssm start-session --target i-0dhogehogec26 --profile tanigawa.rei --document-name AWS-StartPortForwardingSession --parameters "portNumber=22,localPortNumber=50022 ssh -i ~/.ssh/key/tanigawa-rei-development.pem ec2-user@127.0.0.1 -p 50022 -N -L 8000:localhost:8000 -L 33306:localhost:33306 -L 9000:localhost:9000 -L 9090:localhost:9090 -L 15808:localhost:15808 `` ssmのポートフォワードでは、複数ポートの指定ができなかったので、ssmでsshポートだけあけて、sshコマンドでやっていた。ひとつひとつウインドウ開いて、セッション貼るのが面倒だった。鍵を使うのも面倒だった。 tobe スクリプトを作ることにした。非同期で、ssmのポートフォワードコマンドを叩く reita@antares:/mnt/c/Users/tanigawa.rei$ cat ./port-forward.sh aws ssm start-session --target i-0dhogehogec26 --profile tanigawa.rei --document-name AWS-StartPortForwardingSession --parameters "portNumber=22,localPortNumber=50022" & aws ssm start-session --target i-0dhogehogec26 --profile tanigawa.rei --document-name AWS-StartPortForwardingSession --parameters "portNumber=8000,localPortNumber=8000" & aws ssm start-session --target i-0dhogehogec26 --profile tanigawa.rei --document-name AWS-StartPortForwardingSession --parameters "portNumber=33306,localPortNumber=33306" & aws ssm start-session --target i-0dhogehogec26 --profile tanigawa.rei --document-name AWS-StartPortForwardingSession --parameters "portNumber=9000,localPortNumber=9000" & aws ssm start-session --target i-0dhogehogec26 --profile tanigawa.rei --document-name AWS-StartPortForwardingSession --parameters "portNumber=9090,localPortNumber=9090" & aws ssm start-session --target i-0dhogehogec26 --profile tanigawa.rei --document-name AWS-StartPortForwardingSession --parameters "portNumber=15808,localPortNumber=15808" & reita@antares:/mnt/c/Users/tanigawa.rei$ ./port-forward.sh Starting session with SessionId: tanigawa.rei-029810fec20da552d Starting session with SessionId: tanigawa.rei-06a4566ef1b1a7ade Starting session with SessionId: tanigawa.rei-0dd66dce67dc95395 Starting session with SessionId: tanigawa.rei-07f0a13ce927c9c42 Starting session with SessionId: tanigawa.rei-001ef0b6bbd275e15 Starting session with SessionId: tanigawa.rei-07917d08a0f0a05e6 Port 33306 opened for sessionId tanigawa.rei-029810fec20da552d. Waiting for connections... Port 50022 opened for sessionId tanigawa.rei-0dd66dce67dc95395. Waiting for connections... Port 9090 opened for sessionId tanigawa.rei-06a4566ef1b1a7ade. Waiting for connections... Port 9000 opened for sessionId tanigawa.rei-07f0a13ce927c9c42. Waiting for connections... Port 8000 opened for sessionId tanigawa.rei-001ef0b6bbd275e15. Waiting for connections... Port 15808 opened for sessionId tanigawa.rei-07917d08a0f0a05e6. Waiting for connections...
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

EKSのバージョンの「サポート終了」についてちゃんと調べてみた

背景 業務でEKSを扱っていて、ふと生じた疑問について調べてみました。 今回参考にしたドキュメント EKSの「サポート終了」とは? K8sは成長途中の技術であるためバージョンのアップデートが早く、約3ヶ月に1度のペースで新しいマイナーバージョンがリリースされています。 それに伴いAWS上のEKSクラスターもデプロイしたらしっぱなしではなく、運用しながら手動アップグレードし続ける必要があります。ドキュメントでは、 各マイナーバージョンは、最初にリリースされてから約 12 か月間サポートされます と書かれており、これ以降で下記の終了日を超えるとそのバージョンは「サポート終了」となります。 ここで、以下の疑問がわきました。 EKSの「サポート終了」ってどういう意味なんだろう?? OSやソフトではの「サポート終了」 = 「それ以降も使い続けることはできるけど、セキュリティアップデートや不具合時の問い合わせが提供されなくなり、自己責任での運用になる」 とざっくり理解しています。 EKSでも、同じようにAWSサポートへの問い合わせができなくなるって意味なのか? まさかサポート終了日過ぎたらPodが一気に停止してサービス停止に陥ったりしないよな… そこでこの疑問を晴らすべく、ちゃんと調べてみることにしました。 ただ大前提として、EKSクラスターはきちんと手動バージョンアップしてサポート終了日までほったらかしってことは無いようにしましょう。笑 セキュリティのためにもですし、便利なツールがどんどん導入されています。 サポート終了日が過ぎた時の挙動 EKSクラスターをデプロイした時のバージョンがサポート終了日を過ぎた場合の挙動は、コントロールプレーンとデータプレーンで違います。 1. コントロールプレーン こっちはドキュメントに明確に書かれています。 サポート終了日には、終了の対象となっているバージョンで新しい Amazon EKS クラスターを作成できなくなります。既存のコントロールプレーンは、Amazon EKS の段階的なデプロイプロセスを通じて、サポートされている最も古いバージョンに自動的に更新されます。 つまり、バージョン1.20でEKSクラスターを運用中の場合、1.20のサポート終了したらコントロールプレーンは自動的に(サポートされている最も古い)1.21にアップグレードされます。この自動バージョンアップのタイミングははっきり決まっておらず、AWS側で任意のタイミングで行われるようです。 2. データプレーン コントロールプレーンと違い、データプレーンは自動でアップグレードされないようです。 ただ、データプレーンの構築方法として、EC2/Fargateの2種類があります。ドキュメントにも分けて書かれていたので、ここでも以下で分けて説明します。 データプレーンの挙動を詳しく 1. データプレーンがEC2のとき EC2を使用した時は、マネージドノード型グループでも、セルフマネージド型ノードグループでもEC2は自動バージョンアップされないようです。 ドキュメント中の以下2項目で詳しく書かれています。 Q: Amazon EKS のマネージド型ノードグループは、クラスターのコントロールプレーンのバージョンとともに自動的に更新されますか? Q: セルフマネージド型ノードグループは、クラスタコントーロールプレーンのバージョンとともに自動的に更新されますか? 「だったらコントロールプレーンとバージョン差異が出たら互換性なくなって障害が起きるのか?」と一瞬不安になりましたが、マイナーバージョン2世代まではコントロールプレーンとデータプレーン間の互換性がサポートされているらしいです。なので、ある程度バッファはあります。(ずっと差異がある状態は推奨されていませんが) 最大 2 つ前のマイナーバージョンに対して、コントロールプレーンとノード間の互換性が確認されています。 実際にAWSサポートに問い合わせたところ、プレーン間で2世代以上の差異が出た場合はKubernetes自体の各コンポーネントが正常に動作しなくなり、EKS上で運用しているアプリケーションは意図せず中断する可能性はある。という旨の回答をもらいました。 結論として、 「EC2データプレーンはずっと手動バージョンアップせず放置すると、サービス中断のリスクがある。そのためデプロイ後もK8sのリリースに追随してアップデートを続ける必要がある。」 ということになります。 2. データプレーンがFargateのとき じゃあEKS on Fargateを使用した場合はどうなるのか?これもドキュメントに書かれています。 Q: クラスターコントロールプレーンのバージョンに対する自動アップグレードによって、Fargate で実行中のポッドも自動的にアップグレードされますか? ただ、これに対するAnswerが分かりづらく、自分の読解力では理解できませんでした…。 「自動でPod削除されて再スケジュールされる的に読めるから、自動バージョンアップされるのか?よくわからん…」 そこで、これもAWSサポートに問い合わせたところ、結局EC2のときと同様に自動バージョンアップはされず、手動バージョンアップが必要、という回答もらいました。 具体的な手順としては、Fargateノードで実行されているPodを再デプロイして、手動でワーカーノードのバージョンを更新します。  まとめ ○EKSクラスタを手動バージョンアップせず放置した場合 ・コントロールプレーンはAWS側で自動でバージョンアップされる。 ・データプレーンはEC2/Fargateいずれを使った場合でも、自動バージョンアップされない。 なので、データプレーンは手動バージョンアップが必ず必要 ○データプレーンをバージョンアップしなかった場合、最悪サービス中断に陥る恐れがある。(コントロールプレーンと2世代以上差異が出た場合) ○EKSクラスターはデプロイ後も放置せず、ちゃんと手動バージョンアップしてメンテナンスするようにしましょう。 今回参考にしたドキュメント
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Route53でS3にホスティングしたアプリケーションをCNAMEを使って任意のドメイン名でアプリを公開する

前提 ドメインをとってRoute53でホストゾーンを作成してあるものとする。 CNAMEとは 別名に対する正式名を指定するためのリソースレコードです。 ホスト名には、「canonical name(正式名)」以外に、「aliases(別名)」を付けることができます。DNSの名前解決では、CNAMEリソースレコードが見つかった場合、ドメイン名を正式名に置き換えて名前解決を継続します。ある別名に対する正式名は常に一つであるため、一つの別名に対し、正式名を二つ以上指定することはできません。 CNAMEリソースレコードは、以前はホスト名に別名を付ける手段として使われていました。現在では主にCDN (Contents Delivery Network)や、/24未満のIPv4アドレスの逆引きを設定する際に使われています。 別名は、例えば1台のサーバーで複数のサービスを提供している場合に、サービスごとにサーバーの名前を変えるときに使用します。サーバーの正式なドメイン名はservice.example.jpであるが、将来のことを考えて情報提供ではinfo.example.jpを、ショッピングではshop.example.jpというドメイン名で運用したいといったケースが該当します。この例のような場合、DNSではCNAMEリソースレコードを用いて以下のように定義できます。 引用:https://jprs.jp/glossary/index.php?ID=0212 つまり、Aレコードと関連づけて、その別名を登録することができる。 まずAレコードを作成する 使用したいドメインのホストゾーンを選択し、レコードを作成。 ウィザードに切り替えるを選択。 以降画像のように設定していく。 レコード名はなんでもOK。 値/トラフィックのルーティング先 の部分は選択していくと候補が現れていく。 これでレコードを定義するとレコード名でアクセスできる。 CNAMEレコードを作成する CNAMEとはcの部分の画像を見ればわかる通り、Aレコードのレコード名をCNAMEレコードの値にして新しくCNAMEレコードの名前をつければいい(S3のバケット名をつければいい)ので CNAMEレコードはこのように作成。 Aレコードの関連はこのようになっている。 するとCNAMEレコード名でアクセスできるようになる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

作成したアプリケーションをS3でホスティングしてインターネットに公開する

Nuxt.jsで作ったアプリをS3にホスティングする Nuxt.jsでの作業 こちらの本を参考に(というかまるっと引用)して簡単なアプリケーションを作成。 そして $ npm run generate でdistファイルを作る。 このファイルの中身を後でS3にアップロードする。 generaateはホスティングサービスにデプロイするとき、 build はNode.js サーバにデプロイするとき ように使い分ける。 参考:https://blog.mktia.com/diffrences-between-build-and-generate-in-nuxt/ AWS S3での作業 バケットを作成する 後でRoute53で time.moun.info で公開するために、今回はバケット名を time.moun.info として作成。 デフォルトではバケットは非公開なので公開にするために3つ設定を変更する。 1.静的ウェブサイトホスティング プロパティの一番下にある静的ウェブサイトホスティングを編集する。 画像のように設定。 インデックスドキュメントは、Nuxt.jsでgenerateしたdistフォルダの中のindex.htmlを表示させるのでその名前と同一でなければいけない。 2. ブロックパブリックアクセス (バケット設定) アクセス許可のブロックパブリックアクセス (バケット設定)を編集する。 パブリックアクセスをすべて ブロックのチェックを外す。 3. バケットポリシー アクセス許可のところにあるバケットポリシーを編集。 ポリシージェネレータをクリックすると下記のような画面が新しく開かれるので、この通りに設定する。 Amazon Resource Nameは、新しく開かれる前のAWSのページのバケットポリシーのバケットARN部分をコピペして /* を最後に追加。 Add Statement をクリックすると、もう少し下の方にGenerate Policy という部分が出てくるのでそこをクリック。 このようなコードが出てくるので全てコピーして、バケットポリシーのポリシー部分に貼り付けて変更する。 Nuxt.jsのアプリケーションをS3に入れる Nuxt.jsのdistフォルダの中身をドラッグしてS3の先ほど作ったバケットに貼り付ける。 貼り付けたファイルを全て選択し、アクションをクリックすると下の方にACL経由で公開と出てくるのでそれをクリック。 すると上記アドレスでアクセスできるようになる!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails] AWS SESのSMTPサーバを使う大まかな流れとSandboxを解除したやりとりの記録

Deviseのパスワード発行メールのように、返信を気にしないメールをサクッと飛ばしたい時がままあるので記事にしました。 Rails gem gem 'aws-sdk-rails' ActionMailer # config/initializers/aws.rb Aws::Rails.add_action_mailer_delivery_method( :ses, credentials: Aws::Credentials.new(ENV.fetch('AWS_ACCESS_KEY_ID') { 'AWS_ACCESS_KEY_ID' }, ENV.fetch('AWS_SECRET_ACCESS_KEY') { 'AWS_SECRET_ACCESS_KEY' }), region: 'ap-northeast-1' ) # config/environments/production.rb config.action_mailer.delivery_method = :ses AWS IAM ユーザグループにSESのPermission policy を追加する IAM > User groups SES ドメインの所有者確認とDKIM認証してもらう Amazon Simple Email Service Sandboxの解除リクエスト その後 リクエストの詳細確認の連絡が届いたので、回答したところ無事解除されました?(というか日本語でもよかったかも) Good day, thank you to confirm our request. We respond to enhance information. I wonder if you could look at that. Thanks. how often you send email: Less than 5 email a month. how you maintain your recipient lists: The administrator can regulate at the web site who will receive mail. your website or app(please include any necessary links): Website URL: https://www.example.com how you manage bounces, complaints, and unsubscribe requests: Only colleague obtains mail. If the member cannot receive a mail, who can ask the administrator. It is also helpful to provide examples of the email you plan to send so we can ensure that you are sending high-quality content: Subject: Reset password instructions Body: Hello <%= @resource.email %>! Someone has requested a link to change your password. You can do this through the link below. <%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %> If you didn't request this, please ignore this email. Your password won't change until you access the link above and create a new one. Hello, Thank you for submitting your request to increase your sending limits. We are unable to grant your request at this time because we do not have enough information about your use case. If you can provide additional information about how you plan to use Amazon SES , we may be able to grant your request. In your response, include as much detail as you can about your email-sending use case and how you intend to use Amazon SES. For example, tell us more about how often you send email, how you maintain your recipient lists, your website or app(please include any necessary links), and how you manage bounces, complaints, and unsubscribe requests. It is also helpful to provide examples of the email you plan to send so we can ensure that you are sending high-quality content. You can provide this information by replying to this message. Our team provides an initial response to your request within 24 hours. If we're able to do so, we'll grant your request within this 24-hour period. However, if we need to obtain additional information from you, it might take longer to resolve your request. Thank you for contacting Amazon Web Services. We value your feedback. Please share your experience by rating this correspondence using the AWS Support Center link at the end of this correspondence. Each correspondence can also be rated by selecting the stars in top right corner of each correspondence within the AWS Support Center. 参考になりました?
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LINE x SageMaker で背景切り抜きアプリつくった

はじめに LINExAWSでほげほげする回の続編です。これまで i. LINEでLambdaに画像を送信 ii. Rekognitionで顔情報の取得(表情判定) iii. SageMakerでセマンティックセグメンテーションモデル作成 をしてきました。今回はi, iiiを用いて、背景切り抜きするLINEアプリを作ってみました。具体的には 1. LINEでLambdaに画像を送信して 2. セマンティックセグメンテーションモデルを用いて背景画像を切り抜き 3. 切り抜いた画像をLINEに送り返す をしてみました。基本的には組み合わせです。 完成物 こんな感じになります。 LINEで画像をおくると、背景が切り抜かれた画像が返却されます。 いぬ。かわゆ。 「あれ、処理後の画質悪くなってね?」はちょっと聞こえません。切り抜き精度もご愛嬌でお願いいたします。 では書いていきます。 #バイナリ画像処理に慣れていないので、冗長な部分もあると思いますが、ご容赦ください... LINE->Lambdaで画像受信できるようにするconfig おさらいになりますが、まずはLINEMessagingAPIで送られてきた画像をLambdaで受信できるようにする設定から。 lambda_function.py LINE_CHANNEL_ACCESS_TOKEN = os.environ["LINE_CHANNEL_ACCESS_TOKEN"] #-- Headerの生成 HEADER = { 'Content-type': 'application/json', 'Authorization': 'Bearer ' + LINE_CHANNEL_ACCESS_TOKEN, } BUCKET_NAME='xxxxxxxx' 画像を受信してバイナリ化(SageMaker呼び出し用) 画像を読み込んで、SageMakerへ入力できるようにバイナリに変換します。 lambda_function.py def lambda_handler(event, context): body = json.loads(event['body']) for event in body['events']: #-- ImageMessageが来た時 if event['message']['type'] == 'image': #-- 1. 画像を読み込み MessageId = event['message']['id'] # メッセージID ImageFile = requests.get('https://api-data.line.me/v2/bot/message/'+ MessageId +'/content',headers=HEADER) #Imagecontent取得 print('get image!') #-- 2. ImageFile(LINEから送られてきた画像)をPILで読込&pngで保存 img = Image.open(BytesIO(ImageFile.content)) img.save('/tmp/receive.png','PNG') #-- 3. bytesioに変換 img_bytes = BytesIO() img.save(img_bytes, format='PNG',optimize=True,quality=80) image_data = img.getvalue() #これが bytes 1はLINEからの画像取得。 2はPILで読み込んでreceive.pngとして保存しておきます(後で使用)。3はSageMakerに入力するためにbyteにします。 SageMakerで学習したモデル を呼び出して推論 さて、画像が用意できたところで、いつぞやの記事で学習したモデルを使って推論してみます! lambda_function.py #-- 4. sagemakerにアクセスする runtime = boto3.client("sagemaker-runtime", region_name="your-region") #-- 5. 作成したエンドポイント名称 endpoint_name='semantic-segmentation' #-- 6. 指定したエンドポイントにデータを渡す res = runtime.invoke_endpoint(EndpointName=endpoint_name, Body=image_data, ContentType='image/jpeg', Accept='image/png' ) #-- 7. 推論結果の画像情報を抽出 body = res['Body'].read() image_decoded = bytearray(body) #-- ここでハマったー!bytearrayとすること。 #-- 8. analysis.pngとして保存 with open('/tmp/analysis.jpg',"wb") as f: f.write(image_decoded) pil_img = Image.open('/tmp/analysis.jpg','r') pil_img.save('/tmp/analysis.png', 'PNG') ここで5はSageMakerで作成したエンドポイント名を入力します。6ではjpegもしくはpngを読み込むように設定しています。読み込み対象のimage_dataは前述の3で作っています。 7で推論結果の画像情報を抽出して、8でpngに保存しています(jpg->pngのやり方が遠回りな気がする...) 背景の切り抜き さて、入力画像(receive.png)と推論画像(analysis.png)を用いて、背景の切り抜きをしてみます。 推論画像をちゃんとしたマスク画像にするために、ちょいと画像処理します。 lambda_function.py ''' 検出物体(黒色以外)を白色に変換 ''' #-- i1. 推論結果をRGBAに変換してRGB分ける org = Image.open('/tmp/analysis.png') rgb_img = org.convert('RGBA') r, g, b,_ = rgb_img.split() #-- i2. RGB各々において、色がないところは0,それ以外は1 _r = r.point(lambda _: 0 if _ == 0 else 1, mode="1") _g = g.point(lambda _: 0 if _ == 0 else 1, mode="1") _b = b.point(lambda _: 0 if _ == 0 else 1, mode="1") #-- i3. mask(111->1, 000->0) mask = ImageChops.logical_or(_r, _g) mask = ImageChops.logical_or(mask, _b) trans=mask.convert('RGBA') trans.save('/tmp/mask.png') #-- i4. 白黒をグレイスケール変換 mask_gry=Image.open('/tmp/mask.png').convert('L').resize(img_input_png.size) #Grayスケール変換&resize #-- i5. img_input_png+img_msk img_input_png=Image.open('/tmp/receive.png') img_mask=Image.open('/tmp/mask.png') im=Image.composite(img_input_png,img_mask,mask_gry) #-- i6. 背景を透過 transparent = Image.new("RGBA", im.size, (0, 0, 0, 0)) transparent.paste(im,(0,0),mask_gry.split()[0]) i2,i3で検出物体の画素を白色に、そのほかを黒色に変換しています。こちらのサイトを参考にさせていただきました。 i2 では、RGB各々に対して、色がないところは0, それ以外は1にする処理をしています。mode=1にすることで、色深度が1ビットの画像生成されます。 i3 では、各々のorをとっています。つまり、RGBどれかひとつでも1があれば残し、全て0であれば要らない子(背景)とみなします(「すべて1の画素を残す」でもそれなりに分離できてた。このあたりの最適解が分からない...)。 i4 では、合成時にマスクするために、生成されたmask画像に対しグレイスケール変換を施します。 i5 では、入力画像と白黒マスク画像 を合成しています。引数が3つありますが、これは「img_input_pngとimg_maskを合成するよ、ただしmask_gryでマスクするよ」という意味です。これによって「切り抜き」が実現されます。 i6 で最後に背景を透過しています。 ちなみに、入力画像(LINEから受信)、マスク画像(~i3で作成)、出力(i5,i6で作成)はそれぞれこんな感じです。 いぬ。かわゆ。 LINEに送り返す これにも一手間必要です。画像をS3バケットに保存し、署名付きのURLを取得する必要があります。 S3に保存された画像をLINE Messaging APIで取得する時に、時間制限をつけてアクセス可能にします。時間制限付きのIAM Roleがつくイメージですね。 lambda_function.py #-- 9. resultをS3に保存(.jpg) filename_output='output.jpg' image_bytes = BytesIO() transparent.save(image_bytes, format="png") image_bytes = image_bytes.getvalue() obj = s3.Object(BUCKET_NAME,filename_output) obj.put( Body=image_bytes) #-- 10. S3へアップロードした画像の署名付きURLを取得する s3_client = boto3.client('s3') s3_image_url = s3_client.generate_presigned_url( ClientMethod = 'get_object', Params = {'Bucket': BUCKET_NAME, 'Key': file_name_output}, ExpiresIn = 10, HttpMethod = 'GET' ) #-- 11. 署名付きURLを用いてimage_urlを送る REQUEST_MESSAGE = [ { 'type': 'image', 'originalContentUrl': s3_image_url, 'previewImageUrl': s3_image_url, }, ] payload = {'replyToken': event['replyToken'], 'messages': REQUEST_MESSAGE} 10.のExpiresInで、有効時間(秒)を決めています。 これでLINEに送信できました! まとめ 今回はLINEMessagingAPIと、SageMakerを使って、「写真送ったら切り抜いて送り返してくれる」簡単なアプリを作ってみました。 普段は音声屋の身分ですが、画像の信号処理も勉強になりました。 Rekognitionと組み合わせて、証明写真ジェネレータとか作れそう。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS ネットワーク

【AWS ネットワーク】 AWSのネットワーク設計はとても重要。 TCP/IPなど、ネットワークの知識ももっとつけていこう。 記事について、誤りや不足している点がございましたらご指摘頂けますと幸いです!! AWS上でのネットワーク設計のポイント 物理設計の検討、構築が不要 マネージドサービスによる運用負荷の軽減 プログラマブルな作成、管理、展開 VPC(Virtual Private Cloud) AWSの仮想ネットワークサービス 地域(リージョン)毎にアカウントと紐づいた仮想的なネットワーク空間 リージョンは、複数のAZから構成される。 基本的に東京リージョンを使用する。 1アカウントで複数のVPCを作成することも可能。 dev環境、stg環境とprod環境でVPCを分けることがスタンダード。 ※ 前提:VPCの内部のことをローカルという。 VPCのCIDRブロックは /16  CIDRブロックは、/16 が推奨されている。 (大きさは /28 から /16 の範囲で使用できる。) 1度作成すると、変更不可のため大きめにしておく。 オンプレミスや他のVPCのレンジと重複しないようにしておく。 重複していると他のVPCとのVPCピアリングができない。 VPCの主な機能 サブネット:VPC内のネットワークを細分化する。 インターネットゲートウェイ:インターネットとの接続をおこなう。 ルートテーブル:ネットワークの通信経路を設定する。 セキュリティグループ:セキュリティ(ファイアーウォールのようなもの) サブネット VPCのCIDRブロックの範囲からIPアドレスレンジを切り出す。 /24 が標準的 サブネットはAZの中に作成される。 高可用性のために2つ以上のAZの使用をしよう。 マルチAZ サブネット分割は、インターネットアクセスの有無で決める。 パブリックかプライベートか。 パブリックサブネットとプライベートサブネットの違い インターネットに接続できるかどうか。 インターネットゲートウェイへのルーティングの有無で決まる。 パブリックサブネット: ルートテーブルにインターネットゲートウェイへのルーティング有り。 デフォルトゲートウェイとインターネットゲートウェイが設定されているサブネット プライベートサブネット: ルートテーブルにインターネットゲートウェイへのルーティング無し。 デフォルトゲートウェイにインターネットゲートウェイが設定されていないサブネット パブリックサブネット : 外部公開しても良いAWSリソース プライベートサブネット : セキュリティレベルの対価用なDBなどのAWSリソース インターネットゲートウェイ VPC内からインターネットへ疎通するには、インターネットゲートウェイが必要。 0.0.0.0/0:インターネットに向かう通信が飛ぶ。 デフォルトでVPC内宛ての経路は作成済み。 ルートテーブル IPアドレスの範囲をどの方向に向けるかを設定する。 サブネットに関連付けて使用する。 サブネット間の通信経路を設定 サブネットから外に出る通信をどこに向けて発信するかルールを決める。 セキュリティグループ 仮想ファイアーウォールサービス どのポートを許可するか。 許可の判断は累積的に判断される。 インスタンスレベルで必要な通信を許可 ホワイトリスト型 許可のみ指定可能 インバウンド・アウトバウンドに対応 ステートフル 戻りトラフィックは自動的に許可 その他 NATゲートウェイ Elastic IP address VPCピアリング VPCエンドポイント NATゲートウェイ プライベートサブネットからインターネット接続を可能とする。 セキュリティを担保して、プライベートサブネットからインターネットに接続可能にする パブリックサブネットに配置し、ルーティングの設定をする。 アウトバウンドは出来るがインバウンドは出来ない。 EIP(Elastic IP address) インターネットと通信が出来る静的なIPアドレス インスタンスが終了、停止、再起動しても変わらない同一のアドレス 無料で利用できるがどこにもアタッチしていない場合1時間あたり1円程度で料金が発生する。 インターネット接続用のIPアドレスはパブリックIPかEIPのどちらか1つ。 EIPアドレスは他のインスタンスに付け替え可能。 VPCピアリング VPCの機能の1つ VPC同士を接続するサービス プライベートIPでVPC同士を接続する。 dev環境、stg環境とprod環境など、目的別にVPCを分割するのがベストプラクティス 2つのVPC間でルーティング、異なるAWSアカウントのVPCとも接続可能 ※ 同一リージョン内のみ IPアドレス範囲は重複できない。 VPCエンドポイント VPC外のAWSサービスとの接続 仮想ネットワークサービス S3などのリージョンサービスにVPCからプライベートに接続することができる。 参考 CloudTech クラウドエンジニア(AWS)ロードマップ2021 AWS のネットワーク設計入門 おわりに。 この記事はAWS初学者を導く体系的な動画学習サービス 「AWS CloudTech」の課題カリキュラムで作成しました。 https://aws-cloud-tech.com
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む