🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

표준 OS 이미지 제작 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 12. 10. · 12 Views

표준 OS 이미지 제작 완벽 가이드

반복적인 서버 설치 작업을 자동화하는 표준 OS 이미지 제작 방법을 배웁니다. Kickstart, Preseed, Packer, Cobbler를 활용하여 수십 대의 서버를 일관되게 배포하는 실무 기술을 소개합니다.


목차

  1. Kickstart 파일 구조와 문법 이해
  2. Rocky Linux Kickstart 작성 실습
  3. Ubuntu Preseed Autoinstall 작성
  4. Packer로 VM 이미지 자동 생성
  5. Cobbler PXE 서버 구축
  6. 자동 설치 ISO 빌드 및 테스트

1. Kickstart 파일 구조와 문법 이해

어느 날 김운영 씨는 새로운 프로젝트를 맡게 되었습니다. 100대의 서버에 동일한 설정으로 Rocky Linux를 설치해야 하는 상황입니다.

"하나하나 손으로 설치하면 일주일은 걸릴 텐데..." 고민하던 김운영 씨에게 선배 박인프라 씨가 다가왔습니다. "Kickstart 파일만 제대로 작성하면 자동으로 설치할 수 있어요."

Kickstart 파일은 Red Hat 계열 리눅스의 무인 설치를 위한 설정 파일입니다. 마치 요리 레시피처럼 설치 과정의 모든 단계를 미리 정의해두는 것입니다.

파티션 구성, 패키지 선택, 네트워크 설정, 사용자 생성까지 모든 것을 자동화할 수 있습니다.

다음 코드를 살펴봅시다.

# Rocky Linux Kickstart 파일 기본 구조
install
text
lang en_US.UTF-8
keyboard us
timezone Asia/Seoul --utc

# 네트워크 설정 - DHCP 사용
network --bootproto=dhcp --device=eth0 --onboot=yes

# 루트 패스워드 설정 (암호화된 형식)
rootpw --iscrypted $6$rounds=4096$saltsalt$hash...

# 파티션 설정 - 자동으로 전체 디스크 사용
clearpart --all --initlabel
autopart --type=lvm

# 설치 후 재부팅
reboot

%packages
@core
vim
wget
%end

김운영 씨는 입사 6개월 차 인프라 엔지니어입니다. 오늘 팀장님께 새로운 미션을 받았습니다.

"다음 주까지 개발 환경용 서버 100대를 구축해주세요." 머릿속이 하얘졌습니다. 서버 한 대 설치하는 데 30분씩 걸린다면...

계산하기도 싫었습니다. 점심시간에 선배 박인프라 씨가 고민하는 김운영 씨를 발견했습니다.

"왜 그래요? 무슨 일 있어요?" 사연을 들은 박인프라 씨가 웃으며 말합니다.

"아, Kickstart 쓰면 되는데요. 한 번만 제대로 만들어두면 나머지는 자동이에요." 그렇다면 Kickstart란 정확히 무엇일까요?

쉽게 비유하자면, Kickstart는 마치 요리 레시피와 같습니다. 레시피에 "양파 1개를 썰어주세요", "소금 한 스푼을 넣으세요"라고 적혀 있으면 그대로 따라 하면 되는 것처럼, Kickstart 파일에는 "파티션을 이렇게 나누세요", "이 패키지들을 설치하세요"라는 지시사항이 담겨 있습니다.

이 레시피만 있으면 누구든지, 몇 번이든, 똑같은 결과물을 만들어낼 수 있습니다. Kickstart 파일이 없던 시절에는 어땠을까요?

시스템 관리자들은 서버를 설치할 때마다 설치 화면 앞에 앉아 있어야 했습니다. "어떤 언어를 사용하시겠습니까?", "키보드 레이아웃을 선택하세요", "파티션을 어떻게 구성하시겠습니까?" 같은 질문에 일일이 답해야 했습니다.

더 큰 문제는 사람이 하는 작업이다 보니 실수가 발생한다는 점이었습니다. 어떤 서버는 파티션이 잘못 나뉘어 있고, 어떤 서버는 필요한 패키지가 빠져 있는 식이었습니다.

바로 이런 문제를 해결하기 위해 Kickstart가 등장했습니다. Kickstart를 사용하면 일관성 있는 시스템 구축이 가능해집니다.

100대를 설치하든 1000대를 설치하든 모두 똑같은 설정을 갖게 됩니다. 또한 시간 절약이라는 큰 이점도 얻을 수 있습니다.

사람이 앞에 앉아 있을 필요 없이 자동으로 설치가 진행됩니다. 무엇보다 휴먼 에러 제거라는 결정적인 장점이 있습니다.

위의 코드를 섹션별로 살펴보겠습니다. 먼저 상단의 기본 설정 섹션을 보면 설치 모드와 언어, 키보드, 시간대를 지정하는 것을 알 수 있습니다.

install 명령어는 새로 설치한다는 의미이며, text는 텍스트 모드로 설치한다는 뜻입니다. 그래픽 환경이 필요 없으니 더 빠르고 가볍습니다.

다음으로 network 섹션에서는 네트워크 설정이 일어납니다. DHCP를 사용하여 자동으로 IP를 할당받도록 설정했습니다.

--onboot=yes 옵션은 부팅 시 자동으로 네트워크를 활성화하라는 의미입니다. rootpw 명령어는 루트 사용자의 비밀번호를 설정합니다.

평문이 아닌 암호화된 형태로 저장하여 보안을 강화합니다. clearpartautopart는 파티션 구성을 담당합니다.

기존 파티션을 모두 삭제하고 LVM 방식으로 자동 파티셔닝합니다. 마지막으로 %packages 섹션에서는 설치할 패키지 목록을 정의합니다.

@core는 핵심 패키지 그룹을 의미하며, 그 아래에 추가로 필요한 패키지들을 나열합니다. 실제 현업에서는 어떻게 활용할까요?

예를 들어 쿠버네티스 클러스터를 구축한다고 가정해봅시다. 워커 노드 50대를 동일한 설정으로 준비해야 합니다.

