使用 shuttle-axum 在 Shuttle 上部署 Axum 应用:零配置 Web 服务实战指南
云原生后端DevOps【免费下载链接】shuttleBuild ship backends without writing any infrastructure files.项目地址https://gitcode.com/gh_mirrors/sh/shuttle点击查看免费下载Axum 是 Rust 生态中广受欢迎的异步 Web 框架而shuttle-axum是 Shuttle 为其提供的官方服务集成层你只需写一个返回Router的异步函数加上#[shuttle_runtime::main]宏就能在 Shuttle 平台上直接运行和部署无需手写任何基础设施配置。本文以 services/shuttle-axum/README.md 为核心骨架结合仓库内源码逐层拆解其版本选择、工作原理与完整的上手路径读完你即可独立完成一个 Axum 服务的本地调试与云端部署。一、shuttle-axum 是什么shuttle-axum是 Shuttle 仓库中众多框架集成Service Integration之一位于 services/shuttle-axum作用是让 Axum 应用无缝接入 Shuttle 的运行时模型。在 Shuttle 的架构中任何可部署的服务都必须实现Servicetrait定义在 service/src/lib.rs其核心是这样一个方法/// This function is run exactly once on startup of a deployment. /// /// The passed [SocketAddr] receives proxied HTTP traffic from your Shuttle subdomain (or custom domain). /// Binding to the address is only relevant if this service is an HTTP server. async fn bind(mut self, addr: SocketAddr) - Result(), error::Error;也就是说Shuttle 运行时会为每次部署分配一个SocketAddr服务方需要把自己的 HTTP 服务器绑定到这个地址上。shuttle-axum做的正是把axum::Router包装起来、并实现Service::bind让你可以像使用普通库一样使用 Axum 的全部能力同时自动获得 Shuttle 的资源供给、日志、部署链路。Shuttle 支持的框架不止 Axum还有 Actix Web、Rocket、Poem、Warp、Tower 等完整列表见 services/README.md其中明确指出编写新的框架集成只需为该框架实现Servicetrait 即可。而本文主角shuttle-axum当前版本为 0.57.0见 services/shuttle-axum/Cargo.toml与整个工作区版本保持一致。二、版本支持与 Feature 选择原文档明确了两点版本事实Axum 0.8 是默认版本Axum 0.7 通过 feature flag 支持。原文档给出的 0.7 接入配置如下toml,ignore代码块需原样保留到你的Cargo.tomlaxum 0.7.3 shuttle-axum { version ..., default-features false, features [axum-0-7] }这里有两个关键动作一是通过default-features false关闭默认的axum特性二是显式开启axum-0-7特性。配套地在依赖里固定你自己的axum 0.7.3保证用户代码、shuttle-axum 内部与 axum 三方版本匹配。从源码可以印证这一设计。查看 services/shuttle-axum/Cargo.toml[dependencies] axum { version 0.8.1, optional true } axum-0-7 { package axum, version 0.7.3, optional true } shuttle-runtime { path ../../runtime, version 0.57.0, default-features false } [features] default [axum] axum-0-7 [dep:axum-0-7]可见axum-0-7本质上是对axum0.7.3 这个包的重新命名引入而在 services/shuttle-axum/src/lib.rs 中通过cfg完成了版本别名#[cfg(feature axum)] pub use axum; #[cfg(feature axum-0-7)] pub use axum_0_7 as axum;两个版本的具体对照如下场景依赖写法说明默认Axum 0.8shuttle-axum 0.57.0直接使用默认特性即可需要 Axum 0.7axum 0.7.3shuttle-axum { version ..., default-features false, features [axum-0-7] }同时关闭默认特性、开启 0.7 特性三、快速开始Hello World 示例原文档给出的最小可运行示例为rust,ignoreuse axum::{routing::get, Router}; async fn hello_world() - static str { Hello, world! } #[shuttle_runtime::main] async fn axum() - shuttle_axum::ShuttleAxum { let router Router::new().route(/, get(hello_world)); Ok(router.into()) }这个示例与普通 Axum 程序相比只发生了两处变化却蕴含了整个 Shuttle 的接入模型不再自己创建tokio::net::TcpListener并调用axum::serve手动绑定端口——监听地址由 Shuttle 运行时注入入口函数从#[tokio::main] async fn main()换成#[shuttle_runtime::main] async fn axum()返回值类型是shuttle_axum::ShuttleAxum。对照仓库根目录 README.md 中的普通 Axum vs Shuttle Axum改写示例二者唯一区别正是去掉了TcpListener::bind(127.0.0.1:3000)与axum::serve的手动绑定逻辑。这正是 Shuttle 的核心价值删除所有基础设施样板代码聚焦业务本身。3.1 初始化项目用 Shuttle CLI 即可生成带 Axum 模板的工程骨架参考 runtime/README.mdshuttle init --template axum my-axum-app生成的my-axum-app是一个二进制 crate其Cargo.toml中会包含以下关键依赖同样见 runtime/README.mdaxum 0.8.1 shuttle-axum 0.57.0 shuttle-runtime 0.57.0 tokio 1.28.23.2 本地运行在项目目录下执行shuttle run应用会在默认端口 8000 启动随后可用 curl 验证curl http://localhost:8000/ # Hello, world!3.3 云端部署shuttle deploy部署完成后服务会分配到一个*.shuttle.app子域名下见 runtime/README.mdcurl https://my-axum-app-0000.shuttle.app/ # Hello, world!四、源码解析AxumService 与 ShuttleAxum 的底层实现4.1 AxumServiceRouter 的 Shuttle 包装services/shuttle-axum/src/lib.rs 定义了唯一的公开结构体/// A wrapper type for [axum::Router] so we can implement [shuttle_runtime::Service] for it. pub struct AxumService(pub Router);它是axum::Router的元组包装tuple struct目的是让Router能够实现shuttle_runtime::Servicetrait——因为孤儿规则不允许为外部类型直接实现外部 trait包装一层即可解决。4.2 bind服务启动的最后一公里Servicetrait 的关键实现在 services/shuttle-axum/src/lib.rs#[shuttle_runtime::async_trait] impl shuttle_runtime::Service for AxumService { /// Takes the router that is returned by the user in their [shuttle_runtime::main] function /// and binds to an address passed in by shuttle. async fn bind(mut self, addr: SocketAddr) - Result(), Error { #[cfg(feature axum)] axum::serve( shuttle_runtime::tokio::net::TcpListener::bind(addr) .await .map_err(CustomError::new)?, self.0, ) .await .map_err(CustomError::new)?; #[cfg(feature axum-0-7)] axum_0_7::serve( shuttle_runtime::tokio::net::TcpListener::bind(addr) .await .map_err(CustomError::new)?, self.0, ) .await .map_err(CustomError::new)?; Ok(()) } }可以拆解为三层地址注入addr由 Shuttle 运行时在启动阶段通过SHUTTLE_RUNTIME_IP、SHUTTLE_RUNTIME_PORT等环境变量解析而来见 runtime/src/rt.rs监听与托管使用shuttle_runtime::tokio的TcpListener绑定该地址再交由axum::serve驱动由用户返回的Routerself.0错误归一绑定与 serve 阶段的错误统一通过CustomError::new包装。CustomError本质是anyhow::Error的类型别名见 service/src/error.rs最终进入service::Error的Custom变体。注意两个cfg分支分别对应 0.8 与 0.7 两种 Axum 版本与第二章的 feature 设计一一对应。4.3 From 一行.into()services/shuttle-axum/src/lib.rs 提供了从Router到AxumService的转换impl FromRouter for AxumService { fn from(router: Router) - Self { Self(router) } }这正是示例代码里Ok(router.into())得以成立的原因。注意Router此处根据 feature 分别解析为axum::Router或axum_0_7::Router见同文件 L10-L13。4.4 ShuttleAxum返回值类型别名services/shuttle-axum/src/lib.rs 定义了对外暴露的返回值别名#[doc include_str!(../README.md)] pub type ShuttleAxum ResultAxumService, Error;即ResultAxumService, shuttle_runtime::Error。Error的定义位于 service/src/error.rs涵盖 IO 错误、数据库错误、构建/绑定阶段 panic、字符串插值错误与自定义错误等类别。五、#[shuttle_runtime::main]宏展开背后的执行流程#[shuttle_runtime::main]属性宏的实现位于 codegen/src/shuttle_main.rs它负责把用户的main函数改造成 Shuttle 的加载-运行模型。从源码看展开后的代码结构为fn main() { // manual expansion of #[tokio::main] ::shuttle_runtime::tokio::runtime::Builder::new_multi_thread() .enable_all() .build() .unwrap() .block_on(async { ::shuttle_runtime::__internals::start( __loader, __runner, env!(CARGO_CRATE_NAME), env!(CARGO_PKG_VERSION), ) .await; }) }要点如下Tokio 运行时宏会手动展开#[tokio::main]创建多线程运行时见 codegen/src/shuttle_main.rs__loader负责收集函数参数上的资源注解如#[shuttle_shared_db::Postgres]将其序列化为资源请求__runner负责反序列化资源供给结果、初始化资源对象如连接池最终调用你的业务函数用户函数重命名无论原函数名是什么甚至可以叫main宏都会将其重命名为__shuttle_原名避免与真实的fn main冲突见 codegen/src/shuttle_main.rs返回类型校验宏在编译期强制要求函数返回一等公民服务类型或Resultimpl shuttle_service::Service, shuttle_runtime::Error否则直接编译报错见 codegen/src/shuttle_main.rsShuttleAxum正是一等公民类型之一。运行时侧start函数runtime/src/start.rs负责参数校验、tracing 日志初始化随后进入 runtime/src/rt.rs 中rt::start的四个阶段Loading / Provisioning 阶段加载 Secrets、通过 API 供给数据库等资源失败时返回 101/111/121/131/132 等非标准退出码Resource Init 阶段调用runner.run把资源转化为最终对象失败返回 151Running 阶段调用service.bind(service_addr)启动服务并监听 SIGTERM/SIGINTUnix或 CtrlC/CtrlBreakWindows实现优雅退出中断返回 10。整个调用链清晰展示了用户代码与平台运行时之间的边界你只管返回 Router从端口分配到资源供给全部由运行时接管。六、进阶为 Axum 应用接入数据库与 Secrets6.1 一行接入 PostgreSQLShuttle 的一行资源供给在 Axum 应用中同样适用。仓库根目录 README.md 给出了完整的 Postgres 接入示例use axum::{routing::get, Router}; async fn hello_world() - static str { Hello, world! } #[shuttle_runtime::main] async fn main( #[shuttle_shared_db::Postgres] pool: sqlx::PgPool, ) - shuttle_axum::ShuttleAxum { pool.execute(include_str!(../schema.sql)) .await .expect(failed to run migrations); let router Router::new().route(/, get(hello_world)); Ok(router.into()) }只需在入口函数参数上添加#[shuttle_shared_db::Postgres]注解运行时就会在__loader阶段自动请求供给数据库并在__runner阶段把sqlx::PgPool注入你的函数——shuttle deploy一次即可同时上线应用 数据库。6.2 Secrets 注入Axum 服务同样可以读取 Shuttle 的 Secrets。在项目根目录放一个Secrets.toml并加入.gitignore然后在入口函数注入SecretStore参考 runtime/src/plugins.rs#[shuttle_runtime::main] async fn main( #[shuttle_runtime::Secrets] secrets: SecretStore ) - ShuttleAxum { // get secret defined in Secrets.toml file. let secret secrets.get(MY_API_KEY).unwrap(); let router Router::new() .route(/, || async move { format!(My secret is: {}, secret) }); Ok(router.into()) }Secrets 在运行时通过client.get_secrets从 Shuttle API 拉取见 runtime/src/rt.rs并支持在资源注解字符串中以{secrets.xxx}形式做插值宏展开处可见strfmt的调用见 codegen/src/shuttle_main.rs。七、生态参照shuttle-axum 在集成层中的位置shuttle-axum的实现模式并非孤例。以 services/shuttle-tower/src/lib.rs 为例它同样定义TowerServiceT包装类型、实现Service::bind内部改用hyper::Server::bindtower::make::Shared并配套FromT与ShuttleTowerT别名。对比可见集成层包装类型bind 内部实现shuttle-axumAxumService(Router)axum::serve0.8/0.7 双分支shuttle-towerTowerServiceThyper::Servertower::make::Shared也就是说理解shuttle-axum的包装 bind From 类型别名四件套就等于掌握了 Shuttle 所有 Web 框架集成的通用范式需要时也可以依照 services/README.md 的指引为自己偏好的框架编写自定义集成。八、常见问题与排查提示结合运行时源码接入shuttle-axum时常遇以下几类问题编译报错shuttle_runtime::main functions need to return a service入口函数返回类型不是ShuttleAxum这类一等公民类型。宏会对ReturnType::Default与非法类型直接 emit 编译错误见 codegen/src/shuttle_main.rs按提示改为- shuttle_axum::ShuttleAxum即可。本地shuttle run时提示环境变量缺失运行时要求SHUTTLE_ENV等变量存在见 runtime/src/start.rs请使用shuttle run启动而非直接cargo run。遇到--port过时参数报错较老的命令行参数已被移除提示信息会明确要求升级 Shuttle CLI见 runtime/src/start.rs。版本不匹配若使用 Axum 0.7务必同时满足依赖里axum 0.7.3shuttle-axum关闭默认特性并开启axum-0-7两个条件否则可能出现类型或版本冲突。总结shuttle-axum用极小的代码量一个包装结构体、一个bind实现、一个From转换和一个类型别名完成了 Axum 与 Shuttle 运行时的深度对接默认随新版 Axum 0.8同时为既有 0.7 项目保留迁移通道#[shuttle_runtime::main]宏在编译期接管入口函数运行时则在加载、供给、初始化、绑定四个阶段按部就班地启动服务。从shuttle init --template axum到shuttle run再到shuttle deploy你无需接触任何端口分配、TLS、反向代理或资源管理细节这正是 Shuttle Build ship backends without writing any infrastructure files 这一核心承诺在 Axum 生态中的落地体现。赞分享云原生后端DevOps【免费下载链接】shuttleBuild ship backends without writing any infrastructure files.项目地址https://gitcode.com/gh_mirrors/sh/shuttle点击查看免费下载相关推荐使用 shuttle-actix-web 在 Shuttle 上部署 Actix Web 应用使用 shuttle actix web 在 Shuttle 上部署 Actix Web 应用 导读 shuttle actix web https://lin云原生后端DevOps在 Vercel 上部署 Rust Axum基于 vercel_runtime 的流式响应与 API 实战在 Vercel 上部署 Rust Axum基于 vercel_runtime 的流式响应与 API 实战 本指南基于当前仓库中的 rust/axum htt示例工程前端后端告别服务孤岛用AxumTonic构建多服务gRPC应用的实战指南告别服务孤岛用AxumTonic构建多服务gRPC应用的实战指南 你是否在开发微服务时遇到过这些痛点多个gRPC服务分散部署导致运维复杂度飙升服务间通信后端RPC框架创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

