Linux自動更新運用の完全形

はじめに:「更新したはずなのに」が起きる理由

apt upgradeやdnf updateを実行すれば安全——そう思っていないだろうか。実際にはパッケージの更新後も古いライブラリをメモリに読み込んだままのプロセスが動き続けるという問題が残る。例えばnginxを更新してもOpenSSLの脆弱性を抱えた古いバイナリが稼働しているのはそのためだ。

さらに自動更新を仕掛けても、新たなカーネルがインストールされていても再起動するまで新しいカーネルは使われない(Ubuntuの無停止カーネルパッチ運用は除く)。ログを見ていないと更新自体が失敗していても気づかないといった事が起こる。

この記事では、筆者が運用している11台のLinux(Debian / RHEL / OracleLinux / Fedora / Proxmox混在)に対して以下の組み合わせで「本当に安全な自動更新運用」を構築した手順と、実際に遭遇したトラブルを記録している。この構成で20年程度運用しているが問題は起きていない。

  • cron-apt(Debian系)/ dnf-automatic(RHEL/Fedora系): パッケージの自動更新
  • Logwatch: 毎朝のログダイジェストで異常検知
  • needrestart / needs-restarting: 更新後にサービスを自動再起動し、古いバイナリを確実に追い出す
  • Ansible: 11ホストへの一括展開

自動パッケージ更新の設定

cron-apt(Debian / Ubuntu / Proxmox)

cron-apt は毎晩 apt を実行し、更新を自動適用する。

apt install cron-apt

/etc/cron-apt/config で動作を制御する。デフォルトでは毎日午前4時に実行される。

# /etc/cron-apt/config
MAILTO="admin@example.com"
MAILONLY="no"
DEBUG="0"

/etc/cron-apt/action.d/3-download を確認し、upgrade アクションが有効か確認する。

# 取得から自動適用まで
apt-get -o quiet=2 dist-upgrade -y

dnf-automatic(RHEL / OracleLinux / Fedora)

dnf install dnf-automatic

/etc/dnf/automatic.conf で自動適用を有効化する。

[commands]
# ダウンロードだけなら "download"、自動適用なら "default"
upgrade_type = default
random_sleep = 0

[emitters]
emit_via = stdio

[email]
email_from = root@localhost
email_to = admin@example.com
email_host = localhost

[base]
debuglevel = 1

systemd timer で有効化する。

systemctl enable --now dnf-automatic.timer
systemctl status dnf-automatic.timer

フリートへのAnsible展開

複数ディストリビューション混在環境では Ansible の ansible_os_family で条件分岐するのが定石である。

- name: cron-apt をインストール (Debian系)
  apt:
    name: cron-apt
    state: present
  when: ansible_os_family == "Debian"

- name: dnf-automatic をインストール (RedHat系)
  dnf:
    name: dnf-automatic
    state: present
  when: ansible_os_family == "RedHat"

- name: dnf-automatic timer を有効化 (RedHat系)
  systemd:
    name: dnf-automatic.timer
    enabled: yes
    state: started
  when: ansible_os_family == "RedHat"

Logwatch:毎朝のログダイジェストで異常を検知

logwatch は毎日サーバーの各種ログ(syslog、auth、ssh、postfix、httpど)を集約し、デイリーレポートをメール配信する。自動更新が実行されたか、デーモン起動障害がないか、不権アクセス試行がないかを毎朝目視するだけで検知が完結する。

インストール

# Debian / Ubuntu / Proxmox
apt install logwatch

# RHEL / OracleLinux / Fedora
dnf install logwatch

設定

/etc/logwatch/conf/logwatch.conf(存在しなければ新規作成)に最低限以下を記載する。

Output = mail
MailTo = yoshi@example.com
MailFrom = logwatch@hostname
Detail = Med
Service = All
Range = yesterday

cron で自動実行する場合は /etc/cron.daily/00logwatch が自動生成される(Debian系)。RHEL系は /etc/cron.d/0logwatch を確認する。

レポートの読み方

Logwatch のメールで特に注目するセクション:

セクション 読み方
sshd Failed password / Invalid user の数を確認。異常に多い IP は fail2ban 等でブロック
sudo 予期せぬ sudo 実行がないか確認
package updates (dpkg/dnf) 更新が自動実行されたことを確認。「0パッケージ」が続いたら更新失敗を調査
disk ディスク満杯警告を確認
postfix / sendmail 山橋が異常なメールがないか

drift-check は不要?

単一管理者環境では Logwatch の目視 + cron-apt/dnf-automatic の実行記録確認で十分である。ansible-playbook --check --diff による drift-check は複数人がサーバーに触れるチーム環境で初めて意味を持つ。

needrestart:更新後のサービス再起動漏れを防ぐ

needrestart はパッケージ更新後に「古いバージョンのライブラリを使い続けているサービス」を検出し、自動または手動で再起動するツール。Debian系標準。

インストールと自動モード設定

apt install needrestart

