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 serviceforeground executable만 존재하고 unit은 없음
disk-space 진단OS filesystem과 분리된 작은 loopback filesystem만 100% 사용
LVM 확장/dev/sdc 위 basevg/applv, ext4 1 GiB, VG free space
SSHnode2의 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

참고 자료