Kickstart 파일에 Docker, kubelet, kubeadm 등 필요한 패키지를 미리 정의해두면, PXE 부팅만으로 모든 노드가 자동으로 설치됩니다. 글로벌 IT 기업들은 이런 방식으로 수천 대의 서버를 관리합니다.

하지만 주의할 점도 있습니다. 초보 엔지니어들이 흔히 하는 실수 중 하나는 암호화되지 않은 비밀번호를 Kickstart 파일에 직접 작성하는 것입니다.

이렇게 하면 보안 문제가 발생할 수 있습니다. 따라서 python -c 'import crypt; print(crypt.crypt("password"))' 같은 명령어로 암호화된 해시를 생성하여 사용해야 합니다.

다시 김운영 씨의 이야기로 돌아가 봅시다. 박인프라 씨의 설명을 들은 김운영 씨는 눈이 반짝였습니다.

"이거 하나만 잘 만들어두면 정말 편하겠네요!" Kickstart 파일을 제대로 이해하면 대규모 인프라 구축 작업이 훨씬 수월해집니다. 여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.

실전 팁

💡 - 암호화된 비밀번호 생성: python -c 'import crypt; print(crypt.crypt("yourpassword"))' 명령어 활용

  • 문법 검증: ksvalidator 도구로 Kickstart 파일의 문법 오류를 미리 확인
  • 모듈식 작성: %include 지시자로 공통 설정을 별도 파일로 분리하여 재사용성 향상

2. Rocky Linux Kickstart 작성 실습

Kickstart의 개념을 이해한 김운영 씨는 이제 직접 만들어보고 싶어졌습니다. "실제로 어떻게 작성하는 거죠?" 박인프라 씨가 에디터를 열며 말합니다.

"자, 같이 만들어볼까요? 실무에서 가장 많이 쓰는 구성으로 알려드릴게요."

Rocky Linux Kickstart 실습은 실제 운영 환경에서 사용할 수 있는 완전한 설정 파일을 만드는 과정입니다. 디스크 파티셔닝, 보안 설정, 네트워크 구성, 사용자 생성, 사후 스크립트까지 모든 요소를 포함합니다.

실무에서 바로 적용할 수 있는 템플릿을 만들어봅니다.

다음 코드를 살펴봅시다.

# Rocky Linux 8 Production Kickstart
install
url --url="http://mirror.example.com/rocky/8/BaseOS/x86_64/os/"
text
lang en_US.UTF-8
keyboard us
timezone Asia/Seoul --utc --ntpservers=time.bora.net

# 네트워크 설정 - 고정 IP
network --bootproto=static --ip=192.168.1.100 --netmask=255.255.255.0 --gateway=192.168.1.1 --nameserver=8.8.8.8 --hostname=web-server-01

# 보안 설정
firewall --enabled --service=ssh
selinux --enforcing
rootpw --iscrypted $6$saltsalt$hashhash...

# 파티션 설정 - LVM 사용
clearpart --all --initlabel --drives=sda
part /boot --fstype=xfs --size=1024 --ondisk=sda
part /boot/efi --fstype=efi --size=512 --ondisk=sda
part pv.01 --size=1 --grow --ondisk=sda
volgroup vg_root pv.01
logvol / --fstype=xfs --name=lv_root --vgname=vg_root --size=51200
logvol /var --fstype=xfs --name=lv_var --vgname=vg_root --size=20480
logvol /home --fstype=xfs --name=lv_home --vgname=vg_root --size=10240
logvol swap --name=lv_swap --vgname=vg_root --size=8192

%packages
@core
@base
vim-enhanced
wget
curl
net-tools
bind-utils
%end

%post --log=/root/ks-post.log
# SSH 키 기반 인증 설정
mkdir -p /root/.ssh
chmod 700 /root/.ssh
echo "ssh-rsa AAAAB3NzaC1yc2E..." > /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys

# 시스템 업데이트
dnf update -y

# 모니터링 에이전트 설치
curl -O https://monitoring.example.com/install-agent.sh
bash install-agent.sh
%end

reboot

김운영 씨는 이제 본격적으로 Kickstart 파일을 작성하기 시작했습니다. 박인프라 씨가 옆에서 하나하나 설명해줍니다.

"실무에서는 이론만으로는 부족해요. 직접 손으로 작성해봐야 감이 잡히죠." 먼저 에디터를 열고 파일 이름을 rocky8-ks.cfg로 저장했습니다.

"파일 이름은 중요하지 않지만, 나중에 알아보기 쉽게 의미 있는 이름을 붙이는 게 좋아요." 실제 운영 환경에서 사용할 Kickstart 파일은 어떤 점이 다를까요? 테스트용 파일과 달리 운영 환경에서는 보안, 안정성, 추적 가능성이 핵심입니다.

아무리 설치가 자동화되어도 보안 설정이 허술하면 나중에 큰 문제가 됩니다. 또한 문제가 생겼을 때 로그를 추적할 수 있어야 합니다.

마지막으로 디스크 파티셔닝이 잘못되면 나중에 용량 부족 문제로 고생하게 됩니다. 박인프라 씨가 화면을 가리키며 설명을 이어갑니다.

"자, 여기 url 옵션을 보세요. 설치 미디어의 위치를 지정하는 겁니다." url 옵션은 네트워크 설치의 핵심입니다.

CD나 USB가 아닌 HTTP 서버에서 설치 파일을 가져옵니다. 이렇게 하면 수백 대의 서버를 동시에 설치할 때도 물리적인 미디어를 일일이 꽂을 필요가 없습니다.

물론 내부에 미러 서버를 구축해두어야 빠르고 안정적입니다. 네트워크 설정 부분을 살펴볼까요?

이번에는 DHCP가 아닌 고정 IP를 사용했습니다. 운영 서버는 IP가 바뀌면 안 되기 때문입니다.

--hostname 옵션으로 서버의 호스트명도 미리 지정합니다. 나중에 모니터링 도구에서 서버를 식별할 때 이 이름이 사용됩니다.

