CICD

[CI/CD Study 1주차] 컨테이너를 빌드하는 다양한 방법

Kimalarm 2025. 10. 19. 04:56

CoudNet@ 팀의 가시다님께서 리딩하시는 CI/CD Study 1주차 스터디 내용 정리

 

이번에는 쿠버네티스 사용에 필요한 컨테이너 이미지를 생성하는 다양한 방법에 대해서 공부할 예정입니다.
이번 글에서 사용되는 컨테이너 저장소는 Dockerhub 를 사용했습니다.



1. 컨테이너 개요

 

컨테이너는 애플리케이션을 배포 목적으로 패키징할 때 널리 사용되는 표준 형식

 

OCI(Open Container Initiative) 가 컨테이너 포맷과 런타임의 개방형 업계 표준을 만들고 있습니다.
이런 개방성 덕분에 서로 다른 운영 체제(OS), 공급 업체, 플랫폼 또는 클라우드 사이에서의 이식성과 상호 운용성을 보장하는 것입니다.

 

또한 개방성 덕분에 컨테이너를 패키징하는 많은 방법이 있는데, 다음과 같은 방법을 공부해볼 예정입니다.

  1. Docker
  2. Jib
  3. Buildah
  4. Buildpack
  5. Shipwright, Kaniko



2. Docker 를 사용한 컨테이너 빌드

 

Docker 에는 Layer, Dockerfile 개념이 존재합니다.

 

Dockerfile

 

- 사용자가 이미지를 조립하기 위해 명령행에서 호출하는 모든 명령을 담은 텍스트 문서

 

Layer

 

- 컨테이너 이미지 생성의 구성 단위
- 각 컨테이너 이미지는 Base Layer 로부터 변경 사항을 적용하여 구성
- 새로운 변경이 적용될 때마다 레이어가 추가로 커밋됨

출처: GitOps Cookbook: Container image layers

 

 

2.1. Docker 빌드 실습

 

컨테이너 빌드 실습은 모두 GitOps Cookbook 예제를 이용합니다.

 

# 예제 다운로드
git clone https://github.com/gitops-cookbook/chapters

# 파이썬 예제 이동
cd chapters/chapters/ch03/python-app

# Dockerfile 확인
cat Dockerfile

 

 

이미지 빌드

 

# Dockerhub 계정명
MYUSER=<각자 본인의 도커허브 계정명>

docker build -f Dockerfile -t docker.io/$MYUSER/pythonapp:latest .

 



2.2. Docker Image Build Cache



최초 이미지 빌드 시에는 모든 레이어 작업을 수행해야 되기 때문에 오랜 시간이 걸리지만,
2회차 이후부터는 기존 레이어 계층은 캐싱하고 신규 레이어 작업만 수행합니다.

 

각각의 레이어는 컨테이너 캐시 or 도커 캐시라 부르는 특별한 로컬 저장소에 보관됩니다.

 

 

이미지 레이어 정보는 다음과 같이 Inspect 명령어로 확인할 수 있습니다.

 

# 베이스 이미지 다운로드
docker pull registry.access.redhat.com/ubi8/python-39:latest

# 베이스 이미지 레이어
docker inspect registry.access.redhat.com/ubi8/python-39:latest | jq | grep -e "Layers" -A5

# 빌드 이미지 레이어
docker inspect $MYUSER/pythonapp:latest | jq | grep -e "Layers" -A9

 

 

 

2.3. Docker Image Push

 

생성한 이미지를 도커허브에 올려보겠습니다.

 

# Docker 로그인
docker login docker.io

# 이미지 push
docker push docker.io/$MYUSER/pythonapp:latest

 




3. Jib 를 사용한 컨테이너 빌드



Jib 는 Dockerfile 을 사용하지 않거나 Docker 를 설치할 필요 없이 컨테이너를 빌드할 수 있습니다.
Maven, Gradle 용 Jib 플러그인 사용 혹은 Jib 자바 라이브러리를 사용할 수 있습니다.

 

