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

【Android】ObjectMetadata.setContentEncoding で文字化け【AWS】

AWS(s3)Android サンプルコードを試していたのですが、
アップロードしたファイルの文字化けで手間取ったのでメモ。

文字化けしたコード
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType("text/plain");
metadata.setContentEncoding("UTF-8");   // "utf-8"も"UTF8"も試したけどダメ
うまくいったコード
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType("text/plain;charset=utf-8");

setContentEncodingなんて、期待しちゃうにきまってるじゃないですか。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS】SysOpsアドミニストレーター-アソシエイト(SOA)合格記

はじめに

AWS認定試験-SysOpsアドミニストレーター-アソシエイト(SOA)に合格した(2020-08-10)ので、合格までの道のりを残しておこうと思います。
CLF合格記は以下をご覧ください。
【AWS】クラウドプラクティショナー(CLF)合格記

SAA合格記は以下をご覧ください。
【AWS】ソリューションアーキテクト-アソシエイト(SAA)合格記

SOAはSAA合格後すぐに勉強を始めました。

What's SOA?

まずは、SOA試験について
AWS 認定 SysOps アドミニストレーター – アソシエイト

上記サイトによると、認定によって検証される能力は以下のようです。

  • スケーラブルで、高可用性および高耐障害性を備えたシステムを AWS でデプロイ、管理、運用する
  • AWS との間のデータフローを実装および制御する
  • コンピューティング、データ、セキュリティ要件に基づく適切な AWS のサービスを選択する
  • AWS 運用のベストプラクティスの適切な使用方法を識別する
  • AWS の使用コストを予測し、運用コストコントロールメカニズムを識別する
  • オンプレミスワークロードを AWS に移行する

SOAはSAAよりも運用を重視した問題が多かった印象です。
ログ監視や、移行設計(snowballかDirectconnectか等)が問題としては出ました。
難易度的にはSAAよりも簡単だった印象があります。

試験に向けて

基本的にはSAAと同じ手法をとっていきました。(研修への参加はしていません。)

試験に向けて

公式サンプル問題

これはCLFと変わらず事前に受けて現状のレベルの確認をします。
私は60%ほどの出来でした。

ホワイトペーパーを読む

CLFと同じくホワイトペーパーを読みました。

Black Beltを読む

こちらもCLFと同じくBlack Beltを読みました。

問題を解く

AWS WEB問題集で学習しよう

こちらのサイトは一問ごとに解説が表示され、都度確認ができ、BlackBeltやホワイトペーパーへのリンクもあるので、勉強しやすかったです。

試験当日

上記対策を計2週間(延べ20時間程度)行い、試験に臨みました。

結果は、731点(720点以上で合格)で合格でした。

感想

SAAよりも移行関係や、データセンターとの接続方法、コストに関する問題が多めでした。
基本的に出題されるサービスに関して、SAAから新しいものがあるとは言えませんので、SAAの勉強の流れで運用に重点を置いた解答を選べるようになればいいと思います。

問題集などで試験に応じた解答を選択できるようになれば良いかと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【原因と対策】An error occurred (InvalidClientTokenId) when calling the GetCallerIdentity operation: The security token included in the request is invalid.

AWS-CLIで

An error occurred (InvalidClientTokenId) when calling the GetCallerIdentity operation: The security token included in the request is invalid.

というエラーが出た時の備忘録。

原因

そのままGoogle翻訳にぶち込んでみる。

GetCallerIdentity操作の呼び出し中にエラーが発生しました(InvalidClientTokenId):要求に含まれているセキュリティトークンが無効です。

セキュリティトークンが無効だとおっしゃっている。

では「aws configure list」を入力してアクセスキーとシークレットキーを確認してみよう。

      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************hoge shared-credentials-file
secret_key     ****************fuga shared-credentials-file
    region           ap-northeast-1      config-file    ~/.aws/config

おそらく上記エラーが出ている場合、意図したアクセスキー、シークレットキーの値と異なっているはず。
なぜか?

AWS-CLIを導入した際に「aws configure」を設定したと思うが、その時の設定が残っているからである。

私の場合は、AWSの練習でIAMユーザーをちょくちょく作ったり消したりしていたので、以前作ったIAMユーザーのアクセスキー、シークレットキーが反映された状態になっていた。
おそらくほとんどのケースがこんな感じなのではないかと思う。

解決策

もう一度

aws configure --profile IAMユーザー名

を実行して、意図しているアクセスキーとシークレットキーに設定し直す。

ターミナルで別タブを開いて、再度「aws configure list」を入力。

アクセスキー、シークレットアクセスキーが意図したものに変更されていればOK。

参考

https://qiita.com/kaito_program/items/7b9ba489e44d2295cf6f

https://qiita.com/ryuzee/items/e3ce493f132f1981f57a

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Step Functions 値の受け渡しについて

こんにちは。GxPの2年目の伊藤です。
この記事はグロースエクスパートナーズ アドベントカレンダーの6日目の記事となります。

「今年の学び」がテーマということで、僕は今年の4月から案件が変わりAWSへ移行する案件に就くことになりました。AWSについてほとんど知識のない状態でしたが、仕事を通してAWSについてだけではなく多くのことを学ばせてもらいました。
今回の記事はTerraformで管理しているStep FunctionsでECS Taskを実行したときに値を渡したかったのですが、そのやり方で詰まったのでその方法の紹介になります。

構成

CloudWatch Eventsから直接ECS Taskを起動することもできますが、監視をしやすくするためにStep Functionsを挟んでいます。

スクリーンショット 2020-12-02 10.42.59.png

バージョン
Terraform: 0.12.20
aws provider: 3.13.0

Step Functionsから値を受け渡す

上記の構成だったのですが、ECS Task実行時に値を渡す必要が出てきました。そこで、Step Functionsから値を受け渡して実行できるようにしなくてはなりませんでした。
僕たちの案件ではAWSのリソースをTerraformで管理していたため、Step Functionsだと実行時のポップアップのJSONがECS Taskに値を渡す場所になりますが、Terraformだとどのように書くのかわからず詰まってしまいました。

こちらでStepFunctionsの入出力制御について丁寧に説明されています。
参考にするとState InputがStep Functions実行時のポップアップのJSONに当たります。今回はここから値を入れてあげたいのですが、どうやればよいのか分からなかったという話です。
スクリーンショット 2020-12-01 1.18.31.png

Step Functionsの定義

StepFunctionsでECSを操作についてのAWSのドキュメントを参考にするとOverridesを使うとStep FunctionsからECSへ値を渡せるようでした。そこで以下のようにStep Functionsのoverridesを定義することで環境変数を設定することができました。

