分类
嵌入式开发 开发计划

利用Docker编译openwrt 19.07与latest,需要无损切换

创建 Docker,openwrt 19.07与latest需要同时存在,根据工作的需要在docker中来回切换

步骤1:安装 Docker(需要 root 权限)

# 切换到 root 用户
su - root

# 安装 Docker
apt update
apt install -y docker.io

# 或者使用官方 Docker 安装脚本
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

步骤2:启动 Docker 服务并设置权限

# 启动 Docker 服务
systemctl start docker
systemctl enable docker

# 创建 docker 组(如果不存在)
groupadd docker

# 将 openwrt 用户添加到 docker 组
usermod -aG docker openwrt

# 重启 Docker 服务
systemctl restart docker

步骤3:验证安装

# 切换回 openwrt 用户
su - openwrt

# 验证 Docker 安装
docker --version

# 验证权限(应该能正常执行)
docker ps
# 安装 Docker Compose(无需 sudo)
# 切换到项目目录
cd ~/openwrt-docker-build

# 下载 docker-compose 二进制文件
mkdir -p ~/.local/bin
curl -SL https://github.com/docker/compose/releases/download/v2.24.0/docker-compose-linux-x86_64 -o ~/.local/bin/docker-compose

# 赋予执行权限
chmod +x ~/.local/bin/docker-compose

# 添加到 PATH
echo 'export PATH="HOME/.local/bin:PATH"' >> ~/.bashrc
source ~/.bashrc

# 验证安装
docker-compose --version
# 切换到 openwrt 用户
sudo su - openwrt

# 创建项目根目录
mkdir -p ~/openwrt-docker-build
cd ~/openwrt-docker-build

# 创建独立的目录结构
mkdir -p openwrt-19.07/{src,bin,dl,build_dir,staging_dir}
mkdir -p openwrt-latest/{src,bin,dl,build_dir,staging_dir}
mkdir -p {ccache-19.07,ccache-latest}
mkdir -p scripts

# 设置目录权限
chmod -R 755 openwrt-19.07 openwrt-latest ccache-19.07 ccache-latest

# 查看目录结构
tree -L 2 ~/openwrt-docker-build/
#修正 docker-compose.yml 使用正确的 v2 语法
# 创建正确的 docker-compose.yml
cat > docker-compose.yml << 'EOF'
services:
  openwrt-19.07:
    build: 
      context: .
      dockerfile: Dockerfile.19.07
    container_name: openwrt-19.07-build
    volumes:
      - type: bind
        source: ./openwrt-19.07/src
        target: /home/openwrt/openwrt-19.07
      - type: bind
        source: ./ccache-19.07
        target: /home/openwrt/.ccache-19.07
    tty: true
    stdin_open: true
    working_dir: /home/openwrt/openwrt-19.07
    restart: unless-stopped
    user: "1000:1000"

  openwrt-latest:
    build:
      context: .
      dockerfile: Dockerfile.latest
    container_name: openwrt-latest-build
    volumes:
      - type: bind
        source: ./openwrt-latest/src
        target: /home/openwrt/openwrt-latest
      - type: bind
        source: ./ccache-latest
        target: /home/openwrt/.ccache-latest
    tty: true
    stdin_open: true
    working_dir: /home/openwrt/openwrt-latest
    restart: unless-stopped
    user: "1000:1000"
EOF



# Dockerfile.19.07 
cat > Dockerfile.19.07 << 'EOF'
FROM debian:10

# 使用 Debian 归档镜像
RUN sed -i 's/deb.debian.org/archive.debian.org/g' /etc/apt/sources.list && \
    sed -i 's|security.debian.org|archive.debian.org/debian-security|g' /etc/apt/sources.list && \
    sed -i 's|buster/updates|buster/updates|g' /etc/apt/sources.list && \
    echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf.d/10no--check-valid-until && \
    echo 'Acquire::Check-Date "false";' >> /etc/apt/apt.conf.d/10no-check-valid-until

RUN groupadd -g 1000 openwrt && \
    useradd -m -u 1000 -g 1000 -s /bin/bash openwrt

