Upgrade to Pro — share decks privately, control downloads, hide ads and more …

AWS CDKを利用して、 Next.js/Stripeで構築したフルスタックSaaSアプリをデプロイ・管理する/cdk-conf-jp-2022

AWS CDKを利用して、 Next.js/Stripeで構築したフルスタックSaaSアプリをデプロイ・管理する/cdk-conf-jp-2022

Hidetaka Okamoto (Stripe)

April 09, 2022
Tweet

More Decks by Hidetaka Okamoto (Stripe)

Other Decks in Programming

Transcript

  1. AWS CDKを利用して、
    Next.js/Stripeで構築したフルスタック
    SaaSアプリをデプロイ・管理する
    AWS CDK Conference Japan 2022
    Hidetaka Okamoto(@hide__dev)
    2022/04/09

    View Slide

  2. 岡本 秀高 ( @hide__dev )
    ● Stripe Developer Advocate
    (ex-developer in Digitalcube)
    ● JavaScript / TypeScript developer
    ● AWS / Next.js / WordPress / etc…
    ● WordCamp Kyoto 2017 / JP_Stripes
    Connect 2019 / AWS Samurai 2017 /
    etc…
    ● 🐈(猫フラご容赦󰢛)
    2
    ジャムジャム!!Jamstack_5
    #cdkconf

    View Slide

  3. 3
    https://stripe.com/jp

    View Slide

  4. 4
    決済だけでなく決済周辺の機能もご利用可能
    AWS CDK Conference Japan 2022
    Payments
    Checkout
    Radar
    Billing
    Connect
    Terminal Issuing
    Payouts
    Capital
    Corporate Card
    Treasury
    オンライン決済
    構築済み決済 UI
    不正使用とリスクの管理
    サブスクリプションの管理
    プラットフォーム向けの決済
    Climate
    Sigma
    Atlas
    収益の一部で CO2 除去に貢献
    カスタムレポート
    Identity
    決済最適化 ビジネスモデル ビジネス運営 送金・資金移動 融資・法人カード発行
    オンライン請求書
    Invoicing
    BaaS
    支出管理
    ビジネスの資金調達
    海外への入金
    カード作成
    Tax
    消費税と VAT の自動計算
    オンライン本人確認
    スタートアップの企業設立
    対面支払い
    (日本未展開)

    View Slide

  5. Low Code / No Codeで、決済リンクが作れる
    5
    AWS CDK Conference Japan 2022
    #cdkconf
    const session = await stripe.checkout.sessions.create({
    mode: "payment",
    success_url: `${req.headers.origin}`,
    cancel_url: `${req.headers.origin}`,
    line_items:[{
    price: req.body.price_id,
    quantity: 1
    }]
    })
    return session.url

    View Slide

  6. Stripeをより便利に使うには、サーバー側の処理が必要
    ● 請求やサブスクのデータは、
    サーバー側で作成・処理する
    ● クライアント側だけでもできないことはない
    *Stripe-js SDKのCheckoutやPayment Linksを利用
    ● が、機能面の制限がでる
    ○ クーポン入力
    ○ 消費税の自動計算
    ○ 動的な料金プラン
    ○ etc…
    ● フロントエンドのアプリと、
    サーバー側の処理の両方を
    用意しておきたい
    6
    AWS CDK Conference Japan 2022
    #cdkconf

    View Slide

  7. Next.js: ExpressライクなAPIとReactアプリをまとめて管理
    ● React向けのフレームワーク
    ● フロントエンドと
    バックエンド(REST API)を
    まとめて管理できる
    ● SSRや静的化、ISRに対応
    画像の最適化も
    ● ウェブアプリから
    メディア・通販など、
    幅広い用途で採用が増加中
    7
    AWS CDK Conference Japan 2022
    #cdkconf
    https://nextjs.org/

    View Slide

  8. Reactでフロントエンドを実装(一部Next.js独自実装有)
    8
    AWS CDK Conference Japan 2022
    import type { GetStaticProps, NextPage } from 'next';
    import Head from 'next/head';
    import Image from 'next/image';
    import styles from '../styles/Home.module.css';
    export const getServerSideProps: GetServerSideProps = async () => {
    return { props: {} };
    };
    export const getStaticProps: GetStaticProps = async () => {
    return { props: {} };
    };
    const Home: NextPage = (props) => {
    return (


    Create Next App

    );
    };

    View Slide

  9. APIはExpressライクな書き方で実装
    9
    AWS CDK Conference Japan 2022
    import { NextApiRequest, NextApiResponse } from 'next';
    import Stripe from 'stripe';
    export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY as string, { apiVersion: '2020-08-27' });
    export default async function handler(req: NextApiRequest, res: NextApiResponse) {
    const session = await stripe.checkout.sessions.create({
    mode: 'payment',
    line_items: [{
    price: 'price_xxxxx',
    quantity: 1,
    } ],
    success_url: 'http://localhost:3000/success',
    cancel_url: 'http://localhost:3000/cancel',
    });
    res.status(200).json({
    url: session.url,
    });
    }

    View Slide

  10. Next.jsで実装したアプリのデプロイ先(一例)
    ● Vercel: Next.jsの提供元で、Next.jsに最適化されているホスティング
    ● NetlifyやAmazon S3: 静的にサイトをビルドする(
    APIやサーバー側機能を使わない)場合に使える
    ● AWS Amplify: AWSで、GUIからアプリの設定やアプリのパイプラインを管理したい。
    [email protected]など: serverless-nextjsを使って、AWSで構成をコード管理したい。
    ● AWS App Runner: Node.jsのアプリとして、コンテナの文脈で管理したい。
    10
    AWS CDK Conference Japan 2022

    View Slide

  11. Amplifyか、それ以外のAWSサービスか
    ● AWSで手軽に開始するなら
    AWS Amplify
    ● GUIで直感的に設定が可能
    ワークフローなども管理可
    ● Amplify Studioを使えば、
    Figmaとの連携も可能
    ● 連携するAWSサービスが
    増えると、IAM系で少し手間
    ● コードで管理したいか、
    GUIでなるべく管理したいか
    11
    AWS CDK Conference Japan 2022
    #cdkconf

    View Slide

  12. Serverless Next.js pluginを利用する
    ● AWSでNext.jsを
    Serverlessに使う場合に利用
    ● Next.jsを動かすための、
    AWSリソースを作成・管理
    ● CloudFront / [email protected]
    S3 / SQSなどをデプロイする
    ● Serverless Componentまたは
    AWS CDKから利用可能
    ● CDK v2にも対応済み
    12
    AWS CDK Conference Japan 2022
    #cdkconf
    https://github.com/serverless-nextjs/serverless-next.js

    View Slide

  13. NextJSLambdaEdgeコンストラクタを設定するだけ
    13
    AWS CDK Conference Japan 2022
    import * as cdk from "aws-cdk-lib";
    import { NextJSLambdaEdge } from "@sls-next/cdk-construct";
    import { Construct } from "constructs";
    export class ServerlessNextjsCdkExampleStack extends cdk.Stack {
    constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    const app = new NextJSLambdaEdge(this, "NextJsApp", {
    serverlessBuildOutDir: "./build"
    });
    new cdk.CfnOutput(this, 'Domain', {
    value: app.distribution.domainName,
    description: 'CloudFrontDomain'
    })
    }
    }

    View Slide

  14. serverless-nextjsでデプロイするリソース
    ● CloudFront: CDN
    ● S3: 静的ファイルのホスト
    [email protected]
    ○ APIの処理実行
    ○ アプリのSSR系処理
    ○ 画像処理系
    ○ ISR処理系
    ● SQS: ISR処理系
    ● そのほか: IAM / CWL / etc
    14
    AWS CDK Conference Japan 2022
    #cdkconf
    https://github.com/serverless-nextjs/serverless-next.js#
    architecture

    View Slide

  15. serverless-nextjsを使う上での注意点
    [email protected]の仕様・制限に影響を受ける
    ○ Nodeのランタイムバージョン
    ○ 実行時間
    ○ 環境変数
    ● Lambdaのログが複数リージョンの
    CWLに散らばるので、Sentryなどの併用が安全
    ● Next.js / Vercelのアップデート後、サポートまで時間差があるケースも
    15
    AWS CDK Conference Japan 2022

    View Slide

  16. AWS CDK + Next.js (+ Stripe) Topics:
    ● Next.jsプロジェクトに、serverless-nextjs + AWS CDKを追加する
    ● Secrets Managerを利用して、安全にAPIキーを利用する
    ● CloudFrontのキャッシュ設定をカスタマイズする
    ● 独自ドメイン設定のために、
    ACMを設定する
    16
    AWS CDK Conference Japan 2022

    View Slide

  17. AWS CDK + Next.js (+ Stripe) Topics:
    ● Next.jsプロジェクトに、serverless-nextjs + AWS CDKを追加する
    ● Secrets Managerを利用して、安全にAPIキーを利用する
    ● CloudFrontのキャッシュ設定をカスタマイズする
    ● 独自ドメイン設定のために、
    ACMを設定する
    17
    AWS CDK Conference Japan 2022

    View Slide

  18. Next.jsをセットアップ後、CDKを追加する
    ● CDKの方が、
    後から手動追加しやすい
    ● Next.jsとCDKを
    別ディレクトリ化はちょっと大変
    (monorepoなら・・・?)
    ● リソース区別のため、
    CDKディレクトリを用意
    ● CDKのリソースを消せば、
    Vercelなどへの引っ越しも容易
    ● cdk initした後、ファイルだけ
    持ってくるやり方でも可能
    18
    AWS CDK Conference Japan 2022
    https://github.com/serverless-nextjs/serverless-next.js
    # Next.jsのセットアップ
    $ npx create-next-app --typescript
    ✔ What is your project named? … cdk-demo
    # AWS CDKのリソースを手動追加(最小限)
    $ yarn add aws-cdk-lib constructs source-map-support
    $ yarn add -D aws-cdk ts-node
    $ touch tsconfig.cdk.json cdk.json
    # Serverless Next.jsを追加する
    $ yarn add @sls-next/cdk-construct
    # CDK用のファイルを追加
    $ mkdir -p cdk/bin
    $ touch cdk/bin/aws-cdk.ts
    $ touch cdk/stack.ts

    View Slide

  19. CDKとNext.jsでtsconfig.jsonを分ける(tsconfig.cdk.json)
    19
    AWS CDK Conference Japan 2022
    {
    "compilerOptions": {
    "target": "ES2018",
    "module": "commonjs", // ここでNext.js/CDKがコンフリクトする
    "lib": [
    "es2018"
    ],

    "typeRoots": [ "@types", "./node_modules/@types" ]
    },
    "include": [ "next-env.d.ts", "cdk" ],
    "exclude": [ "pages", "public", "styles", "node_modules", ".next", "cdk.out"]
    }

    View Slide

  20. CDK.jsonを用意する(cdk initした結果を使っても可)
    20
    AWS CDK Conference Japan 2022
    {
    "app": "npx ts-node --project tsconfig.cdk.json --prefer-ts-exts cdk/bin/aws-cdk.ts",
    "context": {
    "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true,
    "@aws-cdk/core:stackRelativeExports": true,
    "@aws-cdk/aws-lambda:recognizeVersionProps": true,

    }

    View Slide

  21. CDKでリソースを定義(cdk/stack.ts)
    21
    AWS CDK Conference Japan 2022
    import * as cdk from "aws-cdk-lib";
    import { NextJSLambdaEdge } from "@sls-next/cdk-construct";
    import { Construct } from "constructs";
    export class ServerlessNextjsCdkExampleStack extends cdk.Stack {
    constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    const app = new NextJSLambdaEdge(this, "NextJsApp", {
    serverlessBuildOutDir: "./build"
    });
    new cdk.CfnOutput(this, 'Domain', {
    value: app.distribution.domainName,
    description: 'CloudFrontDomain'
    })
    }
    }

    View Slide

  22. CDKでNext.jsのビルドを指示(cdk/bin/aws-cdk.ts)
    22
    AWS CDK Conference Japan 2022
    #!/usr/bin/env node
    import 'source-map-support/register';
    import { App } from 'aws-cdk-lib';
    import { Builder } from "@sls-next/lambda-at-edge";
    import { AwsCdkStack } from '../stack';
    const builder = new Builder(".", "./build", { args: ["build"] });
    builder.build()
    .then(() => {
    const app = new App();
    new AwsCdkStack(app, 'ServerlessNextjsCdkExampleStack', {
    });
    })
    .catch((e) => {
    console.log(e);
    process.exit(1);
    });

    View Slide

  23. nextコマンドでローカル実行、cdkコマンドでデプロイ
    23
    AWS CDK Conference Japan 2022
    # Next.jsアプリをローカル実行
    $ yarn dev
    $ npx next dev
    # Next.jsアプリとCDKのビルド -> CFN出力
    $ npx cdk synth
    # Next.jsアプリのビルド -> AWSへデプロイ
    $ npx cdk deploy

    View Slide

  24. AWS CDK + Next.js (+ Stripe) Topics:
    ● Next.jsプロジェクトに、serverless-nextjs + AWS CDKを追加する
    ● Secrets Managerを利用して、安全にAPIキーを利用する
    ● CloudFrontのキャッシュ設定をカスタマイズする
    ● 独自ドメイン設定のために、
    ACMを設定する
    24
    AWS CDK Conference Japan 2022

    View Slide

  25. Serverless Next.jsでのAPIキー管理
    ● Stripeには、フロント用の公開可能キー
    とシークレットAPIキーの2つがある
    ○ シークレットAPIキーは、顧客情報などにもアクセスできる
    ので、門外不出
    ○ 公開可能キーは、ソースから取得されても問題のない
    「公開して良い」キー
    ○ 「カスタマイズ可能なシークレット
    APIキー相当」として、「制限付きキー」もある
    ● 最低でもシークレットAPIキーは、AWSを利用して安全に管理する必要がある
    [email protected]なので、環境変数で埋め込む方法はそもそも使えない
    25
    AWS CDK Conference Japan 2022

    View Slide

  26. 安全なAPIキー管理のため、Secrets Managerをつかう
    ● APIキーなどを安全に
    管理するためのサービス
    ● API呼び出しへの課金なので、
    呼び出し回数には注意
    ● コストが厳しい場合、
    Systems Managerで代替も
    ● キーのローテーションなど、
    安全性をとるならこちら
    26
    AWS CDK Conference Japan 2022
    #cdkconf

    View Slide

  27. Secrets Managerへのアクセス権を設定
    27
    AWS CDK Conference Japan 2022
    import { PolicyStatement } from 'aws-cdk-lib/aws-iam'
    // 中略
    const app = new NextJSLambdaEdge(this, "NextJsApp", {
    serverlessBuildOutDir: "./build"
    });
    const secretManagerPolicyStatement = new PolicyStatement({
    resources: ['Secret ManagerのSecret ARN'],
    actions: ['secretManager:GetSecretValue']
    })
    app.defaultNextLambda.addToRolePolicy(secretManagerPolicyStatement);
    if (app.nextApiLambda) app.nextApiLambda.addToRolePolicy(secretManagerPolicyStatement);

    View Slide

  28. Lambda内で取得・利用する
    28
    AWS CDK Conference Japan 2022
    import { SecretsManager } from 'aws-sdk';
    import Stripe from 'stripe';
    const secretsmanager = new SecretsManager();
    const secrets = await secretsmanager.getSecretValue({
    SecretId: 'secret-id'
    }).promise()
    const secretsJSON = JSON.parse(secrets.SecretString)
    const stripe = new Stripe(secretsJSON.STRIPE_SECRET_API_KEY)

    View Slide

  29. AWS CDK + Next.js (+ Stripe) Topics:
    ● Next.jsプロジェクトに、serverless-nextjs + AWS CDKを追加する
    ● Secrets Managerを利用して、安全にAPIキーを利用する
    ● CloudFrontのキャッシュ設定をカスタマイズする
    ● 独自ドメイン設定のために、
    ACMを設定する
    29
    AWS CDK Conference Japan 2022

    View Slide

  30. Serverless Next.js Constructの戻り値から上書きする
    ● LambdaやCloudFrontの設定は
    上書き可能
    ● TypeScriptなどの型付き言語は、
    定義を追いかけて調査しやすい
    ● 「一部だけ変更」は難しそう
    ● cdk synthでCFNスタックを
    出力し、初期値を調査する方式
    ● Amplifyより手間だけど、
    触れる範囲と柔軟性は上
    30
    AWS CDK Conference Japan 2022
    https://github.com/serverless-nextjs/serverless-next.js
    import { Stack, StackProps, CfnOutput, Duration } from 'aws-cdk-lib';
    import { NextJSLambdaEdge } from "@sls-next/cdk-construct";
    import { CachePolicy, CacheQueryStringBehavior, CacheHeaderBehavior } from
    'aws-cdk-lib/aws-cloudfront';
    // 中略
    const app = new NextJSLambdaEdge(this, "App", { serverlessBuildOutDir: "./build"});
    app.nextLambdaCachePolicy = new CachePolicy(this, "NextLambdaCache", {
    queryStringBehavior: CacheQueryStringBehavior.all(),
    headerBehavior: CacheHeaderBehavior.allowList("Authorization", "Origin"),
    cookieBehavior: {
    behavior: 'all'
    },
    defaultTtl: Duration.seconds(0),
    maxTtl: Duration.days(365),
    minTtl: Duration.seconds(0),

    View Slide

  31. AWS CDK + Next.js (+ Stripe) Topics:
    ● Next.jsプロジェクトに、serverless-nextjs + AWS CDKを追加する
    ● Secrets Managerを利用して、安全にAPIキーを利用する
    ● CloudFrontのキャッシュ設定をカスタマイズする
    ● 独自ドメイン設定のために、ACMを設定する
    31
    AWS CDK Conference Japan 2022

    View Slide

  32. Serverless Next.js Constructの引数から設定
    ● 「よくある設定」は、
    Constructの引数から指定可能
    ● ドメイン・ログ・Cookie
    キャッシュ設定など・・・
    ● 「どう解釈されるか」は、
    cdk synthなどで出力を読もう
    32
    AWS CDK Conference Japan 2022
    https://github.com/serverless-nextjs/serverless-next.js
    const app = new NextJSLambdaEdge(this, "NextJsApp", {
    serverlessBuildOutDir: "./build",
    domain: {
    domainNames: ['example.com'],
    certificate: Certificate.fromCertificateArn(
    this,
    "ACM",
    'ACM Resource ARN'
    )
    },
    withLogging: false,
    whiteListedHeaders: ["Authorization", "Origin"]
    });

    View Slide

  33. まとめ
    ● AWS CDKを使うと、Next.jsアプリをAWSと連携させやすくなる
    ● ただし[email protected]を利用する前提の構成になる点に注意
    ● GUIベースの管理や手軽さを求めるなら
    Amplify、AWS使わないならVercel
    ● 利用開始も終了も手軽にできる
    serverless-nextjsで、
    Next.jsを利用したアプリ・サイト開発で
    AWSリソースをフル活用しよう
    33
    AWS CDK Conference Japan 2022

    View Slide