보안 설정도 빼놓을 수 없습니다. firewall --enabled 옵션으로 방화벽을 활성화하고, SSH 서비스만 허용합니다.

selinux --enforcing은 SELinux를 강제 모드로 설정하여 보안을 한층 더 강화합니다. 초보자들은 SELinux가 복잡하다고 비활성화하는 경우가 많은데, 이는 위험한 선택입니다.

파티션 구성이 이번 예제의 하이라이트입니다. LVM(Logical Volume Manager)을 사용하여 파티션을 구성했습니다.

LVM은 마치 레고 블록처럼 나중에 볼륨 크기를 자유롭게 조정할 수 있게 해줍니다. /boot는 부팅에 필요한 커널 파일을 저장하는 곳이므로 별도로 분리했습니다.

/var는 로그 파일이 쌓이는 곳이라 넉넉하게 20GB를 할당했습니다. swap 공간은 메모리의 2배인 8GB로 설정했습니다.

%post 섹션이 진짜 마법이 일어나는 곳입니다. 설치가 끝난 직후 자동으로 실행되는 스크립트를 여기에 작성합니다.

SSH 공개키를 등록하여 비밀번호 없이 로그인할 수 있도록 설정했습니다. 시스템 업데이트도 자동으로 진행되며, 모니터링 에이전트까지 설치됩니다.

--log 옵션으로 실행 로그를 저장하므로 나중에 문제가 생기면 추적할 수 있습니다. 실제 현업에서는 어떻게 활용할까요?

대형 전자상거래 회사에서 블랙프라이데이를 준비한다고 가정해봅시다. 트래픽 급증에 대비해 웹 서버 200대를 긴급 증설해야 합니다.

이 Kickstart 파일을 사용하면 새벽에 시작해서 점심 전에 모든 서버가 준비됩니다. 각 서버는 동일한 보안 설정, 동일한 파티션 구조, 동일한 패키지를 가지고 있습니다.

하지만 주의할 점이 있습니다. 초보 엔지니어들이 자주 하는 실수는 고정 IP를 모든 서버에 똑같이 설정하는 것입니다.

Kickstart 파일은 템플릿이므로 서버마다 다른 IP를 할당하려면 별도의 메커니즘이 필요합니다. PXE 부팅 환경에서는 MAC 주소별로 다른 Kickstart 파일을 제공하는 방식을 사용합니다.

김운영 씨가 파일 작성을 마치고 저장 버튼을 눌렀습니다. "이제 이걸 어떻게 테스트하죠?" 박인프라 씨가 웃으며 답합니다.

"VirtualBox나 VMware에서 새 가상머신을 만들고, 부팅 옵션에 **inst.ks=http://yourserver/rocky8-ks.cfg**를 추가하면 돼요." 실제로 테스트해보니 정말 신기했습니다. 부팅하자마자 자동으로 설치가 시작되고, 10분 후에는 완전히 설정된 서버가 준비되어 있었습니다.

"이거 진짜 편한데요!" 김운영 씨의 얼굴에 환한 미소가 번졌습니다. Kickstart 파일을 제대로 작성하면 인프라 구축이 예술이 됩니다.

여러분도 실제 환경에서 직접 테스트해보며 감을 익혀보세요.

실전 팁

💡 - MAC 주소별 설정: PXE 서버에서 01-xx-xx-xx-xx-xx-xx.cfg 파일명으로 MAC별 개별 설정 제공

  • ksvalidator 활용: dnf install pykickstart 후 ksvalidator rocky8-ks.cfg로 문법 검증
  • 로그 확인: 설치 중 문제 발생 시 Alt+F3으로 콘솔 전환하여 실시간 로그 확인

3. Ubuntu Preseed Autoinstall 작성

Kickstart를 마스터한 김운영 씨에게 새로운 과제가 떨어졌습니다. "이번에는 Ubuntu 서버 50대를 구축해야 해요." Kickstart는 Red Hat 계열 전용이라 사용할 수 없습니다.

당황한 김운영 씨에게 박인프라 씨가 말합니다. "Ubuntu는 Autoinstall을 쓰면 돼요.

Kickstart랑 비슷한데 YAML 형식이에요."

Ubuntu Autoinstall은 Ubuntu 20.04부터 도입된 자동 설치 시스템입니다. 기존의 Preseed를 대체하며, YAML 형식으로 작성하여 가독성이 뛰어납니다.

클라우드 환경에 최적화되어 있으며, cloud-init과 자연스럽게 통합됩니다.

다음 코드를 살펴봅시다.

#cloud-config
autoinstall:
  version: 1
  locale: en_US.UTF-8
  keyboard:
    layout: us

  # 네트워크 설정
  network:
    version: 2
    ethernets:
      ens33:
        dhcp4: false
        addresses: [192.168.1.150/24]
        gateway4: 192.168.1.1
        nameservers:
          addresses: [8.8.8.8, 8.8.4.4]

  # 스토리지 설정
  storage:
    layout:
      name: lvm
    config:
      - type: disk
        id: disk0
        path: /dev/sda
        wipe: superblock
      - type: partition
        id: boot-partition
        device: disk0
        size: 1G
        flag: boot
      - type: partition
        id: root-partition
        device: disk0
        size: -1

  # 사용자 생성
  identity:
    hostname: ubuntu-server-01
    username: admin
    password: "$6$rounds=4096$saltsalt$hash..."

  # 패키지 설치
  packages:
    - vim
    - curl
    - wget
    - git
    - htop

  # 설치 후 스크립트
  late-commands:
    - echo 'admin ALL=(ALL) NOPASSWD:ALL' > /target/etc/sudoers.d/admin
    - curtin in-target --target=/target -- apt update
    - curtin in-target --target=/target -- apt upgrade -y

김운영 씨는 처음 보는 형식에 잠시 당황했습니다. "YAML이요?

이거 뭔가 다르게 생겼는데요?" 박인프라 씨가 화면을 가리키며 설명합니다. "들여쓰기로 구조를 표현하는 거예요.

