应用镜像制作与导入指南
概述
本指南介绍如何在开发环境中制作应用 Docker 镜像,打包为 .neoapp 应用包,
并导入到 NeoRuntime 设备上运行。
完整流程包括:
准备应用文件(Dockerfile、app.yaml、app.py)
构建 Docker 镜像
导出镜像并打包为
.neoapp应用包通过 Web Console 应用安装向导导入,或使用命令行导入
Tip
交付产物是单文件 .neoapp 应用包(tar.gz,内含 app.yaml 与
image.tar)。在 Web Console 上传一个 .neoapp 即可完成安装,
服务端自动解出配置与镜像;也可以只上传裸镜像 tar,由向导表单生成配置。
步骤 1: 准备应用文件
创建应用目录并准备以下核心文件。app.yaml 会随镜像一起打进 .neoapp
应用包,上载后仍可在安装向导中微调;只上传裸镜像时才完全依赖向导表单生成配置。
创建应用目录
mkdir my-app && cd my-app
应用代码(app.py)
#!/usr/bin/env python3
"""My Application"""
import signal
from neoruntime_ipc_sdk import InferenceClient, EventClient, DeviceClient, Config
class MyApp:
def __init__(self):
self.running = True
self.app_id = Config.get_app_id()
self.inference = InferenceClient()
self.events = EventClient()
self.device = DeviceClient()
signal.signal(signal.SIGINT, self.signal_handler)
signal.signal(signal.SIGTERM, self.signal_handler)
def signal_handler(self, signum, frame):
self.running = False
def run(self):
try:
for frame, result in self.inference.subscribe(
stream="main", model="person_v1", fps=10
):
if not self.running:
break
person_count = result.count_by_label("person")
if person_count > 0:
self.events.publish(f"app/{self.app_id}/detection", {
"count": person_count,
})
except Exception as e:
print(f"[{self.app_id}] Error: {e}")
finally:
self.inference.close()
self.events.close()
self.device.close()
if __name__ == "__main__":
MyApp().run()
Dockerfile
FROM python:3.9-slim
LABEL maintainer="your@email.com"
# 安装 NeoRuntime Python SDK(已发布到 PyPI;锁定版本保证可重复构建,
# 升级 SDK 时同步修改此处版本号)
RUN python -m pip install --no-cache-dir \
"neoruntime-ipc-sdk==0.7.4"
WORKDIR /app
COPY app.py app.yaml /app/
RUN mkdir -p /app/logs /app/data
# 非 root 用户(推荐)
RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app
USER appuser
ENV APP_ID=my_app
ENV DEBUG=0
ENV LOG_LEVEL=INFO
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD python3 -c "import sys; sys.exit(0)"
CMD ["python3", "app.py"]
应用清单(app.yaml)
最小可用的 app.yaml 如下(字段详解见 app_yaml_reference):
apiVersion: v1
kind: Application
metadata:
id: my_app
name: My Application
version: 1.0.0
description: Person detection demo
spec:
image: my-app:1.0.0
permissions:
video:
- cam0_main.raw
inference:
models: ["person_v1"]
Note
官方应用仓库 neoruntime-apps
的 templates/basic/ 提供完整 manifest 模板,各 example/showcase 目录
也可作为参考。
步骤 2: 构建 Docker 镜像
在应用目录下执行构建命令:
docker build -t my-app:1.0.0 .
构建参数说明:
-t my-app:1.0.0— 镜像名称和标签,需与app.yaml中的spec.image一致.— 构建上下文为当前目录
验证镜像构建成功:
docker images | grep my-app
Note
如果应用需要额外依赖,可在目录中添加 requirements.txt 并在 Dockerfile 中加入
RUN pip install -r requirements.txt。如果需要离线或可重复构建,建议先构建 SDK
wheel,将 neoruntime_ipc_sdk-*.whl 复制进镜像,再安装这个本地 wheel;亦可从
源码安装并钉住发布 tag:
git+https://github.com/camthink-ai/neoruntime-sdks.git@v0.7.4#subdirectory=python。
步骤 3: 导出镜像并打包 .neoapp
将构建好的镜像导出为 tar 文件(打包时统一命名为 image.tar):
docker save my-app:1.0.0 -o image.tar
然后将 app.yaml 与 image.tar 组装为 .neoapp 应用包:
PKG=my-app-1.0.0-arm64
mkdir -p "$PKG"
cp app.yaml "$PKG/"
mv image.tar "$PKG/"
(cd "$PKG" && sha256sum app.yaml image.tar > SHA256SUMS)
tar -czf "$PKG.neoapp" "$PKG"
.neoapp 本质是 tar.gz:包内需含 app.yaml 与 image.tar``(放在根下
或唯一子目录中均可),``SHA256SUMS 等其余文件会被安装端忽略。gzip 同时承担
传输压缩,无需再单独压缩。
Note
官方应用仓库 neoruntime-apps
的 scripts/build_app.sh <应用目录> 一键完成 docker build → save →
.neoapp 打包;其 Releases 还提供预构建的 showcase 应用包
(*-arm64.neoapp)可直接下载导入。
步骤 4: Web Console 导入(推荐)
Web Console 的 导入应用 对话框共三屏:选择来源 → 配置应用 → 安装进度。
Note
单一上传槽支持的文件:.neoapp 应用包(推荐,服务端自动解出
app.yaml 与镜像),或裸镜像 .tar / .tar.gz / .tgz,
最大 2GB。
打开导入对话框
打开浏览器,访问设备 Web Console:
http://<device-ip>:8080导航到 应用管理 页面
点击 导入应用 卡片,打开导入对话框
第 1 屏 — 选择来源
本地上传 (默认,离线设备推荐):拖入或选择一个
.neoapp应用包 (或裸镜像 tar),上传过程显示进度条镜像仓库:输入 Docker 镜像地址(如
docker.io/library/nginx:latest), 设备需可访问网络
上传 .neoapp 后,服务端自动解出包内 app.yaml 与镜像,后续表单以包内
app.yaml 为准,可在下一屏微调;仅上传裸镜像时,配置完全由表单生成。
第 2 屏 — 配置应用
单页表单按分区组织(侧栏分区导航,支持 表单/YAML 双视图切换):
基本信息:应用 ID、名称、版本、描述
资源:CPU / 内存限制、共享内存(零拷贝视频流需要)、开机自启、重启策略
模型:设备上可用的推理模型与最大 QPS
权限:视频流、事件主题(支持通配符)、网络模式、设备控制
高级 (可选):环境变量、卷挂载
第 3 屏 — 安装进度
提交后显示安装任务进度;安装完成后应用出现在应用列表中。
步骤 5: 命令行导入(备选方案)
如果无法使用 Web Console,可先将 .neoapp 应用包通过 SCP 传输到设备,
解包后用 aipc-cli 安装。
传输应用包到设备:
scp my-app-1.0.0-arm64.neoapp root@<device-ip>:/tmp/
然后 SSH 登录设备:
# 解包 .neoapp(得到 app.yaml 与 image.tar)
tar xzf /tmp/my-app-1.0.0-arm64.neoapp -C /tmp/
# 安装应用(位置参数:manifest 在前,镜像 tar 在后)
aipc-cli app install /tmp/my-app-1.0.0-arm64/app.yaml \
/tmp/my-app-1.0.0-arm64/image.tar
# 启动应用
aipc-cli app start my_app
# 查看应用状态
aipc-cli app list
# 查看应用日志
aipc-cli app logs my_app
也可以使用 gRPC 客户端直接调用 app-manager 服务:
grpcurl -plaintext \
-d '{"manifest_path": "/tmp/my-app-1.0.0-arm64/app.yaml",
"image_path": "/tmp/my-app-1.0.0-arm64/image.tar"}' \
unix:///run/aipc/app-manager.sock \
appmanager.AppManager/InstallApp
应用清单参考(app.yaml)
以下是 app.yaml 各字段的详细说明。
元数据(metadata)
字段 |
必填 |
说明 |
|---|---|---|
id |
是 |
应用唯一标识符(小写字母、数字、下划线) |
name |
是 |
应用显示名称 |
version |
是 |
语义化版本号(如 1.0.0) |
description |
是 |
应用描述 |
author |
否 |
作者名称 |
否 |
联系邮箱 |
资源限制(spec.resources)
字段 |
默认值 |
说明 |
|---|---|---|
cpu |
— |
CPU 限制,如 |
memory |
— |
内存限制,如 |
shm |
false |
是否启用共享内存(零拷贝视频流需要) |
权限配置(spec.permissions)
视频流权限(video)
指定应用可访问的视频流:
cam0_main.raw— 原始视频流(通过 SHM 零拷贝)cam0_sub.raw— 子码流原始视频cam0_main— 编码视频流(通过 Unix socket)
Note
权限层与 SDK 客户端的流命名不同层:manifest 权限按平台侧命名(如
cam0_main.raw)申请;SDK 调用(FdMediaClient.subscribe /
InferenceClient.subscribe)按设备实际暴露的流 ID main / sub
订阅。
AI 推理权限(inference)
字段 |
默认值 |
说明 |
|---|---|---|
models |
[] |
可使用的模型列表 |
max_qps |
— |
最大 QPS 限制 |
max_concurrent |
— |
最大并发推理数 |
事件总线权限(events)
publish— 可发布的事件主题(支持通配符*)subscribe— 可订阅的事件主题(支持通配符*)
设备控制权限(device)
字段 |
默认值 |
说明 |
|---|---|---|
light |
false |
补光灯控制 |
ir_cut |
false |
红外滤光片控制 |
ptz |
false |
云台控制 |
lens |
false |
镜头变焦/对焦控制 |
网络权限(network)
mode— 网络模式:"isolated"``(默认)或 ``"host"outbound— 允许的出站地址(isolated 模式下)
生命周期配置
字段 |
默认值 |
说明 |
|---|---|---|
autostart |
false |
系统启动时自动启动 |
restart_policy |
“no” |
重启策略:always / on-failure / no |
restart_max_retries |
3 |
最大重启次数(on-failure 时) |
健康检查(healthcheck)
字段 |
默认值 |
说明 |
|---|---|---|
enabled |
false |
启用健康检查 |
interval |
30s |
检查间隔 |
timeout |
5s |
超时时间 |
retries |
3 |
失败重试次数 |
常见问题
镜像构建失败
错误: failed to solve: failed to fetch
检查网络连接,如需代理:
docker build --build-arg HTTP_PROXY=http://proxy:port \
--build-arg HTTPS_PROXY=http://proxy:port \
-t my-app:1.0.0 .
应用包过大
.neoapp 本身已是 gzip 压缩。若仍然过大,检查镜像是否带入了不必要的
层或缓存(Dockerfile 使用 --no-cache-dir 安装依赖、多阶段构建等):
# 查看各层体积,定位大层
docker history my-app:1.0.0
导入失败
错误: Failed to import image to containerd
# 检查 containerd 状态
systemctl status containerd
# 手动导入测试
ctr -n aipc images import /tmp/my-app-1.0.0-arm64/image.tar
权限错误
错误: Permission denied
chmod 644 /tmp/my-app-1.0.0-arm64/app.yaml /tmp/my-app-1.0.0-arm64/image.tar