michimani.net

AWS Chalice で API Gateway のカスタムドメイン名作成がサポートされたので試してみた

2020-07-22

AWS Chalice で API Gateway のカスタムドメイン名の作成がサポートされたので、実際に試してみたいと思います。

目次

概要

Python でサーバレスアプリケーションを作成するためのマイクロフレームワークである AWS Chalice ですが、今回バージョン 1.16.0 にて API Gateway のカスタムドメイン名作成がサポートされました。今まではカスタムドメイン名の作成は手動で実施する必要があったのですが、今回はそれが Chalice の機能として実装されたことになります。

既に AWS ブログにも実際の手順について記載されているので、今回はそれを元にして実際に試してみたいと思います。

これまで

今回のアップデートがくるまでは、 Chalice で構築した API に対してカスタムドメインを当てる場合、マネジメントコンソールや CLI や CloudFormation などで自分で設定をする必要がありました。

過去に Chalice で todo を管理する簡単な API を作ったのですが、カスタムドメインを当てるために次のような手順を踏んでいました。

  1. chalice deploy を実行
  2. 作成された API Gateway に対してカスタムドメイン名を作成
  3. Route 53 で ALIAS レコード作成

2, 3 については CloudFormation テンプレートを作成して、シェルスクリプト経由でデプロイをするようにしていました。手作業ではなく CFn で構築できるようにしておくと楽といえば楽なのですが、できれば Chalice の機能としてカスタムドメイン名の作成ができれば良いなーとは思っていました。

やってみる

では、AWS ブログを元に実際にやってみます。その前に、 Chalice を最新版 1.16.0 にアップデートしておきます。

$ pip install chalice --upgrade
$ chalice --version
chalice 1.16.0, python 3.7.7, darwin 19.5.0

Chalice プロジェクトの作成

まずは Chalice プロジェクトの作成です。

$ chalice new-project custom-domain-app
$ cd custom-domain-app
$ tree -a -L 2
.
├── .chalice
│   └── config.json
├── .gitignore
├── app.py
└── requirements.txt

初期状態では、 / というエンドポイントで {'hello': 'world'} と返すような app.py になっています。

from chalice import Chalice

app = Chalice(app_name='custom-domain-app')


@app.route('/')
def index():
    return {'hello': 'world'}

chalice local コマンドでローカル実行できるので、試してみます。

$ chalice local
Serving on http://127.0.0.1:8000
Restarting local dev server.
Serving on http://127.0.0.1:8000

別のターミナルを開いてアクセスしてみます。

$ http http://127.0.0.1:8000/
HTTP/1.1 200 OK
Content-Length: 17
Content-Type: application/json
Date: Tue, 21 Jul 2020 21:18:13 GMT
Server: BaseHTTP/0.6 Python/3.7.7

{
    "hello": "world"
}

ちなみに、ここで使っている http コマンドは、 HTTPie というツールです。 cURL よりも直感的でわかりやすいコマンド、オプションが特徴です。

一旦デプロイしてみる

カスタムドメインを設定する前に、まずはデプロイしてみます。
AWS ブログではエンドポイントを Regional に変更してデプロイしていましたが、今回はデフォルトのまま Edge タイプでデプロイします。また、実行対象のリージョンは バージニア北部 (us-east-1) とします。

$ export AWS_DEFAULT_REGION=us-east-1
$ chalice deploy
Creating deployment package.
Creating IAM role: custom-domain-app-dev
Creating lambda function: custom-domain-app-dev
Creating Rest API
Resources deployed:
  - Lambda ARN: arn:aws:lambda:us-east-1:123456789012:function:custom-domain-app-dev
  - Rest API URL: https://1234567893.execute-api.us-east-1.amazonaws.com/api/

API Gateway のエンドポイントが出力されるので、確認してみます。

$ http https://1234567893.execute-api.us-east-1.amazonaws.com/api/
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 17
Content-Type: application/json
Date: Tue, 21 Jul 2020 21:43:26 GMT
Via: 1.1 60c021dff092d29bb692026a19f1de3b.cloudfront.net (CloudFront)
X-Amz-Cf-Id: jcQfmHIp5XfuvOAMg4RKJECU8pIsVMW9qOcuMFMnkq7uTW3bvPXi2Q==
X-Amz-Cf-Pop: NRT20-C4
X-Amzn-Trace-Id: Root=1-5f17617d-1e5da61a1164ffc4a7ef10d4;Sampled=0
X-Cache: Miss from cloudfront
x-amz-apigw-id: QCwrrEtVoAMFUSw=
x-amzn-RequestId: 8614edfa-4709-4e01-997d-21b703af194e