StepFunctionsの定義
  "Parameters":{
    "Overrides":{
      "ContainerOverrides":[
        {
          "Environment":[
            {
              "Name":"hoge",
              "Value.$":"$.VALUE"
            }
          ],
          "Name":"hoge-task"
        }
      ]
    },

これによりECS Taskにhogeという名前でState Inputから受け取ったVALUEの値を環境変数として設定し、値を渡すことができるようになります。$.を使うことによって実行中のJSONの値を取り出すことができます。

注意1:渡し先のECS TaskのNameもちゃんと設定してあげないとエラーになります。

注意2:.$を使う場合はダブルクォーテーションで括ってあげないとちゃんと認識してもらえませんでした。

注意3:StepFunction定義のキーに .$を使って値をパス解決させた場合、実行時にJson-pathが表すキーが存在しないとエラーになります。つまり、State Inputにキーを与えないといけません。
kako-t3DYfD7a8M2FAXxl.png

CloudWatch Eventsの定義

このままではCloudWatch Eventsから実行したときにJson-pathが表すキーが存在しないため、CloudWatch EventsからStepFunctionsに渡すinputを設定しました。
Step FunctionsにVALUEという名前で値を渡してくれます。

CloudWatchEvents
resource "aws_cloudwatch_event_target" "cloudwatch_event" {
  ...
  input    = "{\"VALUE\" : \"\"}"
}

確認

Step Functionsの手動実行時のポップアップのJSONに画像のようにキーを設定し、実行後TaskSubmittedのjsonのEnvironmentのNameとValueが設定されていればECS Taskに値を渡すことができるています。
スクリーンショット 2020-12-01 17.54.31.png

TaskSubmitted
    "Overrides": {
      "ContainerOverrides": [
        {
          "Command": [],
          "Environment": [
            {
              "Name": "hoge",
              "Value": ""
            }
          ],
          "EnvironmentFiles": [],
          "Name": "hoge-task",
          "ResourceRequirements": []
        }
      ],
      "InferenceAcceleratorOverrides": []
    }

最終的に以下のように値の受け渡しがされています。
スクリーンショット 2020-12-03 11.28.22.png

今回の学び

ほとんど分からなかった状態からチームメンバーの助けを借りつつも自分で調べて解決することができたので自信を付けることが出来ました。
AWSのドキュメントは難解なところはありましたが、ちゃんと読み解くと欲しい情報は結構書いてあったりするので他の記事を参考にしつつも頑張って読むことが大切だなと思いました。
これからも多くのことに触れて学びを増やしていこうと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CloudFrontでアクセスログを有効にするとS3のACLに見慣れない外部アカウントの権限がつくのでビビった話

長いですが題の通りです。

起きた事

AWSの設定を見ていたら、S3のACL(権限周りの設定ね)に見慣れない外部アカウントに対して権限がついている!これはセキュリティにやばいのでは(゚A゚;)ゴクリ

image.png

種明かし

CloudFrontでLogの出力先をS3にすると、自動でこうなります。なので安全です。大丈夫です。

CloudFrontのログはawslogsdelivery というAWSアカウント(!)を経由して出力される仕組みになっています。で、このawslogsdeliveryのアカウントIDが c4c1ede66af53448b93c283ce9448c4ba468c9432aa01d700d3878632f77d2d0 なのです。

AWSのdocの該当部分

ディストリビューションを作成または更新してロギングを有効にすると、CloudFront はこれらのアクセス許可を使用してバケットの ACL を更新し、awslogsdelivery アカウントに FULL_CONTROL のアクセス許可を付与します。awslogsdelivery アカウントはログファイルをバケットに書き込みます。

やっかいなのが、この設定をCloudFrontでLogの設定をした時に自動でやってくれるため、S3の設定としては意識されない事です。よって、知らないうちに変なIDが追加されてる!という状況が発生します。怖いですね。

c4c1ede66af53448b93c283ce9448c4ba468c9432aa01d700d3878632f77d2d0 というIDを見たら、
?「あ、これは awslogsdelivery のアカウントIDだな」
と思い出してくださいね(無理でしょ)

参考

classmethodさんの記事
AWSのdoc

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Amazon SageMakerとAzure MLにおける機械学習モデルのサービング技術比較(後編)

初版: 2020年11月24日

著者: 橋本恭佑、柿田将幸, 株式会社 日立製作所

はじめに

本連載では、ストリーム型の機械学習システムをサービングする技術について、
Amazon SageMakerとAzure Machine Learningを比較した結果を紹介しています。
後編では、実際にストリーム型の機械学習システムを両クラウドでサービングして、本投稿で紹介した違いが現れること、
また、SEがAmazon SageMakerとAzure Machine Learningのいずれかの利用を、どのような基準で選択するべきかについて議論します。
なお、本連載に記載のAmazon SageMakerまたはAzure MLの情報は2020年9月末日現在のものであり、今後のアップデート等によって内容が変わることがあります。

投稿一覧

  1. Amazon SageMakerとAzure MLにおける機械学習モデルのサービング技術比較(前編)
  2. Amazon SageMakerとAzure MLにおける機械学習モデルのサービング技術比較(後編)・・・本投稿

パブリッククラウドにおけるサービング実機検証と検証項目

Amazon SageMakerとAzure MLでランタイムを作成し、前編で示した相違点を実機で比較します。
ランタイムは次の手順で作成されます。
1. パブリッククラウドが提供するOSSの入ったコンテナイメージを指定する
2. モデル、前処理、後処理コードを呼び出す
3. 1と2をコンテナとしてコンテナ基盤上にデプロイする

11_パブリッククラウドにおけるランタイム作成手順.png

検証項目は以下の通りです。
1. 前処理コードや後処理コードの実装方法の違い
2. ランタイム作成時のOSS追加可否
3. ランタイム作成時のコンテナ基盤指定有無

検証1: 前処理コードと後処理コードの実装方法の比較

Amazon SageMakerでは前処理や後処理を別の関数で書くため、可読性が高くランタイム作成後のコード変更が容易と考えられます。
一方でAzure MLは前処理と後処理を1つの関数に書くため、モデル訓練時の実装に近く、訓練時のコードを流用しやすいと考えられます。

12_前処理コードと後処理コードの実装方法の比較.png

検証2: ランタイム作成時のOSS追加可否

Azure MLではランタイム作成時にpipやcondaを利用してOSSを追加できます。
モデル訓練には不要だが推論システム作成には必要なOSSがある場合に、それらをすぐに追加できます。
したがって、最初の推論システムを作成するのに要する時間が短いと考えられます。

13_ランタイム作成時のOSS追加可否.png

検証3: ランタイム作成時のコンテナ基盤指定有無

Azure MLではランタイム作成先のコンテナ基盤を別途用意して指定する必要があり、コンテナ基盤(AKS)の知識が必要です。

14_ランタイム作成時のコンテナ基盤指定有無.png

実機検証を通したAmazon SageMakerとAzure MLの特徴考察

Amazon SageMakerには以下の特徴があり、推論システム作成時に問題が起こりにくいと考えられます。

  • 前処理コードや後処理コードの可読性が高く、コードの誤りに気づきやすい
  • 用意したコンテナイメージにないOSSはランタイムにインストールできない
  • コンテナ基盤を意識せずにランタイムを作成できる

一方でAzure MLにも以下の特徴があります。

  • モデル訓練には不要だが推論システム作成には必要なOSSがある場合に、すぐにそれらを追加できるため、 モデル訓練後からランタイム作成までのリードタイムが短く、顧客がすぐに推論システムを利用しやすいと考えられます。
  • 訓練時の前処理や後処理コードを推論システムに流用しやすい
  • ランタイム作成時に独自にOSSを追加できる

こうしたAmazon SageMakerとAzure MLの特徴をとらえて、いずれのベンダを利用するか検討すべきといえます。

おわりに

本投稿ではAmazon SageMakerとAzure MLにおける機械学習システムのサービング技術を比較しました。
実機検証を通して、Azure MLはモデル訓練後から推論システム構築までのリードタイムを短くしたい場合に有効であること、
それ以外の場合はAmazon SageMakerが有効である可能性が高いことを確認しました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

The security token included in the request is expiredとなった時の対応方法

事象 : Secrets Managerからシークレット値を取得しようとしたら怒られた

  • 環境
    • AWS Cloud9
    • Python 3.6.12

はじめてSecrets Managerにシークレット値を設定してCloud9からシークレット値を取得しようとした。
取得するコードは超親切にシークレット値を設定した時に表示されるのでほぼコピペで使った・・・がExpiredTokenException・・・

def get_backlog_api_key():

    secret_name = 'シークレットの名前'

    session = boto3.session.Session()
    client = session.client(
        service_name='secretsmanager',
        region_name='リージョン'
    )

    try:
        get_secret_value_response = client.get_secret_value(
            SecretId=secret_name
        )
    except ClientError as e:
        print(e.response['Error'])
        raise e
    else:
        if 'SecretString' in get_secret_value_response:
            secret = get_secret_value_response['SecretString']
        else:
            decoded_binary_secret = base64.b64decode(get_secret_value_response['SecretBinary'])
{'Message': 'The security token included in the request is expired', 'Code': 'ExpiredTokenException'}

原因 : Lambdaに権限がないから

権限の存在を忘却していた。

Minimum permissions
To run this command, you must have the following permissions:
secretsmanager:GetSecretValue
GetSecretValue - AWS Secrets Manager

対応 : 権限を付与する

  1. AWSのコンソール > Lambda > 対象の関数 > [アクセス権限]タブ > [実行ロール]からIAMの画面を開く
  2. [アクセス権限]タブ > [ポリシーをアタッチします]ボタン
  3. secretsmanagerを検索 > SecretsManagerReadWriteにチェック > [ポリシーのアタッチ]ボタンで権限追加
    • ちょっと雑、取得するだけならもっと権限の範囲は小さいほうがいいけど今はとりあえず
    • image.png
  4. Cloud9のLambdaマークから更新ボタンで更新
    • image.png
    • 更新しても :arrow_double_down: こうなっている間はうまくいかない。なんでこれが出るのかよくわからない、しばらくしてから更新すると消える。よくわからない。
      • image.png
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Code PipelineでJekyllをビルドしてS3+CloudFrontで静的配信する

はじめに

概要

Civichat(https://civichat.jp)をJekyllに変更し、S3+CloudFrontで配信するために調べていた時に記事が昔すぎ(2016年とか...)or英語だったのでせっかくだしCodePipelineやり方をまとめようと思った次第です


Civichatとは:あなたにぴったりの助成金などの公共制度がLINEでわかるサービスです。
https://civichat.jp/


Jekyllってなに?

Jekyllは、個人、プロジェクト、または組織のサイト向けの、シンプルなブログ対応の静的サイトジェネレーターです。 GitHubの共同創設者であるTom Preston-WernerによってRubyで書かれ、オープンソースのMITライセンスで配布されています。 (by Wikipedia)

要するにRubyでできた静的サイト生成ツールですね(Markdownで記事が書ける)
最近だと@Nuxt/Content とか Gatsby.js みたいな感じですね。

なぜAWS? なぜCode Pipeline? なぜCode Build?

多分 Netlify とか Vercel とかでもできるはず....
今回はAWSに請求まとめたりしたいのと、AWSを使いたかったのでAWSです。

手順

すでにGitHub上にJekyllのコード自体が存在して、ローカルでjekyll build_siteに出力されることを確認しているものとして書きます

S3のバケットを用意する

普通にバケットを作りますが、パブリックアクセスのブロックは外しておきます。
image.png

Code Pipelineでパイプラインを作る

パイプラインの設定

ここではパイプライン名を設定します
(このパイプライン名は変えられなくなるので注意)
image.png

GitHubとの接続

今回はGithubのコミットをトリガーにするのでソースプロバイダーに GitHub(バージョン2)を選択します。
GitHubに接続するをクリックし接続名を入力し、GitHubにAWS Connectorをインストールします
image.png

その後、インストールしたGitHubからリポジトリが取得できるようになるので、リポジトリ名とブランチ名を設定します。
(ねんのため塗りつぶしています)
image.png

CodeBuildの設定

プロバイダにAWS CodeBuildを指定するとプロジェクトを作成するというボタンが出るのでクリック
するとCodeBuildの設定ページが表示されるので、以下のように設定します。

プロジェクトの設定

プロジェクト名は適当に...

環境

せっかくなのでAmazon Linux 2を使いましょう
特権付与のチェックは今回は必要ないので外しておきます。
image.png

Buildspec

もしBuildspec.ymlをルートディレクトリに置けない場合にはその場所を指定してあげてください

バッチ設定・ログ設定

基本的にはそのままでよいはず

すべて設定が終わったらCodePipelineに戻るをクリックして戻ります。

image.png

戻るとAWSが自動的にプロジェクト名を入れてくれています(素敵!!)

デプロイの設定

デプロイプロバイダにAmazon S3を選択するとバケットの選択ができるようになるので、初めに作成したバケットを選択します。
また、この時 デプロイする前にファイルを抽出する にチェックをつけ忘れるとS3にビルドされたファイルがZipで出てしまうのでつけ忘れないようにしましょう
image.png

作成前の確認

いろいろまずそうなのは塗りつぶしてますが....
大事なのはFullRepositoryIdが正しいこと・ExtractTrueであることなのでそれを確認しましょう
確認したらパイプラインを作成するをクリックしてパイプラインを作ります。
image.png

buildspec.ymlを作成する

今のままだとなんの処理をすればいいかをCodeBuildに伝えていないので、接続したリポジトリのルートディレクトリにbuildspec.ymlというのを作成し、以下の内容を記述します

buildspec.yml
version: 0.2

phases:
  pre_build:
    commands:
      - export LC_ALL="en_US.utf8"
      - bundle install
  build:
    commands:
      - bundle exec jekyll build

artifacts:
  base-directory: '_site'
  files:
    - '**/*'

普通にbundle installしてjekyll buildしているだけですが、
export LC_ALL="en_US.utf8でUTF-8に固定してあげないとjekyllがエラーを吐いてしまうのでお気をつけください。

これらをCommit & Pushすると自動でPipelineが走って

image.png

このようになれば成功です!

成果物を確認する

最初に確認したバケットを見ると以下のようにいろいろとファイルがあるはずです!
これでCDについては完成です!
image.png

CloudFront + S3の設定

Create Distributionをクリックし、WebのGet Startedを選択します

Origin Settings

  • Origin Domain Name : 最初に作成したS3のを選択
  • Restrict Bucket Access : Yes
  • Origin Access Identity : Create a New Identity
  • Grant Read Permissions on Bucket : Yes, Update Bucket Policy ↑でS3バケットへのアクセス設定を変更しています image.png

Default Cache Behavior Settings

お好みで (私はいつもViewer Protocol PolicyRedirect HTTP to HTTPSにしています)

Distribution Settings

  • Price Class : お好み(Use U.S., Canada, Europe, Asia, Middle East and Africaで十分な気が)
  • Alternate Domain Names(CNAMEs) : 必要なら
  • SSL Certificate : 必要なら
  • Default Root Object : index.html
  • Standard Logging : 必要なら

image.png

設定後 Create Distribution をクリックして完了
StatusがIn Progress から DeployedになったらDomain Nameに書いてある xxxxxxxxxxxxxxxx.cloudfront.netにアクセスしてみて、接続できれば全設定完了です。

お疲れさまでした:clap:

この方法でbuildspec.ymlを変えてあげればNuxtだったり、Gatsbyでもできますが、その話はまた今度...機会があれば...ということで。

皆さんもぜひやってみてください!!
ではではー

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【備忘録】AWSでCakePHP4の環境構築

1. EC2のインスタンス作成 ~ PHP7.4インストール

「EC2立ち上げ→Apacheインストール→PHP7.4インストール」の流れはこちらの記事を参考にしました。
AWS(EC2)を立ち上げてPHPを動かす話

2. PHP拡張モジュールのインストール

$ sudo yum -y --enablerepo=remi-php74 install php74-php-intl php74-php-mbstring php74-php-pdo

apache再起動

$ sudo systemctl restart httpd

3. composerのインストール

$ curl -sS https://getcomposer.org/installer | sudo php
$ sudo mv composer.phar /usr/local/bin/composer
$ sudo ln -s /usr/local/bin/composer /usr/bin/composer

4. cakephp4のインストール

phpのバージョンが7.2以上ならcakephpのバージョンを指定しなくても自動的にversion4がインストールされると思います。

$ composer create-project --prefer-dist cakephp/app my-app

5. Apacheの設定

vimでapacheの設定ファイルを開きます。

$ sudo vim /etc/httpd/conf/httpd.conf 

DocumentRootを"/var/www/html"から先ほどインストールしたcakephpディレクトリのwebrootに変更します。
.htaccessでの設定の上書きを許可するよう、AllowOverride を All に設定します。

DocumentRoot "/var/www/html/my-app/webroot"

<Directory "/var/www/html">
    Options FollowSymLinks
    AllowOverride All
</Directory>

その後、apacheを再起動

6. 完了

ブラウザで次のように表示されればインストール完了です。
スクリーンショット 2020-11-24 13.54.29.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CDKでクロスアカウントアクセス可能なS3バケットを作成しようとしてハマったので解決方法

ハマった流れ

  1. CDKでのインフラ構成に初挑戦
  2. S3バケットを作成、別のAWSアカウントからの書き込みを許可したい
  3. できたと思ったら、別アカウントからアクセスできない事態が発生
    • ブロックパブリックアクセスをオフにした→アクセスできたが、セキュリティ面に不安
    • 公式doc見る限り、ブロックパブリックアクセスをオンにしたままクロスアカウントアクセス許可できるはず…
  4. バケット作成した→できた。
  5. そのS3バケットを Bucket.fromBucketName(...) で利用し、別サービスをデプロイしたら、クロスアカウントアクセスがまた不可に。
    • 見ると、バケットポリシーが消えている
  6. addToResourcePolicyで再付与 → できない
  7. 混乱

ブロックパブリックアクセスをオンにしたままクロスアカウントアクセス許可する方法

  • ブロックパブリックアクセスについては、全てオンでOK(CDKだと BlockPublicAccess.BLOCK_ALL は設定してOK)
  • バケットポリシーでクロスアカウントアクセスを許可するのだが、公式ドキュメントの「パブリック」の意味にしたがって、「非パブリックのポリシー」とみなされる書き方をしないと、ブロックパブリックアクセスが優先されてアクセス不可になるので注意。

というわけで今回はここの問題ではなかった。

CDKによるS3バケットの作成と利用について

  • new Bucket(...) で作成したS3バケットに addToResourcePolicy でバケットポリシーを付与可能
  • Bucket.fromBucketName(...) で呼び出したS3バケットには addToResourcePolicy等の操作ができないが、2020/11/24現在エラーは出ない。(対応するGitHubのissue
    • 別スタックやCloudFormationで管理されていないリソースの改変を防ぐための仕様、とのこと

そのため、既存のS3バケットを利用する際、同じStackで作成済みのS3バケットを利用するとクロスアカウントアクセス可能なバケットポリシー設定がうまくいかない

  • Bucket.fromBucketName(...) で呼び出したS3バケットに addToResourcePolicy で権限設定
    • 不可。.fromBucketName(...)で呼び出すとaddToResourcePolicyが使えない。
  • new Bucket(...) でバケット作成した時点で addToResourcePolicy で権限設定済みのバケットを Bucket.fromBucketName(...) で呼び出す。
    • できそうだが不可。同じスタック内でバケットポリシーを付与していて、その記述がコードから消えるので、スタックで管理されているバケットポリシーが消される。

じゃあどうするか?

  • S3バケットのスタックだけ分ける
    • アリだが、そもそも分けたスタック内でのアップデートがうまく行かないならCDKでやるメリットってないような。
  • S3は手動で管理する
    • 正直アリな気もする。イケてないけど。
  • CfnBucket で管理する

最終的なソースコード

  • (あとで追記します。)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS S3に保存しているオブジェクトを1度に1000件削除する。

やりたいこと

 削除するオブジェクトのキー名が記載されたファイルを読み込んで、ポチッと実行するだけで、削除できるようにしたい。

方針

・削除するオブジェクトのキーがかかれたファイルを用意する。
・S3のAPI(delete_objects)を利用して、ループしながらキーを指定削除する。

参考リンク
S3の削除について
pythonのdelete_objects APIについて

やったこと

・削除するオブジェクトのキーリストを作成する。

削除するオブジェクトのキーリスト
hoge/fuga/hoge.jpg
hoge/fuga/hoge.png
hoge/hoge/hoge.gif
hoge/hoge/fuga.png
・・・
fuga/fuga/fuga.png

・削除プログラムを実行する
 delete_objectsは1度に1000件しか指定できないので、読み込んだキーリストを1000件単位のリストに再分割する。分割した単位でDELETE APIを叩き、ループ実行する。
 

削除プログラム.py
import boto3
import re
import json

MY_REGION = 'リージョン名';
MY_BUCKET = 'バケット名';

client = boto3.client('s3', region_name=MY_REGION)
request_list = []
img_path_list = ''

def split_list(l):
    for idx in range(0, len(l), 1000):
        yield l[idx:idx + 1000]

# 削除データを読み込む
with open('削除するオブジェクトのキーリスト.text') as f:
    img_path_list = f.readlines()

# データ末尾の改行を削除してリストに追加する
for path in img_path_list:
    path = path.replace('\n','')
    request_list.append({'Key': path})

# リストを1000件ごとに分ける
# devide_list = [[0,...,999],[1000,...,1999],...,[n,...,n+999]]
devide_list = list(split_list(request_list))

# DELETE APIを実行する
for key_list in devide_list:
    response = client.delete_objects(
        Bucket = MY_BUCKET,
        Delete = {
            'Objects': key_list
        }
    )

    # 削除結果を記録する
    with open('log/削除結果.txt', mode='a') as f:
        for res in response['Deleted']:
            f.write(json.dumps(res))
            f.write('\n')

・削除が成功していれば、結果は下記のようになる。

削除結果.text
{"Key": "hoge/fuga/hoge.jpg", "DeleteMarker": true, "DeleteMarkerVersionId": "hogehoge1"}
{"Key": "hoge/fuga/hoge.png", "DeleteMarker": true, "DeleteMarkerVersionId": "hogehoge2"}
{"Key": "hoge/hoge/hoge.gif", "DeleteMarker": true, "DeleteMarkerVersionId": "hogehoge3"}
{"Key": "hoge/hoge/fuga.png", "DeleteMarker": true, "DeleteMarkerVersionId": "hogehoge4"}
{"Key": "fuga/fuga/fuga.png", "DeleteMarker": true, "DeleteMarkerVersionId": "hogehoge5"}

その他

削除するリストと削除しないリストを用意して、両方のリストに存在するキーがあるか確認する
Pythonで複数のリストに共通する・しない要素とその個数を取得

2つのリストに存在する要素を表示する.py
input_urls = ''
not_delete_urls = ''

# リストデータを読み込む
with open('入力リスト.txt') as f:
    input_urls = f.readlines();

with open('削除しないリスト.txt') as f:
    not_delete_urls = f.readlines();

duplicate_urls = set(input_urls) & set(not_delete_urls)

# set型からlist型に変更する
list_duplicate_urls = list(duplicate_urls)
list_duplicate_urls.sort()

# 共通要素の件数と要素を表示する
print(len(list_duplicate_urls))
for elem in list_duplicate_urls:
    print(elem, end='')

注意事項

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS認定試験の合格特典を紹介してみた

前書き

意外とQiita上ではAWS認定試験の特典に関する記事が見受けられなかったので記してみます。

なお、自分が受かったのはSAA(ソリューションアーキテクトアソシエイト)となります。
よければこちらの合格体験の記事もご参考に!

特典内容

①認定デジタルバッジの取得

ざっくり合格の証ですね。(バッジと聞くとなんかテンション上がりますよね・・・!)
現在は、Acclaim (アクレーム)というサービス上で付与されるようです。

※Acclaim:様々な資格に関するデジタルバッジを管理するサービス(?)、LinkedInなどの別SNSと連携できるので、このサービスでより簡単に資格の証明を共有できるようになったみたいです。

②AWS認定の本試験料金の半額クーポン

めちゃくちゃでかいですね。
アソシエイトレベルで税込16,500円、プロフェッショナルで税込33,000円とかするので。。

③AWS認定の模擬試験料金の無料クーポン

こちらも大きい特典ですね。
模擬試験も種類によって2000〜4000円くらいかかるので、助かります。

④LinkedInのAWS認定グローバルコミュニティへ参加できる

LinkedInの、認定者しか入れないコミュニティへ参加することができます。
正直あんまり有用性を感じていませんが、、、特別感あってなんか良いです!

⑤AWS認定ストアを使える

AWSの公式グッズが買えます。

※2020/11/24時点でのラインナップ、調べると全然内容出てくるので載せてみます。

パーカーカッコいい・・・!!

でも現在はアメリカ内の住所にしか届けられないよう。。(コロナの影響かな。)

⑥AWS Certification SME Programへの参加資格が得られる。

一緒に試験の問題を作れたりするらしいです。

詳細はこちらの記事が参考になります!

まとめ

とりあえず、認定試験に合格すれば、

  • ①認定デジタルバッジの取得
  • ②AWS認定の本試験料金の半額クーポン
  • ③AWS認定の模擬試験料金の無料クーポン

がもらえるんだ〜と認識いただければよいのかなと思います。

パーカー欲しかったなあ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWSアカウント不要】ローカル環境でAWS CDKのデプロイ&動作確認をするチュートリアル

1. はじめに

1-1. この記事で行うこと

  • LocalStackコンテナをセットアップし、動作確認
  • Node.js環境コンテナ内にAWS CDKプロジェクトを作成
  • AWS CDKプロジェクトをLocalStackへデプロイし、動作確認

1-2. この記事の対象者

  • AWS CDKを本物のAWSを使わずに動かしたい方
  • AWS CDKをすぐに捨てられる環境で色々と試してみたい方
  • AWS CDKをブラウザのみで気軽に始めてみたい方

1-3. 動作環境

このチュートリアルはブラウザだけでDockerを使用可能なPlay with Dockerを使用しております。詳細な説明は以下の記事をご参考ください。
Docker 入門にはインストールなしで使える「Play with Docker」がいいと思う

また、Play with DockerではなくてもDockerが動く環境ならおそらく同じようにチュートリアル可能だと思います (が、この記事では手順等ございませんのでご了承ください)。

  • 共通して必要なもの
    • Docker Hubアカウント
  • Play with Dockerで試す場合、必要なもの
    • Play with Dockerを操作可能なブラウザ
  • Play with Docker以外で試す場合、必要なもの
    • Dockerをセットアップ済のPC等

1-4. 各種のバージョン

2020年11月24日時点で動作確認済のバージョンは以下の通りです。

  • docker
    • Docker version 19.03.11, build 42e35e61f3
  • localstack
    • 0.12.2
  • aws-cli
    • aws-cli/2.1.3 Python/3.7.3 Linux/4.4.0-189-generic docker/x86_64.amzn.2
  • aws-cdk
    • 1.74.0
  • aws-cdk-local
    • 1.65.0

2. チュートリアル

このチュートリアルではLocalStackというローカルでAWSを擬似的に使用できるツールを用います。詳しい説明は以下の記事をご参考ください。
LocalStack を使って無料で AWS を学ぶ

このLocalStackのDockerコンテナ内に擬似的なAWS環境を立て、そこへAWS CDKをデプロイし、動作確認を行っていきます。

2-1. 最終的なファイル構成

いきなりですが、このチュートリアルが完了した状態のファイル構成です。
以下の「▶︎ 詳細」をクリックしてご確認ください。


$ tree -L 5 -I node_modules
.
├── localstack
│   ├── CHANGELOG.md
│   ├── Dockerfile
│   ├── LICENSE.txt
│   ├── MANIFEST.in
│   ├── Makefile
│   ├── README.md
│   ├── bin
│   │   └── 略
│   ├── doc
│   │   └── 略
│   ├── docker-compose.yml
│   ├── localstack
│   │   └── 略
│   ├── requirements.txt
│   ├── setup.py
│   └── tests
│       └── 略
├── node_workdir
│   ├── Dockerfile
│   ├── app
│   │   └── sample
│   │       ├── README.md
│   │       ├── bin
│   │       │   ├── sample.d.ts
│   │       │   ├── sample.js
│   │       │   └── sample.ts
│   │       ├── cdk.json
│   │       ├── cdk.out
│   │       │   ├── SampleStack.template.json
│   │       │   ├── cdk.out
│   │       │   ├── manifest.json
│   │       │   └── tree.json
│   │       ├── jest.config.js
│   │       ├── lib
│   │       │   ├── sample-stack.d.ts
│   │       │   ├── sample-stack.js
│   │       │   └── sample-stack.ts
│   │       ├── package-lock.json
│   │       ├── package.json
│   │       ├── test
│   │       │   ├── sample.test.d.ts
│   │       │   ├── sample.test.js
│   │       │   └── sample.test.ts
│   │       └── tsconfig.json
│   └── docker-compose.yml
└── s3.txt

2-2. LocalStackのセットアップ

2-2-1. LocalStackをダウンロードする

[node1] (local) root@192.168.0.18 ~
$ git clone https://github.com/localstack/localstack
Cloning into 'localstack'...
remote: Enumerating objects: 44, done.
remote: Counting objects: 100% (44/44), done.
remote: Compressing objects: 100% (39/39), done.
remote: Total 14028 (delta 15), reused 13 (delta 5), pack-reused 13984
Receiving objects: 100% (14028/14028), 5.75 MiB | 9.78 MiB/s, done.
Resolving deltas: 100% (9762/9762), done.

2-2-2. LocalStackコンテナを起動する

[node1] (local) root@192.168.0.18 ~
$ cd localstack

[node1] (local) root@192.168.0.18 ~/localstack
$ docker-compose up -d
WARNING: The TMPDIR variable is not set. Defaulting to a blank string.
Pulling localstack (localstack/localstack:)...
latest: Pulling from localstack/localstack
1cff8f8f4790: Pull complete
Digest: sha256:0e85ea6d44e3bf69a415298e72be46d06500ac038faebd98ea7bd9bcbcaab614
Status: Downloaded newer image for localstack/localstack:latest
Creating localstack_main ... done

[node1] (local) root@192.168.0.18 ~/localstack
$ cd ..

2-2-3. LOCALHOST_IP_ADDRESS変数を設定する

[node1] (local) root@192.168.0.18 ~
$ LOCALHOST_IP_ADDRESS=192.168.0.18 # 各自の環境によって異なります!

後ほど、様々なコンテナ内からホストのIPアドレスを使用することになるので、先に変数としてLOCALHOST_IP_ADDRESSを設定しておきます。
Play with Dockerの場合、root@192.168.0.18@以降の192.168.0.18を設定します (Play with Dockerでも毎回IPアドレスが固定ではないのでお気をつけください)。
それ以外の環境で試されている方は、各自で調べていただけると幸いです。

2-2-4. LocalStackのステータスを確認する

[node1] (local) root@192.168.0.18 ~
$ curl "http://${LOCALHOST_IP_ADDRESS}:4566"
{"status": "running"}

https://github.com/localstack/localstack
2020-09-15: A major (breaking) change has been merged in PR #2905 - starting with releases after v0.11.5, all services are now exposed via the edge service (port 4566) only! Please update your client configurations to use this new endpoint.
(DeepLによる翻訳)
PR #2905 に主要な (壊すような) 変更がマージされました - v0.11.5 以降のリリースから、すべてのサービスがエッジサービス (ポート 4566) のみを介して公開されるようになりました! この新しいエンドポイントを使用するために、クライアントの設定を更新してください。

公式githubにport 4566のみで動いてると書いてあるので、curlのポートに:4566を指定しています。
上手く動いていると{"status": "running"}が返ってきます。

2-2-5. Docker版aws-cliをaliasに登録する

[node1] (local) root@192.168.0.18 ~
$ alias awsd='docker run --rm -ti -v ~/.aws:/root/.aws -v $(pwd):/aws amazon/aws-cli'

LocalStackは基本的にはGUIで操作できないのでaws-cliを使用する必要があります。
以下の記事を参考に設定しました。
AWS公式さんがDocker Hubで aws-cli のイメージを公開してくれた!
ちなみにawsd (AWS Dockerの意味) は各自好きなように変更していただいても大丈夫です。

2-2-6. Docker版aws-cliを起動し、バージョンを確認する

[node1] (local) root@192.168.0.18 ~
$ awsd --version
Unable to find image 'amazon/aws-cli:latest' locally
latest: Pulling from amazon/aws-cli
37373184fe69: Pull complete 
fc9d36ec628d: Pull complete 
2ddf91b98617: Pull complete 
9504c29fa015: Pull complete 
21fd79a0d708: Pull complete 
Digest: sha256:8f8283ee998f26145569d411f986f1bdf0c56b1f4005077a22d94c7ed4561fb3
Status: Downloaded newer image for amazon/aws-cli:latest
aws-cli/2.1.3 Python/3.7.3 Linux/4.4.0-189-generic docker/x86_64.amzn.2

初回のDocker版aws-cli実行時にはDockerイメージのプルがまず実行されます。
そして、aws-cliのバージョンが表示されます。
ちなみに、2回目以降は以下のようにDockerイメージのプルが実行されずにDocker版aws-cliを使用できるようになります。

[node1] (local) root@192.168.0.18 ~
$ awsd --version
aws-cli/2.1.3 Python/3.7.3 Linux/4.4.0-189-generic docker/x86_64.amzn.2

2-2-7. LocalStack用のaws-cliのconfigureを設定する

[node1] (local) root@192.168.0.18 ~
$ awsd configure --profile=localstack
AWS Access Key ID [None]: dummy
AWS Secret Access Key [None]: dummy
Default region name [None]: ap-northeast-1
Default output format [None]: json

上記のように入力してください。
LocalStack用なのでAWS Access Key IDAWS Secret Access Keyは適当な値 (dummy等) で大丈夫です。

2-2-8. LocalStack用の情報入力を省略するaliasを設定する

[node1] (local) root@192.168.0.18 ~
$ alias awsdl="awsd --endpoint-url=http://${LOCALHOST_IP_ADDRESS}:4566 --profile=localstack"

毎回awsd --endpoint-url=http://${LOCALHOST_IP_ADDRESS}:4566 --profile=localstackを入力しなくてもすむように、aliasを設定します。
ちなみにawsdl (AWS Docker Localstackの意味) は各自好きなように変更していただいても大丈夫です。
なお、この記事ではこれ以降のawsコマンドはawsdlとなっています。

2-3. LocalStackの動作確認

Amazon Simple Storage Service (以降、S3) へバケットを登録し、テキストファイルをアップロードできるかを確認します。

2-3-1. S3にバケットを登録する

[node1] (local) root@192.168.0.18 ~
$ awsdl s3 mb s3://test-s3
make_bucket: test-s3

2-3-2. S3のバケット一覧を取得する

[node1] (local) root@192.168.0.18 ~
$ awsdl s3 ls
2020-11-23 07:04:37 test-s3

2-3-3. S3へファイルをコピーする

[node1] (local) root@192.168.0.18 ~
$ echo "test text" > s3.txt

[node1] (local) root@192.168.0.18 ~
$ awsdl s3 cp ./s3.txt s3://test-s3
upload: ./s3.txt to s3://test-s3/s3.txt 

2-3-4. 指定したS3のバケットのファイル一覧を取得する

[node1] (local) root@192.168.0.18 ~
$ awsdl s3 ls test-s3
2020-11-23 07:05:43         10 s3.txt

2-4. Node.js環境のセットアップ

今回はAWS CDKをTypeScriptを使用して作成するので、Node.js環境が必要となります。
特別な理由はないですが、Node.js環境もDockerで準備していきます。

2-4-1. Node.js環境作業ディレクトリを作成する

[node1] (local) root@192.168.0.18 ~
$ mkdir node_workdir && cd node_workdir

[node1] (local) root@192.168.0.18 ~/node_workdir
$ mkdir app

2-4-2. Dockerfileを作成する

[node1] (local) root@192.168.0.18 ~/node_workdir
$ vi Dockerfile

以下のファイルの中身をコピペしてください。

Dockerfile
FROM node:14-alpine
WORKDIR /app
CMD ["sh"]

2-4-3. docker-compose.ymlを作成する

[node1] (local) root@192.168.0.18 ~/node_workdir
$ vi docker-compose.yml

以下のファイルの中身をコピペしてください。

docker-compose.yml
version: '3'
services:
  app:
    build: .
    image: my-node-image
    volumes:
      - ./app:/app
    environment:
      - LOCALSTACK_HOSTNAME=${LOCALHOST_IP_ADDRESS}
    tty: true

environmentのLOCALSTACK_HOSTNAMEは後ほど出てくるaws-cdk-localライブラリ内で必要となります。

aws-cdk-local/bin/cdklocalから一部抜粋
const getLocalEndpoint = () => {
  const port = process.env.EDGE_PORT || DEFAULT_EDGE_PORT;
  const host = process.env.LOCALSTACK_HOSTNAME || DEFAULT_HOSTNAME;
  return `http://${host}:${port}`;
};

2-4-4. Node.js環境作業ディレクトリの中身を確認する

[node1] (local) root@192.168.0.18 ~/node_workdir
$ ls
Dockerfile          app                 docker-compose.yml

3つの項目が表示されていたら、次の工程へ移りましょう。

2-4-5. Node.js環境コンテナを起動する

[node1] (local) root@192.168.0.18 ~/node_workdir
$ LOCALHOST_IP_ADDRESS=$LOCALHOST_IP_ADDRESS docker-compose up -d
Creating network "node_workdir_default" with the default driver
Building app
Step 1/3 : FROM node:14-alpine
14-alpine: Pulling from library/node
cbdbe7a5bc2a: Pull complete
f2ffd52523c3: Pull complete
48a445fb9d78: Pull complete
7a27e63388b2: Pull complete
Digest: sha256:d41417bb7fd04744cd159a40632f918c13bc1af3486a848782e1f68af2c3e6cb
Status: Downloaded newer image for node:14-alpine
 ---> 7f1893c3ede0
Step 2/3 : WORKDIR /app
 ---> Running in 47b57683cdda
Removing intermediate container 47b57683cdda
 ---> 71423a0bee1b
Step 3/3 : CMD ["sh"]
 ---> Running in e23e65a6f1f7
Removing intermediate container e23e65a6f1f7
 ---> c695ce33957e
Successfully built c695ce33957e
Successfully tagged my-node-image:latest
WARNING: Image for service app was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating node_workdir_app_1 ... done

docker-compose up -dコマンドの前にLOCALHOST_IP_ADDRESS=$LOCALHOST_IP_ADDRESSの指定を忘れないようにお気をつけください。
コンテナの起動に成功するとCreating node_workdir_app_1 ... doneのように生成されたコンテナの名前が出力されます。

2-4-6. Node.js環境コンテナの中に入る

[node1] (local) root@192.168.0.18 ~/node_workdir
$ docker exec -it node_workdir_app_1 sh
/app # 

先ほど生成されたコンテナの名前を指定してdocker execコマンドを実行します。
オプションに-itを、コマンドにshを指定しているので、コンテナの中に入ることができます。
Dockerコンテナに入る方法については以下の記事をご参考ください。
docker exec -itって実際は何をしてるの?【90日目】

なお、「2-5. AWS CDKプロジェクトの作成〜デプロイ」は、このコンテナの中に入っている状態で進めていきます。

2-5. AWS CDKプロジェクトの作成〜デプロイ

aws-cdkでプロジェクトを作成し、aws-cdk-localでLocalStackへデプロイしていきます。

2-5-1. aws-cdkとaws-cdk-localをグローバルインストールする

/app # npm install -g aws-cdk
/usr/local/bin/cdk -> /usr/local/lib/node_modules/aws-cdk/bin/cdk
+ aws-cdk@1.74.0
added 188 packages from 186 contributors in 12.617s

/app# npm install -g aws-cdk-local
/usr/local/bin/cdklocal -> /usr/local/lib/node_modules/aws-cdk-local/bin/cdklocal
+ aws-cdk-local@1.65.0
added 189 packages from 187 contributors in 7.703s

2-5-2. サンプルcdkプロジェクト用ディレクトリを作成し、移動する

/app # mkdir sample && cd sample

2-5-3. サンプルcdkプロジェクトを作成する

/app/sample # cdk init sample-app --language=typescript
Applying project template sample-app for typescript
# Welcome to your CDK TypeScript project!

You should explore the contents of this project. It demonstrates a CDK app with an instance of a stack (`SampleStack`)
which contains an Amazon SQS queue that is subscribed to an Amazon SNS topic.

The `cdk.json` file tells the CDK Toolkit how to execute your app.

## Useful commands

 * `npm run build`   compile typescript to js
 * `npm run watch`   watch for changes and compile
 * `npm run test`    perform the jest unit tests
 * `cdk deploy`      deploy this stack to your default AWS account/region
 * `cdk diff`        compare deployed stack with current state
 * `cdk synth`       emits the synthesized CloudFormation template

Initializing a new git repository...
/bin/sh: git: not found
Unable to initialize git repository for your project.
Executing npm install...
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated request-promise-native@1.0.9: request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
npm WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated
npm WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^2.1.2 (node_modules/jest-haste-map/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.2.1: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
npm WARN sample@0.1.0 No repository field.
npm WARN sample@0.1.0 No license field.

✅ All done!

cdk initコマンドで--language=typescriptを指定してTypeScriptでファイルが生成されるようにしています。
また、sample-appと指定すると、簡単なサンプルを含んだプロジェクトが生成されます。出力の中に簡単なサンプルについての説明があります。

You should explore the contents of this project. It demonstrates a CDK app with an instance of a stack (`SampleStack`)
which contains an Amazon SQS queue that is subscribed to an Amazon SNS topic.

(DeepLによる翻訳)
このプロジェクトの内容を探ってみてください。スタック (SampleStack) のインスタンスを持つ CDK アプリのデモを行います。
これは、Amazon SNSのトピックにサブスクライブされているAmazon SQSキューを含んでいます。

生成された簡単なサンプルのソースコードを、ちょっとだけ見てみましょう。

/app/sample # vi ./lib/sample-stack.ts
./lib/sample-stack.ts
import * as sns from '@aws-cdk/aws-sns';
import * as subs from '@aws-cdk/aws-sns-subscriptions';
import * as sqs from '@aws-cdk/aws-sqs';
import * as cdk from '@aws-cdk/core';

export class SampleStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const queue = new sqs.Queue(this, 'SampleQueue', {
      visibilityTimeout: cdk.Duration.seconds(300)
    });

    const topic = new sns.Topic(this, 'SampleTopic');

    topic.addSubscription(new subs.SqsSubscription(queue));
  }
}

Amazon Simple Queue Service (以降、SQS) のキューとAmazon Simple Notification Service (以降、SNS)のトピックとサブスクリプションが定義されています。SNSトピックからメッセージを発行すると、サブスクリプションとして登録されているキューに登録されるようになっています。

2-5-4. TypeScriptファイルをJavaScriptファイルにトランスパイルする

/app/sample # npm run build

> sample@0.1.0 build /app/sample
> tsc

ブラウザやNode.js環境はJavaScriptしか実行できないため、TypeScriptファイルをJavaScriptファイルへ必ず変換しましょう。

2-5-5. 初めてデプロイする場合、デプロイ用のS3バケットを作成する

/app/sample # cdklocal bootstrap
 ⏳  Bootstrapping environment aws://000000000000/us-east-1...
CDKToolkit: creating CloudFormation changeset...
[··························································] (0/3)

 ✅  Environment aws://000000000000/us-east-1 bootstrapped.

2-5-6. LocalStackへデプロイする

/app/sample # cdklocal deploy
This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening).
Please confirm you intend to make the following modifications:

IAM Statement Changes
┌───┬─────────────────────────┬────────┬─────────────────┬─────────────────────────┬───────────────────────────┐
│   │ Resource                │ Effect │ Action          │ Principal               │ Condition                 │
├───┼─────────────────────────┼────────┼─────────────────┼─────────────────────────┼───────────────────────────┤
│ + │ ${SampleQueue.Arn}      │ Allow  │ sqs:SendMessage │ Service:sns.amazonaws.c │ "ArnEquals": {│   │                         │        │                 │ om                      │   "aws:SourceArn": "${Sam │
│   │                         │        │                 │                         │ pleTopic}"                │
│   │                         │        │                 │                         │ }                         │
└───┴─────────────────────────┴────────┴─────────────────┴─────────────────────────┴───────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Do you wish to deploy these changes (y/n)? y
SampleStack: deploying...
SampleStack: creating CloudFormation changeset...
[··························································] (0/6)


 ✅  SampleStack

