20210915のAWSに関する記事は16件です。

AWS Cost ExplorerのAPIとGUIで額が違う?と思って調べた記録

目的 AWS Cost ExplorerのAPIを利用して月ごとの額を確認しようと思ったとき、 APIで出た額とGUI (コンソールのCost Explorer) の額がずれていたため、その原因を探りました。 結果、私の単純なミスであり、単純であるがゆえに調べてもなかなかヒットしなかったため記録として残します。 同じ状況に遭遇し、無駄撃ちはしたくない場合(AWS Cost Explorer APIは2021年現在1回あたり0.01 USDのため)、こちらの記録を参考としてください。 結論 悪い例: start_date = "2021-08-01" end_date = "2021-08-31" 正しい例: start_date = "2021-08-01" end_date = "2021-09-01" と「1ヶ月分」を指定する際は、end_dateは31日ではなく翌月の1日を指定する。 背景 AWSの各サービス(S3やEC2など)でかかるコストはAWS Cost Explorerで確認することができます。 このAWS Cost Explorerはコンソールから確認することができるのですが、それ以外にもAPIを利用して、pythonで確認することができます。 今回、AWS以外のサービスのコストもまとめて算出するシステムを作成するためにAPIを用いました。 しかし、 AWS Cost ExplorerのAPIをpythonで利用して月ごとの算出を行った結果(以下API)の額 と AWSコンソールからのCost Explorer(以下GUI)の同期間での額 が異なりました。 APIで算出した額がGUIの額より少なかったです。 この差分の原因を調査しました。 実際にAPI利用のために用いた関数は以下です。 ※「tag_name」部分はAWS リソースのタグ付けによりつけたタグごとにコスト算出を目的としたためついていますが、人によっては不要と思いますので、不要な場合削除してください。 def get_all_cost_by_api(start_date,end_date,tag_name): response = client.get_cost_and_usage( TimePeriod={ 'Start': start_date, 'End': end_date }, Granularity='MONTHLY', GroupBy=[ { "Type":"DIMENSION", "Key":"SERVICE" }, { "Type":"TAG", "Key":tag_name } ], Metrics=["UnblendedCost"] ) return response start_date = "2021-08-01" end_date = "2021-08-31" ### 悪い例。1ヶ月分を算出したい場合は"2021-09-01" tag_name = "hoge" response = get_all_cost_by_api(start_date,end_date,tag_name) 行った調査 Metrics まず、Metricsに着目しました。 APIでは、こちらの記事:AWS Cost Explorerに渡す、Metricsの値の意味 を参考に、とりあえずUnblendedCostで算出しました。 GUIでは右下の方に「コストの表示方法」という項目があり、「非ブレンドコスト」となっておりました。 言語が日本語だったので英語に変えたところ、UnblendedCostでした。 よって、Metricsの問題ではなさそうでした。 算出期間の変更 1月分の算出から1日分の算出に変更したところ、額が一致しました。 仮設構築&確認 「1日分の算出だと値が一致する」 「APIの額がGUIの額より少ない」 ということから 「期間の指定方法が適切ではないのでは?」 という仮設を立てて確認を行いました。 Before start_date = "2021-08-01" end_date = "2021-08-31" tag_name = "hoge" response = get_all_cost_by_api(start_date,end_date,tag_name) After start_date = "2021-08-01" end_date = "2021-09-01" tag_name = "hoge" response = get_all_cost_by_api(start_date,end_date,tag_name) Afterで算出した額とGUIで表示された額が(四捨五入の有無はあれど)無事一致しました。 感想 APIとGUIで額が違うという事象に遭遇し、 「aws cost explorer api gui 額 違う」 や 「different results cost explorer api gui」 などで検索しても該当の事象に遭遇した人の記事がなかなかヒットせず、 1回あたり0.01USDのコストがかかるということで検証のための実行もやりづらかったです。 こちらの記事を書くことで、今後は同様の事象に遭遇した人の検索に引っかかると良いなと思います。 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Transit Gatewayを使用した通信制御をやってみた①

AWS Transit Gatewayとは? VPCやオンプレミスを行き来するルートを一か所に集約できるサービスです。(たぶん) 詳しくは公式のドキュメントを見てください。 →AWS Transit Gateway(VPC およびアカウント接続を簡単にスケール)| AWS 概要と全体構成図 AWS Transit Gateway(以下:TGW)を使用して、 ① VPC(test-a) → TGW → VPC(test-palo) → インターネット ② VPC(test-a) → TGW → VPC(test-palo) →TGW → VPC(test-b)(VPC間通信) という2つの通信をやってみました。 ※インターネットに抜けるときも、VPC間通信するときも、FW(PaloAlto VM)を通過させます。  インターネットに出れていることをログで確認するためにPaloAltoを置いてみました。 ↓ こんな感じの構成を作成していきます。 端的にまとめると、TGWアタッチメントをルートテーブルにAssosiationすることにより、TGWアタッチメントが参照するルートテーブルを指定できるので、それをうまく使ってルートテーブルを分けることにより、①,②の通信を実現させる感じです。 1.VPC作成 超基本的なことから書いていきますが、知ってる人は飛ばしてください。 (半年前の自分のような)無知の極みから始めた人のために一応書きました。 AWSマネジメントコンソールにログイン>左上の「サービス」>「VPC」>左の一覧から「VPC」>右上の「VPCを作成」 上記の流れでクリックしていくと、こんな画面が出てくるので、赤枠のところを埋めます。 ※VPCのCIDRは下記URLに書いてある範囲で指定できます。 https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/VPC_Subnets.html#VPC_Sizing 赤枠を埋めたら、右下の「VPCを作成」をクリックします。 そうするとVPC完成です。 今回の検証には、いま作成したVPCを含めて3つ必要なので、同様にあと2つのVPCを作成します。 こんな感じで3つ出来ていればOKです。 2.TGW作成 2-1.Transit Gatewayの作成 2.と2-1.で、なんで同じこと書いてあるんだろうって思うかもしれませんが、作っていくうちに察すると思うのでスルーしてください。 左上の「サービス」>「VPC」>左の一覧から「Transit Gateway」>左上の「Create Transit Gateway」 上記の流れでクリックしていくと、こんな画面が出てくるので、また赤枠のところを埋めます。 ★VPN ECMP support、Default route table association、Default route table propagationの3つのチェックボックスは外しておいてください。 赤枠を埋めて、チェックを外したら、画面右下にある「Create Transit Gateway」をクリックします。 TGW作成リクエストが成功しましたという画面が出たらOKです。Closeして大丈夫です。 Closeして、Transit Gateway画面にさっき作成したtest-tgwが表示されていて、Stateが「Available」になっていたらTransit Gatewayの作成は完了です。 でもこれだけではTGWは使えません。2-2.へ続きます。 2-2.Transit Gateway接続(アタッチメント)の作成 2-2-1.TGWアタッチメント用サブネットの作成 VPCをTGWに関連付けるためには、VPCにTGWアタッチメントを作成する必要があります。 そのTGWアタッチメントを作成するために、そのTGWアタッチメントを作成するサブネットをまずは作成します。 左上の「サービス」>「VPC」>左の一覧から「サブネット」>右上の「サブネットを作成」 上記の流れでクリックしていくと、こんな画面が出てくるので、赤枠のところを埋めます。 サブネットは適当に切ってください。 自分はアタッチメントを作成するだけのサブネットなので、最小サブネットにしようと思い/28にしました。 赤枠を埋めたら、画面右下にある「サブネットの作成」をクリックします。 ★TGWアタッチメント用サブネットが各VPCに必要なので、同様の手順で残り2つのVPCにもTGWアタッチメント用サブネットを作成します。 こんな感じで3つ出来ていればOKです。 2-2-2.TGWアタッチメントの作成 準備ができたので、TGWアタッチメントを作成します。 左上の「サービス」>「VPC」>左の一覧から「Transit Gateway」>左上の「Create Transit Gateway Attachment」 上記の流れでクリックしていくと、こんな画面が出てくるので、また赤枠のところを埋めます。 ■ Transit Gateway ID・・・2-1.で作成したTGWを指定する ■ Attachment Type・・・VPCでOK ■ Attachment name tag・・・適当に名前を付ける ■ VPC ID・・・TGWアタッチメントを作成するVPCを指定する ■ Subnet IDs・・・VPC IDを指定したら自動で選択肢が出てくるので、2-2-1.で作成したサブネットを指定する 赤枠を埋めたら、画面右下にある「Create attachment」をクリックします。 TGWアタッチメント作成リクエストが成功しましたという画面が出たらOKです。Closeして大丈夫です。 ★TGWアタッチメントは各VPCに必要なので、同様の手順で残り2つのVPCにもTGWアタッチメントを作成します。 こんな感じで3つのTGWアタッチメントが出来て、Stateが「available」になっていればOKです。 (もしもStateがpendingでも待っていればavailableになります。きっと。) ちなみに現時点での構成図はこんな感じです。 最初に示した構成図と比べるとまだまだすっからかんですね。 さっきのTGWアタッチメントの作成で、赤線で示したような接続ができるイメージです。 2-3.Transit Gatewayルートテーブルの作成 2-3-1.インターネット通信用ルートテーブルの作成 Transit Gatewayの中身(?)、ルートテーブルを作ります。 左上の「サービス」>「VPC」>左の一覧から「Transit Gatewayルートテーブル」>左上の「Create Transit Gateway Route Table」 上記の流れでクリックしていくと、こんな画面が出てくるので、また赤枠のところを埋めます。 まず構成図上のtest-a(test-b)→test-palo(→Internet)を通すためのルートテーブルを作成します。 ■ Name tag・・・適当につけてください ■ Transit Gateway ID・・・2-1.で作成したTGWを指定します 赤枠を埋めたら、右下の「Create Transit Gateway Route Table」をクリックします。 TGWルートテーブル作成リクエストが成功しましたという画面が出たらOKです。Closeして大丈夫です。 ■ Associations そしたら、さっき作成したTGWルートテーブルを選択して(①)、Assosiationsをクリックします(②)。 すると「Create association」が出てくるので、それをクリックして、また赤枠のところを埋めます。 ■ Choose attachment to associate・・・インターネットに向かうためのルートテーブルなので、test-aのTGWアタッチメントを指定しています 赤枠を埋めたら、右下の「Create association」をクリックします。 TGWルートテーブルアソシエーションリクエストが成功しましたという画面が出たらOKです。Closeして大丈夫です。 そもそも、associationって何?って感じだと思うのですが、イメージはこんな感じです。 (色々調べてこんな感じだと理解したので、違ってたらごめんなさい。) ■ Propagations 2-1.Transit Gatewayの作成にて、「Default propagation route table」のチェックを外したので、今回使用していない機能にはなりますが、プロパゲーションについても少しだけ触れておきます。 こちらにチェックを入れたままTGWを作成すると、TGWアタッチメントが属するVPC宛てのルートが、TGWのルートテーブルに自動で追加されます。 今回はルートテーブルを2つに分けたりする手前、このプロパゲーション機能は使わないことにしました。 意図しないルートテーブルを作りたくない場合はチェックを外した方がいいと思います。 ■ Routes そしたら、またTGWルートテーブルを選択して(①)、今度はRoutesをクリックします(②)。 すると「Create static route」が出てくるので、それをクリックして、また赤枠のところを埋めます。 ■ CIDR・・・インターネット通信用のルートテーブルなので、デフォルトルート(0.0.0.0/0)を作成します ■ Choose attachment・・・このルートのネクストホップとなるTGWアタッチメントを指定するので、今回はtest-paloのTGWアタッチメントを選択します 赤枠を埋めたら、右下の「Create static route」をクリックします。 TGWルート作成リクエストが成功しましたという画面が出たらOKです。Closeして大丈夫です。 ということで、いまの構成図はこんな感じです。 残るTGWの設定は、 ・test-bのTGWアタッチメントを、test-rtb-to-internetに紐づけ(Associationsの追加) ・VPC間通信用ルートテーブルの作成(Associations、Routesの設定を含む) です。 全体構成図とここまでの流れを踏襲すれば、残るTGWの設定もできると思います。 ここで終わるの?って感じですが・・・ ちょっとかなり長くなりそうなので、続きは別の記事に書こうと思います。 残っているTGWの設定もそちらにちゃんと書きますので、少々お待ちください。 読んでくださりありがとうございました。 ■ 続きの記事はこちら →(作成中)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

