20190302のAWSに関する記事は13件です。

aws-cli で S3ウェブサイトホスティングをする

前提

  • S3 のwebサイトホスティングをcliでやってみようの巻。
  • 今回は bucket-acl のみで bucket-policy は使ってません。
  • cloudfrontは無しの構成です。

流れ

  1. バケット作成
  2. webサイトの設定をする
  3. コンテンツ置く
  4. 公開

手順

バケット作成

aws s3 mb s3://mybucket

webサイトホスティングの設定をする

以下のファイルを作成する(website.json)

website.json(例)
{
    "IndexDocument": {
        "Suffix": "index.html"
    },
    "ErrorDocument": {
        "Key": "error.html"
    }
}

上で作ったファイルをオプションで指定してwebサイト用の設定を投入

aws s3api put-bucket-website --bucket mybucket --website-configuration file://website.json

コンテンツ(html とか)置く

aws s3 cp index.html s3://mybucket/index.html --acl public-read
  • その他のファイルをアップロードする場合は、上のコマンドの index.html を置き換えてください。
  • 注意
    • aws s3api put-objectを使う場合はContent-type(text/html)やContent-Lengthオプションを設定して下さい。aws s3 cpであれば自動でいい感じに設定してくれますが、aws s3api put-objectだと設定してくれないです。

公開

aws s3api put-bucket-acl --bucket mybucket --acl public-read

アクセス

http://mybucket.s3-website-us-west-2.amazonaws.com/

  • バケットのURLと違うので気をつけて下さい。
  • リージョンはバケットを作ったリージョンに置き換えてください
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

API GatewayのLambda統合で嵌った話

今まで仕事でLambdaを触っていたけど、自宅で一から作ろうとしたら嵌ったので、その時の話を書いていきます。

仕事の記憶を頼りに、次のようなLambdaハンドラとserverless.ymlを書きました。ごく単純なPOSTメソッドで、リクエストボディからparamという値を取り出します。

handler.py
def handle_request(event, context):
    body = event.get('body')
    param = body.get('param')
    # 以下省略
serverless.yml
functions:
  sample:
    handler: python:handler.handle_request
    events:
      - http: post sample

早速リクエストを送ってみると、502 Internal server errorが返ってきて、Lambdaのログには以下のエラーが出ていました。

[ERROR] AttributeError: 'str' object has no attribute 'get'
Traceback (most recent call last):
  File "/var/task/handler.py", line 22, in handle_request
    param = body.get('param')

あれ、おかしいな。仕事の時はbodyからgetするだけでパラメータを取得できていたのだが…。

で、調べてみると、Lambdaプロキシ統合が関係していることが分かりました。

Lambdaプロキシ統合.png

今までほとんど意識していませんでしたが、これを使用するとAPI GatewayがLambdaへうまい感じにリクエストパラメータ等を渡したり、Lambdaからのレスポンスを処理したりするようです。

ただし、リクエストボディはJSON形式ではなく文字列に変換されてしまうとのこと。Lambdaプロキシ統合を使用しないとJSON形式で扱えたので、この点だけは若干不便な気がします。

serverless.yml
functions:
  sample:
    handler: python:handler.handle_request
    events:
      - http:
          path: sample
          method: post
          integration: lambda

このように書くと、Lambda統合はされますが、Lambdaプロキシ統合は使用されません。仕事ではこうしていたからgetだけでうまく行ったんだな。週明けに直さなきゃ!

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

AWS Cloud9がConnecting...の画面から抜け出せたので解決方法まとめました。(for Mac)

環境

Macbook pro(2013年モデル)
macOS Mojave
AWS Cloud9使用

状況

つい先日まで普通に使っていたCloud9がConnecting...から動かなくなっていました。特に何かを動かした訳ではないはず...と思いながらも、色々調べてたら解決できたのでその方法書いておきます。

解決方法

  1. まず、AWSのホームへ行き、"EC2"をクリック。 スクリーンショット 2019-02-28 20.19.18.jpg
  2. "実行中のインスタンス"をクリック。 スクリーンショット 2019-02-28 20.24.35.jpg
  3. インスタンスの状況がrunningになっていることを確認し、"停止"させる。 スクリーンショット 2019-02-28 20.28.51.jpg スクリーンショット 2019-02-28 20.49.02.jpg
  4. それだけでは、停止せず、runningの状態に戻ってしまうため、もう一度"停止"し、"強制停止"を実行。 スクリーンショット 2019-02-28 20.41.37.jpg スクリーンショット 2019-02-28 20.41.52.jpg
  5. インスタンスの状況がstopped担っていることを確認し、"開始"をクリック。 スクリーンショット 2019-02-28 20.42.52.jpg スクリーンショット 2019-02-28 20.44.15.jpg 以上で、再開できました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Cloud9がConnecting...の画面から抜け出せたので解決方法まとめました。