Stack ARN:
arn:aws:cloudformation:us-east-1:000000000000:stack/SampleStack/3b39e2b2-bb7d-42d0-9b36-d53e069c1451

途中でDo you wish to deploy these changes (y/n)?と入力を求められるので、問題がなければyを入力しましょう。

2-5-7. Node.js環境コンテナから抜け出す

/app/sample # exit
[node1] (local) root@192.168.0.18 ~/node_workdir
$ 

2-6. AWS CDKからLocalStackへデプロイされたリソースの動作確認

「リソースが生成されているか」と「SNSトピックからメッセージを発行し、サブスクリプションとして登録されているキューに登録されるか」を確認していきます。

2-6-1. SQSキューの一覧を取得する

[node1] (local) root@192.168.0.18 ~/node_workdir
$ awsdl sqs list-queues
{
    "QueueUrls": [
        "http://localhost:4566/000000000000/queue-7f6ead47"
    ]
}

SQSキューがちゃんと生成されていますね。
ちなみに、QueueUrlsに表示されている値は各自の環境で異ります。

2-6-2. 指定したSQSキューの詳細を取得する

[node1] (local) root@192.168.0.18 ~/node_workdir
$ awsdl sqs get-queue-attributes --queue-url http://localhost:4566/000000000000/queue-7f6ead47
{
    "Attributes": {
        "ApproximateNumberOfMessages": "0",
        "ApproximateNumberOfMessagesDelayed": "0",
        "ApproximateNumberOfMessagesNotVisible": "0",
        "CreatedTimestamp": "1606116190.41501",
        "DelaySeconds": "0",
        "LastModifiedTimestamp": "1606116190.41501",
        "MaximumMessageSize": "262144",
        "MessageRetentionPeriod": "345600",
        "QueueArn": "arn:aws:sqs:us-east-1:000000000000:queue-7f6ead47",
        "ReceiveMessageWaitTimeSeconds": "0",
        "VisibilityTimeout": "300"
    }
}

