使用fly.io的litefs和bun
#javascript #sqlite #ts #bunjs

既不建议生产BunLiteFS,所以我认为在fly.ioð

- 但是为什么?

面包非常擅长:

serving performance

  • 在引导时非常快,非常适合Lambdas Cold and Hot开始,以及基于Docker的容器ð
  • 它在服务方面非常迅速,使其成为与云相关的任何云的理想运行时(此外,它是TS/JSX兼容,而无需额外的工具!)ð
  • 当涉及到sqliteð的最快JS/TS运行时,事实上,BUN具有直接构建和绑定的sqlite其他带有sqlite bintings的PL

fly.io的litefs非常擅长:

sqlite performance

  • 它可以免费提供一个可以将1个固定文件系统托管到许多SQLITE数据库的全GB(1GB是很多文本!!!)ðÖ©
  • 当需要/如果需要的话,它可以在全球范围内复制和同步数据库
  • fly.io允许任何docker映像,因此我们可以轻松地在本地测试并在生产中部署在生产中

最重要的是,Sqlite周围的景观作为托管解决方案几乎没有像Fly.io 设置那样简单且做得很好,我们现在要检查详细信息!

项目树

Image description

  • litefs 文件夹而不是实际安装的 litefs 路径,每当我们在本地进行测试和/或不在生产中进行测试。让我们只在目录中键入mkdir litefs,我们想用来通过bun run start(或bun start甚至npm start)来测试此设置,如果存在节点并可用bun)
  • .dockerignore文件包含我们不应该推到docker
  • 的所有可能的东西
  • Dockerfile包含bun’s official alpine based docker image(总计s〜100mb)加上一些命令来引导服务器
  • fly.toml包含脚手架NodejsLiteFS准备的示例的混合物看起来像
  • litefs.js文件将数据库连接作为唯一模块输入点处理,以及一些基于模板的实用程序
  • package.json用于提供start命令和可选依赖项
  • serve.js文件只是启动服务器演示,该演示显示一些欢迎和虚拟/示例中的所有行Sqlite数据库

所有文件也将与其内容一起显示。

在我们开始之前

The easiest way to scaffold a fly.io project is to use fly apps create, which will generate a unique YOUR_FLY_APP_NAME (see fly.toml later on) and it will give you indications of regions you can use要部署您的应用程序,然后您需要使用最接近的免费位置来进行create your LiteFS volume

P.S。如果您不知道从哪里或如何开始,请使用LiteFS example,因为它最近已更新,并且在开始时确实可以使用(但是它使用GO (dehihi)在ð

之后

完成此操作后,列表中的每个文件都是强制性的,这就是我作为每个文件内容所拥有的:

.dockerignore

.git
litefs
node_modules
.dockerignore
bun.lockb
Dockerfile
fly.toml

Dockerfile

### GLOBALS ###
ARG GLIBC_RELEASE=2.34-r0


### GET ###
FROM alpine:latest as get

# prepare environment
WORKDIR /tmp
RUN apk --no-cache add unzip

# get bun
ADD https://github.com/oven-sh/bun/releases/latest/download/bun-linux-x64.zip bun-linux-x64.zip
RUN unzip bun-linux-x64.zip

# get glibc
ARG GLIBC_RELEASE
RUN wget https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub && \
    wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_RELEASE}/glibc-${GLIBC_RELEASE}.apk


### IMAGE ###
FROM alpine:latest

# install bun
COPY --from=get /tmp/bun-linux-x64/bun /usr/local/bin

# prepare glibc
ARG GLIBC_RELEASE
COPY --from=get /tmp/sgerrand.rsa.pub /etc/apk/keys
COPY --from=get /tmp/glibc-${GLIBC_RELEASE}.apk /tmp

# install glibc
RUN apk --no-cache --force-overwrite add /tmp/glibc-${GLIBC_RELEASE}.apk && \

# cleanup
    rm /etc/apk/keys/sgerrand.rsa.pub && \
    rm /tmp/glibc-${GLIBC_RELEASE}.apk && \

# smoke test
    bun --version

#######################################################################

RUN mkdir /app
WORKDIR /app

# NPM will not install any package listed in "devDependencies" when NODE_ENV is set to "production",
# to install all modules: "npm install --production=false".
# Ref: https://docs.npmjs.com/cli/v9/commands/npm-install#description

ENV NODE_ENV production

COPY . .

RUN bun install

LABEL fly_launch_runtime="bun"

WORKDIR /app
ENV NODE_ENV production
CMD [ "bun", "run", "start" ]

fly.toml

