7장: Packaging Software in Images (이미지로 소프트웨어 패키징하기)
이 장에서는 컨테이너 이미지의 빌드 과정을 수동으로 경험하고, 이미지와 레이어의 상호작용, 그리고 이미지 설계 시 고려할 점들을 다룹니다. 또한 간단한 "Hello, World" 예제에서 시작하여 실제 소프트웨어(Git)를 설치해보며, 컨테이너 파일 시스템을 변경하고 그 결과를 새로운 이미지로 커밋하는 과정을 체계적으로 이해할 수 있습니다.
핵심 목표:
- 컨테이너 내부에서 소프트웨어를 설치하거나 변경하고, 이를 커밋(commit)하여 새로운 이미지를 빌드하는 실습 과정을 통해 이미지를 수동 생성하는 워크플로를 익힙니다.
- 이미지 레이어, 파일 시스템 변화, 그리고 이미지 크기 관리 문제를 심층적으로 이해하고, 더 나은 이미지 설계 전략을 고민합니다.
- 향후 Dockerfile 기반의 자동화된 빌드(8장에서 다룸)를 대비하여, 이미지 빌드 과정의 기초를 다집니다.
이미지 빌드 수동 워크플로
컨테이너 이미지를 빌드하는 전형적인 수동 과정은 다음과 같습니다.
- 베이스 이미지 선택: 예를 들어
ubuntu:latest
나busybox:latest
같은 기존 이미지에서 컨테이너를 생성합니다. - 컨테이너 내부 변경: 컨테이너에서 소프트웨어를 설치하거나, 파일을 추가/수정/삭제하는 등의 작업을 수행합니다.
- 변경사항 커밋(commit): 수정된 컨테이너 상태를 새로운 이미지로 커밋하여, 변경사항을 반영한 새 이미지를 생성합니다.
docker container commit
명령을 통해 컨테이너의 현재 상태(파일 시스템 및 메타데이터 변화)를 새로운 이미지에 반영할 수 있습니다. 이는 임시 수정사항을 영구화하고, 다른 사용자나 다른 환경에서 재사용할 수 있도록 만듭니다.
예제: "Hello, World" 추가에서 Git 설치까지
간단한 예로, 빈 ubuntu:latest
컨테이너를 띄운 뒤 /HelloWorld
라는 파일을 추가하고, 그 컨테이너를 커밋하면 hw_image라는 새 이미지를 얻을 수 있습니다. 이 과정을 통해 이미지 빌드 흐름을 익혔다면, 좀 더 실용적인 사례로 Git 설치를 들 수 있습니다.
ubuntu:latest
에서 컨테이너를 실행한 뒤apt-get install git
으로 Git을 설치합니다.- 컨테이너 내에서 Git 설치가 끝나면,
exit
로 쉘을 종료합니다. 컨테이너는 중지되지만 변경사항은 유니온 파일 시스템 상에 기록되어 있습니다. docker container commit
명령을 사용해 이 컨테이너로부터ubuntu-git
이라는 이름의 새 이미지를 생성합니다. 이제ubuntu-git
이미지를 기반으로 컨테이너를 띄우면 Git이 설치된 상태로 시작할 수 있습니다.
이렇게 이미지에 특정 소프트웨어를 포함시키는 과정을 수동으로 확인함으로써, 이미지가 어떻게 형성되는지 감각을 기를 수 있습니다.
파일 시스템 변화와 유니온 파일 시스템(UFS)
컨테이너 파일 시스템은 유니온 파일 시스템을 통해 여러 레이어가 겹쳐진 형태로 구성됩니다. 각 레이어는 읽기 전용이며, 변경사항(파일 추가/수정/삭제)은 항상 새로운 상위 레이어로 기록됩니다. 이로 인해 발생하는 특징은 다음과 같습니다.
- 파일 추가: 상위 레이어에 새로 추가(A)로 표시됩니다.
- 파일 수정(변경): 상위 레이어에 변경(C)으로 표시되며, 원래 하위 레이어의 해당 파일을 덮어씌우는 형태로 작동합니다. 수정 시에는 카피 온 라이트(Copy-on-Write)로 인해 파일 전체가 상위 레이어로 복사됩니다.
- 파일 삭제: 삭제(D)로 표시되며, 실질적으로 하위 레이어에 존재하는 해당 파일을 숨기는 식으로 구현됩니다.
docker container diff
명령을 사용하면 특정 컨테이너에서 어떤 파일 변경이 일어났는지 A/C/D 표시로 확인할 수 있습니다.
이미지, 레이어, 레포지토리, 태그의 관계
- 이미지(Image): 여러 레이어가 쌓인 결과물이며, 최상위 레이어에서 시작해서 부모 레이어를 따라 내려가는 경로로 정의됩니다.
- 레이어(Layer): 불변(immutable)한 파일 시스템 상태 스냅샷. 각 레이어는 부모 레이어 위에 쌓여 최종 이미지를 구성합니다.
- 레포지토리(Repository): 특정 이미지(레이어 스택)에 인간이 읽기 쉬운 이름을 붙여서 관리하는 버킷입니다. 예:
myuser/myrepo
- 태그(Tag): 레포지토리 내에서 이미지 버전을 식별하는 용도로 사용. 예:
myuser/myrepo:1.0
여러 버전의 이미지를 다루기 위해 태그를 다양한 형태로 붙여 서로 다른 이미지를 명확히 구분할 수 있습니다. 이로써 사용자는 긴 16진수의 이미지 ID 대신 myrepo:latest
, myrepo:v2
와 같은 식별자를 사용할 수 있습니다.
이미지 사이즈 관리와 전략
이미지 레이어가 늘어나고 파일 추가/삭제/변경이 반복되면 이미지 크기가 불필요하게 커질 수 있습니다. 예를 들어, apt-get install
로 패키지를 설치했다가 다시 제거하더라도, 이전 레이어 어딘가에는 설치된 파일들이 남아 있을 수 있습니다. 이는 최종 이미지에 부정적인 영향을 미칩니다.
이미지 크기를 최소화하기 위한 방법:
- 불필요한 파일, 캐시, 패키지를 최소화하는 빌드 전략 수립.
- 필요하다면
docker container export
와docker import
를 통해 평탄화(flat)된 단일 레이어 이미지를 생성해 볼 수도 있습니다. 단, 이는 캐싱 이점이나 레이어 재사용을 포기하는 대가를 치릅니다. - 상황에 따라 "from scratch"를 통해 아주 작은 베이스 이미지부터 시작할 수도 있습니다.
파일 시스템 평탄화 (Flat Images)
docker container export
를 사용하면 컨테이너 파일 시스템을 tar
아카이브로 추출할 수 있고, docker import
로 이 tar
아카이브를 다시 새로운 이미지로 만들 수 있습니다. 이 방법을 사용하면 단 하나의 레이어만 가진 매우 간결한 이미지를 만들 수 있습니다. 정적으로 링크된 실행 파일만을 포함하는 아주 작고 심플한 이미지를 만드는 데 적합합니다. 하지만 이 경우 레이어 캐싱 이점을 잃기 때문에 상황에 맞게 사용할지 판단해야 합니다.
앞으로 나아가기
이 장에서는 Dockerfile 없이 수동으로 이미지 빌드 과정을 경험하고, 이미지/레이어/리포지토리/태그의 상호작용과 파일 시스템 변화를 깊이 이해했습니다. 또한 이미지 크기 문제를 다루고, flat 이미지와 같은 전략도 언급했습니다.
다음 장(8장)에서는 Dockerfile을 통한 자동화된 빌드 방식을 다룹니다. Dockerfile 사용 시 매번 수동으로 반복하던 작업을 선언적으로 관리하고 재현성 높은 빌드 파이프라인을 구축할 수 있게 됩니다. 이를 통해 이미지 빌드 프로세스를 효율적이고 체계적으로 유지할 수 있습니다.
정리:
이 장에서는 수동으로 이미지를 빌드해보며 파일 시스템 레이어의 원리와 변경사항 기록 방식을 배웠습니다. 나아가 이미지 크기 최적화 문제, flat 이미지 전략, 레포지토리와 태그를 통한 버전 관리, 그리고 향후 Dockerfile 기반 빌드 자동화를 위한 기초를 다졌습니다. 이를 통해 이미지 설계와 관리의 개념적 토대를 확보하게 되었으며, 다음 단계인 자동화 빌드로 자연스럽게 넘어갈 수 있는 준비가 되었습니다.
'Docker' 카테고리의 다른 글
Spring Boot 애플리케이션 Docker로 빌드 및 실행하기 (0) | 2024.12.10 |
---|---|
Docker in Action Chapter 8 (1) | 2024.12.09 |
Docker in Action Chapter 6 (0) | 2024.12.09 |
Docker in Action Chapter 5 (0) | 2024.12.09 |
Docker in Action Chapter 4 (0) | 2024.12.09 |