普通用户的界面
仅管理员可见界面
一个让你只需要花 10 分钟就可以从镜像创建 SaaS 网站的开源工具。
Docker2SaaS 是一个通过虚拟化技术(调用云平台接口)实现多租户,并进行租户管理和订阅扣费的小工具。它可以帮助 Web 应用和服务开发者快速建立销售用网站。你只需要将自己开发的应用制作成镜像,然后架设并配置一个 Docker2SaaS 网站,就可以开始销售云应用。
当用户订阅成功,它会按配置自动从镜像创建一个 VPS 为其服务;当用户取消订阅并过期后,它会自动删除 VPS。用户登入网站后可以看到自己的订阅、主机的 IP 信息。当然,你还可以添加更多,因为它是开源的。
下边的图展示了 Docker2SaaS 是如何在客户、支付服务商 Stripe 和 云服务提供商 DigitalOcean 之间进行交互的。
Docker2SaaS 主要面向云应用的开发者,为其提供一个迅速将应用变现的解决方案。
假设你开发了一个好用的 Web 小应用,并将其开源到了 Github。一些开发者很容易的自行搭建并使用了起来,但随着这个应用越来越受欢迎,非技术用户也开始变多。但是即使是已经制作了 docker file,对他们来讲,难度依然不小。
这时候你可能想提供 cloud hosting 的版本。一方面可以解决非技术用户在搭建上的细节问题,另一方面,hosting 可以带来一些利润,让你获得财务上的回报。
但这会带来额外的开发量,在你尚不知道 cloud hosting 是否受欢迎之前,花上几周时间来开发似乎并不是明智之举。
幸好,开源的 Docker2SaaS 可以解决这个问题,只需要花十分钟进行配置,你就可以得到一个简单但可用的 cloud hosting 销售网站。通过它立刻就可以进行早期的销售;当用户的需求增加后,你还可以修改源码添加更多的业务相关功能。
当然,它也可以被用来在云应用开发方许可下搭建第三方销售用网站。但整体而言,Docker2SaaS 是面向开发者设计的产品,并未考虑非技术用户的体验,如果您没有技术背景,那么更好的选择是使用别人搭建完成的 Docker2SaaS 网站,而非自己来搭建。
PS:Docker2SaaS 是基于 Laravel 构建的,虽然简单的搭建无需相关知识,但如果你要进行定制和添加功能,那么则需要具备一点 Laravel 开发常识。
我们假设你已经将应用做成 docker 镜像,并可以通过 docker-compose 命令启动。下边我们以 Ghost 为例,来进行讲解。
首先我们在 Digital Ocean 上创建一个 droplet( Digital Ocean 的 VPS 叫做 droplet )。镜像选择 marketplace
下的 docker on ubuntu
。
然后我们通过 SSH 登入到新创建的实例里边。在根目录下(或者其他地方)创建我们的 docker-compose.yaml 文件。这里我们使用 bitnami 提供的 yaml。
version: '2'
services:
mariadb:
restart: always
image: 'docker.io/bitnami/mariadb:10.3-debian-10'
environment:
- ALLOW_EMPTY_PASSWORD=yes
- MARIADB_USER=bn_ghost
- MARIADB_DATABASE=bitnami_ghost
volumes:
- 'mariadb_data:/bitnami'
ghost:
restart: always
image: 'docker.io/bitnami/ghost:3-debian-10'
environment:
- MARIADB_HOST=mariadb
- MARIADB_PORT_NUMBER=3306
- GHOST_DATABASE_USER=bn_ghost
- GHOST_DATABASE_NAME=bitnami_ghost
- ALLOW_EMPTY_PASSWORD=yes
- GHOST_HOST=localhost
- GHOST_EMAIL=guest@ftqq.com
- GHOST_PASSWORD=admin
ports:
- '80:2368'
volumes:
- 'ghost_data:/bitnami'
depends_on:
- mariadb
volumes:
mariadb_data:
driver: local
ghost_data:
driver: local
需要注意的是,这里我们添加了 restart: always
,以保证镜像启动的时候会自动启动 docker。
文件创建完成后,进入 droplet 管理创建一个 snapshot。
创建完成以后可以把 droplet 实例删除了。
进入 images 页面,在刚创建的 snapshot 条目对应的源代码中,查找到它的 data-id ,这个值(图中是 78661121 )就是 snapshot 的 id。知道了它,我们就可以把从这个 snapshot 创建 droplet 了。把它记录下来,之后会用到。(我们称其为 A1)
下边我们来创建一个 token,这样才能通过 API 管理 droplet 。在左侧菜单最下方,选择 API。
在 Tokens/Keys tab, 生成一个新的 token。注意要选择 read && write 权限。 生成好以后把它记录下来,之后会用到。(我们称其为 A2)
以下均以 Test mode 进行说明。
进入 Stripe dashboard,创建一个 product。
注意在 Pricing 部分,选择 Recurring ,这样才能自动续费。其他的项按自己的需求填写即可。
创建完成后,进入该 product 详情页面,可以看到 Pricing 一节中的 API ID,将其记录下来。(我们记为 B1 )
根据自己的需要,可创建多个 price ,记得把 price id 都记录下来。
为了能通过 API 和 Stripe 平台交互,我们同样需要 API key。点击左侧的 Developer 菜单,选择 API Keys,把右侧的 publishable key 和 secret key 记录下来。(记为 B2,B3)
将 docker2saas 的源代码下载/clone 到要运行销售网站的环境。该环境需要配置好 PHP7.4+ 和 MySQL 。
git clone https://gitlab.com/easychen/docker-2-saas.git --depth=1 docker2saas
初始化依赖包:
cd docker2saas
composer install
将 .env.example
改名为 .env
,并运行命令生成 APP_KEY
php artisan key:generate
填写其他相关信息:
- APP_DEBUG : 调试完成后应设置为 false
- APP_URL:网站网址
- APP_LOGO_URL 和 APP_ICON_URL:首页大图和顶部菜单图标
- DB_*:数据库相关配置
- STRIPE_KEY:前文中的 B2
- STRIPE_SECRET:前文中的 B3
在 MySQL 中创建数据库 docker2saas 后,然后运行命令初始化数据库:
php artisan migrate
启动测试环境
php artisan serve --host=0.0.0.0 --port=8001
访问机器 ip 的 8001 端口即可看到网站。点击 register 注册用户并自动登录,第一个注册的用户将自动成为管理员。
管理员的判断逻辑可自行在 app/Providers/AuthServiceProvider.php
中修改:
Gate::define('saas-admin', function (User $user) {
return $user->id == 1;
});
点击 settings tab,配置网站的基本信息,其中 DigitalOcean token
为上文中的 A2。
DigitalOcean sshkey
是你想要用来管理所有 droplet 的 public key。如果你没有准备好的,可以运行以下命令创建:
ssh-keygen -t rsa -f <name>
运行过程中,如果你不想设置 passphrase ,可以直接按两次 enter 将其设置为空。
ssh-keygen -t rsa -f this
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
完成后,在命令目录下会生成 .pub ,其内容就是我们要填写到表单中的 sshkey。
点击 Plans
页面的 Add a plan
来添加订阅计划:
- Name:用户可见的计划名称,比如 pro
- Stripe Price ID:前文中的 B1
- DigitalOcean Droplet Region:创建的云主机所在区域
- DigitalOcean Droplet Size:创建的云主机的型号
region 和 size 的值可以在 Digital Ocean 官网创建 droplet 页面获得,当你选择好需要的区域和型号后,在生成云主机的默认名称中,如下图选中部分即为 size,其后的 sgp1
部分即为 region。
- DigitalOcean Droplet Image:前文中的 A1
- DigitalOcean Droplet User Data:在云主机中可以访问到的自定义信息,可以传递购买用户的信息,如 email 等,具体用到什么地方,后文会做讲解。可暂时留空。
保存以后,可以在列表界面得到一个 Link,用户点击该链接即可进入计划的订阅流程。(此链接记为 C1)
点击 Pricing
页面,可以看到一个预设的计划展示页面。
编辑 resources/views/pricing.blade.php
可以对此页面进行定制。该页面采用 blade 语法,但几乎全由 HTML 构成,修改起来难度不大。
除了样式、提供服务项的修改,需要特别注意下方的 Subscribe
按钮,应该链接到对应的计划上,如前文的 C1 。
同样的,编辑 resources/views/dashboard.blade.php
,可以修改用户注册后看到 dashboard
页面,可以在此添加云服务的相关使用说明和帮助。
Docker2Saas 每天监测过期的用户,并将其云主机删除。为了能定时执行,你需要将此项目的命令添加到系统的 crontab 中:
* * * * * php </path/to/docker2saas>/artisan schedule:run
由于用户可以在 Stripe 网站对其订阅进行修改,所以 Docker2Saas 中的订阅修改和支付确认都是通过 webhook 来进行的。
webhook 需要填写外网可访问的 URL,建议上线后再进行配置。如果是在本机调试,可以使用 ngrok 进行内网穿透。
假设 Docker2Saas 网站的网址是 http://D.com
,那么 webhook endpoint URL 则为 http://D.com/stripe/webhook
。
在 events to send 处选择以下事件:
- invoice.created
- invoice.paid
- invoice.payment_action_required
- customer.subscription.created
- customer.subscription.updated
- customer.subscription.deleted
- customer.created
- customer.updated
- customer.deleted
注意其中 customer.subscription.updated
为订阅变更,由于背后涉及到云应用具体的升降级逻辑,默认并未进行处理。可以在 app/Http/Controllers/WebhookController.php
中自行实现。
至此,网站就可以进行正常的交易了。注意这里我们是使用 develop server 进行调试的,为了支持更多的用户,应切换到 Nginx 等专用服务器软件上。具体的操作,请参考这里。
在 Ghost 镜像中,我们需要知道当前 droplet 的 IP 地址或者域名来配置连接路径;也需要知道用户的 email 地址来为他们创建默认账户。
所以我们需要一个在镜像中获取用户信息的方式。在上文创建 plan 时,我们有一个 user data 选项(记为 F1),就是用来干这个的。
这是 Digital Ocean 提供的一个机制,在所有的 droplet 中,只要访问 http://169.254.169.254/metadata/v1/user-data
就可以获取到创建时传入的信息。
你可以在 droplet 中通过 curl 命令进行查看:
curl http://169.254.169.254/metadata/v1/user-data
但是这里有一个问题,那就是每一个用户的 email 地址是不同的。所以我们在填写 F1 处时,需要有变量支持。这里 Docker2Saas 通过 blade 语法提供了 $user
变量,你可以通过 {{$user->id}}
来插入用户 id;通过 {{$user->email}}
来插入 email:
uid={{$user->id}}
甚至可以直接将 docker-compose.yml
的模板直接放到 F1 处。
当然,在 droplet 镜像中,也需要配置相应的启动脚本来获取这些数据并进行配置。
另外,通过 curl http://169.254.169.254/metadata/v1
还可以获得 droplet 的相关信息,比如 ip、域名等。具体格式,请参考相关文档。
本项目采用有附加条件的 GPLv2 授权。
个人和商业公司均可在 GPLv2 授权下使用 Docker2SaaS 架设自己的云应用销售网站。
但禁止将 Docker2SaaS 本身作为 Cloud Hosting 服务售卖( 比如将 Docker2SaaS 制作为镜像,通过 Docker2SaaS 或其他平台 将其作为云服务售卖 )