📚 連載:Ansibleが理解できない理由はLinuxにあった【OS編】第6回:【cronが動かない理由】手動では動くのに失敗する原因
Linuxの仕組みからAnsibleを理解するシリーズです。
0️⃣ Ansibleの仕組み
1️⃣ Linuxの構造(Kernel / Shell / Filesystem)
2️⃣ command not foundの原因:PATH
3️⃣ SSH接続できない理由:鍵認証とポート
4️⃣ Permission deniedの原因:ユーザーと権限
5️⃣ サービスが起動しない理由:systemd
6️⃣ cronが動かない理由:PATH問題
7️⃣ ディスク満杯になる理由
8️⃣ サーバーが遅くなる理由
🗺️ 初めての方・シリーズの全体像を知りたい方はこちら
本記事は、OSの仕組みからAnsible設計までを繋ぐ連載シリーズの一部です。
「どこから読み始めればいいか」あるいは、「OS/Shell/Ansible編の関係性」 について把握されたい場合は、以下の統合ガイドで整理しています。
📑 【OS編】全体のまとめはこちら
→ Ansibleが理解できない理由はLinuxにあった【OS編】まとめ
📑 連載の移動
前の記事:【OS編】第5回 | 次の記事:【OS編】第7回
シリーズ全体構造(学習 × 問題解決)
本シリーズは
「理解(各記事)」と「問題解決(逆引き辞典)」を組み合わせて
スキルを身につける構成になっています。
この図は、どこから学び、どこに進めばよいかを示した“ロードマップ”です。
📍 現在の位置
現在はこの図の「OS編 第6回」になります
📍 はじめに:この記事のスタンス
Ansibleで定期実行タスクを構成する際、以下の事象が発生することがあります。
-
Ansibleの
cronモジュールは正常(changed)だが、実際には処理が実行されていない。 -
対象ホストにコマンドは存在するが、cron経由では
command not foundと判定される。
Ansibleによる設定は完了しているため、OS側での失敗原因が特定できない。
⚠️ 注意事項
本稿は、Linuxの cron の全機能を解説するものではありません。
目的は、Ansibleで設定した定期実行ジョブが動作しない場合、
「OS側のどの判定ステップで停止し、どのログを確認すべきか」を特定する手順の確立です。
「Ansibleによる設定(予約)は成功したが、OSによる実行は失敗した」
この切り分けを行い、第2回で扱った環境変数 $PATH の知識を軸に、AnsibleとOSの境界における仕様を整理します。
📋 目次
- 前回の振り返り:systemd管理と今回のcronの共通点
- 逆引き辞典との連動
- cronとは何か:Ansibleが書き換える「実行予約リスト」の実態
- なぜAnsibleで設定したジョブが動かないのか:登録〜実行における3つの判定ステップ
- cronログの読み方:OS側の「実行プロセスの事実」を特定する
- 実機検証:Ansibleの設定完了とOS側の実行失敗(Step1〜3)の再現
- 実務で遭遇する「ジョブが発見・実行できない」2つの要因と改善策
- まとめ:事象の特定を迅速化する「調査のプロセス」
- 次回予告
- 連載一覧:Ansibleが理解できない理由はLinuxにあった
1. 前回の振り返り:systemd管理と今回のcronの共通点
前回の記事では、システムのサービス管理を担う systemd を解説しました。Ansibleの成否は、OS側の「管理リスト」が期待通り(Active)に更新されるかどうかが基準でした。
今回のテーマである cron も同様の構造を持っています。
Ansibleの役割は対象ホストの「予約リスト」を書き換えることですが、最終的な目的は「処理の実行」です。第2回で解説した「$PATH(検索対象リスト)」の仕組みが、cronという制限された実行環境において、どのように影響するのかを確認していきます。
2. 逆引き辞典との連動
具体的なエラー名から原因を特定したい場合は、以下の逆引き辞典を活用してください。
Ansibleが理解できない理由はLinuxにあった :【保存版】Ansibleトラブル逆引き辞典|エラー別の原因と解決フローまとめ
- まず「逆引き辞典」で該当ステップを特定する
- 次に「本編(各連載記事)」で仕組みを理解する
3. cronとは何かansibleが書き換える実行予約リストの実態)
Linuxでスケジュールに基づいて処理を自動実行させる仕組みが cron です。
Ansibleの cron モジュールを使用する際、OS側で何が起きているのかを「責任範囲」の観点から整理します。
3-1. 構成要素と実行の仕組み
実務上、私たちが操作しているのは、システムが内部に保持している 「実行予約リスト(crontab)」 です。
| 構成要素 | 役割 | 実務での位置づけ |
|---|---|---|
| crond | 実行主体 | 1分ごとに「予約リスト」をチェックする常駐プロセス。 |
| crontab | 予約リスト | 「いつ・誰が・何を実行するか」が書かれた設定ファイル。 |
| crontabコマンド | 登録処理 | 書き込み時に書式チェックを実行 |
| 実行環境 | 隔離された環境 | ログインシェルとは切り離された、最小限の環境変数。 |
3-2. Ansibleの責任範囲:リスト更新プロセス
Ansibleの cron モジュールが行う操作は、対象ホストの「実行予約リスト(crontab)」に対する書き込み、更新、または削除です。このプロセスでは、OS側(crontabコマンド)による書式チェックの結果がAnsibleの戻り値に直結します。
1. 登録処理(crontabコマンド)
Ansibleが crontab を書き換えようとする際、OS側は設定値が仕様(分、時、日、月、曜日の範囲)に適合しているかを検証します。
-
仕様外の値(FAILED): 分の指定が「60」など、許容されない値である場合。OS側で「リストの更新不可」と判定されるため、Ansibleは失敗(FAILED)となります。この場合、実行予約自体が行われないため、crondのログ(
/var/log/cron)には記録が残りません
2. スケジュール管理(crond)
OS側のチェックを通過し、設定が受理された場合に限り、リストが更新されます。
- Ansibleの成功(changed/ok): 予約リストが指定通りの状態に更新されたことを意味します。この時点でAnsibleのタスクとしての役割は完結します。
3. 実行処理(シェル / OS)
更新されたリストに基づき、OS側の crond プロセスが独立してジョブを起動します。ここでの不備(コマンドが見つからない、あるいは出力先への権限不足)は、すでに完了したAnsibleの戻り値には一切影響を与えません。
処理の遷移と責任範囲の相関図
ポイント
- Ansibleは「crontabを書き換えるところまで」
- 実際の実行はOS(crond)が担当
- 両者は完全に独立している
3-3. 「登録成功」と「実行成否」の分離
Ansibleは「OSの書式チェックを通過し、実行予約リストへ登録すること」までは保証しますが、その後の「実行結果」には関与しません。
失敗のパターンは、以下の二段階に明確に分離されます。
-
登録段階の不備:
リスト更新時にOS側で「更新不可」と判定され、Ansibleが FAILED となります。OS側には予約が存在しないため、ログも記録されません。 -
実行段階の不備:
Ansibleが 「changed」または「ok」 と判定されているにもかかわらずジョブが動作しないケースです。この場合、Ansibleが指定した「書式」は正解ですが、「実行環境のパス(PATH)」や「書き込み権限」といったOS側の環境設定に原因があります。
この事実により、Ansibleが成功しているにもかかわらず目的の処理が行われていない場合は、速やかにOS側の実行ログ(/var/log/cron)を確認し、CMD(実行の試み)と CMDOUT(エラー内容)を確認して原因を特定する必要があります。
4. なぜAnsibleで設定したジョブが動かないのか:登録〜実行における3つの判定ステップ
Ansibleが設定を行った後、OS側の実行プロセス(crond)がジョブを起動しようとする際、以下の 「3つの判定ステップ」 を順次確認します。
第6章での実機検証結果が示す通り、どの段階で不備が生じるかによって、エラーの現れ方は明確に異なります。
OS側の判定フロー(全体像)
4-1. Step 1:設定形式(仕様)の整合性
OS側の crontab コマンドが、Ansibleから渡された設定値を「有効な実行予約リスト」として受理できるかどうかの判定です。
-
具体的な事象: 分の指定が「60」など、cronの仕様(0-59)に適合しない値を指定した場合。
-
OS側の挙動:
crontabコマンドが書式エラー(bad minute等)として入力を受理しません。 -
システム上の特徴:
・Ansibleの結果:FAILEDとなります。
・OSログ(/var/log/cron): 記録なし。
・状態: 予約リスト(crontab)の更新自体が行われないため、実行対象に含まれません。
4-2. Step 2:実行環境(PATH)の有効性
【Playbookでの確認箇所:job パラメータ内のコマンド指定】
OS側の crond が予約を認識した後、指定されたコマンドを環境内から見つけ出し、正常にジョブを起動できるかどうかの判定です。cron環境の $PATH はログイン時と異なり極めて限定的(/usr/bin:/bin など)であるため、不整合が最も起きやすい箇所です。
-
Playbookでの定義ミス(例):
ansible.builtin.cronモジュールのjobパラメータ に、コマンド名のみ(例:echo)を記述し、フルパスを指定しなかった場合。 -
OSログ(/var/log/cron) :
CMD(実行の試み) が記録されます。その後、不備があればCMDOUTにエラー内容(「コマンドが見つかりません」やCMDOUT にエラー内容が記録されます)が記録されます。 -
解決策 :
jobに記述するコマンドは、環境変数に依存しない 「絶対パス(フルパス)」 で記述します。
4-3. Step 3:実行ユーザー(USER)の権限
【Playbookでの確認箇所:job パラメータ内のリダイレクト(出力先)や処理内容】
OS側の crond がコマンドの特定と起動に成功した(Step 2をクリアした)後、そのコマンドが実際のファイル操作やディレクトリへのアクセスを許可されているかどうかの判定です。
-
Playbookでの定義ミス(例) :
jobパラメータに/usr/bin/echo(フルパス) を使用し、コマンド自体は正しく指定できているが、リダイレクト先である出力ディレクトリ(例:/var/log/myapp/)に対して、実行ユーザーの書き込み権限がない場合。 -
OS側の挙動 :
コマンドの起動自体は行われますが、その後のファイル書き込みやコマンド実行の段階で、OS(シェル)によって 「許可がありません(Permission denied)」 と判定され、処理が中断されます。 -
解決策 :
この不備はcronモジュールの設定だけでは解決できません。Ansibleのfileモジュール等を用いて、対象のディレクトリやファイルの所有権(owner/group)やパーミッションを適切に設定し、実行ユーザーが操作できるように環境側を調整する必要があります。
4-4.第4セクションのまとめ:OSによる3段階の判定基準
これまでの3つのステップを整理すると、トラブルの原因がどの階層に位置するかが明確になります。
| 判定箇所 | OSの判断基準 | 主な不整合の要因 | ログ(/var/log/cron)の現れ方 |
|---|---|---|---|
| Step 1: 形式 | 予約リストとして解釈可能か? | パラメータの範囲外指定(例: 60分) | なし(登録自体が拒絶される) |
| Step 2: 環境 | 指定されたコマンドは存在するか? | PATHの不足(フルパス未指定) | CMD(実行試行)と CMDOUT(エラー) |
| Step 3: 権限 | 実行およびアクセスは許可されているか? | ディレクトリ等のパーミッション不足 | CMD(実行試行)と CMDOUT(許可なし) |
5. cronログの読み方:OS側の「実行プロセスの事実」を特定する
Ansibleの実行結果が「changed」である以上、調査の対象はサーバー側のOSログへと移ります。OSがジョブをどう扱ったかは、以下のログファイルに全て記録されています。
5-1. 確認すべき主要なログファイル
使用しているOSのディストリビューションによって、出力先が異なります。
| OSの種類 | ログファイルのパス | 役割 |
|---|---|---|
| RHEL / CentOS / Alma / Rocky | /var/log/cron | cron専用の動作記録 |
| Ubuntu / Debian | /var/log/syslog | システム全体のログ(cronも含む) |
ログからの切り分けフロー
Ansibleの実行後、期待した時刻にジョブが動かなかった場合、以下のフローで「どこまで処理が進んでいるか」を特定します。
5-2. ログから読み取る「3つのステータス」
ログの出力内容によって、第4セクションで解説したどのStepで停止しているかを正確に判別できます。
① ログに何も記録されていない場合(Step 1 で停止)
指定した時刻を過ぎても、対象ジョブに関する行が一行も見当たらない状態です。
-
事実:
ログに何も記録されない場合、以下のいずれかが発生しています。
-
登録時に弾かれている
crontabコマンドのバリデーションエラーにより、Ansibleは FAILED となる。
→ 予約が登録されていないため、ログも出ない。 -
登録後に無効と判断されている
crondが設定を解釈できず、その行を無視する。
→ 実行対象に入らないため、ログも出ない。
- 確認ポイント : パラメータの範囲外指定(例:分に「60」と書く)や、ファイル末尾の改行不足、あるいは設定ファイルのパーミッション異常を疑います。
② 「CMD」が記録されている場合(Step 2 / 3 の段階)
以下のように、OSがジョブを認識し、プロセスを生成した履歴が残っている状態です。
Apr 29 19:18:01 server-01 CROND[2678]: (ansibleuser) CMD (/usr/bin/echo 'Test' >> /var/log/myapp/test.log 2>&1)
-
事実 : 設定形式(Step 1)はクリアしており、OSは「実行を試みた」ことを意味します。
-
確認ポイント: この記録があるにもかかわらず「本来の目的(ファイルの更新など)」が達成されていない場合は、エラーの内容を特定するために次の「CMDOUT」を確認します。
③ 「CMDOUT」が記録されている場合(Step 2 / 3 のエラー内容)
CMD 行の直後(または数秒以内)に出力され、具体的な失敗理由を教えてくれます。
-
「/bin/sh: command not found」など: PATHの不足やフルパス指定の欠如(Step 2: 環境不備)。
-
「許可がありません(Permission denied)」: 出力先ディレクトリや実行ファイル自体への権限不足(Step 3: 権限不足)。
5-3. 重要:ログは「開始まで」しか保証しない
ここで最も注意すべきは、/var/log/cron 等に記録されるのはあくまで「プロセスの起動」までであるという点です。
-
ログに記録されること:
crondがプロセスを生成し、コマンドを投げ出した事実。 -
ログに記録されないこと: 投げ出された後のコマンドが、バックグラウンドで正常に終了したかどうか(
CMDENDは単なる「プロセス終了」の合図であり、成功の証ではありません)。
[!IMPORTANT]
「正常に起動したか」 はOSログ(CMD/CMDOUT)で分かりますが、「ジョブが意図した成果を上げたか」 は、ジョブ側で個別に設定したログ(例:>> /var/log/myapp/test.log)の中身を直接確認する必要があります。
5-4. リアルタイムでの挙動確認
Ansibleを実行した直後の挙動を確認する場合、以下のコマンドでログを監視するのが実務的な手法です。
ログをリアルタイムで監視し、特定のユーザーの動きを追う(RHEL系)
sudo tail -f /var/log/cron | grep "(ansibleuser)"
6. 実機検証:Ansibleの設定完了とOS側の実行失敗(Step1〜3)の再現
これまでの論理(なぜ動かないのか)と調査手法(ログの読み方)が正しいことを、実機での挙動をもって証明します。
6-1. 検証の準備(リモートノード側の環境整備)
リモートノード側で、後の検証(Step 3)で使用する「権限不備」の環境を事前に作成し、ログの監視を開始します。
# [リモートノードで実行] ログ専用ディレクトリの作成(所有者root、権限755)
[root@localhost ~]# sudo mkdir -p /var/log/myapp
[root@localhost ~]# sudo chown root:root /var/log/myapp
# 権限の確認(ansibleuserは書き込み不可の状態)
[root@localhost ~]# ls -ld /var/log/myapp
drwxr-xr-x. 2 root root 6 4月 29 17:40 /var/log/myapp
# [リモートノードで実行] ログのリアルタイム監視
[root@localhost ~]# sudo tail -f /var/log/cron
6-2. 【検証1】ログに記録が残らない失敗(Step 1:形式エラー)
OS(crond)が解釈できない不正な値を設定し、登録段階で拒絶される状態を確認します。
コントロールノード側:Playbook
ファイル名:step1_format_error.yml
- name: Step 1 失敗再現(形式エラー)
hosts: test_servers
become: no
tasks:
- name: 誤って「60分」と指定
ansible.builtin.cron:
name: "step1-format-error"
minute: "60" # 0-59の範囲外
job: "/usr/bin/echo 'Step 1 Test'"
実機での検証結果:
■コントローラーノード側
(ansible) [root@localhost workspace]# ansible-playbook -i inventory.ini step1_format_error.yml
PLAY [Step 1 失敗再現(形式エラー)] ****************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************************
ok: [192.168.1.21]
TASK [誤って「60分」と指定] *************************************************************************************************************
fatal: [192.168.1.21]: FAILED! => {"changed": false, "msg": "\"/tmp/crontabi2pa3vzw\":2: bad minute\nInvalid crontab file, can't install.\n"}
PLAY RECAP ******************************************************************************************************************************
192.168.1.21 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
■リモートノード側
[root@localhost ~]# sudo tail -f /var/log/cron
Apr 29 17:39:03 localhost crond[777]: (CRON) STARTUP (1.5.7)
Apr 29 17:39:03 localhost crond[777]: (CRON) INFO (Syslog will be used instead of sendmail.)
Apr 29 17:39:03 localhost crond[777]: (CRON) INFO (RANDOM_DELAY will be scaled with factor 51% if used.)
Apr 29 17:39:03 localhost crond[777]: (CRON) INFO (running with inotify support)
(実行時刻になっても変化なし)
結論
「60分」のような形式エラーを指定した場合、OS側の crontab コマンドがバリデーションを行い、登録を拒絶します。このため、Ansibleは FAILED となり、予約リストに入らないためOSログも一切残らない ことが証明されました。
6-3. 【検証2】実行環境の不備(Step 2:環境エラー)
次は、設定形式は正しい(Ansibleは成功する)が、実行時にコマンドが見つからないケースを再現します。
1. コントロールノード側:Playbook作成
ファイル名:step2_path_error.yml
- name: Step 2 失敗再現(環境エラー)
hosts: test_servers
become: no
tasks:
- name: コマンドをあえて相対パスで指定
ansible.builtin.cron:
name: "step2-path-error"
minute: "*" # 毎分実行
# フルパスではない「echo」を指定。
# 出力先は準備した /var/log/myapp/step2.log を指定。
job: "echo 'Step 2 Test' > /var/log/myapp/step2.log 2>&1"
実機での検証結果:
■コントローラーノード側
(ansible) [root@localhost workspace]# ansible-playbook -i inventory.ini step2_path_error.yml
PLAY [Step 2 失敗再現(環境エラー)] ****************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************************
ok: [192.168.1.21]
TASK [コマンドをあえて相対パスで指定] ***************************************************************************************************
changed: [192.168.1.21]
PLAY RECAP ******************************************************************************************************************************
192.168.1.21 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
■リモートノード側
[root@localhost ~]# sudo tail -f /var/log/cron
Apr 29 19:03:01 localhost CROND[2236]: (ansibleuser) CMD (echo 'Step 2 Test' > /var/log/myapp/step2.log 2>&1)
Apr 29 19:03:02 localhost CROND[2234]: (ansibleuser) CMDOUT (/bin/sh: 行 1: /var/log/myapp/step2.log: 許可がありません)
Apr 29 19:03:02 localhost CROND[2234]: (ansibleuser) CMDEND (echo 'Step 2 Test' > /var/log/myapp/step2.log 2>&1)
結論
検証1(形式エラー)とは異なり、設定値が正しい場合は Ansibleの結果は changed(成功) となります。しかし、OSログを確認すると CMD(実行の試み) が記録されており、その後の CMDOUT によって、環境変数(PATH)の不足やリダイレクト先への権限不足により実行段階で失敗した事実が証明されました。
6-4. 【検証3】実行権限の不備(Step 3:パーミッション不足)
最後は、コマンドをフルパスに修正し、純粋に「出力先ディレクトリの権限」のみが原因で失敗する状況を再現します。
コントロールノード側:Playbook
ファイル名:step3_permission_error.yml
- name: Step 3 失敗再現(権限エラー)
hosts: test_servers
become: no
tasks:
- name: フルパスで指定するが、出力先(/var/log/myapp)に権限がない
ansible.builtin.cron:
name: "step3-permission-error"
minute: "*" # 毎分実行
# コマンドをフルパス(/usr/bin/echo)で指定。
job: "/usr/bin/echo 'Step 3 Test' >> /var/log/myapp/test.log 2>&1"
実機での検証結果:
■コントローラーノード側
(ansible) [root@localhost workspace]# ansible-playbook -i inventory.ini step3_permission_error.yml
TASK [フルパスで指定するが、出力先(/var/log/myapp)に権限がない] ***********************************************************************
changed: [192.168.1.21]
PLAY RECAP ******************************************************************************************************************************
192.168.1.21 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
■リモートノード側
[root@localhost ~]# sudo tail -f /var/log/cron
Apr 29 19:17:44 localhost crontab[2647]: (ansibleuser) REPLACE (ansibleuser)
Apr 29 19:18:01 localhost crond[777]: (ansibleuser) RELOAD (/var/spool/cron/ansibleuser)
Apr 29 19:18:01 localhost CROND[2678]: (ansibleuser) CMD (/usr/bin/echo 'Step 3 Test' >> /var/log/myapp/test.log 2>&1)
Apr 29 19:18:01 localhost CROND[2673]: (ansibleuser) CMDOUT (/bin/sh: 行 1: /var/log/myapp/test.log: 許可がありません)
Apr 29 19:18:01 localhost CROND[2673]: (ansibleuser) CMDEND (/usr/bin/echo 'Step 3 Test' >> /var/log/myapp/test.log 2>&1)
結論
検証2と同様、設定内容(コマンドのフルパス指定)が正しい場合、Ansibleの結果は changed(成功) となります。OSログには実行を試みた CMD が記録されますが、出力先(/var/log/myapp/)に対する書き込み権限がないため、最終的に CMDOUT でエラーとなり、ジョブが実質的に失敗している事実が証明されました。
6-5. 実機検証のまとめ(三段階の失敗パターン比較)
今回の検証で明らかになった、原因別の挙動の違いを整理します。
| 失敗の分類 | 原因の所在 | Ansibleの結果 | OSログ(/var/log/cron) | 失敗の特定難易度 |
|---|---|---|---|---|
| Step 1: 形式エラー | 設定値(構文) | FAILED | 記録なし(登録拒絶) | 低(Ansibleで即判明) |
| Step 2: 環境エラー | 実行環境(PATH等) | changed | CMD / CMDOUT に記録 | 中(OSログ確認が必要) |
| Step 3: 権限エラー | ファイル権限 | changed | CMD / CMDOUT に記録 | 中(OSログ確認が必要) |
結論
実機検証の結果、以下の事実が証明されました。
-
Ansibleの成功(changed)は実行の成功を意味しない: Step 2およびStep 3のように、設定ファイルの更新さえ成功すれば、Ansibleは「成功」と判定します。
-
OSログ(/var/log/cron)が唯一の実行証跡となる: Ansibleが成功しているにもかかわらずジョブが動作しない場合、OS側のログに出力される
CMD(実行の試み) およびCMDOUT(実行エラー内容) を確認することで、失敗原因を特定できます。
7. 実務で遭遇する「ジョブが発見・実行できない」2つの要因と改善策
実機検証(第6セクション)で証明された通り、Ansibleが「changed」と表示してもジョブが失敗する原因は、OS側の実行段階(Step 2およびStep 3)に潜んでいます。ここでは、現場で多発する2つの要因と、その根本的な改善策をまとめます。
7-1. 【要因1】環境変数(PATH)の不一致による実行失敗
実機検証2で確認した通り、ログインシェル(人間が操作する環境)とcron環境では、コマンドを探しに行く範囲(PATH)が全く異なります。
-
現象 :
ログインシェルでは動くコマンドが、cron経由だとCMDOUTに 「command not found」や、リダイレクト評価の失敗によるエラーを吐いて停止する。 -
改善策 :
・原則:コマンドはすべて絶対パスで記述する
Ansibleのjobパラメータには、echo ではなく/usr/bin/echoのようにフルパスを記述します。
・cron専用の環境変数(PATH)を定義する
複数のコマンドを使用する場合や、環境依存を減らしたい場合は、Ansibleの cron モジュールで env: yes を使用し、cron環境用のPATHを明示的に設定します。
※この設定は該当ユーザーのcrontab全体に適用されるため、既存ジョブへの影響にも注意が必要です。
- name: cron用のPATHを設定
ansible.builtin.cron:
name: PATH
env: yes
value: /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
7-2. 【要因2】実行ユーザーとディレクトリ権限の不整合
実機検証3で証明された通り、Ansibleは「設定ファイルの更新」には成功しますが、「そのジョブが書き込む先の権限」までは自動で調整してくれません。
-
現象 :
ログにCMDは記録されるが、CMDOUTに「許可がありません(Permission denied)」と出力され、ファイル出力やスクリプト実行が阻止される。 -
改善策:
・Ansiblefileモジュールによる事前整備
ジョブを登録する前に、出力先ディレクトリやログファイルの所有権・権限を適切に設定するタスクをセットで記述します。
- name: 出力先ディレクトリの権限を確保(Step 3 対策)
ansible.builtin.file:
path: /var/log/myapp
owner: ansibleuser # cronを実行するユーザーに合わせる
state: directory
mode: '0755'
※既存ファイルがある場合は、そのファイル自体の所有権・パーミッションも確認が必要です。
・適切な実行ユーザーの選択
システム領域を操作するジョブであれば、ansible.builtin.cron の user パラメータで明示的に適切なユーザー(root等)を指定して登録します。
8. まとめ:事象の特定を迅速化する「調査のプロセス」
Ansibleによるcron設定で、期待通りにジョブが動かない(あるいは FAILED になる)際は、以下の3ステップに従って「OS側の事実」を確認してください。
1. Ansible実行結果の確認
→ FAILED であれば設定値の構文エラー(Step 1)。changed なら「設定ファイルの更新」までは成功している。
2. OSログ(/var/log/cron)での実行証跡確認
→ 指定時刻に CMD(実行の試み)が記録されているか。なければ「登録されていない(FAILED)」か、OS側が設定行を無効と判断している。
3. 実行ログに記録された制限理由の特定
→ CMDOUT を確認し、「command not found」ならパスの不備(Step 2)、「Permission denied」なら権限不足(Step 3)を修正。
- 本質的な視点
cronの実行失敗は、Ansibleのタスクエラーではなく、その大半が 「OS側でのプロセス実行条件(パス・権限)の未充足」 です。
第3回の「接続」、第4回の「権限」、そして第5回の「サービス管理」と同様に、「OS側の証跡(log)にどのような事実が記録されているか」。この一点を正確に把握することが、トラブルシューティングにおける最短の経路となります。
9. 次回予告
定期実行(cron)の設定まで終え、自動運用が軌道に乗った段階で直面しやすいのが、Ansibleのタスクが停止する「容量不足」のエラーです。
「FAILED! => msg: No space left on device」
-
copy / template / unarchive モジュールが突然失敗する根本原因とは?
-
「ファイルを消して容量を空けた」にもかかわらず、Ansibleがエラーを出し続ける理由とは?
-
df -h で空き容量があるように見えても、新規作成が拒否される事象の正体とは?
次回、【第7回】No space left on device:Ansibleが失敗する「3つの実行チェック」 をお送りします。
「容量不足」というエラーメッセージの裏に隠されたOS側の判定ロジックを解き明かし、確実な調査手順を整理していきましょう。
📑 連載の移動
前の記事:【OS編】第5回 | 次の記事:【OS編】第7回
📑 【OS編】全体のまとめはこちら
→ Ansibleが理解できない理由はLinuxにあった【OS編】まとめ
🗺️ 初めての方・シリーズの全体像を知りたい方はこちら
本記事は、OSの仕組みからAnsible設計までを繋ぐ連載シリーズの一部です。
「どこから読み始めればいいか」あるいは、「OS/Shell/Ansible編の関係性」 について把握されたい場合は、以下の統合ガイドで整理しています。
10. 連載一覧:Ansibleが理解できない理由はLinuxにあった
| 回数とタイトル | 内容(概要) |
|---|---|
| Ansibleが理解できない理由はLinuxにあった【OS編】:【保存版】Ansibleトラブル逆引き辞典(Linux / SSH / Shellエラー対応 | Ansibleで発生するエラー(UNREACHABLE / Permission denied / command not found など)を「エラーから逆引き」で調べられる実務向け記事。各回の内容と対応しており、トラブル時の入口として使える。 |
| 第0回:【なぜAnsibleは理解できないのか】仕組みを分解してみる | Ansibleは「Linux操作の自動化」ツール。Ansible → SSH → Shell → Linux の構造を理解し、シリーズ全体の土台を作る。 |
| 第1回:【なぜLinuxが分からないと詰むのか】Kernel / Shell / Filesystemの全体像 | Linuxの基本構造を理解することで、Ansibleが内部で何をしているのか(Shell実行・プロセス・ファイル操作)を把握できるようになる。 |
| 第2回:【Ansibleでハマる】command not foundの原因はPATHだった(環境変数の正体) | Ansible実行時に発生する「command not found」の原因はPATHにある。環境変数の仕組みを理解しないとエラーを解決できない。 |
| 第3回:AnsibleのSSH接続が失敗すると UNREACHABLE エラーになる。(Connection refused / Permission denied / Timeout など) | AnsibleのSSH接続が失敗すると UNREACHABLE エラーになる。SSH(鍵認証・ポート・Firewall)を理解することで原因を特定できる。 |
| 第4回:【Permission deniedの正体】Linuxユーザーと権限の仕組み | Ansibleのbecome(sudo)で発生する Permission denied の原因はLinux権限にある。ユーザー・グループ・権限の仕組みを理解する。 |
| 第5回:【サービスが起動しない理由】systemdの仕組みを理解する | Ansibleのservice / systemdタスクが失敗する原因はLinux側にある。systemdの仕組みを理解することで原因を特定できる。 |
| 第6回:【cronが動かない理由】手動では動くのに失敗する原因 | Ansibleで設定したcronが動かない原因は環境差分(PATHなど)にある。cron特有の実行環境を理解することで解決できる。 |
| 第7回:【No space left on device】ディスク容量不足の原因と調査方法(df / du / log) | Ansible実行時のディスク不足エラーはLinuxのログ肥大化や容量管理が原因。df / duを使った調査方法を解説する。 |
| 第8回:【サーバーが遅い】原因の見つけ方(CPU / メモリ / プロセス) | Ansible実行が遅い・失敗する原因はサーバー負荷の可能性がある。CPU・メモリ・プロセスの見方を理解して原因を特定する。 |