アリババクラウドで作ったサービスを公開して1ヶ月でかかった料金

みなさん気になるお金の話です。

私は今サーバレス+RDSでサービスを公開しています。このサービスが1ヶ月で消費した値段を公開します。

結論

サービスを公開して1ヶ月で4000円分程利用しました。

作ったサービスの構成

ざっくりと、こんな感じです。

f:id:asmsuechan:20181029115611p:plain

作ったサービスの規模

SNSなのですが人がいません。

(そもそも集客していません。まだプロモーションうまく考えていないためスマホアプリリリースした後誰にも知らせないまま放置しちゃってます)

集計の期間

集計の期間は9月1日から9月30日までです。

開発開始: 9月1日
リリース: 9月21日

サーバレスな環境にしたので開発でもほとんどお金はかからないと思い最初からクラウドで動かしていました。

内訳など

まず、料金・支払い管理の利用状況です。

公開したサービスで使用しているリソースとドキュメントに書いてある値段を以下の表に示します。

サービス名 ドキュメントの値段(円) 実際の値段 備考
Function Compute 0 0.024 100万リクエスト/月まで無料
API Gateway 0 0.196 100万リクエスト/月まで無料
ApsaraDB for RDS 3600 3604.930 rds.mysql.t1.smallを利用
Alibaba Cloud DNS 0 0
OSS 0 0.074 5GBまで無料
Log Service 0 296.796 ログファイル500万
合計 3700 3902.02

Log Serviceが想像以上に使ってましたね。まあ許容範囲内です。

ちなみにFunction Computeの微妙な課金は開発環境と本番環境のInternetOutで生じたものです。

まとめ

日本のアリババクラウドは今ミートアップなども含めて無料で使えるクーポンを配布してくれています。このクーポンのおかげで今のところほとんどお金を払わずに済んでいます。

クーポンが気になる方はアリババクラウドのミートアップに顔を出してみましょう!(本記事はクーポンをいただけることを保証するものではありません)

alibabacloud.connpass.com

.apkファイルに署名できない問題

.apkファイルの中の署名鍵を消しましょう。

$ jarsigner -verbose -keystore app/myapp.keystore app/build/outputs/apk/app-release.apk myapp
Enter Passphrase for keystore:
jarsigner: unable to sign jar: java.util.zip.ZipException: invalid entry compressed size (expected 20224 but got 20510 bytes)
$ zip -d app/build/outputs/apk/app-release.apk META-INF/\*
deleting: META-INF/CERT.RSA
deleting: META-INF/CERT.SF
deleting: META-INF/MANIFEST.MF

参考

stackoverflow.com

Alibaba CloudのFunction Computeに環境変数を設定する方法

Function Computeに環境変数を設定するためにはtemplate.ymlにEnvironmentVariablesセクションを追加します。

例えば、NODE_ENV=productionを追加したいときはtemplate.ymlに以下を追加します。

EnvironmentVariables:
  NODE_ENV: production

以下はtemplate.ymlの全文です。

# template.yml
ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
  MyServicei: # service name
    Type: 'Aliyun::Serverless::Service'
    Properties:
      Description: 'fc for auto testing'
    graphql: # function name
      Type: 'Aliyun::Serverless::Function'
      Properties:
        Handler: index.handler
        Runtime: nodejs8
        CodeUri: './'
        Timeout: 60
        EnvironmentVariables:
          NODE_ENV: production

  MyFunctionGroup: # group name
    Type: 'Aliyun::Serverless::Api'
    Properties:
      StageName: RELEASE
      DefinitionBody:
        '/':
          post:
            x-aliyun-apigateway-api-name: myapi
            x-aliyun-apigateway-request-config:
              requestProtocol: 'https'
            x-aliyun-apigateway-fc:
              arn: acs:fc:::services/${MyService.Arn}/functions/${graphql.Arn}/

公式のサンプル(github.com/aliyun/fun)が参考になります。

HTTPSに対応したAlibaba CloudのAPI GatewayがAndroidでNetwork request failedする問題

API GatewayHTTPS化したらreact-nativeのAndroidアプリからfetchできなくなってしまいました。

HTTPへのリクエストは成功するのですがHTTPSへのリクエストを送ると以下のエラーが出てしまいます。

