20211128のAWSに関する記事は15件です。

WP Offload Media Lite for Amazon S3でS3に画像が保存されない場合に確認するべきポイント

はじめに WP Offload Media Lite for Amazon S3を使用した際にはまったポイントをまとめました。 一番のポイントは1で、私はここでハマってまいました。 画像付きで記事を作成しましたので、イメージしやすくなればと思います。 ■WP Offload Media Liteとは WordPressの記事作成で画像などをアップロードした際にサーバ上ではなくS3上にファイルをアップロードするWordPressのプラグイン 確認ポイントと解消方法 1.必要なPHP関連パッケージがインストールされているか? そもそもPHPが入っていないとWP Offload Media Liteは動作しないのですが、加えてphp-gd(画像を生成するためのPHPライブラリ)が入っていいないと正常に動作しませんでした。 最終的に以下の状態で私は正常に動作しました。 【正常動作時のphp関連パッケージ】 yum list installed | grep php 【php関連パッケージのインストールのコマンドと途中経過】 ■初期状態 yum list installed | grep php ■php7.2のインストールとその確認 sudo amazon-linux-extras install -y php7.2 yum list installed | grep php ■php-mbstringのインストールとその確認 sudo yum install -y php php-mbstring yum list installed | grep php ■php-gdのインストールとその確認 sudo yum install -y php-gd yum list installed | grep php ■apachのサービスを再起動 sudo systemctl restart httpd.service 2.Offload Media Lite自体の設定はあっているか? 設定「Copy Files to Bucket」がONになっていないとS3にデータはコピーされません。 (When a file is uploaded to the Media Library, copy it to the bucket. <ファイルがメディアライブラリにアップロードされたら、バケットにコピーします。>) 3.S3バケットの設定で、「ブロックパブリックアクセス」がオフになっているか? S3バケットを作成時にapachからアクセスするために以下設定で作成する必要があります。 ■S3バケット作成時のブロックアクセス設定 4.接続ユーザのアクセス件はあっているか? IAMで接続ユーザにS3へのアクセス権を付与してある必要があります。(AmazonS3FullAccessなど) 最後に AWSの勉強を進めている中でググってもなかなか解決方法が見つからなかったので本記事を作成してみました。 他にもポイントがあれば追記できたらと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

姉さん、大変です。New Relicを・・・

姉さん、大変です。New Relicを使ったことがないと言えなくなりました。 1.はじめに 今日は、2021年11月27日。気づいたら、アドベントカレンダー投稿まで今日を入れて残り5日しかないという状況になりました。 Qiitaさんからも、もうすぐだよっと、親切なメッセージをいただいている状態。AWSのことしか投稿していない私が、今回なぜ、New Relicで投稿しようと思ったのか、、、、きっかけは、元同僚であり、現在は、New Relic でご活躍されている清水毅氏に、ふとしたことで質問したときに、「もう、これ以上、、New Relic を使っていないなんて言えない」と私自身が思ったことがきっかけでした。でも、それから、1か月以上が経過した今、この時点でも、New Relicのコンソールにログインしたことも、アカウントさえも持っていません(実は持ってたみたいだけど)。ログインもしてません(実はログインしていたみたいだけど記憶もなく、パスワードも失念)。本も読めてません。 が、この状況から今回、アドベントカレンダーに挑戦し、「New Relic 完全に理解した」と言えるようになりたいと思い2時間限定でブログを書きながらまず挑戦してみました。すいません。初心者のしょぼしょぼブログです。 2.まとめ アカウントは3分程度で作れる(実際には、持ってたみたいだけど) EC2(Cloud9)環境には、2分程度で導入完了。あっさりと連携。 Tomcatもコーディングの変更なく、Dockerfileの修正、build/deployであっさり連携 3.目的 とはいえ、何を目的にするかが重要かなと思います。 そこで、まずは、目的を考えてみましたが、まずは 次に清水さんと会話する機会に 「核心を突く良い質問ですね~」 「そうなんです。そこが大事なんです~」 と言ってもらえるようになること。全然技術的じゃない。では、そうなるためには、まず何をすればよいか、、、 アカウントを作る ログインする EC2やFargateと連携させる え?こんなんで「核心を突く良い質問ですね~」とか「そうなんです。そこが大事なんです~」とか言ってもらえると思ってるの?と思うかもしれないですが、清水さんは大人なので、きっと言ってくれるはず。 ということで、今日は、いまだ、アカウントも持っていない、New Relic 実践入門も読んだことが無い、Amazon CloudWatch しかかじったことのない私が、New Relicに入門したいと思います。 4.New Relic のアカウントづくり。 さて、アカウントを作ればよいと思うものの、どこから作るのかも今時点ではわかってません。現在時刻はこちら。 何分で作れるのかな。よーいドン。 画面キャプチャーしながらなので、時間はかかるけど、まずは、以下で検索。え?そこはマニュアルでしょ?と思うかもしれませんが、「何も知らない人が思い付きでどれくらい簡単にできるか?」ということを考えると、やっぱ、Googleでしょ。 すると、幾つか該当リンクが表示された中で、私がおおお!っておもったのが、こちら 無料ユーザーアカウント月間100GBまでのデータ容量 100GBだと!!ログ送りたい放題じゃないか!って思ったわけです。ということで、リンク先に行ってみます。ブログ書きながら、ここまで、7分ですね、まあ、検索&リンククリックで10秒で終わると思います。 はい、仮登録を行います。 1分程度で入力を終え仮登録をしたらお礼をいただく。それがこちら。 そして、本登録へ進むと、こんな感じで、英語の画面に切り替わったけど、内容は簡単。名前と先ほど仮登録で入れたメアドを入力 Start Now を押したら、3秒程度で以下の画面が表示されたのでメールを確認しました。 5. 衝撃の事実。 メール、1分後には、届きました。 でも、タイトルがおかしい。 むむむ。どうやら、私がアカウントを持っていないっていうのは、嘘っぽい。 むしろ既にNew Relicのアカウントを持って居たっぽい? まあ、いいか、とりあえず、記憶からは完全に消えてしまってるので、アカウントを持っていない感じは継続して、このまま進めてみます。 Create New Organizationをクリック すると・・・パスワードリセット画面に行く。まあ、そうだよね、パスワードなんて覚えてるわけないしね。 リセットが完了すると、今度は、データの保存先を選択することができるらしい。 とりあえず、何も知らない私は、よし、じゃあ、シンガポール当たりを選んでみよう!って思ったらどうやら、アメリカとヨーロッパの二択。アメリカにしておきました。 そして、10秒ほど待っていたら、こんな画面に。 困った、思い付きで始めたから、アプリも何もない。最近は、EC2も極力Terminateしてるし・・・。 6. どこに入れようか ここまで、ブログを書きながら30分が経過。 ここまでドキュメントを読まずに来たけど、いよいよ、これは何を入れる気だ?んん?と思い、画面右側のSee our docsをクリック。 If you haven't already, sign up for a free New Relic account so you can instrument your systems and send telemetry data to New Relic. Our guided install creates a customized CLI command for your environment that downloads and installs the New Relic CLI and the infrastructure agent. なるほど。New Relic CLIの導入ね。ふむふむ。じゃあ、とおもって、ドキュメントにあった。ボタンを押すとさっきと同じ画面に遷移。Installation plan画面。 どこに入れようかなとおもたけど、「取り合えず Cloud9が入っている、Amazon Linux 2の環境に入れてみるか」と試してみた。 ということで、Linux用のダウンロード&インストールコマンドを実行。引数には、API KeyとアカウントIDが含まれてる。うっかりBlogに掲載するところだった。。。 curl -Ls https://download.newrelic.com/install/newrelic-cli/scripts/install.sh | bash && sudo NEW_RELIC_API_KEY=NNNN-ABCDEFGHIJKLMN NEW_RELIC_ACCOUNT_ID=0000000 /usr/local/bin/newrelic install Log integrationとGolden Signal Alertsを両方がデフォルトで選ばれてるな~と思いつつ、念のため、検索すると、清水さんの記事もある。 まあ、じゃあ、デフォルトで、という感じで進める。 あああ、数分で導入完了。 お、とりあえず、あっという間に導入で来たな。じゃあ、見せてもらおうか、New RelicのUIとやらを。。。ということで、インフラデータとログデータを覗き見。 おおお、ちゃんと計測されている。ログも、連携されている。楽ちんだね。とはいえ、こんな1台のEC2にAgentを入れただけで完全に理解したとは言わない。 7. 二台目を動かす。。そして、Tomcatへ まあ、同じことの繰り返し。追加先は、別のリージョンにしてみようということで、シンガポール。すぐ、二台目も追加された。 ここまで、特に困ることもなく進んだので、TomcatをFargateで起動して試してみることに。 これも、なんとなく、UIを見ながらやってみた。 画面上部にある、Add More Dataをクリックする 画面上部にある検索バーにtomcatを入れたが出てこなかったのでJavaを入れて選択。 Begin Installationをクリック。 すると、こんな画面が出るも、。これ、JavaのAgentを環境に導入する感じだよね。このコマンドは違うよね~って思い画面下部にある。[Other Java installation options]をクリック。 すると、私のアカウント用に設定された設定ファイルをダウンロード可能な画面に遷移し親切にもtomcatのディレクトリに配置する指示や環境変数に追加する指示があるので、Dockerfileにそれらを書き、ビルド ちなみにDocker Fileはこちら。こちらのImageをベースに作るとWebappsは空っぽなので、アプリは空状態で今回はしのぎました。 FROM public.ecr.aws/docker/library/tomcat:latest WORKDIR /usr/local/tomcat/ RUN curl -O "http://download.newrelic.com/newrelic/java-agent/newrelic-agent/current/newrelic-java.zip" RUN ["apt-get", "install", "unzip"] RUN ["unzip", "newrelic-java.zip", "-d", "/usr/local/tomcat"] ENV JAVA_OPTS="$JAVA_OPTS -javaagent:/usr/local/tomcat/newrelic/newrelic.jar" COPY newrelic.yml /usr/local/tomcat/newrelic/ # run the Tomcat Server CMD ["/usr/local/tomcat/bin/startup.sh", "run"] Docker Imageをビルド後にECRにPush後起動したら・・・・なんか連携されたっポイ。完全に理解した!! 姉さん、、、 大変です。Lambdaと連携したいです。Lambda-SNS-SQS-Lambdaがどう可視化されるかみてみたいとです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Cypress 認証情報を保持して自動化へ Cognito編〜

はじめに 現在、SESとして自社開発に携わっているエンジニア一年生です。e2eテストを初めて作成するにあたって、ユーザー認証(今回は、AWSCognito)を考慮することに少し手こずったので備忘録としての記事です。また、もし同じ内容につまづいた方へ参考程度になればいいなと思っております。 AWS-amplifyの利用 今回はAWSのCognitoを使用したユーザー認証を行なっているので、アクセスするために以下のaws-amplifyを使用して認証情報を取得します。 npm install --save aws-amplify Cognitoを利用した認証自動化 Cypressでオリジナルのメソッドを生成するにあたって、Cypress.Commands.add()で新しく作成することができるので今回は使用時に、login(username,password)となるように作成していく。 AWSのCognitoを使用しているので、リージョンやプールIDなどを設定する。 そして、aws-amplify内のsignIn()を使用して認証情報を取得する。 /support/commnads.ts import Amplify, { Auth } from 'aws-amplify'; Amplify.configure({ Auth: { mandatorySignIn: true, region: **********, userPoolId: **********, identityPoolId: **********, userPoolWebClientId: **********, }, }); Cypress.Commands.add('login', (username, password) => { return Auth.signIn(username, password) .then((user) => { console.log('===> user', user); const session = Auth.currentSession(); console.log('===> session', session); }) .catch((err) => console.log('===> err', err)); }); そして、カスタムメソッドの型定義を入力していく。 /support/index.d.ts /// <reference types="cypress" /> declare namespace Cypress { interface Chainable<Subject> { login(username: string, password: string): Chainable<any>; } } Cognito内で保存してあるユーザー情報を指定することで認証情報を取得することで、ログイン状態を保持してテストを走らせることができる。 /integration/ぱす import '../support/commnads'; it('cognito settion on', () => { cy.login(ユーザーID, パスワード); cy.visit('/'); }); ちなみに今回のCypressについて 簡単にまとめている記事があったので以下を参考にしました。 https://blog.microcms.io/cypress-react-e2e/ 参考記事 感想・まとめ 初現場で0⇨1でE2Eテストをしていく中でユーザー情報を保持するサイトが多い中こういった工夫が必要だと思いました。また、CSSフレームワークを使用しているとテストしたいタグを指定するのにデベロッパーツールで確認するとマテリアルコンポーネントだと、指定場所が変わってくるので確認に手間がかかりました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSで社員自己紹介サイトを作ってみた

