問題の発生
新しいUbuntuやDebianのインスタンスに対してAnsibleプレイブックを実行した際、即座にクラッシュすることがあります。通常、以下のようなエラーが表示されます。
FAILED! => {
"msg": "'/usr/bin/apt-get dist-upgrade' failed: E: Could not get lock /var/lib/dpkg/lock-frontend - open (11: Resource temporarily unavailable)",
"rc": 100
}
原因
aptパッケージマネージャーは、複数のプロセスが同時にデータベースを変更するのを防ぐために、/var/lib/dpkg/lock-frontendなどのロックファイルを使用します。他のツールがソフトウェアをインストール中の場合、Ansibleはブロックされます。
主な原因は以下の通りです。
- **Unattended Upgrades(自動更新):** 近年のUbuntuのバージョンでは、起動後60秒以内に自動的に`apt update`が実行されることがよくあります。
- **タスクの重複:** 同じノードに対して複数のプレイブックを実行していたり、高いフォーク数(forks)で実行していたりする可能性があります。
- **ゾンビプロセス:** 前回のインストール試行がクラッシュし、古いロックファイルが残されたままになっている。
解決策 1: 「忍耐」パラメーター(ベストプラクティス)
Ansible 2.8以降、aptモジュールにはロックの解除を待機する機能が組み込まれています。エラーで終了する代わりに、ロックが解除されるまで指定した秒数待機します。
- name: ロックタイムアウトを指定してNginxをインストール
apt:
name: nginx
state: present
lock_timeout: 300
これにより、Ansibleは最大5分間待機します。追加のロジックや複雑なシェルコマンドを必要とせずにバックグラウンドの更新を処理できるため、最もスマートな解決策です。
解決策 2: 手動リトライロジック
古いバージョンのAnsibleを使用している場合や、より詳細に制御したい場合は、untilを使用します。これにより、10秒間隔で10回タスクをリトライし、バックグラウンドプロセスが終了するまで100秒間の猶予を与えます。
- name: リトライ設定付きでNginxをインストール
apt:
name: nginx
state: present
update_cache: yes
register: apt_result
until: apt_result is success
retries: 10
delay: 10
解決策 3: プリフライトチェック(事前確認)
パッケージ関連のタスクを実行する前に、状況を整えておきたい場合があります。プレイブックの最初に、aptプロセスが解放されるまで待機するタスクを追加できます。
- name: aptのロックが解除されるのを待機
shell: fuser /var/lib/dpkg/lock-frontend
register: lock_check
until: lock_check.rc != 0
retries: 20
delay: 10
failed_when: false
changed_when: false
このスニペットでは、ファイルを使用しているプロセスがない場合にfuserが0以外の終了コードを返します。Ansibleはそうなるまでループを繰り返します。
解決策 4: 自動更新の無効化
CI/CDランナーやイミュータブル・インフラストラクチャでは、OS自体の自動更新を完全に停止させたい場合があります。これにより、Ansibleだけがパッケージを管理する唯一のエンティティであることを保証できます。
- name: unattended-upgradesを停止し無効化する
systemd:
name: unattended-upgrades
state: stopped
enabled: no
- name: aptのデイリータイマーを無効化する
systemd:
name: "{{ item }}"
state: stopped
enabled: no
loop:
- apt-daily.timer
- apt-daily-upgrade.timer
最終手段: 強制削除
SSHセッションの切断などが原因で、ロックが完全に固着してしまっている場合は、手動で削除できます。警告: 実際の更新が実行されていないことが確実な場合にのみ使用してください。アップグレードの実行中にこれらを削除すると、dpkgデータベースが破損する可能性があります。
- name: 古いロックファイルを強制的に削除
file:
path: "{{ item }}"
state: absent
loop:
- /var/lib/dpkg/lock
- /var/lib/dpkg/lock-frontend
- /var/lib/apt/lists/lock
確認方法
現在どのプロセスがプレイブックの実行を妨げているかを確認するには、サーバーにログインして以下を実行します。
sudo lsof /var/lib/dpkg/lock-frontend
PID(プロセスID)が返された場合、それが原因です。何も返されない場合は、ロックは解放されています。Ansibleを実行する際に-vvvを使用すると、タスクが成功するまでに何回リトライされているかを正確に確認できます。

