跳到主要内容

OpenTwins Linux 离线环境部署指南

本文档参考 OpenTwins 官方文档,提供 Linux 离线环境下的完整部署指南。

一、部署概述

1.1 离线部署挑战

离线环境部署需要提前准备:

  • 所有必需的 Docker 镜像
  • Helm Charts 及其依赖
  • 二进制安装包(kubectl、helm、docker 等)
  • 相关配置文件和脚本

1.2 部署架构

1离线服务器
2├── Docker 容器运行时
3├── Kubernetes 集群(单节点或多节点)
4├── Helm 包管理器
5└── OpenTwins 平台组件
6 ├── Eclipse Ditto(数字孪生核心)
7 ├── Mosquitto(MQTT 消息代理)
8 ├── InfluxDB(时序数据库)
9 ├── Grafana(数据可视化)
10 └── OpenTwins Frontend(Web 界面)

1.3 系统要求

硬件要求

  • CPU: 4 核心或以上
  • 内存: 8GB RAM(最低),推荐 16GB
  • 磁盘: 至少 40GB 可用空间
  • 网络: 离线环境,需要内网连接

软件要求

  • 操作系统: CentOS 7/8、RHEL 7/8、Ubuntu 18.04/20.04/22.04、Debian 10/11
  • 内核版本: 3.10+
  • SELinux: 可选关闭或配置

二、准备阶段(联网环境)

重要

此阶段需要在有互联网连接的机器上完成,准备好所有资源后传输到离线环境。

2.1 创建资源目录结构

bash
1mkdir -p /opt/opentwins-offline/{binaries,images,charts,scripts}
2cd /opt/opentwins-offline

2.2 下载二进制文件

下载 Docker

bash
1# CentOS/RHEL
2wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-20.10.24-3.el7.x86_64.rpm
3wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-cli-20.10.24-3.el7.x86_64.rpm
4wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.6.21-3.1.el7.x86_64.rpm
5
6# Ubuntu/Debian
7wget https://download.docker.com/linux/ubuntu/dists/focal/pool/stable/amd64/docker-ce_20.10.24~3-0~ubuntu-focal_amd64.deb
8wget https://download.docker.com/linux/ubuntu/dists/focal/pool/stable/amd64/docker-ce-cli_20.10.24~3-0~ubuntu-focal_amd64.deb
9wget https://download.docker.com/linux/ubuntu/dists/focal/pool/stable/amd64/containerd.io_1.6.21-1_amd64.deb
10
11# 移动到 binaries 目录
12mv *.rpm *.deb binaries/

下载 kubectl

bash
1cd binaries
2# 下载 kubectl(选择合适的版本)
3curl -LO "https://dl.k8s.io/release/v1.28.0/bin/linux/amd64/kubectl"
4chmod +x kubectl

下载 Helm

bash
1cd binaries
2# 下载 Helm v3
3wget https://get.helm.sh/helm-v3.13.0-linux-amd64.tar.gz
4tar -xzf helm-v3.13.0-linux-amd64.tar.gz
5mv linux-amd64/helm ./
6rm -rf linux-amd64 helm-v3.13.0-linux-amd64.tar.gz
7chmod +x helm

下载 Minikube(用于单节点部署)

bash
1cd binaries
2curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
3mv minikube-linux-amd64 minikube
4chmod +x minikube

2.3 下载 Helm Charts

bash
1cd /opt/opentwins-offline/charts
2
3# 添加 Helm 仓库
4helm repo add ertis https://ertis-research.github.io/Helm-charts/
5helm repo update
6
7# 下载 OpenTwins Chart 及其依赖
8helm pull ertis/OpenTwins --untar
9helm dependency update OpenTwins/
10
11# 打包所有 charts
12helm package OpenTwins/
13
14# 下载依赖的 charts(如果需要)
15# 根据 OpenTwins/Chart.yaml 中的依赖列表下载

2.4 导出 Docker 镜像

创建镜像列表文件 images-list.txt

