第 14 章:嵌入式应用
第 14 章:嵌入式应用
将 Alpine Linux 应用于嵌入式设备、IoT 场景和自定义系统构建。
14.1 嵌入式场景概览
| 场景 | 设备 | 资源需求 | 优势 |
|---|---|---|---|
| IoT 网关 | 树莓派 | 256MB RAM | 体积小、安全 |
| 边缘计算 | 工控机 | 512MB RAM | 快速启动、可靠 |
| 网络设备 | 路由器 | 128MB RAM | 网络功能完善 |
| 媒体中心 | 树莓派 | 1GB RAM | 轻量高效 |
| 工业控制 | ARM 板 | 128MB RAM | 实时性好 |
14.2 树莓派安装与配置
系统安装
# 下载树莓派镜像
wget https://dl-cdn.alpinelinux.org/alpine/v3.20/releases/aarch64/alpine-rpi-3.20.3-aarch64.tar.gz
# 写入 SD 卡
# ⚠️ 确认设备路径,错误将导致数据丢失
DISK=/dev/sdX
dd if=alpine-rpi-3.20.3-aarch64.tar.gz of=$DISK bs=4M status=progress conv=fsync
# 或使用 Raspberry Pi Imager
# 选择 Custom OS -> 选择 Alpine 镜像
# 首次启动后配置
ssh root@<树莓派IP>
setup-alpine
树莓派特定配置
# /boot/config.txt (树莓派固件配置)
cat > /boot/config.txt << 'EOF'
# 基本设置
gpu_mem=256
disable_overscan=1
dtparam=audio=on
# 性能优化
arm_freq=1800
over_voltage=4
gpu_freq=600
# 接口启用
dtparam=i2c_arm=on
dtparam=spi=on
# 显示设置
hdmi_force_hotplug=1
hdmi_group=2
hdmi_mode=82
EOF
# 启用硬件接口
# I2C
modprobe i2c-dev
echo "i2c-dev" >> /etc/modules
# SPI
modprobe spi-bcm2835
echo "spi-bcm2835" >> /etc/modules
# 1-Wire (DS18B20 温度传感器)
modprobe w1-gpio
modprobe w1-therm
echo "w1-gpio" >> /etc/modules
echo "w1-therm" >> /etc/modules
GPIO 控制
# 安装 GPIO 工具
apk add wiringpi wiringpi-dev
# Python GPIO
apk add python3 py3-pip
pip install RPi.GPIO
# 命令行控制 GPIO
# 读取 GPIO 状态
cat /sys/class/gpio/gpio17/value
# 导出 GPIO
echo 17 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio17/direction
echo 1 > /sys/class/gpio/gpio17/value
# Python 示例
cat > /home/pi/blink.py << 'EOF'
import RPi.GPIO as GPIO
import time
LED_PIN = 17
GPIO.setmode(GPIO.BCM)
GPIO.setup(LED_PIN, GPIO.OUT)
try:
while True:
GPIO.output(LED_PIN, GPIO.HIGH)
time.sleep(1)
GPIO.output(LED_PIN, GPIO.LOW)
time.sleep(1)
except KeyboardInterrupt:
GPIO.cleanup()
EOF
14.3 IoT 应用场景
传感器数据采集
# 安装传感器库
apk add python3 py3-pip py3-smbus i2c-tools
# 检测 I2C 设备
i2cdetect -y 1
# Python 读取 DHT22 温湿度传感器
cat > /home/pi/sensor.py << 'EOF'
import time
import json
import paho.mqtt.client as mqtt
# 传感器读取函数(需根据具体传感器实现)
def read_sensor():
return {
"temperature": 25.5,
"humidity": 60.2,
"timestamp": int(time.time())
}
# MQTT 上报
client = mqtt.Client()
client.connect("mqtt.example.com", 1883, 60)
client.loop_start()
while True:
data = read_sensor()
client.publish("sensors/room1", json.dumps(data))
print(f"Published: {data}")
time.sleep(30)
EOF
MQTT 消息代理
# 安装 Mosquitto
apk add mosquitto mosquitto-clients
# 配置
cat > /etc/mosquitto/mosquitto.conf << 'EOF'
listener 1883
allow_anonymous false
password_file /etc/mosquitto/passwd
persistence true
persistence_location /var/lib/mosquitto/
log_dest syslog
EOF
# 创建用户
mosquitto_passwd -c /etc/mosquitto/passwd iotuser
# 启动服务
rc-update add mosquitto
rc-service mosquitto start
# 测试
mosquitto_sub -h localhost -t "sensors/#" -u iotuser -P password
mosquitto_pub -h localhost -t "sensors/test" -m "hello" -u iotuser -P password
Home Assistant 集成
# docker-compose.yml
version: "3.8"
services:
homeassistant:
image: homeassistant/home-assistant:stable
container_name: homeassistant
restart: unless-stopped
privileged: true
network_mode: host
volumes:
- ./config:/config
- /etc/localtime:/etc/localtime:ro
environment:
- TZ=Asia/Shanghai
14.4 自定义 ISO 构建
使用 mkimage 构建
# 安装构建工具
apk add alpine-sdk apk-tools-cron busybox-initscripts
# 克隆 aports
git clone --depth 1 https://gitlab.alpinelinux.org/alpine/aports.git
# 创建自定义 profile
mkdir -p /tmp/myiso
# 构建脚本
cat > /tmp/myiso/build.sh << 'SCRIPT'
#!/bin/sh
set -e
OUTPUT="/tmp/myiso/output"
PROFILE="custom"
ARCH="x86_64"
mkdir -p "$OUTPUT"
# 使用 mkimage 构建
apk add alpine-conf
lbu package "$OUTPUT/$PROFILE.apkovl.tar.gz"
# 创建 ISO
mkisofs -o "$OUTPUT/$PROFILE.iso" \
-b boot/syslinux/isolinux.bin \
-c boot/syslinux/boot.cat \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
"$OUTPUT/iso"
SCRIPT
chmod +x /tmp/myiso/build.sh
自定义 rootfs
# 创建最小 rootfs
mkdir -p /tmp/rootfs
# 初始化
apk -X https://dl-cdn.alpinelinux.org/alpine/v3.20/main \
-U --allow-untrusted \
--root /tmp/rootfs \
--initdb add alpine-base
# 添加自定义软件
apk --root /tmp/rootfs add nginx python3 openssh
# 配置文件
cat > /tmp/rootfs/etc/hostname << 'EOF'
iot-gateway
EOF
# 打包
cd /tmp/rootfs
tar -czf /tmp/alpine-custom-rootfs.tar.gz .
无盘系统(PXE 引导)
# DHCP/TFTP 服务器配置
apk add dhcp tftp-hpa
# /etc/dhcp/dhcpd.conf
cat > /etc/dhcp/dhcpd.conf << 'EOF'
subnet 192.168.1.0 netmask 255.255.255.0 {
range 192.168.1.100 192.168.1.200;
option routers 192.168.1.1;
option broadcast-address 192.168.1.255;
filename "pxelinux.0";
next-server 192.168.1.10;
}
EOF
# TFTP 根目录
mkdir -p /var/tftpboot
# 复制 Alpine boot 文件到 TFTP 目录
14.5 工业应用
实时性配置
# PREEMPT_RT 内核补丁(需要自定义内核编译)
# Alpine 默认内核不适合硬实时需求
# 安装实时工具
apk add rt-tests
# 设置实时优先级
# /etc/security/limits.conf
@realtime - rtprio 99
@realtime - memlock unlimited
# 创建实时用户组
addgroup realtime
adduser myuser realtime
# 使用实时调度
chrt -f 99 ./my-rt-app
Modbus 通信
# 安装 Modbus 库
apk add libmodbus libmodbus-dev
# Python Modbus
pip install pymodbus
# 读取 Modbus 设备
cat > /home/pi/modbus_read.py << 'EOF'
from pymodbus.client import ModbusSerialClient
client = ModbusSerialClient(
method='rtu',
port='/dev/ttyUSB0',
baudrate=9600,
parity='N',
stopbits=1
)
client.connect()
result = client.read_holding_registers(0, 10, slave=1)
print(f"Registers: {result.registers}")
client.close()
EOF
14.6 边缘计算
容器化部署
# 边缘设备运行 Docker
apk add docker
rc-update add docker
# 边缘应用栈
cat > docker-compose.yml << 'EOF'
version: "3.8"
services:
# 数据采集
collector:
build: ./collector
restart: unless-stopped
privileged: true
volumes:
- /dev:/dev
# 本地处理
processor:
build: ./processor
restart: unless-stopped
depends_on:
- collector
# 数据上传
uploader:
build: ./uploader
restart: unless-stopped
environment:
- CLOUD_ENDPOINT=https://cloud.example.com
volumes:
- ./data:/data
EOF
14.7 系统定制
最小化裁剪
# 创建极小系统(<10MB)
# 仅包含 busybox + 自定义应用
# /etc/apk/world
busybox
alpine-baselayout
alpine-keys
apk-tools
musl
# 移除不需要的文件
rm -rf /var/cache/apk/*
rm -rf /usr/share/man
rm -rf /usr/share/doc
# 最终系统大小
du -sh /
只读系统
# 创建只读 rootfs
# /etc/fstab
/dev/mmcblk0p2 / ext4 ro,noatime 0 1
tmpfs /tmp tmpfs defaults 0 0
tmpfs /run tmpfs defaults 0 0
tmpfs /var/log tmpfs defaults 0 0
# overlayfs 可写层
mount -t overlay overlay \
-o lowerdir=/,upperdir=/tmp/overlay/upper,workdir=/tmp/overlay/work \
/mnt
14.8 OTA 更新
# 轻量 OTA 更新方案
cat > /usr/local/bin/ota-update << 'SCRIPT'
#!/bin/sh
OTA_URL="https://updates.example.com"
CURRENT_VERSION=$(cat /etc/version)
# 检查更新
NEW_VERSION=$(curl -s "$OTA_URL/latest")
if [ "$CURRENT_VERSION" = "$NEW_VERSION" ]; then
echo "Already up to date"
exit 0
fi
# 下载更新包
curl -o /tmp/update.tar.gz "$OTA_URL/$NEW_VERSION/update.tar.gz"
# 校验
EXPECTED_HASH=$(curl -s "$OTA_URL/$NEW_VERSION/hash")
ACTUAL_HASH=$(sha256sum /tmp/update.tar.gz | cut -d' ' -f1)
if [ "$EXPECTED_HASH" != "$ACTUAL_HASH" ]; then
echo "Hash mismatch!"
exit 1
fi
# 应用更新
tar -xzf /tmp/update.tar.gz -C /
echo "$NEW_VERSION" > /etc/version
echo "Updated to $NEW_VERSION"
reboot
SCRIPT
chmod +x /usr/local/bin/ota-update
14.9 注意事项
⚠️ 嵌入式开发注意
- SD 卡寿命有限,使用 tmpfs 减少写入
- 定期备份配置和数据
- 使用看门狗防止系统挂起
- 配置自动恢复机制
💡 性能优化
- 使用
noatime挂载选项- 减少日志写入频率
- 使用 tmpfs 存储临时文件
- 禁用不需要的服务和内核模块
扩展阅读
上一章:第 13 章:故障排查 下一章:第 15 章:生产最佳实践