{
    "hello": "world"
}

Chalice のデプロイは他のフレーム枠と違って CloudFormation を使っていないので、めちゃくちゃ早いです。

Route 53 と ACM でドメインと SSL 証明書の設定

続いてカスタムドメインを設定していきますが、 Chalice プロジェクトでの設定の前に Route 53 でホストゾーン作成と、 ACM で SSL 証明書を発行します。

今回はエンドポイントのタイプを Edge にしているので、 SSL 証明書はバージニア北部 (us-east-1) で発行します。

手順については割愛しますが、今回は下記のドメイン、及び SSL 証明書を利用します。

ここでひとつ注意が必要なのは、 ワイルドカード証明書では chalice deploy 時にエラーになる という点です。

$ aws route53 list-hosted-zones \
--query "HostedZones[?Name==\`michimani.net.\`]"
[
    {
        "Id": "/hostedzone/Z3911234567890",
        "Name": "michimani.net.",
        "CallerReference": "E2XXXXXX-XXXX-XXXX-XXXX-123456789012",
        "Config": {
            "PrivateZone": false
        },
        "ResourceRecordSetCount": 28
    }
]
$ aws acm list-certificates \
--query "CertificateSummaryList[?DomainName==\`chalice-api.michimani.net\`]" \
--region us-east-1
[
    {
        "CertificateArn": "arn:aws:acm:us-east-1:123456789012:certificate/96123456-xxxx-xxxx-xxxx-f401234567890",
        "DomainName": "chalice-api.michimani.net"
    }
]

ホストゾーンの設定と SSL 証明書の発行が完了したら、それぞれ hosted zone ID (Z3911234567890) と CertificateArn (arn:aws:acm:us-east-1:123456789012:certificate/c3610514-3ef7-4478-9778-a5ab59ad168) をメモしておきます。

Chalice でカスタムドメインの設定

続いては Chalice プロジェクトでカスタムドメインの設定をします。

.chalice/config.json に対して次のような設定を追記します。

  {
    "version": "2.0",
    "app_name": "custom-domain-app",
    "stages": {
      "dev": {
+       "api_gateway_custom_domain": {
+         "domain_name": "chalice-api.michimani.net",
+         "certificate_arn": "arn:aws:acm:us-east-1:123456789012:certificate/96123456-xxxx-xxxx-xxxx-f401234567890"
+       },
        "api_gateway_stage": "api"
      }
    }
  }

デプロイしてみます。

$ chalice deploy
Creating deployment package.
Updating policy for IAM role: custom-domain-app-dev
Updating lambda function: custom-domain-app-dev
Updating rest API
Creating custom domain name: chalice-api.michimani.net
Creating api mapping: /
Resources deployed:
  - Lambda ARN: arn:aws:lambda:us-east-1:123456789012:function:custom-domain-app-dev
  - Rest API URL: https://1234567893.execute-api.us-east-1.amazonaws.com/api/
  - Custom domain name:
      HostedZoneId: Z2FDTNDATAQYW2
      AliasDomainName: 1234567890q58.cloudfront.net

これで API Gateway のカスタムドメイン名が作成されましたので、あとはこの出力にある HostedZoneIdAliasDomainName を使って Route 53 に ALIAS レコードを作成します。

ちなみに、 SSL 証明書としてワイルドカード証明書を指定した場合は、下記のようなエラーになりました。

$ chalice deploy
Creating deployment package.
Updating policy for IAM role: custom-domain-app-dev
Updating lambda function: custom-domain-app-dev
Updating rest API
Creating custom domain name: chalice-api.michimani.net
Traceback (most recent call last):
...
 An error occurred (BadRequestException) when calling the CreateDomainName 
 operation: The specified SSL certificate doesn't exist, isn't in us-east-1 
 region, isn't valid, or doesn't include a valid certificate chain. (Service: 
 AmazonCloudFront; Status Code: 400; Error Code: InvalidViewerCertificate; 
 Request ID: 65485f0b-7063-4eef-a4ce-2c45e56128cf)

Route 53 のレコード作成

レコードの作成には AWS CLI の route53 change-resource-record-sets コマンドを使います。

まずは --generate-cli-skeleton オプションで、パラメータのテンプレートを確認します。