bash
1cd /opt/opentwins-offline/images
2cat > images-list.txt << 'EOF'
3# Eclipse Ditto 组件
4eclipse/ditto-policies:latest
5eclipse/ditto-things:latest
6eclipse/ditto-things-search:latest
7eclipse/ditto-gateway:latest
8eclipse/ditto-connectivity:latest
9eclipse/ditto-concierge:latest
10nginx:alpine
11
12# MongoDB(Ditto 使用)
13mongo:4.4
14
15# Mosquitto MQTT
16eclipse-mosquitto:2.0
17
18# InfluxDB
19influxdb:2.7
20
21# Grafana
22grafana/grafana:latest
23
24# OpenTwins Frontend
25# 需要查看 Helm Chart values.yaml 确认具体镜像
26
27# Kubernetes 基础组件(如果使用 minikube)
28registry.k8s.io/pause:3.9
29registry.k8s.io/kube-apiserver:v1.28.0
30registry.k8s.io/kube-controller-manager:v1.28.0
31registry.k8s.io/kube-scheduler:v1.28.0
32registry.k8s.io/kube-proxy:v1.28.0
33registry.k8s.io/etcd:3.5.9-0
34registry.k8s.io/coredns/coredns:v1.10.1
35
36# Storage provisioner(如果使用)
37k8s.gcr.io/storage-provisioner:v5
38EOF

下载并保存镜像:

bash
1cd /opt/opentwins-offline/images
2
3# 创建镜像下载脚本
4cat > pull-images.sh << 'EOF'
5#!/bin/bash
6while IFS= read -r image; do
7 # 跳过注释和空行
8 [[ "$image" =~ ^#.*$ ]] && continue
9 [[ -z "$image" ]] && continue
10
11 echo "正在拉取镜像: $image"
12 docker pull "$image"
13
14 # 保存镜像
15 image_file=$(echo "$image" | sed 's/[\/:]/_/g').tar
16 echo "正在保存镜像到: $image_file"
17 docker save -o "$image_file" "$image"
18done < images-list.txt
19
20echo "所有镜像已下载并保存完成"
21EOF
22
23chmod +x pull-images.sh
24./pull-images.sh

2.5 创建部署脚本

离线安装脚本

bash
1cd /opt/opentwins-offline/scripts
2
3cat > 01-install-docker.sh << 'EOF'
4#!/bin/bash
5set -e
6
7echo "========================================"
8echo "开始安装 Docker"
9echo "========================================"
10
11# 检测操作系统
12if [ -f /etc/os-release ]; then
13 . /etc/os-release
14 OS=$ID
15else
16 echo "无法检测操作系统"
17 exit 1
18fi
19
20cd /opt/opentwins-offline/binaries
21
22case $OS in
23 centos|rhel)
24 echo "在 CentOS/RHEL 上安装 Docker"
25 sudo yum install -y *.rpm
26 ;;
27 ubuntu|debian)
28 echo "在 Ubuntu/Debian 上安装 Docker"
29 sudo dpkg -i *.deb
30 sudo apt-get install -f -y
31 ;;
32 *)
33 echo "不支持的操作系统: $OS"
34 exit 1
35 ;;
36esac
37
38# 启动 Docker
39sudo systemctl start docker
40sudo systemctl enable docker
41
42# 验证安装
43docker --version
44
45echo "Docker 安装完成"
46EOF
47
48chmod +x 01-install-docker.sh
bash
1cat > 02-load-images.sh << 'EOF'
2#!/bin/bash
3set -e
4
5echo "========================================"
6echo "开始加载 Docker 镜像"
7echo "========================================"
8
9cd /opt/opentwins-offline/images
10
11for tar_file in *.tar; do
12 echo "正在加载: $tar_file"
13 docker load -i "$tar_file"
14done
15
16echo "镜像加载完成"
17docker images
18EOF
19
20chmod +x 02-load-images.sh
bash
1cat > 03-install-kubectl-helm.sh << 'EOF'
2#!/bin/bash
3set -e
4
5echo "========================================"
6echo "安装 kubectl 和 Helm"
7echo "========================================"
8
9cd /opt/opentwins-offline/binaries
10
11# 安装 kubectl
12sudo cp kubectl /usr/local/bin/
13sudo chmod +x /usr/local/bin/kubectl
14
15# 安装 helm
16sudo cp helm /usr/local/bin/
17sudo chmod +x /usr/local/bin/helm
18
19# 验证安装
20kubectl version --client
21helm version
22
23echo "kubectl 和 Helm 安装完成"
24EOF
25
26chmod +x 03-install-kubectl-helm.sh
bash
1cat > 04-setup-minikube.sh << 'EOF'
2#!/bin/bash
3set -e
4
5echo "========================================"
6echo "设置 Minikube Kubernetes 集群"
7echo "========================================"
8
9cd /opt/opentwins-offline/binaries
10
11# 安装 minikube
12sudo cp minikube /usr/local/bin/
13sudo chmod +x /usr/local/bin/minikube
14
15# 启动 minikube(使用 Docker 驱动,离线模式)
16minikube start \
17 --cpus 4 \
18 --memory 8192 \
19 --disk-size 40gb \
20 --driver=docker \
21 --image-mirror-country=cn \
22 --base-image="gcr.io/k8s-minikube/kicbase:v0.0.42"
23
24# 配置 kubectl
25kubectl config use-context minikube
26
27# 验证集群
28kubectl cluster-info
29kubectl get nodes
30
31echo "Minikube 集群设置完成"
32EOF
33
34chmod +x 04-setup-minikube.sh
bash
1cat > 05-deploy-opentwins.sh << 'EOF'
2#!/bin/bash
3set -e
4
5echo "========================================"
6echo "部署 OpenTwins 平台"
7echo "========================================"
8
9cd /opt/opentwins-offline/charts
10
11# 创建本地 Helm 仓库
12helm repo add local file://$(pwd)
13helm repo update
14
15# 安装 OpenTwins
16helm upgrade --install opentwins ./OpenTwins-*.tgz \
17 --wait \
18 --timeout 20m \
19 --set global.imageRegistry="" \
20 --set global.imagePullPolicy=IfNotPresent
21
22# 等待所有 Pod 就绪
23echo "等待所有 Pod 启动..."
24kubectl wait --for=condition=ready pod --all --timeout=600s
25
26# 显示部署状态
27kubectl get pods
28kubectl get services
29
30echo "========================================"
31echo "OpenTwins 部署完成!"
32echo "========================================"
33EOF
34
35chmod +x 05-deploy-opentwins.sh
bash
1cat > 06-port-forward.sh << 'EOF'
2#!/bin/bash
3
4echo "========================================"
5echo "设置端口转发"
6echo "========================================"
7
8# 获取 Pod 名称
9FRONTEND_POD=$(kubectl get pods -l app=opentwins-frontend -o jsonpath='{.items[0].metadata.name}')
10GRAFANA_POD=$(kubectl get pods -l app=grafana -o jsonpath='{.items[0].metadata.name}')
11
12# 在后台启动端口转发
13echo "启动端口转发..."
14
15# OpenTwins 前端 - 端口 3000
16kubectl port-forward svc/opentwins-frontend 3000:80 > /dev/null 2>&1 &
17echo "OpenTwins 前端: http://localhost:3000"
18
19# Ditto nginx - 端口 8080
20kubectl port-forward svc/ditto-nginx 8080:8080 > /dev/null 2>&1 &
21echo "Ditto API: http://localhost:8080"
22
23# Mosquitto MQTT - 端口 1883
24kubectl port-forward svc/mosquitto 1883:1883 > /dev/null 2>&1 &
25echo "Mosquitto MQTT: localhost:1883"
26
27# Grafana - 端口 3001
28kubectl port-forward svc/grafana 3001:3000 > /dev/null 2>&1 &
29echo "Grafana: http://localhost:3001"
30
31echo "========================================"
32echo "端口转发已启动"
33echo "使用 'pkill -f port-forward' 停止所有转发"
34echo "========================================"
35EOF
36
37chmod +x 06-port-forward.sh

2.6 打包资源

bash
1cd /opt
2tar -czf opentwins-offline-package.tar.gz opentwins-offline/

opentwins-offline-package.tar.gz 传输到离线服务器。

三、离线环境部署

3.1 传输资源包

使用 USB 驱动器、内网文件传输或其他方式将资源包传输到离线服务器:

bash
1# 在离线服务器上
2cd /opt
3# 假设已经将 opentwins-offline-package.tar.gz 复制到此目录
4
5# 解压资源包
6tar -xzf opentwins-offline-package.tar.gz

3.2 执行安装

bash
1cd /opt/opentwins-offline/scripts
2
3# 步骤 1: 安装 Docker
4sudo ./01-install-docker.sh
5
6# 步骤 2: 加载 Docker 镜像
7sudo ./02-load-images.sh
8
9# 步骤 3: 安装 kubectl 和 Helm
10sudo ./03-install-kubectl-helm.sh
11
12# 步骤 4: 设置 Kubernetes 集群
13sudo ./04-setup-minikube.sh
14
15# 步骤 5: 部署 OpenTwins
16./05-deploy-opentwins.sh

3.3 验证部署

bash
1# 检查所有 Pod 状态
2kubectl get pods --all-namespaces
3
4# 检查服务
5kubectl get services
6
7# 查看 OpenTwins 组件
8kubectl get pods -l app.kubernetes.io/name=opentwins

3.4 设置访问

bash
1# 启动端口转发
2cd /opt/opentwins-offline/scripts
3./06-port-forward.sh
4
5# 或者使用 NodePort 服务(持久访问)
6kubectl patch svc opentwins-frontend -p '{"spec":{"type":"NodePort"}}'
7kubectl patch svc grafana -p '{"spec":{"type":"NodePort"}}'
8
9# 获取 NodePort
10kubectl get svc opentwins-frontend
11kubectl get svc grafana

四、配置 OpenTwins

4.1 访问 Web 界面

bash
1# 如果使用端口转发
2http://localhost:3000
3
4# 如果使用 NodePort
5http://<节点IP>:<NodePort>

4.2 配置 Ditto 连接

  1. 在 OpenTwins 界面中配置:
    • Ditto nginx 地址: http://ditto-nginx:8080(集群内)或 http://localhost:8080(端口转发)
    • Ditto Extended API: http://ditto-nginx:8080/api/ditto-extended

4.3 创建数字孪生

参考官方文档创建数字孪生的步骤与在线环境相同:

创建 Car 类型

json
1{
2 "thingId": "example:car",
3 "policyId": "default:basic_policy",
4 "attributes": {
5 "name": "Car",
6 "description": "数字孪生汽车示例",
7 "image": "https://images.pexels.com/photos/119435/pexels-photo-119435.jpeg"
8 },
9 "features": {
10 "gps": {
11 "properties": {
12 "latitude": null,
13 "longitude": null
14 }
15 }
16 }
17}

创建 Wheel 类型

json
1{
2 "thingId": "example:wheel",
3 "policyId": "default:basic_policy",
4 "attributes": {
5 "name": "Wheel",
6 "description": "车轮数字孪生",
7 "image": "https://images.pexels.com/photos/111766/pexels-photo-111766.jpeg"
8 },
9 "features": {
10 "velocity": {
11 "properties": {
12 "value": null
13 }
14 },
15 "direction": {
16 "properties": {
17 "value": null
18 }
19 }
20 }
21}

五、数据接入

5.1 准备 Python 环境

bash
1# 如果离线环境没有 Python,需要提前准备
2# 在联网环境下载 Python 和依赖包
3
4# 下载 paho-mqtt(联网环境)
5pip download paho-mqtt -d /opt/opentwins-offline/python-packages/
6
7# 在离线环境安装
8pip install --no-index --find-links=/opt/opentwins-offline/python-packages/ paho-mqtt

5.2 创建数据模拟器

创建 car_simulator.py