環境

Macbook pro(2013年モデル)
macOS Mojave
AWS Cloud9使用

状況

つい先日まで普通に使っていたCloud9がConnecting...から動かなくなっていました。特に何かを動かした訳ではないはず...と思いながらも、色々調べてたら解決できたのでその方法書いておきます。

解決方法

  1. まず、AWSのホームへ行き、"EC2"をクリック。 スクリーンショット 2019-02-28 20.19.18.jpg
  2. "実行中のインスタンス"をクリック。 スクリーンショット 2019-02-28 20.24.35.jpg
  3. インスタンスの状況がrunningになっていることを確認し、"停止"させる。 スクリーンショット 2019-02-28 20.28.51.jpg スクリーンショット 2019-02-28 20.49.02.jpg
  4. それだけでは、停止せず、runningの状態に戻ってしまうため、もう一度"停止"し、"強制停止"を実行。 スクリーンショット 2019-02-28 20.41.37.jpg スクリーンショット 2019-02-28 20.41.52.jpg
  5. インスタンスの状況がstopped担っていることを確認し、"開始"をクリック。 スクリーンショット 2019-02-28 20.42.52.jpg スクリーンショット 2019-02-28 20.44.15.jpg 以上で、再開できました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

EC2(Linux)のメモリをCloudWatchのメトリクスでモニタリングできるように設定(自分用のメモ)

自分用のメモ

概要

CloudWatchではCPUやStatusCheck(EC2が止まっているかどうか)については表示のメトリクスが用意されているが、MemoryやSwapなどはメトリクスが用意されていないため、自分でカスタマイズメトリクスを作成しなければならない。

手順

以下参照(これを上から順番に見るだけでできます)
https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/mon-scripts.html

設定例

crontabの設定例

*/1 * * * * ~/aws-scripts-mon/mon-put-instance-data.pl --mem-util --mem-used --mem-avail --mem-avail --memory-units=Gigabytes --swap-util --swap-used --from-cron
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS SDK for Go S3バケット基本操作

AWS SDK for Go

公式Doc
https://docs.aws.amazon.com/ja_jp/sdk-for-go/v1/developer-guide/s3-example-basic-bucket-operations.html

S3と接続するインスタンスの生成

import (
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/aws/credentials"
    "github.com/aws/aws-sdk-go/service/s3"
)

creds := credentials.NewStaticCredentials("AWS_ACCESS_KEY", "AWS_SECRET_ACCESS_KEY", "")
sess, err := session.NewSession(&aws.Config{
    Credentials: creds,
    Region: aws.String("ap-northeast-1")},
)
svc := s3.New(sess)

バケットの一覧を取得:ListBuckets

result, _ := svc.ListBuckets(nil)
fmt.Println("Buckets:")

for _, b := range result.Buckets {
    fmt.Printf("* %s created on %s\n", aws.StringValue(b.Name), aws.TimeValue(b.CreationDate))
}

バケットの作成:CreateBucket

bucket := "new-bucket-name"
resp, err := svc.CreateBucket(&s3.CreateBucketInput{
    Bucket: aws.String(bucket),
})
fmt.Println(resp) // -> { Location: "http://new-bucket-name.s3.amazonaws.com/" }

バケット内のオブジェクト一覧を取得:ListObjects

bucket := "bucket-name"
resp, err := svc.ListObjects(&s3.ListObjectsInput{Bucket: aws.String(bucket)})

for _, item := range resp.Contents {
    fmt.Println("Name:         ", *item.Key)
    fmt.Println("Last modified:", *item.LastModified)
    fmt.Println("Size:         ", *item.Size)
    fmt.Println("Storage class:", *item.StorageClass)
    fmt.Println("")
}

ファイルのアップロード:Upload

import "github.com/aws/aws-sdk-go/service/s3/s3manager"

bucket := "bucket-name"
filename := "filename"
file, err := os.Open(filename)

defer file.Close()

uploader := s3manager.NewUploader(sess)
_, err = uploader.Upload(&s3manager.UploadInput{
    Bucket: aws.String(bucket),
    Key: aws.String(filename),
    Body: file,
})

ファイルのダウンロード:Download

import "github.com/aws/aws-sdk-go/service/s3/s3manager"

bucket := "bucket-name"
file, err := os.Create("filename")

defer file.Close()

downloader := s3manager.NewDownloader(sess)
numBytes, err := downloader.Download(file,
    &s3.GetObjectInput{
        Bucket: aws.String(bucket),
        Key:    aws.String(item),
    })

バケット間でファイルをコピー:CopyObject

bucket := "bucket-containing-file"
item := "file-to-copy"
other := "bucket-to-file-copied"

_, err = svc.CopyObject(&s3.CopyObjectInput{Bucket: aws.String(other), CopySource: aws.String(source), Key: aws.String(item)})