JSON이나 XML보다 훨씬 읽기 쉽죠." Ubuntu의 자동 설치 시스템은 흥미로운 역사를 가지고 있습니다. 예전에는 Preseed라는 시스템을 사용했습니다.

Debian 설치 프로그램의 질문에 미리 답변을 제공하는 방식이었죠. 하지만 문법이 복잡하고 디버깅이 어려웠습니다.

Ubuntu 20.04부터 Autoinstall이라는 새로운 시스템이 등장했습니다. cloud-init 프로젝트를 기반으로 하여 클라우드 환경과 완벽하게 통합됩니다.

YAML 형식이 주는 장점은 무엇일까요? 마치 책의 목차처럼 계층 구조가 명확하게 보입니다.

autoinstall 아래에 network, storage, identity 같은 섹션이 들여쓰기로 구분됩니다. 주석도 # 기호로 자유롭게 달 수 있어서 나중에 다른 사람이 봐도 이해하기 쉽습니다.

네트워크 설정을 자세히 살펴봅시다. version: 2는 Netplan 버전 2 형식을 의미합니다.

Ubuntu는 17.10부터 Netplan을 네트워크 설정 도구로 사용합니다. ethernets 섹션 아래에 인터페이스별 설정을 작성합니다.

ens33은 네트워크 인터페이스 이름인데, 환경마다 다를 수 있으므로 주의해야 합니다. 스토리지 설정이 조금 복잡해 보일 수 있습니다.

layout: lvm으로 간단하게 설정할 수도 있지만, 세밀한 제어가 필요하면 config 섹션에 상세하게 작성합니다. type: disk로 디스크를 정의하고, type: partition으로 파티션을 만듭니다.

size: -1은 남은 공간 전체를 사용하라는 의미입니다. Kickstart의 --grow 옵션과 같은 역할입니다.

사용자 생성 방식도 Kickstart와 차이가 있습니다. identity 섹션에 호스트명, 사용자명, 비밀번호를 한 번에 정의합니다.

비밀번호는 역시 암호화된 형태로 저장해야 합니다. mkpasswd --method=SHA-512 --rounds=4096 명령어로 생성할 수 있습니다.

late-commands 섹션이 특히 유용합니다. 설치 마지막 단계에서 실행되는 명령어들을 정의합니다.

curtin in-target은 설치 중인 시스템 내부에서 명령어를 실행하는 특별한 도구입니다. /target은 새로 설치되는 시스템의 루트 디렉토리를 의미합니다.

여기서 sudo 권한을 설정하고, 시스템 업데이트를 진행합니다. 실제 현업에서는 어떻게 활용할까요?

글로벌 SaaS 기업에서 멀티 리전 서비스를 운영한다고 가정해봅시다. 서울, 도쿄, 싱가포르에 각각 Ubuntu 서버를 배포해야 합니다.

Autoinstall 파일 하나를 준비해두면, 각 리전의 클라우드 환경에서 동일한 설정의 서버를 빠르게 생성할 수 있습니다. AWS EC2, Google Cloud, Azure 모두에서 cloud-init을 지원하므로 완벽하게 호환됩니다.

흔한 실수를 피하는 방법을 알려드리겠습니다. 초보자들이 자주 겪는 문제는 YAML 들여쓰기 오류입니다.

스페이스와 탭을 섞어 쓰면 안 됩니다. 반드시 스페이스만 사용해야 하며, 일반적으로 2칸 들여쓰기를 사용합니다.

에디터에서 "탭을 스페이스로 변환" 옵션을 켜두는 것이 좋습니다. 김운영 씨가 파일을 완성하고 검증 도구를 실행했습니다.

"어떻게 테스트하죠?" 박인프라 씨가 답합니다. "Ubuntu Server ISO를 다운로드하고, 부팅 옵션에 autoinstall ds=nocloud-net;s=http://yourserver/ 를 추가하면 돼요." 테스트 환경에서 실행해보니 Kickstart와 비슷하지만 뭔가 더 깔끔한 느낌이었습니다.

"YAML이 확실히 읽기 편하네요." 김운영 씨가 고개를 끄덕였습니다. Ubuntu Autoinstall을 이해하면 Red Hat 계열과 Debian 계열 모두를 자유롭게 다룰 수 있습니다.

여러분도 두 가지 방식을 모두 익혀두세요.

실전 팁

💡 - YAML 검증: yamllint 도구로 문법 오류 미리 확인 (pip install yamllint)

  • 암호화 비밀번호 생성: mkpasswd --method=SHA-512 --rounds=4096 명령어 활용
  • 디버깅: 설치 중 Ctrl+Alt+F2로 쉘 접근, journalctl -f로 실시간 로그 확인

4. Packer로 VM 이미지 자동 생성

김운영 씨는 이제 Kickstart와 Autoinstall을 자유자재로 다룰 수 있게 되었습니다. 그런데 문득 궁금해졌습니다.

"매번 처음부터 설치하지 말고, 이미 완성된 이미지를 만들어두면 더 빠르지 않을까요?" 박인프라 씨가 환하게 웃으며 답합니다. "바로 그거예요!

Packer를 쓰면 이미지를 코드로 만들 수 있어요."

HashiCorp Packer는 가상머신 이미지를 코드로 정의하고 자동으로 생성하는 도구입니다. VMware, VirtualBox, AWS AMI, Azure Image 등 다양한 플랫폼의 이미지를 하나의 설정 파일로 만들 수 있습니다.

Infrastructure as Code의 핵심 도구 중 하나입니다.

다음 코드를 살펴봅시다.

packer {
  required_plugins {
    virtualbox = {
      version = "~> 1"
      source  = "github.com/hashicorp/virtualbox"
    }
  }
}