python
1#!/usr/bin/env python3
2import paho.mqtt.client as mqtt
3import json
4import time
5import random
6
7# 配置参数
8MQTT_BROKER = "localhost" # 或者 Kubernetes 节点 IP
9MQTT_PORT = 1883
10TOPIC_PREFIX = "ditto/"
11NAMESPACE = "example"
12CAR_NAME = "mycar"
13WHEEL_PREFIX = "mycar:wheel_"
14
15def on_connect(client, userdata, flags, rc):
16 if rc == 0:
17 print(f"已成功连接到 MQTT Broker: {MQTT_BROKER}:{MQTT_PORT}")
18 else:
19 print(f"连接失败,返回码: {rc}")
20
21def on_publish(client, userdata, mid):
22 print(f"消息 {mid} 已发布")
23
24# 初始化 MQTT 客户端
25client = mqtt.Client()
26client.on_connect = on_connect
27client.on_publish = on_publish
28
29try:
30 client.connect(MQTT_BROKER, MQTT_PORT, 60)
31 client.loop_start()
32except Exception as e:
33 print(f"MQTT 连接错误: {e}")
34 exit(1)
35
36def generate_wheel_data():
37 """生成车轮模拟数据"""
38 velocity = random.uniform(0.0, 120.0)
39 direction = random.uniform(-45.0, 45.0)
40 return velocity, direction
41
42def generate_gps_data():
43 """生成 GPS 模拟数据"""
44 # 模拟在某个区域内移动
45 base_lat, base_lon = 39.9042, 116.4074 # 北京天安门
46 latitude = base_lat + random.uniform(-0.01, 0.01)
47 longitude = base_lon + random.uniform(-0.01, 0.01)
48 return latitude, longitude
49
50def create_ditto_message(thing_id, features_update):
51 """创建 Ditto 协议消息"""
52 return {
53 "topic": f"{NAMESPACE}/{thing_id}/things/twin/commands/merge",
54 "headers": {
55 "content-type": "application/merge-patch+json"
56 },
57 "path": "/features",
58 "value": features_update
59 }
60
61def publish_car_data(timestamp, latitude, longitude):
62 """发布汽车数据"""
63 features = {
64 "gps": {
65 "properties": {
66 "latitude": latitude,
67 "longitude": longitude,
68 "timestamp": timestamp
69 }
70 }
71 }
72 message = create_ditto_message(CAR_NAME, features)
73 topic = f"{TOPIC_PREFIX}{NAMESPACE}/{CAR_NAME}"
74 client.publish(topic, json.dumps(message))
75 print(f"✓ {CAR_NAME}: GPS ({latitude:.6f}, {longitude:.6f})")
76
77def publish_wheel_data(wheel_num, timestamp, velocity, direction):
78 """发布车轮数据"""
79 thing_id = f"{WHEEL_PREFIX}{wheel_num}"
80 features = {
81 "velocity": {
82 "properties": {
83 "value": velocity,
84 "timestamp": timestamp
85 }
86 },
87 "direction": {
88 "properties": {
89 "value": direction,
90 "timestamp": timestamp
91 }
92 }
93 }
94 message = create_ditto_message(thing_id, features)
95 topic = f"{TOPIC_PREFIX}{NAMESPACE}/{thing_id}"
96 client.publish(topic, json.dumps(message))
97 print(f"✓ {thing_id}: 速度={velocity:.2f} km/h, 方向={direction:.2f}°")
98
99# 主循环
100print("="*60)
101print("数字孪生数据模拟器已启动")
102print("="*60)
103
104try:
105 iteration = 0
106 while True:
107 iteration += 1
108 timestamp = int(time.time() * 1000)
109
110 print(f"\n--- 第 {iteration} 次数据更新 (时间戳: {timestamp}) ---")
111
112 # 发布汽车数据
113 latitude, longitude = generate_gps_data()
114 publish_car_data(timestamp, latitude, longitude)
115
116 # 发布四个车轮数据
117 for i in range(1, 5):
118 velocity, direction = generate_wheel_data()
119 publish_wheel_data(i, timestamp, velocity, direction)
120
121 print(f"--- 完成,等待 5 秒... ---")
122 time.sleep(5)
123
124except KeyboardInterrupt:
125 print("\n\n程序被用户中断")
126finally:
127 client.loop_stop()
128 client.disconnect()
129 print("已断开 MQTT 连接")

5.3 运行模拟器

bash
1chmod +x car_simulator.py
2python3 car_simulator.py

六、数据可视化

6.1 访问 Grafana