ファイルの削除:DeleteObject

bucket := "bucket-name"
obj := "file-to-delete"

_, err = svc.DeleteObject(&s3.DeleteObjectInput{Bucket: aws.String(bucket), Key: aws.String(obj)})

err = svc.WaitUntilObjectNotExists(&s3.HeadObjectInput{
    Bucket: aws.String(bucket),
    Key:    aws.String(obj),
}) // errorが帰ってこなければ成功

全てのファイルを削除:DeleteObjects

import "github.com/aws/aws-sdk-go/service/s3/s3manager"

bucket := "bucket-name"

iter := s3manager.NewDeleteListIterator(svc, &s3.ListObjectsInput{
    Bucket: aws.String(bucket),
})

if err := s3manager.NewBatchDeleteWithClient(svc).Delete(aws.BackgroundContext(), iter); err != nil {
    fmt.Println(err)
}

アーカイブされたファイルの復元:RestoreObject

obj := "file-to-restore"
_, err = svc.RestoreObject(&s3.RestoreObjectInput{
    Bucket: aws.String(bucket),
    Key: aws.String(obj), 
    RestoreRequest: &s3.RestoreRequest{Days: aws.Int64(30)}
    })

バケットの削除:DeleteBucket

bucket := "bucket-name"
_, err = svc.DeleteBucket(&s3.DeleteBucketInput{
    Bucket: aws.String(bucket),
})

err = svc.WaitUntilBucketNotExists(&s3.HeadBucketInput{
    Bucket: aws.String(bucket),
})
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

モダンな技術を全く知らないSIer5年目がWebサービスを作ることになったため0から勉強する ~AWS編その2~

はじめに

現在SIer5年目でjavascript(Jqueryのみ)、PHP(フレームワーク無し)を2年ほど、C#(Windowsアプリ)3年ほどやってきました。
色々なご縁があり、個人で最近Webサービスの立ち上げをやることになったのですが何せ本当にWebサービスを立ち上げるための知識がほぼ0に等しいです:sob:

ただ今後のキャリアを考えた時に今のままではいけないと思いチャレンジすることにしました。

まずは最初に技術を習得しないといけないので、学ぶ&アウトプットするために毎回投稿していこうと思います。
今後身についていこうと思ってるのは下記のような技術です。
AWS
Docker
CI/CD環境の構築(何を使うかはまだ未定)
Laravel
Nuxt.js

今回はAWSについて学んでいきます。

関連記事

モダンな技術を全く知らないSIer5年目がWebサービスを作ることになったため0から勉強する ~AWS編その1~

EC2を学ぶ

AWSでは一番有名?なサービスで、自分もAWSは全く勉強してなくてもこのサービス名とこれでクラウドにサーバを建てれるのは知っていました。

EC2インスタンスを起動する

起動までの流れ
大きく分けて5つの流れで構成されています。

  1. OS/Imageの選択
  2. インスタンスタイプの選択
  3. ストレージの選択
  4. セキュリティグループの作成
  5. SSHキーペアの設定

image.png

OS/Imageの選択

どのOSを使用するか選定する
EC2サービスの画面でインスタンス作成ボタンを押下すると
Amazonマシンイメージ(AMI)を選択する画面が出てくる
image.png

クイックスタート

AWSで用意されているデフォルトのイメージ

マイAMI

自分で作成したAMI

AWS Marketplace

他のベンダーが作成したAMI

コミュニティAMI

その他コミュニティで作成されているAMI

インスタンスタイプの設定

インスタンスタイプを一覧から選択する。今回は無料枠にしておく
image.png

ストレージの設定

ストレージの設定を行う
今回は初期値にしておくが、実際Webサービス構築時にはここら辺も考慮が必要かも。。

image.png

セキュリティグループの設定

FWの設定を行える。
ソースの項目の箇所でよりアクセスできるところを限定しておかないとセキュリティ的に危ない
image.png

SSHキーペアの設定

SSHのキーペアを作成し、ローカルに保存しておく。
SSH接続に必要なため
image.png

EC2インスタンスに接続し、ミドルウェアを起動する

立ち上げたEC2にSSH接続し、ミドルウェアを起動する(Apache)

SSH接続する

ターミナルを開いてSSHのキーファイルに移動する

cd {xxx.pemファイルのパス}

SSHキーのファイル権限が大きすぎるためこのままだと接続時にWarningで弾かれてしまう
そのためpermissionの設定を変える

chmod 400 xxx.pem

SSHで接続する

ssh -i udemy-aws-14days.pem ec2-user@{EC2のIPv4 パブリック IP}

httpdのインストールを行う

sudo yum install httpd

httpdを立ち上げる

sudo service httpd start

サーバのIPアドレスでアクセスすると下記の画面が表示されるのでWebサーバが立ち上がったのが確認できる