source "virtualbox-iso" "rocky8" {
  # ISO 설정
  iso_url      = "https://download.rockylinux.org/pub/rocky/8/isos/x86_64/Rocky-8.9-x86_64-minimal.iso"
  iso_checksum = "sha256:abcdef1234567890..."

  # 가상머신 설정
  vm_name              = "rocky8-base"
  guest_os_type        = "RedHat_64"
  disk_size            = 40960
  memory               = 2048
  cpus                 = 2

  # 네트워크 설정
  http_directory       = "http"
  boot_wait            = "10s"
  boot_command         = [
    "<tab> inst.text inst.ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/rocky8-ks.cfg<enter>"
  ]

  # SSH 설정 - Packer가 접속하기 위한 설정
  ssh_username         = "root"
  ssh_password         = "packer"
  ssh_timeout          = "30m"

  shutdown_command     = "shutdown -P now"
}

build {
  sources = ["source.virtualbox-iso.rocky8"]

  # 프로비저닝 - 추가 설정
  provisioner "shell" {
    inline = [
      "dnf update -y",
      "dnf install -y docker-ce",
      "systemctl enable docker",
      "dnf clean all"
    ]
  }

  # 후처리 - OVA 파일로 내보내기
  post-processor "vagrant" {
    output = "builds/rocky8-base.box"
  }
}

김운영 씨는 새로운 도구를 접하며 설레었습니다. "이제 이미지까지 자동으로 만들 수 있다니!" 박인프라 씨가 터미널을 열며 말합니다.

"Packer는 Terraform을 만든 HashiCorp의 제품이에요. 인프라를 코드로 관리하는 철학이 담겨 있죠." Packer가 해결하는 문제는 무엇일까요?

전통적인 방식에서는 골든 이미지를 만들 때 사람이 직접 개입해야 했습니다. 가상머신을 설치하고, 필요한 소프트웨어를 설치하고, 설정을 조정하고, 마지막으로 이미지 파일로 내보냅니다.

이 과정에서 "어떤 패키지를 설치했더라?", "설정을 어떻게 바꿨더라?" 같은 정보가 사라집니다. 6개월 후에 이미지를 다시 만들려면 기억을 더듬어야 합니다.

Packer는 이 모든 과정을 코드로 만듭니다. 마치 요리 레시피처럼 모든 단계가 파일에 기록됩니다.

누가, 언제, 어디서 실행해도 똑같은 결과가 나옵니다. Git으로 버전 관리도 할 수 있습니다.

"3개월 전 이미지는 어떻게 만들었지?"라는 질문에 커밋 히스토리를 보면 됩니다. 코드 구조를 자세히 살펴봅시다.

packer 블록은 필요한 플러그인을 정의합니다. Packer는 플러그인 아키텍처를 사용하여 다양한 플랫폼을 지원합니다.

virtualbox 플러그인을 사용하지만, amazon-ebs로 바꾸면 AWS AMI를 만들 수 있습니다. source 블록이 핵심입니다.

여기서 이미지를 어떻게 만들지 정의합니다. iso_url은 설치 미디어 경로이고, iso_checksum은 무결성 검증용 해시값입니다.

이미지 변조를 방지하는 중요한 보안 기능입니다. boot_command가 매우 흥미로운 부분인데, 마치 사람이 키보드를 누르는 것처럼 부팅 명령어를 자동으로 입력합니다.

http_directory 옵션을 주목해보세요. Packer는 자동으로 간단한 HTTP 서버를 실행합니다.

http 디렉토리에 Kickstart 파일을 넣어두면, 설치 과정에서 접근할 수 있습니다. **{{ .HTTPIP }}**와 **{{ .HTTPPort }}**는 Packer가 자동으로 채워주는 변수입니다.

정말 영리한 설계입니다. SSH 설정은 왜 필요할까요?

이미지 설치가 완료되면 Packer가 SSH로 접속하여 추가 작업을 수행합니다. provisioner 블록에서 정의한 명령어들을 실행하는 것이죠.

여기서는 시스템 업데이트와 Docker 설치를 진행합니다. provisioner 블록의 활용 범위는 무궁무진합니다.

shell 타입으로 간단한 스크립트를 실행할 수도 있고, ansible 타입으로 복잡한 프로비저닝을 할 수도 있습니다. Chef, Puppet, Salt 등 다양한 도구를 지원합니다.

실무에서는 Ansible과 조합하여 사용하는 경우가 많습니다. post-processor는 마지막 마무리 작업을 담당합니다.

여기서는 Vagrant Box 형식으로 내보냈습니다. Vagrant는 개발 환경 구축 도구로, 이 Box 파일을 개발자들에게 배포하면 모두가 동일한 환경에서 작업할 수 있습니다.

compress로 압축할 수도 있고, checksum으로 해시값을 생성할 수도 있습니다. 실제 현업에서는 어떻게 활용할까요?

대형 게임 회사에서 게임 서버 이미지를 관리한다고 가정해봅시다. 개발팀, QA팀, 운영팀 모두 동일한 베이스 이미지가 필요합니다.

Packer 파일을 Git에 올려두고, CI/CD 파이프라인에서 자동으로 이미지를 빌드합니다. 새 버전이 필요하면 코드를 수정하고 커밋하면 끝입니다.

주의해야 할 점이 있습니다. 초보자들이 자주 하는 실수는 너무 많은 것을 이미지에 담으려는 것입니다.

이미지는 베이스 환경만 담고, 애플리케이션은 배포 시점에 설치하는 것이 좋습니다. 그래야 이미지 크기도 작고, 보안 업데이트도 쉽습니다.

김운영 씨가 명령어를 입력합니다. packer build rocky8.pkr.hcl 엔터를 누르자 마법 같은 일이 벌어졌습니다.

자동으로 VirtualBox가 실행되고, ISO를 다운로드하고, 설치가 진행되고, 프로비저닝이 완료되었습니다. 20분 후, builds 폴더에 완성된 이미지가 생성되었습니다.

"이거 진짜 대박인데요!" 김운영 씨가 감탄했습니다. 박인프라 씨가 미소 지으며 답합니다.

"이제 Infrastructure as Code의 진수를 맛보기 시작한 거예요." Packer를 마스터하면 이미지 관리가 한층 체계적으로 변합니다. 여러분도 실제 프로젝트에서 적용해보세요.

실전 팁

