Let’s Bootc! [11] - 시리즈를 마무리하며… 전체 흐름 정리

Let’s Bootc! [11] - 시리즈를 마무리하며… 전체 흐름 정리

Summary bootc 시리즈를 통해 기술을 이해하는 여정을 회고하며, bootc 이미지의 구조와 작동 원리, 기존 도구의 재활용, 그리고 인프라 코드화의 중요성을 강조한다. 또한, bootc의 장점과 다양한 활용 가능성을 설명하고, 앞으로의 발전 방향에 대한 통찰을 공유한다.


Image

Image

[10] 전체 흐름 정리: 이미지에서 부팅까지

시리즈를 마무리하며

긴 여정이었습니다. [0]번에서 bootc를 처음 만나게 된 계기를 이야기한 뒤, [1]번에서 일단 돌아가는 시스템을 만들어보고, [2]번부터 [9]번까지 그 과정에서 생긴 의문들을 하나씩 풀어왔습니다. 이제 그 조각들을 하나로 엮어볼 차례입니다.

이 글은 기술 문서가 아닙니다. 레퍼런스가 “bootc란 무엇인가"에 대한 체계적 설명이라면, 이 글은 “내가 bootc를 이해하기까지 어떤 길을 걸었는가"에 대한 회고입니다. 독자분들이 시리즈를 다 읽고 나서 머릿속에 전체 그림이 그려지기를 바라는 마음으로 정리합니다.

[레퍼런스] 아키텍처 개요 (독립 문서, 수시 참조)

[0] 동기 - 왜 이 기술에 매료되었나
[1] 퀵스타트 - 일단 해보자 (의문 발생)
    ┌─────────────────────────────────┐
    │  [섹션: 동작 원리 이해하기]          │
    ├─────────────────────────────────┤
    │  [2] OCI와 bootc 이미지 ←── OCI 소개 포함  │
    │      ↓                            │
    │  [3] 파일시스템 구조 (핵심 분기점)      │
    │      ├──→ [4] anaconda/kickstart   │
    │      │        ↓                   │
    │      │    [5] toml 설정            │
    │      │                            │
    │      └──→ [6] OSTree/재부팅 속도     │
    └─────────────────────────────────┘
    ┌─────────────────────────────────┐
    │  [섹션: 실제 운영하기]              │
    ├─────────────────────────────────┤
    │  [7] 저장소 비교                   │
    │      ↓                            │
    │  [8] 인증 설정                     │
    │      ↓                            │
    │  [9] 데이터 관리 ←── [3]에서 /var 연결  │
    └─────────────────────────────────┘
    ┌─────────────────────────────────┐
    │  [섹션: 마무리]                    │
    ├─────────────────────────────────┤
    │  [10] 전체 흐름 정리 ←── 서사적 마무리  │
    └─────────────────────────────────┘

처음 가졌던 의문들, 어떻게 해결되었나

[1]번 퀵스타트를 따라하면서 여러 의문이 생겼습니다. 그 의문들이 이후 글에서 어떻게 해소되었는지 되짚어보겠습니다.

**"그냥 Docker 이미지인 것 같은데, 왜 부팅이 되지?"**

이 질문이 아마 가장 근본적인 것이었습니다. Containerfile로 이미지를 빌드하고, podman으로 푸시하고, 레지스트리에서 당겨오는 과정이 일반적인 컨테이너 워크플로우와 너무 비슷했기 때문입니다.

[2]번에서 이 의문을 풀었습니다. 핵심은 bootc 이미지가 OCI 표준을 따르되, 일반 애플리케이션 컨테이너와 결정적으로 다른 점이 있다는 것입니다. 애플리케이션 컨테이너는 호스트의 커널을 공유합니다. 반면 bootc 이미지는 커널과 initramfs를 이미지 내부에 포함하고 있습니다. /usr/lib/modules 디렉토리 안에 커널 모듈이 들어있고, 이것이 실제 부팅에 사용됩니다. 베이스 이미지인 quay.io/centos-bootc/centos-bootc:stream9가 이 역할을 담당합니다.

OCI 표준을 따른다는 것의 또 다른 의미도 있습니다. 기존 컨테이너 생태계의 도구와 인프라를 그대로 재활용할 수 있다는 점입니다. Podman으로 빌드하고, Docker Hub나 GHCR에 푸시하고, 같은 레이어 캐싱의 이점을 누릴 수 있습니다. 새로운 도구를 처음부터 익힐 필요가 없다는 것은 생각보다 큰 장점입니다.

**"Containerfile에서 왜 어떤 건 되고 어떤 건 안 되지?"**

Containerfile을 작성하다 보면 이상한 상황을 마주칩니다. 분명히 패키지를 설치했는데 부팅 후에 없는 경우가 있고, 설정 파일을 수정했는데 업데이트 후 되돌아가는 경우도 있습니다.

