Cron でホストレポートの定期実行を管理する

LinuxBeginner
オンラインで実践に進む

はじめに

信頼できるスケジューリングには、Play の成功 recap 以上の証拠が必要です。一般ユーザー用の保護されたレポートプログラムを配置し、安定した名前付き cron エントリを管理して、自然なスケジュール実行を観察し、フェーズを更新して、別の一時エントリを削除します。最終チェックは、無関係の既存ジョブを維持しながら、新たなスケジューラー実行を観察します。

一般ユーザーのレポートと名前付きスケジュールを配置する

このステップでは、提供されたレポートプログラムを配置し、両管理対象ホストの automation ユーザーにスケジュールします。

前提として cron はインストール済みで、デーモンも稼働中です。ノードでは systemd は動作していません。各 automation の crontab には、無関係の keep-existing-report エントリもあります。それを維持してください。cron モジュールは、ユーザーの crontab 全体を置き換えず、安定した名前付きエントリを管理します。

プロジェクトに移動し、提供されたコントローラーのプログラムを調べます。

cd /home/labex/project
cat files/host-report.sh

このプログラムは、UTC エポックタイムスタンプ、実際のホスト名、フェーズ引数を、保護された管理対象ログに追記します。Umask 027 により、新しいログファイルのモードは 0640 になります。プログラムは変更せず、cron に自然に実行させてください。手動で呼び出しても、スケジュールの実証にはなりません。

フェーズを再利用可能な入力として定義します。

cat > group_vars/all.yml <<'YAML'
report_phase: initial
YAML

Playbook を作成します。cron ジョブには minute、hour、日、month、weekday のフィールドがあり、各フィールドのアスタリスクは毎分 1 回の実行を意味します。name は、後の更新に使う Ansible マーカーを作成し、user automation はそのユーザーの crontab を選択します。Become は、その指定ユーザーのスケジュールと明示的なファイル所有権を管理できるようにするもので、定期実行プログラムを root として実行するものではありません。

cat > reporting.yml <<'YAML'
- name: Manage a scheduled ordinary-user host report
  hosts: all
  gather_facts: false
  become: true
  tasks:
    - name: Prepare the ordinary user's reporting directory
      ansible.builtin.file:
        path: /home/automation/reporting
        state: directory
        owner: automation
        group: automation
        mode: "0750"

    - name: Deploy the supplied report program
      ansible.builtin.copy:
        src: /home/labex/project/files/host-report.sh
        dest: /home/automation/reporting/host-report.sh
        owner: automation
        group: automation
        mode: "0750"

    - name: Keep the named report schedule present
      ansible.builtin.cron:
        name: ansible-host-report
        user: automation
        minute: "*"
        hour: "*"
        day: "*"
        month: "*"
        weekday: "*"
        job: "/home/automation/reporting/host-report.sh {{ report_phase }}"
YAML

検証し、適用します。

ansible-playbook reporting.yml --syntax-check
ansible-playbook reporting.yml

実際の automation の crontab を調べます。照会するアカウントを明示できるよう、コマンドは become 付きで実行します。

ansible all -b -m ansible.builtin.command -a 'crontab -u automation -l'

それぞれに 1 つの ansible-host-report マーカーと毎分実行のコマンド、そして変更されていない keep-existing-report エントリが含まれるはずです。crontab の行だけでは実行の証明にはなりません。

最初の自然なスケジューラー実行タイミングを待ちます。timeout は待機を 90 秒に制限し、bash の until ループは 2 秒ごとに空でないログを確認します。cron がログを作成する間、このコマンドは状態を読むだけです。

ansible all -m ansible.builtin.command -a "timeout 90 bash -c 'until test -s /home/automation/reporting/host-report.log; do sleep 2; done'"
ansible all -m ansible.builtin.command -a 'cat /home/automation/reporting/host-report.log'

それぞれに time= host=web1 phase=initial のような記録があり、web2 には対応する実際のホスト名があるはずです。タイムスタンプは変動し、自然な毎分のスケジューリングと一致するはずです。制限時間内の待機に失敗した場合は、自分で成功ログを書くのではなく、スケジュールと稼働デーモンを調べてください。