1.活動内容 久保田チームではAWSを活用して社員の自己紹介サイトを作成してみました。 なお、作成にあたりチーム内で下記のような役割分担をして作成を進めました。 ・インフラ構築 ・フロントエンド作成 ・DB構築 2.利用したサービス IAM アカウント  ・rootユーザー  ・IAM ユーザー 設定  ・ポリシー  ・グループ  ・ロール VPC ・サブネットグループ ・セキュリティグループ EC2 下記をインストール ・Apache ・MySQL ・phpAdmin ・WordPress RDS 下記をインストール ・MySQL 3.成果物 1.各種サービスの手順書​  ・EC2インスタンス作成とWordpressインストール手順​  ・RDSインスタンス作成手順​  ・Wordpressへの自己紹介プラグイン導入手順​ 2.AWS上のサイト構築​  ・社員自己紹介サイト 4.サイト構成図 5.実際のサイトページ トップページ 自己紹介ページ ※架空の人物を記載 6.課題 自己紹介ページ(プラグイン)のデータが格納されているテーブルが見あたらず、RDSとWordpressを連携させることができなかったという課題が残りました。​ 7.最後に 今年のチーム会の活動では、実際にAWSを利用して自己紹介サイトの構築を行うことでAWSの各種サービスの理解を深めることができました。 来年の活動では、課題解決と自己紹介サイトの改善を行うことを検討したいと考えております。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS HTTPS通信でアクセス / CloudFront

【AWS HTTPS通信でアクセス / CloudFront】 HTTPS通信でアクセスのハンズオンメモとCloudFrontを基礎。 今後に備えて、今はあまり実務で使っていないCloudFrontを基礎から学習。 S3をHTTPS化!自分のドメインで配信したい。 本番サービスでは、よりセキュアなHTTPS通信が最低限求められる。 前提: EC2インスタンスが立ち上がっていること。 RDSが起動していること。 ドメイン名でアクセス可能であること。 手順: ELBロードバランサーの方でリスナーを追加。 マネジメントコンソールから「ロードバランサー」>「リスナー」>「リスナーの追加」 プロトコルに「HTTPS」 > 転送先に「作成したターゲットグループ」を選択 「新しいACM証明書をリクエスト」> ドメイン名の追加で、ドメイン名を入力 検証方法の選択、「DNSの検証」> 証明書のタグは必要に応じて作成 >「次へ」 本人確認のような確認。 検証画面、検証準備中となっている(検証作業をおこなうと準備完了に。) 「Route53でのレコード作成」> CNAMEのDNSレコードを作成したRoute53のホストゾーンに追加 検証完了 ELB リスナー追加画面「デフォルトのSSL証明書」で、作成したACM証明書を選択 > 更新 HTTPSのリスナーの作成が完了 ELBのセキュリティグループで、HTTPS通信を許可する。 インバウンドルールで、全てのIP(0.0.0.0/0)からのHTTPS通信を許可 ELBがHTTPS通信を受け付けられるようになった!! ブログのURLに鍵マークがついていることで確認する。 HTTPS通信のみ可能に変更する。 HTTP通信を許可した状態だとセキュリティ上問題があるため。 ELBのセキュリティグループ・リスナーにて、既存のHTTP通信の許可設定を削除する。 AWS Edge Services AWSのエッジロケーションから提供されるサービス群 AWSのサービスへのアクセスをユーザーに近い場所から提供 Edge Location と AWS Region Edge Location Amazon CloudFront Amazon Route 53 AWS Global Accelerator AWS WAF AWS Shield AWS Lambda@Edge AWS Region Amazon EC2 Amazon VPC Amazon RDS Amazon S3(Simple Storage Service) Webアクセスの課題 レスポンスの遅延、不安定なレスポンス インターネット経由でのアクセスにおけるネットワーク遅延の影響 ネットワーク遅延は、(物理的、ネットワーク的な)距離に依存 コンテンツの元サーバー(オリジン)が遠いと、応答に時間がかかる。 応答時間の多くが、ネットワーク転送の待ち時間を占める場合もある。 大量アクセスへの対応 不要なトラフィックをオリジンに到達させない効率的な仕組みが必要 Webコンテンツには、あまり変化しない静的なデータが多く含まれる。 例)画像、動画、CSS、JavaScript等のファイル 同じデータを何度も取得するのは、ネットワーク帯域、サーバーリソースの無駄な消費 CloudFront 【AWSのフルマネージド型CDNサービス】 大容量キャパシティを持つ地理的に分散したサーバー群(エッジ)からコンテンツをキャッシュしたり代理配信をするサービス 高性能な分散配信 高いパフォーマンス(高いパフォーマンスの実績) キャパシティアクセスからの解放(予測不可能なスパイクアクセスへの対応) ビルトインのセキュリティ機能(WAF連携、DDoS対策) 設定が容易で即時利用可能(GUIからの設定で15分程度でサービス利用可能) 充実したレポーティング(ログ、ダッシュボード、通知機能) 完全従量課金(初期費用がなく安価、一時的な利用も可能) CloudFront導入の利点 ユーザーエクスペリエンスの向上 ユーザーを一番近いエッジロケーションに誘導することで配信を高速化 DNSを応用した仕組みで最適なエッジロケーションを割り当てる。 エッジサーバでコンテンツのキャッシングを行いオリジンの負荷が減る。 CloudFrontを開始してデータの配信元を指定すると、世界中のエッジロケーションデータがコピーされる。 AWS WAFとの組み合わせや、組み込みのDDoS対策により、高いセキュリティを実現 ログ・レポート機能でアクセス傾向分析も可能 大容量の配信や大量アクセスがあるサイトでの活用が有用 小規模でも、WAF/DDoS等のセキュリティ対策が必要なサイトで有用 必要な荷物を取りに行く場合、自宅まで取りに行くのは距離が遠く面倒なので途中に倉庫を設置してよく使う荷物は倉庫に保管することで時間を短縮できる。 Webページでも同様でキャッシュサーバーという中間地点にWebページを保存しておくことでより高速にユーザーに配信することができます。 CloudTechより、引用しました。 CloudFront コンテンツ配信設定の流れ S3バケット, ALB, EC2, オンプレミスにある独自のHTTPサーバーなどのオリジンサーバーを設定 ファイルをオリジンサーバーにアップロード CloudFrontディストリビューションを作成 CloudFrontがドメイン名を割り当て ディストリビューションの構成を全てのエッジロケーションに送信 CloudFrontディストリビューション ドメイン毎に割り当てられるCloudFrontの設定 AWS Management Console、APIで即時作成可能 HTTP/1.0, HTTP/1.1, HTTP/2, WebSocket対応 IPV6にも対応 デフォルト:xxxx.cloudfront.net ディストリビューションのドメイン名として割り当てられる。 CNAMEエリアスを利用して独自ドメイン名の指定が可能 有効な、SSL/TLS証明書の対象であることが必要 CNAMEエリアスのワイルドカード指定もサポート 例)*.example.com Route53と組み合わせた、Zone Apexが利用可能 例) example.com エッジでのgzip圧縮機能 CloudFrontエッジでコンテンツをgzip圧縮し、高速にコンテンツを配信 S3はgzip 圧縮をサポートしていないため、有効なオプション キャッシュ キャッシュコントロール機能 キャッシュヒット率を向上させることがCDN導入におけるポイント GET/HEAD/OPTION(選択可能)のリクエストが対象 単一ファイルサイズのキャッシングは最大20GBまで。 URLパス毎にキャッシュ期間指定が可能 フォワードオプション機能による動的ページ配信 Header/Cookie/Query Strings URLおよび有効化したフォーワードオプション機能のパラメータ値の完全一致でキャッシュが再利用される。 キャッシュコントロールヘッダー キャッシュ時間のコントロールが可能 オリジン側がHTTPキャッシュコントロールヘッダーを付与しない場合でも上書きが可能 キャッシュ動作(Behavior)毎にキャッシュ設定を行うことで、URLパス毎にキャッシュ期間を変える。 デフォルトTTL:24時間 キャッシュファイルの無効化(Invalidation) コンテンツ毎の無効化パス指定(同時に最大3,000個) ワイルドカードを利用した無効化パス指定(同時に最大15個) オブジェクト数の制限無し AWS Management Console、APIで実行可能 動的コンテンツキャッシュへの対応 オリジンサーバに対して Header, Cookie, Query Strings 情報をフォワードすることで、動的なページの配信にも対応 URLパス(Behavior)と組み合わせ、きめ細かなキャッシュコントロールを実現 Whitelistを利用して、必要最低限のパラメータのみをフォワード設定することで、キャッシュを有効活用する。 キャッシュしないコンテンツでも、オリジンとの通信の最適化により配信の高速化を実現 必要最小限のヘッダーを指定することが推奨されている。 Cookieをオリジンへ転送 クエリ文字列パラメータの値をオリジンへ転送 パラメータの順序を常に統一する。 パラメータ名とパラメータ値の大文字と小文字を常に統一する。 これらを統一しないと、それぞれにキャッシュされてしまう。 TTLの設計: どのデータをキャッシュするか。それを何秒間キャッシュするかが重要です。 一般的にSNSサイトのプロフィールなどのようなデータなど一定の間隔で頻繁にアクセスされデータが多少古くても問題とならないデータなどは向いているデータとなります。 変化の激しいデータ。株価のデータ、アクセスが殆どないデータなどは向いていないデータになります。 CloudTechより、引用しました。 カスタムエラーページの生成 S3と組み合わせた構成例 4XX系はCloudFront側ですべてをハンドリングしていないかつ、クライアント要求のエラーのため、オリジン側で対処 Webサーバ側で4XXエラー時のページ設定 5XX系はオリジン側のエラーのため、CloudFront側で対処 5XXのカスタムエラーページをS3に設定(4XXはオプション) ※ エラーキャッシュ期間(Error Caching Minimum TTL) はデフォルト5分 オリジン オリジンの読み取りタイムアウト CloudFrontがカスタムオリジンからの応答を待つ時間を指定 デフォルトのタイムアウトは 30秒(4~60秒の範囲) キープアライブタイムアウト 接続を閉じる前にCloudFrontがカスタムオリジンサーバーとの持続的接続を維持する最大時間を指定 デフォルトは、5秒(1~60秒の範囲) CloudFrontオリジンフェイルオーバーによる高可用性 オリジングループを作成し、プライマリオリジン·セカンダリオリジンを指定 エラーHTTPステータスコードを返した場合や接続タイムアウトした場合にバックアップオリジンにルーティング カスタムエラーページでもオリジンフェイルオーバー可能 地域制限 地域指定によるアクセス制御 接続されるクライアントの地域情報を元にエッジでアクセス判定 Blacklist、Whitelistで指定可能 ディストリビューション全体に対して適用される 署名付きURL/Cookieを利用したプライベートコンテンツ配信 Restricted Viewer Access を有効にするだけで、署名のないアクセスを全てブロック 単一コンテンツアクセスの場合は、署名付きURLの利用が推奨 複数コンテンツアクセスの場合は、署名付きCookieの利用が推奨 オリジンサーバの保護 オリジンがS3の場合 Origin Access Identity(OAI)を使用。 S3バケットへのアクセスをCloudFrontからのみに制限 カスタムオリジンの場合、下記の2種類が選択可能 オリジンカスタムヘッダーを利用し、CloudFrontで指定された任意のヘッダーをオリジンでチェック オリジン側のアドレスを公開しないとともに、CloudFrontが利用するIPアドレスのみを許可させる。 AWS WAF連携 AWS WAFで定義したWeb ACLをCloudFrontディストリビューションに適用 CloudFrontをサービスの前段に配置することでサイトの保護を実現 XSS/IPアドレス制限/SQLインジェクション/正規表現マッチング ...etc AWS WAFの内容が即時反映 AWS Shieldによる、DDoS攻撃対策 Amazonのノウハウを詰め込んだDDoS攻撃を緩和するサービス デフォルトで有効 無料で利用できる。 他ユーザートラフィックは、インラインシステムが可用性、スループット、レイテンシに影響を与えずに迅速に対応 今後 CloudFrontをCFnテンプレートで作成予定 そのコードを記載できたらなと。 CloudFormationスキルのアップに注力する。 参考 CloudTech 【AWS Black Belt Online Seminar】 Amazon CloudFrontの概要 おわりに。 この記事はAWS初学者を導く体系的な動画学習サービス 「AWS CloudTech」の課題カリキュラムで作成しました。 https://aws-cloud-tech.com
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

