Serverless 部署 Deno 应用有那么难吗 ???

胡琦

共 8338字,需浏览 17分钟

 ·

2021-02-11 12:24




牛年大吉




Serverless 部署 Deno 应用有那么难吗 ???

Deno 是一个简单、现代且安全的 JavaScript 和 TypeScript 运行时环境,其基于 V8 引擎并采用 Rust 编程语言构建。Deno 自打出生就不乏话题:“Node.js 的替代品,将来可能就不需要 Node.js 了”、"Deno 并不是下一代 Node.js"、“Deno 已经死了吗?”……而对于 Copy 攻城狮 来说,有趣就行!目前 CloudBase Framework 支持一键部署 Deno 应用,而我却踩了不少坑,谨以此文纪念逝去的那些一文不值的时光!

CloudBase Framework

🏆 腾讯云开发 ☁️ 云原生一体化部署工具 🚀 CloudBase Framework:一键部署,不限框架语言,云端一体化开发,基于 Serverless 架构。

「云开发 CloudBase 是腾讯云的热门产品,云开发应用可以是运行在云开发环境的应用,例如一个包含前后端、数据库等能力的服务,可以通过一键部署,直接部署在云开发环境中,使用云开发底层的各项 Serverless 资源,享受弹性免运维的优势。」 什么是云开发?什么是 Serverless?Copy 攻城狮心中满是疑问,还能不能愉快地切图!上一次了解到云开发还是看到“小程序·云开发”,印象比较深刻的是云开发提供一个云函数环境,提供云数据库、鉴权服务等,无需自备服务器搭建后端服务。听过一些老师的课,得益于云开发,前端开发尤其是小程序开发者,一个人就能前后端甚至运维也全干,快速上线一款弹性伸缩企业级应用;而 「Serverles」「功能即服务」(Function-as-a-Service,缩写为 FaaS) 和 「平台即服务」(platform as a service,缩写:PaaS 的组合,是当前主流的技术实现;不过,Copy 攻城狮只会跑跑 Hello World 。在 Serverless 技术体系中,我们熟知的 Node.js 扮演着举足轻重的一环,比如 Serverless Framework、Vercel等 Serverless 优秀产品都离不开 Node.js 完善的生态。CloudBase Framework也是如此,因此我们能够轻而易举的想到 CloudBase Framework 的安装和使用方式。

  • 安装 CLI 工具

    npm install -g @cloudbase/cli@latest

    如遇到权限问题,请使用 sudo , MacOS 上好像容易出现。

  • help 指令

    cloudbase -h

    盲猜应遵循了国际惯例, help help help!,当然,惊喜发现 cloudbase 还能简写为 tcb

     Tip: cloudbase 命令可以简写为 tcb

    CloudBase CLI 1.5.0
    CloudBase Framework 1.6.18-+

      命令

        login           [options]                  登录腾讯云账号
        logout                                     登出腾讯云账号
        env             [cmd]                      环境管理操作
        fn              [cmd]                      操作函数
        framework       [cmd]                      云开发 Serverless 应用框架操作
        hosting         [cmd]                      静态托管资源管理操作
        new             [appName] [template]       创建新的云开发应用
        open            [link]                     在浏览器中打开云开发相关连接
        storage         [cmd]                      云存储资源管理操作
        service         [cmd]                      HTTP 访问服务管理操作

      选项

        --verbose                                  打印出内部运行信息
        -r, --region                       指定环境地域
        --mode                               指定加载 env 文件的环境
        --config-file                        指定配置文件路径
        -v, --version                              输出当前版本
        -h, --help                                 查看命令帮助信息

      Tips:

        – 登录

          $ tcb login

        – 创建新的云开发应用

          $ tcb new appName

        – 部署云函数

          $ tcb fn deploy

        – 查看命令使用介绍

          $ tcb fn -h

  • 登录

    看到有登录的命令,先尝试一下,由于我之前已经登录过了,通过 logout 登出,再 login 。

    huqi@Mac-mini deno % tcb login
    CloudBase CLI 1.5.0
    CloudBase Framework 1.6.18
    ✔ 您已登录,无需再次登录!
    huqi@Mac-mini deno % tcb logout
    CloudBase CLI 1.5.0
    CloudBase Framework 1.6.18
    ✔ 注销登录成功!
    huqi@Mac-mini deno % tcb login
    CloudBase CLI 1.5.0
    CloudBase Framework 1.6.18
    ⠋ 获取授权中...

    此时,会通过默认浏览器打开一个 CLI 授权的页面,这让我想起 Huawei DevEcho Studio 在登录时也会调用网页来进行授权。登录逻辑实现的代码,我们可以「给 github 加 1s」 来打开在线 VSCode 来查看:https://github1s.com/TencentCloudBase/cloudbase-cli/blob/HEAD/src/commands/account/login.ts,感兴趣的小伙伴可以尝试通读源码。

    授权成功之后,它还会征求我的意见收集我的使用数据,为了更好的体验 Cloudbase ,我愿意!我愿意奉献我的使用数据!

    async function askForCollectDataConfirm({
        const agree = await usageStore.get('agreeCollect')
        if (agree) return
        // 询问
        const { confirm } = await inquirer.prompt({
            type'confirm',
            name'confirm',
            message'是否同意 Cloudbase CLI 收集您的使用数据以改进产品?',
            defaulttrue
        })

        if (confirm) {
            await usageStore.set('agreeCollect'true)
        }

        await collectAgree(confirm)
    }
  • 初始化项目及部署

    既然前边已经提到可以使用简写tcb来代替那串冗长的字母,那肯定使用tcb来创建初始化项目。

    tcb new deno_hello deno    # 以 deno 为模板创建项目
    cd deno_hello
    tcb                        # 部署项目

    非常简单明了的命令就实现了一个 Deno 应用的 Serverless 部署。当然,也正是三行命令,让我踩了一个又一个的坑,为此还花费了我好几毛钱的”巨款”,钱不钱倒是无所谓,主要是磨洋工都快把我耐心耗尽了!

    先来看看tcb new deno_hello deno干了啥,大胆猜测是创建了deno_hello文件夹,并通过调用https://tcli.service.tcloudbase.com/download传入 os、uin、macMd5、templateId、templateName、version 等参数,获取到 deno 模板并写入到deno_hello项目中。

    Cloudbase deno 模板源码依旧可通过「给 github 加 1s」 来查看:https://github1s.com/TencentCloudBase/cloudbase-templates/tree/master/deno。如果您碰巧留意到cloudbaserc.json,您可能会想为啥 deno 版本是 1.6.3 呢?:

      {
      "version""2.0",
      "envId""{{envId}}",
      "$schema""https://framework-1258016615.tcloudbaseapp.com/schema/latest.json",
      "framework": {
        "name""deno-app",
        "plugins": {
          "deno": {
            "use""@cloudbase/framework-plugin-deno",
            "inputs": {
              "dockerImage""debian:latest",
              "runtime""1.6.3"
            }
          }
        }
      }
    }

    对,这里便是我踩的坑!目前来看,在执行tcb之前,去掉"runtime": "1.6.3"这行使用 deno 最新的版本能避坑!

Deno 镜像之“锅”

很荣幸能遇到 Deno 生态建设崎岖之路的“bug”,云里雾里,这究竟是怎样一个故事?请听 Copy 攻城狮娓娓道来。

大概半个月之前,我尝试使用 Cloudbase 部署 deno 的 HelloWorld 应用,拉的 Cloudbase 官方的模板直接部署,怎么都不成功,部署失败的关键日志提示如下:

CloudBase CLI 1.2.7
CloudBase Framework 1.6.11
……
step 4/14 : RUN curl -fsSL https://x.deno.js.cn/install.sh | sh
---> Running in df11b9868b9a
�[91m#=#=#
curl: (22) The requested URL returned error: 403
�[0mThe command '/bin/sh -c curl -fsSL https://x.deno.js.cn/install.sh | sh' returned a non-zero code: 22

当时看到https://x.deno.js.cn/install.sh就想到了 justjavac 大大的 Deno 镜像,不过没想到的居然是「jsdelivr CDN 单文件最大只支持 20M」导致了 Deno 1.7.0 版本在当时的镜像无法正常使用,因为 1.7.0 版本的 zip 包刚好超过了 20M,参见https://github.com/justjavac/dvm/issues/42:

这间接导致了 Cloudbase 中 Deno 模板使用最新的版本时,通过镜像无法下载;也造就了我这个注定是巧合的坑!

好在 justjavac 大大及时修复了这个“bug”:

fn compose_url_to_exec(version: &Version) -> String {
  if version.major >= 1 && version.minor >= 7 {
    format!("https://dl.deno.land/release/v{}/{}", version, ARCHIVE_NAME)
  } else {
    format!(
      "https://cdn.jsdelivr.net/gh/justjavac/deno_releases/{}/{}",
      version, ARCHIVE_NAME
    )
  }
}

当然,社区也有大佬折腾出了"自给自足"的方法--向 Deno 学习优秀的脚本管理,果真是自己动手丰衣足食。

这就结束了?非也非也,Deno 的生态目前还不够强大,同样是版本升级带来的问题,这回轮到了 denon!

Denon 兼容之“锅”

Denon 之于 Deno 如同 Nodemon 之于 Node.js ;Denon 可以监视您的 Deno 应用程序中的所有更改并自动重新启动,避免了每修改一处代码就要手动重启的繁琐;此外,对于 Deno 应用来说,还提供了体验非常棒的配置。

在我们通过tcb new deno_hello deno拉取的模板中,也能看到 Denon 的身影,denon.yml:

scripts:
  lint: deno fmt --check .
  build:
    cmd: mkdir dist && deno bundle --no-check src/entry.ts dist/entry.js
    watch: false
  start:
    cmd: deno run --no-check dist/entry.js
    env:
      PATHNAME: "/deno-app"
    allow:
      - net
      - env
      - read
  dev:
    cmd: deno run --no-check src/entry.ts
    env:
      PORT: "3000"
    allow:
      - net
      - env
      - read

上边这个配置文件将我们可以做的一些事安排得明明白白:代码检查、打包构建、本地调试等。

那 Denon 带来了什么困扰呢?“罪魁祸首”还是因为 Deno 版本升级。当时,Deno 刚升到 1.7.0 ,使用 Denon 就会报错permission error,参见:fix: permission error on latest deno:

TS2339 [ERROR]: Property 'url' does not exist on type 'NetPermissionDescriptor'.
? `--allow-${pd.name}=${pd.url}`
                                           ~~~
at https://deno.land/std@0.83.0/permissions/mod.ts:18:44

当时普遍认为 Deno 1.6.3 是比较稳定的版本,至少也不会导致 Denon 无法正常使用,我猜大概也是因为这个原因,我们在上文中提到 Cloudbase 中 deno 模板目前也是使用的 1.6.3。

出现类似的“锅”,如果您依旧想使用最新版本,那就只能等等兼容问题被处理,或者您亲自动手处理兼容问题。再回过头来看看这个兼容问题是如何处理的?看上去只是改了一个版本号,但究竟为何要这样改,估计只能深入 Deno 源码学习才能一探究竟了。

牛刀小试

既然所有的问题都如愿以偿地被社区大佬们解决了,那接下来,我还是想试试 Cloudbase 和 Deno 这两把“牛刀”,完成我琢磨了很久的一个 Hello World,姑且称为「一条热搜」。主要是不想浪费之前通过 Deno 获取的每日热搜数据,加上想体验一下 Cloudbase 的一键部署功能,难得 Cloudbase 支持 Deno 插件。

按照剧情,上文中初始化 Deno 项目之后,直接输出 tcb 这三个字母就能进行部署,「请尽量本地调试好应用再部署,每次部署都会」,当然,截止文章发布前,建议去到指定 Deno 版本的这行配置:

- "runtime": "1.6.3"

简单修改了一下 HelloWorld 的代码,让它变成一个我想要的「一条热搜」,数据基于「trending-in-one」,我粗暴地在 controller 中获取热搜数据:

    const response = await fetch(`https://cdn.jsdelivr.net/gh/hu-qi/trending-in-one/raw/toutiao-search/${formatTime(new Date(),{template:'{{YYYY}}-{{MM}}-{{DD}}'})}.json`)
    const responseJson = await response.json()
    const index = Math.floor(Math.random() * responseJson.length);

    const pathname = Deno.env.get("PATHNAME") || '';
    ctx.response.body = await renderFile(`${Deno.cwd()}/views/home.ejs`, {
      title'一条热搜',
      text: responseJson[index],
      pathname,
    });

来看看部署之后惨不忍睹的效果:

在线预览地址:http://deno-demo-3ghgaf7pa8d97b90-1253880795.ap-shanghai.app.tcloudbase.com/(PS:如果无法访问,那一定是我欠下巨款跑路了,您可以自行一键部署)

一键部署:

最后唠嗑一下 Cloudbase 的一键部署,「一键部署按钮可以让公开的 Git 项目一键部署到云开发 CloudBase 上,大大简化用户部署的门槛,便用户快速使用和体验应用。一键部署功能支持 Github,Gitlab,Coding,Gitee 等 Git 仓库地址。」 简直是 Copy 攻城狮的福音,复制粘贴都不用了,一键部署!(PS: 其实还是需要手动进行配置)

一键部署按钮的生成可以访问:https://docs.cloudbase.net/framework/deploy-button.html,只需填入仓库地址、目录和分支,这点和 Vercel 部署也有些类同:

总体体验还是不错的,不过最后还是遇到了一个访问地址的坑,还没来得及填,不过影响不大。大概是一键部署成功之后,访问地址*.ap-shanghai.app.tcloudbase.com/deno-app在浏览器中打开时变成了文件下载,而实际服务的地址是没有deno-app这个服务名称路径的,大概率是我的配置有点偏差,弃坑弃坑!

小结

总得来说,随着 Deno 生态的不断完善,Serverless 部署 Deno 应用变得越来越简单。借助云开发 Cloudbase,您无需关注 Deno 的安装实现、服务的运维等等,还能以最低的成本运行 Deno 应用。希望我的踩坑能够给您启发,请多多指教,感谢!


点击阅读原文预览哦



浏览 31
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报