--queue-urlに指定する値は「2-6-1. SQSキューの一覧を取得する」で取得した各自の値を指定してください。
今回はとりあえず出力結果のうち、次の一項目だけ確認します。ApproximateNumberOfMessages (キューから取得可能なメッセージのおおよその数) が"0"になっていることが確認できましたでしょうか。

2-6-3. SNSトピックの一覧を取得する

[node1] (local) root@192.168.0.18 ~/node_workdir
$ awsdl sns list-topics
{
    "Topics": [
        {
            "TopicArn": "arn:aws:sns:us-east-1:000000000000:topic-cac07a20"
        }
    ]
}

SNSトピックもちゃんと生成されていますね。
TopicArnも同様に表示されている値は各自の環境で異ります。

2-6-4. 指定したSNSトピックへメッセージを発行する

[node1] (local) root@192.168.0.18 ~/node_workdir
$ awsdl sns publish --message "test message" --topic-arn "arn:aws:sns:us-east-1:000000000000:topic-cac07a20"
{
    "MessageId": "d06d6c48-fba9-4b8b-ab09-5f96e0784aef"
}

--topic-arnに指定する値は「2-6-3. SNSトピックの一覧を取得する」で取得した各自の値を指定してください。
発行に成功するとMessageIdが入ったJSONが返ってきます。

