使用 Packer 建立 AWS EC2 AMI 或者是 GCP Machine Image,兩個都會有機率發生一些問題, 有時候是 image 內一些應用程式安裝出現問題;有時候是再最後啟動 AWS 或 GCP 虛擬機時,使用 user-data 或 startup-script 時會出現問題,共同的錯誤訊息是 no installation candidate. 。 AWS 機率發生體感機率比 GCP 高不少。那問題的根源是什麼呢,來看看吧!


錯誤訊息原因分析

當我們在 script 內使用sudo apt install XXX時,如果:

  • 輸入錯誤的安裝應用程式名稱
  • 嘗試安裝不在預設存儲庫中的應用程式

或者是:

  • Apt 無法在存儲庫中找到要安裝的應用程式,但知道應用程式的存在(可能是預設存儲庫中還有許多其他軟體包引用到該應用程式的引用。

以上問題發生,就會出現 no installation candidate. 錯誤訊息。

如果是 Apt 無法在存儲庫中找到要安裝的應用程式的話,解決方法是先把 Apt 的資料庫更新:

sudo apt update && sudo apt upgrade

出現此問題的原因是 Apt 不會自動檢查本地儲存庫是否與遠端儲存庫同步。故當本地落後於更新時,會因為和遠端連結不同步,而斷開遠端連結,就會產生 no installation candidate. 的錯誤訊息。


Packer build machine image 機率性錯誤分析

承上分析知道,正常的情況下,在 Packer build image 的 script 內,有寫 apt update ,故 Apt 本地儲存庫狀態應該會是完好最新的,應該都可以正常獲取 package,但是卻發現機率性 Apt 本地儲存庫狀態會有問題,到底為甚麼呢?

最後找到原因:

cloud-init 執行時會將 apt default source 改掉

例如 AWS:

看起來是有發生 race condition。Packer 有時會在 cloud-init 仍在運行時就啟動 build script。

這個狀況並非每次都發生的原因是在於 cloud-init 和 Packer 哪一個先跑完

cloud-init 先跑完:

Apt 本地儲存庫狀態,會改成 apt cloud source 。 Packer 再執行的 apt update 就會是 cloud source 最新狀態。在最後啟動虛擬機時用 user-data 或startup-script 時套件正常安裝。

Packer 先跑完:

Packer 先執行 apt update ,故 apt default source 狀態為最新狀態。 接下來 cloud-init 才完成,apt default source 會改成 apt cloud source ,且狀態會是舊的。故可能在最後啟動虛擬機時用 user-data 或 startup-script 時,發現 apt cloud source 狀態並非最新,而發生 no installation candidate.


Solution

這個雷常出現在 Packer 中,網路上有些解決方法:

  • 強制 sleep,等待 cloud-init 完成。這方法雖然不太好,但還是有人用…

    while [ ! -f /var/lib/cloud/instance/boot-finished ]; do echo 'Waiting for cloud-init...'; sleep 1; done
    

  • 推薦解法

    cloud-init status –wait
    


Reference