- 后端
- 数据库
- 文档数据库
【免费下载链接】FerretDB
A truly Open Source MongoDB alternative
FerretDB 是一款真正开源的 MongoDB 替代方案,可将 PostgreSQL 作为文档数据库后端;而 Acorn 是一个基于 Kubernetes 的简化应用部署框架,让开发者无需直接编写 Kubernetes YAML 即可完成云原生部署。本文以一套完整的 Python Flask Todo 应用为例,讲解如何编写Acornfile将应用、FerretDB 与 PostgreSQL 后端一起打包成镜像,并通过acorn run一键部署、acorn build/push完成镜像发布,最终在任意 Kubernetes 环境复用这套工作流。
为什么用 Acorn 部署 FerretDB 应用
FerretDB 是 MongoDB 的替代方案:应用通过 MongoDB 协议与 FerretDB 通信,而数据实际存储在 PostgreSQL 或 SQLite 中,从而避免厂商锁定。与 MongoDB 生态的高度兼容意味着,任何使用pymongo、mongosh等 MongoDB 驱动与工具的应用,都可以在不改动业务代码的前提下切换到 FerretDB。
Acorn 则提供了位于 Kubernetes 之上的抽象层,以 Docker 容器、应用配置、部署描述等应用级原语来声明整个应用。在 Acorn 的模型里,Acornfile之于acorn run,就如同Dockerfile之于docker build——前者描述容器、服务、应用、卷、密钥与部署信息,并被编译成 Acorn 镜像。这样一个文件就能同时承载数据库、中间件与应用的全部配置。
本指南将实现一个 Flask + FerretDB 的 Todo 应用,并使用 Acorn 完成部署、镜像构建与发布。
前置条件
要完成本指南,需要准备:
- Acorn CLI(注册 Acorn 平台需要 GitHub 账号)
FerretDB 本身不需要在本机单独安装,因为最终它会作为 Acorn 应用中的容器被一起构建和运行。
安装 Acorn CLI
安装 Acorn CLI 后即可在终端直接运行acorn命令。macOS 与 Linux 用户:
brew install acorn-io/cli/acornWindows 用户通过 Scoop 安装:
scoop install acorn安装完成后,使用 GitHub 账号登录 Acorn 平台:
acorn login终端会引导你创建(或登录)Acorn 账号,完成授权后回到终端即可继续后续操作。
搭建 Python Flask 应用
我们创建一个简单的 Todo 应用,它通过pymongo连接 FerretDB(后端为 PostgreSQL)。先建立项目目录与文件:
mkdir -p my-ferret/templates cd my-ferret touch app.py requirements.txt templates/template.html Dockerfile Acornfile最终目录结构如下:
my-ferret/ │ ├── app.py # Python 主应用文件 ├── requirements.txt # Python 依赖清单 ├── Dockerfile # Docker 构建配置 ├── Acornfile # Acorn 部署配置 │ └── templates/ # HTML 模板目录 └── template.html # HTML 模板文件应用主代码 app.py
import os from flask import Flask, render_template, request, redirect, url_for from pymongo import MongoClient from bson.objectid import ObjectId app = Flask(__name__) db_uri = os.environ["DB_URI"] db_name = os.environ["DB_NAME"] print("DB_URI:", db_uri) print("DB_NAME:", db_name) client = MongoClient(db_uri) db = client[db_name] todos_collection = db['todos'] def redirect_url(): return request.args.get('next') or \ request.referrer or \ url_for('home') @app.route("/") def home(): todo_list = list(todos_collection.find({})) return render_template("template.html", todo_list=todo_list) @app.route("/add", methods=["POST"]) def add(): title = request.form.get("title") new_todo = {"title": title, "done": False} todos_collection.insert_one(new_todo) return redirect(redirect_url()) @app.route("/update/<todo_id>") def update(todo_id): todo = todos_collection.find_one({"_id": ObjectId(todo_id)}) todos_collection.update_one({"_id": ObjectId(todo_id)}, {"$set": {"done": not todo["done"]}}) return redirect(redirect_url()) @app.route("/delete/<todo_id>") def delete(todo_id): todos_collection.delete_one({"_id": ObjectId(todo_id)}) return redirect(redirect_url()) if __name__ == "__main__": app.run(debug=True)应用通过 Flask 提供 Web 页面,用pymongo与 FerretDB 通信——这正是 FerretDB 兼容 MongoDB 生态的体现:驱动层无需任何改造。DB_URI与DB_NAME两个环境变量由 Acornfile 注入,分别指向 FerretDB 的连接地址与数据库名;CRUD 操作(增删改查)由insert_one、find_one、update_one、delete_one完成,数据最终落盘到 PostgreSQL。
前端模板 template.html
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Todo App</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css" /> <script src="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.js"></script> </head> <body> <div style="margin-top: 50px;" class="ui container"> <h1 class="ui center aligned header">To Do App</h1> <form class="ui form" action="/add" method="post"> <div class="field"> <label>Todo Title</label> <input type="text" name="title" placeholder="Enter Todo..." /><br /> </div> <button class="ui blue button" type="submit">Add</button> </form> <hr /> <div class="ui items"> {% for todo in todo_list %} <div class="item"> <a href="/update/{{ todo.id }}"> {% if todo.done == False %} <i class="large square outline icon"></i> {% else %} <i class="large green check square icon"></i> {% endif %} </a> <div class="middle aligned content"> <div class="header">{{ todo.title }}</div> </div> <a href="/delete/{{ todo.id }}"> <i class="red trash alternate icon"></i> </a> </div> {% endfor %} </div> </div> </body> </html>页面使用 Semantic UI 渲染 Todo 列表:未完成项显示空心方框,点击后可切换为绿色勾选;删除按钮直接调用/delete/<todo_id>路由。
依赖清单 requirements.txt
Flask==2.3.2 pymongo这两行依赖将在 Dockerfile 构建阶段安装到容器内。
创建 Dockerfile 容器化 Python 应用
Dockerfile 负责构建运行 Flask 应用所需的镜像:设置环境、安装依赖、配置运行参数,最终在隔离容器内启动服务。
FROM cgr.dev/chainguard/python:latest-dev WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt --user COPY . . ENV FLASK_APP app.py ENV FLASK_ENV development ENV FLASK_RUN_HOST 0.0.0.0 ENV FLASK_RUN_PORT 8000 EXPOSE 8000 ENTRYPOINT ["python", "-m", "flask", "run"]注意FLASK_RUN_HOST设为0.0.0.0,确保容器外(即 Acorn 的负载均衡层)可以访问 8000 端口;EXPOSE 8000与 Acornfile 中ports: publish: "8000/http"的声明保持一致。
编写 Acornfile:一份文件描述整个应用
Acornfile 是整个部署的核心,它集中声明了 Docker 构建、数据库、密钥、容器、端口与部署信息。与 Dockerfile 构建出 Docker 镜像同理,Acornfile 会被编译成 Acorn 镜像。
services: postgres: { image: "ghcr.io/acorn-io/postgres:v15.#-#" } containers: { app: { build: context: "." ports: publish: "8000/http" env: { DB_URI: "mongodb://@{service.postgres.secrets.admin.username}:@{service.postgres.secrets.admin.password}@ferretdb/ferretdb?authMechanism=PLAIN" DB_NAME: "ferretdb" } dependsOn: [ "ferretdb" ] if args.dev { files: { "/src": "./" }, env: FLASK_DEBUG: "1" } } ferretdb: { image: "ferretdb/ferretdb" ports: publish: "27017/tcp" consumes: ["postgres"] env: { FERRETDB_POSTGRESQL_URL: "postgres://@{service.postgres.secrets.admin.username}:@{service.postgres.secrets.admin.password}@@{service.postgres.address}" } } }三个核心声明逐一拆解
postgres 服务:services: postgres声明了一个由 Acorn 托管的 PostgreSQL 服务(镜像ghcr.io/acorn-io/postgres:v15),运行在持久卷之上并提供admin凭据。默认配置下的该服务不具备高可用能力,生产环境可以无缝替换为其他 PostgreSQL 服务接口(如 AWS RDS for PostgreSQL)——这正是 FerretDB 避免厂商锁定价值所在。Acorn 为该服务注入的admin凭据包括:
POSTGRES_HOST:@{service.db.address}POSTGRES_DB:@{service.db.data.dbName}POSTGRES_USER:@{service.db.secrets.admin.username}POSTGRES_PASSWORD:@{service.db.secrets.admin.password}
ferretdb 容器:通过consumes: ["postgres"]消费上述服务,并用@{service.postgres.xxx}变量组装FERRETDB_POSTGRESQL_URL环境变量,指向 PostgreSQL 后端。这里的连接串格式与仓库中的配置体系完全一致:在 配置文档 中,FerretDB 通过--postgresql-url命令行标志或FERRETDB_POSTGRESQL_URL环境变量指定 PostgreSQL 连接 URL,默认值为postgres://127.0.0.1:5432/postgres,容器化部署时必须在环境变量中显式覆盖。仓库根目录的 docker-compose.yml 中 FerretDB 服务同样采用FERRETDB_POSTGRESQL_URL=postgres://pg-user:pg-pass@host.docker.internal:5432/postgres的写法,可作为对照。
app 容器:build: context: "."让 Acorn 基于同目录 Dockerfile 构建应用镜像;ports: publish: "8000/http"将 8000 端口对外暴露为 HTTP 端点;dependsOn: ["ferretdb"]保证 FerretDB 容器先就绪。DB_URI中值得注意的authMechanism=PLAIN参数:FerretDB 不自行存储用户认证信息(详见 认证文档),用户名与密码必须已存在于 PostgreSQL 中,客户端携带的凭据会被校验并映射到数据库权限。
dev 开发模式:if args.dev块为开发场景注入files卷(把源码挂载到/src)并设置FLASK_DEBUG=1,实现本地代码改动即时生效的热加载与调试体验。
使用 Acorn 部署应用
一切就绪后,在 Acornfile 所在目录执行:
acorn run -n my-ferret构建完成后,终端会输出应用端点与控制面摘要:
┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ || STATUS: ENDPOINTS[https://my-ferret-91916df9.qactc6.on-acorn.io, tcp://k8s-myferret-ferretdb-0c404ccc3f-0e3f1499f0b768c7.elb.us-east-2.amazonaws.com:27017] HEALTHY[2] UPTODATE[2] OK | └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘https://my-ferret-...on-acorn.io:Todo 应用的 HTTP 访问端点;tcp://...:27017:FerretDB 的 MongoDB 协议端点(端口 27017 与 Acornfile 中27017/tcp发布声明对应);HEALTHY[2] UPTODATE[2]:两个容器(app 与 ferretdb)均健康且版本一致。
通过该 URL 即可访问 Todo 应用:新增任务会写入 FerretDB(底层 PostgreSQL),勾选与删除操作同样实时反映到数据库中。如需本地验证 FerretDB 协议接入,可参考 Docker 安装文档 中mongosh连接 URI(mongodb://username:password@127.0.0.1/)的用法——Acorn 部署后,该连接串只需将主机替换为上面输出的 27017 TCP 端点。
构建与发布 Acorn 镜像
开发完成、准备交付时,可以像传统 Docker 工作流一样把应用打包成 Acorn 镜像。通用构建命令格式为:
acorn build -t <registry>/<organization>/<app-name>:<version> .例如发布到 Docker Hub:
acorn build -t index.docker.io/<organization>/my-ferret:v1.0 .该命令会把应用源码与Acornfile中声明的全部依赖(含 FerretDB、PostgreSQL 服务描述)编译进镜像,-t指定镜像标签。若非 Docker Hub,请替换 registry 前缀,并确保 organization/用户名正确。
推送镜像前需先登录 registry:
acorn login index.docker.io随后上传镜像:
acorn push index.docker.io/<organization>/my-ferret:v1.0镜像进入 registry 后,任何能访问该 registry 的环境都能直接部署,acorn run会自动拉取并运行:
acorn run index.docker.io/<organization>/my-ferret:v1.0如需在本地手动拉取镜像:
acorn pull index.docker.io/<organization>/my-ferret:v1.0至此,基于 FerretDB 的 Todo 应用已完成容器化、打标签并可在生产环境中跨环境部署。
清理环境
完成验证后,删除应用及其容器:
acorn rm my-ferret总结
本文演示了完整链路:从 Flask +pymongo编写业务代码,到 Dockerfile 容器化,再到用一份 Acornfile 同时声明 PostgreSQL 服务、FerretDB 容器与应用容器,最后通过acorn run部署、acorn build/push发布镜像。关键要点回顾:
- FerretDB 兼容 MongoDB 协议与驱动(如
pymongo),业务代码无需改动即可切换; FERRETDB_POSTGRESQL_URL是 FerretDB 连接后端的核心环境变量,与仓库 flags.md 中的--postgresql-url配置一一对应,Acorn 通过@{service.postgres.xxx}模板变量自动注入;- Acorn 将复杂的服务、密钥、容器、任务与配置封装为应用级抽象,一份 Acornfile 即可承载完整应用,配合 FerretDB 的开源属性,整套方案从应用层到数据库层都不存在厂商锁定问题。
无论你正在快速原型验证,还是构建面向生产的应用,都可以参考本指南用 Acorn 将 FerretDB 应用一键部署到云原生环境。更多 FerretDB 能力可查阅仓库内 docs 目录 与 安装文档。
- 后端
- 数据库
- 文档数据库
【免费下载链接】FerretDB
A truly Open Source MongoDB alternative
相关推荐
实战:使用Zappa部署Flask和Django应用
实战:使用Zappa部署Flask和Django应用 本文详细介绍了使用Zappa无服务器框架部署Flask和Django应用到AWS Lambda的完整配置指
云原生DevOps后端使用 Waitress 部署 Flask 应用:纯 Python WSGI 服务器实战指南
使用 Waitress 部署 Flask 应用:纯 Python WSGI 服务器实战指南 Waitress 是一个纯 Python 实现的 WSGI 服务器,
后端Web框架使用 Crossplane 与 OAM 在 Kubernetes 上管理云原生应用:安装、部署与实战
使用 Crossplane 与 OAM 在 Kubernetes 上管理云原生应用:安装、部署与实战 本文以 Kubernetes 云原生基础设施为背景,系统介
教程云原生容器编排
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考