* Docker 빌드 흐름

- 도커 파일 작성 > 이미지 빌드 > 저장소에 이미지 푸시

 

* Jib 빌드 흐름

- 프로젝트 빌드와 동시에 이미지 생성, 저장소에 푸시

 

Jib 는 Application 을 종속 항목, 리소스, 클래스 등 별개의 레이어로 구성하고

Docker 이미지 레이어 캐싱을 활용하여 변경사항만 다시 빌드함으로써 빌드를 빠르게 유지합니다.


Jib 레이어 구성과 작은 기본 이미지전체 이미지 크기를 작게 유지하여 성능과 휴대성을 향상 시킵니다.

 

 

3.1. Jib 예제 코드

 

# Springboot 예제 코드
git clone https://github.com/gitops-cookbook/chapters
cd /chapters/chapters/ch03/springboot-app/

# 변수
M=<도커허브 계정>
MYPASSWD=<도커허브 비밀번호/토큰암호>

# Jib 를 파라미터로 수행
mvn compile com.google.cloud.tools:jib-maven-plugin:3.4.6:build \
  -Dimage=docker.io/$MYUSER/jib-example:latest \
  -Djib.to.auth.username=$MYUSER \
  -Djib.to.auth.password=$MYPASSWD \
  -Djib.from.platforms=linux/arm64

 

 

 

3.2. Jib Gradle 사용

 

Gradle 에서는 아래와 같이 사용하면 됩니다.

 

Gradle Plugin 추가 (build.gradle 설정)

 

plugins {
    // jib for container build
    id 'com.google.cloud.tools.jib'
}

 

jib 설정 (build.gradle)

 

- from : 기반 이미지 (빌드에 사용될 Base Image)
- to : 결과 이미지 (빌드 후 저장할 이미지 정보)
- container : 컨테이너 실행 환경

 

jib {
    from {
        image = 'public.ecr.aws/amazoncorretto/amazoncorretto:21-al2-generic'
//        platforms {
//            platform {
//                architecture = 'arm64'
//                os = 'linux'
//            }
//        }
    }
    to {
        image = 'xxxxxxx.dkr.ecr.ap-northeast-2.amazonaws.com/test-image' // Push 이미지 명칭
        tags = ['1010', 'latest'] // Push 이미지 태그 (멀티 태그 가능)
    }
    // 컨테이너 파라미터 지정
    container {
        // jvm 실행 옵션
        jvmFlags = [
            '-Dspring.profiles.active=dev',
            '-Dmy.property=example.value',
            '-Dfile.encoding=UTF-8',
            '-Duser.timezone=Asia/Seoul'
        ]
        ports = ['8080']
    }
}




4. 빌다(Buildah + Podman) 를 사용한 컨테이너 빌드

 

도커를 설치하거나 관리할 수 없는 경우가 있을 때, 도커 없이 컨테이너 이미지를 생성할 수 있는 도구입니다.

 

4.1. Buildah, Podman 소개

 

Podman

 

- 컨테이너를 유지 관리하고 수정하는 명령어 및 기능 (이미지 풀/푸시, 태그 지정 등)에 특화된 도구

 

Buildah

 

- 컨테이너 이미지 빌드에 특화된 도구

 

 

Podman 과 Buildah 는 상호 보완적인 관계입니다.



4.2. Docker vs Podman, Buildah

 

* Docker

- 컨테이너 이미지 생성, 실행, 배포를 모두 단일 애플리케이션 사용 (Docker)
- 루트 권한 및 데몬 필요

 

* Podman, Buildah

- 컨테이너 이미지 생성, 실행, 배포는 각각 특화된 프로젝트로 분리 (Podman, Buildah, Skepeo)
- 루트 권한 및 데몬이 필요 없음
- 도커파일 없이도 컨테이너 이미지 빌드 가능한 저수준 인터페이스 제공
- 도커 소켓을 마운트 하지 않고도 컨테이너 이미지 생성



