LFCS 종합 모의시험 시작 상태 준비
종합 모의 B에 필요한 기존 Git 변경, 확장용 LV, 실패 서비스, mock fstab, SSH key와 외부 fixture를 재현 가능하게 준비
이 문서는 시험 풀이가 아니라 종합 모의 B의 시작 상태를 만드는 절차다. 운영 host에서 실행하지 않는다.
/dev/sdc를 LVM PV로 초기화하고 작은 loopback filesystem을 의도적으로 가득 채우므로 snapshot과 console이 있는 폐기 가능한 VM에서만 수행한다.
작성·검증 상태: AI가 fixture 설계와 초안 작성을 보조했다. destructive target과 dependency를 정적으로 검토했지만, 전체 절차를 깨끗한 동일 2노드 VM에서 end-to-end 실행한 상태는 아니다. 각 절의 검증이 실패하면 snapshot을 만들지 않는다.
1. 이 문서가 준비하는 것
| 모의 task | 시작 상태 |
|---|---|
| Git | 세 파일이 수정된 기존 repository |
| custom service | foreground executable만 존재하고 unit은 없음 |
| disk-space 진단 | OS filesystem과 분리된 작은 loopback filesystem만 100% 사용 |
| LVM 확장 | /dev/sdc 위 basevg/applv, ext4 1 GiB, VG free space |
| SSH | node2의 private key와 node1에 제공된 public key file |
| failed service | 잘못된 output path 때문에 실패한 reporter.service |
| fstab recovery | 실제 /etc/fstab과 분리된 /etc/fstab.mock의 잘못된 UUID |
| libvirt·container | 정의 전 XML과 cached container image |
DNS·NTP·NFS·iSCSI·HTTP backend와 downstream namespace는 2노드 실습 서비스 준비에서 만든다. LDAP provider와 추가 bridge·bond NIC는 외부 prerequisite로 남긴다.
2. 시작 전 중단 조건
node1에서 다음을 확인한다.
hostnamectl --static
lsblk -o NAME,PATH,SIZE,TYPE,FSTYPE,MOUNTPOINTS
findmnt
pvs
vgs
lvs
ip -brief address
systemctl --failed
다음 중 하나라도 참이면 작업을 중단한다.
/dev/sdb또는/dev/sdc가 OS·home·swap·기존 data에 사용 중이다.- device 이름을 hypervisor의 추가 disk와 대응시키지 못했다.
- node1 console 또는 snapshot 복원 경로가 없다.
basevg,examvg,web01,mockweb같은 이름이 이미 다른 목적으로 존재한다.- management NIC와 private lab NIC를 구분하지 못했다.
읽기 전용 signature 확인:
wipefs -n /dev/sdb
wipefs -n /dev/sdc
findmnt -rn -S /dev/sdb
findmnt -rn -S /dev/sdc
pvs --noheadings -o pv_name
이 문서는 /dev/sdb를 모의 응시자가 초기화할 빈 disk로 보존하고, 확인된 빈 /dev/sdc만 fixture 준비에 사용한다.
3. package와 공통 directory
dnf install -y git lvm2 e2fsprogs util-linux lsof sysstat \
openssh-clients policycoreutils-python-utils
install -d -m 0755 /var/lib/lfcs-fixtures
install -d -m 0755 /usr/local/libexec
4. 기존 Git repository
문제 시작 시 세 파일 모두 수정됐지만 commit되지 않은 상태를 만든다.
(
set -eu
test ! -e /srv/config-repo
install -d -m 0755 /srv/config-repo
cd /srv/config-repo
git init
git config user.name 'LFCS Lab'
git config user.email 'lfcs-lab@example.invalid'
printf 'mode=production\n' > app.conf
printf '# Application configuration\n' > README.md
printf 'initial log\n' > debug.log
git add app.conf README.md debug.log
git commit -m 'Initial configuration'
printf 'mode=staging\n' > app.conf
printf '\nUse the staging profile.\n' >> README.md
printf 'debug=true\n' >> debug.log
git status --short
git diff -- app.conf README.md debug.log
)
완료 상태는 세 파일이 modified이고 staging area는 비어 있는 것이다.
5. custom service executable
unit은 만들지 않고 executable만 제공한다.
(
set -eu
test ! -e /usr/local/libexec/heartbeat
cat > /usr/local/libexec/heartbeat <<'EOF'
#!/usr/bin/bash
set -eu
while :; do
date -Is
sleep 5
done
EOF
chown root:root /usr/local/libexec/heartbeat
chmod 0755 /usr/local/libexec/heartbeat
timeout 1 /usr/local/libexec/heartbeat || test "$?" -eq 124
test ! -e /etc/systemd/system/heartbeat.service
)
timeout 종료 코드 124는 foreground process가 제한시간까지 실행됐다는 fixture 점검 결과다.
6. 확장용 LVM과 ext4 filesystem
이 절부터 /dev/sdc의 기존 signature와 data는 사라질 수 있다. 위의 중단 조건과 device 확인을 다시 수행한 뒤 진행한다.
(
set -eu
lsblk -f /dev/sdc
wipefs -n /dev/sdc
if findmnt -rn -S /dev/sdc; then
printf 'STOP: /dev/sdc is mounted\n' >&2
exit 1
fi
if pvs --noheadings -o pv_name | grep -F '/dev/sdc'; then
printf 'STOP: /dev/sdc is already an LVM PV\n' >&2
exit 1
fi
if grep -Eq '^[^#]+[[:space:]]+/srv/appdata[[:space:]]' /etc/fstab; then
printf 'STOP: /etc/fstab already contains /srv/appdata\n' >&2
exit 1
fi
pvcreate /dev/sdc
vgcreate basevg /dev/sdc
lvcreate -L 1G -n applv basevg
mkfs.ext4 /dev/basevg/applv
install -d -m 0755 /srv/appdata
app_uuid=$(blkid -s UUID -o value /dev/basevg/applv)
printf 'UUID=%s /srv/appdata ext4 defaults 0 2\n' "$app_uuid" >> /etc/fstab
findmnt --verify
mount /srv/appdata
printf 'preserve this data\n' > /srv/appdata/preserve.txt
sha256sum /srv/appdata/preserve.txt > /root/appdata.fixture.sha256
pvs
vgs
lvs -o lv_name,vg_name,lv_size,devices
df -hT /srv/appdata
vgs basevg -o vg_size,vg_free
)
위 명령은 확인된 빈 lab disk에서만 실행한다. 괄호 안의 subshell은 중간 검증이 실패하면 남은 명령을 중단하지만 현재 root shell 자체는 종료하지 않는다.
basevg에 최소 512 MiB보다 넉넉한 free extent가 남아 있어야 한다. /etc/fstab에 같은 UUID나 mount point의 기존 entry가 있었다면 중복을 고치지 말고 snapshot으로 복원해 원인을 확인한다.
7. 실제 fstab과 분리된 잘못된 mock table
/etc/fstab.mock만 고치는 복구 문제를 위해 존재하지 않는 UUID를 넣는다.
(
set -eu
test ! -e /etc/fstab.mock
cat > /etc/fstab.mock <<'EOF'
UUID=00000000-0000-0000-0000-000000000000 /mnt/recovery ext4 defaults 0 2
EOF
chown root:root /etc/fstab.mock
chmod 0644 /etc/fstab.mock
install -d -m 0755 /mnt/recovery
grep -F '00000000-0000-0000-0000-000000000000' /etc/fstab.mock
blkid /dev/basevg/applv
)
mock table을 준비하는 단계에서는 mount -a -T /etc/fstab.mock을 실행하지 않는다.
8. 안전하게 격리한 ENOSPC failure
OS filesystem을 채우지 않고 48 MiB image 안의 ext4만 가득 채운다.
(
set -eu
test ! -e /var/lib/lfcs-fixtures/logwriter.img
test ! -e /usr/local/libexec/logwriter
test ! -e /etc/systemd/system/logwriter.service
if findmnt -rn /srv/mock-enospc; then
printf 'STOP: /srv/mock-enospc is already mounted\n' >&2
exit 1
fi
truncate -s 48M /var/lib/lfcs-fixtures/logwriter.img
mkfs.ext4 -F /var/lib/lfcs-fixtures/logwriter.img
install -d -m 0755 /srv/mock-enospc
mount -o loop /var/lib/lfcs-fixtures/logwriter.img /srv/mock-enospc
printf 'existing log\n' > /srv/mock-enospc/logwriter.log
dd if=/dev/zero of=/srv/mock-enospc/fill.bin bs=1M status=none || true
df -hT /srv/mock-enospc
df -i /srv/mock-enospc
)
subshell 안의 preflight가 실패하면 image 생성까지 진행하지 않는다.
진단 대상 service:
cat > /usr/local/libexec/logwriter <<'EOF'
#!/usr/bin/bash
set -eu
printf '%s fixture log\n' "$(date -Is)" >> /srv/mock-enospc/logwriter.log
EOF
chmod 0755 /usr/local/libexec/logwriter
cat > /etc/systemd/system/logwriter.service <<'EOF'
[Unit]
Description=LFCS isolated ENOSPC fixture
[Service]
Type=oneshot
ExecStart=/usr/local/libexec/logwriter
EOF
systemd-analyze verify /etc/systemd/system/logwriter.service
systemctl daemon-reload
systemctl start logwriter.service || true
systemctl is-failed logwriter.service
journalctl -u logwriter.service -b -n 20 --no-pager
findmnt -T /srv/mock-enospc/logwriter.log
실패가 No space left on device이고 root filesystem에는 여유가 있어야 한다. inode가 남아 있는지는 df -i로 구분한다. 이 fixture를 수동 정리할 때는 service를 stop한 뒤 /srv/mock-enospc를 unmount하고 image를 제거한다. OS filesystem 전체를 채우거나 /var/log를 삭제하지 않는다.
9. 잘못된 output path의 failed service
(
set -eu
test ! -e /etc/reporter.conf
test ! -e /usr/local/libexec/reporter
test ! -e /etc/systemd/system/reporter.service
test ! -e /srv/reporter-output
install -d -m 0755 /srv/reporter-output
cat > /etc/reporter.conf <<'EOF'
OUTPUT=/srv/reporter-output/missing/summary.txt
EOF
cat > /usr/local/libexec/reporter <<'EOF'
#!/usr/bin/bash
set -eu
. /etc/reporter.conf
printf '%s report\n' "$(date -Is)" >> "$OUTPUT"
EOF
chmod 0755 /usr/local/libexec/reporter
cat > /etc/systemd/system/reporter.service <<'EOF'
[Unit]
Description=LFCS reporter path fixture
[Service]
Type=oneshot
ExecStart=/usr/local/libexec/reporter
EOF
systemd-analyze verify /etc/systemd/system/reporter.service
systemctl daemon-reload
systemctl start reporter.service || true
systemctl is-failed reporter.service
journalctl -u reporter.service -b -n 20 --no-pager
)
/srv/reporter-output은 존재하지만 설정에 적힌 하위 directory는 존재하지 않아야 한다. 모의 응시자는 unit이나 executable이 아니라 /etc/reporter.conf의 output path 한 곳만 수정한다.
10. SSH key fixture
node2에서 password 없는 lab 전용 key pair를 만든다. 기존 key를 덮어쓰지 않는다.
(
set -eu
test ! -e /root/mock-builder-ed25519
test ! -e /root/mock-builder-ed25519.pub
ssh-keygen -q -t ed25519 -N '' -f /root/mock-builder-ed25519
ssh-keygen -lf /root/mock-builder-ed25519.pub
)
public key만 node1의 /root/builder_authorized_key.pub로 전달한다. private key는 node2 밖으로 복사하지 않는다. 관리용 SSH나 승인된 host-side copy 방법을 사용한 뒤 node1에서:
test -s /root/builder_authorized_key.pub
ssh-keygen -lf /root/builder_authorized_key.pub
chmod 0600 /root/builder_authorized_key.pub
두 fingerprint가 같아야 한다. 모의 task가 끝난 뒤 node2에서 다음 형태로 positive test를 수행할 수 있어야 한다.
ssh -i /root/mock-builder-ed25519 builder@192.168.56.11 id
11. 외부 fixture 완료 확인
node1에서:
getent hosts app.lab.example
chronyc sources -v
curl --fail http://192.168.56.12:8081/
curl --fail http://192.168.56.12:8082/
showmount -e 192.168.56.12
iscsiadm -m discovery -t sendtargets -p 192.168.56.12:3260
ip route get 192.168.56.12
systemctl is-enabled lfcs-dst-fixture.service
ip netns exec lfcs-dst ping -c 2 198.51.100.1
podman image exists docker.io/library/nginx:stable-alpine
virsh net-info default
virsh dominfo web01 >/dev/null 2>&1 && echo 'web01 is already defined: restore the pre-mock snapshot' || true
test -s /root/web01.xml
LDAP client task는 provider가 실제로 준비된 경우에만 포함한다. node1에서 TLS와 directory search가 먼저 성공해야 한다.
openssl s_client -connect ldap.lab.example:636 \
-servername ldap.lab.example \
-verify_hostname ldap.lab.example \
-verify_return_error \
-CAfile /etc/openldap/certs/lab-ca.pem </dev/null
LDAPTLS_CACERT=/etc/openldap/certs/lab-ca.pem \
ldapsearch -x -H ldaps://ldap.lab.example \
-b dc=lab,dc=example '(uid=alice)' dn uid uidNumber gidNumber
bridge·bond task에는 management NIC와 별개인 미사용 NIC 세 개가 필요하다. nmcli device status와 MAC address로 대상을 기록한다. dummy interface만 준비한 상태는 실제 carrier failover 준비 완료로 세지 않는다.
12. 최종 시작 상태 점검
# 비어 있어야 하는 응시자용 disk
lsblk -f /dev/sdb
wipefs -n /dev/sdb
# 제공된 확장 대상
lvs basevg/applv
vgs basevg -o vg_free
findmnt /srv/appdata
sha256sum -c /root/appdata.fixture.sha256
# 제공된 오류와 변경 상태
git -C /srv/config-repo status --short
systemctl is-failed logwriter.service
systemctl is-failed reporter.service
grep -F '00000000-0000-0000-0000-000000000000' /etc/fstab.mock
# task에서 아직 만들면 안 되는 객체
test ! -e /etc/systemd/system/heartbeat.service
getent passwd builder && echo 'builder already exists: restore snapshot' || true
vgs examvg && echo 'examvg already exists: restore snapshot' || true
podman container exists mockweb && echo 'mockweb already exists: restore snapshot' || true
모든 조건이 맞으면 VM을 정상 종료하고 30-mock-b-start snapshot을 만든다. 모의시험을 다시 볼 때는 답을 수동으로 되돌리지 말고 이 snapshot으로 복원한다.
13. fixture 초기화 원칙
권장 초기화는 20-fixtures-ready snapshot 복원이다. 수동 정리가 필요하다면 먼저 mount·loop·LVM dependency를 출력하고 이 문서가 만든 객체만 역순으로 제거한다. 다음처럼 범위가 넓은 명령은 사용하지 않는다.
wipefs -a <확인하지 않은 disk>
vgremove --select ...
rm -rf /srv
nft flush ruleset
podman system reset