/etc/needrestart/needrestart.conf で自動モードを有効化する。

# デフォルト (interactive)
# $nrconf{restart} = 'i';

# 自動モードに変更
$nrconf{restart} = 'a';

動作確認

needrestart -b

出力の読み方:

NEEDRESTART-VER: 3.6
NEEDRESTART-KCUR: 6.1.0-28-amd64   ← 現在稼働中のカーネル
NEEDRESTART-KEXP: 6.1.0-28-amd64
NEEDRESTART-KSTA: 1                 ← 1=OK、 3=再起動必要
NEEDRESTART-SVC: php8.4-fpm.service ← 古いライブラリを使い続けているサービス

KSTA:3 はカーネル再起動が必要なことを示す。KSTA:1 はカーネルも最新で問題なし。

RHEL系でのneedrestart代替:needs-restarting

RHEL/RHELファミリーでは EPEL の needrestart が perl(Locale::TextDomain) 依存性の問題でインストールできないケースがある(CRB リポジトリが利用不可なサブスクリプション)。その場合は標準添付の dnf-utils(yum-utils)に包まれる needs-restarting を代わりに使う。

# 再起動が必要なサービスを一覧
needrestart -s

# 再起動が必要かどうか確認(rc=1 なら再起動必要)
needs-restarting -r; echo $?

注意: needs-restarting -r の成功終了コードは rc=1(再起動必要)。シェルスクリプトで && で纋げると次のコマンドが実行されないので || か条件分岐を使うこと。

Ansibleでフリートに一括展開

11台のホスト(Debian 12 / RHEL 9 / OracleLinux 10 / Fedora / Proxmox VE混在)に対して needrestart-deploy.yml Playbook で一括展開した。

Playbook

---
- name: needrestart を全サーバーに展開
  hosts: all:!windows
  become: yes
  tasks:
    - name: needrestart をインストール (Debian / Proxmox 系)
      apt:
        name: needrestart
        state: present
      when: ansible_os_family == "Debian"

    - name: EPEL を有効化 (RHEL のみ。OracleLinuxは不要)
      dnf:
        name: epel-release
        state: present
      when:
        - ansible_os_family == "RedHat"
        - ansible_distribution == "RedHat"

    - name: needrestart をインストール (RedHat / Fedora 系)
      dnf:
        name: needrestart
        state: present
      when: ansible_os_family == "RedHat"

    - name: needrestart を自動モードに設定
      lineinfile:
        path: /etc/needrestart/needrestart.conf
        regexp: '^#?\$nrconf\{restart\}'
        line: "$nrconf{restart} = 'a';"
      when: ansible_os_family in ["Debian", "RedHat"]

    - name: 動作確認(再起動が必要なサービスを一覧)
      command: needrestart -b -r l
      register: nr_check
      changed_when: false
      when: ansible_os_family in ["Debian", "RedHat"]

    - name: 再起動が必要なサービスを表示
      debug:
        msg: "{{ nr_check.stdout_lines }}"
      when:
        - ansible_os_family in ["Debian", "RedHat"]
        - nr_check is defined
        - nr_check.stdout_lines | length > 0

実際に発生したトラブルと解決

OracleLinux 10 で EPEL リポジトリへのアクセス失敗

OracleLinux 10 は epel-release パッケージではなく、ol10_u1_developer_EPEL リポジトリがプリビルトで入っている。Playbook の EPEL 有効化ステップを ansible_distribution == "RedHat" だけに絞ることで解決。OracleLinux はそのまま needrestart を dnf install で導入できる。

RHEL で perl(Locale::TextDomain) 依存性エラー

RHEL のこのサブスクリプションでは CRB (CodeReady Builder)リポジトリが利用不可。needrestart のインストールが失敗するため、dnf-utils に標準添付の needs-restarting を代替ツールとして使用する。

GCPインスタンス再起動時のSSHタイムアウト

GCP インスタンスは再起動後の SSH 接続が 120秒を超えることがある。Ansible の reboot_timeout を 300 以上に設定することで回避できる。

ansible -i hosts.ini dns01 -m reboot -a "reboot_timeout=300" --become

実行時の注意点

  • ansible.cfg はカレントディレクトリで読み込まれる: ~/ansible/ から実行することが必須。~ から実行すると inventory が読めずホスト横断が失敗する。
  • DNSサーバーの同時再起動は禁物: dns01(Primary DNS)と dns02(Secondary DNS)を同時に再起動すると DNS が停止する。必ず順次再起動する。

カーネル更新後の再起動管理

needrestart が自動再起動するのはサービスのみであり、カーネルの再起動は必ず手動で行う必要がある。

カーネル再起動が必要なホストの確認

# needrestart で KSTA:3 のホストを確認
ansible all -i hosts.ini -m command -a "needrestart -b" --become 2>/dev/null | grep -A2 'KSTA: 3'

# RHEL系は needs-restarting -rで確認
ansible rhel -i hosts.ini -m command -a "needs-restarting -r" --become
# rc=1 が返ったホストは再起動必要

