spawn ./petalinux-v2014.4-final-installer.run $install_dir
expect "Press Enter to display the license agreements"
send "\r"
expect "*>*"
send "y\r"
expect "*>*"
send "y\r"
expect eof
第一行聲明使用 expect 這個(gè)工具來(lái)解釋此腳本,/usr/bin/env 會(huì)遍歷 PATH 變量來(lái)尋找后面的可執(zhí)行文件,這樣避免了依賴于 expect 的安裝路徑。
第二行設(shè)置等待超時(shí),因?yàn)?PetaLinux 的安裝過(guò)程比較慢,這里將其設(shè)為 -1,即一直等待。
第三行設(shè)置一個(gè)變量來(lái)接收此腳本的參數(shù),我們借此來(lái)指定希望將 PetaLinux 安裝到哪個(gè)目錄下。注意 expect 腳本設(shè)置參數(shù)的方式和 bash 腳本不同,參數(shù) 0 代表我們調(diào)用腳本時(shí)給出的第一個(gè)參數(shù),而在 bash 腳本中,參數(shù) 0 代表腳本本身的名字。
第五行用 spawn 命令去執(zhí)行安裝程序。PetaLinux 的安裝程序的第一個(gè)參數(shù)也是安裝路徑。
接下來(lái)我們用 expext 命令來(lái)捕獲程序的輸出,用 send 命令發(fā)送預(yù)設(shè)的輸入。安裝程序提示你確認(rèn)協(xié)議的語(yǔ)句是這樣的:Do you accept this license? [y/N] >,直接用 expext 匹配這一句會(huì)有問(wèn)題,因?yàn)橹辽?[] 在 expect 的語(yǔ)法中是有特定含義的,需要轉(zhuǎn)義。已無(wú)心情研究 expect 那奇怪的語(yǔ)法,所幸它有很棒的模糊匹配功能,我們只需要匹配最后一個(gè) > 字符就可以了。
1.5 減小鏡像體積
PetaLinux 的安裝包在 Xilinx 官方網(wǎng)站上可以下載,但需要先注冊(cè),沒(méi)有固定的下載鏈接。所以要么需要在構(gòu)建前把它下載到本地,要么在互聯(lián)網(wǎng)上尋找一個(gè)合適的托管地點(diǎn),可以提供穩(wěn)定的下載鏈接。
PetaLinux 的安裝包比較大(2014.4 版有 1.2GB,而 2016.4 已經(jīng)到了喪心病狂的 8.3 GB),在安裝完成后,安裝包再留在鏡像中已經(jīng)沒(méi)有什么意義了,還會(huì)顯著的增加鏡像的體積。這里要理解 Docker 的鏡像是由一個(gè)個(gè)的層(layer)組成的,Dockerfile 中的每一條指令都對(duì)應(yīng)于一層,每一層都是在前一層的基礎(chǔ)上進(jìn)行的增量的改變。這意味著,一旦我們?cè)谀骋粚又幸肓艘粋€(gè)文件,即使在下一層中將其刪除,對(duì)體積的減小也無(wú)濟(jì)于事,我們只是無(wú)法在最終的容器中“看見(jiàn)”它們而已。如果我們使用 COPY 指令將 PetaLinux 的安裝包添加進(jìn)去,則 COPY 指令會(huì)生成一個(gè)層,我們無(wú)法再把它產(chǎn)生的體積抹除掉。Stack Overflow 上有一個(gè)關(guān)于這個(gè)問(wèn)題的討論6,主要提到了三種方式:一是在本地構(gòu)建一個(gè)網(wǎng)絡(luò)服務(wù)器,通過(guò)網(wǎng)絡(luò)的方式傳到 Docker 容器的內(nèi)部,我采用了這種方式,后面詳述;二是不能使用 Dockerfile 的方式構(gòu)建容器,而是在容器中完成安裝和清理工作后手動(dòng)提交更改到鏡像;三是使用第三方工具對(duì)生成的鏡像進(jìn)行再壓縮。
這里使用網(wǎng)絡(luò)是更好的方式,一方面如果我們?cè)诨ヂ?lián)網(wǎng)或者私有服務(wù)器上存放了安裝包,通過(guò)更改 installer_url 變量就可以使用新的地址獲取文件;另一方面,在本地可以使用 Python 輕松的創(chuàng)建一個(gè) HTTP 服務(wù)器。在 Dockerfile 中,我們使用 wget 下載安裝包、配置其權(quán)限、運(yùn)行自動(dòng)安裝腳本,最后刪除安裝包。這些步驟必須在一個(gè) RUN 指令下完成,這樣安裝包才不會(huì)留在最終的鏡像里。
WORKDIR $install_dir
COPY ./auto-install.sh .
RUN wget -q $installer_url/petalinux-v2014.4-final-installer.run && \
chmod a+x petalinux-v2014.4-final-installer.run && \
./auto-install.sh $install_dir && \
rm -rf petalinux-v2014.4-final-installer.run
在外部,我使用了一個(gè)腳本來(lái)封裝啟動(dòng) HTTP 服務(wù)器、構(gòu)建 Docker 鏡像、停止服務(wù)器的步驟:
#!/usr/bin/env bash
installer_dir=$1
docker_context=`pwd`
echo "Start to build petalinux tools docker image ..."
echo "-----------------------------------------------"
cd $installer_dir
python3 -m http.server &
server_pid=$!
cd $docker_context
installer_ip=`ifconfig docker0 | grep 'inet\s' | awk '{print $2}'`
docker build -t petalinux-docker:2014.4 \
--build-arg installer_url=${installer_ip}:8000 \
.
kill $server_pid
echo "---------------"
echo " Finish. ^_^ "
echo "---------------"
這個(gè)腳本的第一個(gè)參數(shù)是安裝包在本地的路徑。首先讓服務(wù)器在后臺(tái)建立,并記錄下其對(duì)應(yīng)的 pid,在完成鏡像的構(gòu)建后再將其殺死。Python 創(chuàng)建的服務(wù)器會(huì)默認(rèn)監(jiān)聽(tīng) 8000 端口。在容器內(nèi)部(Docker 構(gòu)建的過(guò)程即相當(dāng)于在臨時(shí)的容器中執(zhí)行 Dockerfile 的過(guò)程)可以通過(guò) Docker 的默認(rèn)網(wǎng)橋(docker0)的 IP 地址來(lái)訪問(wèn)本地主機(jī)。網(wǎng)橋?qū)?yīng)的 IP 地址并不是唯一的,Docker 是根據(jù)主機(jī)中網(wǎng)卡的配置不同,選擇一個(gè)沒(méi)有被占用的私有網(wǎng)段(如果 3 類私有 IP 網(wǎng)段都被占用了,Docker 啟動(dòng)時(shí)會(huì)報(bào)錯(cuò)),也可以自行更改,所以這里我們從 ifconfig 的輸出中提取 docker0 對(duì)應(yīng)得 IP 地址。docker build 命令中 -t 參數(shù)為鏡像指定標(biāo)簽,--build-arg 參數(shù)用來(lái)覆蓋我們?cè)?Dockerfile 內(nèi)部設(shè)置的參數(shù),最后一個(gè)參數(shù) . 指的是構(gòu)建環(huán)境(build context)為當(dāng)前路徑。注意,如果你將安裝包放在了這個(gè)構(gòu)建環(huán)境的同一個(gè)目錄下,一定要通過(guò) .dockerignore 文件來(lái)忽略這個(gè)安裝包文件,因?yàn)榉駝t它會(huì)被發(fā)送到 Docker daemon 上,增加構(gòu)建時(shí)間且毫無(wú)用處,除非你要使用 COPY 指令的方式導(dǎo)入安裝包。
1.6 其他
PetaLinux 會(huì)檢查 shell 環(huán)境,并推薦使用 Bash。在 Ubuntu:16.04 的鏡像中 /bin/sh 這個(gè)軟連接指向的是 /bin/dash,這里我們將其更改為 /bin/bash。
RUN ln -fs /bin/bash /bin/sh # bash is PetaLinux recommended shell
使用 WORKDIR 指令新建了一個(gè) /workspace 的路徑用于連接數(shù)據(jù)卷。最后一個(gè) WORKDIR 指定的路徑就會(huì)是進(jìn)入容器后的所在路徑,這一點(diǎn)似乎官方文檔沒(méi)有明說(shuō)。
WORKDIR /workspac
1.7 鏡像的構(gòu)建
如果安裝包放在本地,則如 1.5 節(jié)所述,使用 build-image.sh 腳本構(gòu)建鏡像。如果安裝包在互聯(lián)網(wǎng)或本地服務(wù)器上,則直接使用 docker build 命令,并使用 installer_url 參數(shù)指定訪問(wèn)地址。
2. 測(cè)試
你可以自行按照上面的方法自行構(gòu)建鏡像,也可以從 Docker Hub 上下載我上傳好的鏡像:
docker pull xaljer/petalinux:2014.4
運(yùn)行容器:
docker run -ti -v /path/to/projects:/workspace xaljer/petalinux:2014.4
在容器中創(chuàng)建工程并編譯:
petalinux-create -t project -s
-n
cd
petalinux-build # 構(gòu)建整個(gè)工程,會(huì)比較慢
3. 現(xiàn)有問(wèn)題和下一步工作
3.1 現(xiàn)有問(wèn)題
PetaLinux 2014.4 支持的原本是 Ubuntu 14.04,但使用此版本的鏡像時(shí)發(fā)現(xiàn),其軟件源似乎有些問(wèn)題,經(jīng)常安裝失敗,故沒(méi)有使用。
PetaLinux 會(huì)提示找不到 tftp,這是因?yàn)闆](méi)有對(duì)其進(jìn)行進(jìn)一步的配置。如果不使用 tftp 可以忽略這個(gè)問(wèn)題。
在 Docker for Windows 下構(gòu)建時(shí),可能會(huì)出現(xiàn)錯(cuò)誤7,將存儲(chǔ)驅(qū)動(dòng)更改為 aufs 后可修復(fù)。然而 Windows 下構(gòu)建的鏡像仍有其他問(wèn)題,無(wú)法使用,作者尚未對(duì)其作更多的測(cè)試和探究。
3.2 下一步工作
添加 Vivado SDK 的一些工具。
PetaLinux 工具的名字都有點(diǎn)長(zhǎng),可以考慮在鏡像里對(duì)常用的操作添加別名。但在容器外部作可能會(huì)更方便一些,因?yàn)槲覀儾槐亟换ナ降倪M(jìn)入容器,而是使用 docker exec 來(lái)執(zhí)行命令,此時(shí)可以在容器外面為整個(gè)命令添加別名。
有了標(biāo)準(zhǔn)化環(huán)境,不僅可以在自己的電腦上運(yùn)行,還希望放在私有服務(wù)器上,讓大家通過(guò)網(wǎng)絡(luò)訪問(wèn)。要達(dá)到這樣的目的,一要能通過(guò) SSH 訪問(wèn)容器,二要能在服務(wù)器的數(shù)據(jù)卷和本地計(jì)算機(jī)之間同步數(shù)據(jù)(源碼及編譯結(jié)果)。對(duì)于 SSH,初步設(shè)想可以通過(guò)外部的一些 Docker 工具來(lái)完成,而不是在容器內(nèi)部建立 SSH 服務(wù)器,因?yàn)橛卸鄠€(gè)容器時(shí),要對(duì)應(yīng)多個(gè)不同端口等問(wèn)題。對(duì)于數(shù)據(jù)同步,可以在本地的 Windows 系統(tǒng)上通過(guò) Linux 子系統(tǒng)(WSL)建立 NFS 服務(wù)器,在容器內(nèi)部掛載 NFS,或者通過(guò) Docker 的插件實(shí)現(xiàn)直接將遠(yuǎn)端的 NFS 作為數(shù)據(jù)卷掛載。
4. 總結(jié)
如果并不需要 Docker 的一些優(yōu)勢(shì),我們也可以考慮將 PetaLinux 裝進(jìn) Windows 的 Linux 子系統(tǒng)(WSL),這樣可以有更好的性能和更無(wú)縫的操作。
使用虛擬機(jī)在 Windows 下搭建嵌入式開(kāi)發(fā)環(huán)境是以往非常常用的方式,但也是一種比較笨重的方式。隨著一些新的技術(shù)、平臺(tái)的出現(xiàn),如 Docker 和 WSL,我們可以嘗試?yán)盟鼈兇罱ㄩ_(kāi)發(fā)環(huán)境,提升開(kāi)發(fā)的效率。
參考
Dockerfile reference?
Best practices for writing Dockerfiles?
PetaLinux Reference Guide?
unable to locate packag lib32bz2-1-0?
how to run 32 bit app in ubuntu 64 bit?
how to add a file to an image in dockerfile without using the add or copy direct?
fails on ‘tar’ with: “Directory renamed before its status could be extracted”?
評(píng)論
查看更多