Ubuntu(16.04/18.04) 默認會每天自動安裝系統(tǒng)的安全更新,但是不會自動安裝包的更新。本文梳理 Ubuntu 16.04/18.04 系統(tǒng)的自動更新機制,并介紹如何配置系統(tǒng)自動更新所有的包。說明:簡單起見,本文中使用 Ubuntu 指代 Ubuntu 16.04/18.04。
系統(tǒng)需要更新
當(dāng)我們遠程登錄系統(tǒng)時,會收到如下圖所示的更新相關(guān)的消息:
紅框中的第一行文字說明系統(tǒng)中有 149 個包需要更新。第二行說明沒有安全相關(guān)的包需要更新。之所以會這樣,是因為 Ubuntu 默認的配置會每天自動安裝安全更新而忽略其它包的更新。接下來我們就介紹 Ubuntu 中的自動更新機制。
通過定時任務(wù)執(zhí)行更新
Ubuntu 默認定義了 4 個 systemd unit 執(zhí)行更新任務(wù),它們分別是:
/lib/systemd/system/apt-daily-upgrade.service
/lib/systemd/system/apt-daily-upgrade.timer
/lib/systemd/system/apt-daily.service
/lib/systemd/system/apt-daily.timer
其中的 apt-daily.timer 和 apt-daily-upgrade.timer 是兩個觸發(fā)器,分別在每天指定的時間觸發(fā) apt-daily.service 和 apt-daily-upgrade.service。這兩個 service 的類型都是 oneshot,意思是當(dāng)任務(wù)完成后 service 進程退出。這兩個 service 其實調(diào)用的是同一個腳本: /usr/lib/apt/apt.systemd.daily。 apt-daily.service 為腳本傳入?yún)?shù) “update”,其功能為檢查系統(tǒng)的更新并下載對應(yīng)的更新包。apt-daily-upgrade.service 為腳本傳入?yún)?shù) “install”,其功能為安裝更新并刪除緩存在本地的更新包。
apt-daily.timer 默認每天觸發(fā)兩次,分別為 6 點和 18 點,主要是為了緩解服務(wù)器端的下載壓力。我們可以根據(jù)自身業(yè)務(wù)的特點設(shè)置合適的觸發(fā)時間。
apt-daily-upgrade.service 默認每天在 6 點觸發(fā)一次,我們也可以設(shè)置為其它時間,比如午夜。
apt.systemd.daily 腳本
/usr/lib/apt/apt.systemd.daily 腳本負責(zé)完成與更新相關(guān)的一系列工作,這些工作主要分為兩大塊:
•檢查更新并下載更新包
•安裝更新并清理更新包
apt.systemd.daily 腳本中調(diào)用 apt-config 命令從 /etc/apt/apt.conf.d/10periodic 文件和 /etc/apt/apt.conf.d/20auto-upgrades 讀中取配變量,并根據(jù)這些變量的值來控制系統(tǒng)的更新策略。下面我們介紹幾個比較重要的配置項。
隔多少天執(zhí)行一次 apt-get update,默認是 1 天,0 表示不執(zhí)行該操作:
APT::Periodic::Update-Package-Lists “1”;
隔多少天執(zhí)行一次 apt-get upgrade –download-only 下載更新包,0 表示不執(zhí)行該操作:
APT::Periodic::Download-Upgradeable-Packages “0”;
下載的更新版被緩存在目錄 /var/cache/apt/archives/ 中,執(zhí)行升級操作時直接從緩存目錄中讀取包文件而不是從網(wǎng)絡(luò)上下載。
隔多少天執(zhí)行一次 apt-get autoclean 清除無用的更新包,0 表示不執(zhí)行該操作:
APT::Periodic::AutocleanInterval “0”;
隔多少天執(zhí)行一次 Unattended-Upgrade 執(zhí)行系統(tǒng)安全更新(或者所以包的更新),0 表示不執(zhí)行該操作:
APT::Periodic::Unattended-Upgrade “1”;
通過這些配置,我們可以控制自動更新的頻率和行為。注意,到目前為止的配置還只能安裝系統(tǒng)的安全更新,如果要想安裝所有包的更新還需要其它的配置,相關(guān)內(nèi)容我們在后面的小節(jié)中介紹。
在繼續(xù)介紹后面的內(nèi)容前,讓我們先來了解一下 apt.systemd.daily 腳本中用到的 apt-config 命令和 apt.systemd.daily 腳本依賴的配置文件。
apt-config 命令
apt-config 是一個被 APT 套件使用的內(nèi)部命令,使用它可以在腳本中提取 /etc/apt/apt.conf 目錄下配置文件中的信息。
比如,如果要在腳本中獲取 APT::Periodic::Update-Package-Lists 的設(shè)置,可以使用下面的代碼:
#!/bin/bash
ABC=0
eval $(apt-config shell ABC APT::Periodic::Update-Package-Lists)
echo ${ABC}
此時腳本變量 ABC 中保存的就是 APT::Periodic::Update-Package-Lists 的值。
10periodic 和 20auto-upgrades
/etc/apt/apt.conf.d/10periodic 是 update-notifier-common 的配置文件:
$ dpkg-query -S /etc/apt/apt.conf.d/10periodic
update-notifier-common: /etc/apt/apt.conf.d/10periodic
在 ubuntu 16.04 和 18.04 中,這兩個文件的默認內(nèi)容是一樣的。apt.systemd.daily 腳本在注釋中說我們可以通過 /etc/apt/apt.conf.d/10periodic 文件自定義相關(guān)的變量值,它通過 get-config 命令來獲得這些變量的值。但是測試的結(jié)果是 /etc/apt/apt.conf.d/20auto-upgrades 文件中的變量會覆蓋 /etc/apt/apt.conf.d/10periodic 文件中的變量??磥硎?get-config 命令根據(jù)文件名稱的順序,排在后面的文件中的變量會覆蓋前面文件中的變量。
在 desktop 版本中,通過 GUI 程序修改相關(guān)的變量,這兩個文件都會被修改并保持一致,所以在 server 版中我們最好也同時修改這兩個文件并保持其內(nèi)容一致。
unattended-upgrades
Ubuntu 實際上是通過 unattended-upgrades 命令來自動安裝更新的。Ubuntu 16.04/18.04 默認安裝了這個包,如果碰到?jīng)]有安裝的情況你還可以通過下面的命令自行安裝:
$ sudo apt install unattended-upgrades
unattended-upgrades 的配置文件為 /etc/apt/apt.conf.d/50unattended-upgrades。
注意,unattended-upgrades 不僅能夠安裝系統(tǒng)的安全更新,還可以安裝所有包的更新。但是默認的配置只安裝安全更新,我們可以通過配置項讓 unattended-upgrades 安裝所有的包更新或者只安裝安全更新。
unattended-upgrades 命令被設(shè)計為通過 cron 定時執(zhí)行系統(tǒng)更新,但在 Ubuntu 16.04/18.04 中是通過 systemd 的 timer unit 定時觸發(fā) service unit 執(zhí)行的。
unattended-upgrades 命令的日志文件存放在 /var/log/unattended-upgrades 目錄下。
unattended-upgrade 命令常見的用法之一是檢查系統(tǒng)是否有更新:
$ sudo unattended-upgrade –dry-run
另一種用法是安裝更新:
$ sudo unattended-upgrade
在 apt.systemd.daily 腳本中執(zhí)行 unattended-upgrade 命令時,由于更新包已經(jīng)提前下載到緩存目錄了(/var/cache/apt/archives),所以直接它直接使用緩存中的更新包。
配置文件 50unattended-upgrades
50unattended-upgrades 文件中的默認配置只是安裝安全更新:
復(fù)制代碼
Unattended-Upgrade::Allowed-Origins {
“${distro_id}:${distro_codename}”;
“${distro_id}:${distro_codename}-security”;
“${distro_id}ESM:${distro_codename}”;
// “${distro_id}:${distro_codename}-updates”;
// “${distro_id}:${distro_codename}-proposed”;
// “${distro_id}:${distro_codename}-backports”;
};
復(fù)制代碼
如果要自動安裝所有包的更新,只要取消下面行的注釋就行了:
“${distro_id}:${distro_codename}-updates”;
我們還可以通過黑名單的方式指定不更新哪些包:
Unattended-Upgrade::Package-Blacklist {
“vim”;
“libc6”;
“libc6-dev”;
“libc6-i686”;
};
下面的配置項指定在更新后移除無用的包:
Unattended-Upgrade::Remove-Unused-Kernel-Packages “true”;
Unattended-Upgrade::Remove-Unused-Dependencies “true”;
有些更新需要重啟系統(tǒng),而默認的配置是不重啟系統(tǒng)的。下面的配置允許重啟系統(tǒng)(更新完成后,如果需要重啟,立即重啟系統(tǒng)):
Unattended-Upgrade::Automatic-Reboot “true”;
但是多數(shù)情況下我們更期望指定一個時間讓系統(tǒng)重啟(如果需要重啟,在下面配置中指定的時間重啟系統(tǒng)):
Unattended-Upgrade::Automatic-Reboot-Time “02:38”;
在系統(tǒng)更新的過程中發(fā)生了錯誤怎么辦?當(dāng)然是通知管理員啦!下面的配置在發(fā)生錯誤時給管理員發(fā)送郵件:
Unattended-Upgrade::Mail “user@example.com”;
Unattended-Upgrade::MailOnlyOnError “true”;
注意:如果要向外網(wǎng)發(fā)送郵件,需要安裝 mailx 等工具。
關(guān)閉自動更新
如果你的主機運行在封閉的環(huán)境中,并且無法連接到有效的更新源,此時可以選擇關(guān)閉自動更新功能。首選的方法是停止相關(guān)的服務(wù):
復(fù)制代碼
$ sudo systemctl stop apt-daily.service
$ sudo systemctl stop apt-daily.timer
$ sudo systemctl stop apt-daily-upgrade.service
$ sudo systemctl stop apt-daily-upgrade.timer
$ sudo systemctl disable apt-daily.service
$ sudo systemctl disable apt-daily.timer
$ sudo systemctl disable apt-daily-upgrade.service
$ sudo systemctl disable apt-daily-upgrade.timer
復(fù)制代碼
或者修改自動更新程序的配置文件也可以,同時更新 /etc/apt/apt.conf.d/10periodic 和 /etc/apt/apt.conf.d/20auto-upgrades:
APT::Periodic::Update-Package-Lists “1”;
APT::Periodic::Unattended-Upgrade “1”;
改為
APT::Periodic::Update-Package-Lists “0”;
APT::Periodic::Unattended-Upgrade “0”;
故障調(diào)查
因為 apt.systemd.daily 腳本同時調(diào)用了 apt-get 和 unattended-upgrade 等命令,所以相關(guān)的日志也分散在不同的地方。apt-get 相關(guān)的日志在 /var/log/apt 目錄下,unattended-upgrade 命令的日志在 /var/log/unattended-upgrades 目錄下。