1 つの名前付きエントリを更新して新しいフェーズを観察する

このステップでは、安定した識別名と無関係のスケジュールを維持しながら、ジョブの入力を変えます。

保存されたフェーズ値を更新します。cron タスクは、同じ名前を維持しながら新しいコマンドを生成します。

cat > group_vars/all.yml <<'YAML'
report_phase: verified
YAML
ansible-playbook reporting.yml

両方の crontab をもう一度調べます。

ansible all -b -m ansible.builtin.command -a 'crontab -u automation -l'

各ホストには引き続き、正確に 1 つの ansible-host-report エントリがあり、今度は verified で終わるはずです。名前を再利用すると、2 つ目のスケジュールを蓄積せず、既存のエントリが更新されます。keep-existing-report は変更しないでください。

更新されたフェーズを使う、新しい自然な実行を待ちます。grep -q は、一致するログ記録を表示せずに確認し、timeout と until ループは待機を制限します。

ansible all -m ansible.builtin.command -a "timeout 90 bash -c 'until grep -q phase=verified /home/automation/reporting/host-report.log; do sleep 2; done'"
ansible all -m ansible.builtin.command -a 'cat /home/automation/reporting/host-report.log'

今度は両方に、実際のスケジューラーによる新しい phase=verified 記録が含まれるはずです。以前の initial 記録は有用な履歴なので、そのまま残してください。crontab コマンドを更新しても、古いログ行が遡って変わるわけではありません。

名前付きの一時ジョブだけを削除し、レポートを安定させる

このステップでは、安定した名前で一時スケジュールを削除し、意図した一般ユーザーのレポートが引き続き実行されることを検証します。

アドホックの cron タスクで、害のない名前付き一時エントリを作成します。真夜中に /usr/bin/true をスケジュールし、削除するための実際のエントリを用意します。

ansible all -b -m ansible.builtin.cron -a 'name=ansible-temporary-report user=automation minute=0 hour=0 job=/usr/bin/true'
ansible all -b -m ansible.builtin.command -a 'crontab -u automation -l'

小さなクリーンアップ用 Playbook を記述します。state absent と、一致する name/user は、その管理対象エントリだけを削除します。crontab 全体を空にしたり、置き換えたりしないでください。

cat > cleanup.yml <<'YAML'
- name: Remove only the obsolete named schedule
  hosts: all
  gather_facts: false
  become: true
  tasks:
    - name: Remove the obsolete report entry by its stable name
      ansible.builtin.cron:
        name: ansible-temporary-report
        user: automation
        state: absent
YAML
ansible-playbook cleanup.yml
ansible all -b -m ansible.builtin.command -a 'crontab -u automation -l'

一時マーカーとコマンドはなくなるはずです。フェーズ verified の ansible-host-report と keep-existing-report の両方が残る必要があります。

両方の宣言を繰り返します。

ansible-playbook reporting.yml
ansible-playbook cleanup.yml

両 Playbook が両ホストで changed=0、unreachable=0、failed=0 を報告するはずです。Cron は独立してログ記録を追記し続ける場合がありますが、こうした自然な実行時の記録によって、宣言的な配置が非冪等になるわけではありません。

最終チェックは、名前付きの一般ユーザージョブ、正確に配置されたプログラム、保護されたログを調べ、その後、両ホストでさらにもう 1 回の自然なスケジューラー実行タイミングを待ちます。約 1 分かかる場合があります。手動で準備した成功ファイルではなく、継続的な実行を観察できるよう、レポートのスケジュールとデーモンを動かしたままにしてください。

まとめ

意図した一般ユーザーの安定した名前付き cron エントリを管理し、実際の定期実行を観察して、ジョブを複製せずにコマンド入力を更新し、一時エントリだけを削除しました。明示的なプログラム・ログの権限と、無関係のスケジュールの維持により、範囲を明確に保ちました。レポートが自然に実行され続ける間も、配置の繰り返しには変更がありませんでした。