Red Hat Certified Engineer (RHCE) #15 RHCSA 自動化 2: サービス、chronyd、log

読了 8分

#14 RHCSA 自動化 1 でユーザー・グループとパッケージ・repository を playbook で押さえました。今回の #15 では、RHCSA の手作業の 2 つ目の塊である サービス管理、時刻同期、ログ設定 を自動化します。いずれも RHCSA #9 サービスとブートsystemctlchronycjournalctl で手作業で扱った作業であり、今回は同じ結果を冪等なモジュールで宣言します。

この領域の採点ポイントはいつも変わりません。サービスは起動する (start) だけで終わらず、ブート時にも起動する (enable) 必要があります。 時刻同期は設定ファイルを変えた後にデーモンを上げ直す必要があり、ログは再起動後にも残るように永続設定する必要があります。つまり「今動く」と「再起動後にも動く」を同時に保証することが自動化の核心です。

サービス管理: service と systemd モジュール #

デーモンを起動・停止・ブート登録する作業は ansible.builtin.service または ansible.builtin.systemd_service モジュールで行います。手で打っていた systemctl startsystemctl enable を 1 つの task にまとめて宣言します。

service モジュールの 3 つの核心キー #

キー意味値の例
name対象サービス名httpd、chronyd
state現在の動作状態started、stopped、restarted、reloaded
enabledブート時の自動起動可否true、false

ここで最もよく見落とすのが state と enabled を一緒に指定する ことです。state: started だけ書くと今は起動しますが再起動後は止まっていることがあり、enabled: true だけ書くとブート登録はされますが今は停止しています。試験では両方を要求する場合がほとんどなので、2 つのキーを一緒に書く習慣をつけます。

httpd enable + start プレイブック
- name: 웹 서버를 지금도 켜고 부팅에도 등록한다
  hosts: webservers
  become: true
  tasks:
    - name: httpd 패키지 설치
      ansible.builtin.dnf:
        name: httpd
        state: present

    - name: httpd 서비스 enable + start
      ansible.builtin.service:
        name: httpd
        state: started
        enabled: true

service と systemd_service の違い #

service モジュールは init システムを自動検出する汎用モジュールで、systemd_service モジュールは systemd 専用で daemon_reload や masked のような systemd 固有の機能を追加で提供します。RHEL 9 は systemd を使うので両方とも動作しますが、unit ファイルを直接配置した後に読み直す必要があるときは systemd モジュールが有利です。

unit 変更後の daemon_reload
- name: 사용자 정의 unit 배치 후 데몬 리로드
  ansible.builtin.systemd_service:
    name: myapp
    state: started
    enabled: true
    daemon_reload: true

daemon_reload: truesystemctl daemon-reload に対応し、/etc/systemd/system に unit ファイルを新しく置いたり直したりした直後に systemd が変更を認識するようにします。

時刻同期: timesync system role と chrony テンプレート #

時刻同期は RHCE の定番テーマです。RHEL 9 の NTP 実装は chrony であり、デーモン名は chronyd です。自動化の方法は 2 通りあります。timesync system role を使う道chrony.conf を直接テンプレートで配布する道 です。

方法 1: timesync system role #

#13 system roles で扱った rhel-system-roles を使うと、NTP サーバーの一覧だけを変数で渡し、残りは role に任せます。最も短く安全な道です。

timesync role プレイブック
- name: timesync system role로 NTP 구성
  hosts: all
  become: true
  vars:
    timesync_ntp_servers:
      - hostname: 0.kr.pool.ntp.org
        iburst: true
      - hostname: 1.kr.pool.ntp.org
        iburst: true
  roles:
    - redhat.rhel_system_roles.timesync

role が chrony のインストールと設定ファイルの作成、サービスの enable と start まで一度に処理するので、試験で「この NTP サーバーを使うように時刻同期を構成せよ」という問題に最も速く対応できます。

方法 2: chrony.conf テンプレート + handler #

