簡體   English   中英

在 Jenkins 如何在交叉編譯環境中使用 Docker 鏡像

[英]In Jenkins how to use Docker image with cross compilation environment

我目前正在嘗試設置 Jenkins 構建管道,我正在努力包括 docker 容器。 我的主要問題是 Jenkins 將構建步驟發送到正在運行的容器的方式。

背景

我正在構建一個交叉編譯項目。 這發生在為交叉編譯設置的 linux 中。 所有必要的東西都由 SDK 提供,包括適當的編譯器、頭文件、庫等。

要設置所有內容,它還包括一個環境文件,該文件需要由當前的 shell 提供。 該腳本添加了必要的信息,例如添加環境變量(例如調整 $PATH)或別名。

對於 Jenkins 構建,我正在創建一個包含 SDK 的 docker 映像。 圖像工作正常,我可以在運行容器時構建項目。 但它不適用於 Jenkins。 經過一番評估,我發現問題出在 Jenkins 使用容器的方式上。

問題

似乎 Jenkins 通過docker run -t -d imagename cat在后台啟動 docker 圖像的容器。 然后使用docker exec發送所有后續構建步驟。 這通常很好。 就我而言,我收到錯誤,因為找不到所有可執行文件(例如 cmake)。 可執行文件未安裝在常規系統根目錄中,而是安裝在 SDK 文件夾中。
我在 docker 圖像的入口點腳本中添加了一個source命令。 source命令獲取 SDK 環境。 由於入口點僅在運行期間run而不是使用exec ,因此所有構建步驟都會產生錯誤,因為$PATH變量設置不正確。

這是一個精簡的 Jenkinsfile:

pipeline {
    agent {
        docker {
            label 'docker'
            image 'test:01'
        }
    }
    stages {
        stage('build') {
            steps {
                cmakeBuild  installation: "InSearchPath",
                            generator: "Unix Makefile",
                            buildDir: 'build',
                            sourceDir: 'source',
                            steps: [
                                [args: 'all install']
                            ]
            }
         }
    }
}

產生以下日志 output:

...
[Pipeline] withDockerContainer
$ docker run -t -d -u 1078:1001 -w /jenkins/workspace/project -v /jenkins/workspace/project:/jenkins/workspace/project:rw,z -v /jenkins/workspace/project@tmp:/jenkins/workspace/project@tmp:rw,z  test:01 cat
$ docker top ff1b4ee4e929b83e5741ef7db1e57688f7f996ca3a10a00ae4c5426cf108cb2a -eo pid,comm
...
...
...
[Pipeline] cmakeBuild
[build] $ docker exec --workdir /jenkins/workspace/project/build ff1b4ee4e929b83e5741ef7db1e57688f7f996ca3a10a00ae4c5426cf108cb2a cmake -G "Unix Makefile" /jenkins/workspace/project/source
OCI runtime exec failed: exec failed: container_linux.go:345: starting container process caused "exec: \"cmake\": executable file not found in $PATH": unknown
...

再現圖像

為了了解有關行為的更多信息,我創建了一個小的 docker 圖像來說明問題。

Dockerfile:

FROM debian:jessie

# Add entrypoint script which sources envvars file
RUN echo "#!/bin/bash\n\n\
          . /envvars \n\n\
          exec \"\$@\"\
          " >/entrypoint.sh \
    && chmod ugo+rx /entrypoint.sh

# Add a script foo.sh which returns the content of $PATH
RUN mkdir -p /home/test/script \
    && echo "#!/bin/bash\n\
            echo \$PATH \n\
            " > /home/test/script/foo.sh \
    && chmod ugo+rx /home/test/script/foo.sh

# Add the directory containing the foo.sh script to $PATH
RUN echo "export PATH=/home/test/script:$PATH \n" > /envvars

ENTRYPOINT ["/entrypoint.sh"]
CMD ["/bin/bash"]

您可以構建此映像:

$> docker build -t "test" .
Sending build context to Docker daemon   55.3kB
Step 1/6 : FROM debian:jessie
 ---> c9d6adb06e4d
Step 2/6 : RUN echo "#!/bin/bash\n\n          . /envvars \n\n          exec \"\$@\"          " >/entrypoint.sh     && chmod ugo+rx /entrypoint.sh
 ---> Using cache
 ---> 648affce60a6
Step 3/6 : RUN mkdir -p /home/test/script     && echo "#!/bin/bash\n            echo \$PATH \n            " > /home/test/script/foo.sh     && chmod ugo+rx /home/test/script/foo.sh
 ---> Running in d13391c77668
Removing intermediate container d13391c77668
 ---> 7d88c20f8673
Step 4/6 : RUN echo "export PATH=/home/test/script:$PATH \n" > /envvars
 ---> Running in 55ac66323579
Removing intermediate container 55ac66323579
 ---> 35e081186bfa
Step 5/6 : ENTRYPOINT ["/entrypoint.sh"]
 ---> Running in 53154fed036f
Removing intermediate container 53154fed036f
 ---> 4ca347cbe757
Step 6/6 : CMD ["/bin/bash"]
 ---> Running in a598aefa837b
Removing intermediate container a598aefa837b
 ---> 78fc760bb9db
Successfully built 78fc760bb9db
Successfully tagged test:latest

構建映像后,您可以交互地運行它。 所以你在容器內,在 bash shell 中,並且可以直接調用foo.sh ,因為/home/test/script$PATH的一部分:

$> docker run --rm -ti test
root@42529686fe22:/# foo.sh
/home/test/script:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
root@42529686fe22:/# exit

您甚至可以從 Dockerfile 覆蓋CMD設置,並使用 docker 從容器外部調用docker run

$> docker run --rm -t test foo.sh
/home/test/script:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

但是當你在后台啟動容器時(就像在 Jenkins 中所做的那樣),你不能再調用foo.sh了:

$> docker run --rm --name test -td test cat
0ecf3efecc54d33b73aaab6b4a1e191056c55597b3fe558ff7a7a6f93db2b695

$> docker exec test foo.sh
OCI runtime exec failed: exec failed: container_linux.go:345: starting container process caused "exec: \"foo.sh\": executable file not found in $PATH": unknown

盡管使用絕對路徑調用foo.sh是可行的。 結果顯示$PATH不包含腳本目錄/home/test/script

$> docker exec test /home/test/script/foo.sh
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

問題

您是否知道我可以配置 docker 映像或 Jenkins 管道以使我的場景正常工作?

我能想到的一種可能的解決方案是將所有構建步驟包裝在 shell 腳本中,該腳本本身就是環境文件的來源。 但我更喜歡使用 Jenkins 提供的插件並編寫一個干凈的 Jenkinsfile(即並非所有內容都隱藏在 shell 腳本中)

另一種解決方案是直接在系統根目錄中安裝 SDK。 但我不確定副作用。 此外,我仍然需要為構建步驟設置特定的環境變量。

使用 Dockerfile 中的 ENV 設置路徑:

ENV PATH="/home/test/script:${PATH}"

然后它應該與docker rundocker exec一起使用

$> docker exec test foo.sh
/home/test/script:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

暫無
暫無

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

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