最近 Kubernetes 的發展,以及在我司的大量應用,自己也迫不及待想要嚐嚐鮮,雖然我的部落格是基於 Hexo 的純靜態站點,但這並不能阻擋我把它遷移上 Kubernetes!畢竟... 相比於 GitHub Pages 靈活性更好可控性更高,emmmm... 好了我編不下去了,總之,生命在於折騰?,我們開始吧。
本文涉及的程式碼(也就是我的部落格)完全開源:https://github.com/wi1dcard/blog。
構建 Docker 映象
要上 Kubernetes,首先要做的就是給專案打包映象。Dockerfile 非常簡單:
# 採用 nginx:stable-alpine 作為基礎映象
FROM nginx:stable-alpine
# 複製 ./public 到映象內 /usr/share/nginx/html
COPY ./public /usr/share/nginx/html
# 提示暴露 TCP 協議 80 埠
EXPOSE 80/tcp
我選用 Docker Hub 作為 Docker Registry,如果你有私有專案、許可權控制等相關需求,Quay.io 或許是更好的選擇。
CI 構建
當然啦,構建這種事情肯定是交給 CI。不推薦每次變更手動 Build,費時費力易出錯。
目前我給部落格用的是 Travis CI。我也考慮過:
- Circle CI,試用後感覺配置檔案(以我個人的風格來看)有點反直覺,放棄。
- GitLab CI,目前我認為最好的 CI/CD,我具備 CI/CD 需求的私人專案都在 GitLab。但是考慮到 (1) 要將部落格程式碼開源,(2) GitLab CI for GitHub repos 需要付費,(3) 兩套 VCS 感覺怪怪的,因此放棄。
- GitHub Actions,正在 Beta 中,打敗各路 CI/CD 的種子選手之一。只可惜文件還不夠齊全,穩定欠佳,只好暫時放棄。
- Docker Hub,若是隻用來構建公開映象感覺還不錯,但 (1) CI 和 Docker Registry 強繫結,想要換 Registry(比如上文中提到的 Quay.io)會很繁瑣,(2) 構建速度巨慢... 慢... 慢... 大概是使用者太多吧,情有可原,(3) 映象打包完成後需要使用 Helm 部署(即 CD)到叢集,明顯不適合該場景。
你可以在 這裡 找到我的 Travis 配置。其中定義了三個環境變數:
env:
global:
- DOCKER_USERNAME=wi1dcard # 我的 Docker Hub 使用者名稱
- DOCKER_IMAGE=$DOCKER_USERNAME/blog # Docker 映象名
- DOCKER_TAG=build-$TRAVIS_BUILD_NUMBER # Docker 映象 Tag
這些變數會在之後用到。
注意
$DOCKER_TAG
,它的值是動態的,即每次構建都會變化,由 Travis CI 的 預定義環境變數 拼接而成。
在 before_script
內,定義了構建過程的指令碼:
before_script:
- build/build.sh
由於構建、釋出過程比較複雜,同時為了未來(可能)遷移到 GitLab CI,我沒有將所有指令碼羅列在 .travis.yml
裡,像 alipay-sdk-php 等開源專案那樣。
所有與 CI 相關的內容我都放在了 build/
目錄。
build/build.sh 的主要任務是:
- 安裝依賴,例如 Hexo。
- 執行 lint 過程,檢查 Markdown 語法等。
- 渲染靜態站點,生成 PDF 格式簡歷。
- 構建 Docker 映象。
釋出 Docker 映象
與 CD 相關的內容我放在了 deploy/
目錄。正如 .travis.yml
定義的那樣,部署指令碼位於 deploy/deploy.sh:
script:
- deploy/deploy.sh
首先,登入 Docker Hub,接著推送映象:
echo "Logging in Docker Hub..."
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
echo "Pushing images to Docker Hub..."
docker push "$DOCKER_IMAGE"
注意,這裡用到了之前定義的環境變數。其中,$DOCKER_PASSWORD
我定義在 Travis CI 的私有環境變數內:
還有兩個環境變數 INGRESS_HOST
和 KUBECONFIG_BASE64
稍後會用到。
關於 Immutable
你可以在 這裡 檢視推送的映象和 Tags。
還記得 $DOCKER_TAG
的值是動態的嗎,所以每次 CI 構建產生的映象都會有唯一的 Tag 與它的 Build ID 對應。
這對我來說好處顯而易見:
- Immutable。每次構建的映象就像 Git Commit 一樣留下不可變更的印記。
- 清晰明瞭,不易混淆。你無法快速得知當前
lastet
具體是哪一次構建的產物。 - 便於回滾。雖然你可以重新構建映象,但如果你將每次構建的映象保留,那麼就可以快速地、完美地回滾到任意版本(尤其能夠防止同一 Git Commit 多次 Build 產生不同的 Image)。
- ...
其實,做了一年運維之後我發現,有時候混淆比「我不知道」更可怕。一些隱性的宣告可能會導致你在某個極小的問題上,毫無意義地浪費一整天時間。因此如果某些時候「簡潔優雅」和「清晰明瞭」產生衝突的時候,我會毫不猶豫選擇 清晰明瞭 地顯式宣告,儘管現在看起來可能有點醜,但未來除錯的時候可能會幫上大忙。
(未完待續)