分享：Ubuntu 环境下如何在 Intel xpu 上运行 ollama 驱动 Qwen3
设置 Ollama 运行环境 获取 Intel Analytics IPEX 镜像 启动 Ollama 容器 创建 shell 运行脚本 运行脚本 下载 Qwen3 模型 在 Intel Core Ultra 机器上使用 Ollama 使用命令行 使用 API 设置 Ollama 运行环境 获取 Intel Analytics IPEX 镜像 从 Docker Hub 中提取 IPEX 映像，这里使用私有仓库 docker pull hub.yiqisoft.cn/intelanalytics/ipex-llm-inference-cpp-xpu:latest 启动 Ollama 容器 创建 shell 运行脚本 由于Docker启动容器的命令比较长，所以将其保存为脚本比较方便，方便调整和重启。start-ipex-llm.sh #!/bin/bash docker run -d --restart=always \ --net=bridge \ --device=/dev/dri \ -p 11434:11434 \ -v ~/.ollama/models:/root/.ollama/models \ -e PATH=/llm/ollama:$PATH \ -e OLLAMA_HOST=0.0.0.0 \ -e no_proxy=localhost,127.0.0.1 \ -e ZES_ENABLE_SYSMAN=1 \ -e OLLAMA_INTEL_GPU=true \ -e ONEAPI_DEVICE_SELECTOR=level_zero:0 \ -e DEVICE=Arc \ --shm-size="16g" \ --memory="32G" \ --name=ipex-llm \ hub.yiqisoft.cn/intelanalytics/ipex-llm-inference-cpp-xpu:latest \ bash -c "cd /llm/scripts/ && source ipex-llm-init --gpu --device Arc && bash start-ollama.sh && tail -f /llm/ollama/ollama.log" 运行脚本 sh start-ipex-llm.sh 下载 Qwen3 模型 docker exec ipex-llm ollama pull qwen3:8b 在 Intel Core Ultra 机器上使用 Ollama 使用命令行 docker exec -it ipex-llm ollama run qwen3:8b 运行测试 root@HP:~# docker exec -it ipex-llm ollama run qwen3:8b >>> 你好 Thinking... 好的，用户发来“你好”，我需要友好回应。首先，确认用户的需求，可能是测试或开始对话。保持自然，用中文回应，避免机械感。可以加入表情符号增加亲切感，同时保持简洁。确保符合规范，不涉及敏感内 容。接下来，用轻松的语气打招呼，并邀请用户提问或分享需求。例如：“你好！😊 有什么我可以帮你的吗？” 这样既友好又开放，鼓励用户进一步互动。 ...done thinking. 你好！😊 有什么我可以帮你的吗？ >>> Send a message (/? for help) 使用 API curl -s http://localhost:11434/v1/completions -H "Content-Type: application/json" -d '{ "model": "qwen3:8b", "prompt": "你好" }' | json_pp { "choices" : [ { "finish_reason" : "stop", "index" : 0, "text" : "<think>\n嗯，用户发来“你好”，我需要回应。首先，用户可能正在测试我是不是能正常响应，或者只是随便打个招呼。我应该用友好的语气回应，同时保持简洁。\n\n接下来，我要考虑用户可能的意图。他们可能想开始一段对话，或者只是随便聊聊。不管怎样，我应该主动提供帮助，比如询问有什么我可以协助的。\n\n另外，用户可能有不同的需求，比如需要信息、帮助解决问题，或者只是想找人聊天。所以回应要开放，让用户感到被欢迎和被重视。\n\n还要注意语气，保持自然和亲切。避免使用太正式的语言，让用户觉得轻松。比如用“你好！有什么我可以帮你的吗？”这样既友好又开放。\n\n最后，确认回应是否符合规范，没有使用任何markdown格式，保持口语化。检查是否有拼写错误，确保回复正确无误。\n</think>\n\n你好！有什么我可以帮你的吗？ 😊" } ], "created" : 1752292111, "id" : "cmpl-521", "model" : "qwen3:8b", "object" : "text_completion", "system_fingerprint" : "fp_ollama", "usage" : { "completion_tokens" : 194, "prompt_tokens" : 9, "total_tokens" : 203 } }
分享-在 K3S 中创建定时任务清理 Postgesql 分区，独立部署中清理
K3S 中清理 定义 Secret 定义 CronJob 手动执行 Job 独立部署中清理 清理脚本 shell Crontab 任务 执行日志 K3S 中清理 定义 Secret 最好使用 一个 Secret 来存储用户名和密码 apiVersion: v1 kind: Secret metadata: name: postgres-credentials namespace: n100 type: Opaque data: DB_USER: foo= # 替换为base64编码的用户名 DB_PASSWORD: bar= # 替换为base64编码的密码 定义 CronJob 这里定义了 7 days，根据自己的需求来定义日期即可 apiVersion: batch/v1 kind: CronJob metadata: name: cleanup-ts-kv-partitions namespace: n100 spec: schedule: "0 1 * * *" # 每天凌晨1点 (HKT) jobTemplate: spec: template: spec: containers: - name: cleanup-partitions image: hub.yiqisoft.cn/library/postgres:12 command: - /bin/sh - -c - | psql -h $DB_HOST -U $DB_USER -d $DB_NAME -c " DO \$\$ DECLARE r RECORD; cutoff_date DATE := CURRENT_DATE - INTERVAL '7 days'; cutoff_str TEXT; partition_count INTEGER := 0; dropped_count INTEGER := 0; BEGIN SET TIME ZONE 'Asia/Hong_Kong'; RAISE NOTICE 'Starting partition cleanup at %', current_timestamp; RAISE NOTICE 'Cutoff date: %', cutoff_date; cutoff_str := to_char(cutoff_date, 'YYYY_MM_DD'); FOR r IN ( SELECT tablename FROM pg_tables WHERE schemaname = 'public' AND tablename LIKE 'ts_kv_%' ) LOOP partition_count := partition_count + 1; RAISE NOTICE 'Checking partition: %', r.tablename; IF r.tablename < 'ts_kv_' || cutoff_str THEN BEGIN EXECUTE 'DROP TABLE IF EXISTS ' || quote_ident(r.tablename); dropped_count := dropped_count + 1; RAISE NOTICE 'Successfully dropped partition: %', r.tablename; EXCEPTION WHEN OTHERS THEN RAISE WARNING 'Failed to drop partition %: %', r.tablename, SQLERRM; END; ELSE RAISE NOTICE 'Partition % is within retention period, keeping it.', r.tablename; END IF; END LOOP; RAISE NOTICE 'Cleanup completed. Checked % partitions, dropped % partitions.', partition_count, dropped_count; EXCEPTION WHEN OTHERS THEN RAISE WARNING 'Cleanup process failed: %', SQLERRM; RAISE EXCEPTION 'Terminating due to error'; END \$\$;" env: - name: DB_HOST value: "yiconnect-standalone-0-1749434022-postgres" # 替换为你的PostgreSQL服务名 - name: DB_NAME value: "yiconnect" # 替换为你的数据库名 - name: DB_USER valueFrom: secretKeyRef: name: postgres-credentials key: DB_USER - name: PGPASSWORD valueFrom: secretKeyRef: name: postgres-credentials key: DB_PASSWORD restartPolicy: OnFailure 手动执行 Job 日志如下： NOTICE: Starting partition cleanup at 2025-06-09 10:43:47.469367+08 NOTICE: Cutoff date: 2025-06-02 NOTICE: Checking partition: ts_kv_latest NOTICE: Partition ts_kv_latest is within retention period, keeping it. NOTICE: Checking partition: ts_kv_dictionary NOTICE: Partition ts_kv_dictionary is within retention period, keeping it. NOTICE: Checking partition: ts_kv_indefinite NOTICE: Partition ts_kv_indefinite is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_09 NOTICE: Partition ts_kv_2025_06_09 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_02 NOTICE: Partition ts_kv_2025_06_02 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_05_03 NOTICE: Successfully dropped partition: ts_kv_2025_05_03 NOTICE: Checking partition: ts_kv_2025_05_01 NOTICE: Successfully dropped partition: ts_kv_2025_05_01 NOTICE: Checking partition: ts_kv_2025_05_02 NOTICE: Successfully dropped partition: ts_kv_2025_05_02 NOTICE: Checking partition: ts_kv_2025_05_04 NOTICE: Successfully dropped partition: ts_kv_2025_05_04 NOTICE: Checking partition: ts_kv_2025_05_05 NOTICE: Successfully dropped partition: ts_kv_2025_05_05 NOTICE: Checking partition: ts_kv_2025_05_06 NOTICE: Successfully dropped partition: ts_kv_2025_05_06 NOTICE: Checking partition: ts_kv_2025_05_07 NOTICE: Successfully dropped partition: ts_kv_2025_05_07 NOTICE: Checking partition: ts_kv_2025_05_08 NOTICE: Successfully dropped partition: ts_kv_2025_05_08 NOTICE: Checking partition: ts_kv_2025_05_09 NOTICE: Successfully dropped partition: ts_kv_2025_05_09 NOTICE: Checking partition: ts_kv_2025_05_10 NOTICE: Successfully dropped partition: ts_kv_2025_05_10 NOTICE: Checking partition: ts_kv_2025_05_11 NOTICE: Successfully dropped partition: ts_kv_2025_05_11 NOTICE: Checking partition: ts_kv_2025_05_12 NOTICE: Successfully dropped partition: ts_kv_2025_05_12 NOTICE: Checking partition: ts_kv_2025_05_13 NOTICE: Successfully dropped partition: ts_kv_2025_05_13 NOTICE: Checking partition: ts_kv_2025_05_14 NOTICE: Successfully dropped partition: ts_kv_2025_05_14 NOTICE: Checking partition: ts_kv_2025_05_15 NOTICE: Successfully dropped partition: ts_kv_2025_05_15 NOTICE: Checking partition: ts_kv_2025_05_16 NOTICE: Successfully dropped partition: ts_kv_2025_05_16 NOTICE: Checking partition: ts_kv_2025_05_17 NOTICE: Successfully dropped partition: ts_kv_2025_05_17 NOTICE: Checking partition: ts_kv_2025_05_18 NOTICE: Successfully dropped partition: ts_kv_2025_05_18 NOTICE: Checking partition: ts_kv_2025_05_19 NOTICE: Successfully dropped partition: ts_kv_2025_05_19 NOTICE: Checking partition: ts_kv_2025_05_20 NOTICE: Successfully dropped partition: ts_kv_2025_05_20 NOTICE: Checking partition: ts_kv_2025_05_21 NOTICE: Successfully dropped partition: ts_kv_2025_05_21 NOTICE: Checking partition: ts_kv_2025_05_22 NOTICE: Successfully dropped partition: ts_kv_2025_05_22 NOTICE: Checking partition: ts_kv_2025_05_23 NOTICE: Successfully dropped partition: ts_kv_2025_05_23 NOTICE: Checking partition: ts_kv_2025_05_24 NOTICE: Successfully dropped partition: ts_kv_2025_05_24 NOTICE: Checking partition: ts_kv_2025_05_25 NOTICE: Successfully dropped partition: ts_kv_2025_05_25 NOTICE: Checking partition: ts_kv_2025_05_26 NOTICE: Successfully dropped partition: ts_kv_2025_05_26 NOTICE: Checking partition: ts_kv_2025_05_27 NOTICE: Successfully dropped partition: ts_kv_2025_05_27 NOTICE: Checking partition: ts_kv_2025_05_28 NOTICE: Successfully dropped partition: ts_kv_2025_05_28 NOTICE: Checking partition: ts_kv_2025_05_29 NOTICE: Successfully dropped partition: ts_kv_2025_05_29 NOTICE: Checking partition: ts_kv_2025_05_30 NOTICE: Successfully dropped partition: ts_kv_2025_05_30 NOTICE: Checking partition: ts_kv_2025_05_31 NOTICE: Successfully dropped partition: ts_kv_2025_05_31 NOTICE: Cleanup completed. Checked 36 partitions, dropped 31 partitions. 独立部署中清理 清理脚本 shell more /usr/local/bin/cleanup_ts_kv_partition.sh #!/bin/bash # 数据库连接参数 DB_HOST="127.0.0.1" # 替换为你的PostgreSQL主机 DB_PORT="5432" DB_NAME="yiconnect" # 替换为你的数据库名 DB_USER="postgres" # 替换为你的数据库用户 DB_PASSWORD="admin" # 替换为你的数据库密码 LOG_FILE="/var/log/postgres_cleanup.log" # 设置PGPASSWORD环境变量 export PGPASSWORD="$DB_PASSWORD" # SQL脚本，内嵌在Shell中 SQL_SCRIPT=" SET TIME ZONE 'Asia/Shanghai'; DO \$\$ DECLARE r RECORD; cutoff_date DATE := CURRENT_DATE - INTERVAL '30 days'; cutoff_str TEXT; partition_count INTEGER := 0; dropped_count INTEGER := 0; BEGIN RAISE NOTICE 'Starting partition cleanup at %', current_timestamp; RAISE NOTICE 'Cutoff date: %', cutoff_date; cutoff_str := to_char(cutoff_date, 'YYYY_MM_DD'); FOR r IN ( SELECT tablename FROM pg_tables WHERE schemaname = 'public' AND tablename LIKE 'ts_kv_%' ) LOOP partition_count := partition_count + 1; RAISE NOTICE 'Checking partition: %', r.tablename; IF r.tablename < 'ts_kv_' || cutoff_str THEN BEGIN EXECUTE 'DROP TABLE IF EXISTS ' || quote_ident(r.tablename); dropped_count := dropped_count + 1; RAISE NOTICE 'Successfully dropped partition: %', r.tablename; EXCEPTION WHEN OTHERS THEN RAISE WARNING 'Failed to drop partition %: %', r.tablename, SQLERRM; END; ELSE RAISE NOTICE 'Partition % is within retention period, keeping it.', r.tablename; END IF; END LOOP; RAISE NOTICE 'Cleanup completed. Checked % partitions, dropped % partitions.', partition_count, dropped_count; EXCEPTION WHEN OTHERS THEN RAISE WARNING 'Cleanup process failed: %', SQLERRM; RAISE EXCEPTION 'Terminating due to error'; END \$\$;" # 执行清理脚本并记录日志 echo "=== Cleanup started at $(date '+%Y-%m-%d %H:%M:%S %Z') ===" >> "$LOG_FILE" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -c "$SQL_SCRIPT" >> "$LOG_FILE" 2>&1 EXIT_CODE=$? if [ $EXIT_CODE -eq 0 ]; then echo "Cleanup completed successfully." >> "$LOG_FILE" else echo "Cleanup failed with exit code $EXIT_CODE." >> "$LOG_FILE" fi echo "=== Cleanup ended at $(date '+%Y-%m-%d %H:%M:%S %Z') ===" >> "$LOG_FILE" echo "" >> "$LOG_FILE" # 清理旧日志（可选，保留最近30天的日志） find /var/log -name "postgres_cleanup.log" -mtime +30 -delete Crontab 任务 这里，我们需要每天凌晨执行，使用 docker 容器 0 1 * * * docker run --rm --network host -v /usr/local/bin/cleanup_ts_kv_partition.sh:/cleanup_ts_kv_partition.sh -v /var/log:/var/log hub.yiqisoft.cn/library/postgres:12 /bin/bash /cleanup_ts_kv_partition.sh 执行日志 === Cleanup started at 2025-07-08 05:24:03 UTC === NOTICE: Starting partition cleanup at 2025-07-08 13:24:03.287644+08 NOTICE: Cutoff date: 2025-06-08 NOTICE: Checking partition: ts_kv_latest NOTICE: Partition ts_kv_latest is within retention period, keeping it. NOTICE: Checking partition: ts_kv_dictionary NOTICE: Partition ts_kv_dictionary is within retention period, keeping it. NOTICE: Checking partition: ts_kv_indefinite NOTICE: Partition ts_kv_indefinite is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_11 NOTICE: Partition ts_kv_2025_06_11 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_02 NOTICE: Successfully dropped partition: ts_kv_2025_06_02 NOTICE: Checking partition: ts_kv_2025_06_03 NOTICE: Successfully dropped partition: ts_kv_2025_06_03 NOTICE: Checking partition: ts_kv_2025_06_04 NOTICE: Successfully dropped partition: ts_kv_2025_06_04 NOTICE: Checking partition: ts_kv_2025_06_05 NOTICE: Successfully dropped partition: ts_kv_2025_06_05 NOTICE: Checking partition: ts_kv_2025_06_12 NOTICE: Partition ts_kv_2025_06_12 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_06 NOTICE: Successfully dropped partition: ts_kv_2025_06_06 NOTICE: Checking partition: ts_kv_2025_06_07 NOTICE: Successfully dropped partition: ts_kv_2025_06_07 NOTICE: Checking partition: ts_kv_2025_06_08 NOTICE: Partition ts_kv_2025_06_08 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_09 NOTICE: Partition ts_kv_2025_06_09 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_10 NOTICE: Partition ts_kv_2025_06_10 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_13 NOTICE: Partition ts_kv_2025_06_13 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_14 NOTICE: Partition ts_kv_2025_06_14 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_15 NOTICE: Partition ts_kv_2025_06_15 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_16 NOTICE: Partition ts_kv_2025_06_16 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_17 NOTICE: Partition ts_kv_2025_06_17 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_18 NOTICE: Partition ts_kv_2025_06_18 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_19 NOTICE: Partition ts_kv_2025_06_19 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_20 NOTICE: Partition ts_kv_2025_06_20 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_21 NOTICE: Partition ts_kv_2025_06_21 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_22 NOTICE: Partition ts_kv_2025_06_22 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_23 NOTICE: Partition ts_kv_2025_06_23 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_24 NOTICE: Partition ts_kv_2025_06_24 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_25 NOTICE: Partition ts_kv_2025_06_25 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_26 NOTICE: Partition ts_kv_2025_06_26 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_27 NOTICE: Partition ts_kv_2025_06_27 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_28 NOTICE: Partition ts_kv_2025_06_28 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_29 NOTICE: Partition ts_kv_2025_06_29 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_06_30 NOTICE: Partition ts_kv_2025_06_30 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_07_01 NOTICE: Partition ts_kv_2025_07_01 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_07_02 NOTICE: Partition ts_kv_2025_07_02 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_07_03 NOTICE: Partition ts_kv_2025_07_03 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_07_04 NOTICE: Partition ts_kv_2025_07_04 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_07_05 NOTICE: Partition ts_kv_2025_07_05 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_07_06 NOTICE: Partition ts_kv_2025_07_06 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_07_07 NOTICE: Partition ts_kv_2025_07_07 is within retention period, keeping it. NOTICE: Checking partition: ts_kv_2025_07_08 NOTICE: Partition ts_kv_2025_07_08 is within retention period, keeping it. NOTICE: Cleanup completed. Checked 111 partitions, dropped 77 partitions. DO Cleanup completed successfully. === Cleanup ended at 2025-07-08 05:24:06 UTC ===
K8S Traefik Ingress 独立部署 Nginx K8S Traefik Ingress 为了提升所谓的安全性 创建一个 Middleware apiVersion: traefik.containo.us/v1alpha1 kind: Middleware metadata: name: block-swagger namespace: line-database spec: replacePathRegex: regex: ^/(swagger-ui/|swagger-ui\.html|v3/api-docs|actuator)(.*)$ replacement: /traefik-blocked 应用到 Ingress 的 annotations traefik.ingress.kubernetes.io/router.middlewares: line-database-block-swagger@kubernetescrd 独立部署 Nginx http { server { location ~ ^/(swagger-ui/|swagger-ui\.html|v3/api-docs|actuator)(/.*)?$ { return 403; # Return 403 Forbidden # Alternatively, use `return 404;` for Not Found } ... } }
使用 OpenVINO Model Zoo 下载和转换模型 前提条件 1. 安装 pip 及 OpenVINO 开发包 2. 安装 Protocol Buffers 3. 验证安装 4. 检查 Model Zoo 5. 下载并转换 AlexNet 模型 结论 使用 OpenVINO Model Zoo 下载和转换模型 OpenVINO 是由英特尔开发的一个开源工具包，用于优化和部署深度学习模型。它特别适合在英特尔硬件上运行推理，但也支持其他平台。OpenVINO 的一个关键功能是 Model Zoo，这是一个包含预训练深度学习模型的集合，涵盖了对象检测、分类、图像分割等多种任务。 笔者将详细介绍在 Linux 系统上使用 OpenVINO Model Zoo 的步骤。我们将涵盖安装必要工具、探索可用模型、下载并转换 AlexNet 模型的完整过程。这些步骤基于 OpenVINO 2023.3 版本，并使用命令行工具完成。 前提条件 在开始之前，请确保您的 Linux 系统满足以下要求： Python 3 和 pip：需要 Python 3 以及 pip 来管理 Python 包。 OpenVINO 开发工具：这些工具是与 Model Zoo 交互的必需品。 互联网连接：用于下载工具和模型。 以下是我们将使用的关键命令： 命令 描述 apt install python3-pip 安装 Python 3 的 pip 包管理器 pip install openvino-dev==2023.3 安装 OpenVINO 开发工具（2023.3 版本） pip install protobuf==3.20.1 安装与 OpenVINO 兼容的 Protocol Buffers pip list 列出已安装的 Python 包以验证安装 omz_downloader -h 显示 omz_downloader 工具的帮助信息 omz_downloader --print_all 列出 Model Zoo 中的所有可用模型 omz_downloader --name alexnet 下载 AlexNet 模型 omz_converter --name alexnet 将 AlexNet 模型转换为 OpenVINO IR 格式 1. 安装 pip 及 OpenVINO 开发包 如果您的系统尚未安装 Python 3 的 pip，可以通过以下命令安装： apt install python3-pip 此命令确保可以安装和管理 Python 包。OpenVINO 开发包包含与 Model Zoo 交互所需的工具，例如 omz_downloader 和 omz_converter。安装 2023.3 版本的开发包： pip install openvino-dev==2023.3 确保版本号与您使用的 OpenVINO 版本匹配，以避免兼容性问题。 2. 安装 Protocol Buffers 某些模型可能需要 Protocol Buffers（protobuf）来处理模型文件，例如转换格式等。安装与 OpenVINO 2023.3 兼容的版本： pip install protobuf==3.20.1 此步骤确保您可以处理需要 protobuf 的模型。 3. 验证安装 为了确认所有工具都已正确安装，运行以下命令列出已安装的 Python 包： pip list 在输出中查找以下包，如果这些包出现在列表中，说明安装成功： 包名 版本 openvino-dev 2023.3 protobuf 3.20.1 4. 检查 Model Zoo OpenVINO Model Zoo 包含超过 200 个预训练模型，涵盖了对象检测、分类、图像分割、手写识别、文本到语音、姿势估计等多种任务。这些模型分为两类： 英特尔模型：已转换为 OpenVINO 格式。 公共模型：需要使用 OpenVINO 模型转换 API 进行转换。 要了解 omz_downloader 工具的用法，运行： omz_downloader -h usage: omz_downloader [-h] [--name PAT[,PAT...]] [--list FILE.LST] [--all] [--print_all] [--precisions PREC[,PREC...]] [-o DIR] [--cache_dir DIR] [--num_attempts N] [--progress_format {text,json}] [-j N] options: -h, --help show this help message and exit --name PAT[,PAT...] download only models whose names match at least one of the specified patterns --list FILE.LST download only models whose names match at least one of the patterns in the specified file --all download all available models --print_all print all available models --precisions PREC[,PREC...] download only models with the specified precisions (actual for DLDT networks); specify one or more of: FP16-INT8,FP32-INT1,FP32-INT8,FP16,FP32,FP16-INT1 ... -j N, --jobs N how many downloads to perform concurrently 此命令将显示工具的选项和用法，例如指定模型名称、下载目录等。要查看 Model Zoo 中所有可用模型的列表，运行： omz_downloader --print_all 此命令将输出一个详细的模型列表，您可以根据任务需求选择合适的模型： Sphereface aclnet aclnet-int8 action-recognition-0001 ... yolo-v2-ava-sparse-35-0001 yolo-v2-ava-sparse-70-0001 yolof yolox-tiny 5. 下载并转换 AlexNet 模型 在本例中，我们将下载 AlexNet 模型，这是一个用于图像分类的经典卷积神经网络。运行以下命令： omz_downloader --name alexnet 此命令会将 AlexNet 模型下载到默认目录（通常是用户主目录下的 open_model_zoo_models）。您可以通过 --download_dir 选项指定自定义下载路径。下载的模型需要转换为 OpenVINO 的中间表示（IR）格式，以便在 OpenVINO 应用程序中进行高效推理。使用 omz_converter 工具完成此操作： omz_converter --name alexnet 此命令会将 AlexNet 模型转换为 IR 格式，生成两个文件：一个 .xml 文件（描述模型结构）和一个 .bin 文件（包含模型权重）。转换后的模型可以直接用于 OpenVINO 支持的推理任务。 结论 通过以上步骤，笔者成功在 Linux 系统上安装了 OpenVINO 工具，探索了 Model Zoo，下载并转换了 AlexNet 模型。这些步骤为使用 OpenVINO Model Zoo 中的其他模型奠定了基础，使读者能够轻松集成预训练模型到深度学习应用中。
EdgeX Foundry 开发设备服务的几个关键点 1.设备服务工作流 2.设备服务示例模板 2.1 SDK 相关工作流 2.2 template.c 的细节 3.删除设备的处理逻辑 4.增加设备 4.1 增加设备的方式 4.2 增加设备的处理逻辑 总结 EdgeX Foundry 开发设备服务的几个关键点 EdgeX Foundry 设备服务是与传感器/设备或物联网对象 (“物”) 交互的边缘连接器，它需要与各种设备交互，将数据传输到边缘计算系统，并根据需求执行控制命令。EdgeX Foundry 通过其模块化设计和丰富的工具集，使得设备服务的开发变得更加简单高效。我们还可以使用设备服务 SDK 来创建您自己的 EdgeX 设备服务，本文重点介绍使用 C-SDK 开发设备服务源代码的几个必须明确的关键点 。 1.设备服务工作流 以 设备服务 template.c 为例，作为一个虚拟设备服务，它可以将数据发送到核心数据微服务，用户可以通过命令和控制微服务发送命令并获得响应，虚拟设备服务的这些功能在执行功能或性能测试时不需要任何实际设备就可以使用。 注意点： 虚拟设备服务对核心数据和元数据微服务具有依赖性，因为初始化过程需要检查或注册配置文件，设备和值描述符，因此，核心数据和元数据服务必须在设备服务初始化之前完全启动。 服务启动时，服务会通过从 YAML 文件加载“值描述符”,“设备服务”,“设备描述”来初始化，并登记在元数据微服务中，YAML文件默认存在，也可以自行创建。虚拟设备服务为元数据微服务提供回调API来管理设备实例。 2.设备服务示例模板 2.1 SDK 相关工作流 EdgeX Foundry 的 C-SDK 提供了一个设备服务模板（位于 examples/template.c 强烈推荐先看一遍代码），它提供了一套规范化的开发示例，包括自定义回调函数、设备服务启动关闭、内存开辟释放等，是我们初次接触设备服务开发的良好开端。设备服务工作流在上一节有了一个大致的介绍，结合官方的指导文档 servicewritersguide.md (强烈推荐先阅读一遍)，这里进一步描述设备服务内部 SDK 相关的工作流，展示如下： 从根本上说，设备服务由多个回调组成，上图中的 SDK 内部工作流均在一系列回调函数中作处理。一个设备服务只有一个设备服务实例结构体指针 Implementation 每次调用回调时，该指针都会被传递，如初始化回调函数的第一个参数 (template_driver *) impl。 /* --- template.c ---- */ /* Initialize performs protocol-specific initialization for the device * service. */ static bool template_init ( void *impl, struct iot_logger_t *lc, const iot_data_t *config ) { template_driver *driver = (template_driver *) impl; iot_log_debug (lc, "Template Init."); return true; } 2.2 template.c 的细节 一个设备服务必须要自定义好的回调函数如下：每一个回调函数的实现正如上面提到的 template_init 那样。 /* Device Callbacks */ devsdk_callbacks *templateImpls = devsdk_callbacks_init ( template_init, template_get_handler, template_put_handler, template_stop, template_create_addr, template_free_addr, template_create_resource_attr, template_free_resource_attr ); 同时设备服务 SDK 还提供了一些非必要的回调函数，以便于开发者实现更灵活的需求，在 servicewritersguide.md 的 Optional handlers 部分有提到。举一个例子，一个设备服务实例可以实现 device_added、device_updated 和 device_removed 处理程序，然后它将收到服务管理的设备范围的更改通知。如果需要特殊的初始化/关闭操作来优化设备的使用，这可能会有所帮助。只需要将该函数实现，并注册进设备服务的回调初始化函数即可： //device_added 的具体实现 static void device_added( void *impl, const char *devname, const devsdk_protocols *protocols, const devsdk_device_resources *resources, bool adminEnabled) { openvino_driver *driver = (openvino_driver *)impl; iot_log_info(driver->lc, "New device added: %s", devname); } ... //主函数内的回调初始化 devsdk_callbacks *templateImpls = devsdk_callbacks_init ( template_init, template_get_handler, template_put_handler, template_stop, template_create_addr, template_free_addr, template_create_resource_attr, template_free_resource_attr ); //注册自定义的设备服务回调 devsdk_callbacks_set_listeners(templateImpls, device_added, NULL, NULL); 3.删除设备的处理逻辑 每删除一个设备，一定依次进入的回调函数是：template_free_resource_attr 和 template_free_addr 。 如果自定义回调 device_removed 已经初始化，则会优先进入该回调，然后再进入上面两个默认的释放内存处理回调之中。 4.增加设备 4.1 增加设备的方式 通过 EdgeX Foundry 官方 UI 界面（如下图所示）增加一个具体的设备，通过界面可视化引导，很容易完成以下步骤： SelectDeviceService SelectDeviceProfile DevicePrimary CreateAutoEvent CreateDeviceProtocol 注意点：CreateDeviceProtocol 为必须设置项，且需要跟自己的设备服务所规定的协议保持一致。 通过 API 控制命令，直接向 core-metadata 发送 POST 请求，即可一行命令生成新设备，如下所示： curl http://localhost:59881/api/v3/device -H "Content-Type: application/json" -X POST \ -d '[ { "apiVersion" : "v3", "device": { "name": "Device1", "description": "An Example Device", "adminState": "UNLOCKED", "operatingState": "UP", "serviceName": "device-template", "profileName": "template", "protocols": { "Others": { "key1": "xxxx", "key2": "yyyy", } } } } ]' 4.2 增加设备的处理逻辑 每增加一个设备，会先调用自定义回调 device_add （如果已经初始化） 然后在第一次获取设备资源，也就是 GET 请求时，会依次调用 template_create_resource_attr 、 template_create_addr 和 template_get_handler。 以后的 GET 请求只会直接调用 template_get_handler。 总结 本文深入探讨了使用 EdgeX Foundry C-SDK 开发设备服务的几个关键点，为开发者提供了一个清晰的指导框架。通过分析设备服务的工作流、模板代码的细节以及设备增删的处理逻辑，我们可以更高效地构建自定义设备服务。 首先，设备服务的工作流强调了其与核心数据和元数据微服务的依赖性，以及通过 YAML 文件初始化配置的重要性。其次，C-SDK 的模板（template.c）提供了一个规范化的开发起点，包含必备回调函数（如 init、get、put、stop）和可选回调（如 device_added），开发者可根据需求灵活扩展。再次，删除设备的逻辑涉及内存释放回调（如 template_free_addr），而增加设备则通过 UI 或 API 触发，并涉及初始化和资源获取的回调链。 总的来说，掌握这些关键点——理解工作流、熟悉模板结构、明确设备管理的回调逻辑——能够帮助开发者快速上手 EdgeX Foundry 设备服务开发，无论是构建虚拟服务还是连接真实设备。
1.理解 Git 的核心概念 2.首次提交到远程仓库的步骤 3.通过 SSH 提交代码到 GitHub 4.谨慎使用危险命令 什么是 HEAD git reset：小心回退过头 git rebase：重写历史的双面性 总结 Git 是一个开源的分布式版本控制系统，用于敏捷高效地处理任何或小或大的项目。Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。作为初学者，我在学习和使用 Git 的过程中总结了一些需要注意的事项，希望通过这篇博客帮助其他新手快速上手。 1.理解 Git 的核心概念 在开始使用 Git 之前，理解几个基本概念能让你事半功倍： 工作区（Working Directory）：你本地修改代码的地方。用 git clone 后会自动生成。 暂存区（Staging Area）：用 git add 将修改暂存的地方，它存在于本地 .git 目录中，准备提交到版本库。 版本库（Repository）：用 git commit 提交后，代码保存于本地 .git 目录下。 远程仓库（Remote Repository）：比如 GitHub、GitLab，用于团队协作。 进一步理解：Git 是一个分布式版本控制系统（Distributed Version Control System, DVCS），这意味着每个开发者本地都有一个完整的仓库副本，而不是像集中式系统那样依赖单一的中央服务器。这种分布式设计直接影响了工作区、暂存区和版本库在每个开发者本地的工作方式。 2.首次提交到远程仓库的步骤 首次提交时应初始化本地仓库，并添加远程仓库： git init # 将本地仓库与远程仓库关联起来 git remote add origin https://github.com/xxx/device-openvino-c.git # 验证是否添加成功 git remote -v 输出如下： origin https://github.com/xxx/device-openvino-c.git (fetch) origin https://github.com/xxx/device-openvino-c.git (push) 添加和提交本地代码： git add . git commit -m "add:初次提交到 device-openvino-c 仓库" git push -u origin main 注意： -u（--set-upstream）设置上游分支关联，以后只需 git push 即可。 如果是第一次推送，GitHub 可能会要求你输入用户名和 PAT 令牌（或SSH Authentication keys）。用户名是注册邮箱，令牌是github设置主页内的 Personal access tokens 。不过还是建议提前在 GitHub 上生成 SSH keys 一劳永逸。 配置 SSH 密钥后，URL 改为 git@github.com:xxx/device-openvino-c.git。 3.通过 SSH 提交代码到 GitHub HTTPS 需要每次推送时输入用户名和密码（或 PAT），而 SSH 使用密钥认证，配置一次后无需重复输入凭证，更方便。并且SSH 更安全，适合长期使用。 检查和生成 SSH 密钥：（如果看到 id_rsa 私钥和 id_rsa.pub 公钥，说明已有密钥） ls -al ~/.ssh root@ubuntu:/home/ubuntu/edgex/device-sdk-c/src/c/examples/real/device-openvino-c# ls -al ~/.ssh total 32 drwx------ 2 root root 4096 Mar 27 16:45 . drwx------ 9 root root 4096 Apr 2 10:42 .. -rw------- 1 root root 405 Mar 12 13:46 authorized_keys -rw-r--r-- 1 root root 70 Mar 27 16:44 config -rw------- 1 root root 3381 Mar 27 16:27 id_rsa -rw-r--r-- 1 root root 743 Mar 27 16:27 id_rsa.pub -rw------- 1 root root 978 Mar 27 16:45 known_hosts -rw-r--r-- 1 root root 142 Mar 27 16:45 known_hosts.old 没有 SSH 密钥则生成： （按回车接受默认路径 ~/.ssh/id_rsa） ssh-keygen -t rsa -b 4096 -C "你的github邮箱@example.com" 将公钥添加到 GitHub：复制输出的内容（以 ssh-rsa 开头） # 查看公钥内容 cat ~/.ssh/id_rsa.pub ssh-rsa [binary] ... [binary] xxx@xxx.com 登录 https://github.com → 点击右上角头像 → Settings → SSH and GPG keys → New SSH key： 粘贴公钥，命名（如 “ssh”），保存: 测试 SSH 连接: ssh -T git@github.com 如果成功，会看到：以后推送/抓取远端仓库就不需要每次都输入密码啦！ Hi! You've successfully authenticated, but GitHub does not provide shell access. 如果已用 HTTPS 添加（https://github.com/xxx/device-openvino-c.git），修改为 SSH： git remote set-url origin git@github.com:xxx/device-openvino-c.git 4.谨慎使用危险命令 在 Git 的强大功能背后，一些命令如果使用不当，可能导致代码丢失、历史混乱或团队协作问题。 什么是 HEAD 在 Git 中，HEAD 是一个非常核心的概念，它本质上是一个指针，指向你当前工作的位置。理解 HEAD 对于掌握 Git 的操作（如提交、分支切换、回退等）至关重要。随着操作（提交、切换分支等），HEAD 会移动。 许多 Git 命令（如 git checkout、git reset、git merge）都以 HEAD 为基准。 git reset HEAD^ # 回退到上一次提交 git diff HEAD HEAD^ # 比较当前和上一次提交的差异 git reset：小心回退过头 git reset 可以回退提交或暂存区的改动，尤其是 git reset --hard，会直接丢弃工作区和暂存区的未提交改动，甚至重写提交历史。示例：运行 git reset --hard HEAD^ 回退一次提交，但忘了当前改动还没保存，结果代码全丢。 未提交的改动无法恢复（除非用 git reflog 找回已提交的记录） # 危险操作 git reset --hard HEAD^ # 丢弃最近一次提交和改动 # 安全替代 git status # 检查是否有未提交改动。 git reset --soft HEAD^ # 保留改动，只回退提交 git rebase：重写历史的双面性 Git rebase 是一个重写提交历史的命令，通过将当前分支的提交“重放”到目标分支上，实现线性化的历史。下图展示其意义： A - B - E (main) \ C - D (feature) git checkout feature git rebase main A - B - E - C' - D' (feature) 注意：git rebase 不自动保存未提交的改动，使用 git rebase --abort 中止时只恢复到 rebase 开始前的提交状态。此时未用 git add 和 git commit 保存的内容都会丢失！如果保存过，可以查看 reflog 找回提交。 总结 通过学习和实践 Git，能体会到它作为一个分布式版本控制系统的强大与灵活。从理解核心概念（如工作区、暂存区、版本库）到首次提交代码，再到通过 SSH 实现高效推送，每一步都离不开良好的操作习惯。尤其是在使用 git reset 和 git rebase 等危险命令时，稍有不慎就可能导致代码丢失或历史混乱。 因此，养成以下习惯很有必要：勤于 commit 保存改动，每次小步提交，确保工作有迹可循；操作前用 git status 检查状态，避免误操作；对复杂命令如 rebase，先备份分支或用 git stash 暂存改动。良好的习惯不仅能提高效率，还能让我们在 Git 的世界里游刃有余，无论是个人项目还是团队协作都能得心应手。
EdgeX Foundry 在 Docker 容器微服务下的相关使用技巧 1.Device Services 注册问题 2.数据库服务的操作工具 3.docker-compose.yml 用法 4.Docker Network 容器互联 总结 EdgeX Foundry 在 Docker 容器微服务下的相关使用技巧 EdgeX Foundry 是一个开源的边缘计算框架，广泛用于物联网设备的开发与管理。它高度依赖 Docker 来实现服务的容器化部署。本文将分享一些在 Docker 容器中使用 EdgeX Foundry 的实用技巧，包括 Device Services 的注册、数据库服务操作、docker-compose.yml 的用法以及网络管理等方面的经验总结。希望能为开发者提供参考。 1.Device Services 注册问题 在开发或调试 EdgeX Foundry 的 Device Services 时，可能会遇到设备服务配置残留或配置未正确加载的问题，默认情况下在官方 UI 界面（如下图所示）中没有删除具体一个 Device Service 的接口。 这会导致我们在加载 修改后的设备服务(关键是 /res/configration.yml 文件)时很麻烦，Device Service 的配置信息是存放在官方数据库服务容器 postgres:16.3 中的，最简单干脆的清理办法是清除所有Docker 卷： 清理容器和卷 # 删除所有已停止和运行中的容器 docker rm -f $(docker ps -a -q) # 删除所有未使用的 Docker 卷 docker volume rm -f $(docker volume ls -q) 启动 EdgeX 服务 假设你已经下载了 EdgeX 的 edgex-compose 仓库，可以通过以下步骤重新启动服务，此时获得了全新的一套 EdgeX 微服务： # 进入 compose-builder 目录 cd /home/ubuntu/edgex/edgex-compose/compose-builder/ # 后台启动所有服务 docker compose up -d root@ubuntu:/home/ubuntu/edgex/edgex-compose/compose-builder# docker compose up -d [+] Running 17/17 ✔ Volume "edgex_db-data" Created 0.0s ✔ Volume "edgex_kuiper-data" Created 0.0s ... ✔ Container edgex-support-scheduler Started 2.4s ✔ Container edgex-app-rules-engine Started 2.6s ✔ Container edgex-core-command Started 2.6s 注意： 在执行清理命令前，建议检查是否有重要数据未备份。 如果遇到权限问题，可使用 sudo 提升权限。 2.数据库服务的操作工具 EdgeX 的 Compose 文件仓库会为我们生成数据库服务容器如下： ID IMAGE COMMAND PORTS NAMES ... 8xxx7a postgres:16.3-alpine3.20 "docker-entrypoint.s…" 127.0.0.1:5432->5432/tcp edgex-postgres ... 为了方便查看数据库内部一些关键数据表的状态和信息，建议把 Postgres 端口映射到本地，用 SQL 工具（推荐 DBeaver）连接上，进行增删改查 : 注意： 首次使用需要登陆数据库，在 docker-compose.yml 文件中有数据库用户名和密码： database: container_name: edgex-postgres environment: POSTGRES_DB: edgex_db POSTGRES_PASSWORD: postgres ... 3.docker-compose.yml 用法 Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose，您可以使用 YML 文件来配置应用程序需要的所有服务。然后，使用一个命令，就可以从 YML 文件配置中创建并启动所有服务。 EdgeX Foundry 部署服务的核心配置文件正是 docker-compose.yml , 同时也是自定义设备服务的重要部署工具。以下是一些常用操作和注意事项 : （在 docker-compose.yml 同级文件夹下运行） 停止并删除所有服务容器： docker compose down 查看运行中的容器： docker compose ps 后台启动服务： docker compose up -d 重启某一个具体的服务并查看日志： docker compose restart edgex-device-openvino docker logs -f edgex-device-openvino 可以添加自定义设备服务在现有的 docker-compose.yml 中，如添加 s7 设备服务,也可调整现有的端口映射或服务依赖关系。在调整 docker-compose.yml 时，也可能需要更改文件权限： chmod +w docker-compose.yml vim docker-compose.yml ... bind: create_host_path: true device-s7: command: - -cp=keeper.http://edgex-core-keeper:59890 - --registry ... read_only: true bind: create_host_path: true mqtt-broker: ... 常见问题： 命令未生效：检查是否在正确的目录下运行（包含 docker-compose.yml 的目录）。 服务未启动：运行 docker compose ps 检查状态，可能需要查看日志定位问题。 4.Docker Network 容器互联 Docker 有一个连接系统允许将多个容器连接在一起，共享连接信息。EdgeX Foundry 的服务之间通过 Docker 网络通信，默认网络名为 edgex-network。以下是网络相关的操作技巧： 列出所有 Docker 网络并过滤出 EdgeX 相关网络： docker network ls | grep edgex-network # docker network ls | grep edgex-network 399e879a892b edgex_edgex-network bridge local 检查容器是否加入正确网络： docker inspect edgex-device-openvino | grep Network 如果服务无法通信，可以尝试重建网络： docker network rm edgex-network docker compose up -d # 自动重新创建网络 注意：删除网络前，确保没有正在运行的服务依赖它。 总结 通过本文，我们介绍了在 EdgeX Foundry 中使用 Docker 的一些实用技巧，包括清理容器、操作数据库、管理 docker-compose.yml 文件以及网络排查。这些方法可以帮助开发者更高效地部署和调试 EdgeX 服务。Docker 的灵活性为 EdgeX 提供了强大的支持，但在实际使用中仍需注意资源管理和服务依赖关系。
利用 MkDocs 和 GitHub 部署个人博客网页 1.在本地安装 Material for MkDocs 2.创建网站示例 3.发布网站到 GitHub Pages 3.1 建立 GitHub 博客专用仓库 3.2 配置 GitHub Actions 工作流 3.3 更新远程仓库 总结 利用 MkDocs 和 GitHub 部署个人博客网页 在数字化时代，拥有一个个人博客网站不仅能展示自己的想法与作品，还能提升个人品牌的影响力。本文将详细介绍如何利用 MkDocs 和 Material for MkDocs 创建一个现代化的静态网站，并通过 GitHub Pages 实现免费部署。无论你是技术爱好者还是想要分享生活点滴的创作者，这个简单高效的方法都能帮助你快速搭建属于自己的在线空间。以下内容将带你一步步完成从本地安装到线上发布的完整流程。 1.在本地安装 Material for MkDocs Material for MkDocs 是一个基于 MkDocs 的现代化文档框架，而 MkDocs 本身是一个轻量级的静态网站生成器，特别适合用来创建项目文档或个人博客。它以 Markdown 文件为基础，将内容转化为美观、易读的 HTML 页面。Material for MkDocs 在此基础上提供了优雅的主题和丰富的功能，比如响应式设计、内置搜索等，让你的网站看起来更专业。 安装非常方便，打开终端，使用 pip 即可： pip install mkdocs-material 这将自动安装所有兼容的依赖项版本：MkDocs、Markdown、Pygments 和 Python Markdown Extensions。Material for MkDocs 始终致力于支持这些依赖项的最新版本，因此无需单独安装这些包。 2.创建网站示例 安装完成后，你就可以开始搭建自己的网站了。MkDocs 提供了一个便捷的命令行工具，让你快速初始化项目结构。以下是具体操作步骤： 初始化项目：首先，选择一个你喜欢的工作目录，然后创建一个文件夹（例如 blog_site）作为博客的工作空间。进入该目录后，运行初始化命令： mkdir blog_site && cd blog_site mkdocs new . mkdocs new .会在当前目录下生成一个基础的项目结构。完成后你会看到如下文件布局： . ├─ docs/ │ └─ index.md └─ mkdocs.yml 其中，docs/ 内是存放的具体博客内容，使用 markdown 格式；mkdocs.yml 是网页的基本配置。 配置网站信息：打开 mkdocs.yml文件，用文本编辑器（如 VS Code 或 Notepad++）进行修改。以下是一个简单的配置示例： site_name: sun-seeker's blog site_url: https://sun-seeker.github.io site_author: sun-seeker theme: name: material #主题 注意：我们将站点发布到 GitHub Pages 时，站点通常托管在子路径下，即 https://sun-seeker.github.io ；material 是先前安装好的主题示例。 本地预览：配置完成后，你可以在本地测试网站效果。在 blog_site 目录下运行： mkdocs serve 显示服务本地端口，这个网站就算是初步建好了，可以点击查看： INFO - Building documentation... INFO - Cleaning site directory INFO - Documentation built in 0.33 seconds INFO - [18:21:09] Watching paths for changes: 'docs', 'mkdocs.yml' INFO - [18:21:09] Serving on http://127.0.0.1:8000/ 这表示网站已在本地启动。打开浏览器，输入 http://127.0.0.1:8000/ ，你就能看到初步搭建的网站效果。如果修改了docs/ 中的 Markdown 文件，页面会自动刷新，可边写边预览。 3.发布网站到 GitHub Pages 接下来我们将它部署到 GitHub Pages 上，让全世界都能访问。GitHub Pages 是 GitHub 提供的一项免费服务，特别适合托管静态网站，而且与 GitHub 的版本控制功能无缝集成。 3.1 建立 GitHub 博客专用仓库 创建仓库：登录 GitHub，点击右上角的 “+” 号，选择 “New repository”。仓库名称需遵循特定格式：你的用户名.github.io，例如 Sun-Seeker.github.io。保持其他设置默认，然后点击 “Create repository”。 这个名称很重要，因为 GitHub Pages 会根据它自动生成你的网站地址，比如 https://sun-seeker.github.io/。 注意到仓库名称中，名字即为左边 Owner 的名字。新建好以后，克隆仓库至本地： git clone git@github.com:Sun-Seeker/Sun-Seeker.github.io.git cd Sun-Seeker.github.io.git 3.2 配置 GitHub Actions 工作流 为了简化部署，我们使用 GitHub Actions 自动将网站发布到 GitHub Pages。这是一种自动化工具，可以在每次推送代码时运行预定义脚本。 创建工作流文件：在仓库根目录下创建以下路径和文件： mkdir .github && cd .github mkdir workflows && cd workflows sudo vim ci.yml 进入 .github/workflows/ci.yml，然后复制并粘贴以下内容： name: ci on: push: branches: - master - main permissions: contents: write jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Configure Git Credentials run: | git config user.name github-actions[bot] git config user.email 41898282+github-actions[bot]@users.noreply.github.com - uses: actions/setup-python@v4 with: python-version: 3.x - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV - uses: actions/cache@v3 with: key: mkdocs-material-${{ env.cache_id }} path: .cache restore-keys: | mkdocs-material- - run: pip install mkdocs-material - run: mkdocs gh-deploy --force ci.yml 为持续集成配置文件，其作用是： 在推送代码到 main 或 master 分支时触发。 使用 Ubuntu 环境，安装 Python 和 mkdocs-material。 执行 mkdocs gh-deploy，将网站构建并推送到 GitHub Pages 专用的 gh-pages 分支。 复制本地网站文件：将之前创建的 blog_site 文件夹内容复制到仓库目录： cd Sun-Seeker.github.io.git cp -r ../blog_site/* ./ 到这里先检查一下你的目录结构, 目录树状图如下所示: 要注意mkdocs.yml 文件里的网站链接为 https://<仓库名>，正如 https://sun-seeker.github.io/ $ tree -a Sun-Seeker.github.io ├── .github │ └── workflows │ └── ci.yml ├── docs │ └── index.md └── mkdocs.yml 重点-启用 Actions 权限：Github仓库 setings/Actions/General 勾选这两项： 3.3 更新远程仓库 提交并推送：在本地仓库根目录下执行操作：由于 ci.yml 会为我们自动创建 gh-pages 分支，所以不用自行创建 git add . git commit -m "更新了主页样式" git push origin main 重点-配置 Pages 设置：去远程仓库的 setings/pages 选择下图示意的路径： 等待一会网址就出来了，你的网站就是： https://<名字>.github.io/ 总结 通过本文的步骤，你已经掌握了利用 MkDocs 和 Material for MkDocs 搭建个人博客网站的核心技能。 从本地安装依赖、初始化项目，到配置主题和内容，再到通过 GitHub Pages 和 GitHub Actions 实现自动化部署，整个过程既简单又高效。最终，你的博客以 https://<名字>.github.io/ 的形式成功上线，完全免费且易于维护。未来，你可以通过丰富 docs/ 文件夹中的 Markdown 内容，不断更新和完善你的网站，打造一个独具特色的个人数字家园。
在 ubuntu22.04 中 安装 EdgeX 并运行 device-sdk-c sample
在 ubuntu22.04 中 安装 EdgeX 并运行 device-sdk-c sample 1.克隆源码-EdgeX 2.安装工具 3.编译运行-EdgeX 4.克隆源码-SDK-C 5.添加第三方依赖库 6.编译-C SDK 7.编译运行 random 设备服务示例 总结 在 ubuntu22.04 中 安装 EdgeX 并运行 device-sdk-c sample EdgeX Foundry 作为一个开源的边缘计算框架，为开发者提供了一个灵活、可扩展的平台，用于构建和管理边缘设备及服务。然而，对于初次接触 EdgeX 的用户来说，从零开始安装并运行其相关组件（如 device-sdk-c 示例）可能会面临不少挑战。 无论是环境的配置、依赖的安装，还是编译与调试的过程，每一步都需要细致的操作和清晰的思路。本文将以 Ubuntu 22.04 为基础平台，详细记录如何从克隆 EdgeX 源码到成功运行 device-sdk-c 的 sample 示例的全过程。希望通过这篇博客，不仅能为新手提供一份实用的操作指南，也能让有经验的开发者在遇到问题时找到解决思路。 1.克隆源码-EdgeX 在开始安装 EdgeX 之前，我们需要先获取其源码，而 GitHub 是获取最新版本的最佳途径。为了让后续操作更加有条理，我们首先在用户主目录下创建一个专属的工作目录，用于存放 EdgeX 相关的文件。以下是具体操作： 打开终端，输入以下命令创建一个名为 edgex 的文件夹，并进入该目录： mkdir edgex && cd edgex 接下来，我们需要从 GitHub 上克隆 EdgeX 的 Compose 文件仓库，这是运行 EdgeX 服务的核心配置文件集合。执行以下命令： git clone https://github.com/edgexfoundry/edgex-compose.git cd edgex-compose 结果显示如下： root@ubuntu:/home/ubuntu# mkdir edgex && cd edgex root@ubuntu:/home/ubuntu/edgex# git clone https://github.com/edgexfoundry/edgex-compose.git Cloning into 'edgex-compose'... remote: Enumerating objects: 5826, done. remote: Counting objects: 100% (3563/3563), done. remote: Compressing objects: 100% (319/319), done. remote: Total 5826 (delta 3504), reused 3250 (delta 3244), pack-reused 2263 (from 3) Receiving objects: 100% (5826/5826), 1.59 MiB | 1.76 MiB/s, done. Resolving deltas: 100% (4949/4949), done. root@ubuntu:/home/ubuntu/edgex# ls edgex-compose 输出信息显示了克隆进度，最终 ls 命令确认目录中已存在 edgex-compose 文件夹，说明这一步成功完成。 2.安装工具 EdgeX 的部署离不开 Docker，因为它通过容器化技术简化了服务的管理和运行。因此，我们需要先在 Ubuntu 系统中安装 Docker。以下是详细的安装步骤： 使用官方脚本安装 Docker，并指定阿里云镜像源以加速下载： curl -fsSL https://get.docker.com -o get-docker.sh sh get-docker.sh --mirror Aliyun docker -v 第一条命令通过 curl 下载安装脚本并保存为 get-docker.sh 文件；第二条命令执行脚本，--mirror Aliyun 参数指定使用阿里云镜像源，避免默认源下载缓慢；最后通过 docker -v 检查版本，确保安装成功。安装过程的输出类似： root@ubuntu:/home/ubuntu# curl -fsSL https://get.docker.com -o get-docker.sh root@ubuntu:/home/ubuntu# sh get-docker.sh --mirror Aliyun # Executing docker install script, commit: 4c94a56999e10efcf48c5b8e3f6afea464f9108e ... Client: Docker Engine - Community Version: 28.0.1 API version: 1.48 ... root@ubuntu:/home/ubuntu# docker -v Docker version 28.0.1, build 068a01e 如果下载速度过慢，可能是镜像源的问题。这时可以调整 Ubuntu 的软件源以提高效率。首先检查系统版本： root@ubuntu:/home/ubuntu# more /etc/os-release PRETTY_NAME="Ubuntu 22.04.5 LTS" NAME="Ubuntu" VERSION_ID="22.04" VERSION="22.04.5 LTS (Jammy Jellyfish)" VERSION_CODENAME=jammy ID=ubuntu ID_LIKE=debian HOME_URL="https://www.ubuntu.com/" SUPPORT_URL="https://help.ubuntu.com/" BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-poli cy" UBUNTU_CODENAME=jammy 确认版本为 jammy 后，访问南京大学镜像站（https://mirror.nju.edu.cn/mirrorz-help/ubuntu/）, 获取对应源配置并编辑 /etc/apt/sources.list： # vim /etc/apt/sources.list deb https://mirror.nju.edu.cn/ubuntu/ jammy main restricted universe multiverse deb https://mirror.nju.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse deb https://mirror.nju.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse deb http://security.ubuntu.com/ubuntu/ jammy-security main restricted universe multiverse 启动 docker 并查看状态： root@ubuntu:/home/ubuntu# systemctl restart docker root@ubuntu:/home/ubuntu# systemctl status docker ● docker.service - Docker Application Container Engine Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset> Active: active (running) since Thu 2025-03-13 12:21:05 CST; 6s ago TriggeredBy: ● docker.socket Docs: https://docs.docker.com Main PID: 28525 (dockerd) Tasks: 10 Memory: 22.1M CPU: 1.228s CGroup: /system.slice/docker.service └─28525 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/con> Active: active (running) 表示 Docker 已正常运行，为后续 EdgeX 部署奠定了基础。 3.编译运行-EdgeX 有了 Docker 支持后，我们可以开始部署 EdgeX 服务。EdgeX 使用 Docker Compose 管理多个容器，因此需要进入 compose-builder 目录执行构建和运行命令： 进入目录并运行无安全模式的 EdgeX： cd /home/ubuntu/edgex/edgex-compose/compose-builder/ make run no-secty echo MQTT_VERBOSE= MQTT_VERBOSE= docker compose -p edgex -f docker-compose-base.yml -f add-postgres.yml -f add-mqtt-messagebus.yml -f add-mqtt-broker-mosquitto.yml convert --output docker-compose.yml.gen if [ "0" = "0" ]; then rm -rf ./gen_ext_compose; fi echo "# Generated with: Docker Compose version v2.33.1" > docker-compose.yml cat docker-compose.yml.gen >> docker-compose.yml rm docker-compose.yml.gen docker compose -p edgex up -d [+] Running 12/12 ✔ Container edgex-ui-go Running 0.0s ✔ Container edgex-postgres Running 0.0s ✔ Container edgex-mqtt-broker Running 0.0s ✔ Container edgex-core-keeper Running 0.0s ✔ Container edgex-core-metadata Running 0.0s ✔ Container edgex-core-common-config-bootstrapper Running 0.0s ✔ Container edgex-app-rules-engine Running 0.0s ✔ Container edgex-support-scheduler Running 0.0s ✔ Container edgex-core-data Running 0.0s ✔ Container edgex-kuiper Running 0.0s ✔ Container edgex-support-notifications Running 0.0s ✔ Container edgex-core-command Started 0.4s 这表明所有容器已启动，包括 UI、数据库和核心服务等。 查看容器运行状态，显示如下，每个容器显示 Up 状态，说明 EdgeX 已成功运行： docker compose ps NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS edgex-app-rules-engine nexus3.edgexfoundry.org:10004/app-service-configurable:latest "/app-service-config…" app-rules-engine 7 minutes ago Up 7 minutes 48095/tcp, 127.0.0.1:59701->59701/tcp edgex-core-command nexus3.edgexfoundry.org:10004/core-command:latest "/core-command --reg…" core-command 7 minutes ago Up 5 minutes 127.0.0.1:59882->59882/tcp edgex-core-common-config-bootstrapper nexus3.edgexfoundry.org:10004/core-common-config-bootstrapper:latest "entrypoint.sh /core…" core-common-config-bootstrapper 7 minutes ago Up 7 minutes edgex-core-data nexus3.edgexfoundry.org:10004/core-data:latest "/core-data --regist…" core-data 7 minutes ago Up 7 minutes 127.0.0.1:59880->59880/tcp edgex-core-keeper nexus3.edgexfoundry.org:10004/core-keeper:latest "/core-keeper" core-keeper 7 minutes ago Up 7 minutes 127.0.0.1:59890->59890/tcp edgex-core-metadata nexus3.edgexfoundry.org:10004/core-metadata:latest "/core-metadata ... 4.克隆源码-SDK-C 为了运行 device-sdk-c 的示例，我们还需要获取其源码。device-sdk-c 包含了丰富的 C 语言示例，是开发自定义设备服务的好起点： 在 /edgex 目录下克隆仓库： git clone https://github.com/edgexfoundry/device-sdk-c.git root@ubuntu:/home/ubuntu/edgex/edgex-compose/compose-builder# cd ../.. root@ubuntu:/home/ubuntu/edgex# ls edgex-compose root@ubuntu:/home/ubuntu/edgex# git clone https://github.com/edgexfoundry/device-sdk-c.git Cloning into 'device-sdk-c'... remote: Enumerating objects: 5641, done. remote: Counting objects: 100% (527/527), done. remote: Compressing objects: 100% (213/213), done. remote: Total 5641 (delta 419), reused 337 (delta 307), pack-reused 5114 (from 4) Receiving objects: 100% (5641/5641), 1.93 MiB | 1.70 MiB/s, done. Resolving deltas: 100% (3210/3210), done. 5.添加第三方依赖库 编译 device-sdk-c 需要一系列依赖库，参考官方 README（https://github.com/edgexfoundry/device-sdk-c/blob/main/README.md） A Linux build host A version of GCC supporting C11. CMake version 3 or greater and make. Development libraries and headers for: curl (version 7.56 or later) microhttpd (version 0.9) libyaml (version 0.1.6 or later) libcbor (version 0.5) paho (version 1.3.x) libuuid (from util-linux v2.x) IOTech's C utilities package (version 1.5) apt-get install libcurl4-openssl-dev libmicrohttpd-dev libyaml-dev libcbor-dev libpaho-mqtt-dev apt-get install lsb-release apt-transport-https curl gnupg curl -fsSL https://iotech.jfrog.io/artifactory/api/gpg/key/public | gpg --dearmor -o /usr/share/keyrings/iotech.gpg echo "deb [signed-by=/usr/share/keyrings/iotech.gpg] https://iotech.jfrog.io/iotech/debian-release $(lsb_release -cs) main" | tee -a /etc/apt/sources.list.d/iotech.list apt-get update apt-get install iotech-iot-1.5-dev apt install uuid-dev 6.编译-C SDK 在C SDK 顶层目录下, 运行 make，最终结果显示如下： root@ubuntu:/home/ubuntu/edgex/device-sdk-c# make ... [100%] Built target device-file 7.编译运行 random 设备服务示例 编译前的准备工作，参考https://github.com/edgexfoundry/device-sdk-c/blob/main/src/c/examples/random/README.md 此示例设备服务模拟了一个具有两个随机数生成器和一个可读取和写入状态的开关的设备。先配置环境变量，注意自己的路径： export CSDK_DIR=/home/logan/edgex/device-sdk-c/build/release/_CPack_Packages/Linux/TGZ/csdk-0.0.0 export LD_LIBRARY_PATH=$CSDK_DIR/lib:/opt/iotech/iot/1.5/lib 涉及头文件和库文件的环境变量很重要，并且运行程序的时候也需要用到。 在/random 目录下执行编译命令： gcc -I$CSDK_DIR/include -I/opt/iotech/iot/1.5/include -L$CSDK_DIR/lib -L/opt/iotech/iot/1.5/lib -o device-random device-random.c -lcsdk -liot 将编译好的可执行文件 device-random 复制到以下源文件目录，因为源文件目录提供了/res 里面包含预设的配置文件： cp device-sdk-c/build/release/c/examples/random/device-random device-sdk-c/src/c/examples/random/ cd /home/ubuntu/edgex/device-sdk-c/src/c/examples/random/ 执行以下命令：-o 表示覆盖默认配置，-cp 指定配置提供者 ./device-random -o -cp=keeper.http://localhost:59890 如果遇到报错，按以下方法解决： 安全 Token 报错：设置环境变量禁用安全服务： root@ubuntu:/home/ubuntu/edgex/device-sdk-c/src/c/examples/random# ./device-random -o -cp=keeper.http://localhost:59890 level=INFO ts=2025-03-13T06:44:41Z app=device-random msg="iot_threadpool_alloc (threads: 8 max_jobs: 0 default_priority: -1 affinity: -1)" level=INFO ts=2025-03-13T06:44:41Z app=device-random msg="iot_scheduler_alloc (priority: -1 affinity: -1)" level=ERROR ts=2025-03-13T06:44:41Z app=device-random msg="vault: Token file /tmp/edgex/secrets/device-random/secrets-token.json doesn't parse as JSON" Error: 4: Configuration is invalid 解决：需要关闭Edges安全服务： 参考https://docs.edgexfoundry.org/4.0/microservices/configuration/CommonEnvironmentVariables/#edgex_security_secret_store export EDGEX_SECURITY_SECRET_STORE="false" Curl 解析失败：编辑 /etc/hosts： level=DEBUG ts=2025-03-13T06:45:41Z app=device-random msg="mqtt: subscribing to edgex/configs/edgex/v4/core-common-config-bootstrapper/all-services/#" level=DEBUG ts=2025-03-13T06:45:41Z app=device-random msg="mqtt: subscribing to edgex/configs/edgex/v4/core-common-config-bootstrapper/device-services/#" level=ERROR ts=2025-03-13T06:45:42Z app=device-random msg="Curl failed with code 6 (Couldn't resolve host name)" level=ERROR ts=2025-03-13T06:45:43Z app=device-random msg="Curl failed with code 6 (Couldn't resolve host name)" level=ERROR ts=2025-03-13T06:45:44Z app=device-random msg="Curl failed with code 6 (Couldn't resolve host name)" level=ERROR ts=2025-03-13T06:45:45Z app=device-random msg="Curl failed with code 6 (Couldn't resolve host name)" level=ERROR ts=2025-03-13T06:45:46Z app=device-random msg="Curl failed with code 6 (Couldn't resolve host name)" level=ERROR ts=2025-03-13T06:45:47Z app=device-random msg="Curl failed with code 6 (Couldn't resolve host name)" 解决：在/etc/hosts 中添加127.0.0.1 edgex-core-metadata： /etc/hosts 127.0.0.1 localhost 127.0.0.1 edgex-core-metadata # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters ff02::3 ip6-allhosts 健康检查间隔缺失：修改 res/configuration.yml： level=DEBUG ts=2025-03-13T06:50:39Z app=device-random msg="HTTP response: 404" level=DEBUG ts=2025-03-13T06:50:39Z app=device-random msg="HTTP response: 400" level=ERROR ts=2025-03-13T06:50:39Z app=device-random msg="Register service failed: {"apiVersion":"v3","message":"AddRegistrationRequest.Registration.HealthCheck.Interval field is required","statusCode":400} level=ERROR ts=2025-03-13T06:50:39Z app=device-random msg="Unable to register service in registry" Error: 21: HTTP request failed level=DEBUG ts=2025-03-13T06:50:39Z app=device-random msg="Scheduler thread stopping" 解决：在res/configration.yml 中添加 HealthCheckInterval: 10s： Writable: LogLevel: DEBUG Service: Host: localhost Port: 59999 StartupMsg: Example random device service started HealthCheckInterval: 10s ​ 或者在/etc/hosts 中添加127.0.0.1 edgex-mqtt-broker,然后在执行命令 ./device-random -o -cp=keeper.http://localhost:59890 中去掉 -o： /etc/hosts 127.0.0.1 localhost 127.0.0.1 edgex-core-metadata 127.0.0.1 edgex-mqtt-broker # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters ff02::3 ip6-allhosts 如果程序运行成功，将显示如下： ... level=INFO ts=2025-03-13T07:36:45Z app=device-random correlation-id=c26ef1f7-755c-4952-8091-5c7c436e039b msg="AutoEvent: RandomDevice1/SensorOne" level=INFO ts=2025-03-13T07:36:50Z app=device-random correlation-id=dc222997-3113-465b-9c5c-26829ce24901 msg="AutoEvent: RandomDevice1/SensorTwo" level=INFO ts=2025-03-13T07:36:55Z app=device-random correlation-id=049d560d-896a-4e5a-8101-f3364c2767f1 msg="AutoEvent: RandomDevice1/SensorOne" 打开浏览器进入：localhost:4000 可发现一个设备服务，可成功读取随机数，如下： 总结 通过以上步骤，我们成功地在 Ubuntu 22.04 上完成了 EdgeX 的安装，并运行了 device-sdk-c 的 random 设备服务示例。从源码的克隆到 Docker 环境的搭建，再到依赖库的安装和配置文件的调整，每一个环节都环环相扣，考验着我们的耐心和解决问题的能力。 过程中可能遇到的报错，如安全性 token 问题、Curl 解析失败或健康检查间隔配置缺失，也提醒我们在操作复杂系统时，细节的重要性不容忽视。 最终，当我们在浏览器中看到 localhost:4000 界面上显示的设备服务和随机数据时，那份成就感无疑是对所有努力的最好回报。这不仅是一个技术实现的过程，更是一次对 EdgeX 架构和边缘计算理念的深入学习之旅。未来，我们还可以基于此基础，进一步扩展功能、优化性能，让边缘计算的潜力在更多场景中得以释放！
在 ubuntu22.04 中 安装 OpenVINO 并运行 Hello Classification C Sample
在 ubuntu22.04 中 安装 OpenVINO 并运行 Hello Classification C Sample 1.克隆源码 2.安装依赖 和 编译 3.安装项目 4.配置环境变量 5.编译 Sample 总结 在 ubuntu22.04 中 安装 OpenVINO 并运行 Hello Classification C Sample 从GitHub上获取一个项目的源码并成功运行其Demo，虽然看似简单，但实际上涉及多个步骤和注意事项。这个过程不仅需要对Git的基本操作有所了解，还需要根据项目的具体需求进行环境配置、依赖安装和构建工具的使用。以下是一个相对通用的流程，以OpenVINO项目的编译、安装、运行为例，详细描述从克隆源码到运行Demo的各个步骤。 1.克隆源码 在 root 下创建文件夹目录 mkdir devel && cd devel mkdir openvino && cd 克隆新版本源码 git clone -b 2025.0.0 https://github.com/openvinotoolkit/openvino.git 注意版本号2025.0.0 2.安装依赖 和 编译 编译流程中，前2~5点参考的https://github.com/openvinotoolkit/openvino/blob/2025.0.0/docs/dev/build_linux.md 编译和构建软件之前，安装必要的开发工具和库： sudo apt install build-essential -y OpenVINO 包含一些子模块，还需要更新，国内推荐使用gitee：（时间稍长 须作等待） cd openvino chmod +x scripts/submodule_update_with_gitee.sh ./scripts/submodule_update_with_gitee.sh 使用项目根目录脚本安装依赖项： sudo ./install_build_dependencies.sh 编译的准备工作： mkdir build && cd build OpenVINO Runtime使用基于CMake的构建系统。在创建的构建目录中，运行cmake获取项目依赖关系并创建Unix makefile，然后运行make构建项目： cmake -DCMAKE_BUILD_TYPE=Release .. cmake --build . --parallel 4 （ 通过 nproc 命令查询到 CPU 核心数为 4 ）编译时间漫长，成功后显示如下： 3.安装项目 目的: 将编译结果安装到系统指定位置。 在 build 文件下执行安装命令： sudo cmake --install . 文件会被安装到 /usr/local 如果只是运行 sample，可以跳过此步，直接使用构建目录中的文件。但建议规范安装好完整项目，从 /usr/local/sample 下获取 sample 源码和编译文件。 此时注意到：/usr/local/include 为 openvino 规范的头文件路径，/usr/local/lib/intel64/ 为规范的库文件路径。在 install 之前，二者的路径为/源码/src/bindings/c/include 以及/bin/intel64/Release ，使用它们并不规范！ 4.配置环境变量 目的: 告诉系统的动态链接器等（ld.so）在运行时查找共享库（.so 文件）的额外路径。在 OpenVINO 的例子中，/usr/local/lib/intel64/ 包含编译后的动态库（如 libopenvino.so），程序运行时需要这些库。如果这个路径没有被正确设置，运行程序时可能会遇到错误。openvino 提供了配置脚本 /usr/local/setupvars.sh ，执行 source 命令启动它： source /usr/local/setupvars.sh 注意： 不能直接执行 ./usr/local/setupvars.sh 。因为./setupvars.sh 会在一个新的子 Shell 进程中执行脚本。脚本中设置的环境变量只在子进程中生效，子进程结束后，这些修改不会传递回父 Shell（即你的当前终端）。 OpenVINO 的 setupvars.sh 脚本也是临时的，除非你每次打开终端都运行它，否则需要手动永久设置。 永久设置：（设置需要用到的环境变量） vim ~/.bashrc # .bashrc末尾添加 export LD_LIBRARY_PATH=/usr/local/runtime/3rdparty/tbb/lib:/usr/local/runtime/lib/intel64:$LD_LIBRARY_PATH export PYTHONPATH=/usr/local/python:/usr/local/python/python3:$PYTHONPATH 5.编译 Sample 参考：https://docs.openvino.ai/2025/get-started/learn-openvino/openvino-samples/get-started-demos.html#build-samples 在 <INSTALL_DIR>/samples/c 下执行 source build_samples.sh 命令，如下所示： 根据编译结果的提示，找到二进制可执行文件路径/home/ubuntu/openvino_c_samples_build/intel64/Release 准备好模型文件 alexnet.xml 和 alexnet.bin 之后，准备一张 png 图片 运行程序，结果如下即为运行成功： 总结 本文描述了从 GitHub 获取 OpenVINO 源码并运行Demo的过程，也可简化为以下几个核心步骤： 克隆源码：使用git clone下载项目到本地。 阅读文档：查看README.md，了解项目的安装、依赖和构建说明。 安装依赖：根据项目需求，安装必要的工具和库。 构建项目：使用构建工具（如CMake、Make）编译源码。 配置环境：设置环境变量或路径，确保项目正常运行。 运行Demo：执行Demo，验证项目功能。 每个项目的具体步骤可能会有所不同，但遵循这个通用流程可以帮助你快速上手大多数开源项目。无论是学习新技术、参与开源社区，还是将开源项目应用于实际工作中，掌握这些基本操作都是非常重要的。