NVIDIA Holoscan SDK v2.9.0

打包 Holoscan 应用程序

作为 Holoscan CLI 的一部分包含的 Holoscan 应用程序打包器,以 package 命令的形式,允许您将 Holoscan 应用程序打包到符合 HAP 标准 的容器镜像中,以便分发和部署。

依赖项

确保在要运行 CLI 的环境中安装以下组件

  • 带有 Docker 的 NVIDIA Container Toolkit

    • 开发者套件 (aarch64):已包含在 IGX Software 和 JetPack 中

    • x86_64:已使用 NVIDIA Container Toolkit 1.13.3 和 Docker v24.0.1 进行测试

  • Docker BuildX 插件

    1. 检查是否已安装

      复制
      已复制!
                  

      $ docker buildx version github.com/docker/buildx v0.10.5 86bdced

    2. 如果未安装,请根据 官方文档 运行以下命令

      复制
      已复制!
                  

      # Install Docker dependencies sudo apt-get update sudo apt-get install ca-certificates curl gnupg # Add Docker Official GPG Key sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpg # Configure Docker APT Repository echo \ "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # Install Docker BuildX Plugin sudo apt-get update sudo apt-get install docker-buildx-plugin

  • QEMU (可选)

    • 用于打包与主机架构不同的容器镜像(例如:x86_64 -> arm64)。

CLI 安装

Holoscan CLI 可作为 PyPI 包使用,可以使用以下命令安装

复制
已复制!
            

$ pip install holoscan-cli

验证安装

复制
已复制!
            

$ holoscan version

提示

始终先安装 Holoscan SDK,然后在需要同时安装 SDK 和 CLI 的系统上安装 Holoscan CLI。这可确保正确安装所有必要的依赖项和软件包,从而使 Holoscan CLI 能够顺利运行。

提示

打包器功能也在 cli_packagervideo_replayer_distributed 示例中进行了说明。