何となくわかった気になる週刊AWS - 2021/11/15週

はじめに お久しぶりです、なじむです。 DAS, MLS の試験勉強をしていたら、週末にブログをまとめる時間が取れず期間が空いてしまいました。無事どちらも合格しましたが、ラスト DBS が 12月に控えているため、それまで更新をお休みしようと思います。 というわけで今週は試験勉強の息抜きがてら、張り切ってやっていきましょう!AWS Japan さんがまとめている週刊AWSで確認した内容の自分用メモ。 今回は11/15週のアップデートです。 11/15(月) AWS Amplify が CDK を使用して Amplify で生成されたリソースをオーバーライドする機能を発表 AWS Amplify はモバイルアプリケーションやウェブアプリケーションを構築するための認証基盤やストレージをコマンド一つで作成できるサービスです。本アップデートでは、Amplify で作成したリソースの設定をコマンド一つで変更する機能が使用可能になりました。 これまで Amplify で作成したリソースの設定を変更する場合は amplify update auth のコマンドを実行し、対話型で更新する必要がありました。本アップデートにより、amplify override auth のコマンドを実行することで typescript のテンプレートファイルが作成され、amplify push -y を実行することで CDK が動き、テンプレートファイルの内容で設定を変更することができるようになりました 例えば、認証基盤(Congnito)の設定を変更するためには以下のような流れを実行します。 amplify add auth を実行し、認証基盤(Cognito)を作成する ※詳細は省略 amplify override auth を実行する amplify/backend/auth/<リソース名>/override.ts が作成されるためファイルの内容を修正する amplify push -y を実行する リソースの設定が変更される override.ts は typescript で記載されているので以下のように修正します。 (export の中の resource.…句を追記します) override.ts import { AmplifyAuthCognitoStackTemplate } from '@aws-amplify/cli-extensibility-helper'; export function override(resources: AmplifyAuthCognitoStackTemplate) { resources.userPool.policies = { passwordPolicy: { ...resources.userPool.policies["passwordPolicy"], // 現在の設定を展開 temporaryPasswordValidityDays: 2 // 「一時的なパスワードの有効日」の設定を上書き } } } 上述のコマンドを実行した結果は以下です。 確かに、パスワードのポリシーが変わっていますね。 変更前 変更後 なお、上書き(Override)できるリソースは以下です。 AWS IAM Amazon Cognito Amazon S3 Amazon DynamoDB やってみた系の記事は以下公式ブログが参考になりました。 (参考) Amplifyで生成されたバックエンドリソースをCDKでカスタマイズする新機能 「オーバーライド」のご紹介 日本リージョン対応状況 東京:対応 大阪:未対応 ※Amplify 自体に未対応 AWS Step Functions の Synchronous Express Workflow が AWS PrivateLink のサポートを開始 AWS Step Functions はワークフローを実行するためのサービスです。Lambda や ECS 等を組み合わせたり、StepFunction をネストしたりしてワークフローを作成します。 (出典) AWS Batch および AWS Step Functions を組み合わせて、動画処理ワークフローを作成する Step Functions では以下の種類のワークフローがあります。 標準ワークフロー  :長時間実行され、耐久性が高く、監査可能なワークフローに最適 Express ワークフロー:大容量のイベント処理ワークロード(IoT データの取り込みなど)に最適 非同期:ワークフローが開始されたことの確認を返すが、ワークフローが完了するまで待機しない 同期 :ワークフローを開始し、完了するまで待ってから結果を返す (参考) 標準ワークフローと Express ワークフロー (参考) 同期および非同期の Express ワークフロー これまでは標準ワークフロー、非同期 Express ワークフローの PrivateLink のみ提供されていましたが、今回のアップデートで、同期 Express ワークフローの PrivateLink が使用可能になりました。 実際の画面は以下です。 Synchronous Express Workflow で Privatelink が使用可能になっています。 大阪リージョンは、同期 Express ワークフローの PrivateLink は対応していましたが、標準ワークフロー(states.ap-northeast-3.amazonaws.com)の VPC エンドポイントはサポートしていないんですね。 日本リージョン対応状況 東京:対応 大阪:対応 AWS が Amazon Neptune に接続するためのオープンソース JDBC ドライバーをリリース Amazon Neptune はグラフデータベースのマネージドサービスです。 (出典) グラフデータベースとは? これまで Neptune にアクセスするためには EC2 に Gremlin をインストールしてアクセスしたり、Jupyter Notebook を構築してアクセスする必要がありましたが、今回のアップデートにより JDBC 経由で Neptune にアクセスできるようになりました。 これにより、ビジネスインテリジェンス (BI) ツールなど、JDBC をサポートするツールやライブラリを使用して Neptune に簡単にアクセスできるようになりました。 Neptune 用の JDBC ドライバは Github よりダウンロードできます。 (参考) amazon-neptune-jdbc-driver 日本リージョン対応状況 東京:対応 大阪:未対応 ※Neptune 自体に未対応 11/16(火) 改良された新しい Amazon Athena コンソールが一般提供を開始 Athena は S3 内のデータを標準 SQL を使用して簡単に分析できるインタラクティブなクエリサービスです。ここ最近、各サービスで新しいコンソールに変わってきていますが、Athena も新コンソールになったようです。 新コンソールになったことにより、以下のことができるようになりました。 クエリタブバーで、複数のクエリタブを再配置したり、移動したり、閉じたりすることができます。 改良された SQL フォーマッタと新しいテキストフォーマットテーマにより、クエリの読み取りと編集がより簡単になりました。 クエリの結果をクリップボードにコピーすることができ、さらに結果セットをダウンロードすることができます。 クエリ履歴、保存されたクエリ、ワークグループを並べ替えたり、表示・非表示の列を選択したりすることができます。 簡素化されたインターフェースにより、データソースやワークグループの設定を少ないクリック数で行うことができます。 クエリの結果、クエリの履歴、行の折り返しなどの表示方法を設定できます。 改良された新しいキーボードショートカットや、埋め込まれた製品ドキュメントにより、生産性を向上させることができます。 見た目の変化は以下です。 旧コンソール 新コンソール 日本リージョン対応状況 東京:対応 大阪:対応 Amazon AppStream 2.0 が Linux アプリケーションストリーミングを導入 Amazon AppStream 2.0 はアプリケーションストリーミングのマネージドサービスです。 (出典) Amazon AppStream 2.0でデスクトップアプリケーションのストリームをスケールする これまで、AppStream で使用できるイメージは Windows Server のみでしたが、今回のアップデートにより Amazon Linux 2 のイメージが使用できるようになりました。 これにより、Linux のアプリケーションもストリーミングできるようになり、Windows Server を使用してストリーミングした場合と比較して、総ストリーミングコストを削減することができるようです(どの程度削減できるのか、具体的にどうして削減できるのかは未確認) 実際の画面は以下です。 Amazon Linux 2 のイメージが選択できるようになっています。 Amazon Linux 2 のイメージを使用してアプリケーションをインストールすることにより、ブラウザから任意のアプリケーションやデスクトプ画面をストリーミングすることができます。 (今回、Chrome をストリーミングしたので、ちょっと見た目がアレになっています…) やってみた系はクラメソさんのブログが参考になりました。 「Windows の時にあった "Image Assitant" ないじゃん!どうするんだ!?」と小一時間悩んでいましたが、全てここに書いてありました。クラメソさん凄い(そもそも君は AWS 公式のチュートリアル を読んで…) (参考) [アップデート] AppStream 2.0でLinuxイメージがサポートされました 日本リージョン対応状況 東京:対応 大阪:未対応 ※AppStream 2.0 自体に未対応 11/17(水) AWS Network Firewall が ISO への準拠を達成 AWS Network Firewall は VPC 全体でパケットフィルタリング等のネットワーク保護をデプロイするためのマネージドサービスです。 (参考)AWS ネットワークファイアウォール – VPC 用の新しいマネージド型ファイアウォールサービス 今回、Network Firewall が以下 ISO に準拠するようになりました。 ISO 9001 :品質管理 ISO 27001:情報セキュリティ管理 ISO 27017:クラウドサービスにおける情報セキュリティ管理 ISO 27018:クラウドサービスにおける個人情報の保護 ISO 27701:個人情報の保護 各 ISO への準拠が求められているところでは嬉しいアップデートですね。 日本リージョン対応状況 東京:対応 大阪:対応 AWS Elastic Disaster Recovery の一般提供開始を発表 AWS Elastic Disaster Recovery が GA になりました。その名の通り DR 対策のためのサービスで、オンプレやパブリッククラウドに構築した仮想マシンや DB (Oracle、MySQL、SQL Server など)、 SAP 等のアプリケーションを、AWS にバックアップ、AWS 上でのリカバリが可能です。 (出典) Network diagrams やってみた系の記事でクラメソさんのブログがありましたが一筋縄ではいかなさそう。日本語のドキュメントも少ないので、今後調べながら実際の動作を確認してみようと思います。 (参考) AWS Elastic Disaster RecoveryでAzure仮想マシンをリカバリしてみた 日本リージョン対応状況 東京:対応 大阪:未対応 ※EDR 自体に未対応 Amazon EKS Connector でのすべての Kubernetes クラスターの 1 か所での視覚化の一般提供開始 Amazon EKS Connector が GA になりました。EKS Connector はオンプレやパブリッククラウドに構築した kubernetes クラスターを EKS のコンソールで一元的に確認できるようになる機能です。 流れとしては以下のようになります。 kubernetes クラスターの構築(オンプレでもパブリッククラウドでも可) IAM ロールの作成 Amazon EKS Connector サービスリンク IAM ロールの作成 Amazon EKS Connector Agent IAM ロールの作成 クラスターの登録(登録するとマニュフェストファイルが作成される) マニフェストファイルを kubernetes クラスターに適用 (参考) Amazon EKS Connector またもクラメソさんのブログの引用ですが、、、 やってみた系では以下のブログがとても参考になりました。kubernets クラスターを構築するの大変でさぼり気味… (参考) 【祝GA】EKS ConnectorでGKE上のKubernetesクラスターをEKSのコンソールに表示してみた 日本リージョン対応状況 東京:対応 大阪:対応 11/18(木) AWS Glue DataBrewに4つの新機能が追加 AWS Glue DataBrew はノーコードでデータの前処理を実行してくれるサービスです。 この週は Glue DataBrew で以下4つのアップデートがありました。 AWS Glue DataBrew が、個人を特定できる情報 (PII) の検出とデータマスキング変換の提供を開始 AWS Glue DataBrew が Amazon Redshift と Snowflake からデータを取得するためにカスタム SQL ステートメントのサポートを開始 AWS Glue DataBrew で、ビジネス要件の定義と検証のためのお客様によるデータ品質ルールの作成が可能に AWS Glue DataBrew が Amazon AppFlow とのネイティブコンソール統合を発表 日本リージョン対応状況 東京:対応 大阪:未対応 ※Glue DataBrew 自体に未対応 Amazon Aurora が MySQL 8.0 をサポート Amazon Aurora は MySQL/PostgreSQL 互換のフルマネージドサービスです。今回のアップデートでは、Aurora で MySQL のバージョン 8.0 が使用可能になりました。 MySQL 8.0 では主に以下の機能が使用可能になっています。 バイナリログの改善 マルチスレッドレプリケーション レプリケーションフィルタリング バイナリログトランザクションの圧縮 インスタント DDLのサポート 共通テーブル式のサポート ウィンドウ関数のサポート 並列クエリのサポートの追加 新インデックスのサポート 不可視 降順 ロール機能のサポート 詳細に関しては公式ブログを参照ください。 (参考) Amazon Aurora MySQL 3 with MySQL 8.0 compatibility is now generally available 実際の画面は以下です。 Aurora MySQL 3.01.0 (compatible with MySQL 8.0.23) が使用可能になっています。 日本リージョン対応状況 東京:対応 大阪:対応 AWS Control Tower が、ネストされた組織単位をサポート AWS Control Tower はマルチアカウント運用をベストプラクティスに沿って展開してくれるサービスです。 これまでは Control Tower を使用すると OU の下に OU を作成するネスト OU の構成は作成できませんでしたが、今回のアップデートにより、その構成が可能となりました。これにより、Control Tower を使用しても柔軟な OU 設計が可能となりました。 これまでは Control Tower には制限があり、以下のように OU の配下に更に OU を作成する構成ができませんでしたが、今回のアップデートにより可能となったという感じです(できなかったのが意外) Root ├Prd │├System_A ││├AWS_Account_1 ││├AWS_Account_2 ││└AWS_Account_3 │├System_B │└System_C └Dev  ├System_A  ├System_B  └System_C 実際の画面は以下です。 OU を作成する際に親 OU を選択できるようになっています。 その他、細かい仕様などはクラメソさんのブログが参考になりました。 (参考) [アップデート] AWS Control Tower で入れ子構造の OU を利用できる様になりました 日本リージョン対応状況 東京:対応 大阪:未対応 ※Control Tower 自体に未対応 11/19(金) Amazon Athena が AWS Glue Data Catalog パーティションインデックスを使用してクエリを高速化 Athena は S3 内のデータを標準 SQL を使用して簡単に分析できるインタラクティブなクエリサービスです。Athena はデータソースとして、Glue Data Catalog を設定できます。Glue には、クエリの実行時間を短縮するのパーティションインデックスという機能がありますが、これまでは Glue で パーティションインデックスを有効にしていた場合でも、Athena でのクエリは高速化されませんでした。今回のアップデートによりパーティションインデックスが有効な Glue Data Catalog を指定した場合には Athena からでも検索が高速になるようになりました(おそらく) 使用するための流れは以下です。 Glue Data Catalog からインデックスを作成する列を選択し、インデックスを作成 テーブルでパーティションフィルタリングを有効化 Athena でクエリを実行 以下のようなクエリを実行することで、パーティションインデックスを使用してクエリが実行できます。 SELECT count(*), sum(value) FROM partition_index.table_name WHERE year='2021' AND month='04' AND day='01' パーティションインデックスを使用した場合としていない場合で、以下の結果となりました。大きな差がありますね。 使用した場合   :2.091秒 使用しなかった場合:49.847 秒 やってみた系の記事は公式ブログが参考になりました。 (参考) Improve Amazon Athena query performance using AWS Glue Data Catalog partition indexes 日本リージョン対応状況 東京:対応 大阪:対応 AWS Database Migration Service がパーティションデータの S3 への並行ロードのサポートを開始 AWS Database Migration Service はデータベースを AWS に迅速かつ安全に移行するためのサービスです。 (出典) AWS Database Migration Service Database Migration Service では、RDB -> RDB だけでなく、RDB -> S3 というように、例えば SQL Server のデータ を S3 に出力することができます。これまで、移行時間の短縮のために並列でのデータを移行する機能はターゲットが RDB の場合のみサポートしていましたが、今回のアップデートにより、ターゲットが S3 の場合でも並列でデータ移行することが可能となりました。 実際の画面は以下だと思うのですが、以前の状態が分からないためにはっきりと言えず… 移行タスクの作成時、ターゲットが S3 の場合でもこの項目が設定できるようになったんじゃなかろうかと思っています…(分からない…) 日本リージョン対応状況 東京:対応 大阪:対応 Syne Tone の一般提供、配信ハイパーパラメータ向けオープンソースライブラリとニューラルアーキテクチャの最適化 ハイパーパラメータとニューラルアーキテクチャのチューニングジョブを実行できるオープンソースの Python ライブラリである Syne Tune が GA となりました(タイトルは Syne Tone となっていますが、正しくは Syne Tune のようです) 機械学習では、トレーニング用のデータを使用してモデルを構築していきます。ハイパーパラメータは、例えばモデル構築時にそのトレーニング用のデータからどの程度学習するかの学習率やレイヤーあたりのユニットの数等を指定します。この値により最終的な予測の精度が変わってくるため、ハイパーパラメータのチューニングは機械学種における重要な工程の一つであり、とても時間がかかります。 ハイパーパラメータのチューニング手法はいくつかありますが、Syne Tune を使用することにより以下のチューニングの手法を実装することが可能となります。 ベイズ最適化 Hyperband Population Based Training と、機械学習全く分からない私が書けるのはここまでで、詳細は AWS さんのブログがありますのでこちらを参照ください。。。 (参考) Run distributed hyperparameter and neural architecture tuning jobs with Syne Tune Syne Tune は以下からダウンロード可能です。 (参考) Github: awslabs/syne-tune 日本リージョン対応状況 ※リージョンごとのサービスでないため省略 東京:- 大阪:- Amazon Linux 2 AMI が、カーネル 5.10 で利用可能に Amazon Linux 2 は EC2 での使用に最適化され、EC2 の 最新機能をサポートする Amazon が提供する Linux OS です。2020 年 12 月に Kernel 5.10 が公開されましたが、今回のアップデートで Amazon Linux 2 も Kernel 5.10 に対応するようになりました。Kernel 5.10 を使用することにより、以下のようなメリットがあります。 WireGuard VPN を含むさまざまなセキュリティ機能を搭載 カーネルロックダウン機能(カーネルイメージの不正な変更を防ぐための機能)の改善 CO-RE (Compile Once - Run Everywhere) を含む多くの BPF の改善 実際の画面は以下です。 AMI を選択する時に分かるようになっていますね。 Kernel 5.10 の前の Kernel 4.14 も選択できるようになっています。 Linux Kernel って何ぞや?という方は以下の記事を参照してみてください。勉強になりました。 (参考) 【初心者向け】Linuxカーネルって一体なんだ? 日本リージョン対応状況 東京:対応 大阪:対応 感想 久々にやってみたのですが、記載した内容が合ってるか分からないアップデートもありますし、資格取るだけじゃだめだなと改めて思いました。とりあえず、12月に DBS を取得すれば終わるので、年明けから本格的に再開したいと思います。JAWS とか勉強会にもちゃんと参加しよう(来年の抱負)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS+ServerlessFrameworkを使ってPythonバックエンドを構築する

ここしばらく個人でスマホアプリを作ってみたいと思い色々とバックエンド側の構築方法を探っていました。Amplifyを使おうかと思っていたのですが、Flutterではdatastore周りが少し安定していない感がありまして、噂に聞いていたServerlessFrameworkを使ってみることにしました Flutter的にはバックエンドはFirebaseがメジャーだと思いますが、私のスキルセット的にAWS、LambdaもPythonで構築することにしました この記事でできること ServerlessFramework、AWSを使ったバックエンドの構築 APIGateway + Lambda + S3 + DynamoDBの構成 APIKeyを使ったREST APIのアクセス管理 S3やDynamoDBに対する、アクセスロールの設定 ルートディレクトリに集まりがちなfunctionを関数ごとにディレクトリ分け と、バックエンドを構築するときの一通りのことができるのではないかと思います。また、ServerlessFrameworkそのものの導入方法は割愛します。すでに詳しく解説されている記事がありますので 環境 Framework Core: 2.57.0 Plugin: 5.4.4 SDK: 4.3.0 Components: 3.16.0 初期化 % serverless create --template aws-python3 --name hello-world <<< Serverlessサービスを作る ServerlessFrameworkはサービスという単位で環境を作るそうです。上記のコマンドひとつで、Lambda1つを含む基本的なテンプレートが生成されます serverless.yml service: hello-world frameworkVersion: '2' provider: name: aws runtime: python3.8 lambdaHashingVersion: 20201221 functions: << これ以下を消すと、作ったLambdaを削除することもできる hello: handler: handler.hello <<< hander.pyとの紐付け handler.py import json def hello(event, context): body = { "message": "Go Serverless v1.0! Your function executed successfully!", "input": event } response = { "statusCode": 200, "body": json.dumps(body) } return response このテンプレートをベースにガリガリ触っていきます。ちなみに デフォルトだとバージニア北部リージョンにできる Lambdaは[サービス名]-[環境変数]-[serverless.ymlで指定した名前]でできる 実行ログのCloudWatch吐き出しもデフォルトで設定できるようである Amplifyと比べて、余計なファイルもできないし、デプロイもほぼ待ち時間はありません。全体的にシンプルで良いですね APIGateway > Lambda > DynamoDBの流れを作る serverless.yml service: hello-world frameworkVersion: '2' provider: name: aws runtime: python3.8 lambdaHashingVersion: 20201221 # ///////// ↓DynamoDBへのアクセス権限を追加↓ ///////////# iam: role: statements: - Effect: 'Allow' Action: - 'dynamodb:*' Resource: - "arn:aws:dynamodb:us-east-1:xxxxxxxxxx:table/*" # xxxxxxxxにはAWSのアカウント番号が入る # ///////// ↑DynamoDBへのアクセス権限を追加↑ ///////////# functions: hello: handler: handler.hello # ////////// ↓ここから下でAPIGatewayとDynamoDBを追加↓ ///////// # events: - httpApi: path: /users/create method: get resources: Resources: DynamoDbTable: Type: 'AWS::DynamoDB::Table' Properties: AttributeDefinitions: - AttributeName: id AttributeType: S - AttributeName: name AttributeType: S KeySchema: - AttributeName: id KeyType: HASH - AttributeName: name KeyType: RANGE ProvisionedThroughput: ReadCapacityUnits: 1 WriteCapacityUnits: 1 TableName: hello-dynamodb この時、Lambdaからはboto3を使ってDynamoDBにアクセスします handler.py def hello(event, context): dynamodb = boto3.resource('dynamodb') result = dynamodb.Table('hello-dynamodb').put_item( Item = { 'id': "hoge_id", 'name': 'hoge_name' } ) response = { "statusCode": 200, "body": json.dumps('success!') } return response デプロイをして再度実行すると、DynamoDBにも無事レコードが追加されました。Amplifyでは自動でcreated_at, updated_at, versionなどが付加されていましたが、今回は定義したもの以外は全くなく、非常にシンプルでした。 生成されたURLをブラウザで開いてみると、「success!」とだけ表示されました。成功ですね APIKeyを使ったREST APIのアクセス管理 このままだとAPIは全世界に公開されていて、URLを知ってさえいれば誰でもアクセスできてしまいます。これはこれで良いのですが、コール数を管理したり制限するときにはAPI Key(AWS的には使用量プラン)をつけます serverless.yml # 関連しないところは省略しています service: hello-world frameworkVersion: '2' provider: name: aws runtime: python3.8 lambdaHashingVersion: 20201221 stage: dev # api-keyがstageできりかわるようにするために追加 # ////////// ↓全function共通で使用するAPIKeyを追加↓ ////////// # apiGateway: apiKeys: # API Keyの設定 - mobileApp: - name: ${self:provider.stage}-app-key value: # お好みのAPI Key usagePlan: # 使用量プラン - mobileApp: quota: limit: 1000 offset: 0 period: DAY throttle: rateLimit: 100 burstLimit: 100 # ////////// ↑全function共通で使用するAPIKeyを追加↑ ////////// # functions: hello: handler: handler.hello events: - http: # httpApi -> http path: /users/create method: get private: true # ApiKeyをつけたいものにprivateをつける これで画像のようにAPI KeyをHeaderにつけてAPIコールしないと動かなくなります。(API Key無しだとForbidden) S3の作成と、functionごとへにアクセスロールの設定 serverless.yml custom: backetName: hello-serverless-bucket-${self:provider.stage} resources: Bucket: Type: AWS::S3::Bucket Properties: BucketName: ${self:custom.backetName} S3AccessRole: Type: AWS::IAM::Role DependsOn: Bucket Properties: Path: / RoleName: hello-serverless-lambda-role-with-s3 AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: sts:AssumeRole Policies: - PolicyName: hello-serverless-lambda-policy-with-s3 PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: - 'Fn::Join': - ':' - - 'arn:aws:logs' - Ref: 'AWS::Region' - Ref: 'AWS::AccountId' - 'log-group:/aws/lambda/*:*:*' - Effect: "Allow" Action: - "s3:PutObject" - "s3:GetObject" - "s3:ListBucket" Resource: - 'Fn::Join': - '' - - "arn:aws:s3:::" - ${self:custom.backetName} - 'Fn::Join': - '' - - "arn:aws:s3:::" - ${self:custom.backetName} - "/*" LambdaごとにAWSの各リソースに対するアクセス権限を付与しています Bucket名は定数化して環境ごとに切り替わるようにしています hendler.py def hello(event, context): filepath = '/tmp/data.csv' with open(filepath, 'w') as f: writer = csv.writer(f) writer.writerow(["a", "b", "c"]) s3 = boto3.resource('s3') s3.meta.client.upload_file(filepath, 'hello-serverless-bucket-dev', 'hgoe.csv') response = { "statusCode": 200, "body": json.dumps('success!') } return response Lambdaのコードは上記のようになります functionのディレクトリ分けと、外部ライブラリのアップロード functionは数十個になりうるのですが、このままだとServerlessのルートディレクトリに全て並べないといけなくなります。また、Lambdaがデフォルトでサポートしていない外部ライブラリを使う場合にアップロードする方法に迷いました これらを解決してくれるのが、ServerlessFrameworkのライブラリserverless-python-requirementsです。導入方法は公式を参照していただくのが良いかと思います。ちなみにDockerが必要です ディレクトリ構成 / ├── serverless.yml ├── functions/ │ ├── hello/ │ │ ├── handler.py │ │ └── requirement.txt こんな感じでfunctionごとにディレクトリを切ることができます。ちなみに、各ディレクトリ中のrequirement.txtには利用したい外部ライブラリを列挙するのですが、外部ライブラリを使わない場合でも必要です Serverless定義 serverless.yml service: hello-world frameworkVersion: '2' provider: name: aws runtime: python3.8 lambdaHashingVersion: 20201221 stage: dev plugins: # 追加 - serverless-python-requirements # 追加 custom: backetName: hello-serverless-bucket-${self:provider.stage} pythonRequirements: # 追加 dockerizePip: true # 追加 package: # 追加 individually: true # 追加 functions: hello: role: S3AccessRole module: functions/hello # 追加 handler: handler.hello events: - http: path: /users/create method: get private: true まとめ ServerlessFrameworkはやや情報が少ないのか、一度ハマると解決するのが結構大変でした(requirement.txtが必須とか)。今回の記事で、ServerlessFrameworkで、AWSを使って、Pythonを使う場合の基本的な内容はカバーできた気がします
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS新サービス「Resilience Hub」を使ってみた

今月GAされた新サービス。 耐障害性にフォーカスが当たっており、実装モノではなくチェックツール系のようです(Well-Architected Tool的な) https://aws.amazon.com/jp/blogs/news/monitor-and-improve-your-application-resiliency-with-resilience-hub/ とりあえずコンソールにアクセス マネコンにログインし、「Resilience Hub」を検索。あるある。 トップページはこんな感じ。日本語化はまだ…ですよね〜。 とりあえず「Add application」を押してみる。 なるほど、レジリエンスをチェックしたいアプリケーションを指定しろと。 検証用アプリをどうやって準備しようか問題。 ロースキルなインフラエンジニアがぶつかるいつもの壁。 「検証用のアプリケーションがない」…。業務用の検証環境で実験するわけにはいかないし。 困って公式ブログを読んでいると、「サンプルアプリ用意したよ」的な記述が! https://aws.amazon.com/jp/blogs/news/monitor-and-improve-your-application-resiliency-with-resilience-hub/ CDKかぁ。CloudFormationとかSAMみたいなもの? 「デプロイするだけです(キリッ」って書いてあるけど手順がイメージできないので、色々ググっていると「CDKワークショップ」なるハンズオン教材を発見! とりあえずこれやってみるか…。レジリエンスハブ起動への道のりは長い。 https://summit-online-japan-cdk.workshop.aws CDK入門ワークショップを進めてみて分かったこと まずローカル端末(Mac)にAWS CLIをインストールする。 で、そいつに初期設定としてデプロイ先にしたいAWSアカウントのIAMユーザーの認証情報(アクセスキー)を設定しておく。 あとは「cdk deploy」を実行する際のカレントディレクトリーにあるリソースがデプロイに利用されるというわけだ。 つまり、上記のサンプルアプリを事前にgit cloneしてローカル端末の作業用ディレクトリーにコピーしたうえで、ターミナルで当該ディレクトリーにcdしておけばよさそう。 あと「cdk bootstrap」というのはCDK利用時のおまじない的なもので、最初に実行することによりAWSアカウント側にCDKからデプロイされる準備をしてくれるっぽい。 超絶ハマった箇所 cdk bootstrapがめちゃエラーになる。ググっても手がかり見つからず、最終的にtypescriptのインストールがされていないことが原因と判明。 その後はCloudFormationの権限エラー。最終的に「MFA認証済みでないと参照操作しかできないIAMポリシー」が原因と判明。 それからcdk bootstrapは成功したものの、その後のcdk deploy --all時に「SSMのパラメーターが無いよ。bootstrapした??」って聞かれるエラーが解消できずに諦めた。。ここまでで3時間ほど消費。 インフラエンジニアが検証用アプリを手軽に構築できない問題、ホントにどうにかならんかな…。 仕方ないので何かの残骸っぽいアプリを流用してみる 既存のリソースグループを覗くと、何かの実験の残骸っぽいアプリ?があったのでとりあえず採用。 zangaiと命名して進むと、Step 2ではリソースを特定せよとのこと。 Not supported らしいが一つしか出てこないEKSクラスターを選択して次へ。 お次はポリシーを選択せよとのこと。まだ何もないので新規作成。 Suggested policies を選べば、自分のアプリのミッションクリティカル度に応じてテンプレから選択できる模様。参考としてアプリ/インフラそれぞれのRTOとRPOが記載されている。 作成したポリシーを選択し、zangaiアプリケーションをpublishした。 ワークフローが表示され、次は Assets resiliency へ進めとのこと。 レポート名を設定しRunすると、診断レポート的なものが作成されるらしい。Viewしてみる。 RTO、RPOともにハイフンになっているが、緑チェックが付き問題なさげな雰囲気。ホントか? Recommendatonsを覗いてみるが特に何も指摘はない様子。 FIS(Fault Injection Simulator)とコラボしてみる 次のステップは「Set up recommendations」だが、どうもAdditional informationが必要らしい。 そのためには先日リリースされたFIS(Fault injection simulator)を実行しろとのこと。 試しにFISの実験テンプレートをいくつか作成してみたが、Resilience Hubに出現してこなかった。 よって現時点で触れそうなところはここまで。 ワークフローを見た感じ、最後は「Run experiments」になっているので、FISのテンプレートが正しく設定できればモンキーテストを実施してみて耐障害性をテストする、というのがこのツールの使い方っぽい。 まとめ 以上より、まともなサンプルアプリが用意できず非常に微妙だったが、なんとなくツールの流れはイメージできた。 最近出てきた Fault Injection Simulator との連携色が濃いサービスであることも分かった。 実業務でもFISとセットで活用を検討してみたい。 (そのためにはRPO、RTOといった非機能要件が定義されていることが大前提だが…) あと、様々なAWSサービスをちゃんと実験できるように、インフラエンジニアなりにも検証用アプリケーションぐらいはちゃんと準備しておこうと思いました。。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS SAMでアプリケーションをローカルテスト&デプロイ

はじめに こちらの記事で作成した環境をテンプレート化したい!と思ったので、 AWS SAMを使ってみました。 SAMはリソースをプロビジョニングできるだけでなく、ローカルでLambda、API Gatewayをテストできる便利ツールだったのでその使い方も紹介します。 途中、cloudformationコマンドとの比較もしていますのでご参考までに。 環境 mac OS:Monterey 12.0.1 AWS CLI:2.2.33 SAM CLI:1.35.0 SAMとは AWS Serverless Application Modelの略 サーバーレスアプリケーション構築用のオープンソースフレームワーク YAML,JSON形式でテンプレート記述 CloudFormationの拡張機能で、簡単にテンプレートを記述することが可能 SAM CLIあり SAM CLIのインストール こちらからどうぞ SAM利用の流れ SAMテンプレートの記述 パッケージング デプロイ 1. SAMテンプレートの記述 テンプレート構造 実際のコード template.yaml AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: AWS SAM Serverless demo Resources: TranslateLambda: Type: AWS::Serverless::Function Properties: FunctionName: translation-function CodeUri: translation-function/ Handler: translation-function.lambda_handler Runtime: python3.8 Timeout: 5 MemorySize: 256 Policies: - TranslateFullAccess Events: GetApi: Type: Api Properties: Path: /translate Method: get RestApiId: Ref: TranslateAPI TranslateAPI: Type: AWS::Serverless::Api Properties: Name: translate-api StageName: dev EndpointConfiguration: REGIONAL TranslateDynamoDbTbl: Type: AWS::Serverless::SimpleTable Properties: TableName: tranlate-history PrimaryKey: Name: timestamp Type: String ProvisionedThroughput: ReadCapacityUnits: 1 WriteCapacityUnits: 1 1. リソースタイプの選択 AWS::Serverless::Function AWS::Serverless::Api AWS::Serverless::SimpleTable など 2. リソースタイプごとに必要なプロパティを記述 AWS::Serverless::Functionであれば、 Handler,Runtimeが必須 CodeUri,InlineCodeのいずれか必須 など 2. パッケージング  デプロイするためにzip化し、S3にアップロードする s3パスをSAMテンプレートのCodeUriに記載する必要がある パッケージングコマンドで、アプリケーションをzip化し、CodeUriを書き換えている パッケージングには2つの方法がある cloudformationコマンド SAM CLI cloudformationコマンド実行 ※AWS CLIインストールかつログイン済みであることが前提 aws cloudformation package \ --template-file template.yaml \ --s3-bucket serverless-sam-demo \ --output-template-file packaged-template.yaml コマンド実行後、下記ファイルが出力される packaged-template.yaml AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: AWS SAM Serverless demo Resources: TranslateLambda: Type: AWS::Serverless::Function Properties: FunctionName: translation-function CodeUri: s3://serverless-sam-demo/************* Handler: translation-function.lambda_handler Runtime: python3.8 Timeout: 5 MemorySize: 256 Policies: - TranslateFullAccess Events: GetApi: Type: Api Properties: Path: /translate Method: get RestApiId: Ref: TranslateAPI TranslateAPI: Type: AWS::Serverless::Api Properties: Name: translate-api StageName: dev EndpointConfiguration: REGIONAL TranslateDynamoDbTbl: Type: AWS::Serverless::SimpleTable Properties: TableName: translate-history PrimaryKey: Name: timestamp Type: String ProvisionedThroughput: ReadCapacityUnits: 1 WriteCapacityUnits: 1 パッケージ前 AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: AWS SAM Serverless demo Resources: TranslateLambda: Type: AWS::Serverless::Function Properties: FunctionName: translation-function CodeUri: translation-function/ Handler: translation-function.lambda_handler パッケージ後 Resources: TranslateLambda: Type: AWS::Serverless::Function Properties: FunctionName: translation-function CodeUri: s3://serverless-sam-demo/************* Handler: translation-function.lambda_handler 先ほどのyamlファイルのcodeuriの表記が変わっていることが確認できます さらにS3を見ると、確かにアップされている! SAM CLIでビルド コマンドはたったこれだけ sam build 実行結果 (base) ~~~~~@~~~~~~~~~ sam-serverless-demo % sam build Building codeuri: /Users/***********/sam-serverless-demo/translate-function runtime: python3.8 metadata: {} architecture: x86_64 functions: ['TranslateLambda'] requirements.txt file not found. Continuing the build without dependencies. Running PythonPipBuilder:CopySource Skipping copy operation since source /Users/ohsugiryoya/sam-serverless-demo/translate-function does not exist Build Succeeded Built Artifacts : .aws-sam/build Built Template : .aws-sam/build/template.yaml Commands you can use next ========================= [*] Invoke Function: sam local invoke [*] Deploy: sam deploy --guided .aws-sam/buildが作成され、配下に下記テンプレートファイルが作成される template.yaml AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: AWS SAM Serverless demo Resources: TranslateLambda: Type: AWS::Serverless::Function Properties: FunctionName: translation-function CodeUri: TranslateLambda Handler: translation-function.lambda_handler Runtime: python3.8 Timeout: 5 MemorySize: 256 Policies: - TranslateFullAccess Events: GetApi: Type: Api Properties: Path: /translate Method: get RestApiId: Ref: TranslateAPI TranslateAPI: Type: AWS::Serverless::Api Properties: Name: translate-api StageName: dev EndpointConfiguration: REGIONAL TranslateDynamoDbTbl: Type: AWS::Serverless::SimpleTable Properties: TableName: tranlate-history PrimaryKey: Name: timestamp Type: String ProvisionedThroughput: ReadCapacityUnits: 1 WriteCapacityUnits: 1 先ほどと異なりCodeUriがS3リンクになっていないが、バケットとオブジェクトが作成されていました 3. デプロイ デプロイコマンドで、cloudformation本来のテンプレートに変換されリソースが作成される cloudformationコマンド実行 aws cloudformation deploy \ --template-file ./packaged-template.yaml --stack-name serverless-sam-demo --capabilities CAPABILITY_IAM SAM CLIでデプロイ インタラクティブに実行することが可能 sam deploy --guided (base) sam-serverless-demo % sam deploy --guided Configuring SAM deploy ====================== Looking for config file [samconfig.toml] : Found Reading default arguments : Success Setting default arguments for 'sam deploy' ========================================= Stack Name [sam-app-demo]: AWS Region [ap-northeast-1]: #Shows you resources changes to be deployed and require a 'Y' to initiate deploy #変更点の確認 Confirm changes before deploy [Y/n]: y #SAM needs permission to be able to create roles to connect to the resources in your template Allow SAM CLI IAM role creation [Y/n]: y #Preserves the state of previously provisioned resources when an operation fails Disable rollback [Y/n]: y #パブリックに公開する TranslateLambda may not have authorization defined, Is this okay? [y/N]: y Save arguments to configuration file [Y/n]: y SAM configuration file [samconfig.toml]: SAM configuration environment [default]: Looking for resources needed for deployment: Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-w09u3i2wjkab A different default S3 bucket can be set in samconfig.toml Saved arguments to config file Running 'sam deploy' for future deployments will use the parameters saved above. The above parameters can be changed by modifying samconfig.toml Learn more about samconfig.toml syntax at https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html できた!! ローカル環境でテスト実行 SAMを使って感じたことは、ローカルでテスト実行することができる点だと感じました。 lambda、api gatewayだけのようなシンプルな構成はローカルテスト可能です。 上記で作成したものはdynamoDBやtranslate apiを使用しているので、ローカル環境ではエラーがでます。 ソースコードの構文チェック sam validate 関数をローカルで呼び出す sam local invoke Lambda ローカルテスト sam local start-lambda #別ターミナルで以下コマンド叩く aws lambda invoke --function-name "TranslateLambda" \ --endpoint-url "http://127.0.0.1:3001" \ --no-verify-ssl out.txt API Gateway ローカルテスト sam local start-api #別ターミナルで以下コマンド叩く curl -w "\n" http://127.0.0.1:3000/translate (参考)ハマりポイント 初回デプロイ時エラーからの再デプロイ Initiating deployment ===================== Uploading to sam-app-demo/ec906befd23684dfd9dd718c1f5d6539.template 1114 / 1114 (100.00%) Error: Failed to create changeset for the stack: sam-app-demo, An error occurred (ValidationError) when calling the CreateChangeSet operation: Stack:arn:aws:cloudformation:ap-northeast-1:624840664351:stack/sam-app-demo/515b2930-49e5-11ec-865e-06680d75238d is in DELETE_FAILED state and can not be updated. ⇨スタックを削除してから再デプロイする aws cloudformation delete-stack --stack-name hogehoge FAILEDとなった時の対処法 aws cloudformation describe-stack-events \ --stack-name sam-app-demo \ | jq '.StackEvents[] \ | select(.ResourceStatus == "CREATE_FAILED") \ | .ResourceStatusReason' -r
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS初学者向け】翻訳WEB APIを作成してみた(ハンズオン)

はじめに AWSハンズオン資料集の中から「サーバーレスアーキテクチャで翻訳 Web API を構築する」を試してみて結構楽しかったので AWS初学者向けに構築フロー つまずきポイント 個人的に修正してみた箇所 の3点を共有します。 上記、URLからAWS初学者の方はぜひトライしてみてください。 参考ドキュメント 構成 (ハンズオン資料より抜粋) ブラウザで翻訳語の文字列が返ってくれば完成 LambdaからAWS Translateを呼び出す LambdaからAWS Translateを呼び出すためには、python SDK のboto3を使用します。 公式ドキュメントからtranslateの項目を確認し、使い方を参照します。 必須パラメータは、下記の通り response = client.translate_text( Text='string', SourceLanguageCode='string', TargetLanguageCode='string', } ) レスポンスは下記のように返ってくるとのこと import json import boto3 translate = boto3.client('translate') def lambda_handler(event, context): input_text = 'こんにちは' #日本語→英語への変換 response = translate.translate_text( Text=input_text, SourceLanguageCode='ja', TargetLanguageCode='en' ) output_text = response.get('TranslatedText') return { 'statusCode': 200, 'body': json.dumps({ 'output_text': output_text }), } API Gatewayを設定し、Lambdaのソースコードを修正する アクションからリソースの作成→メソッドの作成を行う クエリ文字列パラメータの設定 API Gateway統合レスポンスで検索すると、 Lambda プロキシ統合で、Lambda 関数は以下の形式で出力を返す必要があることがわかります。 { statusCode: "...", // a valid HTTP status code headers: { custom-header: "..." // any API-specific custom header }, body: "...", // a JSON string. isBase64Encoded: true|false // for binary support } コード修正 import boto3 translate = boto3.client('translate') input_text = event['queryStringParameters']['input_text'] response = translate.translate_text( Text=input_text, SourceLanguageCode='ja', TargetLanguageCode='en' ) output_text = response.get('TranslatedText') return { 'statusCode': 200, 'body': json.dumps({ 'output_text': output_text }), 'isBase64Encoded': False, 'headers': {} } DynamoDBに入力テキストと変換後テキストを格納する 事前にテーブルを作成する必要あり 修正箇所 import datetime dynamodb = boto3.resource('dynamodb') translate_history_table = dynamodb.Table('tranlate-history') translate_history_table.put_item( Item = { 'timestamp': datetime.datetime.now().strftime("%Y%m%d%H%M%S"), 'input_text': input_text, 'output_text': output_text } ) Lambda関数全体 import json import boto3 import datetime translate = boto3.client('translate') dynamodb = boto3.resource('dynamodb') translate_history_table = dynamodb.Table('translate-history') def lambda_handler(event, context): input_text = event['queryStringParameters']['input_text'] response = translate.translate_text( Text=input_text, SourceLanguageCode='ja', TargetLanguageCode='en' ) output_text = response.get('TranslatedText') translate_history_table.put_item( Item = { 'timestamp': datetime.datetime.now().strftime("%Y%m%d%H%M%S"), 'input_text': input_text, 'output_text': output_text } ) return { 'statusCode': 200, 'body': json.dumps({ 'output_text': output_text }), 'isBase64Encoded': False, 'headers': {} } つまずきポイント https://*******.execute-api.ap-northeast-1.amazonaws.com/Stage/translate?input_text=こんにちは あれ、返ってこない、、、 結論:dynamoDBへの実行ロールを付与し忘れ 余談 api gatewayは、作成するときに自動的にロール付与してくれたな。。 個人的に工夫した点 任意のステータスコードを返すようにLambda関数にエラーハンドリングを実装 import json import boto3 import datetime import logging translate = boto3.client('translate') dynamodb = boto3.resource('dynamodb') translate_history_table = dynamodb.Table('tranlate-history') def lambda_handler(event, context): input_text = event['queryStringParameters']['input_text'] #追加箇所 try: response = translate.translate_text( Text=input_text, SourceLanguageCode='ja', TargetLanguageCode='en' ) except Exception : raise ExtendException(400, "Bad Request") output_text = response.get('TranslatedText') translate_history_table.put_item( Item = { 'timestamp': datetime.datetime.now().strftime("%Y%m%d%H%M%S"), 'input_text': input_text, 'output_text': output_text } ) return { 'statusCode': 200, 'body': json.dumps({ 'output_text': output_text }), 'isBase64Encoded': False, 'headers': {} } #追加箇所 class ExtendException(Exception): def __init__(self, statusCode, description): self.statusCode = statusCode self.description = description def __str__(self): obj = { "statusCode": self.statusCode, "description": self.description } return json.dumps(obj) まとめ SAA資格勉強での知識しかなかった私にはとても有用なハンズオンでした。 次は、SAMでデプロイの自動化を実装したいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Route53

【AWS Route53】 DNS, Route53の理解は障害対策、トラブルシューティング時に必要不可欠。 CluldTechを通じて、基本から勉強しました! AWS公式:Route53は、ロードバランサーの代替ではなく拡張機能である旨が明示されている。 ELBのヘルスチェック ロードバランサがどのバックエンドインスタンスにトラフィックをルーティングするかを判断 Route 53のヘルスチェック 重み付けラウンドロビンやDNSフェールオーバーで、どのIPアドレスを回答に含めるかを判断 IPアドレスかエンドポイントがあるもの、ELBやRDSにも分散が可能。 Amazon Route53(Hosted Zone) = ネームサーバー AWSが提供するDNSサービス(フルマネージド型のDNSサービス) Amazonが管理してくれる。 単なるDNSサーバーとしての活用も可能 AWSから自動で割り当てられるドメイン名ではなく、独自ドメイン名で運用を行いたい場合に必要。 Hosted Zoneでドメイン名のリソースレコードを管理 作成したHosted Zoneごとに、NSレコードとSOAレコードを自動的に作成 NSレコード:ドメイン情報を管理するサーバを表したレコード SOAレコード:ドメインの管理情報を表したレコード 1つのHosted ZoneにネームサーバのFDQNを4つ割り当て。 4つのトップレベルドメイン(*.com, *.org, *.net, *.co.uk)にまたがる。 可能性に考慮して作成されているので、レコードを変更しないようにする。 特定のVPCからの問い合わせと、それ以外からの問い合わせを識別し、異なる応答を返す。 Public Hosted Zone インターネットを含む特定のVPC以外向け インターネット上に公開されたDNSドメインのレコードを管理するコンテナ Private Hosted Zone 特定のVPC向け VPCに閉じたプライベートネットワーク内のDNSドメインのレコードを管理するコンテナ エイリアスレコード Amazon Route53 固有の機能 一般的なDNSの仕組みを拡張したAWSオリジナルのレコード ドメインとAWSリソースを関連付ける。 最終的にユーザーが必要とするレコードデータのみを取得する。 問い合わせ元にCNAMEを応答しない。 CNAME:ドメインとURLを関連付けるもの。(エイリアスレコードと非常に似ている) CNAMEレコードは、ドメインを一旦、AWSリソースのドメインに置き換えて、そこからIPアドレスに変換する。 CNAMEを利用しないことで、Zone Apex(サブドメインを含まないドメイン名)でサービスをホスト可能とする。 エイリアスレコードは、ドメインからIPアドレスに変換できる。 CNAMEレコードと比較して、変換の回数が異なり、応答速度に違いが出る。 Route53によるトラフィックルーティング DNSの応答をカスタマイズすることで、クライアントからのトラフィックをより適したリソースにルーティング レコードの作成時に、Route53がクエリに応答する方法を決定するルーティングポリシーを選択。 トラフィックルーティングの種類 シンプル(いわゆるDNSラウンドロビン) 従来のDNSと同様に、静的なマッピングによりルーティングが決定される。 複数の値を1つのレコードに指定すると、すべての値をランダムな順序で応答。 加重 指定した比率で複数のリソースにトラフィックをルーティング より重み付けの高いリソースにより多くルーティング 例)段階的な移行(Blue/Greenデプロイ)、サーバーの負荷平準化 フェイルオーバー ヘルスチェックの結果に基づいて利用可能なリソースのみを応答 アクティブ/アクティブおよびアクティブ/パッシブ構成を実現 フェイルオーバー条件は、複数のヘルスチェック結果を結合するなどのカスタマイズ可能 例)複数リージョンにまたがるシステムで冗長構成 例)S3静的ウエブサイトホスティングのSorry Pageを表示 クライアントに対して、「サイトメンテナンス中」等のページを表示する。 プライマリ > セカンダリ という通信の優先順位付けの設定ができる。 プライマリで異常が発生した時は、セカンダリに通信をフェイルオーバー Route53がドメインに対してヘルスチェックをしてくれる。 S3の静的Webサイトホスティング機能を利用し、障害時に表示するHTMLファイルを用意   ※ フェイルオーバールーティングは、デモをおこないました。(Sorry Pageを表示)    → 自分で手を動かしてみることで理解度が増します。 複数値回答 最大8つのランダムに選択された正常なレコードでDNSクエリに応答 各リソースが正常かどうかも確認し、正常なリソースの値のみを応答 応答をキャッシュされた後にリソースが使用できなくなった場合にも、クライアントは応答内の別のIPアドレスを利用できる。 レイテンシー 複数のAWSリージョンでアプリケーションがホストされている場合 ネットワークレイテンシーが最も低いAWSリージョンのリソースを応答 一定期間中に実行されたレイテンシーの測定値に基づいている。 時間の経過と共にルーティンされるAWSリージョンが変化する場合がある。 位置情報 クライアントの位置情報に基づいて、DNSクエリに応答 特定の地域や国からのDNSクエリに対して、特定のアドレスを応答 クライアントの地域により適切な言語でコンテンツを提供 ライセンス許可をした市場のみに制限 物理的近接性 ユーザーとリソースの地理的場所に基づいてDNSクエリに応答 トラフィックフロー(ポリシーベース:簡単に作成や管理できる機能)を使用する必要がある。 ビジュアルエディタ トラフィックポリシーバージョン ポリシーレコード Amazon Route53 Resolver VPCに標準で備わるDNSサーバー(フォワーダーとフルサービスリゾルバー) VPC作成時にデフォルトで有効 VPC毎に有効/無効に設定可能 IPアドレス設定はDHCPで自動的に配布される。 インターネットに公開されたZoneと内部に閉じたDNS Zoneを解決する。 VPC外からのDNSクエリは受け付けない。 VPC内のインスタンスから発生するDNSクエリには無料 テストとトラブルシューティング テスト 実際にエンドポイントに対して、問い合わせを試行する。 Linux:dig digコマンド $ dig @172.31.0.2 www.example.com. A +rec +all - 参照したいFQDN(必須):(www.example.com) - 以下、省略可能。省略すると以下の内容に保補完される。 - 参照先:スタブリゾルバの参照先(/etc/resol.confのネームサーバ) - クエリタイプ:A - オプション:+rec(再起問い合わせ) +all(表示指定を全て有効) トラブルシューティング 原因がどこか特定する。 再帰的問い合わせと反復問い合わせを明確に区別して、試行する。 出力情報やオプションが豊富なdigコマンドが有用。 ヘッダのstatus, flagsに着目しよう。 DNS(Domain Name System)のおさらい DNSは、FQDNをキーに対応するIPアドレスなどの情報を取得する仕組み DNSから情報取得することを「名前解決」 各ネームサーバが管理する名前空間を「ゾーン」 ホスト名とFQDN(完全修飾ドメイン名) ホスト名 サーバや端末に付けられた名前 ノードが一意に識別されることを前提にしていない相対的な名前 FQDN(完全修飾ドメイン名) サブドメインからトップレベルドメインまで完全に指定されたホスト名 ホスト名に「どこの」という修飾語を付ける。 「どこの」を設定したものを「レコード」 レコードを構成する要素:NAME, TTL, CLASS, TYPE, RDATA 1つ1つの設定のことを、「レコードセット」または「リソースレコード」 それらの設定の集合体を「ホストゾーン」 特定のドメイン名空間において、ノードを一意に識別が可能な名前 DNSサーバーとは DNSサーバーは、以下、4つの異なる機能を持つ実装 ネームサーバー ルートを起点に全てのFQDNを探索できるように構成された分散DB それを成すひとつひとつのサーバー 権威DNSサーバ(Authoritative Serverと表現される場合も) 世界中のユーザーから利用されるが負荷が大きくなる。これを対策するため。 権限委譲元:親ゾーン  権限委譲先:子ゾーン 親ゾーンから子ゾーンのネームサーバーをFQDNで指し示し、権限委譲 子ゾーンのネームサーバーのFQDNが、子ゾーンで管理されている場合、親ゾーンの返答にそのIPアドレスを含めて指し示す。(Glueレコード) フルサービスリゾルバー ルートから順にネームサーバに問い合わせ、得られた回答を問い合わせ元に返す。 効率化のため、所定の期間(TTL)キャッシュを保持 反復問い合わせを受け取った場合、自らが保有している情報を回答する。 ネームサーバへの反復問い合わせは行わない。 スタブリゾルバー 一般に、OSに組み込まれたDNSクライアント ルートからネームサーバを辿る反復問い合わせの機能を持たない。 常に再帰的問い合わせを行う。 キャッシュの有無は実装に依存する。 スタブリゾルバーの制約 複数のDNSサーバーに対し、ドメイン毎に振り分けたり、同時に利用したりする機能は有していない。 複数サーバーを指定するのは、障害時のフォールバックのため。 名前解決に失敗した場合、順に問い合わせため。 耐障害性を高めるため。 フォワーダー 受け取った問い合わせを、ルールに基づいて中継する。 ルートからネームサーバを辿る反復問い合わせの機能を持たない。 常に再帰的問い合わせを行う 効率化のため、所定の期間(TTL)キャッシュを保持 フォワーダーの制約 インターネット向けネームサーバーと内部ネットワーク向けネームサーバーで同じドメイン名を利用している場合に両方を参照することができない。 ドメインやホスト名を分ける、必要なレコードを同期させるなどの必要がある。 再帰的問い合わせと反復問い合わせ 反復問い合わせは、自らがネームサーバを辿る時に行う問い合わせ 再帰的問い合わせは、問い合わせ先に反復問い合わせを依頼する問い合わせ 企業ネットワークのよくあるDNSサーバー構成 フォワーダー、フルサービスリゾルバー、ネームサーバーが同居して、1つのDNSサーバを構成 参考 CloudTech 【AWS Black Belt Online Seminar】Amazon Route 53 Resolver 【AWS Black Belt Online Seminar】Amazon Route 53 Hosted Zone おわりに。 この記事はAWS初学者を導く体系的な動画学習サービス 「AWS CloudTech」の課題カリキュラムで作成しました。 https://aws-cloud-tech.com
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS CDK(Python)でアカウントIDを含むS3バケットを作る

