位元詩人 [技術雜談] 以 Docker 容器編譯並執行 Swift 程式

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

前言

雖然 Swift 支援的系統比先前多,但很多 GNU/Linux 發行版都沒有官方的 Swift 開發環境。由於編譯 Swift 的過程相當複雜,官方的說明文件也不友善,自行編譯幾乎不可行。

為了要在非官方支援的 GNU/Linux 發行版上編譯和執行 Swift 程式,使用 Docker 是相對簡單且可行的方式。本文介紹使用 Docker 建置 Swift 開發環境的過程。

從命令列直接執行 Docker 容器

在動工前,本節先簡要地說明在命令列上直接執行 Docker 容器的方式。

使用 docker run 指令即可直接執行 Docker 容器,其虛擬指令如下:

$ sudo docker run image command

在這個虛擬指令中,image 是系統上已安裝的 Docker 映像檔,command 是要在 Docker 容器中執行的 GNU/Linux 指令。

docker run 指令只能執行單行 GNU/Linux 指令。因應這項限制,我們改用 /bin/sh -c "..." 的方式來執行指令:

$ sudo docker run image /bin/sh -c "..."

把實際要執行的指令以字串的型態寫在 "..." 內即可。這時候就可以寫入多行指令,指令間以 ; 隔開即可。

此外,我們要將程式碼拷貝到 Docker 容器中,該容器中的 Swift 編譯器才能讀得到程式碼。處理方式是將本地端的特定資料夾掛載 (mounting) 到 Docker 映像檔中:

$ sudo docker run -w /app -v `pwd`:/app run image /bin/sh -c "..."

-w 參數是在 Docker 容器中新增工作目錄。-v 參數用來指定要掛載的目錄。-v 參數的格式是 src:dest,其中 src 是本地端的目錄,而 dest 是 Docker 容器內相對應的目錄。

在這裡用 pwd(1) 指令動態地將當前工作目錄掛載到 Docker 容器中,不論工作目錄在那裡,都不需要另外指定程式碼的位置。

前置作業

要先安裝 Docker 才能進行後續的步驟。Docker 是蠻知名的軟體,大部分 GNU/Linux 發行版都有預編好的執行檔。以 openSUSE 為例:

$ sudo zypper install docker

安裝好 Docker 後,要啟動 Docker 服務:

$ sudo systemctl start docker

如果很常用 Docker 的話,可自行將 Docker 服務加入開機啟動項目中。

下載 Swift 官方 Docker 映像檔

使用以下指令下載 Swift 官方映像檔:

$ sudo docker pull swift:5.3

由於此官方映像檔已有完整的 Swift 編譯器,不需要在 Docker 映像檔中再額外安裝其他軟體。

將執行 Docker 的指令包成 Shell 命令稿

執行 Docker 容器的指令比較複雜,每次都手動輸入不太經濟,所以我們將其包成 shell 命令稿 $HOME/bin/swift

#!/bin/sh

input=$1

if ! [ -f $input ];
then
    sudo docker run --rm --cap-drop=all swift:5.3 /bin/sh -c "swift $@"
    exit $?
fi

sudo docker run --rm -w /app --cap-drop=all -v `pwd`:/app swift:5.3 /bin/sh -c \
"cp /app/$input /tmp; cd /tmp; swift $@"

這個指令會把程式碼傳入 Docker 容器中,並以該容器的 swift(1) 指令直接編譯及執行程式碼。

由於 swift(1) 在編譯及執行 Swift 程式的過程中會產生一些暫存檔,在 /tmp 目錄執行指令就不需要考慮權限的問題,是最簡單的方式。

將該命令稿加上可執行權限:

$ chmod +x ~/bin/swift

寫一個簡單的 Swift 程式來測試一下開發環境:

print("Hello World")

的確可順利地編譯和執行 Swift 程式:

$ swift hello.swift
Hello World

執行 Docker 容器時省略輸入密碼的過程

由於 Docker 需要 root 權限,使用 sudo(1) 輸入 Docker 指令時系統會多次詢問密碼。為了簡化輸入密碼的過程,可設置 sudo(1) 的權限:

$ sudo visudo

加入以下這行:

user ALL=(ALL) NOPASSWD: /usr/bin/docker

請將 user 換成實際的系統使用者帳號。我們只要快速地執行 Docker 容器,所以不開放其他的指令。

注意事項

本文所提供的 shell 命令稿以內部使用為主。由於此命令稿未考慮使用 Docker 的安全事項,勿將此命令稿用於對外公開的服務程式。

本方案的限制

本文所使用的 shell 命令稿只能執行單一 Swift 程式碼,而且該 Swift 程式也無法讀入外部檔案。如果需要其他的應用情境,請自行修改此命令稿。

對於有多個檔案的 Swift 專案來說,另外寫 Dockerfile 是比較好的選擇。限於篇幅,不在本文說明撰寫 Dockerfile 的方式。

關於作者

身為資訊領域碩士,位元詩人 (ByteBard) 認為開發應用程式的目的是為社會帶來價值。如果在這個過程中該軟體能成為永續經營的項目,那就是開發者和使用者雙贏的局面。

位元詩人喜歡用開源技術來解決各式各樣的問題,但必要時對專有技術也不排斥。閒暇之餘,位元詩人將所學寫成文章,放在這個網站上和大家分享。