운영을 잇다 02 — Rocky Linux 기반 자동화 인프라 구축
EdwardMoon
이 글에 자주 나오는 용어
- PROD·DEV·STG: 각각 운영·개발·검증 환경입니다.
- HA(고가용성): 일부 서버가 고장 나도 다른 서버가 역할을 이어받도록 구성하는 방식입니다. 실제 전환 시간과 남는 장애 지점은 별도로 확인합니다.
- Proxy·Bastion: Proxy는 모니터링 데이터를 모아 전달하는 중계 서버, Bastion은 관리자가 SSH로 접속할 때 거치는 경유 서버입니다.
- 인벤토리·Workflow·Job: 각각 자동화 대상 서버 목록, 여러 작업을 연결한 실행 흐름, 개별 실행 작업입니다. 뒤의 번호는 실행 기록을 찾는 식별 번호입니다.
- VIP·IPAM·쿼럼: VIP는 서비스 접속용 공용 가상 IP, IPAM은 IP 주소와 자산의 관계 관리, 쿼럼은 여러 노드가 과반수로 장애와 역할을 판단하는 기준입니다.
이 글은 VirtualBox의 네 내부망 위에 서버 설치·자산·자동화·관제를 연결한 실제 구축 절차다. 중앙 서비스는 fml-ops-01/02에 함께 배치하되 Compose와 K3s로 관리 단위를 나눴다. 각 단계에 온라인망과 폐쇄망 절차를 함께 적었다.
명령은 이 실습의 주소와 고정 버전을 기준으로 한다. 비밀번호·토큰·SSH 개인키는 예시나 Git에 포함하지 않는다. 구성 파일의 자리표시자는 자신의 비밀 저장소에서 주입한다. 실행한 범위와 실제 결과는 검증 글을 기준으로 확인한다.
이 글의 순서
- 재구축 실행편 — 처음부터 따라 하는 순서
- 1. 버전과 설치 순서
- 2. VM과 네트워크 준비
- 3. 라우팅·DNS·NTP·접근 경로
- 4. 컨테이너 런타임과 반입 묶음
- 5. PostgreSQL·etcd·Redis 구성
- 6. VIP·HTTPS와 NetBox 이중화
- 7. Zabbix LTS HA와 환경별 Proxy/Bastion
- 8. Git·K3s·AWX와 실행환경
- 9. PXE·Kickstart로 빈 서버 설치
- 10. 자산 API·인벤토리·관제 연결
- 11. 접속 정보와 간단한 운영 가이드
- 12. 백업·업데이트·검증으로 마무리
- 함께 읽기와 구성 자료
재구축 실행편 — VM 준비부터 API 연동까지
새 환경에서 필요한 입력 파일과 실행 위치를 먼저 정리했다. 기존 ZIP의 구성 기록에 VM 생성 도구, 새 비밀 생성기, 노드별 설정 묶음, NetBox 초기화와 온라인·폐쇄망 실행 순서를 보완했다. 설치할 때는 아래 순서를 먼저 읽고 뒤의 구성 원리와 검증 기록을 함께 확인한다.
새 환경 구축·운영 예제 지원 ZIP · 지원 ZIP 무결성 확인값
보완 자료의 구문과 구성 연결을 검수했다. 새 생성기로 VM 11대를 처음부터 재구축하는 전체 시험은 아직 수행하지 않았다. 아래에 제시한 단계별 성공 기준을 확인하고, 이전 실습의 검증 기록을 새 도구 전체 검증으로 바꾸어 표현하지 않는다.
실행 순서와 온라인·폐쇄망 차이
- VM·OS: Windows에서 관리 VM 8대를 생성하고 Rocky 최소 설치를 한다. 설치 메모리는 4GiB 이상이며 정상 종료 후 운영 할당량으로 줄인다. NIC·주소·관리 공개키를 설정한다.
- 내부 기반: Gateway 라우팅, Provision DNS/NTP/저장소, quorum NFS·새 CA를 만든다.
- 중앙 서비스: ops01에서 새 비밀과 노드별 tar를 한 번 생성해 배포한다. etcd → DB/Redis → VIP/HTTPS → NetBox/Zabbix 순서로 시작한다.
- 자동화: 환경별 Proxy/Bastion을 시작하고 새 PXE 대상을 한 대씩 설치한다. 콘솔에서 SSH host key를 승인한 뒤 Git·EE·K3s/AWX를 구성한다.
- 연동: NetBox 계정·토큰 → 카탈로그 → Zabbix Proxy/API → AWX 객체를 초기화한다. DEV 한 대를 limit으로 지정해 자산·관제·인벤토리 연결을 검증하고 설치 완료 controller를 켠다.
온라인망에서 구성 시: 관리 VM의 NAT를 설치 기간 사용한다. 외부 저장소의 RPM, Docker 이미지와 빌드 의존성을 받되 고정 버전과 digest를 기록한다. 대상 PXE VM에는 NAT를 붙이지 않는다.
폐쇄망에서 구성 시: 관리 VM도 NAT 없이 생성한다. 연결된 준비 VM에서 역할별 RPM·의존성, 이미지, K3s airgap 자료, Operator 소스, CA·승인 host key가 들어간 EE를 완성해 반입한다. 현장에서는 외부 repo와 pull/build/Galaxy 접속을 생략하고 반입 자료만 사용한다.
# ops01: 새 환경용 복사본 준비
sudo python3 /opt/fullmoon-lab/build-support/prepare-source.py \
--source /opt/fullmoon-lab/source-original --output /opt/fullmoon-lab/source
# 새 quorum CA와 관리 공개키를 준비한 후 설정 생성
sudo python3 /opt/fullmoon-lab/build-support/generate-config.py \
--source /opt/fullmoon-lab/source --output /opt/fullmoon-lab/build \
--admin-public-key /opt/fullmoon-lab/incoming/labadmin_ed25519.pub \
--ca-cert /opt/fullmoon-lab/incoming/ca.crt
완료 기준: etcd 과반수와 DB/Redis 역할, HTTPS 인증서, NetBox App/Worker, Zabbix HA·최신 Agent 값, AWX Git/인벤토리/Workflow를 확인한다. API 생성 응답만으로 완료 처리하지 않는다. 타이머는 실제 새 AWX 객체 ID와 승인 SSH 신원을 준비한 후 켠다.
전체 실행 절차 펼치기 — Windows VM 생성·파일 전달·설정·온라인/폐쇄망 명령
신규 환경 설치 순서 — 온라인망 / 폐쇄망
Windows 명령은 PowerShell, 게스트 명령은 해당 Rocky VM의 Bash 에서 실행한다. 실행 노드와 경로를 확인하고 각 단계의 판정 기준을 통과한 후 진행한다. 이번 보완 도구로 새 VM 11 대를 처음부터 재구축하는 전체 시험은 아직 수행하지 않았다. 이전 실습의 성공 기록은 신규 도구 검증과 구분한다.
0. 설치 재료와 작업 경로
공개 지원 ZIP을 풀면 config/, automation/, build-support/가 보인다. Rocky Minimal ISO, 공식 iPXE BIOS ISO, RPM, 컨테이너 이미지, K3s 바이너리는 별도로 준비한다. 공식 배포처의 체크섬과 서명을 확인한다. 다운로드 후 자체 생성한 체크섬은 공식 서명을 대신하지 않는다.
Windows의 예시 저장 경로는 C:\FullMoon-Rebuild다. 비밀 파일은 동기화되지 않는 private에 두고 개인키는 VM에 복사하지 않는다.
New-Item -ItemType Directory -Path 'C:\FullMoon-Rebuild\private' -Force
ssh-keygen -t ed25519 -f 'C:\FullMoon-Rebuild\private\labadmin_ed25519'
온라인망: 관리 VM 8 대는 설치 기간 NAT NIC를 사용한다. 폐쇄망: -Mode offline으로 만들면 NAT NIC와 loopback SSH 포워딩이 없다. 최초 설정은 VirtualBox 콘솔에서 하고 필요한 자료는 CD/ISO 등 승인된 경로로 반입한다. 외부 다운로드와 이미지 빌드는 연결된 준비 VM에서 끝낸다. 준비 VM은 같은 Rocky 10 x86_64를 사용한다.
1. 관리 VM 생성과 OS 설치
# Windows: 지원 ZIP을 푼 폴더
$nodes = @('fml-ops-01','fml-ops-02','fml-quorum-01','fml-gateway-01',
'fml-provision-01','fml-edge-prod-01','fml-edge-dev-01','fml-edge-stg-01')
foreach ($node in $nodes) {
.\build-support\New-LabVm.ps1 -Name $node `
-RockyIso 'C:\FullMoon-Rebuild\media\Rocky-10.2-x86_64-minimal.iso' `
-BaseFolder 'C:\FullMoon-Rebuild\machines' -Mode online `
-CpuProfile 'Intel Core i7-6700K' -WhatIf
}
# 계획 확인 후 -WhatIf를 빼고 실행. 폐쇄망은 -Mode offline.
관리 VM 생성기는 EFI64 펌웨어를 사용하고 PXE 대상 생성기는 BIOS를 사용한다. 위 Intel Core i7-6700K는 이 PC의 기존 실습에서 확인한 VirtualBox CPU 프로파일 설정값이며 실제 PC의 CPU 모델명이 아니다. 같은 PC에서 재구축할 때 이 값을 명시한다. 다른 PC에서는 아래 명령으로 사용 가능한 프로파일을 확인하고 Rocky 10에 필요한 x86-64-v3 기능이 게스트에 전달되는지 확인한 뒤 값을 선택한다.
# Windows: 읽기 전용 CPU 프로파일 목록 확인
& 'C:\Program Files\Oracle\VirtualBox\VBoxManage.exe' list cpu-profiles
생성기는 기존 VM과 디스크를 덮어쓰지 않고 중단하며 VM을 자동 시작하지 않는다. 동일한 이름의 기존 실습 VM이 있으면 별도 PC/환경에서 구축한다. OS 설치 중 관리 VM은 4GiB 이상을 사용한다. ops01은 운영 할당량이 7GiB 이므로 그대로 둔다. 설치 완료 후 정상 종료하고 VM 별 운영 메모리로 줄인다.
VirtualBox 콘솔에서 한 대씩 Rocky 최소 설치를 수행한다. 각 VM의 새 VDI를 선택하고 labadmin을 관리자 그룹으로 만든다. 콘솔용 암호는 SSH 공개키 접속 확인 후 관리 정책에 따라 제한한다. 개별 새 설치를 사용하므로 machine-id와 SSH host key를 공유하지 않는다.
| VM | 내부 NIC / 주소 | 온라인 관리 SSH 포트 | 설치 후 메모리 |
|---|---|---|---|
| fml-ops-01 | enp0s8 / 10.77.10.11/24 | 22031 | 7GiB |
| fml-ops-02 | enp0s8 / 10.77.10.12/24 | 22032 | 3GiB |
| fml-quorum-01 | enp0s8 / 10.77.10.13/24 | 22033 | 768MiB |
| fml-gateway-01 | enp0s8 / 10.77.10.1/24 | 22034 | 512MiB |
| fml-provision-01 | enp0s8 / 10.77.10.20/24 | 22035 | 1GiB |
| fml-edge-prod-01 | enp0s8 / 10.77.20.10/24 | 22036 | 768MiB |
| fml-edge-dev-01 | enp0s8 / 10.77.30.10/24 | 22037 | 768MiB |
| fml-edge-stg-01 | enp0s8 / 10.77.40.10/24 | 22038 | 768MiB |
NIC 이름은 ip -br link와 VirtualBox NIC의 MAC으로 확인한다. 이름이 다르면 모든 구성 파일에서 함께 바꾼다. Gateway/Provision의 추가 NIC는 순서대로 enp0s9/enp0s10/enp0s16을 예상한다.
# 각 VM 콘솔. 아래는 ops01 예시.
node=fml-ops-01
address=10.77.10.11/24
dns=10.77.10.20
sudo hostnamectl set-hostname "$node.fullmoon.test"
sudo nmcli connection add type ethernet con-name fml-internal ifname enp0s8 \
ipv4.method manual ipv4.addresses "$address" ipv4.dns "$dns" \
ipv4.never-default yes ipv6.method disabled connection.zone internal
sudo nmcli connection up fml-internal
sudo install -d -m 0700 -o labadmin -g labadmin /home/labadmin/.ssh
sudo install -m 0600 -o labadmin -g labadmin /tmp/labadmin_ed25519.pub /home/labadmin/.ssh/authorized_keys
sudo restorecon -RF /home/labadmin/.ssh
printf '%s\n' 'labadmin ALL=(ALL) NOPASSWD: ALL' | sudo tee /etc/sudoers.d/90-fullmoon-lab >/dev/null
sudo chmod 0440 /etc/sudoers.d/90-fullmoon-lab
sudo visudo -cf /etc/sudoers.d/90-fullmoon-lab
sudo systemctl enable --now sshd firewalld chronyd
ip -br address
관리 공개키는 먼저 /tmp/labadmin_ed25519.pub로 반입한다. Edge의 DNS는 각각 10.77.20.20/30.20/40.20 이다. 게스트 콘솔의 SSH host key fingerprint와 접속 시 표시한 값을 비교한다. SSH 공개키 접속을 확인한 뒤 다음 관리 접근 설정을 적용한다. 기존 접속을 유지한 채 sshd 검사에 통과한 후 reload 한다.
# 각 관리 VM: 콘솔 또는 이미 공개키 인증이 확인된 관리 세션
printf '%s\n' 'PermitRootLogin no' 'PasswordAuthentication no' \
'KbdInteractiveAuthentication no' 'PubkeyAuthentication yes' 'AllowUsers labadmin' \
| sudo tee /etc/ssh/sshd_config.d/00-fullmoon-lab.conf >/dev/null
sudo sshd -t
sudo systemctl reload sshd
NOPASSWD sudo는 실습용이며 운영에서는 실행 명령과 관리자 권한을 정책에 맞춰 제한한다.
2. 소스 전달과 네트워크
ops01에 공개 소스를 /opt/fullmoon-lab/source-original, 보완 파일을 /opt/fullmoon-lab/build-support로 전달한다. 비밀을 만들기 전에 새 환경용 복사본을 준비한다.
온라인 관리 NAT에서는 Windows에서 다음과 같이 공개 소스를 전달한다. 최초 콘솔에서 승인한 SSH host key를 사용한다.
# Windows: ZIP을 푼 폴더
tar -cf 'C:\FullMoon-Rebuild\source.tar' config automation build-support
scp -i 'C:\FullMoon-Rebuild\private\labadmin_ed25519' -P 22031 `
'C:\FullMoon-Rebuild\source.tar' labadmin@127.0.0.1:/tmp/fullmoon-source.tar
ssh -i 'C:\FullMoon-Rebuild\private\labadmin_ed25519' -p 22031 labadmin@127.0.0.1 `
'sudo install -d -m 0755 /opt/fullmoon-lab/source-original; sudo tar -xf /tmp/fullmoon-source.tar -C /opt/fullmoon-lab/source-original; sudo cp -a /opt/fullmoon-lab/source-original/build-support /opt/fullmoon-lab/build-support'
폐쇄망은 동일 tar를 ISO 등에 넣어 콘솔에서 마운트하고 같은 위치로 펼친다. 공개 소스에는 비밀이 없다. 이 과정에서 생성한 비밀 tar를 공개 source.tar와 섞지 않는다.
# ops01
sudo python3 /opt/fullmoon-lab/build-support/prepare-source.py \
--source /opt/fullmoon-lab/source-original --output /opt/fullmoon-lab/source
이후에는 수정한 source/config/를 사용한다. 다른 관리 VM 에도 source/config/를 동일한 경로로 전달한다. 온라인은 Docker를 ops01/ops02/quorum/Edge 세 대에 설치한다. 원래 install-docker.sh는 최신 가용 패키지를 사용한다. 원래 실습의 패치 버전까지 고정하려면 공식 저장소의 NEVRA를 선택해 설치한다.
# Docker 사용 노드: 온라인
bash /opt/fullmoon-lab/source/config/install-docker.sh
# Gateway: 마지막에 재부팅한다.
bash /opt/fullmoon-lab/source/config/configure-gateway.sh
# Provision: DVD에 Rocky ISO를 연결한 상태
bash /opt/fullmoon-lab/source/config/configure-provision.sh
중앙과 quorum 에는 세 환경망을 향하는 경로를 추가한다. Provision은 라우터가 아니며 Gateway가 라우팅한다.
# ops01/ops02/quorum
for subnet in 20 30 40; do
sudo nmcli connection modify fml-internal +ipv4.routes "10.77.$subnet.0/24 10.77.10.1"
done
sudo nmcli device reapply enp0s8
printf '%s\n' 'server 10.77.10.20 iburst' | sudo tee /etc/chrony.conf >/dev/null
sudo systemctl restart chronyd
getent hosts netbox.fullmoon.test git.fullmoon.test
chronyc tracking
DNS는 외부 fallback을 사용하지 않는다. Provision의 local stratum은 고립된 실습 시간을 맞추는 설정이며 정확한 외부 시각을 보장하지 않는다. 폐쇄망에서는 13 절로 역할별 RPM을 먼저 설치하고 모든 외부 repo를 비활성화한다.
3. NFS와 새 CA·새 비밀 생성
# quorum
bash /opt/fullmoon-lab/source/config/quorum-storage-ca.sh
quorum이 만든 공개 인증서 /etc/fullmoon-lab/pki/ca.crt를 ops01의 /opt/fullmoon-lab/incoming/ca.crt로 전달한다. CA 개인키는 quorum에 둔다. 새 관리 공개키도 incoming으로 전달한다.
# ops01 root: 동기화되지 않는 새 경로에서 한 번만 생성
set -e
sudo python3 /opt/fullmoon-lab/build-support/generate-config.py \
--source /opt/fullmoon-lab/source --output /opt/fullmoon-lab/build \
--admin-public-key /opt/fullmoon-lab/incoming/labadmin_ed25519.pub \
--ca-cert /opt/fullmoon-lab/incoming/ca.crt
sudo test ! -e /opt/fullmoon-lab/private
sudo cp -a /opt/fullmoon-lab/build/private /opt/fullmoon-lab/private
sudo cp -a /opt/fullmoon-lab/build/automation /opt/fullmoon-lab/automation
sudo chmod 0700 /opt/fullmoon-lab/private
생성기는 DB 암호, NetBox secret/pepper, 관리자 암호, Agent/Proxy PSK, 자동화 SSH 키를 새로 만든다. 중앙 두 대에는 동일한 비밀을 배포한다. 노드마다 생성기를 다시 실행하지 않는다. build/private, 생성한 tar 에는 비밀이 들어 있어 공개 자료와 Git에 넣지 않는다.
생성한 비밀 tar를 배포할 때 온라인 관리 NAT의 예시는 다음과 같다. ops01 root 전용 파일을 관리 계정 소유의 임시 전송 파일로 복사하고 Windows의 동기화되지 않는 private 폴더를 거쳐 해당 노드로 보낸다. 아래는 ops02 core의 예시이며 4절 표에 맞춰 파일명과 포트를 바꾼다.
# ops01: 해당 tar 한 개만 일시적으로 전달
sudo install -m 0600 -o labadmin -g labadmin /opt/fullmoon-lab/build/fml-ops-02.tar /home/labadmin/fullmoon-transfer.tar
# Windows: 관리 개인키로 두 연결에 인증. 22032는 ops02.
scp -i 'C:\FullMoon-Rebuild\private\labadmin_ed25519' -P 22031 `
labadmin@127.0.0.1:fullmoon-transfer.tar 'C:\FullMoon-Rebuild\private\fullmoon-transfer.tar'
scp -i 'C:\FullMoon-Rebuild\private\labadmin_ed25519' -P 22032 `
'C:\FullMoon-Rebuild\private\fullmoon-transfer.tar' labadmin@127.0.0.1:/tmp/fullmoon-core-config.tar
# 해당 파일 전송 확인 후 ops01의 /home/labadmin/fullmoon-transfer.tar와
# Windows의 fullmoon-transfer.tar를 삭제한다. root의 원본 build tar는 보존한다.
각 임시 전송 파일은 다른 비밀 tar를 받기 전에 정리한다. 폐쇄망은 조직에서 승인한 암호화된 이동 매체로 동일한 목적지에 전달한다. CA 공개 인증서와 HTTPS 개인키도 구분한다. 중앙에 필요한 frontend.pem만 같은 권한 제한으로 전달하고 quorum의 CA 개인키는 옮기지 않는다.
4. core tar 배포와 etcd·DB·Redis 시작
| 생성 파일 | 대상 노드 | 전달 위치 |
|---|---|---|
| build/fml-ops-01.tar | ops01 | /tmp/fullmoon-core-config.tar |
| build/fml-ops-02.tar | ops02 | /tmp/fullmoon-core-config.tar |
| build/fml-quorum-01.tar | quorum | /tmp/fullmoon-core-config.tar |
먼저 온라인 준비 VM에서 Patroni 이미지를 완성해 두 중앙 노드에 동일하게 배포한다. 현장에서 재빌드하지 않는다.
# 온라인 준비 VM
sudo docker build -t fullmoon/patroni:4.1.5-pg15 /opt/fullmoon-lab/source/config/patroni
sudo docker save -o patroni.tar fullmoon/patroni:4.1.5-pg15
# 중앙 두 대에 반입 후
sudo docker load -i patroni.tar
etcd/Redis 도 이미지 pull 또는 archive load로 준비하고 quorum → ops01 → ops02 순서로 bash /opt/fullmoon-lab/source/config/start-core.sh를 실행한다. 과반수가 준비되기 전에는 DB를 정상으로 판정하지 않는다.
sudo docker exec fullmoon-core-etcd-1 etcdctl \
--endpoints=http://10.77.10.11:2379,http://10.77.10.12:2379,http://10.77.10.13:2379 endpoint health
sudo docker exec fullmoon-core-postgres-1 patronictl -c /etc/patroni/patroni.yml list
etcd의 HTTP와 DB/Redis 내부 평문은 이 제한된 실습망의 선택이다. 운영으로 옮길 때 내부 인증과 TLS를 추가 검토한다.
5. VIP·HTTPS·DB 초기화·NetBox/Zabbix
각 build/{node}-apps.tar를 해당 중앙의 /tmp/fullmoon-app-config.tar로 전달한다. quorum의 frontend.pem을 /tmp/fullmoon-frontend.pem, 공개 CA를 /tmp/fullmoon-ca.crt로 전달한다. frontend.pem 에는 서버 개인키가 있으므로 필요한 중앙 두 대에만 root0600으로 배포한다.
아래에서 해당 망에 맞는 명령 하나만 선택해 중앙 두 대에서 실행한다.
온라인망에서 구성 시
FULLMOON_MODE=online bash /opt/fullmoon-lab/source/config/central-frontends.sh
폐쇄망에서 구성 시
FULLMOON_MODE=offline bash /opt/fullmoon-lab/source/config/central-frontends.sh
central-frontends.sh가 tar를 펼친 후 같은 apps tar를 같은 임시 위치로 다시 전달한다. activate-apps.sh 도 tar를 입력으로 읽는다. ops01 에서 먼저 실행해 DB 초기화와 NetBox migration이 끝나는지 확인하고 ops02로 진행한다.
# ops01: 두 DB 역할을 확인. 번호가 아닌 실제 primary를 사용한다.
curl --fail http://10.77.10.11:8008/patroni
curl --fail http://10.77.10.12:8008/patroni
bash /opt/fullmoon-lab/source/config/activate-apps.sh
sudo docker inspect --format '{{.State.Health.Status}}' fullmoon-apps-netbox-1
# ops01 healthy 확인 후 ops02에서도 activate-apps.sh 실행
수정본의 SQL 초기화는 HAProxy 6432로 실제 primary에 전달한다. 두 CORE 노드 사이의 6432, ops02 HAProxy에서 ops01 AWX NodePort30080으로의 제한된 경로도 방화벽에 추가한다. 이 보완 규칙의 실제 HA 전환 재시험은 아직 수행하지 않았다. 원래 로컬 Unix socket 초기화와 섞지 않는다. 수정본은 NetBox Worker도 명시적으로 시작한다.
# 중앙 두 대
sudo docker compose --project-directory /opt/fullmoon-lab/apps \
-f /opt/fullmoon-lab/apps/compose.yml ps
curl --fail https://netbox.fullmoon.test/login/ -o /dev/null
curl --fail https://zabbix.fullmoon.test/ -o /dev/null
6. Proxy/Bastion
환경별 build/fml-edge-{env}-01.tar를 해당 Edge의 /tmp/fullmoon-edge.tar로 전달한다. 수정본은 labadmin 관리 접근을 보존하고 bastion 에는 해당 .101:22 forwarding 만 허용한다.
아래에서 해당 망에 맞는 명령 하나만 선택해 해당 Edge에서 실행한다.
온라인망에서 구성 시
FULLMOON_MODE=online bash /opt/fullmoon-lab/source/config/configure-edge.sh
폐쇄망에서 구성 시
FULLMOON_MODE=offline bash /opt/fullmoon-lab/source/config/configure-edge.sh
두 방식 모두 적용 후 확인
sudo sshd -T -C user=bastion,host=localhost,addr=10.77.10.11 \
| grep -E 'allowusers|permitopen|allowtcpforwarding|forcecommand'
Proxy 이름/PSK는 이후 Zabbix API 초기화와 동일한 생성 값을 사용한다.
7. PXE 대상 설치
생성한 build/pxe의 .ks/.ipxe 파일을 Provision의 /var/www/html/ks에 둔다. 이전 UEFI DHCP boot를 실제 사용한 BIOS iPXE chain으로 바꾼다.
# Provision: 생성 파일을 /tmp/pxe로 전달한 후
sudo install -m 0644 /tmp/pxe/*.ks /tmp/pxe/*.ipxe /var/www/html/ks/
sudo sed -i '/^dhcp-boot=/d' /etc/dnsmasq.d/fullmoon.conf
printf '%s\n' \
'dhcp-boot=tag:prod,http://10.77.20.20/ks/prod.ipxe' \
'dhcp-boot=tag:dev,http://10.77.30.20/ks/dev.ipxe' \
'dhcp-boot=tag:stg,http://10.77.40.20/ks/stg.ipxe' \
| sudo tee -a /etc/dnsmasq.d/fullmoon.conf >/dev/null
sudo restorecon -RF /var/www/html/ks
sudo dnsmasq --test
sudo systemctl restart dnsmasq
# 온라인만 실행. 폐쇄망은 준비 VM의 packages/와 GPG 공개키를 반입한다.
bash /opt/fullmoon-lab/source/config/prepare-agent-repository.sh
# Windows: 한 대씩, 먼저 DEV
.\build-support\Create-PxeTarget.ps1 -Environment dev `
-IpxeIso 'C:\FullMoon-Rebuild\media\ipxe-legacy.iso' `
-BaseFolder 'C:\FullMoon-Rebuild\machines' `
-CpuProfile 'Intel Core i7-6700K' -WhatIf
# 계획 확인 후 -WhatIf를 제거. Provision 준비가 끝나면 VirtualBox에서 시작.
iPXE chain이 시작되지 않으면 콘솔의 iPXE shell 에서 dhcp, chain ${filename}을 실행한다. 설치 완료 후 정상 종료하고 DVD를 분리한 뒤 RAM을 1GiB로 줄인다. serial-console.log의 FULLMOON_HOSTKEY_BEGIN/END 사이 공개 host key와 게스트 콘솔 fingerprint를 비교해 승인한다. 기존 repair-ipxe-autostart.sh는 이전 UEFI 시험용이며 이 BIOS 순서에 쓰지 않는다.
8. SSH host key 승인과 Git
ops02 Git, Bastion 세 대와 설치한 대상의 공개 host key를 VM 콘솔에서 확인한다. ssh-keyscan 결과만으로 신뢰하지 않는다. ops01의 automation/files/known_hosts에 승인한 키만 기록한다.
git.fullmoon.test,10.77.10.12 ssh-ed25519 <ops02 콘솔에서 확인한 공개 host key>
10.77.20.10 ssh-ed25519 <PROD Edge 공개 host key>
10.77.30.10 ssh-ed25519 <DEV Edge 공개 host key>
10.77.40.10 ssh-ed25519 <STG Edge 공개 host key>
10.77.30.101 ssh-ed25519 <DEV 대상 공개 host key>
# ops01: 승인 정보를 포함해 소스 tar를 다시 만든다.
sudo tar -cf /opt/fullmoon-lab/build/automation-source.tar -C /opt/fullmoon-lab/automation .
# ops02로 automation-source.tar → /tmp/automation-source.tar,
# private/automation_ed25519.pub → /tmp/automation.pub 전달 후
bash /opt/fullmoon-lab/source/config/setup-git.sh
대상을 추가할 때 승인 host key·bootstrap inventory·Bastion PermitOpen을 갱신하고 Git에 커밋한다. 초기 setup-git.sh를 운영 중 무조건 반복하는 방식으로 수정하지 않는다.
9. EE·K3s·AWX
Git과 Bastion 승인 host key를 준비한 후 EE를 빌드한다. EE에 새 CA와 공개 known_hosts를 넣는다. 폐쇄망은 준비 VM의 빌드 결과를 반입한다.
# ops01 온라인
bash /opt/fullmoon-lab/source/config/install-k3s.sh
bash /opt/fullmoon-lab/source/config/k3s-lab-dns.sh
bash /opt/fullmoon-lab/source/config/build-ee.sh
# 폐쇄망 K3s는13절의 install-k3s-offline.sh 사용. 현장 EE 빌드는 생략.
폐쇄망용 EE를 만드는 준비 VM에는 K3s가 없어도 된다. 준비 단계는 build/save까지만 수행하고 현장 ops01에서 import한다. 새 quorum CA 공개 인증서와 승인한 known_hosts를 준비 VM에 전달한 뒤 실행한다.
# 온라인 준비 VM: Docker 설치와 수정 source 준비 완료
sudo install -m 0644 /tmp/fullmoon-new-ca.crt /etc/pki/ca-trust/source/anchors/fullmoon-lab-ca.crt
sudo install -d -m 0755 /opt/fullmoon-lab/automation/files
sudo install -m 0644 /tmp/fullmoon-approved-known_hosts /opt/fullmoon-lab/automation/files/known_hosts
bash /opt/fullmoon-lab/source/config/build-ee-prepare.sh
# 출력: /opt/fullmoon-lab/offline/images/fullmoon-ee-r2.tar
# 이 파일을 현장 ops01에 반입한 후
sudo k3s ctr images import /mnt/fullmoon-offline/fullmoon-ee-r2.tar
공식 Operator 2.19.1 소스를 온라인 준비 VM에서 받고 commit을 기록한 후 ops01의 build/awx/operator로 전달한다. 생성기의 kustomization은 로컬 Operator를 참조한다.
# 온라인 준비 VM
git clone --branch 2.19.1 --depth 1 https://github.com/ansible/awx-operator.git operator
git -C operator rev-parse HEAD
# ops01: operator/를 build/awx/operator로 반입한 후
sudo tar -cf /opt/fullmoon-lab/build/awx.tar -C /opt/fullmoon-lab/build/awx .
sudo install -m 0600 /opt/fullmoon-lab/build/awx.tar /tmp/fullmoon-awx.tar
bash /opt/fullmoon-lab/source/config/install-awx.sh
sudo k3s kubectl -n awx get pods,jobs
curl --fail https://awx.fullmoon.test/api/v2/ping/
admin_user는 labadmin 이다. AWX Secret Key는 Operator가 만든 Secret에 있으므로 DB와 함께 백업한다. 단일 K3s/replica는 AWX HA가 아니다.
10. NetBox 사용자·토큰과 API 연동 초기화
NetBox migration과 labadmin 생성이 완료되면 새 토큰을 컨테이너 root 전용 파일로 만든다. 토큰 값은 stdout에 출력하지 않는다.
# ops01
sudo docker cp /opt/fullmoon-lab/build-support/bootstrap-netbox-users.py fullmoon-apps-netbox-1:/tmp/bootstrap-netbox-users.py
sudo docker exec -u 0 fullmoon-apps-netbox-1 sh -c \
'/opt/netbox/venv/bin/python /opt/netbox/netbox/manage.py shell < /tmp/bootstrap-netbox-users.py'
sudo docker cp fullmoon-apps-netbox-1:/tmp/fullmoon-api-tokens.json /opt/fullmoon-lab/private/netbox-token-export.json
sudo chmod 0600 /opt/fullmoon-lab/private/netbox-token-export.json
sudo docker exec -u 0 fullmoon-apps-netbox-1 rm -f /tmp/fullmoon-api-tokens.json /tmp/bootstrap-netbox-users.py
sudo python3 /opt/fullmoon-lab/build-support/finish-integration.py \
--tokens /opt/fullmoon-lab/private/netbox-token-export.json
순서는 NetBox Custom Field/카탈로그 → Zabbix Proxy/API role/user/token → AWX Credential/Project/Inventory/Job/Workflow 다. AWX 객체 ID는 private/awx-objects.json에 저장되고 이전 실습의 번호와 다르다. Git Project와 bootstrap inventory sync가 성공한 후 DEV 만 limit으로 지정해 Workflow를 실행한다. 자산/Interface/IP → Zabbix host → NetBox inventory sync → 최신 모니터링 값까지 검증한다.
11. 설치 완료 controller
이번 패키지의 신규 환경용 controller는 private/awx-objects.json의 ID를 읽고 빈 state 에서 시작한다. 원래 공개 파일의 이전 job 22/30 이나 Project8/Inventory9/Workflow13을 복사하지 않는다. 설치 marker·hostname·machine-id·승인 SSH 키 확인을 수동으로 먼저 검사하고 timer를 켠다. 불일치 대상에는 쓰기를 시작하지 않고 실패는 manual_review_required로 남긴다.
# ops01: 지원 패키지의 수정 controller와 초기화 installer 사용
sudo install -m 0644 /opt/fullmoon-lab/source/config/postinstall_controller.py \
/opt/fullmoon-lab/automation/tools/postinstall_controller.py
sudo install -d -m 0700 /opt/fullmoon-lab/postinstall
# 새 환경에만 적용. 기존 state 파일이 있으면 초기화하지 않고 내용을 검토한다.
sudo test ! -e /opt/fullmoon-lab/postinstall/state.json
sudo python3 -c 'import json; from pathlib import Path; p=Path("/opt/fullmoon-lab/private/awx-objects.json"); d=json.loads(p.read_text()); assert all(d.get(k) for k in ("project","bootstrap_source","workflow")); print("새 AWX 객체 ID 파일 확인 완료")'
# 신규 대상 신원과 자동 실행할 limit을 확인한 후 설치
bash /opt/fullmoon-lab/source/config/install-postinstall-controller.sh
sudo systemctl is-enabled fullmoon-postinstall.timer
sudo systemctl list-timers fullmoon-postinstall.timer
sudo journalctl -u fullmoon-postinstall.service -n 20 --no-pager
타이머 활성화 시 승인된 새 대상의 Workflow가 시작될 수 있다. 최초 시험은 DEV만 준비하고 marker·hostname·SSH host key를 확인한 상태에서 수행한다. 성공한 state를 지워 중복 실행시키지 않는다.
12. 브라우저 접속과 완료 판정
Windows 에서 새 CA의 공개 인증서를 신뢰한다. hosts는 관리자 권한으로 세 서비스 이름을 127.0.0.1에 연결한다. 온라인 관리 NAT의 접속 예시:
ssh -i 'C:\FullMoon-Rebuild\private\labadmin_ed25519' -p 22031 -N `
-L 127.0.0.1:443:10.77.10.10:443 labadmin@127.0.0.1
폐쇄망은 NAT tunnel이 없다. CORE Internal Network에 별도 관리용 VM을 연결하고 DNS는 10.77.10.20, CA 신뢰는 새 CA로 설정한다.
- etcd endpoint 세 개가 healthy, Patroni는 leader 한 대와 replica 한 대, Redis/Sentinel 역할이 일치한다.
- 두 NetBox App/Worker가 정상이고 VIP/HTTPS 인증서 검증이 성공한다.
- Zabbix는 Active 한 대와 Standby 한 대, Proxy 이름/PSK가 일치하고 Agent 최신 값이 갱신된다.
- AWX Git/Inventory 동기화와 DEV Workflow가 성공하고 IP 중복을 거부한다.
- 재실행해도 자산이 늘지 않고, 알 수 없는 SSH 키와 다른 machine-id 에서 쓰기를 거부한다.
- 노드 중단·DB 역할 전환·Redis 복구·Proxy 지연 데이터 재전송·백업 복원을 03 검증표로 재시험한다.
13. 폐쇄망 반입과 설치
준비 VM은 같은 Rocky 10 x86_64로 만든다. 모든 역할의 RPM과 의존성을 저장한다. 고정 버전은 실제 NEVRA로 지정하고 rpm-versions.txt에 남긴다.
# 온라인 준비 VM: 공식 저장소와 서명키 설정 후
sudo dnf -y install dnf-plugins-core createrepo_c
mkdir -p offline/rpms
dnf download --resolve --alldeps --destdir offline/rpms \
docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin \
git-core jq curl python3 python3-pip kernel-modules-extra dnsmasq httpd chrony \
firewalld openssh-server openssh-clients sudo haproxy keepalived nfs-utils \
openssl policycoreutils-python-utils createrepo_c gnupg2
# k3s-selinux도 공식 Rancher 저장소에서 의존성을 포함해 추가
createrepo_c offline/rpms
rpm -qp --queryformat '%{NAME}-%{EPOCHNUM}:%{VERSION}-%{RELEASE}.%{ARCH}\n' offline/rpms/*.rpm > offline/rpm-versions.txt
rpm -K offline/rpms/*.rpm
공식 RPM 서명 공개키를 함께 반입하고 현장에서 등록한다. /mnt/fullmoon-offline/rpms로 반입했다면 다음 내용을 /etc/yum.repos.d/fullmoon-offline.repo에 작성한다.
[fullmoon-offline]
name=FullMoon approved offline RPMs
baseurl=file:///mnt/fullmoon-offline/rpms
enabled=1
gpgcheck=1
repo_gpgcheck=0
개별 RPM 서명 검증은 유지한다. metadata 까지 서명했다면 repo_gpgcheck 도 사용한다. 모든 외부 repo를 disabled로 두고 offline repo 만 enabled로 설정한다. 이후 기존 스크립트의 dnf 도 이 저장소만 사용한다.
sudo dnf --disablerepo='*' --enablerepo=fullmoon-offline -y install \
docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
# 역할별 패키지도 동일한 repo 지정으로 먼저 설치한다.
Docker 반입 이미지 목록은 아래와 준비 완료한 Patroni 다. 각 RepoDigest/ImageID를 기록하고 tag 만 같은 다른 빌드를 섞지 않는다.
gcr.io/etcd-development/etcd:v3.7.1
redis:7.4-alpine
fullmoon/patroni:4.1.5-pg15
netboxcommunity/netbox:v4.7.1-5.1.1
zabbix/zabbix-server-pgsql:alpine-7.0.30
zabbix/zabbix-web-nginx-pgsql:alpine-7.0.30
zabbix/zabbix-proxy-sqlite3:alpine-7.0.30
K3s/AWX는 고정 버전 K3s binary·installer·k3s-airgap-images-amd64.tar.zst·공식 Operator 소스와 아래 이미지를 준비한다. Docker load는 K3s image import를 대신하지 않는다.
quay.io/ansible/awx-operator:2.19.1
quay.io/brancz/kube-rbac-proxy:v0.15.0
quay.io/ansible/awx:24.6.1
quay.io/ansible/awx-ee:24.6.1
docker.io/redis:7
localhost/fullmoon-ee:24.6.1-netbox3.23.0-r2
Operator가 만든 pod의 모든 container/initContainer 이미지도 준비 시험에서 확인한다. CR 외에 추가 이미지가 있으면 archive에 더한다. 외부 DB 이므로 Operator 관리 PostgreSQL은 배포하지 않는다. 모든 이미지를 pull/build 한 뒤 docker save로 저장한다.
# 준비 VM: 해당 이미지를 pull/build한 후 저장
sudo docker save -o offline/docker-images.tar \
gcr.io/etcd-development/etcd:v3.7.1 redis:7.4-alpine \
fullmoon/patroni:4.1.5-pg15 netboxcommunity/netbox:v4.7.1-5.1.1 \
zabbix/zabbix-server-pgsql:alpine-7.0.30 \
zabbix/zabbix-web-nginx-pgsql:alpine-7.0.30 \
zabbix/zabbix-proxy-sqlite3:alpine-7.0.30
sudo docker save -o offline/awx-images.tar \
quay.io/ansible/awx-operator:2.19.1 quay.io/brancz/kube-rbac-proxy:v0.15.0 \
quay.io/ansible/awx:24.6.1 quay.io/ansible/awx-ee:24.6.1 \
redis:7 localhost/fullmoon-ee:24.6.1-netbox3.23.0-r2
# 현장 Docker 노드
sudo docker load -i /mnt/fullmoon-offline/docker-images.tar
# ops01: k3s-selinux와 의존 RPM을 먼저 설치하고 반입 체크섬 검증
bash /opt/fullmoon-lab/source/config/install-k3s-offline.sh
sudo k3s ctr images import /mnt/fullmoon-offline/awx-images.tar
sudo k3s ctr images list
install-k3s-offline.sh는 /mnt/fullmoon-offline/{k3s,install-k3s.sh,k3s-airgap-images-amd64.tar.zst}를 읽는다. 같은 고정 버전과 공식 체크섬으로 준비한다. source/config/k3s-lab-dns.sh 도 실행한다. EE는 새 CA와 승인 known_hosts를 준비 VM에 전달해 온라인에서 빌드한 후 반입한다. 폐쇄망 Job 실행 중 Galaxy/pip에 연결하지 않는다.
Provision에 반입할 자료는 ISO의 .treeinfo·kernel/initrd·전체 rocky/설치 트리, packages/repodata와 Agent 2 RPM·의존성, GPG 공개키다. ISO가 Minimal/repodata를 사용하므로 BaseOS/AppStream 경로를 임의로 복사하지 않는다.
# 비밀이 없는 반입 offline 디렉터리에서 체크섬 목록 생성
find . -type f ! -name SHA256SUMS -print0 | sort -z | xargs -0 sha256sum > SHA256SUMS
# 현장 동일 구조에서 확인
sha256sum -c SHA256SUMS
처음부터 NAT가 없는 신규 관리 환경의 전체 설치 시험은 아직 미수행이다. 외부 NIC·DNS를 차단한 새 대상의 설치 시험과 같은 검증으로 표현하지 않는다.
1. 버전과 설치 순서
이 문서의 Zabbix 7.0.30은 9월 실습 결과를 재현하기 위한 고정 패치다. 10월 9일 검수 시 공식 배포 목록의 7.0 LTS 최신 패치는 7.0.31이다. 새 패치를 적용할 때는 Server·Frontend·Proxy·Agent·보고 생성 이미지를 함께 검토하고 호환성과 장애 전환을 다시 확인한다. 기존 검증 결과를 새 패치의 검증으로 바꾸어 표시하지 않는다.
| 구성 요소 | 사용 버전·방식 | 선택 이유 |
|---|---|---|
| 가상화 / OS | VirtualBox 7.2.18 / Rocky Linux 10.2 | 실제 PC에서 재현 가능한 Linux 실습 |
| Docker / Compose | 29.8.1 / 5.5.1 | 중앙·Proxy의 컨테이너 관리 |
| Zabbix | 7.0.30 LTS Server/Web/Proxy/Agent 2 | Server와 Proxy의 버전 일치, 정식 LTS 패치 고정 |
| NetBox | 4.7.1, netbox-docker 5.1.1 | 두 App/Worker와 API 기반 자산 관리 |
| PostgreSQL / Patroni | PostgreSQL 15 / Patroni 4.1.5 | 중앙 DB 복제·역할 전환 |
| Redis / etcd | Redis 7.4 / etcd 3.7.1 | Sentinel과 분산 장애 판정 |
| AWX / Operator | 24.6.1 / 2.19.1 | 공식 Operator 설치 방식 |
| K3s | v1.37.0+k3s1 | 단일 VM의 AWX 실행 기반 |
| NetBox collection | netbox.netbox 3.23.0 | NetBox v2 Bearer 토큰을 사용하는 inventory plugin |
설치 순서는 OS·네트워크 → DNS/NTP·CA → etcd/PostgreSQL/Redis → 접속 VIP → NetBox/Zabbix → 환경별 Proxy/Bastion → K3s/AWX·Git → PXE 대상 → 자동화 연동 → 장애/복원 검증이다. 뒤 단계의 UI가 뜨더라도 앞 단계의 DB 역할·이름 해석·시간 동기화가 정상인지 먼저 확인한다.
‘최신’은 2026년 9월 20일 구축 기준의 고정 버전이다. 이후 재구축에서는 지원 정책과 이미지 digest를 다시 확인하고, 이 글의 버전과 새 버전을 섞어 설치하지 않는다. Zabbix의 최신 일반 릴리스와 최신 정식 LTS는 구분한다.
2. VM과 네트워크 준비
CORE는 10.77.10.0/24, PROD는 10.77.20.0/24, DEV는 10.77.30.0/24, STG는 10.77.40.0/24다. 각각 fml-core/prod/dev/stg Internal Network로 만든다. Gateway와 Provision에는 네 내부망 NIC를 붙이고, Edge와 대상은 자신의 환경망에 붙인다.
온라인망에서 구성 시
공식 ISO의 체크섬을 확인하고 Rocky 최소 설치 템플릿을 만든다. 관리 VM에는 설치 기간 NAT NIC와 내부망 NIC를 분리해 사용한다. 호스트의 SSH 포트 포워딩은 127.0.0.1에만 바인딩한다. 대상 PXE VM에는 NAT를 붙이지 않는다.
$VBox = 'C:\Program Files\Oracle\VirtualBox\VBoxManage.exe'
& $VBox list vms
& $VBox showvminfo fml-ops-01 --machinereadable
# 대상은 승인된 빈 디스크에만 새로 생성한다.
.\build-support\Create-PxeTarget.ps1 -Environment prod -BaseFolder 'C:\FullMoon-Rebuild\machines' -IpxeIso 'C:\FullMoon-Rebuild\media\ipxe-legacy.iso' -CpuProfile 'Intel Core i7-6700K'
템플릿 복제 시 hostname, machine-id, SSH host key, MAC을 각각 새로 만든다. 원본 템플릿의 고정 주소·키·machine-id가 여러 VM에 남지 않도록 확인한다. SELinux Enforcing과 firewalld를 유지하고 root 원격 로그인·암호 로그인을 제한한다.
폐쇄망에서 구성 시
ISO, 검증된 설치 패키지, 내부 CA, 공개키와 구성 템플릿을 반입한 뒤 같은 내부망 구조를 만든다. NAT NIC를 연결하지 않은 상태에서도 OS 설치와 내부 DNS/NTP에 접근할 수 있어야 한다. ‘NAT를 나중에 끈 기존 설치’와 ‘필요한 의존성을 반입해 처음부터 설치’를 다른 시험으로 기록한다.
이 PC에서는 새 BIOS PXE 대상의 2 vCPU 부팅이 정지해 1 vCPU를 사용했다. 중앙 1호기는 Intel Core i7-6700K CPU profile에서 4 vCPU로 실행했다. 이 프로파일명은 실제 PC CPU가 아니다. Hyper-V/VBS/메모리 무결성은 변경하지 않았다. 자세한 VM 문제는 별도 블로그에서 다룬다.
3. 라우팅·DNS·NTP·접근 경로
환경 간 통신은 Gateway의 firewalld policy로 허용한다. Provision은 각 환경에 직접 연결되어 DHCP·PXE·저장소를 제공하며 라우터로 사용하지 않는다.
| 출발 | 목적지 | 포트 | 목적 |
|---|---|---|---|
| 중앙 .11/.12 | 환경 Edge .10 | TCP 22 | Bastion 진입 |
| 환경 Edge .10 | 승인된 대상 .101 | TCP 22 | SSH forwarding |
| 환경 대상 | 같은 환경 Edge .10 | TCP 10051 | Agent Active 데이터 |
| 환경 Edge .10 | 중앙 .11/.12 | TCP 10051 | Active Proxy와 HA Server |
| 승인된 환경망 | VIP 10.77.10.10 | TCP 443 | NetBox/Zabbix/AWX API·웹 |
| 환경 대상 | 같은 환경 Provision .20 | DNS 53, NTP 123, HTTP 80, PXE 관련 포트 | 설치·이름 해석·시간·내부 저장소 |
| 중앙·quorum | 해당 내부 서비스 노드 | etcd 2379/2380, Patroni 8008, PG 5432/6432, Redis 6379/26379, NFS 2049 | 데이터 복제·판정·공유 미디어 |
위 표는 통신 목적 요약이다. 실제 허용 규칙은 호스트 방화벽과 라우터 정책을 함께 확인한다. DB·etcd·Redis를 인터넷이나 모든 환경망에 공개하지 않는다.
온라인망에서 구성 시
관리 VM에 필요한 패키지를 설치하고 내부 인터페이스와 정적 경로를 만든다. 인터넷용 default route와 실습망의 정적 경로를 섞지 않는다.
nmcli connection modify fml-internal \
+ipv4.routes '10.77.20.0/24 10.77.10.1'
nmcli connection modify fml-internal \
+ipv4.routes '10.77.30.0/24 10.77.10.1'
nmcli connection modify fml-internal \
+ipv4.routes '10.77.40.0/24 10.77.10.1'
nmcli device reapply enp0s8
ip route
chronyc tracking
폐쇄망에서 구성 시
내부 DNS에서 netbox.fullmoon.test, zabbix.fullmoon.test, awx.fullmoon.test를 VIP 10.77.10.10으로, git.fullmoon.test를 10.77.10.12로 해석한다. 외부 DNS fallback에 의존하지 않는다. Provision의 chrony를 내부 기준으로 쓰되 실제 운영에서는 별도 검증한 시간원과 동기화 정책을 준비한다.
getent hosts netbox.fullmoon.test git.fullmoon.test
chronyc sources -v
ip route get 10.77.20.10
브라우저 접속은 실습 CA를 신뢰하는 관리 단말에서 HTTPS 이름으로 한다. Windows에서 내부망을 직접 라우팅하지 않을 때는 loopback SSH tunnel을 사용할 수 있다. 이미 사용하는 로컬 443 포트가 없는지 먼저 확인한다.
ssh -i <관리용_개인키> -p 22031 -N -L 127.0.0.1:443:10.77.10.10:443 labadmin@127.0.0.1
관리 단말의 hosts에는 세 서비스 이름을 127.0.0.1로 연결하고, 검증한 공개 CA 인증서를 신뢰 저장소에 등록해야 한다. 서버 CA 개인키는 가져오지 않는다. 중앙 1호기 장애 시험 중에도 접근하려면 중앙 2호기의 관리 SSH 포트 22032를 사용한다. 인증서 경고를 무시하는 방식은 정상 접속 절차로 삼지 않는다.
4. 컨테이너 런타임과 반입 묶음
온라인망에서 구성 시
Docker 공식 RHEL 저장소에서 Docker/Compose를 설치한다. Compose 프로젝트 경로는 /opt/fullmoon-lab/core, /opt/fullmoon-lab/apps, /opt/fullmoon-lab/edge로 구분한다. 민감한 환경 파일은 root 소유 0600, 상위 디렉터리는 0700으로 둔다.
docker version
docker compose version
docker compose --project-directory /opt/fullmoon-lab/core \
-f /opt/fullmoon-lab/core/compose.yml config --quiet
docker image inspect --format '{{json .RepoDigests}}' \
zabbix/zabbix-server-pgsql:alpine-7.0.30
렌더링된 compose 전체 출력에는 비밀번호가 포함될 수 있으므로 공개 로그에 config 내용을 저장하지 않는다. 호스트 SELinux Enforcing 여부와 Docker daemon의 SELinux integration 활성 여부도 구분한다. 이 실습은 호스트 Enforcing을 유지하지만 Docker SELinux integration까지 적용한 환경으로 주장하지 않는다.
폐쇄망에서 구성 시
같은 CPU 아키텍처·Rocky major release의 연결된 준비 VM에서 RPM과 의존성을 받는다. Docker image archive와 K3s/containerd archive는 별개다. Docker에 이미지를 load했다고 K3s에서 사용할 수 있는 것은 아니다.
# 준비 VM: 필요한 버전의 RPM과 모든 의존성 저장
dnf download --resolve --alldeps --destdir ./rpms \
docker-ce docker-ce-cli containerd.io docker-compose-plugin
createrepo_c ./rpms
docker image save -o images.tar <반입할_고정_이미지_목록>
sha256sum images.tar > images.tar.sha256
# 폐쇄망 반입 후
sha256sum -c images.tar.sha256
docker image load -i images.tar
k3s ctr images import fullmoon-ee-r2.tar
반입 목록은 OS ISO·RPM 저장소, Docker/Compose, Patroni 빌드 결과, NetBox/Zabbix/Redis/etcd 이미지, K3s 바이너리와 airgap 이미지, Operator/RBAC proxy/AWX/EE 이미지, Git bundle, 설정 템플릿·공개 CA, 서명 키와 체크섬이다. 준비 VM의 캐시 덕분에 우연히 통과하지 않도록 외부 NIC가 없는 새 대상에서 검증한다.
5. PostgreSQL·etcd·Redis 구성
etcd와 Sentinel은 중앙 두 노드와 quorum 노드에 배치한다. PostgreSQL/Patroni와 Redis는 중앙 두 노드에 배치한다. DB는 NetBox·Zabbix·AWX용 계정과 데이터베이스를 분리한다.
온라인망에서 구성 시
고정 이미지를 pull/build하고 노드별 NODE_NAME/NODE_IP, Patroni 설정, Redis/Sentinel 설정, 제한된 비밀 파일을 배치한다. etcd 세 노드가 서로 통신하는지 확인한 뒤 중앙 DB를 시작한다.
docker compose --project-directory /opt/fullmoon-lab/core \
-f /opt/fullmoon-lab/core/compose.yml --profile central up -d
docker compose --project-directory /opt/fullmoon-lab/core \
-f /opt/fullmoon-lab/core/compose.yml exec -T postgres \
patronictl -c /etc/patroni/patroni.yml list
curl --fail http://10.77.10.11:8008/patroni
curl --fail http://10.77.10.12:8008/patroni
quorum 노드는 central profile 없이 etcd·Sentinel만 실행한다. Patroni의 synchronous_mode는 활성화하고 synchronous_mode_strict는 false로 두었다. 복제 상태와 장애 시 커밋 손실 가능성을 운영 조건에 맞춰 판단해야 한다. 두 DB를 각각 수동 primary로 만드는 방식은 사용하지 않는다.
폐쇄망에서 구성 시
Patroni Dockerfile이 pip·apt 등 외부 저장소를 필요로 하므로 온라인 준비 구간에서 이미지를 완성해 반입한다. 현장에서 즉석 빌드하다 인터넷 의존성을 만나는 방식은 피한다. 같은 archive를 두 중앙 노드에 load하고 이미지 ID를 비교한 뒤 동일한 절차로 시작한다.
HAProxy의 DB 접속 포트는 6432다. Patroni /primary가 200을 반환하는 노드만 DB 쓰기 backend로 사용한다. 초기 60초 timeout에서는 유휴 DB 연결이 끊어질 수 있어 DB listener의 client/server timeout을 1시간으로 분리했다. 값은 실제 쿼리·연결 풀 정책에 맞춰 조정한다.
6. VIP·HTTPS와 NetBox 이중화
Keepalived의 VIP는 10.77.10.10, 정상 우선 노드는 ops01이다. 두 노드의 HAProxy는 NetBox 8082, Zabbix Web 8080, AWX 30080으로 연결한다. Node·DB·Redis·VIP의 active 역할은 항상 같은 노드일 필요가 없다.
온라인망에서 구성 시
실습 CA로 세 웹 이름을 SAN에 넣은 인증서를 발급하고 두 중앙 노드에 인증서/키를 제한된 권한으로 배치한다. NetBox App와 Worker에는 같은 SECRET_KEY, API token pepper, Redis Sentinel 설정을 사용한다.
# netbox-configuration.py의 주요 관계
DATABASES = {'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'netbox', 'USER': 'netbox',
'PASSWORD': '<비밀_파일에서_주입>',
'HOST': '127.0.0.1', 'PORT': 6432,
}}
# SECRET_KEY / API_TOKEN_PEPPERS는 두 App에서 일치시킨다.
# REDIS tasks/caching은 Sentinel의 service와 각각의 DB 번호를 지정한다.
기본 설정 파일의 실제 버전별 형식은 제공한 NetBox 설정과 공식 문서를 기준으로 사용한다. 환경 변수의 이름만 맞추고 Python 설정에서 읽지 않으면 적용되지 않는다. DB 초기 migration은 먼저 한 노드에서 완료하고 나머지 노드와 Worker를 시작한다.
미디어는 quorum의 /srv/fullmoon/netbox-media를 NFSv4로 공유한다. 두 중앙 노드만 export에 허용하고 root_squash를 유지한다. NetBox 이미지의 실제 UID를 확인해 디렉터리 권한을 맞춘다. 이 Rocky 환경에서 확인한 NFS SELinux boolean은 virt_use_nfs다.
findmnt /srv/fullmoon/netbox-media
haproxy -c -f /etc/haproxy/haproxy.cfg
keepalived -t -f /etc/keepalived/keepalived.conf
systemctl is-active haproxy keepalived
curl --fail https://netbox.fullmoon.test/login/ -o /dev/null
폐쇄망에서 구성 시
NetBox 이미지에는 실행에 필요한 Python 의존성이 포함되어 있어 같은 digest의 이미지를 두 노드에 반입한다. 내부 CA를 호스트뿐 아니라 AWX 작업 실행환경(EE)에도 넣는다. 두 노드의 SECRET_KEY/pepper가 달라지지 않도록 비밀의 복구 절차도 준비한다. NFS 중단은 웹 API 성공과 별개로 미디어에 영향을 주므로 따로 시험한다.
실제로 만난 문제는 NetBox 상태 확인 요청(health check)였다. HTTP/1.1 Host 없이 /login/을 검사하면 NetBox가 400을 반환하고 HAProxy가 모든 backend를 down으로 판정해 VIP가 503을 반환했다. 다음처럼 Host를 지정했다.
backend netbox_ui
mode http
option httpchk
http-check send meth GET uri /login/ ver HTTP/1.1 hdr Host netbox.fullmoon.test
http-check expect status 200
server ops01 10.77.10.11:8082 check
server ops02 10.77.10.12:8082 check
장애 시험에서는 Redis 연결의 기본 재시도로 NetBox 캐시 조회가 불필요하게 오래 지연됐다. 설치된 NetBox 4.7.1과 django-redis 코드를 확인하고, 로컬 Sentinel을 먼저 조회하도록 바꿨다. 캐시는 지원되는 KWARGS에 연결·응답 timeout과 재시도 정책을 명시했다. loopback은 같은 Sentinel의 다른 접속 주소이며 과반수 구성원이 추가된 것은 아니다.
from redis.backoff import NoBackoff
from redis.retry import Retry
# 각 NetBox 노드의 로컬 Sentinel을 첫 번째로 조회한다.
SENTINELS = [('127.0.0.1', 26379), ('10.77.10.13', 26379),
('10.77.10.11', 26379), ('10.77.10.12', 26379)]
REDIS['caching']['KWARGS'] = {
'socket_connect_timeout': 3,
'socket_timeout': 3,
'retry': Retry(NoBackoff(), 0),
}
빠르게 오류를 반환하도록 제한한 값이므로 개별 요청의 재시도와 서비스 복구 시간은 다르다. 실제 DB/Redis 주 노드 장애 후 API 회복까지의 시간은 검증 글에서 확인한다. 운영 부하나 다른 버전에서도 같은 결과가 나온다고 일반화하지 않는다.
7. Zabbix LTS HA와 환경별 Proxy/Bastion
온라인망에서 구성 시
Server/Web/Proxy는 alpine-7.0.30 태그를 사용하고 Rocky 대상 Agent 2는 el10용 7.0.30 RPM을 사용한다. 두 Server는 공통 Zabbix DB를 바라보되 HANodeName과 NodeAddress를 다르게 설정한다. Web은 특정 Server 주소를 고정하지 않고 HA 정보에서 활성 노드를 찾도록 설정했다.
# ops01
ZBX_HANODENAME=fml-ops-01
ZBX_NODEADDRESS=10.77.10.11:10051
# ops02
ZBX_HANODENAME=fml-ops-02
ZBX_NODEADDRESS=10.77.10.12:10051
# Active Proxy의 같은 HA cluster 주소는 세미콜론으로 연결
ZBX_SERVER_HOST=10.77.10.11:10051;10.77.10.12:10051
Proxy 이름은 Zabbix API에 등록한 이름과 정확히 일치해야 한다. 환경별 Proxy PSK와 Agent PSK를 구분한다. Proxy SQLite 데이터는 영속 볼륨에 두고 디스크 버퍼 정책을 적용한다. 단절 후 지연 데이터를 재전송했는지까지 확인해야 버퍼 동작을 검증했다고 할 수 있다.
폐쇄망에서 구성 시
Proxy 이미지는 docker load로 반입한다. Agent RPM은 내부 저장소로 제공하고 GPG 서명 검증을 유지한다. 이 el10 RPM은 B5333005 키로 검증했다. 기존 A14FE591 키만 사용하는 구성에서는 검증이 실패했으므로 공식 서명 키의 fingerprint를 확인해 추가했다.
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX-B5333005
rpm -K zabbix-agent2-7.0.30-release1.el10.x86_64.rpm
# 검증한 키 fingerprint
# 4C3D6F2CC75F5146754FC374D913219AB5333005
Bastion은 환경 대상 .101:22로만 forwarding한다. 대화형 셸과 agent forwarding은 허용하지 않는다. 중앙의 키를 사용해 대상까지 연결하고 개인키를 Edge에 두지 않는다. 기존 관리 계정의 SSH 접근을 보존한 상태에서 sshd -t로 검사하고 reload한다.
Match User bastion
AuthenticationMethods publickey
AllowTcpForwarding local
PermitOpen 10.77.20.101:22
PermitTTY no
AllowAgentForwarding no
ForceCommand /bin/false
Match all
8. Git·K3s·AWX와 실행환경
온라인망에서 구성 시
Git 원격 저장소(bare repository)는 ops02의 /srv/git/fullmoon-automation.git이다. AWX는 fmlgit의 읽기 전용 배포키로 main branch를 가져온다. forced command는 git-shell이 해석할 수 있게 경로까지 작은따옴표로 감쌌다.
restrict,command="git-upload-pack '/srv/git/fullmoon-automation.git'" ssh-ed25519 <공개키>
ops01에 K3s를 설치하고 SELinux와 Secret 암호화를 활성화했다. Traefik·ServiceLB·metrics-server는 이 실습에 불필요해 제외했다. AWX는 Operator 2.19.1과 AWX 24.6.1로 고정하고, PostgreSQL Secret은 기존 HA DB의 6432 경로를 가리킨다. 관리자 암호·DB 암호·CA bundle은 Kubernetes Secret으로 주입한다.
k3s kubectl -n awx get pods,jobs
k3s kubectl -n awx apply -f awx.yml
curl --fail https://awx.fullmoon.test/api/v2/ping/
Operator의 초기 RBAC proxy 이미지 gcr.io 경로가 404여서 같은 v0.15.0의 공식 quay.io/brancz 이미지로 수정했다. AWX CRD에서 cookie 설정은 문자열, host_aliases는 배열이어야 한다. SYSTEM_TASK_ABS_MEM을 숫자로 넣으면 해당 AWX 코드가 문자열 메서드를 호출하며 dispatcher가 실패해 불필요한 수동 설정을 제거했다.
폐쇄망에서 구성 시
K3s airgap 이미지와 Operator가 생성하는 모든 이미지까지 반입한다. 특히 init/migration/EE/RBAC proxy 이미지가 빠지면 Web 이미지만 있어도 설치되지 않는다. K3s containerd에 import 후 실제 이미지 이름이 CR의 이름과 일치하는지 확인한다.
실습 EE는 awx-ee:24.6.1에 netbox.netbox:3.23.0, 공개 CA, 검증한 Git 서버와 경유 서버의 SSH 호스트 키를 추가했다. 이미지 이름은 localhost/fullmoon-ee:24.6.1-netbox3.23.0-r2이며 AWX 실행환경의 pull 정책은 Never다. 이름에 localhost가 있다고 registry를 실행한 것은 아니며, K3s에 미리 import한 로컬 이미지를 사용한다.
k3s ctr images import fullmoon-ee-r2.tar
k3s ctr images list
git bundle verify fullmoon-automation.bundle
AWX에는 Git 소스 연동(Project), 최초 설치용 승인 서버 목록, NetBox 기반 대상 서버 목록 연동, SSH 접속 자격 증명, NetBox·Zabbix API 인증 정보, 서버 등록·결과 검증용 작업 템플릿을 만든다. 자동화 실행 흐름(Workflow)은 서버 등록 → 대상 서버 목록 동기화 → 결과 검증 순서로 연결한다. AWX 자체는 중앙 1호기 한 대에만 설치했다. 상태 확인 API의 ha 필드만으로 여러 물리 서버에 걸친 이중화가 완성됐다고 판단하지 않는다.
9. PXE·Kickstart로 빈 서버 설치
온라인망에서 구성 시
공식 Rocky Minimal ISO를 검증하고 Provision의 /var/www/html/rocky에 설치 트리를 제공한다. 실제 ISO에는 Minimal/repodata가 있다. DVD의 BaseOS/AppStream 경로를 그대로 쓰면 404가 발생한다. DHCP는 환경별 승인 MAC만 .101에 매핑한다.
fml-prod-app-01 : 08:00:27:a0:20:65 → 10.77.20.101
fml-dev-app-01 : 08:00:27:a0:30:65 → 10.77.30.101
fml-stg-app-01 : 08:00:27:a0:40:65 → 10.77.40.101
이 PC의 VirtualBox에서는 BIOS + 공식 ipxe-legacy.iso가 DHCP→HTTP kernel/initrd→Kickstart까지 동작했다. iPXE 파일은 네트워크 설치를 시작하는 부트 매체이며 OS 패키지는 Provision에서 받는다. 새 VM은 빈 32GiB 디스크, 설치 RAM 4GiB, 1 vCPU로 만들고 설치 후 1GiB로 줄인다.
Kickstart의 %pre는 MAC, DMI의 VirtualBox 식별, /dev/sda 존재, 디스크 서명 부재를 확인한 뒤에만 파티션 작업을 허용한다. root 암호는 잠그고 labadmin 공개키·sshd·sudo·chrony·firewalld를 구성한다. %post가 남긴 SSH host key는 신뢰하는 VM 콘솔 기록과 비교해 등록한다. unknown host key를 무조건 수락하지 않는다.
폐쇄망에서 구성 시
같은 ISO·부트 파일·Kickstart를 내부 HTTP에 반입한다. 대상에는 외부 NIC가 없고 DNS/NTP/패키지를 같은 환경의 Provision에서 받는다. Agent 2용 내부 저장소까지 구성하면 외부 RPM 저장소가 없어도 기본 설정을 수행할 수 있다.
물리 서버에 적용할 때에는 VirtualBox DMI guard를 그대로 제거하고 실행하면 안 된다. 승인된 실제 serial/BMC/MAC, RAID 논리 디스크와 설치 대상 WWN, UEFI/Secure Boot·NIC 드라이버를 별도 매핑한 뒤 디스크 파괴 범위를 검토해야 한다. 이 글의 실제 설치 증거는 VM이며, 물리 서버 실장비 검증 결과로 바꾸어 표현하지 않는다.
10. 자산 API·인벤토리·관제 연결
온라인망에서 구성 시
NetBox의 자산 쓰기 계정에는 필요한 VM/Device/Interface/IP/카탈로그 권한을 부여하고, 대상 서버 목록 조회 계정은 조회만 허용한다. 초기 Custom Field와 카탈로그 생성은 별도 bootstrap으로 수행한다. NetBox 4.7의 v2 토큰은 Bearer nbt_ 형식이다. Zabbix 자동화 계정은 관리 대상 그룹과 API method를 제한하고 토큰에 만료일을 둔다.
plugin: netbox.netbox.nb_inventory
api_endpoint: https://netbox.fullmoon.test
token:
type: Bearer
value: "{{ lookup('env', 'NETBOX_TOKEN') }}"
validate_certs: true
query_filters:
- tag: auto
- status: active
수집 단계는 임의 임시 디렉터리에 Python collector를 배포하고 실행 후 항상 제거한다. 대상의 실제 hostname·운영체제 고유 식별값(machine ID)·관리 NIC/IP를 승인된 대상 서버 목록과 비교한다. 값이 다르거나 기존 IP가 다른 자산에 할당되어 있으면 NetBox 변경 전에 중단한다. API token이나 /proc 환경 전체를 수집 결과에 포함하지 않는다.
API 작업은 delegate_to: localhost로 AWX 작업 실행환경(EE)에서 실행한다. 대상용 ansible_become 변수가 로컬 작업에 전파되면 EE 안에서 sudo를 찾으며 실패할 수 있으므로 다음처럼 명시한다.
delegate_to: localhost
become: false
vars:
ansible_become: false
ansible_python_interpreter: "{{ ansible_playbook_python }}"
등록 순서는 실제 자산/Interface/IPAM → Zabbix host/Proxy/template → NetBox 기반 대상 서버 목록 동기화 → 대상 서버의 기본 설정과 최신 Zabbix 데이터 검증이다. NetBox와 Zabbix API는 하나의 DB transaction이 아니므로 부분 성공 후 재실행을 지원하고, 성공한 자산을 무조건 삭제하는 보상 작업은 하지 않는다.
폐쇄망에서 구성 시
API 코드는 내부 HTTPS만 사용하므로 방식은 같다. EE의 CA, collection, Python 라이브러리, pinned SSH host key와 Git 소스 버전 식별값(커밋)이 모두 반입되어 있어야 한다. Job 실행 중 Galaxy나 pip에서 패키지를 내려받지 않는다. target에는 fullmoon-minimal·fullmoon-zabbix 저장소만 명시해 Agent를 설치한다.
ServerActive=10.77.20.10:10051
Hostname=fml-prod-app-01
TLSConnect=psk
TLSAccept=psk
TLSPSKIdentity=fml-prod-app-01
TLSPSKFile=/etc/zabbix/agent.psk
PSK 파일은 zabbix 소유 0400으로 두고 AWX 로그에는 값을 남기지 않는다. 관리 호스트 중복 여부와 모니터링 항목의 최근 수집 시각(lastclock)과 최근 수집 값(lastvalue)까지 확인한다. 호스트 생성 응답만으로 완료 처리하지 않는다.
설치 완료와 Workflow의 자동 연결
AWX 객체 번호는 설치마다 달라진다. 보완 자료의 컨트롤러는 초기 설정 스크립트가 저장한 /opt/fullmoon-lab/private/awx-objects.json의 Project·bootstrap source·Workflow 번호를 읽는다. 새 환경의 성공 상태는 빈 값으로 시작한다. 검증 글의 작업 번호를 새 환경 설정에 복사하지 않는다. 기존 성공·실패 상태를 임의 초기화하지 않고 재등록 대상 한 대를 검토한다.
중앙 1호기의 fullmoon-postinstall.timer가 승인 대상의 설치 완료를 확인한다. SSH는 해당 Bastion을 거치고 고정한 host key를 검증한다. /var/lib/fullmoon-lab/pxe-installed, hostname, 운영체제 고유 식별값(machine ID)이 일치하면 Git 소스 동기화 → 최초 설치용 승인 서버 목록 동기화 → 대상 한 대를 limit으로 지정한 Workflow를 실행한다. 작업 ID와 상태는 root만 읽는 state.json에 남긴다.
처음 생성한 SSH host key는 신뢰하는 VirtualBox serial console과 대조하여 승인 목록에 넣는다. 이 신원 승인 전에는 컨트롤러가 대기한다. 알 수 없는 키를 자동 수락하지 않는다. 이후 설치 완료 감지와 API 등록·관제 검증은 자동으로 이어진다. 물리 서버에서는 이 신원 등록을 BMC 콘솔이나 조직의 SSH CA 발급 절차와 연결해야 한다.
systemctl status fullmoon-postinstall.timer
journalctl -u fullmoon-postinstall.service --since '-30min'
# 성공: launched → AWX workflow ID → completed
# 실패: manual_review_required. 원인을 확인하기 전 자동 재등록하지 않는다.
이 컨트롤러와 AWX는 ops01에 있어 해당 노드 장애 동안 신규 서버 등록·운영 준비이 멈춘다. Git이 있는 ops02가 중단되면 새 Git 소스 동기화가 실패한다. 상태 파일을 잃거나 실행 응답 직후 프로세스가 종료되면 같은 Workflow가 다시 시도될 수 있으므로, 자산 등록 자체도 식별자와 IP 중복을 검사하는 재실행 가능한 방식으로 구성했다.
11. 접속 정보와 간단한 운영 가이드
| 기능 | 접속 경로 | 운영 확인 |
|---|---|---|
| NetBox | https://netbox.fullmoon.test | VM/Device, Interface, 대표 관리 IP, collection 상태 |
| Zabbix | https://zabbix.fullmoon.test | HA 상태, 중계 서버의 마지막 연결 시각, 모니터링 대상의 최신 데이터 |
| AWX | https://awx.fullmoon.test | 적용한 Git 소스 버전, 대상 서버 목록 갱신, 전체·개별 작업의 실행 결과 |
| Git | ssh://fmlgit@git.fullmoon.test/srv/git/fullmoon-automation.git | 읽기 전용 Git 소스 동기화 |
| 관리 SSH | loopback 22031~22038 | 해당 VM의 labadmin 공개키 인증 |
| 대상 SSH | 환경별 Bastion 경유 | 승인 host key와 .101:22 제한 |
일상 점검은 시간 동기화·디스크/메모리 → DB/Redis 역할 → App/Worker → HA/VIP → Proxy → 실제 Agent 데이터 → 최근 AWX 실패 순으로 수행한다. 컨테이너가 Up인지만 확인하지 않는다.
df -h
free -m
chronyc tracking
docker ps --format '{{.Names}} {{.Status}}'
k3s kubectl -n awx get pods
systemctl is-active haproxy keepalived
새 서버를 추가할 때에는 승인된 대상 서버 목록·MAC/IP·Bastion PermitOpen·SSH host key를 먼저 등록하고 Git에 커밋한다. Git 소스 동기화 후 해당 호스트만 limit으로 지정한다. NetBox의 대표 관리 IP와 환경 그룹을 확인한 뒤 운영 대상으로 넘긴다. 실행 중인 서버 전체를 무제한 all 대상으로 바꾸지 않는다.
비밀번호 변경과 토큰 갱신은 비밀 저장소·AWX Credential·서비스 재시작 범위를 함께 관리한다. 만료된 토큰, 변경된 SSH host key, 다른 운영체제 고유 식별값(machine ID)는 자동으로 우회하지 않는다. 노드 장애 후에는 살아남은 primary를 기준으로 복제본을 복귀시키고, 분리된 노드를 임의로 쓰기 활성화하지 않는다.
12. 백업·업데이트·검증으로 마무리
PostgreSQL 논리 백업, NetBox media, Git repository, AWX SECRET_KEY와 DB, CA/설정/비밀 자료를 각각 관리한다. VM snapshot만으로 애플리케이션 정합성 있는 백업을 대신하지 않는다. 백업 파일이 존재하는 것과 격리된 DB에 복원해 같은 자산을 읽는 것은 서로 다른 검증이다.
업데이트는 이미지 tag·digest와 EE/collection을 함께 기록하고 검증 후 진행한다. NetBox migration이나 DB major upgrade는 이전 이미지로 되돌리는 것만으로 복구되지 않을 수 있으므로 데이터 백업·복원 절차를 준비한다. 폐쇄망에서는 업데이트 반입 묶음과 checksum을 새로 만들고 이전 검증 묶음을 보존한다.
구축 완료 판정에는 자산 등록, 대상 서버 목록 동기화, 최신 관제 값, 재실행, 주소 충돌 거부, 서비스 장애 전환, Proxy 버퍼 복구, 백업 복원, 외부 통신이 없는 대상 설치를 포함한다. 실제로 수행한 시험과 미실행 항목은 검증 프로젝트에 구분해 기록한다.
함께 읽기와 구성 자료
포트폴리오 원문 · 온라인망·폐쇄망 구축 가이드 · 장애 시나리오·검증 기록
검수 보완 자료: 설정 생성기·VM 도구·실행 순서·운영 플레이북 · 보완 ZIP SHA-256
다음 기존 ZIP은 9월 실습의 소스 보관본이다. 신규 구축에는 위 보완 자료와 실행 순서를 사용한다.
실습 설정·자동화 소스 ZIP · ZIP 무결성 확인값(SHA-256)
공개 ZIP에는 구성 템플릿과 자동화 소스를 담았습니다. OS·RPM·컨테이너 이미지와 자격 증명은 포함하지 않습니다. 자신의 주소·공개 CA·승인 SSH 키·비밀 저장소로 구성한 뒤 적용합니다.