この記事は ハンズラボ AdventCalendar2021 1日目の記事です。 プログラム言語でAWSインフラを定義できるという AWS CDK を試してみました。言語はPython3を利用します。 インストール Node、Python3、virtualenvが必須のため事前にセットアップ。 私の環境ではpyenvも導入しています。 $ node -v v12.12.0 $ python -V Python 3.8.6 $ virtualenv --version virtualenv 20.10.0 from /Users/xxxx/.pyenv/versions/3.8.6/lib/python3.8/site-packages/virtualenv/__init__.py 早速CDKをインストールします。 $ npm install -g aws-cdk # インストール確認 $ cdk --version 1.134.0 (build dd5e12d) 初期設定 今回の検証用ディレクトリを作成し、そこで初期設定を行います。 $ mkdir cdk_practice $ cd cdk_practice $ cdk init app --language python source .venv/bin/activate → pip install -r requirements.txt を実行しなさい、とメッセージが表示されますが私は pipenv を使いたいので小細工をします。 特にこだわりのない方はメッセージに従ってコマンドを実行することをおすすめします。 # デフォルトで作成された仮想環境を削除 $ rm -rf .venv # pipenvで再セットアップ $ export PIPENV_VENV_IN_PROJECT=true $ pipenv --python 3 # ライブラリインストール $ pipenv install $ pipenv install --dev -r ./requirements-dev.txt # もう使わないので削除 $ rm -rf requirements*.txt # 仮想環境有効化 $ pipenv shell コーディング ドキュメントによるとCDKでは構築したいサービスに対応するコアモジュールをインストールする必要があるようです。命名規則は aws-cdk.SERVICE-NAME とのことです。今回はS3バケットを作成したいので、以下のコマンドを実行しS3用モジュールをインストールします。 $ pipenv install aws-cdk.aws-s3 次はコードを見ていきます。主に修正を行うのは app.py と cdk_practice/cdk_practice_stack.py のようです。過去のバージョンでは setup.py も存在していたようですが、現在のバージョンでは配置されないようです。 app.py 初期化直後の app.py はこんな感じです。 #!/usr/bin/env python3 import os from aws_cdk import core as cdk # For consistency with TypeScript code, `cdk` is the preferred import name for # the CDK's core module. The following line also imports it as `core` for use # with examples from the CDK Developer's Guide, which are in the process of # being updated to use `cdk`. You may delete this import if you don't need it. from aws_cdk import core from cdk_practice.cdk_practice_stack import CdkPracticeStack app = core.App() CdkPracticeStack(app, "CdkPracticeStack", # If you don't specify 'env', this stack will be environment-agnostic. # Account/Region-dependent features and context lookups will not work, # but a single synthesized template can be deployed anywhere. # Uncomment the next line to specialize this stack for the AWS Account # and Region that are implied by the current CLI configuration. #env=core.Environment(account=os.getenv('CDK_DEFAULT_ACCOUNT'), region=os.getenv('CDK_DEFAULT_REGION')), # Uncomment the next line if you know exactly what Account and Region you # want to deploy the stack to. */ #env=core.Environment(account='123456789012', region='us-east-1'), # For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html ) app.synth() これに以下の通り修正を加えました。 from aws_cdk import core as cdk でimportするのが推奨というコメントに従い from aws_cdk import core を削除 CdkPracticeStackにenv追加 #!/usr/bin/env python3 import os from aws_cdk import core as cdk from cdk_practice.cdk_practice_stack import CdkPracticeStack app = cdk.App() CdkPracticeStack(app, "CdkPracticeStack",env=cdk.Environment(region='ap-northeast-1.')) app.synth() 複数のスタックを管理したい場合はCdkPracticeStackと同様の定義を追加していけば良さそうですね。 cdk_practice_stack.py 次は初期化直後の cdk_practice/cdk_practice_stack.py です。 from aws_cdk import ( core as cdk # aws_sqs as sqs, ) # For consistency with other languages, `cdk` is the preferred import name for # the CDK's core module. The following line also imports it as `core` for use # with examples from the CDK Developer's Guide, which are in the process of # being updated to use `cdk`. You may delete this import if you don't need it. from aws_cdk import core class CdkPracticeStack(cdk.Stack): def __init__(self, scope: cdk.Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) # The code that defines your stack goes here # example resource # queue = sqs.Queue( # self, "CdkPracticeQueue", # visibility_timeout=cdk.Duration.seconds(300), # ) 今回構築したいS3バケットの仕様は以下の通りです。 バケット名重複防止のためバケット名にAWSアカウントIDを含ませる デフォルトキーを利用してサーバーサイドで暗号化する ファイルの有効期限を1年とする スタックが削除されたら合わせて削除する コアモジュールの仕様書と睨めっこしながら書き上げたコードがこちらです。 from aws_cdk import ( core as cdk, aws_s3 as s3, ) class CdkPracticeStack(cdk.Stack): def __init__(self, scope: cdk.Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) # アカウントIDの取得 accountId = cdk.Aws.ACCOUNT_ID # バケットの作成 bucket = s3.Bucket(self, 'cdkpracticebucket', # サーバーサイド暗号化 encryption=s3.BucketEncryption.S3_MANAGED, # バケット名にアカウントIDを付与 # f'hogehoge-{accountId}'だとNG bucket_name= 'cdkpracticebucket-' + accountId ) # 1年経過で削除するライフサイクルルールを追加 bucket.add_lifecycle_rule( enabled=True, expiration=cdk.Duration.days(365) ) # スタック削除時に一緒に削除 bucket.apply_removal_policy(cdk.RemovalPolicy.DESTROY) テンプレート生成 以下のコマンドを実行すると記述した定義をもとにCloudFormationテンプレート(yaml形式)が生成され、標準出力に表示されます。定義に誤りがある場合はエラーになります。 $ cdk synth 今回はこのようなテンプレートになりました。また/cdk.outにも同様にテンプレートが出力されるようです。 Resources: cdkpracticebucket59CD39AD: Type: AWS::S3::Bucket Properties: BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 BucketName: Fn::Join: - "" - - cdkpracticebucket- - Ref: AWS::AccountId LifecycleConfiguration: Rules: - ExpirationInDays: 365 Status: Enabled UpdateReplacePolicy: Delete DeletionPolicy: Delete Metadata: aws:cdk:path: CdkPracticeStack/cdkpracticebucket/Resource CDKMetadata: Type: AWS::CDK::Metadata Properties: Modules: aws-cdk=1.134.0 デプロイ テンプレートを見た感じ問題なさそうですのでデプロイしていきます。ここからはAWSアカウントに対するcredentialが必要ですので、別途設定してください。 $ cdk deploy うまくいきました。 S3バケットが作成されています。 暗号化やライフサイクルルールも大丈夫そうです。 後片付け 一通り検証できたので後片付けをします。削除コマンドは cdk destroy です。 $ cdk destroy Are you sure you want to delete: CdkPracticeStack (y/n)? y CdkPracticeStack: destroying... ✅ CdkPracticeStack: destroyed 削除できました。 apply_removal_policy を指定していたのでバケットも消えています。指定しなかった場合、デフォルト設定がRETAINのため削除がスキップされます。 ハマりポイント バケット名にアカウント名を含める際、CloudFormationでは擬似パラメーターを活用してこのように書くことが多いです。 !Sub hogehoge-${AWS::AccountId} CDKでアカウントIDを取得したい場合は aws_cdk.core.Aws を見れば良いようです。 そこでPythonでも同じようにbucket_nameを指定してみたところエラー。 bucket_name= f'cdkpracticebucket-{accountId}' 色々と調査した結果、以下の記述だとテンプレートに変換することができました。 bucket_name= 'cdkpracticebucket-' + accountId 生成されたテンプレートでは、Fn::Joinを利用した形式に自動変換されていました。加算演算子を使った場合のみ、CDK内部で何らかの変換処理が行われているものと思われます。 BucketName: Fn::Join: - "" - - cdkpracticebucket- - Ref: AWS::AccountId バケット名のような文字列のみ受け付けるパラメータに擬似パラメータを渡したい場合は工夫が必要のようです。 感想 上記のハマりなどもあり最初は苦労しました。しかし、一般のプログラム言語を利用していることからIDEの豊富な支援をそのまま受けることができ、補完機能なども多数扱えるためノウハウが溜まればCloudFormationより高速に構築できるようになる可能性を感じました。テストの実施もできるようですので、もう少し深掘りして検証を行ってみても良いかもしれません。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