2-6-5. 指定したSQSキューの詳細を取得し、ApproximateNumberOfMessagesを確認する

[node1] (local) root@192.168.0.18 ~/node_workdir
$ awsdl sqs get-queue-attributes --queue-url http://localhost:4566/000000000000/queue-7f6ead47
{
    "Attributes": {
        "ApproximateNumberOfMessages": "1",
        "ApproximateNumberOfMessagesDelayed": "0",
        "ApproximateNumberOfMessagesNotVisible": "0",
        "CreatedTimestamp": "1606116190.41501",
        "DelaySeconds": "0",
        "LastModifiedTimestamp": "1606116190.41501",
        "MaximumMessageSize": "262144",
        "MessageRetentionPeriod": "345600",
        "QueueArn": "arn:aws:sqs:us-east-1:000000000000:queue-7f6ead47",
        "ReceiveMessageWaitTimeSeconds": "0",
        "VisibilityTimeout": "300"
    }
}

「2-6-2. 指定したSQSキューの詳細を取得する」と同じコマンドを実行しましょう。
ApproximateNumberOfMessages (キューから取得可能なメッセージのおおよその数) が"1"になっていたら、SNSトピックから発行されたメッセージがSQSキューに登録される処理がうまくいった証拠です!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【ほぼ無料】FreenomとLet's Encryptを使って0円でドメインとSSL証明書を手に入れて、AWS EC2にdockerを入れてnginxコンテナを起動してドメインで繋がるHTTPS WEBサービスを立ち上げる方法

