logo

鱼肚的博客

Don't Repeat Yourself

Serverless 域名管理方案

引言

Serverless应用一般都是微服务架构,项目会比较多,域名管理比较复杂。

本文提出了一种便捷的Serverless应用域名管理方案。

此方案基于 AWS 平台,使用 Serverless 框架及其周边生态实现。使用其它平台或框架的读者请酌情参考。

方案概述

  1. 前后端分离
  2. 每个前端项目占用一个独立的子域名
    1. foo 项目前端工程会使用 foo.demo.com
    2. bar 项目前端工程会使用 bar.demo.com
  3. 后端项目共用一个公共子域名,如 api。再通过子路径区分不同的业务(以及公共服务)。
    1. foo 项目后端工程会使用 api.demo.com/foo
    2. bar 项目后端工程会使用 api.demo.com/bar
  4. 将域名委托在对应的Serverless云服务商(如 AWS Route53),方便使用程序添加、删除记录。
  5. 使用工具进行域名管理。

示意图

1graph LR
2
3root(demo.com)
4foo-front(foo.demo.com)
5bar-front(bar.demo.com)
6
7subgraph backend
8api(api.demo.com)
9foo-backend(api.demo.com/foo)
10bar-backend(api.demo.com/bar)
11common-backend(api.demo.com/common)
12end
13
14root --> foo-front;
15root --> bar-front;
16
17root --> api;
18
19api --> foo-backend;
20api --> bar-backend;
21api --> common-backend;

实现方式

Serverless 中主要有两种方式管理域名,分别是基于 Serverless Components 的 Domain 和基于原生 Serverless 的 serverless-domain-manager

它们的主要区别有两个:

  1. 应用领域不同,Serverless Components 和 原生 Serverless 的写法差异比较大。
  2. serverless-domain-manager支持子路径,而 Domain 暂时还不支持。

本方案中使用 serverless-domain-manager 管理后端域名,使多个工程即使不在同一个Git仓库中,也可以共用同一个域名(api.demo.com)。

至于前端项目域名就比较灵活了,具体看前端项目采用的是 Serverless Components 方式还是原生 Serverless 方式而定。

两种方式都需要先将域名的DNS服务改到Route53下,具体方法请参阅官方文档。

https://aws.amazon.com/cn/route53/

示例代码

基于serverless-domain-manager管理后端域名

基于serverless-domain-manager管理后端应用,共用同一个域名的示例:

  1. 创建serverless.yml,如下所示,将其中的 *.demo.com,foo 等换成对应的域名。
1service:
2  name: foo-backend
3
4custom:
5  serverless-offline:
6    port: 3000
7  domains:
8    prod: api.demo.com
9    staging: staging-api.demo.com
10    dev: dev-api.demo.com
11
12  customDomain:
13    domainName: ${self:custom.domains.${self:provider.environment.stage}}
14    basePath: 'foo'
15    stage: ${self:provider.environment.stage}
16    createRoute53Record: true
17
18# Add the serverless-webpack plugin
19plugins:
20  - serverless-domain-manager
21
22provider:
23  name: aws
24  runtime: nodejs12.x
25  stage: dev
26  apiGateway:
27    minimumCompressionSize: 1024 # Enable gzip compression for responses > 1 KB
28  memorySize: 256
29  environment:
30    stage: ${opt:stage, self:provider.stage}
31    AWS_NODEJS_CONNECTION_REUSE_ENABLED: 1
32
33functions:
34  test:
35    handler: handler.test
36    events:
37      - http:
38          method: get
39          path: test
40          cors: true
41
  1. 安装相关依赖: serverless、serverless-domain-manager 等包

    npm i -D serverless serverless-domain-manager

  2. 执行命令创建对应的域名

    npx serverless create_domain --stage dev

    这里的 dev 根据需要换成对应的 stage名。上面的 serverless.yml 中定义了三种stage(dev、staging、prod)分别对应三个不同的子域名。

    如果此域名已经在别处创建过,此步骤可忽略

  3. 执行deploy

    npx serverless deploy --stage dev

基于serverless-domain-manager管理前端域名

与上面的方案基本相同,去除 basePath: 'foo' 即可。

基于 Serverless Components Domain 管理前端域名

Serverless Components环环相扣,所以有可能您并不需要直接使用 Serverless Components Domain。

如果您在使用 Next.js 做前端应用,可考虑使用 serverless-nextjs-component

serverless-nextjs-component的自定义域名使用极为简单:

  1. 创建 serverless.yml 文件,写入如下内容:

    1# serverless.yml
    2
    3myNextApplication:
    4  component: serverless-next.js
    5  inputs:
    6    domain: "example.com" # sub-domain defaults to www
  2. 运行 serverless ,自动执行部署及域名创建。(注意不是 serverless deploy)。

如果直接使用 serverless components domain,则可使用如下的 serverless.yml

1domain:
2  component: '@serverless/domain'
3  inputs:
4    privateZone: false
5    domain: mywebsite.com
6    subdomains:
7      www: ${websiteComponentInstance}
8      api: ${backendComponentInstance}
9      admin: ${anotherWebsiteComponentInstance}

HTTPS 证书

AWS Route53 会负责证书的自动创建和更新,如果是通过上述的两种serverless方案创建的域名,不需要关心证书问题。

总结

本文提出了一种简便的Serverless应用域名管理方案。

它将前端域名和后端域名独立开,规避了前端项目和后端项目处于同一子域名下带来的制约。

使得前端工程可以和后端工程互相独立。前端工程也可以不采用Serverless架构,直接做CNAME映射到其它静态托管服务,如 Github pages或netlify。