1年でAWS全冠(11冠)したのでいろいろ語っていく

AWSを業務にして、1年でAWS全冠(11冠)したので、 これから資格取得に向けて頑張ろうと思っている人の助けになればと思います。 自己紹介(AWS資格取得する前) ・ネットワークエンジニア 設計・構築3年 ・保持資格(当時)  LinuC-2  旧CCNP  基本情報技術者 全冠までの履歴 全冠合格までの道のりを振り返ります。 一応、一度も落ちずに全冠できました。 合格できると確信できるまで勉強していたこともあるので、 要領が良い人は半分くらいの時間で合格できるのでは?っと思っています。 ※勉強時間はStudy Plusにて測定(分は省略) 略号 資格名 合格日 点数 勉強時間(時) SAA ソリューションアーキテクト – アソシエイト 2020/11/29 747 135 SAP ソリューションアーキテクト – プロフェッショナル 2021/3/30 840 400 SOA システムオペレーション アドミニストレーター – アソシエイト 2021/4/24 886 70 DVA デベロッパー – アソシエイト 2021/5/3 840 29 CLF クラウドプラクティショナー 2021/5/3 905 8 DOP DevOps エンジニア – プロフェッショナル 2021/6/19 821 109 ANS 高度なネットワーキング – 専門知識 2021/7/17 821 52 SCS セキュリティ – 専門知識 2021/8/14 898 40 DAS データアナリティクス – 専門知識 2021/9/4 807 63 MLS 機械学習 – 専門知識 2021/10/2 865 79 DBS データベース – 専門知識 2021/10/24 804 50 難易度ランキング 個人的な難易度ランキングです。 参考程度と思ってください。 プロフェッショナルが上位にランクインするのは同じだと思っていますが、 特に専門分野は、バックグラウンドによってかなり左右されます。 例えば、「高度なネットワーキングが一番難しかった」 というのをよく目にしますが、 ネットワークエンジニアだった私からすれば、 専門分野で一番簡単だったと感じました。 私は、専門分野で難しかったと感じたのは、 今まで触れたこともなかった データアナリティクス(DAS)、機械学習(MLS)です。 また、開発経験がなかったので、DVA、DOPも難しく感じました。 順位 略号 資格名 1 SAP ソリューションアーキテクト – プロフェッショナル 2 DOP DevOps エンジニア – プロフェッショナル 3 MLS 機械学習 – 専門知識 4 DAS データアナリティクス – 専門知識 5 DBS データベース – 専門知識 6 SCS セキュリティ – 専門知識 7 ANS 高度なネットワーキング – 専門知識 8 DVA デベロッパー – アソシエイト 9 SAA ソリューションアーキテクト – アソシエイト 10 SOA システムオペレーション アドミニストレーター – アソシエイト 11 CLF クラウドプラクティショナー 勉強方法 勉強方法はホントに人それぞれだと思いました。 ホワイトペーパーを読めとか言われたことがありましたが、 正直何を言っているかわからず、あまり頭に入ってこなかったですw 初学者に最初からホワイトペーパーを読むと心が折れてしまうと思っています。 私のように理解力の低い人間や初学者の方には、 まずAWS公式が無料で出している Exam Readinessを受けるのお勧めします。 ※日本語バージョンがあるやつないやつありますが、  ないやつはgoogle翻訳使うとうまくいくといかないとか・・・ ※参考にSAAのExam Readinessのリンクを貼っておきます。 ・Exam Readiness SAA Exam Readinessは、 何から勉強したらいいか、試験範囲、問題の解き方 などを解説してくれているので、 資格取得までの助走としてはかなり有効と私は考えています。 何から始めたらいいかわからない人は、 Exam Readinessから始めるとよいと思います。 Exam Readiness受講後は、 試験対象のサービスのBlackBeltを見て概要を見ましょう。 ・BlackBelt BlackBeltを見終わったら、その後は公式ドキュメントを読んで深めるか、 問題集に取り掛かることになると思います。 英語が読める人は下記サイトもお勧めです。 ・Jayendra's Cloud Certification Blog 私は問題集をひたすら解きまくりました。 問題集を解いていき、 なぜこの選択肢が正解かを理解するのはもちろんですが、 他の選択肢がなぜ不正解なのかを ちゃんと説明できるようになるようになることは、 もっと大事だと思っています。 説明ができない場合は、ググったり、公式ページを見て、 ちゃんと自分の言葉で解釈できるようにするとよいと思います。 参考にした問題集 ※どちらも有料です。 ・WEB問題集で学習しよう ・Udemy 資格取得してよかったこと 残念ながら、全冠したら 「AWSを全て理解した」 の領域まで行くことはできません。 むしろ、海の深さを知るというのが私の感想です。 浜辺から見た海の深さはわからないけど、 いざ海に入った見たら(資格取得したら)、 思った以上に深かったということです。 じゃあ意味ないのか?というとそうではないです。 資格を通じて、知識が増えたことはかなりよかったと感じます。 業務での理解が早かったり、 業務では利用していない領域やサービスを知ることができ、 お客さんからの相談に「このサービスでなんとかできないかな?」とか 頭をよぎるようになったことは資格試験で受けた知識の恩恵でした。 またどうしても業務だけだと知識や利用するサービスが限られますが、 資格試験を受けることで「こんなサービスあるんや!」と感動することも多かったです。 最後に伝えたいこと 皆さん、勉強方法などをググったりすることが多いかと思いますが、 効率よく取りたい、簡単に取りたい罠には注意してください! 私は、最初に受けたSAAは、そういう甘い罠にかかってしまい、 まぐれで受かってしまいました。 正直試験中は、絶対不合格だと思ったくらいで、 合格して申し訳ないという気持ちでした・・・・ (点数を見てもらえばわかりますが、ギリギリの点数です) よくある 「たった〇〇だけで合格!」 「たった一週間で合格!」 みたいなものを鵜呑みにしないでください。 この人たちが嘘をついているということを言いたいわけではなく、 知識や経験、理解力は、人によって違うということです。 元々野球が上手い人が、ソフトボールやったら上達が早いのと同様で、 元々ITインフラの知識がある、元々AWSを業務で利用しているなど、 経験や知識によって勉強量が変わるのは当然の話です。 また公式ページを読んですぐ理解できる人もいれば、 私のように1度で理解できない人もいます。 そのため、必ずしもその経験談が自分に当てはまるとは限らないことを 肝に銘じていただければなと思います。 また、合格することも大事ですが、 不合格になったとしても、試験を受講した自分を褒めてください。 私もAWS試験では不合格にはなりませんでしたが、 他のベンダー試験で何回か不合格になっています。 ※LinuCを1回、CCNPを2回ほど不合格になっています。 これは、他社の方がおっしゃっていましたが、 合否問わずに試験を受けたことに対して 「ナイストライ!」とおっしゃっており、 この精神は素晴らしいなと思いました。 勉強したことは無駄にならないので、 頑張ってください!!! 以上です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