4.3. Buildah 이미지 생성 실습

 

빌다는 리눅스 커널의 컨테이너 네이티브 기능(namespace, cgroups)에 의존하기 때문에 mac 에서는 실습이 불가합니다.
따라서 별도의 리눅스 컨테이너를 생성한 후 그 안에서 테스트를 진행했습니다.
리눅스 컨테이너는 편한대로 사용하시면 됩니다.

 

# Linux 컨테이너 내부 진입
docker exec -it myk8s-control-plane bash

# Podman (+ Buildah) 설치
apt update
mkdir -p /usr/share/man/man1
apt install podman -y

# podman 확인
podman version

# buildah 확인
buildah version

 

 

# 변수 생성
MYUSER=<도커허브 계정>

# Buildah 를 통해 Build 전용 컨테이너 다운로드 (Mac 환경이라 arm64 아키텍처 이미지를 지정)
buildah from --arch arm64 quay.io/centos/centos:latest

## Buildah 이미지 빌드 (Dockerfile 없이 Layer 생성)
buildah <수행 작업> <빌드 이미지명> <명령어>

# 1. httpd 설치
buildah run centos-working-container yum install httpd -y

# 2. index.html 파일 작성 후 컨테이너 내부로 복사
cat << EOF > index.html
<html>
    <head>
        <title>Cloudneta CICD Study</title>
    </head>
    <body>
        <h1>Hello, World!</h1>
    </body>
</html>
EOF

buildah copy centos-working-container index.html /var/www/html/index.html

# 3. 이미지 생성 완료 (Commit)
buildah config --entrypoint "/usr/sbin/httpd -DFOREGROUND" centos-working-container
buildah commit centos-working-container docker.io/$MYUSER/gitops-website

 

 

생성된 이미지 확인

 

podman images

 

 

Dockerfile 을 통한 Buildah 빌드

 

Dockerfile 을 통해서도 아래와 같이 Buildah 이미지 빌드가 가능합니다.

 

# Dockerfile 지정
buildah build -f Dockerfile -t docker.io/$MYUSER/gitops-website




5. 빌드팩(Buildpacks) 을 사용한 컨테이너 빌드

 

클라우드 네이티브 빌드팩(CNB, Cloud Native Buildpacks) 은 도커파일 없이도 앱 소스 코드를 검사하여 애플리케이션 빌드 및 실행 계획을 생성하는 실행 파일들을 제공하는 오픈소스 프로젝트입니다.

 

빌드팩은 Dockerfile 없이도 앱 소스 코드에서 OCI 호환 컨테이너 이미지를 생성할 수 있습니다.

 

출처:  https://buildpacks.io/docs/for-app-developers/concepts/buildpack

 



5.1. 빌드팩 실습

 

Mac 을 사용하므로 Homebrew 를 통해 buildpack cli 를 설치했습니다.

# Homebrew 설치
brew install buildpacks/tap/pack

# 버전 확인
pack version

 

실습 코드 확인

 

git clone https://github.com/gitops-cookbook/chapters
cd chapters/chapters/ch03/nodejs-app/

# 추천 빌더 확인
pack builder suggest

 

 

빌드팩을 이용한 빌드

 

pack build nodejs-app --platform linux/arm64 --builder heroku/builder:24

 




6. 십라이트(Shpwrite)를 사용한 컨테이너 빌드

 

십라이트는 쿠버네티스에서 컨테이너 이미지를 빌드할 수 있게 해주는 확장 가능한 프레임워크

 

십라이트는 빌다, 빌드팩, 카니코같은 유명 빌드 도구를 지원합니다.
다만, Kaniko 는 이제 업데이트가 종료되었으므로 다른 도구를 사용할 것을 권장드립니다.

 

십라이트는 쿠버네티스 스타일 API 를 사용하여 Tekton 위에서 작업을 수행합니다.



6.1. 십라이트(Shpwrite) k8s 설치

 