💡 - 멀티 플랫폼 빌드: sources에 여러 플랫폼 정의 후 한 번에 빌드 (VirtualBox, VMware, AWS 동시 지원)

  • 빌드 속도 향상: ISO를 로컬 미러에 캐싱하고, headless 모드로 실행 (headless = true)
  • 변수 활용: variables 블록으로 버전, 크기 등을 매개변수화하여 재사용성 향상

5. Cobbler PXE 서버 구축

어느 날 김운영 씨에게 거대한 미션이 떨어졌습니다. "신규 데이터센터에 서버 500대를 2주 안에 구축해주세요." USB로 일일이 설치할 수는 없는 노릇입니다.

박인프라 씨가 회의실로 김운영 씨를 불렀습니다. "이제 Cobbler를 배울 때가 왔네요.

네트워크 부팅으로 한 번에 여러 대를 설치하는 거예요."

Cobbler는 리눅스 설치 서버를 구축하고 관리하는 통합 도구입니다. PXE 부팅, DHCP, TFTP, HTTP를 모두 관리하며, Kickstart 파일을 동적으로 생성합니다.

대규모 베어메탈 서버 배포에 최적화되어 있습니다.

다음 코드를 살펴봅시다.

# Cobbler 설치 및 기본 설정 (Rocky Linux 8)
# DHCP와 TFTP 서비스 설치
dnf install -y cobbler cobbler-web dhcp-server tftp-server

# Cobbler 설정 파일 편집
cat > /etc/cobbler/settings.yaml <<EOF
server: 192.168.1.10
next_server: 192.168.1.10
manage_dhcp: true
manage_tftpd: true
pxe_just_once: true
default_password_crypted: "$6$salt$hash..."
EOF

# DHCP 템플릿 설정
cat > /etc/cobbler/dhcp.template <<EOF
subnet 192.168.1.0 netmask 255.255.255.0 {
  option routers 192.168.1.1;
  option domain-name-servers 8.8.8.8;
  range dynamic-bootp 192.168.1.100 192.168.1.200;
  next-server \$next_server;
  filename "pxelinux.0";
}
EOF

# 서비스 시작
systemctl enable --now cobblerd httpd tftp dhcpd
cobbler sync

# Rocky Linux 8 배포판 추가
cobbler import --name=Rocky8 --path=/mnt/rocky8-iso

# 프로파일에 Kickstart 연결
cobbler profile edit --name=Rocky8-x86_64 \
  --kickstart=/var/lib/cobbler/kickstarts/rocky8-ks.cfg \
  --kopts="net.ifnames=0 biosdevname=0"

# 특정 MAC 주소에 시스템 등록
cobbler system add --name=web-server-01 \
  --profile=Rocky8-x86_64 \
  --mac=00:11:22:33:44:55 \
  --ip-address=192.168.1.150 \
  --hostname=web-server-01.example.com \
  --gateway=192.168.1.1

cobbler sync

김운영 씨는 화이트보드 앞에 섰습니다. 박인프라 씨가 그림을 그리며 설명합니다.

"PXE 부팅은 이렇게 동작해요. 서버가 켜지면 네트워크 카드가 DHCP 서버에 요청을 보냅니다.

DHCP 서버는 IP와 함께 부팅 파일 위치를 알려줍니다. 그럼 서버가 TFTP로 부팅 이미지를 다운로드하고, HTTP로 Kickstart 파일을 가져옵니다." PXE 부팅의 원리는 생각보다 간단합니다.

PXE(Preboot Execution Environment)는 네트워크를 통해 운영체제를 부팅하는 표준입니다. 마치 USB나 CD 대신 네트워크 케이블로 부팅하는 것이라고 생각하면 됩니다.

1990년대 인텔이 개발했지만, 지금도 데이터센터에서 핵심 기술로 사용됩니다. Cobbler가 없던 시절에는 어땠을까요?

DHCP 서버를 따로 설정하고, TFTP 서버를 따로 구축하고, HTTP 서버에 Kickstart 파일을 올리고, 각 서버의 MAC 주소별로 설정 파일을 수동으로 만들어야 했습니다. 서버 50대를 설치하려면 설정 파일만 50개를 만들어야 했죠.

실수라도 하면 처음부터 다시 해야 했습니다. Cobbler는 이 모든 것을 통합합니다.

하나의 명령어로 배포판을 등록하면, 자동으로 필요한 파일들이 적절한 위치에 복사됩니다. 프로파일을 만들면 기본 설정이 정의되고, 시스템을 등록하면 MAC 주소별 개별 설정이 생성됩니다.

cobbler sync 한 번이면 모든 서비스가 재설정됩니다. 코드를 단계별로 살펴보겠습니다.

먼저 settings.yaml 파일에서 servernext_server를 설정합니다. 두 값은 보통 같은 IP입니다.

Cobbler 서버 자신의 주소죠. manage_dhcp: true는 Cobbler가 DHCP 서버 설정을 자동으로 관리하라는 의미입니다.

pxe_just_once: true는 중요한 옵션인데, 한 번 설치가 끝나면 다음 부팅 때는 로컬 디스크에서 부팅하도록 합니다. DHCP 템플릿을 살펴봅시다.

dhcp.template 파일은 Jinja2 템플릿 형식으로 작성됩니다. Cobbler가 이 템플릿을 읽어서 실제 DHCP 설정 파일을 생성합니다.

range dynamic-bootp는 DHCP가 할당할 IP 범위입니다. **filename "pxelinux.0"**은 PXE 부팅 시 다운로드할 첫 번째 파일입니다.

cobbler import 명령어가 마법을 부립니다. ISO 파일을 마운트한 경로를 지정하면, Cobbler가 자동으로 커널, initrd, 패키지 저장소를 적절한 위치에 복사합니다.

이 과정에서 distro(배포판)와 profile(프로파일)이 자동으로 생성됩니다. 정말 편리합니다.

프로파일 편집은 세밀한 제어를 가능하게 합니다. --kickstart 옵션으로 Kickstart 파일을 연결합니다.