TypeError: Network request failed
    at XMLHttpRequest.xhr.onerror (blob:http://localhost:8081/2cf03b53-c0b2-404c-8dda-906f61a7d7ee:27276:18)
    at XMLHttpRequest.dispatchEvent (blob:http://localhost:8081/2cf03b53-c0b2-404c-8dda-906f61a7d7ee:29368:27)
    at XMLHttpRequest.setReadyState (blob:http://localhost:8081/2cf03b53-c0b2-404c-8dda-906f61a7d7ee:29121:20)
    at XMLHttpRequest.__didCompleteResponse (blob:http://localhost:8081/2cf03b53-c0b2-404c-8dda-906f61a7d7ee:28948:16)
    at blob:http://localhost:8081/2cf03b53-c0b2-404c-8dda-906f61a7d7ee:29058:47
    at RCTDeviceEventEmitter.emit (blob:http://localhost:8081/2cf03b53-c0b2-404c-8dda-906f61a7d7ee:3707:37)
    at MessageQueue.__callFunction (blob:http://localhost:8081/2cf03b53-c0b2-404c-8dda-906f61a7d7ee:2593:44)
    at blob:http://localhost:8081/2cf03b53-c0b2-404c-8dda-906f61a7d7ee:2370:17
    at MessageQueue.__guard (blob:http://localhost:8081/2cf03b53-c0b2-404c-8dda-906f61a7d7ee:2546:13)
    at MessageQueue.callFunctionReturnFlushedQueue (blob:http://localhost:8081/2cf03b53-c0b2-404c-8dda-906f61a7d7ee:2369:14)

ドキュメントやissueやらを読み漁って悩んでいると、以下のコメントを見つけました。どうやら証明書が間違っている時にもこのエラーが出るそうです。

github.com

解決法

中間CA証明書とクロスルート証明書を追加したら解決しました。

さくらのRapidSSLだとこの2つの証明書はここにあって、それぞれコピペします。

そしてAPI GatewaySSL証明書を追加するテキストエリアに以下のように証明書を3つまとめて入力します。

-----BEGIN CERTIFICATE-----
SSL証明書
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
中間CA証明証
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
クロスルート証明書
-----END CERTIFICATE-----

これで私は通信できるようになりました。

参考

qiita.com

Alibaba CloudのAPI GatewayをHTTPS化する

独自ドメインを設定したAPI GatewayのエンドポイントをHTTPS対応させます。なお、Function Computeをバックグラウンドで動かしています。

基本は以下の公式ドキュメントを参考にしました。

jp.alibabacloud.com

SSL証明書の取得

私はさくらのRapidSSLで取得しました。SSL証明書買ったの久々です。

CSR作成なんかは完全に忘れていましたので以下を参考にしました。

qiita.com

サーバー認証

API Gatewayでちょっと苦労するのがサーバー認証キーのアップロードです。

普通のサーバーのようにファイルをアップロードすることはできないので、API Gatewayのエンドポイントを/.well-known/pki-validation/fileauth.txtと設定してGETで認証キーを返すようにします。

webコンソール画面からだとAPI Gatewayのエンドポイントに/.well-known/pki-validation/fileauth.txtを設定することができなかった(多分ドットがバリデーションエラーになる)ので、template.ymlを使ってデプロイします。

ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
  MyService: # service name
    Type: 'Aliyun::Serverless::Service'
    Properties:
      Description: 'my fc'
    myfunction: # function name
      Type: 'Aliyun::Serverless::Function'
      Properties:
        Handler: index.handler
        Runtime: nodejs8
        CodeUri: './'
        Timeout: 60

  MyFunctionGroup: # group name
    Type: 'Aliyun::Serverless::Api'
    Properties:
      StageName: RELEASE
      DefinitionBody:
        '/.well-known/pki-validation/fileauth.txt':
          get:
            x-aliyun-apigateway-api-name: myfunction
            x-aliyun-apigateway-fc:
              arn: acs:fc:::services/${MyService.Arn}/functions/${myfunction.Arn}/

index.jsはこちらです。

module.exports.handler = (event, context, callback) => {
  callback(null, { statusCode: 200, body: 'YOUR KEY IN fileauth.txt' });
};

API GatewayのFunction GroupにSSL証明書を追加する

画面をポチポチしてSSL証明書を追加します。

Function GroupからSSL証明書を追加します。 f:id:asmsuechan:20180912160130p:plain

秘密鍵はパスワードを削除する必要があります。 f:id:asmsuechan:20180912161000p:plain

HTTPSで通信できるようにする

次にAPI GatewayHTTPSを受け取るように変更します。template.ymlで設定を定義している人は画面からでは変更できません。template.ymlを変更しましょう。

template.ymlに以下を追加します。

            x-aliyun-apigateway-request-config:
              requestProtocol: 'https'

以下はtemplate.ymlの全体です。

ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
  MyService: # service name
    Type: 'Aliyun::Serverless::Service'
    Properties:
      Description: 'my fc'
    myfunction: # function name
      Type: 'Aliyun::Serverless::Function'
      Properties:
        Handler: index.handler
        Runtime: nodejs8
        CodeUri: './'
        Timeout: 60

  MyFunctionGroup: # group name
    Type: 'Aliyun::Serverless::Api'
    Properties:
      StageName: RELEASE
      DefinitionBody:
        '/':
          get:
            x-aliyun-apigateway-api-name: myfunction
            x-aliyun-apigateway-request-config:
              requestProtocol: 'https'
            x-aliyun-apigateway-fc:
              arn: acs:fc:::services/${MyService.Arn}/functions/${myfunction.Arn}/

これをfun deployしたらHTTPS対応が完了します。

Tips

curlを送った時のレスポンスのserverがTengineならFunction Computeまでリクエストが渡っていて、nginxならAPI Gatewayがレスポンスを返しています。

Alibaba CloudのAPI Gatewayに独自ドメインを紐付ける

API Gatewayはデフォルトの状態で使うと1日に1000回のリクエスト制限があります。これを回避するにはFunction Groupに独自ドメインを設定しなければなりません。

ここではAPI Gateway独自ドメインを設定する方法について書きます。

asmsuechan.hatenablog.com

Alibaba Cloud DNSの設定

まず、どこかでドメインを取得します。私はお名前.comを使いました。

取得が完了したらドメイン名を追加よりドメインを追加します。 f:id:asmsuechan:20180908211541p:plain

無効なDNSサーバーと表示されるので、お名前.comにから対象のドメイン名のDNSサーバーをns7.alidns.com, ns8.alidns.comに変更します。お名前.comではネームサーバーの設定より変更することができます。

追加したらDNSサーバー:ns7.alidns.com, ns8.alidns.comと表示されます。

f:id:asmsuechan:20180908211722p:plain

次にレコードを追加をします。

f:id:asmsuechan:20180909162243p:plain

ホストにサブドメイン名、値にデフォルトで設定されるAPI Gatewayのエンドポイントを入力します。

Alibaba Cloud API Gatewayの設定

ドメイン名のバインドよりドメイン名をAPI GatewayのFunction Groupに紐付けます。

f:id:asmsuechan:20180909174248p:plain

これで完了です。

Alibaba Cloud API Gatewayのアクセス制限に気をつけよう

最終的にはドキュメントちゃんと読めって話ですが、Alibaba CloudのAPI Gatewayを使っているときに403で悩まされました。

以下のリクエストを送った時、API Gateway + Function ComputeのAPIから突然403が返ってくるようになりました。

$ curl -i -H "Content-Type: application/json" -H 'Authorization: Bearer MY_JWT' -X POST -d '
{ "query": "query getPosts { posts(limit: 100) { id url body user_id created_at updated_at } }"}
' http://xxxxxxxxxxxxxxxxxxxxxxxxxx-ap-northeast-1.alicloudapi.com/
HTTP/1.1 403 Forbidden
Server: Tengine
Date: Sat, 08 Sep 2018 11:36:14 GMT
Content-Type: text/plain;charset=UTF-8
Content-Length: 0
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,POST,PUT,DELETE,HEAD,OPTIONS,PATCH
Access-Control-Allow-Headers: X-Requested-With,X-Sequence,X-Ca-Key,X-Ca-Secret,X-Ca-Version,X-Ca-Timestamp,X-Ca-Nonce,X-Ca-API-Key,X-Ca-Stage,X-Ca-Client-DeviceId,X-Ca-Client-AppId,X-Ca-Signature,X-Ca-Signature-Headers,X-Ca-Signature-Method,X-Forwarded-For,X-Ca-Date,X-Ca-Request-Mode,Authorization,Content-Type,Accept,Accept-Ranges,Cache-Control,Range,Content-MD5
Access-Control-Max-Age: 172800
X-Ca-Request-Id: EE2517BA-5775-46AB-8339-B96AF926367F
X-Ca-Error-Message: Throttled by DOMAIN Flow Control

こう言う時はX-Ca-Error-Messageを見てみましょう。Throttled by DOMAIN Flow Controlと書いてあります。

以下のリンクによると、

The second-level domain name used for API calls can be accessed up to 1,000 times each day.Each group has limited 500 QPSs.

だそうで、API GatewayはデフォルトのURLだと1日に1000回しかアクセスできないみたいです。

www.alibabacloud.com

これを解決するには独自ドメインを紐づけるのが手っ取り早いです。

独自ドメインの使用方法は近日書きます。