簡體   English   中英

dockerfile中的RUN命令產生的結果與在容器內手動運行相同命令的結果不同

[英]RUN command in dockerfile produces different result than manually running same commands inside container

我正在創建一個具有gcc 4.8.5的Ubuntu 12.04 docker鏡像。 我正在獲取gcc 4.8.5源代碼並自己構建它。 該容器將在Ubuntu 18.04主機上運行。

引用底部的代碼,如果我沒有把它放在dockerfile中並在啟動容器后運行相同的命令,那么構建工作正常,但是如果我在dockerfile中使用RUN,我會得到以下構建錯誤

In file included from /usr/include/stdio.h:28:0,
             from ../../../gcc-4.8.5/libgcc/../gcc/tsystem.h:87,
             from ../../../gcc-4.8.5/libgcc/libgcc2.c:27:
/usr/include/features.h:324:26: fatal error: bits/predefs.h: No such 
file or directory
#include <bits/predefs.h>
                      ^

問題似乎源於./gcc-4.8.5/configure調用。 當在容器內運行時,我得到:

checking build system type... i686-pc-linux-gnu

當放入dockerfile我得到:

checking build system type... x86_64-unknown-linux-gnu

有人可以在dockerfiles中填寫我對RUN的理解,因為我覺得我錯過了它的工作方式。 我的印象是這些命令會在前一層運行嗎? 但似乎他們正在我的主機上運行。

## Get gcc 4.8.5 and build it
RUN wget ftp://gcc.gnu.org/pub/gcc/releases/gcc-4.8.5/gcc-4.8.5.tar.gz \
&& tar xzf gcc-4.8.5.tar.gz && \
cd gcc-4.8.5 && \
./contrib/download_prerequisites && \
cd .. && mkdir gccbuild && cd gccbuild && \
../gcc-4.8.5/configure \
--prefix="/opt/gcc" \
--enable-shared --with-system-zlib --enable-threads=posix \
--enable-__cxa_atexit --enable-checking --enable-gnu-indirect-function \
--enable-languages="c,c++" --disable-bootstrap \
&& make all && make install 

編輯:

docker build -t 12.04_builder - < dockerfile
docker run -i -t 12.04_builder

完整的dockerfile:

FROM jnickborys/i386-ubuntu:12.04

RUN apt-get update && \ 
    apt-get install -y \ 
      wget \
      build-essential \
      libssl-dev \
      git \
      asciidoc \
      libpulse-dev \
      libasound2-dev \
      libpcsclite-dev 

## Get latest cmake that has a 32-bit version
RUN wget https://github.com/Kitware/CMake/releases/download/v3.6.3/cmake-3.6.3-Linux-i386.sh && \ 
    chmod +x cmake-3.6.3-Linux-i386.sh && \ 
    ./cmake-3.6.3-Linux-i386.sh --skip-license --prefix=/usr

## Get gcc 4.8.5 and build it
RUN wget ftp://gcc.gnu.org/pub/gcc/releases/gcc-4.8.5/gcc-4.8.5.tar.gz \
    && tar xzf gcc-4.8.5.tar.gz && \
    cd gcc-4.8.5 && \
    ./contrib/download_prerequisites && \
    cd .. && mkdir gccbuild && cd gccbuild && \
    ../gcc-4.8.5/configure \
    --prefix="/opt/gcc" \
    --enable-shared --with-system-zlib --enable-threads=posix \
    --enable-__cxa_atexit --enable-checking --enable-gnu-indirect-function \
    --enable-languages="c,c++" --disable-bootstrap 
    && make all && make install

首先,一點背景:在構建期間運行的平台檢測腳本使用uname(1)實用程序(因此uname(2)系統調用)來識別它運行的硬件:

root@6e4b69adfd4c:/gcc-4.8.5# grep 'uname -m' config.guess 
UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown

在64位計算機上, uname -m返回x86_64 但是,有一個系統調用允許覆蓋此結果: personality(2) 當進程調用personality(2) ,它及其后續的forks(children)在調用uname(2)時開始看到假結果。 因此,有可能要求內核在uname(2)提供虛假的硬件信息。

您使用的基本映像( jnickborys/i386-ubuntu:12.04 )包含32位二進制文​​件並定義入口點/usr/bin/linux32 ,它調用personality(PER_LINUX32)以要求內核假裝它在32位上運行硬件並以uname(2)返回i686 (這可以分別使用docker inspectstrace進行檢查)。 這使得可以假裝容器化過程在32位環境中運行。

RUN指令中執行構建和在容器中手動執行構建有什么區別?

RUN執行構建時,Docker不使用入口點來運行命令。 它使用SHELL指令中指定的內容(默認為/bin/sh -c )。 這意味着運行構建的shell的個性不會改變,它(和子進程)會看到真正的硬件信息 - x86_64 ,因此,您可以在32位環境中獲得x86_64-unknown-linux-gnu構建系統類型並且構建失敗。

當您在容器中手動運行構建時(例如,在使用docker run -it jnickborys/i386-ubuntu:12.04啟動它然后執行與Dockerfile中相同的步驟之后),將調用入口點,從而改變個性,並且內核開始報告它在32位硬件( i686 )上運行,因此您獲得了i686-pc-linux-gnu構建系統類型,並且構建正確運行。

如何解決這個問題? 取決於你想要什么。 如果您的目標是為64位環境構建gcc,則只需使用64位基本映像。 如果要構建32位環境,可以選擇在這些RUN之前更改用於RUNSHELL

SHELL ["/usr/bin/linux32", "/bin/sh", "-c"]

這將使Docker執行具有改變個性的RUN ,因此,將正確檢測構建系統類型( i686-pc-linux-gnu )並且構建將成功。 如果需要,您可以在構建后將SHELL更改回/bin/sh -c

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM