LFCS — 리눅스 재단 시스템 관리자 · 서비스와 네트워크를 실제로 — systemd·nginx·iptables·chrony·podman · 실습
systemd 타이머부터 podman 까지 — 서비스와 네트워크를 실제로 만든다
목표
systemd 서비스와 타이머, nginx 리버스 프록시, iptables DNAT/DROP, dummy 인터페이스 위의 브리지·본드와 netplan, chrony 와 시간대, git 병합, 레지스트리 없는 podman 이미지, 영구 sysctl, 부하 지표 — LFCS 의 Operations 와 Networking 도메인에서 파드가 막아 두었던 것을 우분투 24.04 VM 에서 실제로 실행합니다.
왜 중요한가
LFCS 는 "설명" 이 아니라 "결과" 를 봅니다. 유닛 파일을 잘 써도 systemctl is-enabled 가 disabled 면 0점이고, nginx 설정이 문법적으로 맞아도 기본 사이트가 80 을 잡고 있으면 프록시는 동작하지 않습니다. 이 실습의 채점기는 파일만 보지 않고 systemctl is-active, curl, iptables -S, /sys/class/net, sysctl -n, podman inspect 로 지금 시스템의 상태를 봅니다.
세 가지 원칙이 반복됩니다. 첫째, enable 과 start 는 다른 질문입니다(부팅 때 켤 것인가 / 지금 켜져 있는가). 둘째, 파일을 쓴 것과 커널·데몬이 아는 것은 다릅니다(sysctl --system, daemon-reload, nginx reload). 셋째, 되돌아갈 길을 남깁니다 — iptables 의 INPUT 기본 정책을 DROP 으로 바꾸거나 8899·22 를 막으면 채점 에이전트가 끊겨 다음 단계부터 원인 모를 실패가 납니다.
세션은 60분에 시작해 최대 180분까지 연장할 수 있고, VM 은 세션이 끝나면 사라집니다. 이 실습은 85분으로 잡혀 있으니 시작하면서 한 번 연장해 두세요.
단계
1. /usr/local/bin/lfcs-heartbeat.sh 가 현재 시각을 /var/log/lfcs-heartbeat.log 에 한 줄 덧붙이게 만들고, 이것을 Type=oneshot 인 lfcs-heartbeat.service 와 1분마다 그 서비스를 부르는 lfcs-heartbeat.timer 로 /etc/systemd/system/ 에 작성하세요. 타이머는 enable 과 start 둘 다 되어 있어야 하고, 서비스를 한 번 직접 시작해 로그에 최소 한 줄이 있어야 합니다.
2. /srv/backend/index.html 에 backend ok 라는 문구를 넣고, python3 -m http.server 8000 --directory /srv/backend 를 systemd 서비스 lfcs-backend.service 로 만들어 enable·start 하세요. 그런 다음 nginx 가 80 포트에서 이 백엔드로 리버스 프록시하도록 /etc/nginx/sites-available/lfcs-proxy 를 만들고 활성화(기본 사이트는 비활성화)하세요. curl http://127.0.0.1/ 이 backend ok 를 돌려줘야 합니다.
3. iptables 로 두 규칙을 넣으세요. (1) nat 테이블 PREROUTING 에서 tcp 8080 으로 들어온 것을 80 으로 보내는 DNAT(또는 REDIRECT). (2) filter 테이블 INPUT 에서 tcp 9999 를 모든 인터페이스에서 DROP. INPUT 의 기본 정책은 ACCEPT 그대로 두고 8899 와 22 는 건드리지 마세요(채점 에이전트와 SSH). 마지막으로 iptables-save 출력을 /root/lfcs/net/rules.v4 에 저장하세요.
4. 더미 인터페이스 dummy0, dummy1, dummy2 를 만드세요. 브리지 br0 에 dummy0 을 넣고 br0 에 192.0.2.1/24 를 주세요. 본드 bond0 을 active-backup 모드로 만들어 dummy1 과 dummy2 를 넣으세요(eth0 같은 실제 인터페이스는 건드리지 않습니다). 같은 구성을 netplan 문법으로 /root/lfcs/net/99-lab.yaml 에 적되 적용하지는 마세요.
5. /etc/chrony/chrony.conf 에 server time.cloudflare.com iburst 줄을 추가하고 chrony 를 재시작하세요. 시간대를 Asia/Seoul 로 바꾸세요. 그리고 chronyc sources 를 /root/lfcs/time/sources.txt 에, chronyc tracking 을 /root/lfcs/time/tracking.txt 에, timedatectl 을 /root/lfcs/time/timedatectl.txt 에 저장하세요. (이 VM 은 UDP 123 이 막혀 있어 동기화 자체는 안 될 수 있습니다 — 설정과 상태가 채점 대상입니다.)
6. /root/lfcs/repo 에 git 저장소를 만들고(기본 브랜치 main) README.md 를 커밋하세요. 브랜치 feature 에서 feature.txt 를 추가해 커밋한 뒤 main 으로 돌아와 병합 커밋이 남도록(--no-ff) 병합하세요. 작업 트리는 깨끗해야 합니다.
7. /bin/busybox(busybox-static) 하나만 담은 루트 파일시스템을 tar 로 묶어 podman import 로 localhost/lfcs-busybox:1 이미지를 만드세요(레지스트리에서 받지 않습니다). 그 이미지로 이름이 bb1 인 컨테이너를 --network none 으로 실행해 hello-from-busybox 를 출력하게 하고, 그 출력을 /root/lfcs/bb/run.txt 에 저장하세요. 컨테이너는 지우지 마세요(종료 코드가 0 이어야 합니다).
8. /etc/sysctl.d/90-lfcs.conf 에 net.ipv4.ip_forward = 1, vm.swappiness = 10, net.core.somaxconn = 1024 세 값을 적고 지금 커널에도 적용하세요. 적용 뒤 세 값을 sysctl 로 읽어 /root/lfcs/sysctl/runtime.txt 에 저장하세요.
9. uptime 출력을 /root/lfcs/perf/uptime.txt 에, top -bn1 의 앞 15줄을 /root/lfcs/perf/top.txt 에 저장하세요. 그리고 /root/lfcs/perf/load.txt 를 두 줄로 만드세요: NPROC=<이 VM 의 CPU 개수>, LOAD1=<1분 로드 평균(/proc/loadavg 첫 값)>.
참고
- 유닛을 쓰거나 고친 뒤에는
systemctl daemon-reload.systemctl list-timers --all로 타이머가 잡혔는지 봅니다. - nginx:
nginx -t→systemctl reload nginx.sites-enabled/default를 지우지 않으면default_server가 둘이 됩니다. - iptables:
iptables -t nat -S PREROUTING,iptables -S INPUT.-C로 규칙이 이미 있는지 물을 수 있습니다. - 본드 슬레이브는
ip link set dummy1 down뒤에master bond0. 모드 확인은cat /sys/class/net/bond0/bonding/mode. - 이 VM 은 밖으로 DNS 와 80/443 만 열려 있습니다.
chronyc sources의?는 정상이고, podman 은 레지스트리에서 받지 않습니다. - 흔한 실수 1: 타이머를
start만 하고enable을 빠뜨리는 경우 — 재부팅하면 사라집니다. - 흔한 실수 2:
lvextend처럼 sysctl 도 파일만 쓰고sysctl --system을 빼서 커널 값이 그대로인 경우. - 흔한 실수 3: 병합을 fast-forward 로 해서 병합 커밋이 없는 경우.
단계 9개
- 서비스 유닛과 타이머
- nginx 리버스 프록시
- iptables 로 DNAT 와 DROP
- dummy 위의 브리지와 본드, 그리고 netplan
- chrony 와 시간대
- git 기초 — 브랜치와 병합
- 레지스트리 없이 podman 이미지 만들고 실행
- 커널 파라미터를 영구로
- 부하 지표 남기기