构建docker镜像来编译

Dockerfile

采用ubuntu 20构建,除了安装依赖环境,重点是宿主的UID/GID会同步到镜像里面,这样在使用镜像编译的过程中,产生的新文件的权限和用户就会和主机一样。一下是文件内容

FROM ubuntu:20.04

# 使用阿里云apt源
RUN sed -i 's|http://.*.ubuntu.com|http://mirrors.aliyun.com|g' /etc/apt/sources.list

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && \
    apt-get upgrade -y && \
    apt-get install -y \
      busybox rsync wget build-essential subversion git-core libncurses5-dev zlib1g-dev gawk \
      flex quilt libssl-dev xsltproc libxml-parser-perl mercurial bzr \
      ecj cvs unzip lib32z1 lib32z1-dev \
      lib32stdc++6 libstdc++6 libmpc-dev libgmp-dev texinfo \
      autogen automake autoconf libsocketcan-dev \
      sudo locales && \
    locale-gen zh_CN.UTF-8 && \
    rm -rf /var/lib/apt/lists/*

ENV LANG=zh_CN.UTF-8
ENV TZ=Asia/Shanghai

ARG USERNAME=builder
ARG UID=1000
ARG GID=1000

# 兼容 UID/GID 已存在的情况
RUN set -ex; \
    if ! getent group "$GID" >/dev/null; then \
      groupadd -g $GID $USERNAME; \
    fi; \
    if ! id -u "$UID" >/dev/null 2>&1; then \
      useradd -m -u $UID -g $GID -s /bin/bash $USERNAME; \
    else \
      usermod -d /home/$USERNAME -l $USERNAME $(getent passwd $UID | cut -d: -f1) || true; \
      mkdir -p /home/$USERNAME; \
      chown $UID:$GID /home/$USERNAME; \
    fi; \
    echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

WORKDIR /work

RUN echo 'if [ -f build/envsetup.sh ]; then source build/envsetup.sh; fi' >> /etc/skel/.bashrc

USER $USERNAME

说明: - 构建时通过 --build-arg UID=$(id -u) --build-arg GID=$(id -g) 指定宿主的UID/GID。 - 用户家目录会自动带上 source,挂载源码时即可自动生效。 - 默认工作目录 /work,你可以挂载源码到此目录。 - 换成了国内源

构建镜像

docker build -t tina_builder \
  --build-arg UID=$(id -u) \
  --build-arg GID=$(id -g) .

启动并挂载源码目录

假设源码目录在 ~/Tina_linux(注意docker路径与容器内路径一致有利于刚才的 bashrc 自动source):

docker run -it --rm \
    -v ~/Tina_linux:/work \
    -w /work \
    -u $(id -u):$(id -g) \
    tina_builder \
    bash

注意事项: - 挂载到容器内 /work,可在/work下操作源码。 - -u $(id -u):$(id -g) 能保证UID一致,编译后文件归属正确不成 root。

自动source和运行指定命令

你可以通过 docker 的 bash -c 自动source并带参数,示例:

docker run -it --rm \
    -v ~/Tina_linux:/work \
    -w /work \
    -u $(id -u):$(id -g) \
    tina_builder \
    bash -c "source build/envsetup.sh && lunch 8 && make"

或指定你实际想运行的命令。

容器里的常用交互体验

进入容器会直接 source,如果你没跑命令,就是 shell:

docker run -it --rm \
    -v ~/Tina_linux:/work \
    -w /work \
    -u $(id -u):$(id -g) \
    tina_builder

进去后,手动source一下需要

docker run -it --rm -v ../Tina-Linux:/work -w /work -u $(id -u):$(id -g) tina_builder
source build/envsetup.sh

注意事项

docker desktop版本问题

sed -i xxxx这个命令在docker desktop版本下会有问题。 需要安装docker ce版本。

网上说是由于desktop版本的Volume的挂载方式问题,导致的。解决方案是更新sed到4.8及以上版本,这个还没有测试。 切换desktop和ce版本的方法为

# 切换到ce版本
docker context use default

# 切换到desktop版本
docker context use desktop-linux

下面是一个sed 4.8版本的 dockerfile

FROM ubuntu:20.04

# 使用阿里云apt源
RUN sed -i 's|http://.*.ubuntu.com|http://mirrors.aliyun.com|g' /etc/apt/sources.list

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && \
    apt-get upgrade -y && \
    apt-get install -y \
      busybox rsync wget build-essential subversion git-core libncurses5-dev zlib1g-dev gawk \
      flex quilt libssl-dev xsltproc libxml-parser-perl mercurial bzr \
      ecj cvs unzip lib32z1 lib32z1-dev \
      lib32stdc++6 libstdc++6 libmpc-dev libgmp-dev texinfo \
      autogen automake autoconf libsocketcan-dev \
      sudo locales wget xz-utils && \
    locale-gen zh_CN.UTF-8 && \
    rm -rf /var/lib/apt/lists/*

ENV LANG=zh_CN.UTF-8
ENV TZ=Asia/Shanghai

ARG USERNAME=cy
ARG UID=1000
ARG GID=1000

# 兼容 UID/GID 已存在的情况
RUN set -ex; \
    if ! getent group "$GID" >/dev/null; then \
      groupadd -g $GID $USERNAME; \
    fi; \
    if ! id -u "$UID" >/dev/null 2>&1; then \
      useradd -m -u $UID -g $GID -s /bin/bash $USERNAME; \
    else \
      usermod -d /home/$USERNAME -l $USERNAME $(getent passwd $UID | cut -d: -f1) || true; \
      mkdir -p /home/$USERNAME; \
      chown $UID:$GID /home/$USERNAME; \
    fi; \
    echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

WORKDIR /work

RUN echo 'if [ -f build/envsetup.sh ]; then source build/envsetup.sh; fi' >> /etc/skel/.bashrc

### >>> 添加sed 4.8编译安装步骤
RUN cd /tmp && \
    wget https://mirror.team-cymru.com/gnu/sed/sed-4.8.tar.xz && \
    tar -xf sed-4.8.tar.xz && \
    cd sed-4.8 && \
    ./configure && \
    make -j$(nproc) && \
    sudo make install && \
    hash -r && \
    # 确保/usr/local/bin优先于/usr/bin
    if ! grep -q 'export PATH=/usr/local/bin:$PATH' /etc/profile; then \
      echo 'export PATH=/usr/local/bin:$PATH' >> /etc/profile; \
    fi && \
    cd / && rm -rf /tmp/sed-4.8* && \
    sed --version

USER $USERNAME

# bashrc放到用户家目录
RUN cp /etc/skel/.bashrc /home/$USERNAME/.bashrc && \
    chown $USERNAME:$GID /home/$USERNAME/.bashrc