工业一体机Docker容器化部署实战:从镜像构建到远程OTA升级全流程
在工业自动化项目中,工业一体机往往需要部署多个应用服务——数据采集、设备通信、Web监控界面、边缘计算等。传统裸机部署方式存在依赖冲突、版本管理混乱、升级回滚困难等问题。Docker容器化方案通过隔离运行环境,让每个应用在独立的容器中运行,互不干扰,同时支持镜像版本管理和一键部署回滚,是工业一体机软件部署的推荐方案。
## 环境准备
本文以基于Debian 12的工业一体机为例,演示Docker容器化部署的完整流程。
### 安装Docker
```bash
# 更新软件包索引
sudo apt update
# 安装必要依赖
sudo apt install -y ca-certificates curl gnupg lsb-release
# 添加Docker官方GPG密钥
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# 添加Docker仓库
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list
# 安装Docker引擎
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 将当前用户加入docker组,免sudo
sudo usermod -aG docker $USER
```
### 配置Docker数据目录
工业一体机的系统盘空间通常有限,建议将Docker数据目录迁移到独立的存储分区:
```bash
# 停止Docker服务
sudo systemctl stop docker
# 迁移数据目录
sudo rsync -aP /var/lib/docker/ /data/docker/
# 修改Docker配置
sudo tee /etc/docker/daemon.json <<EOF
{
"data-root": "/data/docker",
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
EOF
# 重启Docker
sudo systemctl start docker
```
日志轮转配置很重要。工业设备长期运行不重启,如果不限制日志大小,容器日志文件会撑满磁盘导致设备异常。
## 构建工业应用镜像
以一个Python数据采集服务为例,编写Dockerfile:
```dockerfile
FROM python:3.11-slim
WORKDIR /app
# 安装系统依赖(串口库等)
RUN apt-get update && apt-get install -y --no-install-recommends \
libserialport-dev \
&& rm -rf /var/lib/apt/lists/*
# 安装Python依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 复制应用代码
COPY . .
# 配置时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 启动命令
CMD ["python", "-u", "main.py"]
```
构建镜像并打标签:
```bash
docker build -t data-collector:1.0.0 .
docker tag data-collector:1.0.0 registry.local:5000/data-collector:1.0.0
```
## 设备访问权限处理
Docker容器默认无法访问宿主机的串口和GPIO设备。需要在启动容器时通过`--device`参数映射设备节点:
```bash
docker run -d \
--name collector \
--restart unless-stopped \
--device /dev/ttyS0 \
--device /dev/ttyS1 \
--device /dev/gpiochip0 \
-e MQTT_BROKER=tcp://192.168.1.100:1883 \
-e SERIAL_PORT=/dev/ttyS0 \
-e BAUD_RATE=9600 \
-v /data/config:/app/config \
data-collector:1.0.0
```
如果容器需要访问GPIO,还需要确保容器内的用户有权限操作`/dev/gpiochip*`设备节点。可以通过`--privileged`参数(不推荐,权限过大)或者在容器内添加对gpio组的访问权限。
## Docker Compose多服务编排
实际项目中通常需要同时部署多个服务。使用Docker Compose管理:
```yaml
version: "3.8"
services:
data-collector:
image: registry.local:5000/data-collector:1.0.0
container_name: collector
restart: unless-stopped
devices:
- /dev/ttyS0
- /dev/ttyS1
environment:
- MQTT_BROKER=tcp://mqtt-broker:1883
- SERIAL_PORT=/dev/ttyS0
- BAUD_RATE=9600
volumes:
- ./config/collector:/app/config
depends_on:
- mqtt-broker
mqtt-broker:
image: eclipse-mosquitto:2.0
container_name: mqtt
restart: unless-stopped
ports:
- "1883:1883"
volumes:
- ./config/mosquitto:/mosquitto/config
web-monitor:
image: registry.local:5000/web-monitor:1.0.0
container_name: monitor
restart: unless-stopped
ports:
- "8080:80"
environment:
- MQTT_BROKER=tcp://mqtt-broker:1883
depends_on:
- mqtt-broker
```
启动服务:
```bash
docker compose up -d
```
## 远程OTA升级方案
工业一体机部署在现场后,手动逐台升级非常低效。可以通过本地镜像仓库实现远程OTA升级:
```bash
#!/bin/bash
# OTA升级脚本 upgrade.sh
REGISTRY="registry.local:5000"
APP_NAME="data-collector"
NEW_VERSION=$1
if [ -z "$NEW_VERSION" ]; then
echo "Usage: ./upgrade.sh <version>"
echo "Example: ./upgrade.sh 1.1.0"
exit 1
fi
echo "=== 开始OTA升级 $APP_NAME 到版本 $NEW_VERSION ==="
# 拉取新版本镜像
docker pull ${REGISTRY}/${APP_NAME}:${NEW_VERSION}
if [ $? -ne 0 ]; then
echo "镜像拉取失败,升级中止"
exit 1
fi
# 备份当前版本
CURRENT_VERSION=$(docker inspect --format='{{.Config.Image}}' collector 2>/dev/null | awk -F: '{print $2}')
echo "当前版本: $CURRENT_VERSION"
# 停止旧容器
docker stop collector
docker rename collector collector_backup
# 启动新版本容器
docker run -d \
--name collector \
--restart unless-stopped \
--device /dev/ttyS0 \
--device /dev/ttyS1 \
-e MQTT_BROKER=tcp://mqtt-broker:1883 \
-e SERIAL_PORT=/dev/ttyS0 \
-e BAUD_RATE=9600 \
-v /data/config:/app/config \
${REGISTRY}/${APP_NAME}:${NEW_VERSION}
# 验证新容器运行状态
sleep 5
if docker ps | grep -q collector; then
echo "新版本启动成功"
docker rm collector_backup
echo "$NEW_VERSION" > /data/version
else
echo "新版本启动失败,回滚到 $CURRENT_VERSION"
docker rename collector collector_failed
docker rename collector_backup collector
docker start collector
exit 1
fi
echo "=== 升级完成 ==="
```
脚本内置了回滚逻辑:如果新版本启动失败,自动恢复到旧版本。这在工业现场非常重要,因为设备不能长时间停机。
## 常见问题(FAQ)
**Q:Docker容器内如何访问宿主机的串口设备?**
在docker run时通过--device参数映射设备节点,例如--device /dev/ttyS0。也可以在Docker Compose中使用devices字段配置。注意容器内的应用代码使用映射后的设备路径访问串口,路径与宿主机一致。
**Q:工业一体机存储空间有限,如何清理Docker占用的空间?**
使用docker system prune命令清理未使用的镜像、容器和网络。同时通过daemon.json配置日志轮转参数限制单个容器日志文件大小和数量。建议定期执行docker image prune -a清理悬空镜像,但注意不要删除正在使用的镜像。
**Q:容器化部署会影响串口通信的实时性吗?**
会有轻微影响但通常可接受。Docker使用Linux命名空间隔离资源,串口设备通过直通方式映射到容器,不经过虚拟化层。实测在9600-115200波特率下,容器化部署与裸机部署的通信延迟差异在1ms以内。对实时性要求极高的场景建议使用裸机部署或RT Linux内核。
更多推荐

所有评论(0)