経緯

何か業務で使う技術や新しい技術を試したいときにAWS上にWebサーバーを立ててAPIとかテストページとか用意して、ローカルのChromeやAndroid端末からhttpで繋いでごにょごにょやるってのを結構やる。
RestAPIの疎通確認ぐらいならそれでいいんだけど、WebRTCやWebSocketの検証で使いたい場合、SSL化されたサイトでないとエラーになって接続できないため動作確認が出来ない問題があった。
どうにかこうにか安価でオレオレ証明書じゃないWebサーバーを立てられないかなーと調べたところ、FreenomとLet's Encryptを使えばほぼ無料で独自ドメインのhttpsサーバーを立てられそうだと判明。

Freenomでのドメイン取得方法やLet's EncryptでのSSL証明書取得方法、それらをAWSで設定するやり方等は探せば断片的にはあるけど、全部まとまった記事は無かったので、備忘録もかねてここに残しておく。

やること

  1. 【無料】Freenomで無料ドメインを取得する
  2. 【条件付無料】AWS EC2インスタンスを作成してdockerをインストールする
  3. 【条件付無料】AWS Elastic IPで静的IPアドレスを発行してEC2インスタンスに関連付ける
  4. 【ほぼ無料】AWS Route53でDNS設定を行いドメイン名でEC2インスタンスに繋がるようにする
  5. 【無料】dockerでEC2インスタンスにnginxコンテナを立ち上げる
  6. 【無料】Let's Encryptで無料SSL証明書を取得してhttpsで繋がるようにする