app = "YOUR_FLY_APP_NAME"
kill_signal = "SIGINT"
kill_timeout = 5
processes = []

[env]
  PORT = "8080"

[experimental]
  auto_rollback = true
  enable_consul = true

[mounts]
  source = "litefs"
  destination = "/var/lib/litefs"

[[services]]
  http_checks = []
  internal_port = 8080
  processes = ["app"]
  protocol = "tcp"
  script_checks = []
  [services.concurrency]
    hard_limit = 25
    soft_limit = 20
    type = "connections"

  [[services.ports]]
    force_https = true
    handlers = ["http"]
    port = 80

  [[services.ports]]
    handlers = ["tls", "http"]
    port = 443

  [[services.tcp_checks]]
    grace_period = "1s"
    interval = "15s"
    restart_limit = 0
    timeout = "2s"

litefs.js

import {existsSync} from 'node:fs';
import {join} from 'node:path';
import {Database} from 'bun:sqlite';
import createSQLiteTags from 'better-tags';

// use mounted point on production, use local folder otherwise
const litefs = join(
  process.env.NODE_ENV === 'production' ? '/var/lib' : '.',
  'litefs'
);

// if litefs folder doesn't exist get out!
if (!existsSync(litefs)) {
  console.error('Unable to reach', litefs);
  process.exit(1);
}

// shared db + template literals  based utilities
const {db, get, all, values, exec, run, entries, transaction} =
        createSQLiteTags(new Database(join(litefs, 'db')));

export {db, get, all, values, exec, run, entries, transaction};

///////////////////////////////////////////////////////////////
// FOR DEMO SAKE ONLY - EXECUTED ON EACH DEPLOY
///////////////////////////////////////////////////////////////

// some table schema
exec`
  CREATE TABLE IF NOT EXISTS persons (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    phone TEXT NOT NULL,
    company TEXT NOT NULL
  )
`;

// some table entry
exec`
  INSERT INTO persons
    (name, phone, company)
  VALUES
    (${
      crypto.randomUUID()
    }, ${
      ('+' + (Date.now() * Math.random())).replace(/[^+\d]/, ' ')
    }, 'fly.io')
`;

package.json

{
  "name": "flying-bun",
  "description": "A Bun & LiteFS love 💘 affair",
  "type": "module",
  "scripts": {
    "start": "bun serve.js"
  },
  "dependencies": {
    "better-tags": "^0.1.2"
  }
}

服务

import {serve} from 'bun';

// grab the db or some utility
import {all} from './litefs.js';

// grab the port and start the server
const port = process.env.PORT || 3000;

serve({
  fetch(request) {
    const greeting = "<h1>Hello From Bun on Fly!</h1>";
    const results = `<pre>${JSON.stringify(
      all`SELECT * FROM persons ORDER BY id DESC`, null, '\t')
    }</pre>`;
    return new Response(greeting + '<br>' + results, {
      headers: {'Content-Type': 'text/html; charset=utf-8'}
    });
  },
  error(error) {
    return new Response("Uh oh!!\n" + error.toString(), { status: 500 });
  },
  port
});

console.log(`Flying Bun app listening on port ${port}!`);

在litefs上部署面包

这几乎是这样,一旦您拥有唯一的应用程序名称,您可以访问的LiteFS已安装目录以及提供的代码,则可以在本地进行bun run start,也许是在bun installnpm install之后,最后可以fly deployfly deploy到请参阅您的 Hello bun

如果一切顺利,您应该能够到达https://YOUR_FLY_APP_NAME.fly.dev并查看页面中显示的至少一张记录。

the deployed app example

一些指标

36 MB out of 232 MB RAM used

仅使用 bun glibc 的基本高山图像,以及项目文件,应在允许的232 MB中消耗不超过40MB的RAM,但是 fly.io 的酷部分是,当您计划缩放CPU,RAM,重复数据库或同时,我们总是可以选择付费LL设法达到1 GB的 litefs 文件大小限制。 how to manage fly volumes can be found here的详细指南。

这就是所有人ð¥³

恭喜!您了解了如何在云上部署下一个BUN项目以及免费的数据库解决方案,该解决方案将免费托管GB,而不是仅限于单个DB,因此每个DB分开关注也是一种可能性(1对于IP地理位置,1用于博客文本,用户为1个,1 for管理。)

SQLITE作为数据库中最低估的部分,除了是地球上存在的最酷的嵌入式数据库外,没有秘密的用户和密码会泄漏,并且fly.io安装的文件系统也已被加密,因此整个课程都是这样。安全问题会自动从共享代码的人的所有方程式和责任中自动删除,就像我只是在此处完成ð

一样