system role を使わずに設定ファイルを直接扱うこともできます。template モジュールで chrony.conf を配布し、ファイルが変わったときだけ handler で chronyd を再起動する構造です。このパターンはすべての「設定ファイル変更後にサービス再起動」問題の標準形なので、必ず身につけます。

templates/chrony.conf.j2:

templates/chrony.conf.j2
# Ansible managed
{% for server in chrony_servers %}
server {{ server }} iburst
{% endfor %}

driftfile /var/lib/chrony/drift
makestep 1.0 3
rtcsync
logdir /var/log/chrony

playbook:

chrony.conf 配布プレイブック
- name: chrony.conf 템플릿으로 시간 동기화 구성
  hosts: all
  become: true
  vars:
    chrony_servers:
      - 0.kr.pool.ntp.org
      - 1.kr.pool.ntp.org
  tasks:
    - name: chrony 패키지 설치
      ansible.builtin.dnf:
        name: chrony
        state: present

    - name: chrony.conf 배포
      ansible.builtin.template:
        src: chrony.conf.j2
        dest: /etc/chrony.conf
        owner: root
        group: root
        mode: '0644'
      notify: restart chronyd

    - name: chronyd enable + start
      ansible.builtin.service:
        name: chronyd
        state: started
        enabled: true

  handlers:
    - name: restart chronyd
      ansible.builtin.service:
        name: chronyd
        state: restarted

ここで流れが重要です。template task がファイルを変えると notify で handler が予約され、playbook のすべての task が終わった後に handler が一度実行されて chronyd を再起動します。ファイルが変わらなければ handler は呼ばれないので、2 回目の実行では再起動が起きず冪等性が保たれます。

ジョブ予約: cron と at モジュール #

定期ジョブは ansible.builtin.cron モジュールで管理します。crontab の項目を直接編集する代わりに、モジュールが項目を冪等に入れたり外したりしてくれます。

cron モジュールの主なキー #

キー意味
name項目を識別する名前。冪等性の基準
job実行するコマンド
minute / hour / day / month / weekday実行時刻。デフォルトは *
userどのユーザーの crontab か
statepresent または absent

name が冪等性の基準である点が核心です。cron モジュールは crontab に #Ansible: <name> のコメントを一緒に記録し、次の実行で同じ name に出会うと新しく追加せず既存の項目を更新します。したがって name を毎回変えると重複項目が積み上がるので、一定の name を維持します。

cron ジョブ登録
- name: 정기 백업 cron 작업 등록
  hosts: dbservers
  become: true
  tasks:
    - name: 매일 02:30 백업 스크립트 실행
      ansible.builtin.cron:
        name: nightly-backup
        user: root
        minute: "30"
        hour: "2"
        job: "/usr/local/bin/backup.sh"
        state: present

上の作業は root の crontab に 30 2 * * * /usr/local/bin/backup.sh の項目を冪等に登録します。指定しない day、month、weekday は自動的に * になります。

特定のディレクトリに落とす方式が必要なら、cron_file/etc/cron.d の下にファイルを作ることもできます。このときはシステム全体の crontab 形式なので user を一緒に指定します。

cron_file で /etc/cron.d に登録
- name: /etc/cron.d 파일로 등록
  ansible.builtin.cron:
    name: log-rotate-check
    user: root
    minute: "0"
    hour: "1"
    job: "/usr/local/bin/check-logs.sh"
    cron_file: custom-log-check

一回きりのジョブは ansible.builtin.at モジュールで予約します。例えば ansible.builtin.atcommandcountunits: minutes を与えると、指定時間後に一度だけ実行される at ジョブを登録します。

journald 永続保存の自動化 #

デフォルトの RHEL では journald のログは /run/log/journal のメモリ (揮発性) 領域に保存され、再起動すると消えます。ログを永続保存するには /etc/systemd/journald.confStorage=persistent に変えてデーモンを再起動する必要があります。この作業も template と handler パターンで自動化します。

templates/journald.conf.j2:

templates/journald.conf.j2
# Ansible managed
[Journal]
Storage=persistent
SystemMaxUse={{ journald_max_use | default('500M') }}