image.png

AMIを取得する

  1. AMIとして取得したいインスタンスを停止させる
  2. イメージの作成を行う
    image.png

  3. AMIタブを押下し、作成されたAMIを選択し作成ボタンを押下して新たにインスタンスの生成を行う

  4. 通常のインスタンスのアクセスと同様に行い、Webサーバを立ち上げるとこまで行う

EIPでIPアドレスを固定する

通常インスタンスを起動/停止するたびにIPアドレスが変わってしまう。
IPアドレスを固定にするためEIPの設定を行う

  1. [Elastic IP]>[新しいIPアドレス割り当て]>[割り当て]でIPアドレスの払い出しを行ってもらう
    image.png

  2. [Elastic IP]>[アクション]>[アドレスの関連付け]に移動し、関連付けるインスタンスを選択し、[関連付け]ボタンを押下する

注意点

取得したEIPはどこにも割り当てていなくても料金が発生してしまうため
取得したまま放置しないこと

image.png

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

CloudFormationを使ってS3とCloudFrontの構成で静的Webサイトを構築する(Origin Access Identityは使う)

はじめに

本記事では、AWS CloudFormation管理コンソールを使って、S3とCloudFrontで、静的Webサイトの環境を構築する手順を説明しています。(初心者向け)

また、CloudFrontのOriginの設定においては、OAI(Origin Access Identity)を使って、S3の静的Webサイトには、直接アクセスできない 構成としています。
直接アクセスできる構成にしたい場合は、下記の記事を参考にしてください。
CloudFormationを使ってS3とCloudFrontの構成で静的Webサイトを構築する(Origin Access Identityは使わない)

本記事で掲載しているテンプレートの最新版は、下記に置いてます。
https://github.com/okubo-t/aws-cloudformation

構成図

前提条件

CloudFrontに設定するSSLサーバ証明書を、リージョンがバージニア北部のAWS Certificate Manager(ACM)にインポートしていること。

ACM管理コンソールで、CloudFrontに設定する証明書の識別子をメモしておく。

構築手順

1 AWS CloudFormation管理コンソールから、スタックの作成をクリックします。

2 後述のテンプレートを選択します。

3 各パラメータを入力します。

パラメータ名 用途 備考
スタックの名前 テンプレートから作成するリソース一式の名前 例 s3-cf-web-20190226
BucketName コンテンツを配置するバケット名 必須
WebsiteDomainName 静的Webサイトのドメイン名 CloudFrontのCNAME 必須
CFSSLCertificateId 前提条件でメモした証明書の識別子 必須

4 後続は、デフォルトのまま次へ次へで、作成します。

5 状況が CREATE COMPLETEになれば、S3とCloudFrontの構築が完了です。

6 管理コンソールの下部の出力から、構築したS3バケットとCloudFrontの情報を確認できます。
  ここで、キーがDomainNameの値をメモしておきます。

7 確認のために、S3の管理コンソールから、パラメータに設定したバケットに、index.htmlファイルをアップロードします。

8 ブラウザから、先ほどメモしたDomainNameの値にWebアクセスして、index.htmlの内容が表示されれば、OKです。

9 最後に、適宜、WebsiteDomainNameのCNAMEレコード(Route53の場合は、ALIASレコード)として、CloudFrontのドメイン名をDNSサーバ(Route53)に登録してください。

テンプレート

s3-cloudfront-web-hosting-02.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: 
  S3 and CloudFront for Static website hosting (OAI Available)

Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      - Label: 
          default: "S3 and CloudFront Configuration"
        Parameters: 
          - BucketName
          - WebsiteDomainName
          - CFSSLCertificateId

    ParameterLabels: 
      BucketName:
        default: "BucketName"
      WebsiteDomainName:
        default: "WebsiteDomainName"
      CFSSLCertificateId: 
        default: "CFSSLCertificateId"

# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------# 
Parameters:
  BucketName:
    Type: String

  WebsiteDomainName:
    Type: String

  CFSSLCertificateId:
    Type: String

Resources:
# ------------------------------------------------------------#
#  S3 Bucket
# ------------------------------------------------------------#        
# Bucket
  Bucket:
    Type: "AWS::S3::Bucket"
    Properties:
      BucketName: !Ref BucketName

  CloudFrontOriginAccessIdentity:
    Type: "AWS::CloudFront::CloudFrontOriginAccessIdentity"
    Properties:
      CloudFrontOriginAccessIdentityConfig:
        Comment: !Sub "access-identity-${Bucket}"

  BucketPolicy:
    Type: "AWS::S3::BucketPolicy"
    Properties:
      Bucket: !Ref Bucket
      PolicyDocument:
        Statement:
        - Action: "s3:GetObject"
          Effect: Allow
          Resource: !Sub "arn:aws:s3:::${Bucket}/*"
          Principal:
            CanonicalUser: !GetAtt CloudFrontOriginAccessIdentity.S3CanonicalUserId

