news 2026/9/24 6:31:23

使用 Acorn 打包与部署 FerretDB 应用:Python Flask 应用的云原生实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用 Acorn 打包与部署 FerretDB 应用:Python Flask 应用的云原生实战
  • 后端
  • 数据库
  • 文档数据库

【免费下载链接】FerretDB

A truly Open Source MongoDB alternative

项目地址:https://gitcode.com/gh_mirrors/fe/FerretDB
点击查看免费下载

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 生态的高度兼容意味着,任何使用pymongomongosh等 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/acorn

Windows 用户通过 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_URIDB_NAME两个环境变量由 Acornfile 注入,分别指向 FerretDB 的连接地址与数据库名;CRUD 操作(增删改查)由insert_onefind_oneupdate_onedelete_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

项目地址:https://gitcode.com/gh_mirrors/fe/FerretDB
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 6:24:47

【教程】小爱音箱刷固件开启SSH | Windows系统

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~背景说明• 电脑&#xff1a;Windows• 音箱&#xff1a;Xiaomi 智能音箱 Pro固件打补丁1. 下载仓库&#xff1a;# 克隆代码 git clone https://github.…

作者头像 李华
网站建设 2026/9/24 6:21:20

球杆平衡系统:从PID到LQR的控制算法实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/24 6:10:23

答案跟我差 1,是我错了:一次 NULL 引发的 SQL 连环坑

答案跟我差 1&#xff0c;是我错了&#xff1a;一次 NULL 引发的 SQL 连环坑一道会员留存率练习题&#xff0c;我的结果比标准答案各多 1 个人。 一开始我怀疑答案错了——毕竟第三个数字完全对得上&#xff0c;只有前两个偏。 查到最后发现是我错了&#xff0c;而且错在一个我…

作者头像 李华
网站建设 2026/9/24 6:10:06

从 Prompt Engineering 到 Context Engineering:如何构建稳定的大模型输入输出

AI 基础概念 05&#xff5c;从指令设计、上下文组装到结构化输出与结果校验 上一篇&#xff0c;我们沿着预训练、SFT、偏好优化、LoRA 和量化&#xff0c;看清模型本身可以怎样被改变。但在多数 AI 应用里&#xff0c;团队并不会先训练一个模型&#xff0c;而是先通过 API 使用…

作者头像 李华
网站建设 2026/9/24 6:07:31

AI性能测评方法论:从跑分思维到场景化工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华