# 安装编译依赖
RUN apt-get update && apt-get install -y \
    build-essential ccache ecj fastjar file g++ gawk \
    gettext git java-propose-classpath libelf-dev libncurses5-dev \
    libncursesw5-dev libssl-dev python python2.7-dev python3 unzip wget \
    python3-distutils python3-setuptools rsync subversion swig time \
    xsltproc zlib1g-dev sudo ca-certificates && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

RUN echo 'openwrt ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

WORKDIR /home/openwrt/openwrt-19.07

ENV CCACHE_DIR=/home/openwrt/.ccache-19.07
ENV FORCE_UNSAFE_CONFIGURE=1

USER openwrt

RUN mkdir -p /home/openwrt/.ccache-19.07
EOF

# OpenWrt Latest 的 Dockerfile

cat > Dockerfile.latest << 'EOF'
FROM debian:12

RUN groupadd -g 1000 openwrt && \
    useradd -m -u 1000 -g 1000 -s /bin/bash openwrt

RUN apt-get update && apt-get install -y \
    build-essential ccache ecj fastjar file g++ gawk \
    gettext git java-propose-classpath libelf-dev libncurses5-dev \
    libncursesw5-dev libssl-dev python3 python3-dev python3-pip unzip wget \
    python3-distutils python3-setuptools rsync subversion swig time \
    xsltproc zlib1g-dev cmake pkg-config sudo && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

RUN echo 'openwrt ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

WORKDIR /home/openwrt/openwrt-latest

ENV CCACHE_DIR=/home/openwrt/.ccache-latest
ENV FORCE_UNSAFE_CONFIGURE=1

USER openwrt

RUN mkdir -p /home/openwrt/.ccache-latest
EOF

构建镜像

# 构建 Docker 镜像(这会需要一些时间)
docker-compose build

#查看镜像
docker images
#能看到如下信息
REPOSITORY                            TAG       IMAGE ID       CREATED          SIZE
openwrt-docker-build-openwrt-19.07    latest    c4175b5d175f   25 seconds ago   1.03GB
openwrt-docker-build-openwrt-latest   latest    6df4fd104875   51 seconds ago   1.17GB

# 启动服务
docker-compose up -d

# 查看状态
docker-compose ps

后面如何在工作中,快速、流畅、切换、无损的切换两个工作环境?

#启动两个环境(一次性设置)
### 启动 OpenWrt 19.07 环境
docker run -d \
  --name openwrt-19.07-build \
  -v (pwd)/openwrt-19.07/src:/home/openwrt/openwrt-19.07 \
  -v(pwd)/ccache-19.07:/home/openwrt/.ccache-19.07 \
  -w /home/openwrt/openwrt-19.07 \
  openwrt-docker-build-openwrt-19.07:latest \
  tail -f /dev/null

# 启动 OpenWrt Latest 环境  
docker run -d \
  --name openwrt-latest-build \
  -v (pwd)/openwrt-latest/src:/home/openwrt/openwrt-latest \
  -v(pwd)/ccache-latest:/home/openwrt/.ccache-latest \
  -w /home/openwrt/openwrt-latest \
  openwrt-docker-build-openwrt-latest:latest \
  tail -f /dev/null

### 日常快速切换命令
#切换到 OpenWrt 19.07 环境:
# 进入 19.07 环境
docker exec -it openwrt-19.07-build bash

# 在容器内自动进入工作目录,直接开始工作:
# cd /home/openwrt/openwrt-19.07  # 已经自动在这个目录
# make menuconfig
# make -j(nproc)

#切换到 OpenWrt Latest 环境:
# 进入 latest 环境
docker exec -it openwrt-latest-build bash

# 在容器内自动进入工作目录,直接开始工作:
# cd /home/openwrt/openwrt-latest  # 已经自动在这个目录
# make menuconfig
# make -j(nproc)

# 查看环境状态:
# 查看哪些环境在运行
docker ps -f name=openwrt-