# ------------------------------------------------------------#
#  CloudFront
# ------------------------------------------------------------#  
  CloudFrontDistribution:
    Type: "AWS::CloudFront::Distribution"
    Properties:
      DistributionConfig:
        PriceClass: PriceClass_All
        Aliases:
        - !Ref WebsiteDomainName
        Origins:
        - DomainName: !GetAtt Bucket.DomainName
          Id: !Sub "S3origin-${BucketName}"
          S3OriginConfig:
            OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}"
        DefaultRootObject: index.html
        DefaultCacheBehavior:
          TargetOriginId: !Sub "S3origin-${BucketName}"
          ViewerProtocolPolicy: redirect-to-https
          AllowedMethods:
          - GET
          - HEAD
          CachedMethods:
          - GET
          - HEAD
          DefaultTTL: 3600
          MaxTTL: 86400
          MinTTL: 60
          Compress: true
          ForwardedValues:
            Cookies:
              Forward: none
            QueryString: false
        ViewerCertificate:
          SslSupportMethod: sni-only
          MinimumProtocolVersion: TLSv1.1_2016
          AcmCertificateArn: !Sub "arn:aws:acm:us-east-1:${AWS::AccountId}:certificate/${CFSSLCertificateId}"
        HttpVersion: http2
        Enabled: true

# ------------------------------------------------------------#
# Output Parameters
# ------------------------------------------------------------#  
Outputs:
#BucketName
  BucketName:
    Value: !Ref Bucket

#DistributionID
  DistributionID:
    Value: !Ref CloudFrontDistribution

#DmainName
  DomainName:
    Value: !GetAtt CloudFrontDistribution.DomainName
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Configにてマネージドルールを定期評価をさせる方法

経緯

AWS ConfigにはAWSリソースが適切な設定になっているかを監視してくれる機能があります。
以下は一例です。

  • S3 バケットでパブリック読み取りアクセスが許可されないことを確認します。
  • AWS アカウントで AWS CloudTrail が有効になっているかどうかを確認します。
  • RDS DB インスタンスの高可用性が有効になっているかどうかを確認します。

一回目の非準拠メールを見逃してしまうと
上記のルールに非準拠した状態が継続することになります。
中々恐ろしいですね。
その為、ルールを定期的に評価させてみることになりました。

勘違い

AWS Configのマネージドルールについて勘違いをしまして、
ルールの詳細のトリガータイプを「設定の変更」→「定期的」にすれば
どれでも定期実行が可能だと思ってました。

が、ルールをEditで開いても「定期的」がグレーアウトしていてチェックすることができないものがあります。

AWSのサポートから教えて頂いた対処

StartConfigRulesEvaluationをLambdaで実装してCloudWatch EventsからLambdaを定期実行すれば
要望満たせるとのことでした。

Lambda用のRole

以下のPolicyを作成してこれから作成するLambda用のRoleへアタッチすればOKです。

JSONの場合

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "config:StartConfigRulesEvaluation",
            "Resource": "*"
        }
    ]
}

マネージドコンソールの場合

image.png

Lambda(Python3.6)

Pythonの参考ページを参照しつつ作成したコードがこちらです。

import boto3

client = boto3.client('config')

def lambda_handler(event, context):
    response = client.start_config_rules_evaluation(
        ConfigRuleNames=[
            's3-bucket-public-read-prohibited',
            'cloudtrail-enabled',
            'rds-multi-az-support' 
        ]
    )

ConfigRuleNamesの箇所にマネージドルールの項目名を記載するだけです。
上で作成したRoleを選択するとLambdaの画面でConfigが連携されます。

image.png

CloudWatch Events

スケジュールにて確認したい間隔を設定し、Lambdaを指定することで、連携が完了です。
image.png

確認方法

ルールの項目から評価状況を確認してください。
最後に成功した呼び込みと最後に成功した評価が指定した間隔で更新されたら成功です。

image.png

落とし穴

AWS Configは仕様でルールの準拠・非準拠のステータス変更時しか通知してくれません。
つまり非準拠が継続の場合にはメール通知がありません。
サポートから上記の回答を頂いたので2019年2月末時点では代替手段もなさそなので
「運用でカバー」をしないといけない様です・・・

■ 公式リンク
公式ページ
ブラックベルト
AWS Config マネージドルールのリスト

■ AWS Config過去記事
AWS Configの通知内容をLambdaで成形

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

モダンな技術を全く知らないSIer5年目がWebサービスを作ることになったため0から勉強する ~AWS編その1~

はじめに

初のQiita投稿になります。
色々と間違ってる点や拙い文章になると思いますが生暖かく見守って、ついでにアドバイスをいただけると幸いですw