playbook:

journald 永続化プレイブック
- name: journald 로그 영구 저장 설정
  hosts: all
  become: true
  vars:
    journald_max_use: 1G
  tasks:
    - name: 영구 저장 디렉터리 생성
      ansible.builtin.file:
        path: /var/log/journal
        state: directory
        owner: root
        group: systemd-journal
        mode: '2755'

    - name: journald.conf 배포
      ansible.builtin.template:
        src: journald.conf.j2
        dest: /etc/systemd/journald.conf
        owner: root
        group: root
        mode: '0644'
      notify: restart journald

  handlers:
    - name: restart journald
      ansible.builtin.systemd_service:
        name: systemd-journald
        state: restarted

/var/log/journal ディレクトリがあって初めて journald がそこに永続ログを記録するので、file モジュールで先に作っておきます。設定ファイルが変わると handler が systemctl restart systemd-journald に対応する再起動を実行します。

tuned プロファイルの適用 #

パフォーマンスプロファイルを管理する tuned も自動化の対象です。tuned-adm を手で打つ代わりに、tuned system role または command モジュールでプロファイルを適用します。system role が最もすっきりしています。

tuned role プレイブック
- name: tuned 프로파일 적용
  hosts: dbservers
  become: true
  vars:
    tuned_profile: throughput-performance
  roles:
    - redhat.rhel_system_roles.tuned

system role を使わないなら、tuned サービスを enable と start で上げてから、tuned-adm profile <名前> を command で適用しつつ、すでに適用済みの場合に changed が出ないように changed_when 条件を整えます。

試験ポイント #

  • enabled と state はペア。サービス問題はほぼ常に「今起動して (state: started) ブートにも登録 (enabled: true)」を同時に要求します。片方だけ書くと採点の半分しか満たしません。
  • 設定変更は handler で再起動。chrony.conf や journald.conf のように設定ファイルを template で変えた後は、必ず notify と handler でデーモンを再起動します。task で毎回 restart を直接呼ぶと、ファイルが変わらなくても再起動されて冪等性が崩れます。
  • NTP は system role が速い。時刻同期の問題は timesync system role でサーバー一覧だけを渡すのが最も安全です。role が使えない状況に備えて chrony.conf テンプレート方式も一緒に身につけておきます。
  • cron は name で冪等性。cron モジュールの name が項目の識別子なので、同じ作業には同じ name を維持して重複登録を防ぎます。
  • journald 永続化はディレクトリから/var/log/journal の作成と Storage=persistent の設定、そして systemd-journald の再起動が 1 つの塊です。
  • 2 回回して changed 0 を確認。すべての playbook は 2 回目の実行で changed が 0 になる必要があります。handler が毎回回るか、command/shell が冪等性を崩していないかを点検します。

まとめ #

この記事で押さえたこと:

  • service / systemd_service モジュール。name・state・enabled で enable と start まで一度にデーモンを宣言。unit 変更時は daemon_reload
  • 時刻同期。timesync system role (サーバー一覧だけを変数で) または chrony.conf テンプレート + handler 再起動
  • cron / at モジュール。cron の name で冪等性、minute・hour・user・job・state で定期ジョブを登録。at で一回きりの予約
  • journald 永続保存/var/log/journal の作成 + journald.conf テンプレート + systemd-journald 再起動 handler
  • tuned。system role または command でパフォーマンスプロファイルを適用
  • 共通原則。設定変更は handler で、サービスは enabled と state を一緒に、そして 2 回回して冪等性を検証

次: RHCSA 自動化 3 #

サービスと時刻、ログを自動化しました。次は RHCSA で最も手のかかった領域であるストレージです。

#16 RHCSA 自動化 3: ストレージ (LVM)、ファイルシステム (NFS) では、lvg と lvol モジュールでボリュームグループと論理ボリュームを作り、filesystem と mount モジュールでファイルシステムを作成して永続マウントし、storage system role で一度に宣言する方法、そして NFS クライアントマウントまで playbook で整理します。

X