Red Hat Certified Engineer (RHCE) #16 RHCSA 自動化 3: ストレージ (LVM)、ファイルシステム (NFS)

読了 8分

#15 RHCSA 自動化 2: サービス、chronyd、log でサービスと時刻同期、ログをプレイブックで扱ったなら、今回は RHCSA で最も手のかかる領域である ストレージを Ansible で自動化 します。ディスクにパーティションを作り、LVM で VG と LV を構成し、ファイルシステムを載せてから永続マウントまでつなぐ一連の作業を、冪等性のある task として解きほぐすのが目標です。

ストレージは RHCE 実技の定番の出題領域です。RHCSA で LVM シリーズNFS/autofs シリーズ で手で覚えた作業を、今回の記事では同じ結果を出すプレイブックに移します。

ストレージ自動化の全体像 #

手でやっていたストレージ作業を思い出すと、次の順序でした。ディスクにパーティションを作り (parted)、そのパーティションを PV として VG を作り (vgcreate)、VG から LV を切り出し (lvcreate)、LV をフォーマットし (mkfs)、マウントポイントを作ってから /etc/fstab に登録し、実際にマウントする流れでした。

Ansible はこの段階ごとに専用モジュールを用意します。

手作業Ansible モジュール
parted パーティションcommunity.general.parted
vgcreate (VG)community.general.lvg
lvcreate (LV)community.general.lvol
mkfs フォーマットcommunity.general.filesystem
/etc/fstab + mountansible.posix.mount

ここで核心は モジュールごとに冪等性が保証される方式が違う という点です。lvgfilesystem はすでに存在すればそのまま通り過ぎますが、partedlvol はオプションを誤って与えると毎回 changed として捕捉されたり、サイズを再び触ったりすることがあるので注意が必要です。

parted: パーティションを作る #

community.general.parted はディスクにパーティションテーブルとパーティションを作ります。冪等性のために number (パーティション番号) と開始・終了位置を明示するのが安全です。

パーティション作成
- name: ディスクにパーティションを 1 個作成
  community.general.parted:
    device: /dev/vdb
    number: 1
    state: present
    part_start: 1MiB
    part_end: 1024MiB

同じ number で同じ part_start/part_end を与えると、2 回目の実行では changed が発生しません。逆に終了位置を 100% のように相対値で与えると、環境によって毎回再計算されて冪等性が揺らぐことがあるので、明示的なサイズを推奨します。

LVM に使うパーティションなら、パーティションフラグを LVM に設定することもあります。

LVM 用パーティション作成
- name: LVM 用パーティション作成
  community.general.parted:
    device: /dev/vdb
    number: 1
    state: present
    part_start: 1MiB
    part_end: 2048MiB
    flags: [ lvm ]

ただし試験で提供されるディスクを丸ごと PV として使う場合なら、パーティションなしで /dev/vdb 自体を lvg に渡すこともできます。問題文が「パーティションを作って」と明示するなら parted を使い、そうでなければディスク全体を PV として使う方が単純です。

lvg: VG を作る #

community.general.lvg は PV を束ねて VG を作ります。pvs にディスクやパーティションを渡すと、PV 作成と VG 作成を一度に処理します。

VG 作成
- name: VG 作成
  community.general.lvg:
    vg: data_vg
    pvs: /dev/vdb1
    state: present

VG がすでに存在し、同じ PV で構成されていれば changed が発生しません。複数の PV を束ねるにはリストで渡します。

複数 PV で VG 作成
- name: 複数の PV で VG 作成
  community.general.lvg:
    vg: data_vg
    pvs:
      - /dev/vdb1
      - /dev/vdc1

lvol: LV を作る #

community.general.lvol は VG から LV を切り出します。size でサイズを指定し、絶対サイズ (2g500m) と相対比率 (50%VG100%FREE) のどちらも受け取ります。

LV 作成
- name: LV 作成
  community.general.lvol:
    vg: data_vg
    lv: data_lv
    size: 1g
    state: present

lvol で冪等性が最も壊れやすい箇所が サイズ変更 です。すでに作られた LV に違う size を与えると、モジュールがサイズを縮小しようとすることがあり、縮小はデータ損失につながります。これを防ぐオプションが 2 つあります。

  • shrink: false。縮小動作を防ぎ、誤って LV が小さくなるのを防止します。
  • resizefs: true。LV サイズを変えるとき、その上のファイルシステムも一緒に大きくして整合性を合わせます。
LV サイズの安全な管理
- name: LV サイズを安全に管理
  community.general.lvol:
    vg: data_vg
    lv: data_lv
    size: 2g
    shrink: false
    resizefs: true

試験で「LV を N ギガで作れ」は一度作れば終わりですが、「既存の LV を拡張せよ」が出たら、resizefs: true でファイルシステムまで一緒に大きくするパターンを思い出します。

filesystem: フォーマット #

community.general.filesystem は LV やパーティションにファイルシステムを載せます。fstype と対象デバイス (dev) を指定します。

xfs フォーマット
- name: LV を xfs でフォーマット
  community.general.filesystem:
    fstype: xfs
    dev: /dev/data_vg/data_lv

すでに該当ファイルシステムがあれば changed が発生しません。強制的に作り直すには force: true を与えられますが、既存データを消すので試験ではほとんど使いません。対象デバイスパスは /dev/<vg>/<lv> または /dev/mapper/<vg>-<lv> 形式のどちらも動作します。

mount: fstab 登録と実際のマウント #

ansible.posix.mount/etc/fstab の項目と実際のマウントを一緒に扱います。核心は state 値です。

state動作
mountedfstab に登録して今すぐマウント
presentfstab にのみ登録 (今はマウントしない)
unmounted今アンマウント (fstab 項目は維持)
absentアンマウントして fstab 項目も削除

永続マウントが目標なら、ほぼ常に state: mounted です。fstab 登録と実際のマウントを一度にしてくれるので、再起動後も生き残りながら今すぐも使えます。

マウントポイント作成と永続マウント
- name: マウントポイントディレクトリ作成
  ansible.builtin.file:
    path: /data
    state: directory
    mode: '0755'

- name: LV を永続マウント
  ansible.posix.mount:
    path: /data
    src: /dev/data_vg/data_lv
    fstype: xfs
    state: mounted

src はデバイスパスの代わりに UUID=...LABEL=... で与えることもできます。デバイス名が変わっても安全にマウントするには、UUID を使う方が堅牢です。

swap の追加 #

swap も同じモジュールの組み合わせで扱います。filesystemfstype: swap として swap シグネチャを作り、mount モジュールで fstab に登録します。swap はディレクトリにマウントするものではないので、path: nonefstype: swapstate: present で fstab にのみ登録してから有効化するのが一般的です。

swap フォーマットと fstab 登録
- name: swap LV をフォーマット
  community.general.filesystem:
    fstype: swap
    dev: /dev/data_vg/swap_lv

- name: swap を fstab に登録して有効化
  ansible.posix.mount:
    path: none
    src: /dev/data_vg/swap_lv
    fstype: swap
    opts: sw
    state: present

state: present で fstab に登録してから、実際の有効化は command: swapon -a で補完するか、swap を扱う storage role に任せる方式を使います。

NFS リモートマウント #

NFS マウントも同じ ansible.posix.mount モジュールで処理します。ローカルファイルシステムと違う点は、fstype: nfs であり srcサーバー:エクスポートしたパス 形式だということだけです。

NFS 永続マウント
- name: NFS export を永続マウント
  ansible.posix.mount:
    path: /mnt/share
    src: nfs-server.example.com:/exports/share
    fstype: nfs
    opts: defaults,_netdev
    state: mounted

ネットワークが上がった後にマウントされるよう、opts_netdev を入れる習慣をつけます。NFS クライアントパッケージ (nfs-utils) がないとマウントが失敗するので、その前にパッケージインストール task を置くのが安全です。

nfs-utils インストール
- name: NFS クライアントパッケージインストール
  ansible.builtin.dnf:
    name: nfs-utils
    state: present