現在SIer5年目でjavascript(Jqueryのみ)、PHP(フレームワーク無し)を2年ほど、C#(Windowsアプリ)3年ほどやってきました。
色々なご縁があり、個人で最近Webサービスの立ち上げをやることになったのですが何せ本当にWebサービスを立ち上げるための知識がほぼ0に等しいです:sob:

ただ今後のキャリアを考えた時に今のままではいけないと思いチャレンジすることにしました。

まずは最初に技術を習得しないといけないので、学ぶ&アウトプットするために毎回投稿していこうと思います。
今後身についていこうと思ってるのは下記のような技術です。
AWS
Docker
CI/CD環境の構築(何を使うかはまだ未定)
Laravel
Nuxt.js

今回はAWSについて学んでいきます。

AWSアカウント作成と初期設定諸々

  1. AWSアカウント作成
  2. 作業用IAMを作る
  3. CloudTrailを設定
  4. 料金アラートを設定

1. AWSアカウント作成

下記のURLからAWSのアカウントを作成する
手順通り作成していく
AWS公式サイト

作成後にIAMユーザで請求確認できるように設定する
[UserName]>[マイアカウント]

image.png

この次の手順で作成するIAMユーザでも請求書を確認できるようにする
image.png

2. IAMユーザの作成

AWSでアカウントを作成した直後では、rootユーザのみで全権限を持っており
アカウントの設定方法、サポートプラン変更時はこのrootユーザでなければできない
それ以外はIAMユーザに権限を与えてそちらで作業させるのがAWSのベストプラクティスらしい

それぞれのアカウントの特徴は下記の通り

rootユーザ

  1. 全サービスを扱える特権ユーザ
  2. アカウント設定変更/サポートプラン変更はこのユーザのみでしか行えない
  3. セキュリティ的に通常の作業はこのユーザの仕様は非推奨

IAMユーザ

  1. 許可されたAWSサービスしか行えない
  2. 利用者ごとに払い出し、通常の作業はこちらで行い
IAMユーザの作成をしていく

(1) AWSサービスの検索ボックスで「IAM」と検索し、IAMユーザの画面に移動する
(2) [ユーザ]タブ>[ユーザーを追加]ボタン
(3) 任意のユーザ名を入力
(4) アクセス種類[AWSマネジメントコンソールへアクセス]にチェック
(5) パスワード設定
※他の作業者のために作成してるならパスワードリセットのチェックボックスをONにする

アクセスポリシーの設定

今回は一旦全てのサービスを利用できるようにするためAWSで定義されている下記のポリシーで設定する
image.png

IAMユーザの作成をしたら、ログイン用の独自のURLが発行され
作成したIAMユーザはそのURLからログインすることになる

3. CloudTrailの設定

CloudTrailはAWSに関する操作ログを自動取得するサービス
デフォルトでは90日まで残すようになっているが、個人ならいいが実際に稼働するサービスを構築する場合にはもっと長い期間を置いておく必要がある

cloudtrailのサービス画面に移動する
image.png

移動したら次にログを永続的に残すために[証跡の作成]ボタンを押下する
image.png

今回はこんな感じの設定にしました。ちなみにスクショにはないけどS3のバケットを作成し、S3バケット名も定義しました
image.png
image.png

4. 料金アラートの設定

AWSの料金が指定の値を超えたら通知するように設定する

「請求アラートの設定」

[マイアカウント]>[Billing の設定]
請求アラートを受け通るのチェックボックスをONにする

[CloudWatch機能を利用する]

CloudWatchサービスの画面に移動する
[請求]メニュー>[アラームの作成]ボタン

(1)アラームする金額設定
(2)通知先のメールアドレスの設定

補足:AWS料金の調べ方

最近Qiitaで良さげなの見つけたんでこれ貼っときます
ざっくりAWS

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

リージョン丸ごと綺麗にしてみた

環境作りの練習に使っていた環境を削除するので、その様子をメモ書きします。

やったこと

  1. CloudFormationのスタックを削除する準備
  2. CloudFormationのスタックを削除する
  3. 残ったものを削除する

1. CloudFormationのスタックを削除する準備

  • ECRを削除します。
    あらかじめ消さない場合、以下のようにCloudFormationのスタック削除が失敗します。
in registry with id '******' cannot be deleted because it still contains images (Service: AmazonECR; Status Code: 400; Error Code: RepositoryNotEmptyException; Request ID: cbe340fe-39e6-11e9-90f7-******)
  • API GatewayのVPC Linkを削除します。

    VPC Linkが参照しているリソースは削除できないためです。

  • RDSインスタンスを削除します。

2. CloudFormationのスタックを削除する

普通にCloudFormationのコンソール画面からスタックを削除します。