bash
1# 获取 Grafana 访问信息
2kubectl get svc grafana
3
4# 获取默认密码(如果使用了 secret)
5kubectl get secret grafana-admin-password -o jsonpath="{.data.password}" | base64 --decode

访问: http://localhost:3001http://<节点IP>:<NodePort>

默认凭据:

  • 用户名: admin
  • 密码: 查看上述命令输出或 Helm values

6.2 配置 InfluxDB 数据源

  1. 登录 Grafana
  2. 导航到 Configuration → Data Sources
  3. 添加 InfluxDB 数据源:
    • URL: http://influxdb:8086(集群内地址)
    • Database: opentwins
    • Query Language: Flux

6.3 创建仪表板

创建四个面板监控数字孪生数据:

面板 1: 当前 GPS 位置

flux
1import "strings"
2from(bucket: "opentwins")
3 |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
4 |> filter(fn: (r) => r["_measurement"] == "mqtt_consumer")
5 |> filter(fn: (r) => r["thingId"] == "example:mycar")
6 |> filter(fn: (r) => r["_field"] == "value_gps_properties_latitude" or
7 r["_field"] == "value_gps_properties_longitude")
8 |> map(fn: (r) => ({ r with _field: strings.replace(v: r["_field"],
9 t: "value_gps_properties_",
10 u: "", i: 2) }))
11 |> keep(columns: ["_value", "_field", "_time"])
12 |> sort(columns: ["_time"], desc: false)
13 |> last()

面板 2: GPS 轨迹

flux
1import "strings"
2from(bucket: "opentwins")
3 |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
4 |> filter(fn: (r) => r["_measurement"] == "mqtt_consumer")
5 |> filter(fn: (r) => r["thingId"] == "example:mycar")
6 |> filter(fn: (r) => r["_field"] == "value_gps_properties_latitude" or
7 r["_field"] == "value_gps_properties_longitude")
8 |> map(fn: (r) => ({ r with _field: strings.replace(v: r["_field"],
9 t: "value_gps_properties_",
10 u: "", i: 2) }))
11 |> keep(columns: ["_value", "_field", "_time"])

面板 3: 车轮方向

flux
1import "strings"
2from(bucket: "opentwins")
3 |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
4 |> filter(fn: (r) => r["_measurement"] == "mqtt_consumer")
5 |> filter(fn: (r) => strings.hasPrefix(v: r["thingId"], prefix: "example:mycar:wheel_"))
6 |> filter(fn: (r) => r["_field"] == "value_direction_properties_value")
7 |> map(fn: (r) => ({ r with thingId: strings.replace(v: r["thingId"],
8 t: "example:mycar:",
9 u: "", i: 2) }))
10 |> keep(columns: ["thingId", "_value", "_time"])
11 |> sort(columns: ["_time"], desc: false)
12 |> last()

面板 4: 车轮速度对比

flux
1import "strings"
2from(bucket: "opentwins")
3 |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
4 |> filter(fn: (r) => r["_measurement"] == "mqtt_consumer")
5 |> filter(fn: (r) => strings.hasPrefix(v: r["thingId"], prefix: "example:mycar:wheel_"))
6 |> filter(fn: (r) => r["_field"] == "value_velocity_properties_value")
7 |> map(fn: (r) => ({ r with thingId: strings.replace(v: r["thingId"],
8 t: "example:mycar:",
9 u: "", i: 2) }))
10 |> keep(columns: ["thingId", "_value", "_time"])

七、多节点集群部署(可选)

如果需要在多节点集群上部署(而非 minikube):

7.1 准备集群节点

在所有节点上:

bash
1# 加载 Docker 镜像
2cd /opt/opentwins-offline/images
3for tar_file in *.tar; do
4 docker load -i "$tar_file"
5done

7.2 使用 kubeadm 部署集群

参考 Kubernetes 官方离线部署文档,或使用以下简化步骤:

bash
1# 主节点
2kubeadm init --pod-network-cidr=10.244.0.0/16
3
4# 配置 kubectl
5mkdir -p $HOME/.kube
6sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
7sudo chown $(id -u):$(id -g) $HOME/.kube/config
8
9# 工作节点加入
10# 在工作节点上执行主节点 init 输出的 join 命令
11kubeadm join <主节点IP>:6443 --token <token> --discovery-token-ca-cert-hash <hash>

