[英]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 run
或docker 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.