全体 LVM プレイブック例 #

ここまでの task を一つの流れに束ねると次のようになります。試験で「ディスクで VG/LV を作って xfs でフォーマットし /data に永続マウントせよ」というタイプの標準解答です。

LVM 全体プレイブック
---
- name: LVM ストレージ構成
  hosts: storage
  become: true
  tasks:
    - name: VG 作成
      community.general.lvg:
        vg: data_vg
        pvs: /dev/vdb

    - name: LV 作成
      community.general.lvol:
        vg: data_vg
        lv: data_lv
        size: 1g
        shrink: false

    - name: ファイルシステム作成
      community.general.filesystem:
        fstype: xfs
        dev: /dev/data_vg/data_lv

    - name: マウントポイント作成
      ansible.builtin.file:
        path: /data
        state: directory
        mode: '0755'

    - name: 永続マウント
      ansible.posix.mount:
        path: /data
        src: /dev/data_vg/data_lv
        fstype: xfs
        state: mounted

このプレイブックを 2 回回して、2 回目の実行で changed が 0 になるか必ず確認します。lvg/lvol/filesystem/mount はすべて冪等性をサポートするので、きちんと書いていれば再実行時にすべての task が ok として捕捉されます。

storage system role の代替 #

上の作業を一度に束ねてくれる公式ロールが rhel-system-roles の storage role です。#13 system roles で扱った system role 系で、PV・VG・LV・ファイルシステム・マウントを変数一つで宣言します。

storage role プレイブック
---
- name: storage role でストレージ構成
  hosts: storage
  become: true
  roles:
    - rhel-system-roles.storage
  vars:
    storage_pools:
      - name: data_vg
        disks:
          - vdb
        volumes:
          - name: data_lv
            size: 1g
            fs_type: xfs
            mount_point: /data

storage_pools にディスクとボリュームを宣言すると、ロールが内部で VG/LV 作成、フォーマット、fstab 登録、マウントをすべて処理します。swap も同じ構造で fs_type: swap として宣言できます。個別モジュールを直接組み合わせる方式と storage role のどちらを使っても試験では認められるので、手に馴染んだ方を使います。ただし問題文が特定のモジュールを指定するなら、そのモジュールを使うのが安全です。

試験ポイント #

  • mount モジュールの state: mounted が fstab 登録と実際のマウントを一度に 処理します。永続マウント問題の標準解です。present は fstab にのみ登録するので、今すぐのマウントが抜けます。
  • partedlvol は冪等性が壊れやすいです。parted は開始・終了位置を明示し、lvolshrink: false で縮小を防ぎます。
  • LV 拡張は lvolresizefs: true を与えてファイルシステムまで一緒に大きくします。
  • NFS は ansible.posix.mountfstype: nfsサーバー:パス 形式の srcopts: _netdev で処理し、前に nfs-utils インストールを置きます。
  • ストレージモジュールはほとんどが community.general collection 所属で、mountansible.posix 所属です。FQCN と collection のインストール有無を確認します。

まとめ #

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

  • ストレージ自動化の段階別モジュール。parted (パーティション) → lvg (VG) → lvol (LV) → filesystem (フォーマット) → mount (fstab + マウント)
  • lvolshrink: falseresizefs: true による縮小防止とファイルシステム同時拡張
  • mount モジュールの state の意味。mounted が永続マウントの正解
  • swap は filesystemfstype: swapmountpath: none で処理
  • NFS リモートマウントは fstype: nfs_netdev オプション、nfs-utils インストール
  • 個別モジュール組み合わせの代替として rhel-system-roles の storage role

次へ: RHCSA 自動化 4 #

ストレージまで自動化しました。RHCSA 自動化の最後のピースはセキュリティ領域です。

#17 RHCSA 自動化 4: firewall、SELinux、SSH キー では firewalld を ansible.posix.firewalld で扱い、SELinux モードとブール値・ポートラベルを ansible.posix.selinuxcommunity.general.sefcontext で自動化し、SSH 公開鍵の配布までプレイブックに束ねて整理します。

X