选矿方向的文献综述怎么写:把“品位与回收率“这对指标讲透

选矿方向的文献综述怎么写:把“品位与回收率“这对指标讲透

选矿研究里有个绕不开的矛盾:品位与回收率互相牵制。 想提高精矿品位,往往要牺牲回收率;想把回收率拉上去,品位又容易掉。所以一篇文献只报其中一个指标,实际上等于没把结果说清。看懂这点,综述的骨架就有了…

2026/10/15 17:13:23 阅读更多 →
STM32F4移植uCOS-II实战:Keil工程配置与os_cpu核心文件详解

STM32F4移植uCOS-II实战:Keil工程配置与os_cpu核心文件详解

简介:这份资源面向嵌入式开发初学者与进阶工程师,提供将UCOS_II实时操作系统移植到STM32F407ZGT6的完整Keil工程,帮助读者理解RTOS在Cortex-M4平台上的运行机制与移植流程。压缩包共252个文件,约7.18MB,以61个c源文件与…

2026/10/15 17:13:23 阅读更多 →
青蛙跳石头:从状态设计掌握动态规划核心

青蛙跳石头:从状态设计掌握动态规划核心

我至今记得第一次在模拟训练赛里看到A. Frog Jumping这道题时的感觉——题面短得离谱,就一句“青蛙要从第一块石头跳到对岸”,配上几张石头的坐标图,乍一看好像很简单。结果我在草稿纸上画了十几分钟,贪心、模拟、暴力枚举全试了一…