3. 残ったものを削除する

  • EC2のマネジメントコンソールからネットワークインターフェースの一覧を表示し、それを削除対象のVPCで絞り込み、利用しているリソースを削除します。

  • ENIを利用しているリソースを削除したら、次はENIをでタッチします。

  • 最後にVPCを削除します。

  • Route53で登録されているドメイン名から、使わなくなったものを削除します。

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

Amazon EFSに数百GB以上のデータを置く場合の注意点

複数EC2インスタンスからアクセス可能なキャッシュとしてEFSを利用し、数百GB以上のデータを定常的に運用している。その中でいくつかハマりポイントが見つかったので書いておく。

EFSとは

えごったーでは、ツイッターAPIのデータのキャッシュとしてEFSを利用している。EFSは簡単に言うと、複数EC2インスタンスに同時にマウントできるEBS。その他の特徴は下記の通り。

  • 複数EC2インスタンスに同時にマウントできる共有ストレージサービス
    • 内部的にはNFS
  • フルマネージド、複数AZへの冗長化あり
  • アクセス速度は、ローカルストレージ(=EBS)よりは遅い、(使い方によるが)S3よりは早い
    • EBS > EFS > S3
  • 料金は、EBSよりも高い、S3よりはもちろん安い
    • EFS > EBS > S3
  • 保存するデータ量に応じてサイズが自動で増減する

この中でもサイズが自動で増減する点が他にはない特徴かつ非常に役に立つ点。自動で増加するサービスは多いが、減少するサービスは比較的珍しい。柔軟性が高い分、EBSよりも料金が高くなっている。

ただし、良い点だけでなく注意が必要な点もいくつかある。それを順に書いていく。

注意点
この規模のデータになると通常のファイルシステム(ext4など)でもそれなりに遅くなります。EFSだけが遅いというわけではない点にご注意ください。

データが大きくなるとファイルの一覧表示(ls)に数十分以上の時間がかかるようになる

今回、EFSには183GBのデータを保存している。

$ df -h
ファイルシス                                                   サイズ  使用  残り 使用% マウント位置
ap-northeast-1b.fs-00000000.efs.ap-northeast-1.amazonaws.com:/   8.0E  183G  8.0E    1% /efs

すると、ファイルの一覧表示ができなくなってしまう。

$ ls /efs/cache

# 結果が返ってこない

ディレクトリ構造は一例として下記の通り。1, 2, 3, 4がファイルで中身はJSONが入っている。ファイル数は250万ほどある。

$ tree /efs/cache
├── 032
│   └── 320
│       └── 1
├── 033
│   └── 330
│       └── 2
├── 034
│   └── 340
│       └── 3
├── 035
│   └── 350
│       └── 4

もちろん、ディレクトリのサイズ表示(du -sh)もできない。

$du -sh /efs/cache

# 結果が返ってこない

ファイルの一覧表示ができないと困るのは有効期限切れのキャッシュを削除するとき

似たような例として、Redis等のキャッシュシステムではキーの一覧表示は非常に負荷がかかる処理であり、本番環境では実行しないように注意する必要があることはよく知られている。

それと同様に、lsをしなければよいと思うかもしれないが、それではうまくいかないケースがある。

Redisは有効期限切れのキャッシュの削除を自動で行う仕組みが用意されているが、ファイルシステムベースのキャッシュは有効期限切れのキャッシュの削除を次回アクセス時に行う実装になっていることがある。

つまり、ある時点で作ったキャッシュは削除されずにずっと残り続ける。それではデータが増えすぎてしまうため、定期的に削除する必要があるが、ファイルシステムベースのキャッシュは有効期限切れキャッシュの探索にlsと類似する仕組みを用いることがあり、このケースに当たると利用しないキャッシュがいつまでも削除されないことになってしまう。

一例として、Rails(ActiveSupport)のFileStoreは上記のような実装になっており、EFSをキャッシュ保存先として利用していると、データが大きくなるにつれ下記のコードで有効期限切れのキャッシュ削除をすることができなくなってしまう。

ActiveSupport::Cache::FileStore.new(dir).cleanup

# 一覧表示ができないためそもそも始まりすらしない

この問題に対して、えごったーでは、定期的にキャッシュを保存するディレクトリを変更することで対処している。

# 1月のキャッシュ。2月になったらrmで削除可能
/efs/cache/201901

# 2月のキャッシュ
/efs/cache/201902

ただし、EFSに数百GBのデータを保存すると、ファイルの削除にも非常に時間がかかるため、rmの実行にも注意が必要となる。

データが大きくなるとファイルの削除(rm)にも数十分以上の時間がかかるようになる

183GBのデータをrmで単純に削除すると、約3時間かかることになる。この点も注意してEFSを運用する必要がある。

$ time rm -rf /efs/cache

real    183m54.272s
user    0m9.202s
sys     1m33.282s

注意点
この規模のデータをrmで削除すると、通常のファイルシステム(ext4など)でもそれなりに遅くなります。EFSだけが遅いというわけではない点にご注意ください。

