Red Hat Certified Engineer (RHCE) #16 RHCSA 自動化 3: ストレージ (LVM)、ファイルシステム (NFS)
#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 + mount | ansible.posix.mount |
ここで核心は モジュールごとに冪等性が保証される方式が違う という点です。lvg と filesystem はすでに存在すればそのまま通り過ぎますが、parted と lvol はオプションを誤って与えると毎回 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 に設定することもあります。
- 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 作成を一度に処理します。
- name: VG 作成
community.general.lvg:
vg: data_vg
pvs: /dev/vdb1
state: presentVG がすでに存在し、同じ PV で構成されていれば changed が発生しません。複数の PV を束ねるにはリストで渡します。
- name: 複数の PV で VG 作成
community.general.lvg:
vg: data_vg
pvs:
- /dev/vdb1
- /dev/vdc1lvol: LV を作る #
community.general.lvol は VG から LV を切り出します。size でサイズを指定し、絶対サイズ (2g、500m) と相対比率 (50%VG、100%FREE) のどちらも受け取ります。
- name: LV 作成
community.general.lvol:
vg: data_vg
lv: data_lv
size: 1g
state: presentlvol で冪等性が最も壊れやすい箇所が サイズ変更 です。すでに作られた LV に違う size を与えると、モジュールがサイズを縮小しようとすることがあり、縮小はデータ損失につながります。これを防ぐオプションが 2 つあります。
shrink: false。縮小動作を防ぎ、誤って LV が小さくなるのを防止します。resizefs: true。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) を指定します。
- 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 | 動作 |
|---|---|
mounted | fstab に登録して今すぐマウント |
present | fstab にのみ登録 (今はマウントしない) |
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: mountedsrc はデバイスパスの代わりに UUID=... や LABEL=... で与えることもできます。デバイス名が変わっても安全にマウントするには、UUID を使う方が堅牢です。
swap の追加 #
swap も同じモジュールの組み合わせで扱います。filesystem で fstype: swap として swap シグネチャを作り、mount モジュールで fstab に登録します。swap はディレクトリにマウントするものではないので、path: none、fstype: swap、state: present で 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: presentstate: present で fstab に登録してから、実際の有効化は command: swapon -a で補完するか、swap を扱う storage role に任せる方式を使います。
NFS リモートマウント #
NFS マウントも同じ ansible.posix.mount モジュールで処理します。ローカルファイルシステムと違う点は、fstype: nfs であり src が サーバー:エクスポートしたパス 形式だということだけです。
- 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 を置くのが安全です。
- name: NFS クライアントパッケージインストール
ansible.builtin.dnf:
name: nfs-utils
state: present全体 LVM プレイブック例 #
ここまでの task を一つの流れに束ねると次のようになります。試験で「ディスクで VG/LV を作って xfs でフォーマットし /data に永続マウントせよ」というタイプの標準解答です。
---
- 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・ファイルシステム・マウントを変数一つで宣言します。
---
- 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: /datastorage_pools にディスクとボリュームを宣言すると、ロールが内部で VG/LV 作成、フォーマット、fstab 登録、マウントをすべて処理します。swap も同じ構造で fs_type: swap として宣言できます。個別モジュールを直接組み合わせる方式と storage role のどちらを使っても試験では認められるので、手に馴染んだ方を使います。ただし問題文が特定のモジュールを指定するなら、そのモジュールを使うのが安全です。
試験ポイント #
mountモジュールのstate: mountedが fstab 登録と実際のマウントを一度に 処理します。永続マウント問題の標準解です。presentは fstab にのみ登録するので、今すぐのマウントが抜けます。partedとlvolは冪等性が壊れやすいです。partedは開始・終了位置を明示し、lvolはshrink: falseで縮小を防ぎます。- LV 拡張は
lvolにresizefs: trueを与えてファイルシステムまで一緒に大きくします。 - NFS は
ansible.posix.mountにfstype: nfsとサーバー:パス形式のsrc、opts: _netdevで処理し、前にnfs-utilsインストールを置きます。 - ストレージモジュールはほとんどが
community.generalcollection 所属で、mountはansible.posix所属です。FQCN と collection のインストール有無を確認します。
まとめ #
この記事で押さえたこと:
- ストレージ自動化の段階別モジュール。
parted(パーティション) →lvg(VG) →lvol(LV) →filesystem(フォーマット) →mount(fstab + マウント) lvolのshrink: falseとresizefs: trueによる縮小防止とファイルシステム同時拡張mountモジュールのstateの意味。mountedが永続マウントの正解- swap は
filesystemのfstype: swapとmountのpath: 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.selinux と community.general.sefcontext で自動化し、SSH 公開鍵の配布までプレイブックに束ねて整理します。