[3]번에서 이 의문을 풀었습니다. bootc 시스템의 파일시스템은 세 가지 영역으로 나뉩니다. /usr는 완전히 불변입니다. 이미지에서 온 그대로 유지되며, 런타임에 수정할 수 없습니다. /etc는 3-way merge 방식으로 동작합니다. 이미지의 기본값, 이전 배포의 기본값, 로컬 수정 사항이 병합됩니다. /var는 완전히 가변입니다. 로그, 데이터베이스, 사용자 데이터가 여기 저장됩니다.

이 구조를 이해하면 Containerfile 작성의 원칙이 보입니다. 시스템 구성요소는 /usr 아래에 두어야 하고, 설정 파일의 기본값은 /etc에 넣되 로컬 수정이 필요한 것은 별도로 관리해야 합니다. 상태를 가지는 데이터는 애초에 이미지에 넣으면 안 됩니다.

**"왜 설치 화면에 anaconda가 뜨지?"**

ISO를 구워서 부팅했을 때 나타난 화면이 너무 익숙했습니다. RHEL이나 Fedora를 설치할 때 보던 그 anaconda 설치 화면이었기 때문입니다.

[4]번에서 이 의문을 풀었습니다. bootc-image-builder는 내부적으로 RHEL 계열의 설치 프레임워크인 anaconda를 활용합니다. 새로운 설치 도구를 만드는 대신, 수십 년간 검증된 기존 도구를 재활용한 것입니다. kickstart 스크립트 역시 그대로 사용할 수 있습니다.

이것이 bootc 설계 철학의 일부라고 생각합니다. 가능한 한 기존 생태계를 재활용하고, 새로운 것은 정말 필요한 부분에만 도입합니다.

**"config.toml 파일은 정확히 무슨 역할을 하지? kickstart와는 뭐가 다른 거지?"**

bootc-image-builder를 사용할 때 toml 설정 파일을 넘겨줍니다. 그런데 kickstart도 있고 toml도 있으니 역할 구분이 헷갈렸습니다.

[5]번에서 이 의문을 풀었습니다. toml 파일은 bootc-image-builder에게 전달하는 설정입니다. 사용자 계정, SSH 키, 파티션 레이아웃, 네트워크 설정 등을 지정합니다. bootc-image-builder는 이 toml 설정을 받아서 내부적으로 kickstart를 생성하거나 직접 설치 과정에 반영합니다.

다시 말해, toml은 “무엇을 설정할 것인가"를 선언적으로 기술하고, kickstart는 “어떻게 설치할 것인가"를 절차적으로 기술합니다. toml이 상위 추상화 계층이라고 볼 수 있습니다.

**"재부팅이 왜 이렇게 빠르지?"**

bootc upgrade 후 재부팅하면 놀랍도록 빠릅니다. 전통적인 dnf upgrade 후 재부팅과는 체감이 다릅니다.

[6]번에서 이 의문을 풀었습니다. 핵심은 OSTree의 원자적 전환(atomic switch) 메커니즘입니다. OSTree는 Git과 유사한 방식으로 파일시스템을 버전 관리합니다. 업데이트할 때 새 버전의 파일시스템을 미리 준비해두고, 재부팅 시점에 단순히 루트 파일시스템의 포인터만 바꿉니다.

전통적인 패키지 업데이트는 재부팅하면서 실제 파일을 교체하고 서비스를 재시작합니다. 반면 OSTree 기반 시스템은 재부팅 전에 이미 모든 준비가 끝나있습니다. 부트로더가 새 deployment를 가리키도록 설정만 바꾸면 됩니다.

A/B 배포 구조 덕분에 롤백도 간단합니다. 이전 버전의 파일시스템이 그대로 남아있으니, 문제가 생기면 포인터만 되돌리면 됩니다.

**"bootc-image-builder 명령어의 그 긴 옵션들은 각각 무슨 의미지?"**

bootc-image-builder를 실행할 때 여러 옵션을 붙입니다. --type iso, --rootfs xfs, --local 같은 것들입니다. 처음에는 의미를 모르고 복사해서 붙여넣었습니다.

이 의문은 여러 글에 걸쳐 해소되었습니다. --type은 출력 형식을 지정합니다. ISO, QCOW2, AMI 등 다양한 형식을 지원합니다. --rootfs는 루트 파일시스템의 종류를 지정합니다. --local은 로컬에 있는 이미지를 사용한다는 의미입니다. 이 옵션이 없으면 레지스트리에서 이미지를 당겨옵니다.

  • v /var/lib/containers/storage:/var/lib/containers/storage 옵션도 중요합니다. 이것은 Podman의 이미지 저장소를 컨테이너 내부에 마운트하는 것입니다. -local 옵션을 쓸 때 필요합니다. 로컬에서 빌드한 이미지를 bootc-image-builder가 접근할 수 있게 해줍니다.