7.3 部署网络插件(离线)

需要提前准备 CNI 插件镜像(如 Calico、Flannel)并加载到所有节点。

八、故障排除

8.1 镜像拉取失败

bash
1# 检查镜像是否已加载
2docker images
3
4# 手动加载缺失的镜像
5docker load -i /opt/opentwins-offline/images/<镜像文件>.tar

8.2 Pod 无法启动

bash
1# 查看 Pod 详情
2kubectl describe pod <pod-name>
3
4# 查看日志
5kubectl logs <pod-name>
6
7# 检查事件
8kubectl get events --sort-by='.lastTimestamp'

8.3 Helm 安装失败

bash
1# 查看详细日志
2helm upgrade --install opentwins ./OpenTwins-*.tgz --debug
3
4# 检查 values
5helm get values opentwins
6
7# 回滚
8helm rollback opentwins

8.4 MQTT 连接问题

bash
1# 检查 Mosquitto 服务
2kubectl get svc mosquitto
3kubectl logs <mosquitto-pod>
4
5# 测试 MQTT 连接(需要 mosquitto-clients)
6mosquitto_pub -h localhost -p 1883 -t "test" -m "hello"

8.5 数据未存储到 InfluxDB

bash
1# 检查 Ditto 连接状态
2kubectl logs <ditto-connectivity-pod>
3
4# 检查 InfluxDB
5kubectl exec -it <influxdb-pod> -- influx
6# 在 influx CLI 中
7> use opentwins
8> show measurements
9> select * from mqtt_consumer limit 10

九、性能优化

9.1 资源限制

编辑 Helm values 文件设置资源限制:

yaml
1resources:
2 limits:
3 cpu: 2000m
4 memory: 4Gi
5 requests:
6 cpu: 1000m
7 memory: 2Gi

9.2 持久化存储

配置 PersistentVolume 用于数据持久化:

yaml
1persistence:
2 enabled: true
3 storageClass: "local-storage"
4 size: 20Gi

9.3 高可用配置

增加副本数:

yaml
1replicaCount: 3

十、备份与恢复

10.1 备份数据

bash
1# 备份 InfluxDB
2kubectl exec <influxdb-pod> -- influxd backup /backup
3kubectl cp <influxdb-pod>:/backup ./influxdb-backup
4
5# 备份 MongoDB (Ditto 数据)
6kubectl exec <mongodb-pod> -- mongodump --out /backup
7kubectl cp <mongodb-pod>:/backup ./mongodb-backup
8
9# 备份 Kubernetes 配置
10kubectl get all --all-namespaces -o yaml > k8s-backup.yaml

10.2 恢复数据

bash
1# 恢复 InfluxDB
2kubectl cp ./influxdb-backup <influxdb-pod>:/backup
3kubectl exec <influxdb-pod> -- influxd restore /backup
4
5# 恢复 MongoDB
6kubectl cp ./mongodb-backup <mongodb-pod>:/backup
7kubectl exec <mongodb-pod> -- mongorestore /backup

十一、卸载

bash
1# 卸载 OpenTwins
2helm uninstall opentwins
3
4# 删除持久卷声明
5kubectl delete pvc --all
6
7# 停止 minikube
8minikube stop
9minikube delete
10
11# 清理 Docker 资源
12docker system prune -a

十二、参考资源

十三、高级功能

部署完成后,可以探索以下高级功能:

  • AI/ML 模型集成: 在数字孪生中集成机器学习模型
  • 3D 可视化: 添加 3D 模型展示
  • FMI 仿真: 集成 FMU 功能模拟单元
  • 边缘计算: 部署边缘节点进行分布式计算
  • 访问控制: 配置 Eclipse Ditto 策略进行细粒度权限管理

文档说明

本文档基于 OpenTwins 官方快速入门指南编写,针对 Linux 离线环境进行了优化和扩展。 最后更新:2025-10

重要提示

离线部署需要仔细规划和充分准备。建议先在联网环境测试完整流程,确保所有资源准备齐全后再进行离线部署。

评论