serverless frameworkを試した

背景 AWS上にlambda関数を開発した codecommitから各環境にlambda関数をデプロイする DBやS3と接続するのでローカルで開発してテストしにくい serverless frameworkとは サーバーレス開発ツーるである https://github.com/serverless/serverless  メリット インフラ自動構築 Cloudformationのstackを自動的に作れる  デプロイ簡単 Lambda関数を1コマンドでデプロイできる 複数functionを管理とデプロイできる   環境と環境変数の管理 環境を分けることが簡単  Dev, stg, pro  環境変数を簡単に定義  IAMロールの定義も簡単  Functionよりroleを定義できる  簡単な使い方 serverless frameworkのインストール npm install -g serverless 初期化 serverless create --template aws-nodejs --name my-service --path my-special-service 要素説明 serverless.yml: serverless.ymlは各サービス全体の設定を行うためのファイル handler.js: これはファンクションを定義するためのスケルトンとして生成されるファイル インフラ構築 sls deploy -v Lambda関数をデプロイ sls deploy function -f hello ローカル実行  sls invoke local -f hello -l インフラ削除 sls remove -v
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Certificate ManagerでEメール認証からDNS認証に切り替え

メール連絡 AWSより以下のメール連絡がありました。 Changes to AWS Certificate Manager (ACM) email validated certificate renewal workflow これはaws acmで管理しているSSL/TSL証明書の認証方法が変わりましたよ という案内で、要はEメール認証は今後自動更新に対応しないので DNS認証に切り替えをおすすめしますという内容のメールでした。 現在のドメイン設定を確認 ドメインレジストラ | お名前ドットコム AWS構成 Route 53 → CloudFront → Elastic Beanstalk(ALB → EC2) → RDS ↑この構成の場合SSL/TSL証明書は CloudFront(バージニアリージョン) ALB(東京リージョン) と2箇所に設置されているケースが多いと思います。 これはCloudFrontのリージョンがグローバルでかつ すべてのエッジロケーションに反映されるのに時間がかかる場合があることが理由です。 このように証明書を分けておくことでCloudFrontでトラブルが起こった際にも Route53 → Elastic Beanstalk(ALB → EC2) → RDSのように 切り替えたり、CloudFrontのディストリビューションを 新たに作ったりする事によって柔軟に対応ができるメリットがあります。 逆に証明書を共通にしてしまうと逃れられないダウンタイムが発生するリスクが想定できます。 現在の認証方法 Email認証 証明書の認証方法の切り替えはできない 現在のEmail認証で使用している証明書をCDN認証に切り替えることは出来ないため、新しくCDN認証の証明書を作る形で申請をする。 新規CDN認証をCertificate Managerから申請する作業手順 1.リージョンを確認し、Certificate Managerコンソール画面の証明書リクエストをクリック 2.パブリック証明書のリクエストにチェックが入っていることを確認し【証明書のリクエスト】をクリック 3.*.example.comで設定し【次へ】をクリック (当方の環境ではhttp、wwwなしのネイキッドドメインへのアクセスはすべて https://www.example.com へ301しているという環境のためこの設定ですがサブドメイン運用や細く設定する必要があれば適宜ここで設定できると思います。) 4.DNSの検証にチェックを入れて【確認】をクリック 5.内容を確認して【確認とリクエスト】をクリック 6.DNS検証の為のネームサーバへ設定する値が表示されますのでネームサーバへ設定します。Route53を使用している場合は【Route53でのレコードの作成】ボタンを押すと、Route53コンソールにCNAMEレコードが設定されます。ここで場合によっては反映されるまでには時間がかかります。30分くらいは時間を置くのが良さそうです。 ※ここでいうネームサーバとはRoute53のようなDNSサービス内の設定項目のことです。 証明書を割り当てる 私の環境の場合CloudFrontとALBの2箇所に割り当てます。 CloudFrontへの設定 CloudFrontのコンソール画面からディストリビューションを選び【一般】→【編集】から 【SSL Certificate】 → 【Custom SSL Certificate】 → 【今回作成した証明書】を選び設定します。 注意点|CloudFront設定時 CloudFrontはエッジロケーションと呼ばれるサーバを複数持っており、約24時間は証明書が古いものと 新しいものを使用しているサーバが混在する状況となるようです。したがって旧証明書も約24時間以降に 削除したほうが安全とのことです。 ちなみにCertificate Managerのコンソール画面では証明書が使用中という項目がありますが 新しい証明書を適用後ここを見ていましたがすぐにはいいえになりませんでした。 ALB( Beanstalk内)への設定 【Beanstalkコンソール】 → 【ロードバランサー】 → 【編集】 → 【該当するリスナーを選択してアクション→編集】 → 【SSL証明書を選択】 → 最後忘れずに画面最下部の 【オレンジの適用ボタン】をクリックすると反映が始まります。 自分の環境ではおそらく10分もかからずに反映されました。 反映中も該当のURLをリロードしてみましたがダウンタイムは確認できませんでした。 Certificate Managerのコンソール画面、証明書が使用中の項目はすぐにいいえになりました。 (確認できておらず恐縮ですがおそらく即時反映) 作業前、作業中に起こった疑問 Eメール認証している証明書を使用している状態でDNS認証用の証明書を発行することになるわけですが、運用中のドメインで複数証明書を発行することは運用中のサイト表示、メール受信などに影響を与えることはあるのか?という疑問が生まれました。 回答 同ドメインに対する新規証明書を発行すること(2枚の証明書が存在する状態)ではサイト表示、メール送受信には影響が出ない。 余談 今後ACMでSSLサイト公開用の証明書申請するならDNSが良いと個人的には思います。 (AWSのマニュアルでもおすすめされていました。) Eメール認証だと年1で更新手続きの作業が発生するので面倒&忘れるリスクも0ではありません。 DNS認証の運用で注意したいこと Route53にCNAMEが設定されているのでこれを削除してしまうと認証が失敗してしまいサイトが表示されないなどの事故が想定できます。Route53のCNAMEに設定されたことは忘れずに&情報共有などをしっかりめにやったほうが良さそうです。 参考ページ E メールで検証済みの AWS Certificate Manager(ACM)証明書の更新ワークフローの変更 ACMの証明書をDNS検証にする
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS初めの作業メモ

はじめに AWSを初めた際の作業メモ ハンズオンのリンク 初めに見るべきハンズオン一覧 ハンズオンはじめの一歩: AWS アカウントの作り方 & IAM 基本のキ Security #1 アカウント作成後すぐやるセキュリティ対策 スケーラブルウェブサイト構築編 IAMユーザの作成 まずは、アカウント(ルートユーザ)作成。 ルートユーザは請求情報も含め権限があるので基本使わないので管理用のIAMユーザを作成し日々の管理は管理用IAMユーザで実施 あとは各プロジェクトに応じたIAMユーザを作成し作業 IAMポリシー IAMポリシーの作成と適用については、IAMポリシーをグループに付与し、ユーザがそれに属するパターンが管理しやすそう 例えば、管理用IAMはadminグループを作成し、それに属するようにする その他の作業 以下のサービスを有効化しておく billing (請求関連の設定) Cost Explorer 請求額と使用状況の分析が可能。有効に1日程度かかるので早めに設定する Budgets 請求金額のアラートを設定できる。 一定の金額になるとメール通知や、定期的な請求額レポートのメール送信などが可能。請求アラート、2つの予算までは無料で作成、レポートは1つにつき0.01USD Cost & Usage Reports 請求額と使用状況の詳細ログをS3に保存 CloudTrail 操作履歴のログの保存。保存先のS3料金が発生 Config リソース変更履歴ログの保存や構成情報の管理・監視。保存先のS3料金が発生 GuardDuty ・脅威の検知。(VPN Flow Logs, DNS Logs, CloudTrailの情報をもとに自動検出)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSでAIサービスを使ってみる~⑨lex編~

Lexとは AWSのbotのAIサービス。Amazon Lex を使うと、すべてのデベロッパーが Amazon Alexa に採用されている深層学習技術と同じ技術を利用できるため、自然言語での高度な対話ボット (チャットボット) を短時間で簡単に構築できます。 今回はlexを用いてアイスクリームのフレーバーや容器について答えるボットを作成して行きます。 コードの量があるので順番に解説して行きます。 ボット作成ファイルの全体像 lex_create_bot.py import boto3 import time iam = boto3.client('iam') iam.create_service_linked_role(AWSServiceName='lex.amazonaws.com') lex = boto3.client('lex-models', 'us-east-1') #フレーバーのスロットタイプの作成 flavor_slot_type = lex.put_slot_type( name='FlavorSlotType', enumerationValues=[ {'value': 'vanilla'}, {'value': 'chocolate', 'synonyms': ['choc']}, {'value': 'strawberry', 'synonyms': ['berry']} ], valueSelectionStrategy='TOP_RESOLUTION', createVersion=True) print('slot type:', flavor_slot_type['name']) #容器のスロットタイプを作成 container_slot_type = lex.put_slot_type( name='ContainerSlotType', enumerationValues=[ {'value': 'corn'}, {'value': 'cup'} ], valueSelectionStrategy='TOP_RESOLUTION', createVersion=True) print('slot type:', container_slot_type['name']) #インテントの作成 intent = lex.put_intent( name='OrderIntent', #インテント内のスロット slots=[ { 'name': 'Flavor', 'slotConstraint':'Required', 'slotType':'FlavorSlotType', 'slotTypeVersion': '1', 'valueElicitationPrompt': { 'messages': [{ 'contentType': 'PlainText', 'content': 'Vanilla, chocolate or strawberry?' }], 'maxAttempts': 3 } }, { 'name': 'Container', 'slotConstraint': 'Required', 'slotType': 'ContainerSlotType', 'slotTypeVersion': '1', 'valueElicitationPrompt': { 'messages': [{ 'contentType': 'PlainText', 'content': 'Corn or cup?' }], 'maxAttempts': 3 } } ], #発話例 sampleUtterances=[ 'I want {Flavor} ice cream in {Container}', '{Flavor} ice cream {Container}', 'ice create' ], #完了時のセリフ conclusionStatement={ 'messages': [{ 'contentType': 'PlainText', 'content': 'OK, {Flavor} ice cream in {Container}' }], }, #完了の動作 fulfillmentActivity={'type': 'ReturnIntent'}, createVersion=True) print('intent:',intent['name']) #ボットの作成 bot = lex.put_bot( name ='MyBot', locale='en-US', childDirected=False, #インテント intents=[ { 'intentName': 'OrderIntent', 'intentVersion': '1' } ], #中止時のセリフ abortStatement={ 'messages':[ { 'contentType': 'PlainText', 'content': 'Please try again.' } ] }, voiceId='Joanna', createVersion=True) print('bot:', bot['name']) #ボット作成の進捗表示 start = time.time() status = '' while status not in ['READY', 'FAILED']: #ボットを取得 status = lex.get_bot(name='MyBot', versionOrAlias='1')['status'] time.sleep(10) print('{:7.2f} {}'.format(time.time()-start, status)) #作成に失敗した場合は理由を表示 if status == 'FAILED': print(lex.get_bot( name='Mybot', versionOrAlias='1')['failureReason']) #ボットエイリアスを作成 bot_alias = lex.put_bot_alias( name='MyBotAlias', botName='MyBot', botVersion='1') print('bot alias:', bot_alias['name']) ①importとサービスクライアント作成 lex_create_bot.py import boto3 import time iam = boto3.client('iam') iam.create_service_linked_role(AWSServiceName='lex.amazonaws.com') lex = boto3.client('lex-models', 'us-east-1') boto3とtimeのインポートとiamのロールとlexのサービスクライアントを作成 ②スロットタイプ作成 スロットとはユーザーから聞き出す必要のあるパラメーターです。 今回はフレーバーと容器をスロットに設定しています。 lex_create_bot.py #フレーバーのスロットタイプ flavor_slot_type = lex.put_slot_type( name='FlavorSlotType', enumerationValues=[ {'value': 'vanilla'}, {'value': 'chocolate', 'synonyms': ['choc']}, {'value': 'strawberry', 'synonyms': ['berry']} ], valueSelectionStrategy='TOP_RESOLUTION', createVersion=True) print('slot type:', flavor_slot_type['name']) #容器のスロットタイプ container_slot_type = lex.put_slot_type( name='ContainerSlotType', enumerationValues=[ {'value': 'corn'}, {'value': 'cup'} ], valueSelectionStrategy='TOP_RESOLUTION', createVersion=True) print('slot type:', container_slot_type['name']) put_slot_typeメソッドでスロットを作成します。 enumerationValuesでスロットが取りうる値を辞書型で指定 valueSelectionStrategyの'TOP_RESOLUTION'はスロットタイプの中からユーザーの言葉に近いものを返します。今回でいえばchocoと入力すると本来の値のchocolateが返ってくる。 ③インテントの作成 intentとは意思や意図という意味がありますが、lexの中ではユーザーと会話する台本のイメージになります。 今回をアイスクリーム注文するコマンドを受け取るインテントを作成します。パラメーターとしてアイスクリームのフレーバーと容器を受け取リます。 put_intentメソッドでインテントを作成します。 引数slotsについて lex_create_bot.py #インテントの作成 intent = lex.put_intent( name='OrderIntent', #インテント内のスロット slots=[ { 'name': 'Flavor', 'slotConstraint':'Required', 'slotType':'FlavorSlotType', 'slotTypeVersion': '1', 'valueElicitationPrompt': { 'messages': [{ 'contentType': 'PlainText', 'content': 'Vanilla, chocolate or strawberry?' }], 'maxAttempts': 3 } }, { 'name': 'Container', 'slotConstraint': 'Required', 'slotType': 'ContainerSlotType', 'slotTypeVersion': '1', 'valueElicitationPrompt': { 'messages': [{ 'contentType': 'PlainText', 'content': 'Corn or cup?' }], 'maxAttempts': 3 } } ], 引数slotsはインテント内にスロットを作成するために使います。 ・slotConstraint:スロットの制約です。'Required'または'Optinal'で選択。 ・slotTypeVersion:スロットのバージョン。最初はバージョン'1' ・valueElicitationPrompt:スロットの値をユーザーから促すためのセリフ →valueElicitationPromptに指定する辞書の項目 ・message:セリフを表す辞書リスト。その中にcontentTypeとcontentが含まれる ・maxAttempts:聞き返す回数の上限 →→messageに指定する辞書の項目 ・contentType:セリフのタイプ。'PlainText','SSML','CustomPayload'から指定 ・content:セリフの内容 引数sampleUtterances lex_create_bot.py #発話例 sampleUtterances=[ 'I want {Flavor} ice cream in {Container}', '{Flavor} ice cream {Container}', 'ice create' ], 引数sampleUtterancesはインテントに対するユーザーの発話例です。 {スロット名}でスロットを表します。{Flavor}の部分にはフレーバー(chocolate,strawberry,vanilla)が入り、{Container}には(cupなど)が入ります。 今回ユーザーの発話を見ることはなさそうですね。 引数conclusionStatement lex_create_bot.py #完了時のセリフ conclusionStatement={ 'messages': [{ 'contentType': 'PlainText', 'content': 'OK, {Flavor} ice cream in {Container}' }], }, 引数conclusionStatementはボットがユーザーから必要なスロットの情報を聞き出すことができて、インテントが完了したときのセリフです。辞書型の項目として引数slotsのvalueElicitationPromptに指定する辞書の項目と同じです。 引数fulfillmentActivity lex_create_bot.py #完了の動作 fulfillmentActivity={'type': 'ReturnIntent'}, createVersion=True) print('intent:',intent['name']) 引数fulfillmentActivityはインテントが完了したときの動作です。 引数にはキー'type'を含む辞書を指定します。 typeの種類 ReruenIntent:呼び出し元のプログラムにインテントの情報を返します。 CodeHook:Lambda呼び出してLambdaに登録されたプログラムを実行します。 ④botの作成 最後にボットとボットエイリアスを作成します。Lexでbotを公開するにはボットエイリアスを作成する必要があります。 lex_create_bot.py #ボットの作成 bot = lex.put_bot( name ='MyBot', locale='en-US', childDirected=False, #インテント intents=[ { 'intentName': 'OrderIntent', 'intentVersion': '1' } ], #中止時のセリフ abortStatement={ 'messages':[ { 'contentType': 'PlainText', 'content': 'Please try again.' } ] }, voiceId='Joanna', createVersion=True) print('bot:', bot['name']) put_botメソッドを呼び出してボットを作成します。 引数のnameは名前、localeは今回'en-US'、childDirected(子供向け)は子供向けの場合にはTrue、子供向けではない場合はFalseに指定。 引数intentはnameとintentVersionを辞書型で渡します。 引数abortStatementには中止時のセリフを辞書型のリストにして指定します。 voiceIdは'en-US'の中から'Joanna'に指定します。 作成時の進捗時間表示 lex_create_bot.py #ボット作成の進捗表示 start = time.time() status = '' while status not in ['READY', 'FAILED']: #ボットを取得 status = lex.get_bot(name='MyBot', versionOrAlias='1')['status'] time.sleep(10) print('{:7.2f} {}'.format(time.time()-start, status)) #作成に失敗した場合は理由を表示 if status == 'FAILED': print(lex.get_bot( name='Mybot', versionOrAlias='1')['failureReason']) #ボットエイリアスを作成 bot_alias = lex.put_bot_alias( name='MyBotAlias', botName='MyBot', botVersion='1') print('bot alias:', bot_alias['name']) get_botメソッドでボットの情報を取得しstatusへ、10秒間時間を待ち開始からに時間と取得したボットの情報をstatusに代入して表示します。 作成に失敗した場合は、失敗した理由を取得し表示。 put_bot_aliasメソッドでボットエイリアスを作成し、画面に表示します。 まとめ ここまで長くなりましたが、lexでのbot作成のコードと解説でした。 次回はbotにテキストを与えて動かしてみます。 参考文献 この記事は以下の情報を参考にして執筆しました AWSでつくるAIプログラミング入門
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CircleCIでcdk deployしようとしてAWSの認証でハマった2点

追記 2021/09/15 * ハマり2の解決策で追加すべきものを追加 * おまけハマりを追加 はじめに CircleCIからaws cdkでデプロイ仕様とした時に、AWSの認証関連でハマった2点です。 CircleCIでの実行ですが、多分どのパイプラインサービスでも同じだと思います。 前提 CircleCI用のIAMユーザー circleci-user を作成しCredentialsを生成しておく。 circleci-user は必要最低限の権限とする。 CloudFormation実行用のIAM Role CFn-Roleを作成してcdkのオプションで指定する。 ハマり1:cdkではProfileが必要 AWS_DEFAULT_REGION=ap-northeast-1 AWS_ACCESS_KEY_ID=AKxxxxxxxxxxxxxxxxxxxxx AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxx npm run cdk -- deploy --require-approval never と実行しても以下のようなエラーになる。 DynamoCdkStack: deploying... ❌ DynamoCdkStack failed: Error: Unable to resolve AWS account to use. It must be either configured when you define your CDK Stack, or through the environment at SdkProvider.resolveEnvironment (/home/circleci/work/Dynamo-CDK/node_modules/aws-cdk/lib/api/aws-auth/sdk-provider.ts:208:13) ハマり1の解決:Profileを設定する どうやらProfileの設定は必須のようなので作成する。 AWS_PROFILE_NAME=prd aws --profile ${AWS_PROFILE_NAME} configure set aws_access_key_id ${AWS_ACCESS_KEY_ID} aws --profile ${AWS_PROFILE_NAME} configure set aws_secret_access_key ${AWS_SECRET_ACCESS_KEY} aws --profile ${AWS_PROFILE_NAME} configure set region ${AWS_DEFAULT_REGION} npm run cdk -- deploy --require-approval never --profile ${AWS_PROFILE_NAME} ハマり2: --role-arnを指定しても途中までは実行ユーザーの権限 最小権限の原則に則り circleci-user にはiam:PassRoleのみを設定して、cdkのオプションに--role-arnを指定したのですが、権限足りないエラーになりました。 npm run cdk deploy --role-arn" "************************************************************************** --require-approval never --profile ${AWS_PROFILE_NAME} DynamoCdkStack: deploying... ❌ DynamoCdkStack failed: AccessDenied: User: arn:aws:iam::123456789012:user/circleci-user is not authorized to perform: cloudformation:DescribeStacks on resource: arn:aws:cloudformation:ap-northeast-1:123456789012:stack/CDKToolkit/* at Request.extractError (/home/circleci/work/Dynamo-CDK/node_modules/aws-cdk/node_modules/aws-sdk/lib/protocol/query.js:50:29) ハマり2の解決:実行ユーザーにはいくつか権限が必要 cdkの--role-arnはターゲットとするStackに対する操作には使用されるが事前の「CDKToolkit」スタックからの情報取得やChangesetの作成までは実行ユーザーの権限で行われるようです。 circleci-userに以下の権限を付与します。 ManagedPolicyの AWSCloudFormationReadOnlyAccess CDKToolkitスタック(cdk bootstrapで作成される)で作成されるS3Bucketに対する書き込み権限 cloudformation:CreateChangeSet/ExecuteChangeSet/DeleteChangeSet権限(これは事前にStack名がわからないのでResource:* おまけハマり:謎のエラー failed: Error: This stack uses assets, so the toolkit stack must be deployed to the environment (Run "cdk bootstrap aws://unknown-account/unknown-region") なんじゃこりゃ?と思ったらcdk bootstrapをそのAWSアカウントで実行していなかったためでした。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python】importが必要なPythonをAWS Lambda へ移行してみた 事前準備編

はじめに 昨日、macOSのcronで自動実行するためにmacOSの省電力モードをOFFにすると1ヶ月で1,200円程度電気代がかかるのでは!?という記事を書きました(あくまで試算です) やはり、オンプレ運用はよくないと。これからはクラウドっしょ! ただ、AWS Lambdaってよくわからん。 って思っている方いますね?(私) ってことで本日はAWS Lambda へPython実行環境を移行にチャレンジしてみました。 少し長くなるので、事前準備編とLambda編とEventBridge編で分けて投稿します。 環境 ・既にAWSのアカウントを持っている(お持ちでない方でもすぐ発行できますよ。) ・Python3.9 ・macOS Catalina10.15.7 ・定期実行したいpythonがある 事前解説 今回はサンプルとして、ccxtという複数の仮想通貨取引所のAPI操作が集約されたライブラリをAWS Lambdaで実行したいと思います。 AWS Lambdaにはデフォルトではccxtがインストールされていません。 またmacOSならターミナルで簡単にpip3コマンドでccxtをインストールできますが、残念ながらAWS Lambdaにはインストールできません。なので、みなさんが一生懸命作ったpythonプログラムの1行目のimportコマンドでいきなりエラーになります。 import ccxt →エラー発生 { "errorMessage": "Unable to import module 'lambda_function': No module named 'ccxt'", "errorType": "Runtime.ImportModuleError" } この時点でAWS Lambda へPython実行環境を移行を諦める人多いと思います。(私) でも今日は諦めません。だって電気代高いんだもん! ではどうすればいいのか。簡単に書きます。 ◆事前準備編◆  1.macOSのデスクトップにtempフォルダを作る  2.tempフォルダにccxtをpip3でインストールする  3.既に作ったpythonプログラムを lambda_function.py へリネームしてtempフォルダに入れる  4.lambda_function.py の先頭に指定プログラムを追記する  5.ターミナルでzipでまとめる ◆Lambda編◆  6.AWSへログインし、5をアップロードする ◆EventBridge編◆  7.EventBridge (CloudWatch Events)に定期実行ルールを登録する 今回は1-5までを説明します。(次回以降で6-7) 手順 1.macOSのデスクトップにtempフォルダを作る  1-1.ターミナルを起動します。pwdコマンドで自分がどこにいるか確認します。 % pwd /Users/Hiroki  1-2.デスクトップに移動します。 % cd /Users/Hiroki/Desktop Desktop %  1-3.デスクトップにtempフォルダを作ります。 Desktop % mkdir temp  1-4.tempフォルダに移動します。 Desktop % cd temp temp % 2.tempフォルダにccxtをpip3でインストールする  2-1.ccxtをフォルダ指定してインストールします。 temp % pip3 install ccxt -t ./  2-2.デスクトップにあるtempフォルダにccxtフォルダがあるか確認します。 3.既に作ったpythonプログラムを lambda_function.pyへリネームしてtempフォルダに入れる 4.lambda_function.py の先頭に指定のプログラムを追記する lambda_function.py def lambda_handler(event, context): return { } おまじないです。 5.ターミナルでzipでまとめる temp % zip -r zip_file ./* tempフォルダの中に zip_file.zip というファイルがあれば成功です。 最後に うまく事前準備できましたでしょうか。 次回はAWSへアップロードして、定期実行を設定していきます。 AWSアカウントをお持ちでない方はご準備をお願いします。 ご参考になれば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RcloneでAWS S3からOCIオブジェクト・ストレージにデータをコピー

初めに AWS S3またはAzure Blobから、Orale Cloudのオブジェクト・ストレージにデータをコピーできますか?答えはできます。このタスクを完了するには多くの方法がありますが、Rcloneを利用すれば、簡単に実現できます。 Rclone は、クラウド・ストレージ上のファイルを管理するコマンドライン・プログラムです。Oracle Cloud Object Storage、AWS S3、Azure Blob、Google Cloud Storageなど、多くのクラウドベンダーがサポートされています。異なるクラウドストレージ間でデータを簡単に転送できます。 では、AWS S3からOracle Cloudのオブジェクト・ストレージにデータをコピーする方法をご紹介します。 ステップ 1. Rcloneのインストール 2. OCI接続用情報の収集 (コピー先) 3. AWS接続用情報の収集 (コピー元) 4. OCI接続の設定 (コピー先) 5. AWS接続の設定 (コピー元) 6. データコピーの実施 事前準備 OCI(Oracle Cloud Infrastructure)およびAWSのクラウドアカウント。 Rclone実行用クライアント。 (Linux/Mac/Windowsがサポートされています。ここではLinux7を使用しています。) HTTPSを使用し、クライアントからソース/ターゲット・クラウドに接続できることを確保してください。 1. Rcloneのインストール 非常に簡単で、一行のコマンドを実行すればOKです。 詳細なガイドについては、こちらを確認してください。(他のOSにインストールしたい場合。) コマンド curl https://rclone.org/install.sh | sudo bash [opc@linux7 ~]$ curl https://rclone.org/install.sh | sudo bash % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 4497 100 4497 0 0 4794 0 --:--:-- --:--:-- --:--:-- 4794 Archive: rclone-current-linux-amd64.zip ...... rclone v1.56.0 has successfully installed. Now run "rclone config" for setup. Check https://rclone.org/docs/ for more details. [opc@linux7 ~]$ 2. OCI接続用情報の収集 (コピー先) 接続を構成するには、OCIコンソールから下記の情報を収集する必要があります。 アクセス・キー(Access Key)と秘密キー(Secret Key) リージョン識別子(Region Identifier) オブジェクト・ストレージ・ネームスペース(Object Storage Namespace) APIエンドポイント(API Endpoint) アクセス・キーと秘密キー OCIから収集方法に関するドキュメント・リンクはこちらです。 MENU->Identity & Secruity->Identity->Users->User Details->Customer Secret Keys 名前を入力し、「秘密キーの作成」ボタンをクリックします。 「コピー」をクリックして保存します。 (秘密キーは二度と表示されないので、ご注意ください。) 作成後、「アクセス・キー」は以下のように表示され、いつでもコピーできます。 リージョン識別子 メニューバーのリージョン名をクリックし、「リージョンの管理」を選択すると、リージョン識別子が表示されます。この例は東京リージョン(ap-tokyo-1)を使用しています。 オブジェクト・ストレージ・ネームスペース MENU->Governance & Administration->Account Management->Tenancy Details APIエンドポイント "Object_Storage_Namespace"と"Region_Identifier"の文字列を収集したものに置き換えて、以下のようにAPIエンドポイントの文字列を作成します。 https://<Object_Storage_Namespace>.compat.objectstorage.<Region_Identifier>.oraclecloud.com 3. AWS接続用情報の収集 (コピー元) アクセス・キー(Access Key IDとSecret Access Key) AWSから収集方法に関するドキュメント・リンクはこちらです。 My Security Credentials->Access keys (access key ID and secret access key)->Create New Access Key 作成後、キーをコピーして安全な場所に保管してください。 4. OCI接続の設定 (コピー先) コマンド: rclone config 以下の情報を入力します。 1. 「n」を入力、接続を新規作成します。 2. 接続名を入力します。(例:「oci」) 3. 「4」を選択します。(S3準拠のストレージ・プロバイダー) 4. 「14」を選択します。(他のS3互換プロバイダー) [opc@linux7 ~]$ rclone config 2021/09/10 12:30:23 NOTICE: Config file "/home/opc/.config/rclone/rclone.conf" not found - using defaults No remotes found - make a new one n) New remote s) Set configuration password q) Quit config n/s/q> n name> oci Type of storage to configure. Enter a string value. Press Enter for the default (""). Choose a number from below, or type in your own value ...... 4 / Amazon S3 Compliant Storage Providers including AWS, Alibaba, Ceph, Digital Ocean, Dreamhost, IBM COS, Minio, SeaweedFS, and Tencent COS \ "s3" ...... Storage> 4 Choose your S3 provider. Enter a string value. Press Enter for the default (""). Choose a number from below, or type in your own value ...... 14 / Any other S3 compatible provider \ "Other" provider> 14 以下の情報を入力します。 5. 「1」を入力します(次のステップでクレデンシャルを入力することを意味します)。 6. 「アクセス・キー」を入力します(OCIコンソールから作成された)。 7. 「秘密キー」を入力します(OCIコンソールから作成された)。 8. リージョン識別子を入力します。(例:「ap-tokyo-1」) 9. 「APIエンドポイント」を入力します。 Get AWS credentials from runtime (environment variables or EC2/ECS meta data if no env vars). Only applies if access_key_id and secret_access_key is blank. Enter a boolean value (true or false). Press Enter for the default ("false"). Choose a number from below, or type in your own value 1 / Enter AWS credentials in the next step \ "false" 2 / Get AWS credentials from the environment (env vars or IAM) \ "true" env_auth> 1 AWS Access Key ID. Leave blank for anonymous access or runtime credentials. Enter a string value. Press Enter for the default (""). access_key_id> Your_Access_Key AWS Secret Access Key (password) Leave blank for anonymous access or runtime credentials. Enter a string value. Press Enter for the default (""). secret_access_key> Your_Secret_Key Region to connect to. Leave blank if you are using an S3 clone and you don't have a region. Enter a string value. Press Enter for the default (""). Choose a number from below, or type in your own value 1 / Use this if unsure. Will use v4 signatures and an empty region. \ "" 2 / Use this only if v4 signatures don't work, e.g. pre Jewel/v10 CEPH. \ "other-v2-signature" region> ap-tokyo-1 Endpoint for S3 API. Required when using an S3 clone. Enter a string value. Press Enter for the default (""). endpoint> https://your_namespace.compat.objectstorage.ap-tokyo-1.oraclecloud.com 以下の情報を入力し、設定を完了します。 10. 「location_constraint」のプロンプトが表示されたら、Enterキーを押します。 (デフォルト) 11. ACLに「1」(プライベート)を入力します。(デフォルト) 12. もっと詳細な設定が必要ない場合は、「n」を入力します。(デフォルト) 13. 「y」を入力して確認します。(デフォルト) Location constraint - must be set to match the Region. Leave blank if not sure. Used when creating buckets only. Enter a string value. Press Enter for the default (""). location_constraint> Canned ACL used when creating buckets and storing or copying objects. ...... Enter a string value. Press Enter for the default (""). Choose a number from below, or type in your own value 1 / Owner gets FULL_CONTROL. No one else has access rights (default). \ "private" ...... acl> 1 Edit advanced config? y) Yes n) No (default) y/n> n -------------------- [oci] type = s3 provider = Other access_key_id = Your_Access_Key secret_access_key = Your_Secret_Key region = ap-tokyo-1 endpoint = https://your_namespace.compat.objectstorage.ap-tokyo-1.oraclecloud.com acl = private -------------------- y) Yes this is OK (default) e) Edit this remote d) Delete this remote y/e/d> y Current remotes: Name Type ==== ==== oci s3 ここまで、OCI接続の設定は完了です。接続可否を確認します。 OCI接続の確認 すべてのバケットを一覧表示します。 コマンド: rclone lsd <remote:> リモート名の末尾に":"があることに注意してください。 [opc@linux7 ~]$ rclone lsd oci: -1 2021-09-10 14:47:45 -1 Target_Bucket [opc@linux7 ~]$ 5. AWS接続の設定 (コピー元) コマンド: rclone config 以下の情報を入力します。 1. 「n」を入力、接続を新規作成します。 2. 接続名を入力します。(例:「aws」) 3. 「4」を選択します。(S3準拠のストレージ・プロバイダー) 4. 「1」を選択します。(AWS S3) [opc@linux7 ~]$ rclone config Current remotes: Name Type ==== ==== oci s3 e) Edit existing remote n) New remote d) Delete remote r) Rename remote c) Copy remote s) Set configuration password q) Quit config e/n/d/r/c/s/q> n name> aws Type of storage to configure. Enter a string value. Press Enter for the default (""). Choose a number from below, or type in your own value ...... 4 / Amazon S3 Compliant Storage Providers including AWS, Alibaba, Ceph, Digital Ocean, Dreamhost, IBM COS, Minio, SeaweedFS, and Tencent COS \ "s3" ...... Storage> 4 Choose your S3 provider. Enter a string value. Press Enter for the default (""). Choose a number from below, or type in your own value 1 / Amazon Web Services (AWS) S3 \ "AWS" ...... provider> 1 以下の情報を入力します。 5. 「1」を入力します(次のステップでクレデンシャルを入力することを意味します)。 6. 「アクセス・キー」を入力します(AWSコンソールから作成された)。 7. 「秘密キー」を入力します(AWSコンソールから作成された)。 8. リージョンを選択します。(東京リージョンの場合、「ap-northeast-1」となります。) Get AWS credentials from runtime (environment variables or EC2/ECS meta data if no env vars). Only applies if access_key_id and secret_access_key is blank. Enter a boolean value (true or false). Press Enter for the default ("false"). Choose a number from below, or type in your own value 1 / Enter AWS credentials in the next step \ "false" 2 / Get AWS credentials from the environment (env vars or IAM) \ "true" env_auth> 1 AWS Access Key ID. Leave blank for anonymous access or runtime credentials. Enter a string value. Press Enter for the default (""). access_key_id> Your_Access_Key AWS Secret Access Key (password) Leave blank for anonymous access or runtime credentials. Enter a string value. Press Enter for the default (""). secret_access_key> Your_Secret_Key Region to connect to. Enter a string value. Press Enter for the default (""). Choose a number from below, or type in your own value ...... / Asia Pacific (Tokyo) Region 14 | Needs location constraint ap-northeast-1. \ "ap-northeast-1" ...... region> ap-northeast-1 他の設定にはデフォルトのオプション(Enterキーを押す)を使用しますが、ここでは省略します。 設定の最後は、次のようになります。 Edit advanced config? y) Yes n) No (default) y/n> n -------------------- [aws] type = s3 provider = AWS access_key_id = Your_Access_Key secret_access_key = Your_Secret_Key region = ap-northeast-1 -------------------- y) Yes this is OK (default) e) Edit this remote d) Delete this remote y/e/d> y Current remotes: Name Type ==== ==== aws s3 oci s3 これで、ソース/ターゲット・クラウドへの接続が正常に構成されました。以下のコマンドで接続を確認できます。 AWS接続の確認 Command: rclone listremotes - 設定ファイルから利用可能なすべてのリモートを一覧表示します。 rclone lsd <remote:> - バケット一覧を表示します。 (":"を忘れずに) rclone ls <remote:path> - 指定されたバケット内のすべてのオブジェクトを一覧表示します。 [opc@linux7 ~]$ rclone listremotes aws: oci: [opc@linux7 ~]$ rclone lsd aws: -1 2021-09-10 15:02:49 -1 mysourcebucket001 [opc@linux7 ~]$ rclone ls aws:mysourcebucket001 747 tmp1.txt 257 tmp2.txt 3346 tmp3.txt 10509 tmp4.txt 1572 tmp5.txt 933 tmp6.txt 1080 tmp7.txt 1232 tmp8.txt 1233 tmp9.txt [opc@linux7 ~]$ 6. データコピーの実施 コピー前: 現在、ターゲットバケットには何もない状態です。 [opc@linux7 ~]$ rclone ls oci:Target_Bucket [opc@linux7 ~]$ コピー用コマンド: rclone copy source:sourcepath dest:destpath 必要に応じてフラグ(オプション)を追加できます。 --verbose - 出力結果に多くのメッセージを出すように。 --dry-run - 何もコピーせずにテストだけをする。 -P/--progress - リアルタイムの転送統計を表示するフラグ。 --max-age 24h - 最近変更された(24時間)すべてのファイルをコピーする "rclone copy"コマンドの詳細を知りたい方は、こちらのマニュアル をご確認ください。 コマンドの出力結果: [opc@linux7 ~]$ rclone --verbose copy aws:mysourcebucket001 oci:Target_Bucket 2021/09/12 12:51:09 INFO : tmp2.txt: Copied (new) 2021/09/12 12:51:09 INFO : tmp1.txt: Copied (new) 2021/09/12 12:51:09 INFO : tmp6.txt: Copied (new) 2021/09/12 12:51:09 INFO : tmp4.txt: Copied (new) 2021/09/12 12:51:09 INFO : tmp5.txt: Copied (new) 2021/09/12 12:51:09 INFO : tmp3.txt: Copied (new) 2021/09/12 12:51:09 INFO : tmp7.txt: Copied (new) 2021/09/12 12:51:09 INFO : tmp8.txt: Copied (new) 2021/09/12 12:51:09 INFO : tmp9.txt: Copied (new) 2021/09/12 12:51:09 INFO : Transferred: 20.419Ki / 20.419 KiByte, 100%, 0 Byte/s, ETA - Transferred: 9 / 9, 100% Elapsed time: 0.4s [opc@linux7 ~]$ コピー後: これで、ソースバケットのデータがコピーされました。 [opc@linux7 ~]$ rclone ls oci:Target_Bucket 747 tmp1.txt 257 tmp2.txt 3346 tmp3.txt 10509 tmp4.txt 1572 tmp5.txt 933 tmp6.txt 1080 tmp7.txt 1232 tmp8.txt 1233 tmp9.txt [opc@linux7 ~]$ 以上
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS lambda@Edge単体テスト(イベントテンプレート)

AWS lambdaを書く時、いちいちデプロイしてテストしてました。 実際どういうリクエストが来るかはある程度イベントテンプレートでまかなえるようです。 lambda@edgeを書いていて、デプロイなどがとても面倒でしたが、これでかなり進みました。 以下の画像はcloudfront-normalize-querystring-to-improve-cache-hitというテンプレートです。 単純にCloudfrontにGetリクエストが来たような感じですかね curl https://[CFドメイン]/test?size=LARGE&color=RED 実際に受け取るeventと比較してキー名などは一致してるみたいなので、使えそう. もしCookieをつけるなら以下のようなものをheadersブロックに追加してあげれば良さそう。 "cookie": [   {     "key": "cookie",     "value": "aaaaa=hogehoge; hoge=200000; status=200"   } ],
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSサーバレスでTerraformビルド

Terraformとは? Terraformはオープンソースであり、HashiCorpによってGo言語で開発されました。具体的にはTerraformではインフラの構成をコードで宣言します。構造化された構成ファイルでは、手動で操作することなくインフラ構成を自動で管理できます。インフラの初期プロビジョニング、更新、破棄、いずれもTerraformではコードにより宣言し、実行します。 AWS の Terraform モジュールは、AWS 統合と自動化ネームスペースページの Terraform レジストリで入手できます。提供されているリンクを使用して、Terraform レジストリのモジュールや GitHub のソースコードにアクセスします。 Terraformビルド順番 ①IAMアカウント作成 ➁CLIユーザー作成 ③Terraformインストール ④DynamoDBとS3作成 ⑤Terraform展開 ①IAMアカウントを作成する AWSへログインしてIAM serviceにアクセスする ➁CLIユーザー作成 アクセスタイプはProgramatic accessをチェックする CLIユーザー作成後権限グループを作成してアクセス権限へ付与する。 Showボタンを押下でAccess key IDとSecret access key ーを取得して、アップデートを行います。 ここまでIAMアカウントとcliユーザーの作成が完了しました。これからTerraformビルドを紹介したいと思います。 AWSでCLIをインストールする https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html ローカル環境により適切なOSバージョンを選択の上、インストールを実行する。 CLIインストールが完了したらterminalを開き、「aws configure」コマンドを実行する。 $ aws configure AWS Access Key ID [None]: [Access Key ID] AWS Secret Access Key [None]: [Secret Access Key] Default region name [None]: ap-xxxxx-1 Default output format [None]: json ③Terraformインストール まずは下記のリンクにてTerraformをインストールする https://learn.hashicorp.com/tutorials/terraform/install-cli インストールが完了したら下記のコマンドを実行する terraform -v 下記の情報が表示されます。 ④DynamoDBとS3作成 情報を確認の上、インフラ構成の作成を行います。 Terraformの設定を保存するために、DynamoDBとS3の作成を行い。 Terraformファイルで環境設定を指定する必要があります、下記のように環境を合わせて修正する。 variable "env"{ default="prod" } variable "developer"{ default="dev" } variable "project_version"{ default="v01" } Terraformの必要なモジュールの設定ため、Terminalで下記のコマンドを実行する terraform init このメッセージが表示されます。 │ If you wish to attempt automatic migration of the state, use "terraform │ init -migrate-state". │ If you wish to store the current configuration with no changes to the │ state, use "terraform init -reconfigure". エラーが発生しない場合はAWSに展開するもののバリデーションと成果テストのため、下記のコマンドを実行します。 terraform plan AWSへ適用ため、applyコマンドを実行します。 terraform apply 結果は下記のイメージが表示されます。 DynamoDBとS3は下記のように作成されます。 ⑤Terraform展開 Teraformファイルで作成したdynamodbとs3バケットをコピーする。 teraform{ required_version=">=0.12.0" backend="S3"{ region ="ap-xxxx-1" bucket =prod-xxxx-terraform-v01" dynamodb_table ="prod-xxxx-terraform-state-lock-v01" key ="./terraform.tfsate" } } 更新後Terminalを開いて下記のコマンドを実行する terraform init terraform plan (※) terraform apply ※lock stateエラーが発生する時に、コマンドに -lock=falseを追加してから実行します。 実行が完了したら、下記のイメージで表示されます。 Run terraform success output updateを上にコピーします Outputs: bastion_security_group = "prod-abc-testsite-bastion-sg-20210811125740118500000005" examinator_cloudfront = "d3pxoqov8cscxi.cloudfront.net" examinator_domain = "prod-examinator.kh-site_services.net" examinator_s3_bucket = "prod-examinator.kh-site_services.net" kh_cloudfront = "d1fvmjxi4u4mf7.cloudfront.net" kh_domain = "prod-cms-kh.kh-site_service.net" kh_s3_bucket = "prod-cms-kh.kh-site_service.net" domain_certificate = "Region: {us-xxx-1}. Cer: *.kh-site_service.net" abc_ecs_alb = "prod-abc-xxx-alb-1805414999.ap-northeast-1.elb.amazonaws.com" abc_vpc = "vpc-0788d809b4d578c05" abc_vpc_security_group = "sg-0da36f8fd568866c1" abc_vpc_subnet_database = [ "subnet-10a6ea0769944a11a0", "subnet-209a6bc288ef8cb88c", "subnet-30d8aa8be98e25b86a", ] abc_vpc_subnet_private = [ "subnet-10b9fa501f91b3b3c8", "subnet-10db375eec3d7bf36a", "subnet-103ec0e4a4d174dce0", ] abc_vpc_subnet_public = [ "subnet-003adb19f3424eb1adf", "subnet-003db18f87d41965dd8", "subnet-00c619164e9187f2287", ] s3_bucket_name = "prod-abc-xxx-logo-upload" owner_cloudfront = "d3ghdpxv1nxu3f.cloudfront.net" owner_domain = "prod-cms-owner.kh-site_service.net" owner_s3_bucket = "prod-cms-owner.kh-site_service.net" Teraformビルドが完了しました。 AWSサーバーレスに関して、詳細に関して下記のホームページへ問い合わせください。 Source: https://onetech.jp/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS】AWSでデプロイ後にhttps化する方法

対象者 AWSでデプロイをおこなった方 https化したい方 目的  https化してWebサイトのセキュリティをより強固にする 実際の手順と実例 1. httpとhttpsの違い 2つの違いは 通信内容が暗号化されているかどうかです。 httpのままだとSSLが未導入であるということになります。 SSLとは インターネット上の通信を暗号化する技術のこと 2.前提 AWSでデプロイしていること nginxがインストールされていること EC2でAmazon Linux 2で環境構築していること Amazon Linuxのもつ特徴7つ|AWSとの関係も解説 3.CertBotを利用してhttps化する 1.EC2のセキュリティにhttpsを追加 EC2に紐付いているセキュリティグループを選択 インバウンドルールにhttpsを追加します。 2.nginxのconfファイルを編集 Terminalに以下のコマンドを打ってファイルを開きます。 Terminal. vi /etc/nginx/conf.d/アプリケーション名.conf /etc/nginx/conf.d/アプリケーション名.conf : : server { server_name ドメイン名; root /home/ec2-user/nginx-puma-deploy/public; access_log /var/log/nginx/access.log main; error_log /var/log/nginx/error.log; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; client_max_body_size 100M; include /etc/nginx/mime.types; location / { proxy_pass http://puma; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_redirect off; proxy_connect_timeout 30; proxy_set_header X-FORWARDED_PROTO https; #これを追加 } : : ※ viコマンドに関してはこちら 3.Certbotを実装 開発環境のターミナルから EC2にSSH接続をして 下記のコマンドを順に打ってください $ cd $ sudo wget -r --no-parent -A 'epel-release-*.rpm' http://dl.fedoraproject.org/pub/epel/7/x86_64/Packages/e/ $ sudo rpm -Uvh dl.fedoraproject.org/pub/epel/7/x86_64/Packages/e/epel-release-*.rpm $ sudo yum-config-manager --enable epel* $ sudo yum install -y certbot python2-certbot-nginx $ sudo certbot --nginx 最後のコマンド実行後下記5つの質問があります。 (Terminalには英語で表示されます。) Terminal. 1.緊急時の通知用メールアドレスを入力 し、[Enter]キーを押す 2.利用規約への同意が表示されるので、「Y」と入力 して[Enter]キーを押す 3.Electronic Frontir Foundationへのメール共有を訊かれるので、「N」と入力 して[Enter]キーを押す 4.対象ドメインを確認し、数字をカンマ区切りで入力して[Enter]キーを押す 5.HTTPへのアクセスをHTTPSに自動リダイレクトを訊かれるので、「2」と入力 して[Enter]キーを押す 下記のように表示されれば、https化完了です! Terminal. Congratulations! You have successfully enabled https://hoge.com Certbotとは 無料かつ自動でSSL証明書を発行できるツールです。 参照 Certbotを使ってSSL証明書を発行し、HTTP通信を暗号化しよう httpsとhttpの違い Amazon Linuxのもつ特徴7つ|AWSとの関係も解説
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Red Hat OpenShift on IBM CloudのクラスターをAmazon EKS ConnectorでEKSコンソールに接続する

Amazon EKS Connector Amazon EKS Connectorは、EKS外の既存のKubernetesクラスターをAmazon EKSコンソールで表示することができる機能です。操作ができるわけではありません。これで何がうれしいかは難しいところですが、複数のKubernetesクラスターを一見一元管理できているように見えるので、マルチクラウド環境でクラスタが乱立した際に、マネージメント向けの印象は良くなるかもしれません。 目的 今回はIBM CloudのRed Hat OpenShift on IBM Cloud(ROKS)をEKS ConnectorでEKSコンソールに表示してみます。 なお、2021年9月時点のEKS ConnectorはまだPreviewリリースのため、GA後の仕様は変更される可能性があります。 手順 公式ガイドはこちらです。 IAMポリシーの追加(AWS) 下記ファイルを作成します。 eks-connector-agent-trust-policy.json { "Version": "2012-10-17", "Statement": [ { "Sid": "SSMAccess", "Effect": "Allow", "Principal": { "Service": [ "ssm.amazonaws.com" ] }, "Action": "sts:AssumeRole" } ] } eks-connector-agent-policy.json { "Version": "2012-10-17", "Statement": [ { "Sid": "SsmControlChannel", "Effect": "Allow", "Action": [ "ssmmessages:CreateControlChannel" ], "Resource": "arn:aws:eks:*:*:cluster/*" }, { "Sid": "ssmDataplaneOperations", "Effect": "Allow", "Action": [ "ssmmessages:CreateDataChannel", "ssmmessages:OpenDataChannel", "ssmmessages:OpenControlChannel" ], "Resource": "*" } ] } IAMに登録します。 $ aws iam create-role --role-name AmazonEKSConnectorAgentRole --assume-role-policy-document file://eks-connector-agent-trust-policy.json $ aws iam put-role-policy --role-name AmazonEKSConnectorAgentRole --policy-name AmazonEKSConnectorAgentPolicy --policy-document file://eks-connector-agent-policy.json クラスタの登録(AWS) 今回はCLIを使います。 $ aws eks register-cluster --name roks-public-tok --connector-config roleArn=arn:aws:iam::************:role/AmazonEKSConnectorAgentRole,provider="OPENSHIFT" EKSコンソールを確認します。一覧にクラスターが表示され、ステータスが保留中となります。 クラスターを選択するとマニフェストファイルがダウンロードできます。この操作は1回しかできませんので、必ずダウンロードしてください。 ServiceAccountの変更(IBM Cloud) ガイドには記載がなく、OpenShift固有の手順です。EKS ConnectorのPod内にrootユーザーで実行されるコンテナがあるため、rootで実行可能なようにServiceAccountにSCCを設定します。 $ oc create ns eks-connector namespace/eks-connector created $ oc create sa eks-connector -n eks-connector serviceaccount/eks-connector created $ oc adm policy add-scc-to-user anyuid -z eks-connector -n eks-connector clusterrole.rbac.authorization.k8s.io/system:openshift:scc:anyuid added: "eks-connector" EKS Connectorのデプロイ(IBM Cloud) 先ほどダウンロードしたマニフェストファイルを登録します。 $ oc apply -f roks-public-tok.yaml Warning: oc apply should be used on resource created by either oc create --save-config or oc apply namespace/eks-connector configured secret/eks-connector-activation-config created role.rbac.authorization.k8s.io/eks-connector-secret-access created serviceaccount/eks-connector created secret/eks-connector-token created rolebinding.rbac.authorization.k8s.io/eks-connector-secret-access created configmap/eks-connector-agent created statefulset.apps/eks-connector created EKSコンソールで確認します。この段階ではエラーになりますが、ステータスがアクティブになります。 ClusterRoleの設定(IBM Cloud) テンプレートをダウンロードします。 $ curl -o eks-connector-clusterrole.yaml https://amazon-eks.s3.us-west-2.amazonaws.com/eks-connector/manifests/eks-connector-console-roles/eks-connector-clusterrole.yaml 最下部の%IAM_ARN%を自ユーザーのARNに書き換えます。 eks-connector-clusterrole.yaml --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: eks-connector-service subjects: - kind: ServiceAccount name: eks-connector namespace: eks-connector roleRef: kind: ClusterRole name: eks-connector-service apiGroup: rbac.authorization.k8s.io --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: eks-connector-service rules: - apiGroups: [ "" ] resources: - users verbs: - impersonate resourceNames: # TODO: 1. ADD your IAM identity arn here # - "%IAM_ARN%" - arn:aws:iam::************:user/teru ClusterRoleを追加します。 $ oc apply -f eks-connector-clusterrole.yaml clusterrolebinding.rbac.authorization.k8s.io/eks-connector-service created clusterrole.rbac.authorization.k8s.io/eks-connector-service created 続いてもう1つテンプレートをダウンロードします。 $ curl -o eks-connector-console-dashboard-full-access-group.yaml https://amazon-eks.s3.us-west-2.amazonaws.com/eks-connector/manifests/eks-connector-console-roles/eks-connector-console-dashboard-full-access-group.yaml こちらも同様に%IAM_ARN%を変更します。 eks-connector-console-dashboard-full-access-group.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: eks-connector-console-dashboard-full-access-clusterrole rules: - apiGroups: - "" resources: - nodes - namespaces - pods - events verbs: - get - list - apiGroups: - apps resources: - deployments - daemonsets - statefulsets - replicasets verbs: - get - list - apiGroups: - batch resources: - jobs verbs: - get - list --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: eks-connector-console-dashboard-full-access-clusterrole-binding subjects: - kind: User # name: "%IAM_ARN%" name: arn:aws:iam::************:user/teru apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: eks-connector-console-dashboard-full-access-clusterrole apiGroup: rbac.authorization.k8s.io --- ClusterRoleを登録します。 $ oc apply -f eks-connector-console-dashboard-full-access-group.yaml clusterrole.rbac.authorization.k8s.io/eks-connector-console-dashboard-full-access-clusterrole created clusterrolebinding.rbac.authorization.k8s.io/eks-connector-console-dashboard-full-access-clusterrole-binding created EKSコンソールの確認(AWS) 画面をリロードするとROKSの状態が確認できるようになります。 まとめ 基本は公式ガイド通りですが、ROKS(OpenShift)固有でSCC設定が追加で必要となります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

EC2でFX自動売買サーバーを構築する

FX自動売買をするため、Amazon Lightsailを利用したが課題があり、 EC2で改めて環境構築することにした AMI選定 「いろいろなシチュエーションでのWindows AMIの選び方について整理してみた」を参考にCloudShellにて検索 今回は「Windows_Server-2022-Japanese-Full-Base-2021.08.25」を利用する aws ec2 describe-images \ --region ap-northeast-1 \ --owners amazon \ --filters "Name=platform,Values=windows" \ "Name=name,Values=Windows_Server-*-Japanese-*-Base-*" \ --query "sort_by(Images, &Name)[].[ImageId, Name]" \ --output text EC2起動 比較的料金の安いオハイオリージョンにてインスタンスの起動を押下 「Windows_Server-2022-Japanese-Full-Base-2021.08.25」を検索 メモリ1GBの「t2.micro」を選択 終了保護を有効化、他はデフォルトのまま  ※VPCは以前作成したものを流用 容量はWindowsの最低要件32GBを満たすために40GB、ボリュームタイプはより安価なgp3を選択 新規のSGを作成、マイIPのみアクセスを許可する 問題なければ起動を押下 任意のキーペア名を入れ、pemをダウンロード後、インスタンス作成を押下 インスタンスが正常に起動したことを確認 ログイン 接続ボタンを押下 RDPクライアントタグからパスワードを取得 pemを指定し、パスワードを複合化 ログイン情報を取得する ログイン情報を利用してRDP接続 ログインできることを確認 MT4インストール 「Amazon LightsailでFX自動売買サーバーを構築する」を参照 感想 日本語版WindowsのAMIを利用することで設定やMT4の文字化けはなくなったので楽だった OSのバージョンは最新のイメージが使えた 今回スペックを上げたのでフリーズせずに動いてほしい うまくいきそうならCloudWatchでの監視とアラートもしていきたい
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SAA勉強中にわからなかった用語2

フェイルオーバー 稼働中のシステムやサーバに障害が発生した場合、あらかじめ用意しておいた経路と同等の待機システムに切り替える機能のこと プロビジョニング 必要に応じてネットワークやコンピュータの設備などのリソースを提供できるよう予測し、準備しておくこと インスタンス ユーザデータ OSの起動スクリプト EC2インスタンスの初回起動時(作成時)に実行したい処理を設定する。 インスタンス メタデータ インスタンスIDやIPアドレス、ホスト名などEC2インスタンス自身に関するデータ。 実行中のEC2インスタンスは設定や管理の為にメタデータを利用する事ができる。 ※ メタデータとユーザデータは暗号化手法によって保護されない エイリアスレコードとCNAMEレコード エイリアスレコード エイリアスレコードは、次のように、選択した AWS リソースにのみクエリをリダイレクトできます。 - Amazon S3 バケット - CloudFront ディストリビューション - 同じ Route 53 ホストゾーンの他のレコード 例えば、acme.example.com という名前の Amazon S3 バケットにクエリをリダイレクトする acme.example.com という名前のエイリアスレコードを作成できます。example.com ホストゾーン内の zenith.example.com という名前のレコードにクエリをリダイレクトする acme.example.com エイリアスレコードを作成することもできます。 CNAMEレコード CNAME レコードは、DNS クエリを任意の DNS レコードにリダイレクトできます。例えば、acme.example.com からzenith.example.com または acme.example.org にクエリをリダイレクトする CNAME レコードを作成できます。クエリのリダイレクト先ドメインの DNS サービスとして Route 53 を使用する必要はありません。 Amazon Kinesis Firehose と Kinesis Streams Amazon Kinesis Firehose ストリーミングデータをデータレイクやデータストア、分析サービスに確実にロードする最も簡単な方法を提供するサービス VPCピアリング接続 異なるVPCを接続することができる インスタンスにパブリックIPアドレスが割り当てらている必要はない NATゲートウェイとNATインスタンス Classic Load Balancer と比較して Application Load Balancer メリット ELBはCLBとALBとNLBの総称 - 複数のロードバランサーを統合してコストを削減できる - パスベースのルーティングサポート - ホストベースのルーティングサポート - 標準及びカスタムのHTTPヘッダーとメソッド、クエリパラメータ、送信元IPアドレスなどリクエスト内のフィールドに基づくルーティングサポート 暗号化を使用したデータの保護 S3を使用した保存データの暗号化 - SSE SSE-KMS:KMS提供の鍵 SSE-C: お客様提供の鍵 CSE S3にアップロードする前にデータを暗号化 クライアント側でS3からダウンロードした後にデータを復号化 SSE-S3 各オブジェクトは強力な他要素暗号化機能を備えた一意キーで暗号化される 定期的に更新されるマスターキーで暗号化される AES-256 SSE-KMS S3と同様だが、追加利点がある - S3オブジェクトへの不正アクセスに対する追加保護を提供するエンベロープキー(暗号化キーを保護するキー)を使用するための個別のアクセス権限 - いつ、だれによってキーが使用されたかの監査証跡が提供 SSE-C 暗号化キーとAmazonS3が暗号化によって、ディスクに書き込む際の暗号化と、オブジェクトにアクセスする際の複合が管理される クライアント側の暗号化 S3に送信する前にデータが暗号化 暗号化キー - AWS KMSで管理されたカスタマーマスターキー - クライアント側のマスターキー
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS SAM】AuthorizationError: ポリシーが効かない場合に確認したい罠

はじめに SAMでStepFunctionsや、Labmdaのリソースにポリシーを設定する際に、SAM policy templatesを利用することは多いかと思う。 しかし、リソースの設定が間違っていてうまく実行ロールに権限が渡っていないことがあった。 確認事項 ポリシーによって、 リソースのARNが必要か あるいは名前などの単なる値が必要か が異なる。 例えば LambdaからSNSのトピック発行する場合 NGな例 Resources: HogeTopic: Type: AWS::SNS::Topic Properties: TopicName: fuga-fuga HogeLambda: Type: AWS::Serverless::Function Properties: Policies: - SNSPublishMessagePolicy: ++ TopicName: !Ref HogeTopic OKな例 Resources: HogeTopic: Type: AWS::SNS::Topic Properties: TopicName: fuga-fuga HogeLambda: Type: AWS::Serverless::Function Properties: Policies: - SNSPublishMessagePolicy: ++ TopicName: !GetAtt HogeTopic.TopicName でも DynamoDBの時は...以下が正解。 Policies: - DynamoDBCrudPolicy: TableName: !Ref HogeTable ARNが必要か、値が必要か ポリシーによって、 リソースのARNが必要か あるいは名前などの単なる値が必要か が異なる。 ドキュメントをよく読めばわかる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む