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

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 章:生产最佳实践