ぽっちぽちにしてやんよ

技術ネタとかアプリに関する話とか

国税庁URL変換器にみる素早くウェブサービスを提供する方法

こんにちは,ぽち@pchwです. 先週作った 国税庁URL変換器 がちょっとバズって,「どうやって作ってるの?」みたいな疑問が寄せられたので,サラッと解説したいと思います.

今年に入って,

などを作ってきてからの,国税庁URL変換器 のバズでした.

基本的に,ベースとなる構成は全部同じです.認証周りが必要な時にAmazon Cognitoを追加で使ったり,処理が複雑になる場合はUI側の構築時にredux-sagaを入れたりしてる感じです.

国税庁URL変換器 は上記に上げた中でもかなりシンプルな造りをしている方ですね.

ベースとなる構成

まず,クライアント側で行う処理とサーバ側で行う処理を分けています. 重ためな処理とかDBとのやり取りとか(今回はありませんが)認証などはサーバ側で行います. 入力を受け取ったり,データを表示したり,簡単な通信で完結するものはクライアント側で行います.

クライアント側に必要なjsファイルやhtmlファイルは全てAmazon S3に置いています. HTTPSで配信するために,Amazon CloudFrontAWS 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です.

構成図にするとこんな感じです.

f:id:poChi:20180409131156p:plain

構築の流れ

  • Route 53でドメインを取る(使えるようになるまで時間がかかる)
    • .com なら$12かかる
  • $ serverless create --template aws-nodejs
    • API Gatewayのテンプレートを使うともっと早いかもしれないけど,大体aws-nodejsを使っている
  • $ 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 deployserverless-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.jsmodule.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 は色々な設定が出来るので,詳しく設定したい場合は,ドキュメントを確認することをオススメします.

serverless.com

MongoDB Atlasの設定

アプリケーションに少しDBが必要だったので,設定した. 自分がMongoDBばっかり使っていて,SQLを書けない体なのでMongoDB Atlas.

www.mongodb.com

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セクションで指定してるのにうまく出来てない謎)
    • 作成した証明書を指定
      • Generalの設定で,SSL CertificateでCustom SSL Certificateを選んでプルダウンからドメイン名のを選ぶ
    • Cacheの時間を変更(自分は1000msにしてる)
      • BehaviorのObject CachingでCustomizeを選択して,Minimum/Maximum/Default TTLを1000にする
  • Route53の設定をする
    • api.ドメイン名. の設定をする(この時に選択肢にCloud Frontのものがプルダウンで出てくるので選択する)
      • Type: AでAlias: Yesを選択して,Alias Target: をクリックしてcloudfront.netのものを選ぶ
    • ドメイン名.(ベアドメイン.こちらもCloud Frontのものがプルダウンで出てくるので選択する)
      • Type: AでAlias: Yesを選択して,Alias Target: をクリックしてcloudfront.netのものを選ぶ

問い合わせ窓口・寄付先の設置

  • 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程度です.

そして,「これだけあれば,とりあえず使ってもらえる!」という状態で公開して反応を見て随時改善を入れていきます.

というのも,誰にも刺さらないサービスを作り込んで公開して全然使われないと,「めっちゃ頑張ったのに誰も使ってくれない・・・自分は世の中で必要とされていないんだ・・・オワタ・・・」みたいになったりするのを予防していたりします.

なお,「公開したサービスが誰にも使ってもらえない」ということと「自分が世の中で必要とされるかどうか」は全く別の事象なので,気にしないことをオススメします.

またなんか作りますね.