2026/10/15 17:13:23 阅读更多 →

最新新闻

C#串口通信三菱PLC实战:MC协议3E帧稳定读DWord与心跳保活

C#串口通信三菱PLC实战:MC协议3E帧稳定读DWord与心跳保活

简介:本资源是一套基于C#实现串口与三菱PLC通信的完整工程实践方案,面向工业自动化领域的初/中级.NET开发者及工控系统集成工程师,解决PLC底层数据交互中单点/批量布尔量、Word/Dword数值读写、心跳监测与多线程稳定通信等核心问题。压缩包共…

2026/10/15 18:08:19 阅读更多 →
CoreNote 技术架构与自托管完全指南

CoreNote 技术架构与自托管完全指南

说明:本文所有命令、配置项与参数均取自 GitHub 仓库 zhangjianxin477/CoreNote 的 README 与 deploy/ 目录。文中凡标注「官方未明确」之处,一律以官方文档为准,不做推测。仓库的内部项目名为 Knowledge Hub,克隆地址是 knowledg…

2026/10/15 18:08:19 阅读更多 →
Android Native音频低延迟实战:从AAudio到Oboe的端到端优化

Android Native音频低延迟实战:从AAudio到Oboe的端到端优化

1. 为什么“Android native音频”不是一句空话,而是真实存在的性能瓶颈在某跨平台音视频项目中,我们曾遇到一个典型场景:用户点击“开始录音”按钮后,UI线程响应正常,但实际音频数据流从麦克风采集到App层回调之间&…

