Dockerfile 支持內(nèi)置Shell腳本, 從此告別 && 鏈接符號
前幾天, 我測試 Dockerfile 的 Here-Doc 語法[1], 說其是 雞肋語法, 是我 淺薄 了。
重新看了 docker 官網(wǎng)文檔關(guān)于 buildkit[2] 的介紹, 從 docker engine 23.0 開始就是默認 builder 了。
BuildKitopen_in_new is an improved backend to replace the legacy builder. BuildKit is the default builder for users on Docker Desktop, and Docker Engine as of version 23.0.
換句話說, 我們上一篇文章說的的諸多不便, 都自然消失了。
之所以得出 HereDoc 是雞肋語法 的 謬論, 我仔細分析了一下, 有以下幾個原因。
我測試服務(wù)器上的 docker 版本過低, (20.x) 。
太久沒寫 基礎(chǔ)鏡像 了, 因此沒有復(fù)雜的 RUN 和 COPY 命令。
基于以上幾點, 我做了一些優(yōu)化。
- 于是我根據(jù)官網(wǎng)文檔,重新安裝 docker engine, 將版本升級到了 24.0.5,
- 找到了在 Docker Hub 上的 redis 官方 dockerfile 重新測試。
得到的結(jié)論是, Here-Doc 語法真的是 太香了。
一句話總結(jié):不僅指支持多行語法, 是直接支持內(nèi)置 Shell 腳本
超級棒的 Dockerfile Here-Document Syntax 語法
首先, 按照官網(wǎng)文檔將 docker engine 版本升到最新。以 ubuntu - docker[3] 為例
sudo apt-get install docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
其次, 在 Docker Hub 上找到對應(yīng)的 redis 官方 dockerfile[4]
可以看到, RUN 內(nèi)容雖然沒有通過 && 鏈接, 但是都是使用 ; 和 \ 進行 分段,換行 管理的, 還是有一定不便。
稍微改造一下, (1) 刪除所有 鏈接作用 的 ; \, (2) 取消 RUN 的所有縮進。
劃重點:這就是 一個Shell腳本 了。 換句話說, 在本地測試完成之后, 可以直接復(fù)制到 Dockerfile 中了。而之前, 還需要使用 && 鏈接整理命令。
注意: 這里必須使用以下格式, 否則 局部變量向下無法傳遞。
RUN <<EOT
#!/bin/bash
# statment
EOT
直接使用 docker build 命令構(gòu)建鏡像, 看看執(zhí)行結(jié)果
Troubleshooting
變量傳遞問題
關(guān)于以下兩種模式, 官網(wǎng)文檔并沒有說明為什么。僅從對比實驗效果上推測, 具體實現(xiàn)還沒有研究。
模式1 bash 直接根在 EOT 后面。
RUN <<EOT bash
dist=$(uname -s)
wget -O example.com/app-${dist} app-${dist}
EOT
這種模式下, 第一行的變量 dist 在第二行 wget 中無法使用。因此 wget 行實際解析出來的命令為
wget -O example.com/app- app-
模式2, 在多行內(nèi)容中 首行 指定解釋器 #!/bin/bash, 則所有內(nèi)容整體被看作一個 Shell 腳本。
RUN <<EOT
#!/bin/bash
dist=$(uname -s)
wget -O example.com/app-${dist} app-${dist}
EOT
這種模式下, wget 行實際解析出來的命令為
wget -O example.com/app-Linux app-Linux
符合預(yù)期
沒有 buildkit 配置文件
ls: cannot access '/root/.docker/buildx/instances/default': No such file or directory
找不到默認的 buildx 配置, 使用如下即可。
{
"Name": "localbuilder",
"Driver": "docker-container",
"Nodes": [
{
"Name": "localbuilder0",
"Endpoint": "unix:///var/run/docker.sock",
"Platforms": [
{
"architecture": "amd64",
"os": "linux"
},
{
"architecture": "arm64",
"os": "linux"
}
],
"Flags": null,
"ConfigFile": "",
"DriverOpts": {}
}
],
"Dynamic": false
}