Ansibleで再起動する

cd ~/ansible

# 単一ホスト再起動
ansible -i hosts.ini <hostname> -m reboot -a "reboot_timeout=300" --become

# 再起動後の確認
ansible -i hosts.ini <hostname> -m command -a "uname -r" --become

今回の実施結果

ホスト ディストリビューション カーネル再起動 検出ツール 備考
web01 Debian 12 済み needrestart KSTA:1
app01 RHEL 9 済み needs-restarting 26秒で正常再起動
backup01 Debian 12 済み needrestart 32秒で正常再起動
dns01 Debian 12 済み needrestart GCP、SSH再接続に120秒超
dns02 Debian 12 未実施 needrestart dns01 の確認後に実施
ol01 OracleLinux 10 保留中 needrestart EPEL問題解決済み
pve01 / pve02 / pve03 Proxmox VE 保留中 needrestart VM配置計画が必要

DNSサーバー再起動の注意

dns01(Primary DNS)と dns02(Secondary DNS)を同時に再起動すると DNS 解決が完全停止する。必ず片方が起動してから、正常を確認してもう片方を再起動する。

Proxmox VE の再起動

PVE ホスト再起動は VM が停止するため、メンテナンスウィンドウを設けて実施する。VMを事前に live migration するか、シャットダウン再起動するかを決める。

Claude メモリへの環境登録

自動化環境が整ったら、今後の AI 支援運用のために Claude のメモリへ環境情報を登録しておくと便利だ。**本セクションは、ここまでの設定(cron-apt / dnf-automatic / Logwatch / needrestart / Ansible 展開)がすべて完了していることを前提とする。**次回以降のセッションでホスト一覧や Ansible のパスを都度説明する手間が省ける。

Claude.ai にはセッションをまたいで情報を記憶できる「メモリ」機能がある。フリートのインベントリや運用ルールをここに登録しておけば、将来のセッションでも即座にコンテキストを把握した状態で作業を再開できる。

登録する情報

  • フリートインベントリ: ホスト名・OS・役割
  • Ansible のパス: Playbook の場所(~/ansible/)、ansible.cfg の前提条件
  • ツール導入状況: 各ホストの cron-apt / dnf-automatic / needrestart の有無
  • 運用ルール: DNS 二重再起動禁止、Proxmox VE はメンテナンスウィンドウ必要、など

登録プロンプト例

以下は記入例。実際のホスト名・ OS・ディレクトリパス・注意事項は自分の環境に合わせて書き換えてから、Claude との会話に貼り付ける。

以下の情報をメモリに保存してください:

フリート構成:
- web01: Debian 12(Webサーバー)
- app01: RHEL 9(needs-restarting を使用)
- backup01: Debian 12(バックアップサーバー)
- dns01, dns02: Debian 12(Primary / Secondary DNS)
- ol01: OracleLinux 10
- pve01, pve02: Proxmox VE

Ansible: ~/ansible/ に配置、必ず cd ~/ansible してから実行

注意事項:
- dns01 と dns02 の同時再起動禁止(DNS 停止)
- Proxmox VE の再起動は VM 停止を伴うため要計画

Claude が /areas/galaxies-infra.md などのメモリファイルに自動記録する。設定を変えたり台数が増えたりしたときは「galaxies-infra.md のメモリを更新して」と伝えれば即座に反映される。

次回セッションからの活用

メモリ登録後は Claude が環境を把握した状態で会話を開始できる。

  • 「KSTA:3 が出ているホストを確認したい」→ 各ホストのツール構成を把握済みで回答
  • 「dns01 を再起動したい」→ SSH タイムアウト注意点も自動で踏まえる
  • 「needrestart を全ホストに再展開したい」→ ~/ansible/ のパスや Playbook 名を聞かずに提案

都度コンテキストを貼り直す手間がなくなり、インフラ作業のスタート時間が大幅に短縤できる。

まとめ:自動更新運用の完全形

これで「パッケージを更新しても古いバイナリが動き続ける」問題が解決される。各ツールの役割分担を整理する。

ツール 役割 対象
cron-apt パッケージ自動更新 Debian / Ubuntu / Proxmox
dnf-automatic パッケージ自動更新 RHEL / OracleLinux / Fedora
Logwatch 更新・異常・不権アクセス検知 全ディストリビューション
needrestart 更新後のサービス自動再起動 Debian系、OracleLinux
needs-restarting 更新後のサービス確認(導入までの代替) RHEL
Ansible 全ホストへの設定一括展開 フリート全体

自動化できない部分

  • カーネル再起動: KSTA:3 を検出したら手動で計画再起動する。Proxmox VE は VM の現班稺認等が必要
  • パッケージ更新の破抑性変更への対応: Logwatch が警告したら手動指対応
  • DNSサービスの同時再起動回避: Primary / Secondary の順次再起動は必ず手動管理

参考リンク

sponsored links
sponsored links
sponsored links