실습에 필요한 쿠버네티스는 kind 를 통해서 설치했습니다. (Control Plane 1대 / Worker Node 1대)

 

Tekton 설치

 

# Tekton dependency 파이프라인(pipeline) 설치
kubectl apply -f https://storage.googleapis.com/tekton-releases/pipeline/previous/v0.70.0/release.yaml

# Tekton 설치 확인
kubectl get crd

 

 

Shipwright Builds 설치

 

# Shipwright Builds Directly 설치
kubectl apply -f https://github.com/shipwright-io/build/releases/download/v0.11.0/release.yaml

# Shipwright Builds 설치 확인
kubectl get crd | grep shipwright

 

 

Shipwright Build 전략 설치

 

빌드 전략이라고 지칭하지만 십라이트에서 사용되는 빌드 도구를 의미합니다. (Buildah, Buildpack, Kaniko 등)

 

# Shipwright build strategies 빌드 전략 설치
kubectl apply -f https://github.com/shipwright-io/build/releases/download/v0.11.0/sample-strategies.yaml

 

 

 

6.2. 컨테이너 레지스트리 자격 증명 생성

 

십라이트가 빌드한 이미지를 Push 하기위해서 컨테이너 레지스트리 자격 증명이 필요합니다.
해당 자격 증명은 쿠버네티스 시크릿으로 생성할 수 있습니다.

 

# Dockerhub 자격증명을 위한 변수 지정
REGISTRY_SERVER=https://index.docker.io/v1/
REGISTRY_USER=<your_registry_user>
REGISTRY_PASSWORD=<your_registry_password>
EMAIL=<your_email>

# 시크릿 생성
kubectl create secret docker-registry push-secret \
--docker-server=$REGISTRY_SERVER \
--docker-username=$REGISTRY_USER \
--docker-password=$REGISTRY_PASSWORD \
--docker-email=$EMAIL

# 시크릿 확인
kubectl get secret

 

 

 

6.3. 빌드 객체 생성

 

십라이트의 빌드 전략(빌드 도구)가 컨테이너화할 때 사용할 빌드 객체를 생성해보겠습니다.

 

빌드가 시작될 때 빌드 객체에 정의된 내용으로 빌드하라는 것이며,
완전히 같지는 않지만 Dockerfile 과 비슷한 기능을 하는 것입니다.

 

Build 객체 생성

 

cat <<EOF | kubectl apply -f -
apiVersion: shipwright.io/v1alpha1
kind: Build
metadata:
  name: kaniko-golang-build
spec:
  source:
    url: https://github.com/shipwright-io/sample-go  # 소스 코드를 가져올 저장소
    contextDir: docker-build                         # 소스 코드가 있는 디렉터리
  strategy:
    name: kaniko                                     # 빌드에 사용할 ClusterBuildStrategy 이름
    kind: ClusterBuildStrategy
  dockerfile: Dockerfile
  output:
    image: docker.io/$REGISTRY_USER/sample-golang:latest # 결과 이미지를 저장할 장소
    credentials:
      name: push-secret                              # 레지스트리에 인증하고 이미지를 푸시하는 데 사용할 시크릿 이름  
EOF

# 빌드 객체 확인
kubectl get builds

 

BuildRun 객체 생성

 

빌드 객체는 생성되었지만 빌드가 시작된 것은 아닙니다.
BuildRun 객체를 생성해서 빌드를 시작하겠습니다.

 

cat << EOF > buildrun-go.yaml
apiVersion: shipwright.io/v1alpha1
kind: BuildRun
metadata:
  generateName: kaniko-golang-buildrun-
spec:
  buildRef:
    name: kaniko-golang-build
EOF

# 빌드 수행
kubectl create -f buildrun-go.yaml

 

 


 

컨테이너 이미지를 빌드하는 다양한 방법에 대해서 알아보았습니다.
어떠한 도구를 사용해도 문제는 없지만, 각자의 업무 환경이나 서비스 환경에 맞는 도구를 선택하는 것이 좋을 것 같습니다.