# 查看所有环境(包括停止的)
docker ps -a -f name=openwrt-

# 停止环境(不需要时):
# 停止 19.07 环境
docker stop openwrt-19.07-build

# 停止 latest 环境
docker stop openwrt-latest-build

# 停止所有环境
docker stop openwrt-19.07-build openwrt-latest-build

# 重新启动环境:
# 启动 19.07 环境
docker start openwrt-19.07-build

# 启动 latest 环境
docker start openwrt-latest-build

# 启动所有环境
docker start openwrt-19.07-build openwrt-latest-build


# 工作流程示例
#1. 先退出当前容器
exit
#2. 检查当前是否有运行的容器
docker ps -a
#3. 如果容器已经存在,先停止并删除
# 停止容器
docker stop openwrt-19.07-build openwrt-latest-build
# 删除容器
docker rm openwrt-19.07-build openwrt-latest-build

# 停止容器(不删除)
docker stop openwrt-19.07-build openwrt-latest-build

# 启动已停止的容器
docker start openwrt-19.07-build openwrt-latest-build

# 重启容器
docker restart openwrt-19.07-build openwrt-latest-build

# 只有在需要完全重置时才删除容器
docker stop openwrt-19.07-build openwrt-latest-build
docker rm openwrt-19.07-build openwrt-latest-build


# 启动 OpenWrt 19.07 环境
docker run -d \
  --name openwrt-19.07-build \
  -v (pwd)/openwrt-19.07/src:/home/openwrt/openwrt-19.07 \
  -v(pwd)/ccache-19.07:/home/openwrt/.ccache-19.07 \
  -w /home/openwrt/openwrt-19.07 \
  openwrt-docker-build-openwrt-19.07:latest \
  tail -f /dev/null

# 启动 OpenWrt Latest 环境  
docker run -d \
  --name openwrt-latest-build \
  -v (pwd)/openwrt-latest/src:/home/openwrt/openwrt-latest \
  -v(pwd)/ccache-latest:/home/openwrt/.ccache-latest \
  -w /home/openwrt/openwrt-latest \
  openwrt-docker-build-openwrt-latest:latest \
  tail -f /dev/null

# 验证容器是否运行
docker ps

# 在终端1:进入 19.07 环境并开始编译
docker exec -it openwrt-19.07-build bash
make -j(nproc) V=s

# 在终端2:新开一个终端窗口,进入 latest 环境也开始编译
docker exec -it openwrt-latest-build bash  
make -j(nproc) V=s


# 串行工作
# 终端1:进入 19.07 编译
docker exec -it openwrt-19.07-build bash
make -j(nproc) &
# 让它在后台编译,然后退出容器
exit

# 同样的终端:进入 latest 编译
docker exec -it openwrt-latest-build bash
make -j(nproc)

# 查看系统资源
htop

# 查看容器资源使用
docker stats

# 如果资源紧张,可以限制 CPU 使用
# 启动时添加限制:
docker run -d --cpus=2 ...  # 限制使用 2 个 CPU 核心



# 场景1:在 19.07 上工作
# 切换到 19.07 环境
docker exec -it openwrt-19.07-build bash

# 在容器内:
make menuconfig    # 配置
make -j(nproc)    # 编译
exit               # 退出容器

# 场景2:切换到 latest 工作
# 切换到 latest 环境
docker exec -it openwrt-latest-build bash

# 在容器内:
make menuconfig    # 配置
make -j(nproc)    # 编译  
exit               # 退出容器

关键优势
无损切换:每个环境独立,ccache 缓存分开,互不影响

快速进入:docker exec -it 秒级切换

状态保持:容器在后台运行,编译状态完全保持

数据持久:所有源码和输出都在宿主机,安全可靠

# 进入 19.07: docker exec -it openwrt-19.07-build bash
# 进入 latest: docker exec -it openwrt-latest-build bash
# 查看状态: docker ps -f name=openwrt-
# 停止所有: docker stop openwrt-19.07-build openwrt-latest-build
# 启动所有: docker start openwrt-19.07-build openwrt-latest-build