2026/10/15 18:08:19 阅读更多 →
Linux下Qt开发贪吃蛇:从环境搭建到游戏逻辑完整实战

Linux下Qt开发贪吃蛇:从环境搭建到游戏逻辑完整实战

简介:基于Linux与Qt开发的贪吃蛇小游戏完整工程,面向C/Qt初学者、Linux开发爱好者以及需要课程设计的在校生。项目实现了界面显示、游戏逻辑、等级管理、背景音乐、英雄榜和帮助等核心功能,交互完整,可用于理解Qt绘图、事件处理与…

2026/10/15 18:08:19 阅读更多 →
世界地图GeoJSON数据选型与压缩:从全球底图到国家级边界

世界地图GeoJSON数据选型与压缩:从全球底图到国家级边界

简介:这份资源面向地理信息开发、地图可视化与GIS教学研究者,提供覆盖全球国家边界的世界地图GeoJSON数据集,可用于构建交互式世界地图、开展地理空间分析或作为服务端地理信息API的数据基础。压缩包共约2000个文件,以3443个json文…

2026/10/15 18:08:19 阅读更多 →
51单片机AD转换实战:ADC0804接口设计与精度优化

51单片机AD转换实战:ADC0804接口设计与精度优化

1. 项目概述:为什么51单片机的AD转换至今仍是入门必修课你打开任何一本单片机实验指导书,翻到第三章,十有八九是“ADC0804与51单片机接口”;你在某高校电子系实验室里看到学生焊的最小系统板,杜邦线一端连着电位器旋钮…

2026/10/15 18:07:18 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/15 9:49:14 阅读更多 →