强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Alpine Linux 完全指南 / 第 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 章:生产最佳实践