無料の条件とほぼ無料の詳細

  • AWS EC2インスタンスは無料利用枠を使用する
    • 無料利用枠と記載のあるAmazonマシンイメージ(AMI)は月に750時間無料で使える。今回はそれを使うことで無料とする
  • ElasticIPで割り当てたEC2インスタンスは起動したままにしておく
    • ElasticIPで発行したIPアドレスがEC2インスタンスに関連付けされていない場合は課金が発生する。いくら課金されるかは調べていないがわずかであるらしい。こういう仕組みになっているのは無駄にIPアドレスを確保されるのを防ぐためだろう。
  • AWS Route53では月に0.5$課金される
    • 下記は公式(2020年11月現在)から抜粋してきたもの。まあこのくらいなら缶コーヒー半分くらいだし、いいよね。 image.png

1. 【無料】Freenomで無料ドメインを取得する

早速やっていきます。ドメインはFreenomというサービスを使って取得します。Freenomとは、ドメインを無料で取得出来る海外のサービスです。ドメイン名は、XXXX.tkやXXXX.ml、XXXX.ga等が無料で取得できます。
https://www.freenom.com/ja/index.html

ドメインが使えることを確認し、チェックアウトする

好きなドメインを取得することが出来ますので、取得したいドメインを入力しましょう。利用可能か調べてくれて利用可能であれば以下のような画面になりますので「今すぐ入手!」を押下した後、「チェックアウト」を押下します。

image.png


image.png

使用期間を選択する

12ヵ月まで無料で使えるようですので、最大限使用させていただきましょう。Periodで「12 Months @ FREE」を選択して「Continue」を押下します。

image.png

ユーザー登録 or ログイン

金額が$0.00USD(無料)なのを確認します。問題なければ購入のためログインします。
私の場合は既に登録済みなので、普通にGoogleでログインします。
初回登録してないと、いろいろ登録しないといけないかもしれません。
image.png

規約に同意して購入

再度、金額が$0.00USD(無料)なのを確認してから、規約に同意のチェックを入れ、「Complete Order」を押下します。

image.png


image.png


image.png

これにてドメインの取得は完了しました。

2. 【条件付無料】AWS EC2インスタンスを作成してdockerをインストールする

こちらは私が書いた別の記事がそのまま使用できますので、こちら↓を参照ください。

AWS EC2インスタンスにdockerとdocker-composeをインストールして簡単なWEBサービスを立ち上げる方法

3. AWS Elastic IPで静的IPアドレスを発行してEC2インスタンスに関連付ける

静的IPアドレス(固定IPアドレス)を取得し、上記で起動したEC2インスタンスにそのIPアドレスを割り当てます。こうすることで、EC2を再起動したりしてもIPアドレスが変わることは無くなります。

静的IPアドレスを取得する

まずは画面操作して静的IPアドレスを取得します。
「Elastic IP」を押下し、
image.png
次の画面で「Elastic IP アドレスの割り当て」を押下します。
image.png
次の画面で「割り当て」を押下します。
image.png
静的IPアドレスが取得できました。
image.png

EC2インスタンスに静的IPアドレスを関連付ける

割り当てられたIPアドレスを選択状態にして「アクション」内の「Elastic IPアドレスの関連付け」を押下します。
image.png
インスタンスには、先ほど作成したEC2のインスタンスIDを入力します。
入力したら「関連付ける」を押下します。
image.png

EC2インスタンスと静的IPアドレスの関連付けが完了しました。
image.png

4. 【ほぼ無料】AWS Route53でDNS設定を行いドメイン名でEC2インスタンスに繋がるようにする

ドメイン名で繋がるようにDNS設定を行います。
ホストゾーン作成→Aレコード登録→FreenomでNameserver設定という手順になります。

ホストゾーンの作成

Route53の画面に行き、
image.png
「ホストゾーン」を押下します。
image.png
「ホストゾーンの作成」を押下します。
image.png
Freenomで取得したドメインを入力して「ホストゾーンの作成」を押下します。
image.png
ホストゾーンの作成が完了しました。
image.png

Aレコードの作成

「レコードの作成」を押下します。
image.png
シンプルルーティングがデフォルト選択されているのを確認して「次へ」を押下します。
image.png
「シンプルなレコードを定義」を押下します。
image.png
値/トラフィックのルーティング先で「レコードタイプに応じたIPアドレスまたは別の値」を選択した後、先ほど取得した静的IPアドレスを入力して、「シンプルなレコードを定義」を押下します。
image.png
レコードの作成を押下します。
image.png
レコードの作成が完了しました。
image.png

Nameserverの設定

今度はFreenomでNameserverの設定を行います。

「My Domains」を押下し、次の画面で「Manage Domain」を押下します。

image.png


image.png
「Management Tools」の「Nameservers」を押下します。
image.png
「Use custom nameservers(enter below)」を選択、Nameserver欄にはRoute53 ホストゾーンのNSレコードの値をコピペします。
入力したら「Change Nameservers」を押下します。
image.png

この時点で数分経過すると、DNSが浸透して行って「http://ドメイン名」でサイトが表示されるようになっているかと思います。
image.png

5. 【無料】dockerでEC2インスタンスにnginxコンテナを立ち上げる

6. 【無料】Let's Encryptで無料SSL証明書を取得してhttpsで繋がるようにする

5と6は一気にやっちゃいます。
いろいろやり方はあるかと思いますが、以下構成でdockerを使用してやってみます。

  • reverse-ploxyコンテナをインターネットに公開し、https通信を受け付けます。
  • reverse-ploxyコンテナからwebコンテナへ通信を転送、webコンテナではreverse-ploxyからhttp通信を受け付けます。

Untitled Diagram.png

全てのdockerを停止しておく

誤動作防止のため、作業前に一度全てのdockerコンテナを止めて、dockerオブジェクトも全部削除しておくといいでしょう。

docker stop $(docker ps -q)
docker system prune -a

webコンテナの作成と起動

homeディレクトリ配下にwebディレクトリを作成し、必要な構成ファイルを作成します。

cd
mkdir web

ディレクトリ配下とファイルの内容は以下のような構成にしました。

ディレクトリ構成
web
  - html
      - index.html # hogeとでも書いておく
  - docker-compose.yml
docker-compose.yml
version: '3'

services:
  web:
    image: nginx:latest
    container_name: web
    volumes:
      - ./html:/usr/share/nginx/html

作成が終わったらdockerコンテナを起動します。

docker-compose up -d --build

起動したことを確認します。

docker-compose ps
Name              Command               State   Ports
------------------------------------------------------
web    /docker-entrypoint.sh ngin ...   Up      80/tcp

reverse-ploxyコンテナの作成と起動

homeディレクトリ配下にreverse-ploxyディレクトリを作成し、必要な構成ファイルを作成します。

cd
mkdir reverse-ploxy

ディレクトリ配下とファイルの内容は、悪戦苦闘の結果、以下のような構成にしました。

ディレクトリ構成
reverse-proxy
  - reverse-proxy
    - default.conf
    - Dockerfile
    - entrypoint.sh
  - docker-compose.yml
default.conf
server{

    server_name y-do.tk;

    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    location / {
      proxy_pass     http://web/;
    }

}
Dockerfile
FROM nginx

COPY default.conf /etc/nginx/conf.d/default.conf

RUN cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

