こんにちは,ぽち@pchwです. 先週作った 国税庁URL変換器 がちょっとバズって,「どうやって作ってるの?」みたいな疑問が寄せられたので,サラッと解説したいと思います.
今年に入って,
などを作ってきてからの,国税庁URL変換器 のバズでした.
基本的に,ベースとなる構成は全部同じです.認証周りが必要な時にAmazon Cognitoを追加で使ったり,処理が複雑になる場合はUI側の構築時にredux-sagaを入れたりしてる感じです.
国税庁URL変換器 は上記に上げた中でもかなりシンプルな造りをしている方ですね.
ベースとなる構成
まず,クライアント側で行う処理とサーバ側で行う処理を分けています. 重ためな処理とかDBとのやり取りとか(今回はありませんが)認証などはサーバ側で行います. 入力を受け取ったり,データを表示したり,簡単な通信で完結するものはクライアント側で行います.
クライアント側に必要なjsファイルやhtmlファイルは全てAmazon S3に置いています. HTTPSで配信するために,Amazon CloudFrontとAWS Certificate Managerを利用しています.
UIライブラリは,Reactを使っています. 見た目は,React + Foundation経由でFoundation for Sitesを使っています. あと,別に無くてもいいのですが,タイポグラフィをいい感じにするために,ShevyJS を使っています.
サーバ側は,AWS Lambdaです. クライアント側から叩くために,HTTPのエンドポイントを公開する必要があるので,Amazon API Gatewayを使っています.こちらにもAmazon ClowdFrontを立てています.
ドメインの取得は Amazon Route 53 を使っています.
AWSの色んなサービスを使うので,Serverless Framework を使って一気に構築してしまいます.
クライアント側のファイルを一気にAmazon S3にアップロードするのも,Serverless Frameworkのpluginの serverless-finch を使って上げてしまいます.
サーバ側のHTTPエンドポイントの部分はapi.ドメイン名
のようなサブドメインを切ってやってるのですが,そのあたりもserverless-domain-manager というpluginを使ってやっています.
データベースが必要になった際はMongoDB Atlas を使っています. 自分がMongoDBばっかり使っていて,SQLが書けない身体になってしまったので,大体MongoDBです.
構成図にするとこんな感じです.
構築の流れ
- Route 53でドメインを取る(使えるようになるまで時間がかかる)
- .com なら$12かかる
$ serverless create --template aws-nodejs
- API Gatewayのテンプレートを使うともっと早いかもしれないけど,大体
aws-nodejs
を使っている
- API Gatewayのテンプレートを使うともっと早いかもしれないけど,大体
$ create-react-app client
でクライアント側を作る$ npm init -y
して,$ npm install
でlambdaで使うモジュールを入れる- serverless-finch
- serverless-domain-manager
- serverless-offline
- debug
- mongoose
$ cd client && npm init -y
して,$ npm install
でクライアント側で使うモジュールを入れる- axios
- foundation-sites
- foundation-icons
- react-foundation
- shevyjs
- react-loading-skeleton
- react-router(1枚ペラのページなら不要)
client/src
以下を色々いじってアプリケーションを構築- サーバの処理が不要ならこれだけで完成する
- 確認が必要であれば,
$ npm start
で確認ができる
serverless.yml
を変更して,HTTPエンドポイントの設定とhandler.js
を変更して処理を書く.- 確認が必要であれば,都度
$ serverless offline
でローカル実行して確認したりする
- 確認が必要であれば,都度
$ serverless deploy
でS3 bucketの用意からAPI Gatewayの設定やlambdaの構築までやってくれる- 必要であれば,
--aws-profile
のオプションで適切なAWSアカウントを選択すること(一つしか無いなら不要)
- 必要であれば,
$ cd client && npm run build
でクライアントのソースを本番用にビルドして,$ cd .. && serverless client deploy
でserverless-finch
を使ってクライアント側のファイルをS3に載せることができる$ serverless create domain
でAPI用のサブドメイン設定を行う- たまに成功してるのに実は失敗してることがある
- ドメイン名で接続してうまく繋がらない場合は
$ serverless remove domain
して再度行う(今回はここでハマった)
serverless.ymlの編集
基本はServerless Framework公式のドキュメントやCloudFormationのドキュメントが参考になります.
プラグインの設定
plugins
セクションを追加して,使うプラグインを指定します.
plugins: - serverless-offline - serverless-finch - serverless-domain-manager
それぞれのプラグインの設定は,custom
セクションで行います.
custom: bucket: nta-go.com client: bucketName: ${self:custom.bucket} distributionFolder: client/build indexDocument: index.html errorDocument: index.html serverless-offline: port: 4000 customDomain: domainName: api.nta-go.com basePath: '' stage: ${self:provider.stage} certificateName: nta-go.com createRoute53Record: true
他のプラグインを使う場合は,それぞれのREADME.mdを確認して設定してください.
HTTPエンドポイントの設定
Lambdaの設定とHTTPエンドポイントの設定を一気に行えます.
functions
セクションに
functions: search: handler: handler.search timeout: 15 events: - http: path: /search method: get cors: true
のように書けば,handler.js
でmodule.exports
しているsearch
という関数が/search
というパスでHTTP GETされた時に呼び出される形になります.
timeout
のプロパティは必要に応じて設定します.
デフォルトは7secなので,外部サービスと連携するなど時間がかかる場合は少し伸ばしてあげないと,タイムアウトします.
S3 bucketやCloudFrontの設定など
S3 bucketなどの設定はresouces
セクションを追加して行います.
resources: Resources: NewResource: Type: AWS::S3::Bucket Properties: BucketName: ${self:custom.bucket} AccessControl: PublicRead WebsiteConfiguration: IndexDocument: index.html ErrorDocument: index.html WebAppCloudFrontDistribution: Type: AWS::CloudFront::Distribution Properties: DistributionConfig: Origins: - DomainName: ${self:custom.bucket}.s3.amazonaws.com (長いので以下略)
のように行います.
NewResource
(名前はなんでもいいです)のところでは,S3のbucketを作成し,アクセス権の設定や静的サイト配信の設定を行っています.
WebAppCloudFrontDistribution
(名前はなんでもいいです)のところでは,CloudFrontの設定を行っています.(しかし,Originの設定がAWS Consoleからプルダウンで行うものと異なるので,設定後にAWS Consoleから再設定します・・・何故・・・)
その他
serverless.yml
は色々な設定が出来るので,詳しく設定したい場合は,ドキュメントを確認することをオススメします.
MongoDB Atlasの設定
アプリケーションに少しDBが必要だったので,設定した. 自分がMongoDBばっかり使っていて,SQLを書けない体なのでMongoDB Atlas.
SQLが好きな人はAWSのサービスなどを,BigQueryが好きな人はGoogleを使えば良いと思う.
AWS Consoleでの設定
- S3で配信するのをHTTPSにするため,AWS Certification Managerで証明書を発行
- Route53連携で確認ができる方法があるのでそれを選ぶ
- Step 1: Add domain names
ドメイン名
を追加して,Add another name to this certificateで*.ドメイン名
を指定すると良い(api.ドメイン名
もHTTPSにするため)
- Step 2: Select validation method
- DNS validationを選択する(これで,Route 53を使ってvalidationすることが出来る)
- 次のStepで Create record in Route 53のボタンを押すと自動的にRoute 53でレコードが追加される
- Cloud Frontの設定をする
- Originの設定
- Origin Domain Nameをプルダウンから
ドメイン名.s3.amazonaws.com
を選択する(Serverless frameworkのresourcesセクションで指定してるのにうまく出来てない謎)
- Origin Domain Nameをプルダウンから
- 作成した証明書を指定
- Generalの設定で,SSL CertificateでCustom SSL Certificateを選んでプルダウンからドメイン名のを選ぶ
- Cacheの時間を変更(自分は1000msにしてる)
- BehaviorのObject CachingでCustomizeを選択して,Minimum/Maximum/Default TTLを1000にする
- Originの設定
- Route53の設定をする
api.ドメイン名.
の設定をする(この時に選択肢にCloud Frontのものがプルダウンで出てくるので選択する)- Type: AでAlias: Yesを選択して,Alias Target: をクリックして
cloudfront.net
のものを選ぶ
- Type: AでAlias: Yesを選択して,Alias Target: をクリックして
ドメイン名.
(ベアドメイン.こちらもCloud Frontのものがプルダウンで出てくるので選択する)- Type: AでAlias: Yesを選択して,Alias Target: をクリックして
cloudfront.net
のものを選ぶ
- Type: AでAlias: Yesを選択して,Alias Target: をクリックして
問い合わせ窓口・寄付先の設置
- Twitter 国税庁URL変換器(@nta_go)さん | Twitter
- サービス用に新規でアカウントを作る
- DMを開放
- アップデート情報や簡単にリプやDMに対して返信ができる
- 取材依頼や買収の依頼などDMも来るかもしれない
- お題箱( お題箱 | ツイッターアカウントで作れるリクエストボックス )
- 匿名での意見を募れる.
- Twitterアカウントに紐づく.5秒で設置出来る.
- Amazon Wishlist Amazon.co.jp
- 投げ銭のように使える
- Amazonギフト券を入れておくと楽
- ちゃんと数量を指定しておかないと1枚だけになって枯渇するので注意(今回ミスって枯渇した)
- 普通に自分の好きなものを入れていてもいい
- 他のサービスより気軽に使える
素早く作るために
- Serverless Frameworkを使って,一気に環境を整えてしまう
create-react-app
でサッとクライアント側を整える- 見た目は
React Foundation
で提供されるパーツでなんとかする - 問い合わせはTwitterのアカウントとお題箱で設置
- 投げ銭先はAmazon Wishlistを貼るだけ
という感じにして,世の中に公開してフィードバックを得るための仕組みは手間をかけない形で構築して,メインのルーチンを考える・組み上げる時間を多く確保することに重きを置いています.
金額は,ドメイン登録で$12はかかってしまいますが,それ以外の部分はそれほどかかりません. 今回であれば,現時点でCloudFrontが$3・その他$1程度です.
そして,「これだけあれば,とりあえず使ってもらえる!」という状態で公開して反応を見て随時改善を入れていきます.
というのも,誰にも刺さらないサービスを作り込んで公開して全然使われないと,「めっちゃ頑張ったのに誰も使ってくれない・・・自分は世の中で必要とされていないんだ・・・オワタ・・・」みたいになったりするのを予防していたりします.
なお,「公開したサービスが誰にも使ってもらえない」ということと「自分が世の中で必要とされるかどうか」は全く別の事象なので,気にしないことをオススメします.
またなんか作りますね.