Docker容器化ESP-IDF:CI/CD自动编译ESP32固件
一、先说结论Docker 容器化 ESP-IDF 后任何人提交代码 → CI 自动编译 → 输出固件文件。本地不装 ESP-IDF 也能开发用 VSCode Dev Container编译环境完全一致。ESP32 固件开发通常在本地装 ESP-IDF 环境、用 VSCode 编译。但团队协作时每个人的环境可能不同——版本不一致、依赖缺失、编译结果不可重现。Docker 容器化 ESP-IDF统一编译环境配合 CI/CD 自动出固件是团队开发的标配方案。二、Docker 镜像构建# Dockerfile FROM ubuntu:22.04 ENV DEBIAN_FRONTENDnoninteractive # 安装依赖 RUN apt-get update apt-get install -y \ git wget unzip \ python3 python3-pip python3-venv \ cmake ninja-build \ gcc g \ libffi-dev libssl-dev \ rm -rf /var/lib/apt/lists/* # 安装ESP-IDF ENV IDF_VERSIONv5.2.1 ENV IDF_PATH/opt/esp/idf ENV IDF_TOOLS_PATH/opt/esp/tools RUN mkdir -p /opt/esp cd /opt/esp \ git clone --depth 1 --branch $IDF_VERSION \ https://github.com/espressif/esp-idf.git $IDF_PATH \ cd $IDF_PATH \ git submodule update --init --depth 1 \ components/bt/host/nimble \ components/esp_wifi \ components/mbedtls \ \ $IDF_PATH/install.sh esp32 esp32s3 \ rm -rf /opt/esp/tools/dist # 设置环境 ENV PATH${IDF_PATH}/tools:${PATH} RUN echo source ${IDF_PATH}/export.sh /etc/bash.bashrc # 设置工作目录 WORKDIR /project # 入口脚本 COPY entrypoint.sh /entrypoint.sh RUN chmod x /entrypoint.sh ENTRYPOINT [/entrypoint.sh]#!/bin/bash# entrypoint.shsource/opt/esp/idf/export.sh/dev/null21exec$构建镜像dockerbuild-tesp-idf-builder:5.2.1.三、编译固件项目结构my-esp-project/ ├── CMakeLists.txt ├── sdkconfig.defaults ├── main/ │ ├── CMakeLists.txt │ └── main.c ├── components/ │ └── my_driver/ │ ├── CMakeLists.txt │ └── my_driver.c └── Dockerfile用容器编译# 编译dockerrun--rm\-v$(pwd):/project\-w/project\esp-idf-builder:5.2.1\idf.py build# 编译并输出固件dockerrun--rm\-v$(pwd):/project\-w/project\esp-idf-builder:5.2.1\bash-cidf.py build cp build/firmware.bin /project/output/四、多目标编译一个项目同时编译 ESP32 和 ESP32-S3# 编译ESP32dockerrun--rm-v$(pwd):/project-w/project\esp-idf-builder:5.2.1\idf.py-DIDF_TARGETesp32 build# 编译ESP32-S3dockerrun--rm-v$(pwd):/project-w/project\esp-idf-builder:5.2.1\idf.py-DIDF_TARGETesp32s3 build批量编译脚本#!/bin/bash# build_all.shTARGETS(esp32esp32s3esp32c3esp32s2)PROJECT_DIR$(pwd)IMAGEesp-idf-builder:5.2.1fortargetin${TARGETS[]};doecho Building for$targetBUILD_DIRbuild_$targetdockerrun--rm\-v$PROJECT_DIR:/project\-w/project\-eIDF_TARGET$target\$IMAGE\bash-c idf.py -B$BUILD_DIR-DIDF_TARGET$targetreconfigure idf.py -B$BUILD_DIRbuild # 复制固件mkdir-poutputcp$BUILD_DIR/*.bin output/$target/cp$BUILD_DIR/*.elf output/$target/echoDone:$target→ output/$target/done五、GitHub Actions CI/CD# .github/workflows/build-firmware.ymlname:Build ESP32 Firmwareon:push:branches:[main,develop]paths:-main/**-components/**-CMakeLists.txt-sdkconfig.defaultspull_request:branches:[main]env:IDF_VERSION:v5.2.1jobs:build:runs-on:ubuntu-lateststrategy:matrix:target:[esp32,esp32s3,esp32c3]steps:-uses:actions/checkoutv4-name:Build Docker imagerun:|docker build -t esp-idf:${IDF_VERSION} .-name:Build firmwarerun:|docker run --rm \ -v ${{ github.workspace }}:/project \ -w /project \ -e IDF_TARGET${{ matrix.target }} \ esp-idf:${IDF_VERSION} \ bash -c idf.py set-target ${{ matrix.target }} idf.py build -name:Generate version inforun:|echo ${{ github.sha }} build/version.txt echo Build date: $(date) build/version.txt echo Branch: ${{ github.ref_name }} build/version.txt-name:Upload firmwareuses:actions/upload-artifactv4with:name:firmware-${{matrix.target}}-${{github.sha}}path:|build/*.bin build/*.elf build/version.txtretention-days:90-name:Release on tagif:startsWith(github.ref,refs/tags/v)uses:softprops/action-gh-releasev2with:files:|build/*.bin build/*.elf build/version.txt六、VSCode Dev Container在 VSCode 中直接用 Docker 容器做开发环境// .devcontainer/devcontainer.json{name:ESP-IDF Development,build:{dockerfile:../Dockerfile,context:..},customizations:{vscode:{extensions:[espressif.esp-idf-extension,ms-vscode.cpptools,ms-vscode.cmake-tools],settings:{idf.espIdfPath:/opt/esp/idf,idf.toolsPath:/opt/esp/tools,idf.pythonInstallPath:/usr/bin/python3}}},workspaceMount:source${localWorkspaceFolder},target/project,typebind,workspaceFolder:/project,remoteUser:root,postCreateCommand:source /opt/esp/idf/export.sh}七、编译优化加速# Dockerfile.build-fast FROM esp-idf-builder:5.2.1 AS builder # ccache加速重复编译 RUN apt-get update apt-get install -y ccache \ rm -rf /var/lib/apt/lists/* ENV CCACHE_DIR/ccache ENV CCACHE_MAXSIZE5G ENV IDF_CCACHE_ENABLE1 # 预编译常见组件 RUN mkdir -p /tmp/prebuild cd /tmp/prebuild \ source /opt/esp/idf/export.sh \ idf.py create-project prebuild \ cd prebuild \ idf.py set-target esp32 \ idf.py build \ cd .. rm -rf /tmp/prebuild# docker-compose.ymlversion:3.8services:esp-build:build:context:.dockerfile:Dockerfile.build-fastvolumes:-./:/project-ccache:/ccacheworking_dir:/projectcommand:bash-c source /opt/esp/idf/export.shidf.py buildvolumes:ccache:八、实测数据ESP32 项目~500KB 固件环境首次编译增量编译本地ESP-IDFM1 MacBook3分钟15秒Docker同机器3分30秒18秒GitHub Actions4核5分钟30秒Dockerccache3分30秒5秒九、踩坑清单镜像大小ESP-IDF 完整镜像约 3-5GB。用--depth 1和rm -rf清理不必要文件能减到 2GB权限问题Docker 默认 root 用户编译产出的文件 root 所有。用--user $(id -u):$(id -g)指定用户路径长度Windows 挂载路径不能太长。把项目放在浅层目录文件监听Docker 容器内文件改动不被 Windows 识别。用idf.py build而不是 monitor 模式sdkconfig不同目标esp32/esp32s3可能需要不同 sdkconfig。用sdkconfig.defaults.esp32和sdkconfig.defaults.esp32s3分文件Python 虚拟环境ESP-IDF 自带 Python venv。容器重建后 venv 丢失首次编译要重建 venv网络代理CI 环境可能需要代理。ESP-IDF 安装时下载工具链设HTTP_PROXY环境变量Git 子模块ESP-IDF 有很多子模块。git submodule update --init --depth 1减少下载量缓存策略GitHub Actions 缓存 Docker layer 和 ccache。用actions/cachev4缓存/ccache目录固件命名编译产物默认firmware.bin。在 CMakeLists.txt 中改project(firmware-name)产物就是firmware-name.bin

相关新闻

最新新闻

日新闻

周新闻

月新闻