**"ISO로 굽는 것과 레지스트리에 올리는 것과 bootc switch, 이 행위들이 어디서 어떻게 연결되는 거지?"**

세 가지 행위가 있습니다. ISO를 만들어서 설치하는 것, 이미지를 레지스트리에 푸시하는 것, 기존 시스템에서 bootc switch를 실행하는 것. 이것들이 어떻게 연결되는지 처음에는 보이지 않았습니다.

되돌아보면, 이것들은 모두 같은 OCI 이미지를 다른 경로로 시스템에 적용하는 방법입니다. ISO 설치는 새 하드웨어에 처음 시스템을 구축할 때 사용합니다. 레지스트리 푸시와 bootc upgrade는 기존 bootc 시스템을 업데이트할 때 사용합니다. bootc switch는 기존 bootc 시스템을 완전히 다른 이미지로 전환할 때 사용합니다.

핵심은 모두 같은 OCI 이미지를 사용한다는 점입니다. 한 번 빌드한 이미지를 여러 경로로 배포할 수 있습니다.


전체 아키텍처: 이미지에서 부팅까지

지금까지 설명한 내용을 하나의 흐름으로 정리하면 다음과 같습니다.

[1단계: 이미지 정의]
Containerfile 작성
├── FROM quay.io/centos-bootc/centos-bootc:stream9
├── RUN dnf install ... (패키지 설치)
├── COPY ... (설정 파일 복사)
└── 커널, initramfs가 베이스 이미지에 이미 포함됨

          ↓ podman build

[2단계: 이미지 빌드]
OCI 이미지 생성
├── 레이어 구조로 저장
├── 이미지 메타데이터 포함
└── 로컬 저장소: /var/lib/containers/storage

          ↓ podman push

[3단계: 레지스트리 배포]
레지스트리에 이미지 저장
├── Docker Hub / GHCR / Quay.io / Harbor
├── OCI 표준 덕분에 어디든 호환
└── 태그로 버전 관리


[4단계: 배포 경로 분기]

┌─────────────────┬─────────────────┬─────────────────┐
│  신규 설치       │  기존 시스템 업데이트  │  시스템 전환      │
├─────────────────┼─────────────────┼─────────────────┤
│ bootc-image-    │ bootc upgrade   │ bootc switch    │
│ builder로 ISO   │                 │                 │
│ 생성            │                 │                 │
│       ↓         │       ↓         │       ↓         │
│ anaconda로 설치  │ OSTree로 새     │ OSTree로 다른   │
│ (kickstart 활용) │ deployment 생성 │ 이미지로 전환    │
└─────────────────┴─────────────────┴─────────────────┘

          ↓ 재부팅 (원자적 전환)

[5단계: 부팅된 시스템]
├── /usr: 불변, 이미지에서 옴
├── /etc: 3-way merge
├── /var: 가변, 데이터 저장
└── OSTree로 버전 관리, 롤백 가능

          ↓ 이후 업데이트 사이클로 반복

각 단계에서 핵심 기술이 어떤 역할을 하는지 정리하면 다음과 같습니다.

OCI 표준은 1단계부터 3단계까지 관여합니다. 이미지 포맷, 빌드 도구, 레지스트리 프로토콜을 표준화합니다. 덕분에 기존 컨테이너 생태계의 도구와 인프라를 그대로 쓸 수 있습니다.

anaconda/kickstart는 4단계의 신규 설치 경로에서 사용됩니다. ISO로 부팅했을 때 디스크 파티셔닝, 사용자 생성, 네트워크 설정 등을 처리합니다.

OSTree는 4단계와 5단계에서 핵심 역할을 합니다. 파일시스템을 버전 관리하고, 원자적 전환을 가능하게 하며, 롤백 기능을 제공합니다.


이 기술을 배우며 얻은 통찰

시리즈를 작성하면서 몇 가지 깨달음이 있었습니다.

Infrastructure as Code가 OS 계층까지 내려왔습니다.

애플리케이션 배포는 이미 컨테이너와 쿠버네티스로 코드화되었습니다. 인프라 프로비저닝은 Terraform 같은 도구로 코드화되었습니다. 그런데 OS 자체는 여전히 수동으로 설치하고 수동으로 패치하는 경우가 많았습니다.

bootc는 OS를 Containerfile이라는 코드로 정의합니다. 어떤 패키지가 설치되어 있는지, 어떤 설정이 적용되어 있는지가 모두 버전 관리됩니다. 더 이상 “이 서버는 언제 누가 무슨 작업을 했는지 모르겠다"는 상황이 없습니다. Containerfile을 보면 됩니다.