启动容器时,需要额外的参数才能在 NGC Holoscan 容器内启用 Holoscan 应用程序的打包。有关更多详细信息,请参阅 NGC Holoscan 容器页面。

  1. 在访问数据时,请尽可能使用 HAP 环境变量。例如

    让我们看一下分布式视频重放器示例(examples/video_replayer_distributed)。

    • 使用应用程序配置文件

      main 函数中,我们使用默认配置文件调用 app->config(config_path) 函数。app->config(...) 检查应用程序是否首先使用 --config 参数执行。如果设置了 --config,则该方法使用来自 --config 参数的配置文件。否则,它会检查是否设置了环境变量 HOLOSCAN_CONFIG_PATH,并将该值用作源。如果两者均未设置,则使用默认配置文件 (config_path)。

      复制
      已复制!
                  

      int main(int argc, char** argv) { // Get the yaml configuration file auto config_path = std::filesystem::canonical(argv[0]).parent_path(); config_path /= std::filesystem::path("video_replayer_distributed.yaml"); auto app = holoscan::make_application<DistributedVideoReplayerApp>(); app->config(config_path); app->run(); return 0; }

      main 函数中,我们使用默认配置文件调用 app.config(config_file_path) 函数。app.config(...) 方法检查应用程序是否首先使用 --config 参数执行。如果设置了 --config,则该方法使用来自 --config 参数的配置文件。否则,它会检查是否设置了环境变量 HOLOSCAN_CONFIG_PATH,并将该值用作源。如果两者均未设置,则使用默认配置文件 (config_file_path)。

      复制
      已复制!
                  

      def main(): input_path = get_input_path() config_file_path = os.path.join(os.path.dirname(__file__), "video_replayer_distributed.yaml") logging.info(f"Reading application configuration from{config_file_path}") app = DistributedVideoReplayerApp(input_path) app.config(config_file_path) app.run()

    • 使用环境变量 HOLOSCAN_INPUT_PATH 进行数据输入

      Fragment1 中,我们尝试使用 HOLOSCAN_INPUT_PATH 中定义的值设置输入视频目录。当我们实例化新的视频流重放器操作器时,我们从 from_config("replayer") 调用中传入所有配置值。此外,如果 HOLOSCAN_INPUT_PATH 中的值可用,我们将使用该值创建的 args 作为最后一个参数包含在内,以覆盖 directory 设置。

      复制
      已复制!
                  

      class Fragment1 : public holoscan::Fragment { public: void compose() override { using namespace holoscan; ArgList args; auto data_directory = std::getenv("HOLOSCAN_INPUT_PATH"); if (data_directory != nullptr && data_directory[0] != '\0') { auto video_directory = std::filesystem::path(data_directory); video_directory /= "racerx"; args.add(Arg("directory", video_directory.string())); HOLOSCAN_LOG_INFO("Using video from {}", video_directory.string()); } auto replayer = make_operator<ops::VideoStreamReplayerOp>("replayer", from_config("replayer"), args); add_operator(replayer); } };

      Fragment1 中,我们尝试使用 HOLOSCAN_INPUT_PATH 中定义的值设置输入视频目录。当我们实例化新的视频流重放器操作器时,我们传入 video_path 以及在配置文件中找到的所有 replayer 配置。

      复制
      已复制!
                  

      class Fragment1(Fragment): def __init__(self, app, name): super().__init__(app, name) def __init__(self, app, name): super().__init__(app, name) def compose(self): # Set the video source video_path = self._get_input_path() logging.info( f"Using video from{video_path}" ) # Define the replayer and holoviz operators replayer = VideoStreamReplayerOp( self, name="replayer", directory=video_path, **self.kwargs("replayer") ) self.add_operator(replayer) def _get_input_path(self): path = os.environ.get( "HOLOSCAN_INPUT_PATH", os.path.join(os.path.dirname(__file__), "data") ) return os.path.join(path, "racerx")

  2. 包含 YAML 配置文件,如 应用程序运行器配置 页面中所述。

  3. 使用 holoscan package 命令创建 HAP 容器镜像。例如

    复制
    已复制!
                

    holoscan package --platform x64-workstation --tag my-awesome-app --config /path/to/my/awesome/application/config.yaml /path/to/my/awesome/application/

非分布式应用程序的附加要求

除了使用 HAP 定义的环境变量之外,应用程序在打包非分布式应用程序时还必须处理 —config 参数的解析。

  • 处理 --config 参数

    定义一个 parse_arguments 函数来处理数据路径和配置文件路径的解析

    复制
    已复制!
                

    bool parse_arguments(int argc, char** argv, std::string& data_path, std::string& config_path) { static struct option long_options[] = { {"data", required_argument, 0, 'd'}, {"config", required_argument, 0, 'c'}, {0, 0, 0, 0}}; while (int c = getopt_long(argc, argv, "d:c:", long_options, NULL)) { if (c == -1 || c == '?') break; switch (c) { case 'c': config_path = optarg; break; case 'd': data_path = optarg; break; default: holoscan::log_error("Unhandled option '{}'", static_cast<char>(c)); return false; } } return true; }

    main 函数中使用上面定义的 parse_arguments() 函数

    复制
    已复制!
                

    int main(int argc, char** argv) { // Parse the arguments std::string config_path = ""; std::string data_directory = ""; if (!parse_arguments(argc, argv, data_directory, config_path)) { return 1; } if (data_directory.empty()) { // Get the input data environment variable auto input_path = std::getenv("HOLOSCAN_INPUT_PATH"); if (input_path != nullptr && input_path[0] != '\0') { data_directory = std::string(input_path); } else { HOLOSCAN_LOG_ERROR( "Input data not provided. Use --data or set HOLOSCAN_INPUT_PATH environment variable."); exit(-1); } } if (config_path.empty()) { // Get the input data environment variable auto config_file_path = std::getenv("HOLOSCAN_CONFIG_PATH"); if (config_file_path == nullptr || config_file_path[0] == '\0') { auto config_file = std::filesystem::canonical(argv[0]).parent_path(); config_path = config_file / std::filesystem::path("app-config.yaml"); } else { config_path = config_file_path; } } auto app = holoscan::make_application<App>(); HOLOSCAN_LOG_INFO("Using configuration file from {}", config_path); app->config(config_path); HOLOSCAN_LOG_INFO("Using input data from {}", data_directory); app->set_datapath(data_directory); app->run(); return 0; }

    定义一个 parse_arguments 函数来解析参数

    复制
    已复制!
                

    def parse_arguments() -> argparse.Namespace: parser = argparse.ArgumentParser(description="My Application") parser.add_argument( "--data", type=str, required=False, default=os.environ.get("HOLOSCAN_INPUT_PATH", None), help="Input dataset", ) parser.add_argument( "--config", type=str, required=False, default=os.environ.get( "HOLOSCAN_CONFIG_PATH", os.path.join(os.path.dirname(__file__), "app-config.yaml"), ), help="Application configurations", ) args, _ = parser.parse_known_args() return args

    使用上面定义的 parse_arguments() 解析参数并启动应用程序

    复制
    已复制!
                

    if __name__ == "__main__": args = parse_arguments() if args.data is None: logger.error( "Input data not provided. Use --data or set HOLOSCAN_INPUT_PATH environment variable." ) sys.exit(-1) app = MyApp(args.data) app.config(args.config) app.run()

使用 Holoscan 打包器时的常见问题

DNS 名称解析错误

Holoscan 打包器可能无法在特定的网络环境中解析主机名,并可能显示类似于以下的错误

复制
已复制!
            

curl: (6) Could not resolve host: github.com. Failed to establish a new connection:: [Errno -3] Temporary failure in name solution...

要解决这些错误,请编辑 /etc/docker/daemon.json 文件以包含 dnsdns-serach 字段,如下所示

复制
已复制!
            

{ "default-runtime": "nvidia", "runtimes": { "nvidia": { "args": [], "path": "nvidia-container-runtime" } }, "dns": ["IP-1", "IP-n"], "dns-search": ["DNS-SERVER-1", "DNS-SERVER-n"] }

您可能需要咨询您的 IT 团队,并将 IP-xDNS-SERVER-x 替换为提供的值。

打包的 Holoscan 应用程序容器镜像可以使用 Holoscan 应用程序运行器 运行

复制
已复制!
            

holoscan run -i /path/to/my/input -o /path/to/application/generated/output my-application:1.0.1

由于打包的 Holoscan 应用程序容器镜像符合 OCI 标准,因此它们也与 DockerKubernetescontainerd 兼容。

每个打包的 Holoscan 应用程序容器镜像都包含用于提取嵌入式应用程序、清单文件、模型等的工具。要访问该工具并查看所有可用选项,请运行以下命令

复制
已复制!
            

docker run -it my-container-image[:tag] help

该命令应打印以下内容

复制
已复制!
            

USAGE: /var/holoscan/tools [command] [arguments]... Command List extract --------------------------- Extract data based on mounted volume paths. /var/run/holoscan/export/app extract the application /var/run/holoscan/export/config extract app.json and pkg.json manifest files and application YAML. /var/run/holoscan/export/models extract models /var/run/holoscan/export/docs extract documentation files /var/run/holoscan/export extract all of the above IMPORTANT: ensure the directory to be mounted for data extraction is created first on the host system. and has the correct permissions. If the directory had been created by the container previously with the user and group being root, please delete it and manually create it again. show ----------------------------- Print manifest file(s): [app|pkg] to the terminal. app print app.json pkg print pkg.json env ------------------------- Print all environment variables to the terminal.

注意

这些工具也可以通过 /var/holoscan/tools 在 Docker 容器内访问。

例如,运行以下命令以提取清单文件和应用程序配置文件

复制
已复制!
            

# create a directory on the host system first mkdir -p config-files # mount the directory created to /var/run/holoscan/export/config docker run -it --rm -v $(pwd)/config-files:/var/run/holoscan/export/config my-container-image[:tag] extract # include -u 1000 if the above command reports a permission error docker run -it --rm -u 1000 -v $(pwd)/config-files:/var/run/holoscan/export/config my-container-image[:tag] extract # If the permission error continues to occur, please check if the mounted directory has the correct permission. # If it doesn't, please recreate it or change the permissions as needed. # list files extracted ls config-files/ # output: # app.json app.yaml pkg.json

上一篇 创建分布式应用程序
下一篇 创建操作器
© 版权所有 2022-2024, NVIDIA。 上次更新时间:2025 年 1 月 27 日。