$ aws route53 change-resource-record-sets --generate-cli-skeleton
{
    "HostedZoneId": "",
    "ChangeBatch": {
        "Comment": "",
        "Changes": [
            {
                "Action": "CREATE",
                "ResourceRecordSet": {
                    "Name": "",
                    "Type": "MX",
                    "SetIdentifier": "",
                    "Weight": 0,
                    "Region": "us-west-1",
                    "GeoLocation": {
                        "ContinentCode": "",
                        "CountryCode": "",
                        "SubdivisionCode": ""
                    },
                    "Failover": "SECONDARY",
                    "MultiValueAnswer": true,
                    "TTL": 0,
                    "ResourceRecords": [
                        {
                            "Value": ""
                        }
                    ],
                    "AliasTarget": {
                        "HostedZoneId": "",
                        "DNSName": "",
                        "EvaluateTargetHealth": true
                    },
                    "HealthCheckId": "",
                    "TrafficPolicyInstanceId": ""
                }
            }
        ]
    }
}

今回使うのは Changes の部分です。先程 取得したカスタムドメインの HostedZoneIdAliasDomainName を使って次のような JSON を作っておきます。

{
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "chalice-api.michimani.net",
        "Type": "A",
        "AliasTarget": {
          "DNSName": "1234567890q58.cloudfront.net",
          "HostedZoneId": "Z2FDTNDATAQYW2",
          "EvaluateTargetHealth": false
        }
      }
    }
  ]
}

ResourceRecordSet.AliasTarget.DNSNameAliasDomainNameResourceRecordSet.AliasTarget.HostedZoneIdHostedZoneId を、それぞれ指定します。

そして、 --change-batch オプションでこの JSON を指定して実行します。このとき --hosted-zone-id で指定するのは、 Route 53 に登録したドメインの hosted zone ID です。

$ aws route53 change-resource-record-sets \
--hosted-zone-id Z3911234567890 \
--change-batch \
'{
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "chalice-api.michimani.net",
        "Type": "A",
        "AliasTarget": {
          "DNSName": "1234567890q58.cloudfront.net",
          "HostedZoneId": "Z2FDTNDATAQYW2",
          "EvaluateTargetHealth": false
        }
      }
    }
  ]
}'

カスタムドメインでリクエストしてみる

最後に、設定したカスタムドメインで API にリクエストしてみます。

$ http https://chalice-api.michimani.net/
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 17
Content-Type: application/json
Date: Tue, 21 Jul 2020 22:08:34 GMT
Via: 1.1 3c7a01dc859868cee354c75bcf600744.cloudfront.net (CloudFront)
X-Amz-Cf-Id: lHTkFHXDMngc5e5KtOvf4bbKS4jGBJaY8VJkYXT-Jo4XQ4vLeFvMfQ==
X-Amz-Cf-Pop: NRT20-C4
X-Amzn-Trace-Id: Root=1-5f176761-350c758e6c6201c99ab9607f;Sampled=0
X-Cache: Miss from cloudfront
x-amz-apigw-id: QC0XTEFIoAMFd_A=
x-amzn-RequestId: 0d12b19d-6fa1-4237-a6e1-a1b979f3b455

{
    "hello": "world"
}

無事にレスポンスが返ってきました。

まとめ

AWS Chalice で API Gateway のカスタムドメイン名の作成がサポートされたので試してみたという話でした。

カスタムドメイン名の作成がサポートされたとは言っても、そのドメイン名を Route 53 で ALIAS レコードとして作成する必要はあります。手順でいうと最後の `` コマンドを実行するところです。なので、そのあたりはシェルスクリプトなり何なりを自作してコマンド化したいところです。

とは言え、これまではカスタムドメイン名の作成も手作業でやる必要があったことを考えると、今回のアップデートですごく便利になったなという印象です。

途中でも書きましたが、 Chalice でのリソース作成・更新・削除は非常に高速なので、サクッと API を作りたいという場面ではとても強力なツールです。今回やってみた内容についても、証明書の発行部分を含めても 15 分程度で試すことができるかなと思います。リソースの削除も chalice delete コマンドでサラッと消えていってくれます。

AWS 環境でサーバレスなアプリケーションを構築するツールには SAM や Serverless Framework がありますが、個人的にはシンプルで高速な Chalice がお気に入りです。Chalice については以前にも記事を書いたので、こちらも参考にしていただけると幸いです。


comments powered by Disqus