RUN apt-get update && apt-get install -y \
  wget cron && \
  apt-get clean && \
  rm -rf /var/lib/apt/lists/*

ADD https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh /usr/local/bin/wait-for-it.sh
RUN chmod +x /usr/local/bin/wait-for-it.sh

ADD https://dl.eff.org/certbot-auto /usr/local/bin/certbot-auto
RUN chmod a+x /usr/local/bin/certbot-auto
RUN certbot-auto --os-packages-only -n

COPY ./entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh

ENTRYPOINT ["entrypoint.sh"]
entrypoint.sh
#!/bin/bash

# hogehoge@example.comはメールアドレス
certbot-auto --nginx -d y-do.tk -m hogehoge@example.com --agree-tos -n
certbot-auto renew

# cron job settings
# Let's Encrypt automatic Renew
echo '0 8 * * * certbot-auto renew --post-hook "nginx -s reload"' >> /cron-tmpfile
crontab /cron-tmpfile
rm /cron-tmpfile

# cron start
/etc/init.d/cron start

/bin/bash
docker-compose.yml
version: '3'

services:
  reverse-proxy:
    build: ./reverse-proxy
    tty: true
    container_name: reverse-proxy
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - '/srv/letsencrypt:/etc/letsencrypt'
    command: ["wait-for-it.sh", "web:80"]
    networks:
      - default
      - web_default

networks:
  web_default:
    external: true

作成が終わったらdockerコンテナを起動します。

docker-compose up -d --build

起動したことを確認します。

docker-compose ps
    Name                   Command               State                    Ports
-------------------------------------------------------------------------------------------------
reverse-proxy   entrypoint.sh wait-for-it. ...   Up      0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp

インターネットからhttpsで繋がるようにAWSでセキュリティグループを更新する

FWで弾かれているため、まだインターネットからhttps通信を受け付けることが出来ません。
AWSのセキュリティグループのインバウンドルールを修正します。

ルールを追加して、タイプ「HTTPS」、ソースは「0.0.0.0/0」を入力します。
入力したら「ルールを保存」を押下します。

image.png

動作確認

ここまでやってやっとhttpsで通信が出来るようになっているはずです。アクセスしてみます。

image.png


image.png

アクセス出来た!!!

結果

月額0.5USDで独自ドメインのSSLサイトが運用できる。
ただし、ドメインは12ヵ月、SSL証明書は3か月で有効期限が切れる(無料だから文句は言えない)ので、今後は自動更新の仕組みを導入したい

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

S3の画像データを無理やりBlob型に変換する方法

なにこれ

S3の画像データをBlob型にしたい!っていう珍しい状況になった時の解決策です。
Vue(Nuxt)で下記のように'Content-Type': 'multipart/form-data'で送りたい!って時に遭遇する可能性が高そうです。
test.js
const response = await this.$axios.put(`/hoges/${this.hoge.id}`, req, {
headers: {
'Content-Type': 'multipart/form-data'
}
})

どうやるか

axiosを利用します

axiosでs3のURLをgetして、その時にresponseをblobで受け取ります。
受け取ったresponseを使って、new BlobでBlob型に変換します。

test.js
import axios from 'axios'

// 〜省略〜
          const req = new FormData()
          try{
            const response = await axios.get(S3のURL, { responseType: 'blob' })
            const blobData = new Blob([ response.data ], { type: "image/png" })
            req.append(`image`, blobData)
          } catch (error) {
            console.error(error.response)
          }

その後は肉なり焼くなり好きに処理してください!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSでクソアプリのアーキテクチャを2週間でガチガチに改修した

AWS雰囲気使いを卒業するために、既存アプリのアーキテクチャを
2週間で結構強固なものに改造してみたので改造前と改造後、そして将来的に実装したいFuture workを書き残しておこうと思います。

(ほとんど自己満足で行ったので、必要以上のことをしてしまっている部分があったり、説明を省いている部分があります。)

既存アプリの詳細

今回改造することにしたアプリケーションは非同期でチャットができるようなwebアプリで、いわゆるL○NEやカカ○ークのようなチャットアプリのwebブラウザバージョンと思っていただけたらと思います。

改造前は、2つのAZ上のpublic subnetにおいたEC2(t2micro)をロードバランサーに設定したうえ、単一のRDSをprivate subnetに置いただけの設計で、ストレージもそれぞれのEC2インスタンス(Ruby on Rails内)が保持し、DBに画像ファイルのパス名を格納しているというもはや完全に不具合とも捉えられる状態でした。

このままではユーザー数が増えた際のEC2インスタンスのサーバーダウンが容易に考えられ、またDBのフェイルオーバー、スケールアップ等もカバーされていない状態です。

他にも、インフラをdockerを用いて殆ど手動で管理していて、サーバーを起動するのにそれぞれのインスタンス内に接続してdocker-compose upしないといけないような、色々と管理コストの高いアプリケーションでした。

改善したポイント

2週間で実装できる範囲で最低限アプリケーションを強固なものし、また今後のインフラの管理コストをできるだけ下げるべく、ほとんどの管理工程の自動化を試みました。

  • ストレージにS3の導入
  • EC2スケーリング, 復旧, ストレージ最適化等の自動化
  • Auroraの導入、DBスケーリングの自動化, キャッシュメモリの導入
  • AWSリソースの管理をコード化(インフラ構築の自動化、CI/CDパイプラインの構築)
  • システム状況を可視化

改善後アーキテクチャ

改善後のアーキテクチャ図はこんな感じです。
スクリーンショット 2020-09-02 13.33.02.png

使用AWSリソース

  • CloudFront
  • S3
  • ElastiCache
  • Aurora
  • Amazon SNS
  • Code pipeline
  • Code build
  • Code deploy
  • Cloud watch
  • Compute optimizer
  • Cloudformation

主な変更点

1.ストレージにS3の導入
2.EC2スケーリング, 復旧, ストレージ最適化等の自動化
3.DBスケーリングの自動化, キャッシュメモリの導入
4.AWSリソースの管理をコード化(インフラ構築の自動化)
5.システム状況を可視化

1.ストレージにS3の導入

  • 画像ファイルをS3に保管する →現状のコードを少し修正する必要がある
  • バックアップのスナップショットもS3に保存
  • アクセスはしないが消したくないデータ(ログなど)はS3 glacierに保存

まず、最低限ストレージをS3に統一します。
これをしないと、あるEC2インスタンスでアップロードされた画像が他のインスタンスからは表示されないといった不具合が生じます。

また、後で説明するDBのバックアップもスナップショットしてS3に保存します。

さらに、アクセスはしないが消したくないデータ(ログなど)はS3 glacierに保存しておくとより低コストに抑えられるので、導入しました。

2.EC2スケーリング, 復旧, ストレージ最適化等の自動化

  • Autoscalingによるスケーリング自動化
  • Compute Optimizerでインスタンスタイプ, Autoscalingの最適化
  • Cloudwatchアラーム設定でEC2インスタンス の自動復旧
  • Amazon SNSによる障害、自動復旧の通知

今後ユーザー数が増えた際に、サーバーに対してリクエスト過多が発生してしまう可能性があります。その際にEC2のスケールアウトを自動化しておくために、Autoscalingを導入します。

また、現在はt2microを採用しているのですがこちらのインスタンスタイプの最適化もCompute Optimizerを導入することによって自動化することができます。

さらに、万が一EC2インスタンスが破損してしまった場合の対策として、Cloudwatchというサービスのアラーム設定をしておくと、EC2インスタンスを自動復旧をしてくれるようになります。
ここで念のため、Amazon SNSでEC2破損時にメールにて通知がくるように設定しておくと、即座に破損のお知らせが届くようになるので、予め設定しておきます。

3.DBスケーリングの自動化, キャッシュメモリの導入

  • Aurora MySQLの導入 →MySQLの5倍のスループット
  • Amazon Aurora Auto Scalingで自動スケーリング
  • キャッシュ(ElastiCache)で高速化
  • DB故障時はAmazon SNSで即座に通知
  • DBの冗長化

まずDBをより高性能なAuroraに変更しました。

現状RDSのMySQLを使用しているということで、モデル変更などの必要はなく、Aurora MySQLに代替することにそれほど作業コストはかかりませんし、 Auroraのデフォルト機能でS3にDBバックアップのスナップショットを保存してくれます。

また、 Aurora Auto Scalingで、自動スケーリングも対応させます。
これにより、DBの移行、管理コストをほぼ0にすることが実現できます。

さらに、DBキャッシュであるElastiCacheを導入することで、データの読み込みを最適化します。

最後に、念のため別AZにAuroraをもう一つ設置しておきます。これによって万が一単一のデータセンターで災害がおきてしまった場合もアプリケーションを持続させることが可能になります。

ここまでいくと自己満足です。

4.AWSリソースの管理をコード化(インフラ構築の自動化)

  • CloudFormation →コードでAWSリソースの管理
  • Former2 →templateの自動生成
  • CodeBuild →buildを自動化
  • CodeDeploy →deployの自動化
  • CodePipeline →パイプライン化しインフラ構築、デプロイを自動化

これまでインフラの構築を手動で行っていたのを自動化し、AWSリソース自体をコードで管理できるようにします。

ここでCloudFormationというサービスを利用するのですが、こちらはAWSのシステム構成をJSONで記述してテンプレート化し、構成の管理、修正、再利用を容易にするサービスのことです。

CloudFormationを導入する際には、システム構成を構築する際のテンプレートの作成に手間が少々かかってしまいがちですが、ここでサードパーティーであるFormer2が大活躍してくれます。これは既存のAWSのリソース情報を取得し、CloudFormation, Terraform, Troposphere のテンプレートを生成してくれるようなOSSで、利用しない手はありませんでした。

また、CodeBuild、CodeDeploy、CodePipelineを用いてCI/CDパイプラインを構築し、リリースプロセスを自動化しました。

5.システム状況を可視化

  • Cloudwatchでシステム状況を可視化 →全体のシステムのどの部分に費用がかかっているか可視化
  • CloudMapper(サードパーティ)によりアーキテクチャ図を自動で生成 →全体図が把握しやすく, 担当の引き継ぎなどが容易になる

Future work

今回は2週間という期間だったので実現しきれなかったものの、将来的に実現させてみたことを何点か最後に記させていただきます。

  • サーバレス化
  • NoSQLへの移行
  • SPAの実現
  • テスト

現段階では、大量同時接続に弱いRDBを用いていますが、将来的にはユーザー数の増加に伴いDynamoDBなどのNoSQLに移行することが望ましいと思っています。
また、現在EC2に保管しているアプリケーションを完全にS3に移すことでSPAも実現させたいです。
おまけとして、これらの移行がかなった際には、Locust等のツールを用いて負荷増大テストとかもやってみるのも夢です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む