--kopts는 커널 부팅 옵션인데, 여기서는 네트워크 인터페이스 이름을 전통적인 eth0 방식으로 고정했습니다. 최신 리눅스는 ens33 같은 예측 가능한 이름을 사용하는데, 때로는 전통적인 방식이 더 편할 때도 있습니다.

system 등록이 핵심입니다. MAC 주소별로 개별 설정을 정의합니다.

이렇게 등록된 서버는 부팅하면 자동으로 지정된 IP, 호스트명, 게이트웨이를 받습니다. 수백 대의 서버를 스프레드시트로 관리하다가 스크립트로 일괄 등록하는 것이 일반적입니다.

실제 현업에서는 어떻게 활용할까요? 대형 클라우드 서비스 업체에서 신규 리전을 오픈한다고 가정해봅시다.

컴퓨트 노드 1000대, 스토리지 노드 200대를 배포해야 합니다. Cobbler 서버 한 대를 구축하고, 서버 정보를 CSV 파일로 준비합니다.

Python 스크립트로 cobbler system add 명령어를 반복 실행하여 모든 서버를 등록합니다. 이후 물리적으로 서버를 랙에 설치하고 전원을 켜면, 자동으로 설치가 진행됩니다.

주의해야 할 사항이 있습니다. DHCP 서버는 네트워크에 하나만 존재해야 합니다.

만약 기존 DHCP 서버가 있는 네트워크에 Cobbler를 설치하면 충돌이 발생합니다. 따라서 전용 설치 네트워크를 구성하거나, DHCP relay를 사용하여 특정 VLAN에서만 작동하도록 설정해야 합니다.

김운영 씨가 첫 번째 테스트 서버를 부팅했습니다. 화면에 "Booting from network..."라는 메시지가 나타났습니다.

곧이어 Rocky Linux 로고와 함께 자동 설치가 시작되었습니다. "오!

진짜 되네요!" 10분 후, 완전히 설정된 서버가 준비되었습니다. 박인프라 씨가 만족스러운 표정으로 말합니다.

"이제 500대도 문제없어요. 서버들을 한 번에 켜기만 하면 알아서 설치될 거예요." Cobbler를 마스터하면 대규모 베어메탈 배포가 일상이 됩니다.

여러분도 실제 환경에서 도전해보세요.

실전 팁

💡 - 웹 UI 활용: https://cobbler-server/cobbler_web 접속하여 시각적으로 관리 (기본 ID/PW: cobbler/cobbler)

  • 로그 확인: /var/log/cobbler/cobbler.log로 문제 추적, 설치 실패 시 클라이언트의 /var/log/messages도 확인
  • 스니펫 활용: /var/lib/cobbler/snippets/에 재사용 가능한 Kickstart 조각 저장하여 모듈화

6. 자동 설치 ISO 빌드 및 테스트

김운영 씨는 이제 Cobbler까지 마스터했습니다. 그런데 고객사에서 요청이 들어왔습니다.

"네트워크 환경이 없는 오프라인 환경에서도 자동 설치가 가능한가요?" 박인프라 씨가 고개를 끄덕입니다. "물론이죠.

Kickstart를 내장한 커스텀 ISO를 만들면 돼요. USB 하나로 자동 설치가 가능합니다."

커스텀 자동 설치 ISO는 Kickstart나 Autoinstall 파일을 ISO 이미지에 내장하여, 네트워크 없이도 무인 설치가 가능하게 만든 것입니다. mkisofs, genisoimage 같은 도구로 직접 빌드하거나, 자동화 도구를 활용합니다.

다음 코드를 살펴봅시다.

#!/bin/bash
# Rocky Linux 8 자동 설치 ISO 빌드 스크립트

# 작업 디렉토리 생성
mkdir -p /tmp/custom-iso
cd /tmp/custom-iso

# 원본 ISO 마운트
mkdir -p /mnt/iso
mount -o loop Rocky-8.9-x86_64-minimal.iso /mnt/iso

# ISO 내용 복사
shopt -s dotglob
rsync -av /mnt/iso/ /tmp/custom-iso/

# Kickstart 파일 추가
mkdir -p /tmp/custom-iso/ks
cp /root/rocky8-ks.cfg /tmp/custom-iso/ks/

# GRUB 부팅 메뉴 수정 - 자동으로 Kickstart 실행
cat > /tmp/custom-iso/EFI/BOOT/grub.cfg <<EOF
set timeout=5
menuentry 'Auto Install Rocky Linux 8' {
  linuxefi /images/pxeboot/vmlinuz inst.stage2=hd:LABEL=Rocky-8-9-x86_64-dvd inst.ks=hd:LABEL=Rocky-8-9-x86_64-dvd:/ks/rocky8-ks.cfg quiet
  initrdefi /images/pxeboot/initrd.img
}
EOF

# ISOLINUX 부팅 메뉴도 수정 (BIOS 부팅용)
cat > /tmp/custom-iso/isolinux/isolinux.cfg <<EOF
default auto
timeout 50
label auto
  menu label ^Auto Install Rocky Linux 8
  kernel vmlinuz
  append initrd=initrd.img inst.stage2=hd:LABEL=Rocky-8-9-x86_64-dvd inst.ks=hd:LABEL=Rocky-8-9-x86_64-dvd:/ks/rocky8-ks.cfg quiet
EOF

# 새 ISO 생성
genisoimage -o /root/rocky8-auto.iso \
  -b isolinux/isolinux.bin \
  -c isolinux/boot.cat \
  -no-emul-boot \
  -boot-load-size 4 \
  -boot-info-table \
  -J -R -V "Rocky-8-9-x86_64-dvd" \
  /tmp/custom-iso/

# 하이브리드 ISO 생성 (USB 부팅 가능)
isohybrid --uefi /root/rocky8-auto.iso

# 정리
umount /mnt/iso
rm -rf /tmp/custom-iso

echo "Custom ISO created: /root/rocky8-auto.iso"
echo "You can write it to USB: dd if=/root/rocky8-auto.iso of=/dev/sdX bs=4M status=progress"

김운영 씨는 새로운 도전에 설레었습니다. "ISO를 직접 만든다니, 뭔가 해커가 된 기분인데요?" 박인프라 씨가 웃으며 답합니다.