チームで作成した出欠管理システムをAWSへ移行しました!

昨年、社内チームで作成したQRコードを認証を利用した出席管理システムをAWSへ移行しました! この記事ではその概要について紹介します。 前回の記事はこちらになります。 https://qiita.com/Hiroki1928/items/d7eb5d819cc5e99e6d4c 実施内容 今回は下記の4つを実施しました。 1.リモート開発作業の推進 2.前年度成果物のAWS移行 3.認証機能の追加 4.フロントエンド資産のビルド・デプロイ自動化 リモート開発作業の推進 Discordに複数ボイスチャンネルを開設してバーチャルオフィスとして利用しました。 モブプログラミングを活用した作業効率化・技術スキルのフォロー ※モブプログラミングはチームの何人かで1組になってコミュニケーションをとりながら リモート作業を行うことです。 共有して1つの作業を行うため通常よりも効率よく作業を進めることができます。 月例社内ミーティングでの開発作業 + 週次 or 隔週でのリモート開発作業 前年度成果物のAWS移行 移行前と移行後の比較 移行前 移行後 クラウド基盤 Dockerコンテナ Amazon Web Service Web Webコンテナ(Nginx・JavaScript) Cloudfront・S3・JavaScript API APIコンテナ(Flask・Python) APIGateway・Lambda・Python DB DBコンテナ(PostgreSQL) DynamoDB AWS移行後の概要 Web画面はS3+CloudFrontで実装しました。 CloudFrontはHTTPSに対応するために使用しました。 APIの実装はAPIGatewayとLamdaで実装しました。 DBはRDBからDynamoDBに移行しました。 認証機能の追加 認証機能はAWSCognitoを使用することで実装できました。 ログイン認証画面はAWSAmplifyを使用することで短時間で作成することができました。 フロントエンド資産のビルド・デプロイの自動化 AWSCodePipelineを使用してビルドからデプロイまでを実装しました。 ソースの変更をトリガーにパイプラインが実行されます。 GitLabで管理されているソースを取得することができないので CodeCommitに同期して実装しています。 CodeBuildでCodeCommitに同期された資産をビルドしてS3にデプロイします。 リモート作業をして感じたこと リモートでの作業だったので通勤時間などがなく効率的に作業ができる。 リモートだと相手の反応から理解度を認識することが難しい。 複数人で作業をしているときは発言のタイミングが難しい 。 課題 各メンバーがリモート作業に慣れていくことが必要。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Bad owner or permissions on /home/(user)/.ssh/config,エラーの対処法

背景 githubにEC2からSSH接続しようとしたところ↑のように怒られた。 原因 セキュリティが緩いので、厳しくする必要がある (エラー発生時の権限状態↓) -rw-rw-r-- 実行したこと chmod 600 ~/.ssh/config をすることで所有者のみに読み書きの与える権限を与えてセキュリティ強化した。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む