たくさんの自由帳
Androidのお話
たくさんの自由帳
投稿日 : | 0 日前
文字数(だいたい) : 17023
目次
本題
完成品
CloudFormation 概要
CloudFormation で間違えたら
用語集
テンプレート
リソース
スタック
やってもらうこと
ながれ
テンプレートを用意
すでにあるテンプレートを読み込む
新規作成
とにもかくにも動かしてみる
構文チェック
保存する
CloudFormation を実行する
出来るのを待つ
削除してみる
yaml で組み立て説明書を書いていく
パラメーター機能
今回使うパラメーター解説
条件分岐の定義
改行する書き方とカッコの書き方がある
リソースを定義
Properties に必要な値
Ref と Sub と GetAtt
並列実行と依存
出力機能
カスタムドメインは自動でやってくれません。
エラー集
ROLLBACK_FAILED
日本語が文字化けする
Resource handler returned message: "Invalid request provided: AWS::CloudFront::OriginAccessControl" (RequestToken: , HandlerErrorCode: InvalidRequest)
Resource handler returned message: "Invalid request provided: Exactly one of CustomOriginConfig, VpcOriginConfig and S3OriginConfig must be specified"
Resource handler returned message: "Invalid request provided: AWS::CloudFront::Distribution: The specified cache policy does not exist. (Service: CloudFront, Status Code: 404, Request ID
CloudFront にアクセスしたら Access Denied
Resource handler returned message: "The XML you provided was not well-formed or did not validate against our published schema
Resource handler returned message: "Invalid request provided: AWS::CloudFront::Function: (Service: CloudFront, Status Code: 409, Request ID
Resource handler returned message: "Invalid request provided: AWS::CloudFront::Distribution: The parameter FunctionAssociationArn is invalid
エラー画面が XML から 503 になった
やっぱり 503
おわりに
おわりに2
おわりに3
おわりに4
どうもこんにちわ。初恋マスターアップ攻略しました。マスターアップってそういうことなのか・・・?
はわちゃん!!!が一番仕事してた。かわいい
2人は本当に、、、、?
なつかしい!!!見返したらAndroid 13とかの頃っぽい(ぱっとわからない言い方)
、、、、、このかさんルートを最後にやるといいのかも?どっちかというと楽しみだから最後にとっておいただけなんだけど
!!!かわいい
理由が不純すぎるのすき
ネタバレなのであれだけど、全員のルートでそれぞれある、、、、
なんでも屋のハルルカさんとしずりさんも(サブヒロインなので短い、、、)攻略できます!
そんなに読んでいるのか、、、(ちがう)
あとこのスクショめっちゃ使えそうじゃない?というわけで貼ります
アプリ開発だからいつか使えそう!
アプリの話では、、、、ありません!
CloudFormation 触ってたので、忘れないうちにまとめようと思って。
このサイトを含めてCloudFront+S3の構成のサイトがいくつかあります。雑ですが構成図はこうで
構成の詳細ですが、S3の機能にある静的ウェブサイト機能は使っていません。
代わりにCloudFrontのオリジンアクセスコントロール (OAC)機能を使って、S3にアクセスできるようにしています。これを使うことでS3へアクセスできるのはCloudFrontだけになり、直接アクセスされるのを防ぐことが出来るってわけ。
(直接S3にアクセスできるとhttpしか受け付けないとか!カスタムドメインでCloudFrontつかうので!)
一方オリジンアクセスコントロールも万能ではなく、URL末尾が/aboutだけだとアクセスできなくて、/about/index.htmlと言った感じに.htmlまで書く必要があります。
あんまりindex.htmlまで書かないですよね、静的サイトホスティングサービスであれば自動的に処理してくれるし、レンタルサーバーの場合はNginxあたりがよしなに返してくれてるので。
というわけでCloudFront Functionです。これはCloudFrontが処理する前に任意のJavaScript コードが介入できる機能で、これを使いURLの末尾に/index.htmlを付与します。
これで/aboutだけでアクセスできるようになる。というわけ。
CloudFrontに介入する方法としてはLambda@Edgeという似たような機能がありますが、URL書き換えであればすぐ出来るのでCloudFront Functionで十二分だと思います。それにこれには十分すぎる無料枠があります。
まあそんな感じでS3とCloudFrontとオリジンアクセスコントロールとCloudFront Functionと、あとドメイン。をやる必要があります。
説明書無しではほぼ覚えてない状態になります。
Parameters:
BucketName:
Type: String
Description: WebSite Output S3 Bucket Name
OriginAccessControlDescription:
Type: String
Default: cloudfront-s3-oac
Description: Origin Access Control Description
CloudFrontComment:
Type: String
Default: s3-cloudfront
Description: CloudFront memo
CloudFrontFunctionCreateOrReuse:
Type: String
Default: Create
AllowedValues:
- Create
- Reuse
Description: Append index.html suffix CloudFront Function. If created some
function, Reuse. Don't have, Create
CloudFrontFunctionName:
Type: String
Default: function-add-index
Description: CloudFront Function Name. If Reuse, created function name.
CachePolicyCreatedOrManaged:
Type: String
Default: 658327ea-f89d-4fab-a63d-7e88639e58f6
Description: Cache Policy. Default is CachingOptimized.
Conditions:
# CloudFront Functions を作るか
CreateCloudFrontFunction: !Equals
- !Ref CloudFrontFunctionCreateOrReuse
- Create
Resources:
# Next.js の static exports した結果を入れる S3
WebSiteBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref BucketName
BucketEncryption:
ServerSideEncryptionConfiguration:
- BucketKeyEnabled: true
ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
# S3 - CloudFront をつなぐバケットポリシー
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref WebSiteBucket
PolicyDocument:
Id: PolicyForCloudFrontPrivateContent
Version: '2008-10-17'
Statement:
- Sid: AllowCloudFrontServicePrincipal
Effect: Allow
Principal:
Service: cloudfront.amazonaws.com
Action: s3:GetObject
Resource: !Sub arn:aws:s3:::${BucketName}/*
Condition:
StringEquals:
AWS:SourceArn: !Sub arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}
# S3 に入っている Web サイトを配信する CloudFront
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- Id: !GetAtt WebSiteBucket.RegionalDomainName # マネジメントコンソールで作ると DomainName と同じ文字列になってそう
DomainName: !GetAtt WebSiteBucket.RegionalDomainName # リージョンが入ってないとアクセスできなかった
OriginAccessControlId: !GetAtt OriginAccessControl.Id
S3OriginConfig:
OriginAccessIdentity: ''
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
TargetOriginId: !GetAtt WebSiteBucket.RegionalDomainName # Origins Id に合わせる
ViewerProtocolPolicy: allow-all
FunctionAssociations:
# CloudFront Functions を作成する場合は、CloudFrontAddIndexFunction に依存するように書いておく。これで CloudFormation は先に Function を作る順番になるはず
- EventType: viewer-request
FunctionARN: !If
- CreateCloudFrontFunction
- !GetAtt CloudFrontAddIndexFunction.FunctionMetadata.FunctionARN
- !Sub arn:aws:cloudfront::${AWS::AccountId}:function/${CloudFrontFunctionName}
CachePolicyId: !Ref CachePolicyCreatedOrManaged
Compress: true
HttpVersion: http2
Enabled: true
Comment: !Ref CloudFrontComment
# S3- CloudFront をつなぐ OAC
OriginAccessControl:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Description: !Ref OriginAccessControlDescription
Name: !GetAtt WebSiteBucket.RegionalDomainName
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
# CloudFront Function を作成する場合
# index.html を付与する Function
# https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/example_cloudfront_functions_url_rewrite_single_page_apps_section.html
CloudFrontAddIndexFunction:
Type: AWS::CloudFront::Function
Condition: CreateCloudFrontFunction
Properties:
Name: !Ref CloudFrontFunctionName
AutoPublish: true
FunctionConfig:
Comment: add index.html to url suffix
Runtime: cloudfront-js-2.0
FunctionCode: |
async function handler(event) {
var request = event.request;
var uri = request.uri;
// Check whether the URI is missing a file name.
if (uri.endsWith('/')) {
request.uri += 'index.html';
}
// Check whether the URI is missing a file extension.
else if (!uri.includes('.')) {
request.uri += '/index.html';
}
return request;
}
Outputs:
WebSiteBucket:
Description: S3
Value: !Ref WebSiteBucket
CloudFrontDistribution:
Description: CloudFront
Value: !Ref CloudFrontDistribution
OriginAccessControl:
Description: CloudFront OAC
Value: !Ref OriginAccessControl
CloudFrontAddIndexFunction:
Condition: CreateCloudFrontFunction
Description: CloudFront Functions
Value: !Ref CloudFrontAddIndexFunction上記の構成が作れます。使い方は、CloudFormationを開いて、Stackを作るときに↑のyamlを読み込んで、パラメーターを埋めてください。
パラメーターの詳細です
| パラメーター名 | 説明 |
|---|---|
| BucketName | S3バケット名。命名規則はS3に準拠します。 |
| OriginAccessControlDescription | OACの説明。名前はバケット名の{バケット名}.s3.{リージョン}.amazonaws.comになります |
| CloudFrontComment | CloudFrontのコメント欄 |
| CloudFrontFunctionCreateOrReuse | CreateかReuse。Createなら新規作成/index.htmlを付与するCloudFrontFunctionがすでにある場合はReuse |
| CloudFrontFunctionName | Createならこれから作るCloudFrontFunctionの名前。ReuseならすでにあるCloudFrontFunctionの名前 |
| CachePolicyCreatedOrManaged | CloudFrontのキャッシュポリシー。デフォルトはキャッシュ最適化 |
カスタムドメインはやってくれないので自分でやってください!
くらうどふぉーめーしょん
AWSで使いたいリソース(S3とかCloudFrontとか)を指示するというか、組み立て説明書みたいなのを渡すと自動で作ってくれる。
人の手でマネジメントコンソール(ブラウザ上)を使ってS3とかを作るとやり忘れが発生するかもしれないし、上記の問題のように同じ構成で他のサイトを構築したいだけなのに、いくつかのリソースにまたがって設定が必要で少し時間がかる。
これに対処したのがIaCと呼ばれるもので、人の手でS3を作る代わりに、組み立て説明書にS3を作れ!!って書くわけです。
これをCloudFormationに食わせると読み込んで作ってくれる。間違いも減るだろうし、繰り返し似たようなサイトを作りたくなってもCloudFormationの実行ボタンを押せばだいたい揃う。
失敗したら途中まで作ったリソース全部消して回らないといけないのか?とか思ってたけど流石にそんなこと無かった。AWSの説明だけ見ると横文字ばっかで実際に使うまで全然わからない・・・AWS文学来るか?
S3とか)は自動で削除されるさっすが~
yamlとかで書いた組み立て説明書です。テキストファイル
S3とかCloudFrontみたいなサービスのこと
CloudFormationを実行すると、スタックが誕生します。CloudFormationの実行単位って感じですかね?
これは今の状態(作成中・完成・失敗したためロールバック)を表示したり、作ったリソースを表示したり、テンプレートに出力(println的なの)があれば表示します。
スタックを削除すると、それが作ったリソースをすべて消すことが出来ます。
GitHub Actionsを起動するとJobが誕生するのと似てる。
そしてこれは起動したものの失敗してロールバックしたスタック一覧です。うわーー
スタックの詳細画面、リソースタブでは作ったリソースが表示される
S3 バケットCloudFront ディストリビューションS3 - CloudFrontを繋ぐオリジンアクセスコントロール/index.htmlを付与するためのCloudFront Functionを作れる組み立て説明書を書いてもらいます。
めちゃくちゃどうでもいいんだけど、IKEAの説明書にある人のキャラクターおもろい。IKEAの店から電話線引いてるやつ
CloudFormationのテンプレート作る組み立て説明書です。yamlで書いていきます。GitHub Actionsで予習済み...!
CloudFormationのここから作れます
そしたら新規作成か既存のを読み込むかが選べます
その場合はS3かyamlをアップロードするなりしてください。
新しく作る場合はInfrastructure Composer からビルドを押して、Infrastructure Composer で作成へ進みます。
そしたらこんな画面になります。ビジュアルエディター的なのがありますが、今回はyamlを書いていきます。
のでテンプレートを選びます。なんかVSCodeみたいな画面になれば成功です。
とりあえずS3を作るテンプレートを書きました。詳しくはあとにして、とりあえず実行してみます。
Parameters:
BucketName:
Type: String
Description: WebSite Output S3 Bucket Name
Resources:
WebSiteBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref BucketName
BucketEncryption:
ServerSideEncryptionConfiguration:
- BucketKeyEnabled: true
ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: trueここの検証ボタンを押すとyaml記法があっているか確認できます。↑コピペすれば有効になるよね?
S3に保存するように言われるので保存します。
次回以降はS3にあるテンプレートから起動できるってわけです。
VSCodeみたいな画面が閉じられて、次へボタンが押せるようになるので進みます。
次にスタックの名前と、このテンプレートはテキストボックスがあるので埋めます。
スタックの名前はわかりやすいのを、その下のテキストボックスはS3バケットの名前です。
その後はデフォルトのままでよいです。よくわかってない
スタック一覧画面に行くので待ちます。終わるとCREATE_COMPLETEになります。嬉しいですね!!!
スタックを押すと詳細が右に表示されます。ここでは作成のログや、失敗してしまったときの失敗理由、あとは作ったリソース(S3とか)が確認できます。
上記の削除ボタンを押すことでスタックと、スタックに書いてあるリソースが消えます。
マネジメントコンソールでS3の画面を開いても、今CloudFormationで作ったS3バケットが消えていると思います。
CloudFormationを起動する際に、パラメーターを指定することが出来ます。S3のバケット名などを、テンプレートを書いている段階ではなく実行する直前に決定することが出来ます。
Parameters:
BucketName:
Type: String
Description: WebSite Output S3 Bucket Name
OriginAccessControlDescription:
Type: String
Default: cloudfront-s3-oac
Description: Origin Access Control Description
CloudFrontComment:
Type: String
Default: s3-cloudfront
Description: CloudFront memo
CloudFrontFunctionCreateOrReuse:
Type: String
Default: Create
AllowedValues:
- Create
- Reuse
Description: Append index.html suffix CloudFront Function. If created some function, Reuse. Don't have, Create
CloudFrontFunctionName:
Type: String
Default: function-add-index
Description: CloudFront Function Name. If Reuse, created function name.
CachePolicyCreatedOrManaged:
Type: String
Default: 658327ea-f89d-4fab-a63d-7e88639e58f6
Description: Cache Policy. Default is CachingOptimized.この例ではBucketNameとかOriginAccessControlDescriptionがID?になって、このあとのリソース作成などの箇所で引用できるようになります。
この後のリソースもそうですが好きな名前をつけることが出来ます。
TypeにStringを入れるとテキストボックスになるし、StringとAllowedValuesを組み合わせるとドロップダウンメニューになります。他にも数字とかもあったと思います。
DescriptionはCloudFormationで実際に入力するときに表示されてて、Defaultはその名のとおりです。
あとは今更ですけどダブルクオーテーション的なので囲う必要はない?
再掲しますがこれです
| パラメーター名 | 説明 |
|---|---|
| BucketName | S3バケット名。命名規則はS3に準拠します。 |
| OriginAccessControlDescription | OACの説明。名前はバケット名の{バケット名}.s3.{リージョン}.amazonaws.comになります |
| CloudFrontComment | CloudFrontのコメント欄 |
| CloudFrontFunctionCreateOrReuse | CreateかReuse。Createなら新規作成/index.htmlを付与するCloudFrontFunctionがすでにある場合はReuse |
| CloudFrontFunctionName | Createならこれから作るCloudFrontFunctionの名前。ReuseならすでにあるCloudFrontFunctionの名前 |
| CachePolicyCreatedOrManaged | CloudFrontのキャッシュポリシー。デフォルトはキャッシュ最適化 |
こうしき
Conditions:
# CloudFront Functions を作るか
CreateCloudFrontFunction: !Equals
- !Ref CloudFrontFunctionCreateOrReuse
- CreateCloudFormationでの条件分岐ですが、あらかじめ true か false か評価して定義しておく必要がある?
条件分岐が必要ならConditionsに書いて、その後必要な箇所で使う
この例だとCreateCloudFrontFunctionがIDになる。
その後の!Equalsは、CloudFormationの組み込み関数で、この後に配列が続きます。インデックス0番目が比較したい文字で、インデックス1番目が等しいのを期待する文字を入れます。
この場合は、パラメーターCloudFrontFunctionCreateOrReuseを読み出してCreateだった場合はtrueになります。
!Refってのを使ってますが、とりあえずは先述のパラメーターから値を取り出すんだな~って
あと実際に条件分岐を使う方法も後で
CreateCloudFrontFunction: !Equals
- !Ref CloudFrontFunctionCreateOrReuse
- CreateCreateCloudFrontFunction:
!Equals [!Ref CloudFrontFunctionCreateOrReuse, Create]これはyamlのリストの書き方の違いで、同じものらしい
ついにS3やCloudFrontを作っていきます。全部張りました。
Resources:
# Next.js の static exports した結果を入れる S3
WebSiteBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref BucketName
BucketEncryption:
ServerSideEncryptionConfiguration:
- BucketKeyEnabled: true
ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
# S3 - CloudFront をつなぐバケットポリシー
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref WebSiteBucket
PolicyDocument:
Id: PolicyForCloudFrontPrivateContent
Version: '2008-10-17'
Statement:
- Sid: AllowCloudFrontServicePrincipal
Effect: Allow
Principal:
Service: cloudfront.amazonaws.com
Action: s3:GetObject
Resource: !Sub arn:aws:s3:::${BucketName}/*
Condition:
StringEquals:
AWS:SourceArn: !Sub arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}
# S3 に入っている Web サイトを配信する CloudFront
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- Id: !GetAtt WebSiteBucket.RegionalDomainName # マネジメントコンソールで作ると DomainName と同じ文字列になってそう
DomainName: !GetAtt WebSiteBucket.RegionalDomainName # リージョンが入ってないとアクセスできなかった
OriginAccessControlId: !GetAtt OriginAccessControl.Id
S3OriginConfig:
OriginAccessIdentity: ''
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
TargetOriginId: !GetAtt WebSiteBucket.RegionalDomainName # Origins Id に合わせる
ViewerProtocolPolicy: allow-all
FunctionAssociations:
# CloudFront Functions を作成する場合は、CloudFrontAddIndexFunction に依存するように書いておく。これで CloudFormation は先に Function を作る順番になるはず
- EventType: viewer-request
FunctionARN: !If
- CreateCloudFrontFunction
- !GetAtt CloudFrontAddIndexFunction.FunctionMetadata.FunctionARN
- !Sub arn:aws:cloudfront::${AWS::AccountId}:function/${CloudFrontFunctionName}
CachePolicyId: !Ref CachePolicyCreatedOrManaged
Compress: true
HttpVersion: http2
Enabled: true
Comment: !Ref CloudFrontComment
# S3- CloudFront をつなぐ OAC
OriginAccessControl:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Description: !Ref OriginAccessControlDescription
Name: !GetAtt WebSiteBucket.RegionalDomainName
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
# CloudFront Function を作成する場合
# index.html を付与する Function
# https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/example_cloudfront_functions_url_rewrite_single_page_apps_section.html
CloudFrontAddIndexFunction:
Type: AWS::CloudFront::Function
Condition: CreateCloudFrontFunction
Properties:
Name: !Ref CloudFrontFunctionName
AutoPublish: true
FunctionConfig:
Comment: add index.html to url suffix
Runtime: cloudfront-js-2.0
FunctionCode: |
async function handler(event) {
var request = event.request;
var uri = request.uri;
// Check whether the URI is missing a file name.
if (uri.endsWith('/')) {
request.uri += 'index.html';
}
// Check whether the URI is missing a file extension.
else if (!uri.includes('.')) {
request.uri += '/index.html';
}
return request;
}WebSiteBucketやCloudFrontDistributionがIDになっています。
その後のTypeは、作りたいAWS リソースを入力します。AWS::S3::Bucketみたいな。Conditionは、上で作った!EqualsのやつのIDを入力することで、trueの時だけ実行される。
その後のPropertiesはそれぞれ必要な値が異なります。
まずはサンプル集を読むとどんな感じか掴みやすいと思います。
その後に、詳しい設定をしたい場合は各自リファレンスを調べてください。S3のバケットポリシーはJSONをyamlにしたようなものだったりする?
S3CloudFront ディストリビューション例えばCloudFront ディストリビューションでIPv6を有効にするなら、IPV6Enabledをつけろって言われてるんでつけます
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
IPV6Enabled: trueどうでもいい話ですがAndroidアプリでIPv6を使うとうまく通信出来ない時があるので、バックエンドエンジニア(インフラ?)の皆さん、IPv6やるときはAndroidエンジニアチームに一声書けてください!!!!!
いちおう解決方法があるので特に問題はないと思いますが...
!Refは、パラメーターのIDの値を読み出したり、その他、リソースのIDを渡すとS3バケット名みたいなのが返ってくることもあります。
BucketName: !Ref BucketName!Subは文字列の中にパラメーターのIDの値を入れたいときに使う。アカウントIDみたいなのが取得できるAWSオブジェクトがあります。グローバル変数というか何もしなくてもAWS::のが使えるようです。
AWS:SourceArn: !Sub arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}GetAttは、作ったリソースの詳細情報を取得したいときに利用します。GetAttで取得可能な値もリファレンスに乗っています。リファレンスのReturn valuesのセクションまでスクロールすると、取得できる値が解説されています。
例えばS3のリソースで以下のようにGetAttすると、、、{バケット名}.s3.{リージョン}.amazonaws.comの文字列が取得できます。
Name: !GetAtt WebSiteBucket.RegionalDomainNameOACもこんな感じ
OriginAccessControlId: !GetAtt OriginAccessControl.IdGetAttや!Refで他のリソースを参照すると、勝手にいい感じに並列の順番を決めてくれます。
すでにリソースが作成されてないとGetAtt出来ないので、完成を待つ感じでしょうか?
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- Id: !GetAtt WebSiteBucket.RegionalDomainName # マネジメントコンソールで作ると DomainName と同じ文字列になってそう
DomainName: !GetAtt WebSiteBucket.RegionalDomainName # リージョンが入ってないとアクセスできなかった
OriginAccessControlId: !GetAtt OriginAccessControl.Id
S3OriginConfig:
OriginAccessIdentity: ''
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
TargetOriginId: !GetAtt WebSiteBucket.RegionalDomainName # Origins Id に合わせる
ViewerProtocolPolicy: allow-all
FunctionAssociations:
# CloudFront Functions を作成する場合は、CloudFrontAddIndexFunction に依存するように書いておく。これで CloudFormation は先に Function を作る順番になるはず
- EventType: viewer-request
FunctionARN: !If
- CreateCloudFrontFunction
- !GetAtt CloudFrontAddIndexFunction.FunctionMetadata.FunctionARN
- !Sub arn:aws:cloudfront::${AWS::AccountId}:function/${CloudFrontFunctionName}
CachePolicyId: !Ref CachePolicyCreatedOrManaged
Compress: true
HttpVersion: http2
Enabled: true
Comment: !Ref CloudFrontComment
CloudFrontAddIndexFunction:
Type: AWS::CloudFront::Function
Condition: CreateCloudFrontFunction
Properties:
Name: !Ref CloudFrontFunctionName
AutoPublish: true
FunctionConfig:
Comment: add index.html to url suffix
Runtime: cloudfront-js-2.0
FunctionCode: |
async function handler(event) {
var request = event.request;
var uri = request.uri;
// Check whether the URI is missing a file name.
if (uri.endsWith('/')) {
request.uri += 'index.html';
}
// Check whether the URI is missing a file extension.
else if (!uri.includes('.')) {
request.uri += '/index.html';
}
return request;
}例えば上記だと以下のようにCloudFrontAddIndexFunctionで作るCloudFront Fuctionの値に依存しています。
そのため先にCloudFrontAddIndexFunctionを作成して、その後CloudFrontDistributionの作成に進むって感じらしい。
FunctionARN: !If
- CreateCloudFrontFunction
- !GetAtt CloudFrontAddIndexFunction.FunctionMetadata.FunctionARN
- !Sub arn:aws:cloudfront::${AWS::AccountId}:function/${CloudFrontFunctionName}Createならこれから作るCloudFrontFunctionの名前。ReuseならすでにあるCloudFrontFunctionの名前」と書きました。CloudFront Functionの名前だけは起動前のパラメーターの時点でわかっているので、ARNを文字列補間で作ることが出来るって、わかりますか?FunctionARN: !Sub arn:aws:cloudfront::${AWS::AccountId}:function/${CloudFrontFunctionName}ただこれだと既にある場合でしか動きません。
明示的に依存しているんだよ~感を出しておくと、先に依存しているリソースを作る判断ができますが、これだとただパラメーターの値を入れているだけになるので。
上記の例で試すと、CloudFront ディストリビューションを作るのにCloudFront Functionの完成を待たない、多分ですが完成よりも前にディストリビューションを作ってしまうので失敗してしまいます。
先述の通りCloudFormationは極力並列でリソースを作るため、先にCloudFront Functionを作ってくれれば動くかもですが、順番を守ってくれることのほうが少ないでしょう。
なので!DependsOnという機能があります!!いい感じに依存してるんだな~って感づいてくれないときに使えそう。今回は気が利いてくれたので問題なかった!
作ったリソースや、パラメーターの値を出力して、スタックの詳細画面から見ることが出来る機能があります。
多分成功してないと何も表示されないと思います。(ROLLBACK_COMPLETEを見たけど何も出力されてなかった)
Outputs:
WebSiteBucket:
Description: S3
Value: !Ref WebSiteBucket
CloudFrontDistribution:
Description: CloudFront
Value: !Ref CloudFrontDistribution
OriginAccessControl:
Description: CloudFront OAC
Value: !Ref OriginAccessControl
CloudFrontAddIndexFunction:
Condition: CreateCloudFrontFunction
Description: CloudFront Functions
Value: !Ref CloudFrontAddIndexFunctionWebSiteBucketやCloudFrontDistributionがキーになり、Valueが値のところに出る
そういえば、カスタムドメインは自動でやってくれないので、CloudFormation実行中の隙に作ってください。(別にいつでも良いですが)
私がRoute53を使っていないせいだと思います・・・
使えればCloudFormationで生成できたらしい。Route53は.devのTLDがそもそも使えない。なのでありがとうクラウドフレア (英語にすると空目しそうで)
数日くらいかかったので怒ってます
CloudFormationで実行したけど失敗してスタックのリソースを消そうとして消せなかったエラー
もう一回削除ボタン?を押すと強制的に削除できます?
このスタックの削除を再試行しますか?
このスタックを削除すると、すべてのスタックリソースが削除されます。リソースは 削除ポリシー に従って削除されます。
このスタックを削除するが、リソースを保持次のリソースの削除に失敗したため、このスタックは以前削除に失敗しています。リソースを保持することを選択した場合、それらのリソースはこの削除オペレーション中にスキップされます。
このスタック全体を強制削除このスタックを強制削除すると、削除プロセス中に削除できなかったリソースが残る可能性があります。ただし、スタック自体は正常に削除されます。雰囲気で英語を使う
CloudFrontのOriginAccessControlの名前が長過ぎる
CloudFront ディストリビューションを作るときに、S3OriginConfigとその中にOriginAccessIdentityを指定する必要あり。OriginAccessIdentityは空文字でいいから必要
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- Id: !GetAtt WebSiteBucket.RegionalDomainName # マネジメントコンソールで作ると DomainName と同じ文字列になってそう
DomainName: !GetAtt WebSiteBucket.RegionalDomainName # リージョンが入ってないとアクセスできなかった
OriginAccessControlId: !GetAtt OriginAccessControl.Id
S3OriginConfig:
OriginAccessIdentity: '' # ここに空文字が必要わからない。
CachePolicyId: !Sub CachePolicyCreatedOrManagedを、とりあえず成功させるために直接指定するようにした。!Refじゃないと成功しないのか?
CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6S3の設定で、Amazon S3 マネージドキーを使用したサーバー側の暗号化 (SSE-S3)を使うようにする必要がありそう?適当にコピペした仇が
WebSiteBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref BucketName
BucketEncryption:
ServerSideEncryptionConfiguration:
- BucketKeyEnabled: true
ServerSideEncryptionByDefault:
SSEAlgorithm: AES256 # これ普通にyamlの書き方間違ってた
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
- BucketKeyEnabled: true↑間違い↓正解
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
BucketKeyEnabled: trueARNの値間違えてる?
CloudFront Functionの作成でAutoPublish: trueをつけ忘れていた?
CloudFrontAddIndexFunction:
Type: AWS::CloudFront::Function
Condition: CreateCloudFrontFunction
Properties:
Name: !Ref CloudFrontFunctionName
AutoPublish: true # これ
# 以下省略...503 ERROR
The request could not be satisfied.
The CloudFront function associated with the CloudFront distribution is invalid or could not run. We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
Generated by cloudfront (CloudFront)
Request ID: ....CloudFront Functionのサンプルコードでasync/awaitを使っているが、私はそれに気付かずJavaScript ランタイム 1.0を選んでしまった。
このコードはランタイム2.0限定だった。
CloudFrontAddIndexFunction:
Type: AWS::CloudFront::Function
Condition: CreateCloudFrontFunction
Properties:
Name: !Ref CloudFrontFunctionName
AutoPublish: true
FunctionConfig:
Comment: add index.html to url suffix
Runtime: cloudfront-js-2.0 # これ
# 以下省略S3のOriginsのIDとDomainNameが微妙に間違えているらしい。!GetAtt WebSiteBucket.DomainNameは間違いで、!GetAtt WebSiteBucket.RegionalDomainNameじゃないとダメっぽい
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- Id: !GetAtt WebSiteBucket.RegionalDomainName # マネジメントコンソールで作ると DomainName と同じ文字列になってそう
DomainName: !GetAtt WebSiteBucket.RegionalDomainName # リージョンが入ってないとアクセスできなかった違いはこうで、リージョンの有無?
!GetAtt WebSiteBucket.DomainName{バケット名}.s3.amazonaws.com!GetAtt WebSiteBucket.RegionalDomainName{バケット名}.s3.{リージョン}.amazonaws.comというのも、マネジメントコンソールでマウスぽちぽちして作ったディストリビューションを見たんですが、どうもリージョンがある方が期待値っぽいんですよね。
これで見れるようになった!!!
数日かかった理由、↑に書いたCloudFrontのS3OriginのDomainNameのせいだと思ってる。!GetAtt WebSiteBucket.DomainNameではダメで、RegionalDomainNameを使わないといけなかった。これに気付かなかった。
なんか検索してもDomainNameの方ばっかりでRegionalDomainNameなんて使って無い。じゃあなんでそっちがなんで動いているのかは不明です。
謎。
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- Id: !GetAtt WebSiteBucket.RegionalDomainName # マネジメントコンソールで作ると DomainName と同じ文字列になってそう
DomainName: !GetAtt WebSiteBucket.RegionalDomainName # リージョンが入ってないとアクセスできなかった
OriginAccessControlId: !GetAtt OriginAccessControl.Id
S3OriginConfig:
OriginAccessIdentity: ''
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
TargetOriginId: !GetAtt WebSiteBucket.RegionalDomainName # Origins Id に合わせる
ViewerProtocolPolicy: allow-all
FunctionAssociations:
# CloudFront Functions を作成する場合は、CloudFrontAddIndexFunction に依存するように書いておく。これで CloudFormation は先に Function を作る順番になるはず
- EventType: viewer-request
FunctionARN: !If
- CreateCloudFrontFunction
- !GetAtt CloudFrontAddIndexFunction.FunctionMetadata.FunctionARN
- !Sub arn:aws:cloudfront::${AWS::AccountId}:function/${CloudFrontFunctionName}
CachePolicyId: !Ref CachePolicyCreatedOrManaged
Compress: true
HttpVersion: http2
Enabled: true
Comment: !Ref CloudFrontComment「静的(漢字変換に成功!!!)サイトなのにAWS使ってるからこんな難しいんだろ」というコメントがありました。
いやーほn・・そうですね、そのとおりだと
じゃあなんでなんだよって話ですが、どっかで書いたような気もしなくないですがもう一回書いておくと、
お一人様MisskeyがAmazon Lightsailで動いているので、もうバックエンドが必要になったらそっちに寄せていこうってことです。
バックエンドとかインフラはさっぱりなんで、やたらめったら増やすのはあれだしもうAWSに寄せていこうと思った。
ちなみに国産 VPSと違ってパット見Lightsailが安く見えるのですが、円安のせいでそんなことないと思います。
Amplifyが進化しているそうなのでそっち選んでも良いかもしれませんね?
わたしとしてはCloudFormation書いたのでしばらく困らないと思う。
AWSで障害があったらしいですが、基本的にはap-northeast-1(東京リージョン)を使っているので、特にこのサイトが見れなかった・・・事態にはなって無い、はずです。
ご利用料金の画面がずっとエラーを返してた。くらい。