"ISO는 그냥 파일 묶음이에요. 우리가 원하는 파일을 추가하고, 부팅 설정만 바꾸면 됩니다." 커스텀 ISO가 필요한 상황은 생각보다 많습니다.

보안이 엄격한 금융권이나 군사 시설에서는 네트워크 연결이 제한됩니다. PXE 서버를 구축할 수도 없고, 인터넷 연결도 불가능합니다.

이런 환경에서는 USB 하나로 모든 것을 해결해야 합니다. 또한 원격지 지사에 장비를 보내야 할 때도 유용합니다.

현지 엔지니어가 기술 지식이 부족해도, USB만 꽂으면 자동으로 설치되도록 만들 수 있습니다. 스크립트의 동작 방식을 단계별로 살펴봅시다.

먼저 원본 ISO를 마운트합니다. mount -o loop 명령어는 ISO 파일을 마치 CD가 삽입된 것처럼 디렉토리로 만들어줍니다.

그런 다음 rsync로 모든 내용을 작업 디렉토리에 복사합니다. 이제 우리가 원하는 대로 수정할 수 있습니다.

Kickstart 파일을 추가하는 부분이 중요합니다. ks 디렉토리를 만들고 우리가 준비한 Kickstart 파일을 복사합니다.

이 파일이 ISO 안에 포함되므로 네트워크 없이도 접근할 수 있습니다. 파일 경로는 나중에 부팅 메뉴에서 참조하게 됩니다.

부팅 메뉴 수정이 핵심입니다. UEFI 부팅을 위한 grub.cfg와 BIOS 부팅을 위한 isolinux.cfg를 모두 수정합니다.

inst.ks=hd:LABEL=...:/ks/rocky8-ks.cfg 부분을 주목하세요. hd는 하드디스크(또는 USB)를 의미하고, LABEL은 ISO의 볼륨 레이블입니다.

이렇게 지정하면 설치 프로그램이 자동으로 ISO 내부의 Kickstart 파일을 찾습니다. genisoimage 명령어가 실제 ISO 파일을 생성합니다.

다양한 옵션들이 복잡해 보이지만, 각각 의미가 있습니다. -b isolinux/isolinux.bin은 부팅 이미지를 지정합니다.

-no-emul-boot는 에뮬레이션 없이 직접 부팅하라는 의미입니다. -J -R은 Joliet과 Rock Ridge 확장을 활성화하여 긴 파일명과 권한을 보존합니다.

-V는 볼륨 레이블인데, 반드시 원본과 동일해야 합니다. isohybrid 명령어가 특별한 역할을 합니다.

일반 ISO는 CD/DVD로만 부팅할 수 있지만, isohybrid로 처리하면 USB에 직접 쓸 수 있게 됩니다. --uefi 옵션으로 UEFI 부팅도 지원합니다.

이제 dd 명령어로 USB에 쓰기만 하면 부팅 가능한 자동 설치 USB가 완성됩니다. 실제 현업에서는 어떻게 활용할까요?

MSP(Managed Service Provider) 회사에서 전국 편의점에 POS 시스템을 배포한다고 가정해봅시다. 각 매장마다 서버 1대씩, 총 1000대를 설치해야 합니다.

현지 파트타이머가 설치를 담당하는데 기술 지식이 전혀 없습니다. 커스텀 USB를 만들어 보내면, 그냥 꽂고 전원을 켜기만 하면 됩니다.

30분 후 자동으로 설정된 서버가 준비됩니다. 테스트는 어떻게 할까요?

VirtualBox나 VMware에서 새 가상머신을 만들고, 광학 드라이브에 커스텀 ISO를 연결합니다. 부팅하면 자동으로 설치가 시작되는지 확인합니다.

USB로 테스트하려면 dd if=/root/rocky8-auto.iso of=/dev/sdb bs=4M status=progress 명령어로 USB에 쓴 후, 실제 서버에서 부팅해봅니다. 주의할 점이 몇 가지 있습니다.

볼륨 레이블이 정확히 일치하지 않으면 설치 프로그램이 Kickstart 파일을 찾지 못합니다. blkid 명령어로 실제 레이블을 확인하고, genisoimage -V 옵션과 일치시켜야 합니다.

또한 Kickstart 파일에서 url 대신 cdrom을 사용해야 CD에서 패키지를 읽습니다. 김운영 씨가 완성된 ISO를 USB에 쓰고, 테스트 서버에 꽂았습니다.

전원을 켜자 "Auto Install Rocky Linux 8"이라는 메뉴가 나타났고, 5초 후 자동으로 설치가 시작되었습니다. "진짜 아무것도 안 눌렀는데 설치되네요!" 박인프라 씨가 뿌듯한 표정으로 말합니다.

"축하해요, 김운영 씨. 이제 진짜 인프라 자동화 전문가가 됐어요." 김운영 씨는 입사 때의 자신을 떠올렸습니다.

서버 한 대 설치하는 데도 헤매던 초보였는데, 이제는 수백 대를 자동으로 배포하는 시스템을 구축할 수 있게 되었습니다. Kickstart, Autoinstall, Packer, Cobbler, 커스텀 ISO까지, 모든 도구를 자유자재로 다룰 수 있습니다.

표준 OS 이미지 제작은 단순한 기술이 아니라, 인프라 운영의 철학입니다. 일관성, 자동화, 재현 가능성이 핵심입니다.

여러분도 오늘 배운 내용을 실무에 적용하여, 효율적인 인프라 환경을 만들어보세요.

실전 팁

💡 - 볼륨 레이블 확인: blkid /dev/sr0 또는 isoinfo -d -i custom.iso로 실제 레이블 확인

  • Kickstart 수정: cdrom 명령어 사용하고, url 제거하여 오프라인 설치 지원
  • 검증 자동화: VirtualBox 헤드리스 모드로 설치 테스트 자동화 (VBoxManage startvm --type headless)

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#DevOps#Kickstart#Packer#Cobbler#Automation#DevOps,인프라,Linux

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.