参考リンク

えごったーのGitHubリポジトリ

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

Amazon EFSで数百GB以上のデータを運用する場合のハマりポイント

複数EC2インスタンスからアクセス可能なキャッシュとしてEFSを利用し、数百GB以上のデータを定常的に運用している。その中でいくつかハマりポイントが見つかったので書いておく。

EFSとは

えごったーでは、ツイッターAPIのデータのキャッシュとしてEFSを利用している。EFSは簡単に言うと、複数EC2インスタンスに同時にマウントできるEBS。その他の特徴は下記の通り。

  • 複数EC2インスタンスに同時にマウントできる共有ストレージサービス
    • 内部的にはNFS
  • フルマネージド、複数AZへの冗長化あり
  • アクセス速度は、ローカルストレージ(=EBS)よりは遅い、(使い方によるが)S3よりは早い
    • EBS > EFS > S3
  • 料金は、EBSよりも高い、S3よりはもちろん安い
    • EFS > EBS > S3
  • 保存するデータ量に応じてサイズが自動で増減する

この中でも サイズが自動で増減する点が他にはない特徴かつ非常に役に立つ点 。自動で増加するサービスは多いが、減少するサービスは比較的珍しい。柔軟性が高い分、EBSよりも料金が高くなっている。

ただし、良い点だけでなく注意が必要な点もいくつかある。それを順に書いていく。

注意点
この規模のデータになると通常のファイルシステム(ext4など)でもそれなりに遅くなります。EFSだけが遅いというわけではない点にご注意ください。

データが大きくなるとファイルの一覧表示(ls)に数十分以上の時間がかかるようになる

今回、EFSには183GBのデータを保存している。

$ df -h
ファイルシス                                                   サイズ  使用  残り 使用% マウント位置
ap-northeast-1b.fs-00000000.efs.ap-northeast-1.amazonaws.com:/   8.0E  183G  8.0E    1% /efs

すると、ファイルの一覧表示ができなくなってしまう。

$ ls /efs/cache

# 結果が返ってこない

ディレクトリ構造は一例として下記の通り。1, 2, 3, 4がファイルで中身はJSONが入っている。ファイル数は250万ほどある。

$ tree /efs/cache
├── 032
│   └── 320
│       └── 1
├── 033
│   └── 330
│       └── 2
├── 034
│   └── 340
│       └── 3
├── 035
│   └── 350
│       └── 4

もちろん、ディレクトリのサイズ表示(du -sh)もできない。

$du -sh /efs/cache

# 結果が返ってこない

ファイルの一覧表示ができないと困るのは有効期限切れのキャッシュを削除するとき

似たような例として、Redis等のキャッシュシステムではキーの一覧表示は非常に負荷がかかる処理であり、本番環境では実行しないように注意する必要があることはよく知られている。

それと同様に、lsをしなければよいと思うかもしれないが、それではうまくいかないケースがある。

Redisは有効期限切れのキャッシュの削除を自動で行う仕組みが用意されているが、 ファイルシステムベースのキャッシュは有効期限切れのキャッシュの削除を次回アクセス時に行う実装になっていることがある

つまり、ある時点で作ったキャッシュは削除されずにずっと残り続ける。それではデータが増えすぎてしまうため、定期的に削除する必要があるが、ファイルシステムベースのキャッシュは有効期限切れキャッシュの探索にlsと類似する仕組みを用いることがあり、このケースに当たると利用しないキャッシュがいつまでも削除されないことになってしまう。

一例として、Rails(ActiveSupport)のFileStoreは上記のような実装になっており、EFSをキャッシュ保存先として利用していると、データが大きくなるにつれ下記のコードで有効期限切れのキャッシュ削除をすることができなくなってしまう。

ActiveSupport::Cache::FileStore.new(dir).cleanup

# 一覧表示ができないためそもそも始まりすらしない

この問題に対して、えごったーでは、定期的にキャッシュを保存するディレクトリを変更することで対処している。

# 1月のキャッシュ。2月になったらrmで削除可能
/efs/cache/201901

# 2月のキャッシュ
/efs/cache/201902

ただし、EFSに数百GBのデータを保存すると、ファイルの削除にも非常に時間がかかるため、rmの実行にも注意が必要となる。

データが大きくなるとファイルの削除(rm)にも数十分以上の時間がかかるようになる

183GBのデータをrmで単純に削除すると、約3時間かかることになる。この点も注意してEFSを運用する必要がある。

$ time rm -rf /efs/cache

real    183m54.272s
user    0m9.202s
sys     1m33.282s

注意点
この規模のデータをrmで削除すると、通常のファイルシステム(ext4など)でもそれなりに遅くなります。EFSだけが遅いというわけではない点にご注意ください。

参考リンク

えごったーのGitHubリポジトリ

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