“수정하지 않고 교체한다"는 불변 인프라 원칙이 OS에 적용되었습니다.

전통적인 OS 관리에서는 실행 중인 시스템을 제자리에서 수정합니다. 패키지를 설치하고, 설정 파일을 바꾸고, 서비스를 재시작합니다. 시간이 지나면 시스템은 점점 “눈송이"가 됩니다. 똑같이 만들어진 서버가 없습니다.

bootc 시스템은 다릅니다. 변경이 필요하면 새 이미지를 빌드하고 교체합니다. 실행 중인 시스템을 직접 수정하지 않습니다. 모든 시스템은 이미지에 정의된 대로 동일한 상태를 가집니다.

이것은 디버깅을 쉽게 만듭니다. 문제가 생기면 이미지를 확인하면 됩니다. 개별 서버의 특수한 상태를 추적할 필요가 없습니다.

컨테이너 생태계의 힘을 실감했습니다.

bootc가 OCI 표준을 채택한 것은 탁월한 선택이었습니다. 새로운 빌드 도구를 배울 필요가 없습니다. 새로운 레지스트리 인프라를 구축할 필요가 없습니다. 새로운 이미지 배포 파이프라인을 만들 필요가 없습니다.

기존에 Docker나 Podman을 써본 사람이라면 진입 장벽이 낮습니다. GitHub Actions에서 컨테이너 이미지를 빌드하던 파이프라인을 그대로 bootc 이미지 빌드에 쓸 수 있습니다. 조직에서 이미 운영 중인 프라이빗 레지스트리가 있다면 그대로 bootc 이미지를 저장할 수 있습니다.

도구와 인프라의 재활용입니다. 이것이 새로운 기술의 채택 비용을 크게 낮춥니다.


앞으로의 가능성

[0]번에서 말했던 제 유즈케이스를 다시 떠올려봅니다.

저는 POC 환경을 자주 구축하고 해체합니다. 레거시 OS 위에 무거운 솔루션을 올렸다 내렸다 하는 일이 번거로웠습니다. 가벼운 KVM 호스트로 쓸 수 있는 OS를 원했고, 그 OS가 재현 가능하고 이식 가능하기를 바랐습니다.

bootc는 이 요구사항에 잘 맞습니다. Containerfile로 정의한 OS를 어떤 하드웨어에서든 동일하게 배포할 수 있습니다. 문제가 생기면 롤백하면 됩니다. 새 버전이 나오면 이미지를 다시 빌드하고 업그레이드하면 됩니다.

더 넓게 보면, bootc가 유용한 시나리오는 여러 가지입니다.

엣지 디바이스 관리가 대표적입니다. 수백, 수천 대의 디바이스에 동일한 OS를 배포하고 원격으로 업데이트해야 하는 상황입니다. 각 디바이스에 SSH로 접속해서 패키지를 설치하는 것은 현실적이지 않습니다. 이미지 기반 배포가 훨씬 효율적입니다.

개발 환경 표준화도 있습니다. 팀원 모두가 동일한 개발 환경을 사용하기를 원한다면, bootc 이미지로 정의할 수 있습니다. 새 팀원이 합류하면 이미지를 설치하면 됩니다.

골든 이미지 관리도 생각해볼 수 있습니다. 조직에서 표준 OS 이미지를 관리한다면, bootc 방식이 전통적인 골든 이미지 관리보다 유연합니다. Containerfile로 정의되어 있으니 변경 이력이 명확하고, 레이어 구조 덕분에 업데이트가 효율적입니다.


마무리

시리즈를 시작할 때 가졌던 의문들이 지금은 대부분 해소되었습니다. 물론 아직 깊이 파보지 못한 부분도 있습니다. OSTree의 내부 구현을 더 자세히 들여다보고 싶고, bootc-image-builder가 anaconda를 정확히 어떻게 활용하는지도 좀 더 파악하고 싶습니다.

하지만 전체 그림은 이제 보입니다. OCI 이미지로 OS를 정의하고, OSTree로 버전 관리하며, 기존 설치 도구로 배포합니다. 각 기술이 맡은 역할이 명확하고, 조합이 자연스럽습니다.

이 글을 읽으신 모든 분들께 도움이 되기를 바랍니다.


Comments

GitHub 계정으로 로그인하여 댓글을 남겨보세요. GitHub 로그인

댓글 시스템 설정이 필요합니다

GitHub Discussions 기반 댓글 시스템을 활성화하려면:

  1. Giscus 설정 페이지에서 설정 생성
  2. GISCUS_SETUP_GUIDE.md 파일의 안내를 따라 설정 완료
  3. Repository의 Discussions 기능 활성화

Repository 관리자만 설정할 수 있습니다.