fluent-plugin-s3 設定と IAMロール アクションの関係と注意
環境 fluent-plugin-s3 1.6.0
関係性のまとめ
アクション | 関係ある設定 | 説明 |
---|---|---|
s3:ListBucket | check_bucket true | true であればfluent起動時にbucket存在をチェック。存在しなければ起動をリトライするfalse だと起動はするが書き込み時に失敗する |
s3:GetObject | check_object true | true であれば同じobjectがあると上書きせずエラーになるfalse だと同名objectは上書きされる |
s3:PutObject | 書き込み全般 |
つまり check_bucket
check_object
が false
ならアクションは最小限の PutObject
のみでよい
check_object false
の注意
check_object false
の時も s3_object_key_format
が同名にしない事で不用意な上書きを防ぐ事ができる。
s3_object_key_format
を設定していなければ、デフォルト値自体が上書きされにくいフォーマットに自動で変更される。
(s3_object_key_format "%{path}/%{date_slice}_%{hms_slice}.%{file_extension}"
になる)
さらに uuid_flush
hex_random
index
hostname
などを使えばより重複を防止し安全に扱える。
uuid_flush
- bufferがフラッシュされる際、常にUUIDに置き換えられる
- 書き込み失敗のリトライ時も新しいUUIDに置き換えられる
hostname
- ホストネームに置き換えられるので、
%s
や%{hms_slice}
などと組み合わせると重複を防止できる
- ホストネームに置き換えられるので、
hex_random
:- bufferに使われるhashで置き換えられる
- 例えば同名エラーでリトライしたときも同じ値が使われる
%{index}
を組み合わせればリトライ時は%{index}
が更新される
fluent-plugin-s3 v0.12
の注意
正確には fluent-plugin-s3 < 1.0.0rc7
のとき。
この時 check_object false
だと s3_object_key_format
が固定されるので注意
check_bucket true
と APIリクエストにかかる料金の注意
check_bucket
は起動時のチェックなので、 true
でもほとんどAPIリクエストはしない。
しかし check_object
は true
だと書き込みの度にAPI GetObject
を発行する。
そのため、特に書き込み頻度が高い場合は、APIリクエストが常に GetObject
-> PutObject
と二重に発生し料金が嵩むので注意。
Scalaでもtry-catchを使う方がよい事もある
環境 Scala 2.13.6
Scalaだと例外を常にTry
で処理しがちなので、反省メモ。
もちろん単純に例外出す可能性ある個所をTry
で包むのは問題ない。
困るのはTry[Either[L, R]]
みたいなネストを避けたい時。
refinedとかでよくある。
例えば以下は単純にString
をEither[String, PosInt]
に変換している。
import cats.implicits._ import eu.timepit.refined.api.RefType import eu.timepit.refined.types.numeric.PosInt import scala.util.Try def s2pi(s: String): Either[String, PosInt] = Try(s.toInt).toEither .leftMap(_.getMessage) .flatMap(RefType.applyRef[PosInt](_)) val etPiR = s2pi("1") // Right(1) val etPiL = s2pi("a") // Left(For input string: "a")
読みずらい!
まあ正直言うと、このくらいならまだマシで、実際コード書いているともっと複雑になる事も多々ある。
こういうTryとEitherのネストを避けようとするなら、以下のように書くのが断然読みやすい。
import eu.timepit.refined.api.RefType import eu.timepit.refined.types.numeric.PosInt import scala.util.Try def s2piVer2(s: String): Either[String, PosInt] = try RefType.applyRef[PosInt](s.toInt) catch { case t: Throwable => Left(t.getMessage) } val etPiV2R = s2piVer2("1") // Right(1) val etPiV2L = s2piVer2("a") // Left(For input string: "a")
ドメイン駆動開発(DDD)とCleanArchitectureのエンティティはどう違うか?
双方と共にビジネスモデル定義のためのオブジェクトという点では共通だが、実際には意味は大幅に異なる。
DDDでは
以下のように定義される
主として同一性によって定義されるオブジェクトはエンティティと呼ばれる。
としている。
つまりDDDではビジネスモデルの中でも、常に同一である事を保証できるオブジェクトととして定義されるものがエンティティである。
CleanArchitectureでは
「クリーンアーキテクチャ(The Clean Architecture翻訳)」から
エンティティーは、大規模プロジェクトレベルのビジネスルールをカプセル化する。エンティティは、メソッドを持ったオブジェクトかもしれない、あるいは、データ構造と関数の集合かもしれない。
とある。
これはDDDで言うところの、エンティティ、値オブジェクト、ドメインサービス、リポジトリ(の仕様)、ファクトリ, 集約などのドメインレイヤー全体を指している。
まとめ
回答としては「DDDにおけるエンティティ」と「CleanArchitectureにおけるエンティティ」は全く異なる定義なので、使うアーキテクチャに合わせてコードを書こう。
もっと言えば - 書いているコードのアーキテクチャが、何を採用しているか? - 各用語はどういう定義なのか?
をきちんと理解して書こうという事になる。
プロジェクトによってはCleanArchtectureだけどentityをdomainというpackage名にしたりで、一見DDD風に見える事もあったり、そもそも全く異なる意味で使っている場合もある。
プロジェクトに参加したときはビジネス的な言葉、DDDでいうユビキタス言語だけではなく、こういったコード上の意味合いも慎重に確認する事が大切。
aws sam (Serverless Application Model)に入門する
Infrastructure as Code入門としてaws samでLambdaを作るところからはじめてみる
sample templateから基本的なアプリケーションをビルト
仕組み的には以下のような順序で作成される
- ローカルでsamコマンドでアプリケーションを作成
- ローカルから
sam deploy
でcloudformationを呼び出しアプリケーションをデプロイする - S3へテンプレートが保存される
- API GatewayとLambdaが作成される
aws samのアプリケーションを作成
$ sam init # まずはawsのtemplateを選択して使う # template一覧は以下 Which template source would you like to use? 1 - AWS Quick Start Templates 2 - Custom Template Location Choice: 1 # パッケージはシンプルに # lambda用のファイルはzipで固め # cloudformationでS3にアップロードされる # # 2のイメージはECR周りの知識が必要なのでそのうち試す What package type would you like to use? 1 - Zip (artifact is a zip uploaded to S3) 2 - Image (artifact is an image uploaded to an ECR image repository) Package type: 1 # go1.xで作っていく Which runtime would you like to use? 1 - nodejs14.x 2 - python3.8 3 - ruby2.7 4 - go1.x 5 - java11 6 - dotnetcore3.1 7 - nodejs12.x 8 - nodejs10.x 9 - python3.7 10 - python3.6 11 - python2.7 12 - ruby2.5 13 - java8.al2 14 - java8 15 - dotnetcore2.1 Runtime: 4 # cloudformation, API Gatewayの名前 # S3, Lambdaのprefixとして使われる Project name [sam-app]: Cloning from https://github.com/aws/aws-sam-cli-app-templates # まずは単独のLambdaで作るので1を選択 AWS quick start application templates: 1 - Hello World Example 2 - Step Functions Sample App (Stock Trader) Template selection: 1 ----------------------- Generating application: ----------------------- Name: sam-app Runtime: go1.x Dependency Manager: mod Application Template: hello-world Output Directory: . Next steps can be found in the README file at ./sam-app/README.md
この段階でgolangのLambdaに適した構成が作成される
template.yamlはcloudformationと共通フォーマット
将来的にaws samの範囲より拡張された場合はcloudformationで使う事もできる
$ tree sam-app sam-app ├── Makefile ├── README.md ├── hello-world │ ├── go.mod │ ├── go.sum │ ├── main.go │ └── main_test.go └── template.yaml 1 directory, 7 files
main.goは以下のようにLambdaでGetリクエストを受ける基本的な構成になっている
package main import ( "errors" "fmt" "io/ioutil" "net/http" "github.com/aws/aws-lambda-go/events" "github.com/aws/aws-lambda-go/lambda" ) var ( // DefaultHTTPGetAddress Default Address DefaultHTTPGetAddress = "https://checkip.amazonaws.com" // ErrNoIP No IP found in response ErrNoIP = errors.New("No IP in HTTP response") // ErrNon200Response non 200 status code in response ErrNon200Response = errors.New("Non 200 Response found") ) func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { resp, err := http.Get(DefaultHTTPGetAddress) if err != nil { return events.APIGatewayProxyResponse{}, err } if resp.StatusCode != 200 { return events.APIGatewayProxyResponse{}, ErrNon200Response } ip, err := ioutil.ReadAll(resp.Body) if err != nil { return events.APIGatewayProxyResponse{}, err } if len(ip) == 0 { return events.APIGatewayProxyResponse{}, ErrNoIP } return events.APIGatewayProxyResponse{ Body: fmt.Sprintf("Hello, %v", string(ip)), StatusCode: 200, }, nil } func main() { lambda.Start(handler) }
アプリケーションをbuild
$ sam build Building codeuri: ./sam-app/hello-world runtime: go1.x metadata: {} functions: ['HelloWorldFunction'] Running GoModulesBuilder:Build Build Succeeded Built Artifacts : .aws-sam/build Built Template : .aws-sam/build/template.yaml Commands you can use next ========================= [*] Invoke Function: sam local invoke [*] Deploy: sam deploy --guided
ローカルでアプリケーションを実行
sam local start-api
と実行する事で、ローカルでsamでbuildしたAPIを実行できる
$ sam local start-api Mounting HelloWorldFunction at http://127.0.0.1:3000/hello [GET] You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template 2021-08-08 23:37:49 * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)
この状態でリクエストを投げると、dockerイメージが作成&実行され、レスポンスを返す
$ curl http://127.0.0.1:3000/hello Hello, 11.111.111.111
sam local start-apiのログ
Invoking hello-world (go1.x) Image was not found. Building image...................................................................................................... Skip pulling image and use local one: amazon/aws-sam-cli-emulation-image-go1.x:rapid-1.27.2. Mounting ./sam-app/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated inside runtime container START RequestId: fa806430-6835-4b88-acd6-4e1b857bcd4a Version: $LATEST END RequestId: fa806430-6835-4b88-acd6-4e1b857bcd4a REPORT RequestId: fa806430-6835-4b88-acd6-4e1b857bcd4a Init Duration: 0.07 ms Duration: 1010.38 ms Billed Duration: 1100 ms Memory Size: 128 MB Max Memory Used: 128 MB No Content-Type given. Defaulting to 'application/json'. 2021-08-08 23:43:07 127.0.0.1 - - [08/Aug/2021 23:43:07] "GET /hello HTTP/1.1" 200 -
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES fa8dda6a0f15 amazon/aws-sam-cli-emulation-image-go1.x:rapid-1.27.2 "/var/rapid/aws-lamb…" 2 seconds ago Up 1 second 127.0.0.1:6436->8080/tcp vigorous_allen
アプリケーションをawsへデプロイする
--guided
をつけると会話形式で設定できる
$ sam deploy --guided Configuring SAM deploy ====================== Looking for config file [samconfig.toml] : Not found Setting default arguments for 'sam deploy' ========================================= Stack Name [sam-app]: AWS Region [ap-northeast-1]: #Shows you resources changes to be deployed and require a 'Y' to initiate deploy Confirm changes before deploy [y/N]: #SAM needs permission to be able to create roles to connect to the resources in your template Allow SAM CLI IAM role creation [Y/n]: HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y Save arguments to configuration file [Y/n]: SAM configuration file [samconfig.toml]: SAM configuration environment [default]: Looking for resources needed for deployment: Not found. Creating the required resources... Successfully created! Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-xarl3ki5fc62 A different default S3 bucket can be set in samconfig.toml Saved arguments to config file Running 'sam deploy' for future deployments will use the parameters saved above. The above parameters can be changed by modifying samconfig.toml Learn more about samconfig.toml syntax at https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html Uploading to sam-app/7ad10cf1c8bd04b9d2c1ad18dd4297c0 4328737 / 4328737 (100.00%) Deploying with following values =============================== Stack name : sam-app Region : ap-northeast-1 Confirm changeset : False Deployment s3 bucket : aws-sam-cli-managed-default-samclisourcebucket-xarl3ki5fc62 Capabilities : ["CAPABILITY_IAM"] Parameter overrides : {} Signing Profiles : {} Initiating deployment ===================== Uploading to sam-app/17fb0b7caff4b6a85cdca466c28c1236.template 1154 / 1154 (100.00%) Waiting for changeset to be created.. CloudFormation stack changeset ---------------------------------------------------------------------------------------------------- Operation LogicalResourceId ResourceType Replacement ---------------------------------------------------------------------------------------------------- + Add HelloWorldFunctionCatchAllPermissionProd AWS::Lambda::Permission N/A + Add HelloWorldFunctionRole AWS::IAM::Role N/A + Add HelloWorldFunction AWS::Lambda::Function N/A + Add ServerlessRestApiDeployment47fc2d5f9d AWS::ApiGateway::Deployment N/A + Add ServerlessRestApiProdStage AWS::ApiGateway::Stage N/A + Add ServerlessRestApi AWS::ApiGateway::RestApi N/A ---------------------------------------------------------------------------------------------------- Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:111111111111:changeSet/samcli-deploy1628426562/db1f0927-131d-4bf1-9b12-aacf949eacda 2021-08-08 21:42:54 - Waiting for stack create/update to complete CloudFormation events from changeset ------------------------------------------------------------------------------------------------------------------------------ ResourceStatus ResourceType LogicalResourceId ResourceStatusReason ------------------------------------------------------------------------------------------------------------------------------ CREATE_IN_PROGRESS AWS::IAM::Role HelloWorldFunctionRole - CREATE_IN_PROGRESS AWS::IAM::Role HelloWorldFunctionRole Resource creation Initiated CREATE_COMPLETE AWS::IAM::Role HelloWorldFunctionRole - CREATE_IN_PROGRESS AWS::Lambda::Function HelloWorldFunction - CREATE_IN_PROGRESS AWS::Lambda::Function HelloWorldFunction Resource creation Initiated CREATE_COMPLETE AWS::Lambda::Function HelloWorldFunction - CREATE_IN_PROGRESS AWS::ApiGateway::RestApi ServerlessRestApi - CREATE_IN_PROGRESS AWS::ApiGateway::RestApi ServerlessRestApi Resource creation Initiated CREATE_COMPLETE AWS::ApiGateway::RestApi ServerlessRestApi - CREATE_IN_PROGRESS AWS::Lambda::Permission HelloWorldFunctionCatchAllPermissionProd - CREATE_IN_PROGRESS AWS::Lambda::Permission HelloWorldFunctionCatchAllPermissionProd Resource creation Initiated CREATE_IN_PROGRESS AWS::ApiGateway::Deployment ServerlessRestApiDeployment47fc2d5f9d - CREATE_COMPLETE AWS::ApiGateway::Deployment ServerlessRestApiDeployment47fc2d5f9d - CREATE_IN_PROGRESS AWS::ApiGateway::Deployment ServerlessRestApiDeployment47fc2d5f9d Resource creation Initiated CREATE_IN_PROGRESS AWS::ApiGateway::Stage ServerlessRestApiProdStage - CREATE_IN_PROGRESS AWS::ApiGateway::Stage ServerlessRestApiProdStage Resource creation Initiated CREATE_COMPLETE AWS::ApiGateway::Stage ServerlessRestApiProdStage - CREATE_COMPLETE AWS::Lambda::Permission HelloWorldFunctionCatchAllPermissionProd - CREATE_COMPLETE AWS::CloudFormation::Stack sam-app - ------------------------------------------------------------------------------------------------------------------------------ CloudFormation outputs from deployed stack ----------------------------------------------------------------------------------------------------------- Outputs ----------------------------------------------------------------------------------------------------------- Key HelloWorldFunctionIamRole Description Implicit IAM Role created for Hello World function Value arn:aws:iam::111111111111:role/sam-app-HelloWorldFunctionRole-MGSTGE9WCIMR Key HelloWorldAPI Description API Gateway endpoint URL for Prod environment for First Function Value https://aaaaaaaaaa.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/ Key HelloWorldFunction Description First Lambda Function ARN Value arn:aws:lambda:ap-northeast-1:111111111111:function:sam-app-HelloWorldFunction-pMOSVaxRjbuN ----------------------------------------------------------------------------------------------------------- Successfully created/updated stack - sam-app in ap-northeast-1
これにより API Gateway経由でLambdaを呼び出せるようところまで作成される
デプロイ結果の確認
Outputs
にあるHelloWorldAPI
へアクセスしてみると、レスポンスが返ってくる
$ curl - 'https://aaaaaaaaaa.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/' HTTP/2 200 content-type: application/json content-length: 22 date: Sun, 08 Aug 2021 13:41:16 GMT Hello, 11.111.111.111
参考
awsデータストレージまとめ(インスタンスストア・EBS・EFS・S3)
各ストレージ
インスタンス ストア
Elastic Block Store (EBS)
- ブロックレベルストレージ
- インスタンスから独立してデータを永続化する
- インスタンスが終了してもデータは残る
- 起動しているインスタンスにアタッチ(追加)できる
- 稼働中にサイズ変更、ボリュームタイプの変更など可能
- インスタンスとEBSは同じAZにある必要がある
Elastic File System (EFS)
- マネージドなサーバーレスなファイルレベルストレージ
- 最大サイズ16TiB(=tebibyte=1024GB)
- EC2でNFSとしてマウント可能
- オートスケール
- リージョン内のAZを跨いでマウント可能
- ただし複数のVPCに接続はできない
Simple Storage Service (S3)
- オブジェクトレベルストレージ
- インターネットストレージとしてURLでアクセス可能
- 無制限のストレージ容量
- 各オブジェクトは最大5TB
- バケットはリージョン単位で保存される
- 各オブジェクトのバージョニングによる変更追跡
- 少なくとも3つのAZにデータが保存(バックアップ)される
- 複数のストレージクラスによる料金プラン
- 各オブジェクトにURLがあり静的webページとしても使える
ストレージ形式について
ファイルレベルストレージ
- ファイルストレージ
- ファイルベース・ストレージ
ファイルによるデータ管理。
階層構造化が容易で、一意のデータパスによりファイルにアクセスする。
データにはファイル名、作成日時などの最低限のメタデータが付与される。
ブロックレべルストレージ
- ブロックストレージ
ディスクを論理ボリュームへ分割し、論理ボリュームをさらにブロックへ分割。
データをブロック単位で保存する(ブロックより大きなデータは複数ブロックへ保存される。連続性はない)
ボリューム、ブロック両方にIDが振られボリュームID+ブロックIDでデータを特定する事で高速なデータアクセスが可能。
ブロック単位での差分更新が可能なため、巨大なデータの更新が高速で行える。
メタデータは基本的にはない、もしくは非常に限定的。
オブジェクトレベルストレージ
- オブジェクトストレージ
- オブジェクトベース・ストレージ
一つのデータを一つのオブジェクトとして保存する。
オブジェクトは一意のIDを持ち、インデックス化され高速にアクセスできる。
多彩なメタ情報が付与され、セキュリティポリシーやアクセス権限に至るまで様々な情報を持つ事ができる。
通常はフラットな構造になるが、S3のようにバケットを入れ子構造にできるサービスもある。
一度書き込まれたオブジェクトは変更できず、オブジェクトは全体を一度で書き込む必要がある。
そのため巨大なデータを更新する場合などは、巨大なデータを再度全て書き込み、過去データを削除(もしくは履歴として残す)ような運用になる。
参考
aws アクセスコントロール系モジュール概要
どのモジュールがどの位置にあるのかを忘れがちなので簡易まとめ
概要図
クラウド単位
外部との接続
- インターネットゲートウェイ(Internet Gateway)
- public cloudへの公開されている接続入口
- 接続はインターネットで行われる
- 仮想プライべートゲートウェイ(Virtual Private Gateway)
- private cloudへの非公開の接続入口
- 接続はインターネットだがVPNで暗号化された接続に
- AWS Direct Connect
ACLとセキュリティグループの違い
- ACL
- セキュリティグループ
つまり以下のようにチェックされる