Ubuntu 18.04 で OS 起動時の apt update と unattended-upgrade を抑制する方法

時間のない人向けのまとめ

sudo systemctl edit apt-daily.timer
sudo systemctl edit apt-daily-upgrade.timer

どちらも次の内容で保存します。

[Timer]
Persistent=false

もしくは、直接ファイルを編集して反映してもよいです。

sudo install -d -o root -g root -m 755 /etc/systemd/system/apt-daily.timer.d
cat <<EOF | sudo tee /etc/systemd/system/apt-daily.timer.d/override.conf
[Timer]
Persistent=false
EOF

cp -pR /etc/systemd/system/apt-daily.timer.d/ /etc/systemd/system/apt-daily-upgrade.timer.d/

sudo systemctl daemon-reload

何が問題なのか?

Ubuntu 18.04、少なくとも EC2 用の Ubuntu cloud image の 20200131 版 (18.04.4) では、毎日 6:00 頃に apt updateunattended-upgrade (セキュリティ関連の更新パッケージのインストール) が行われる (詳しくは後述) のですが、その時間帯に電源がオフで稼働していなかった場合は、次の OS 起動時に実行される設定になっています。

「その時間帯に電源がオフで稼働していなかった」は、AMI からインスタンスを起動したときも同じ状況になるので、AMI が古ければ古いほど更新パッケージが多くなり、起動直後に負荷が高まったり、しばらく apt install できない (unattended-upgrade がロックを獲得しているので) 時間が続いたりします。

その結果、次のような問題が発生します。

  • インスタンス起動後に自動的にプロビジョニングを行うようにしている運用の場合、プロビジョニング (の過程のパッケージのインストール) が完遂するまでの時間が安定しなかったり、場合によってはタイムアウトしてエラー終了してしまう

特にオートスケーリングの場合は、一刻も早くインスタンスを投入したいので深刻な問題になります。

またもし、AMI 採取用のインスタンスから日次で AMI を作る運用の場合は、パッケージはほぼ最新であることが期待できます。

というわけで、 OS 起動時の更新処理を実行されないようにした、というお話でした。

時間のある人向けの詳細

まず定期的に更新処理が実施される仕組みの説明から。

次の 2 つの systemd の timer ユニットがトリガーとなります。

  • apt-daily.timer
  • apt-daily-upgrade.timer

内容を確認すると、

$ systemctl cat apt-daily.timer
# /lib/systemd/system/apt-daily.timer
[Unit]
Description=Daily apt download activities

[Timer]
OnCalendar=*-*-* 6,18:00
RandomizedDelaySec=12h
Persistent=true

[Install]
WantedBy=timers.target


$ systemctl cat apt-daily-upgrade.timer
# /lib/systemd/system/apt-daily-upgrade.timer
[Unit]
Description=Daily apt upgrade and clean activities
After=apt-daily.timer

[Timer]
OnCalendar=*-*-* 6:00
RandomizedDelaySec=60m
Persistent=true

[Install]
WantedBy=timers.target

となっており、 apt-daily.timer は毎日 6:00 と 18:00 頃、 apt-daily-upgrade.timer は毎日 6:00 頃に発火するのがわかります。

発火すると、対応する systemd の service ユニットが実行されます。 systemctl cat で確認すると、実行されるコマンドライン (ExecStart) が確認できます。

  • apt-daily.service
    • ExecStart=/usr/lib/apt/apt.systemd.daily update
  • apt-daily-upgrade.service
    • ExecStart=/usr/lib/apt/apt.systemd.daily install

ざっくり言うと、

/usr/lib/apt/apt.systemd.daily update は - apt-get update - apt-get --download-only dist-upgrade - unattended-upgrade --download-only

/usr/lib/apt/apt.systemd.daily install は - unattended-upgrade

を行うためのもので、APT の設定で個別に実施する/しないを制御することができます。

デフォルトでの次のような設定になっていて、

$ apt-config dump | grep Periodic
APT::Periodic "";
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "0";
APT::Periodic::AutocleanInterval "0";
APT::Periodic::Unattended-Upgrade "1";
  • apt-get update 実施する
  • --download-only 系は実施しない
  • unattended-upgrade 実施する

という挙動になります。

ここまでが定期的に実行される仕組みの説明で、次からは主題の OS 起動時の更新処理の仕組みについてです。

timer ユニットの定義をみると Persistent=true というのがあり、これがキモです。

systemd.timer(5) から引用すると

Persistent=

Takes a boolean argument. If true, the time when the service unit was last triggered is stored on disk. When the timer is activated, the service unit is triggered immediately if it would have been triggered at least once during the time when the timer was inactive. This is useful to catch up on missed runs of the service when the system was powered down. Note that this setting only has an effect on timers configured with OnCalendar=. Defaults to false.

とのことなので、冒頭の方法で Persistent=false と上書き設定したわけです。

ちなみに

定期的なのも含め一切の自動的な更新処理をオフにしたい場合は、 /usr/lib/apt/apt.systemd.daily

# check if the user really wants to do something
AutoAptEnable=1  # default is yes
eval $(apt-config shell AutoAptEnable APT::Periodic::Enable)

if [ $AutoAptEnable -eq 0 ]; then
    exit 0
fi

という処理があるので

echo 'APT::Periodic::Enable "0";' | sudo tee /etc/apt/apt.conf.d/99disable-periodic

とかするといいんじゃないかと思います。

あと /etc/cron.daily/apt-compat という crontab があるんですが、

if [ -d /run/systemd/system ]; then
    exit 0
fi

となってるので systemd な環境では無いのと同じです。