
본 정리는 macOS(Apple Silicon/Intel 공통)에서 Docker Desktop + kind 환경을 기반으로, 컨테이너 이미지를 빌드/검증/배포하는 방법을 한 번에 따라 할 수 있도록 요약한 실습 가이드다. 예시의 모든 레지스트리 경로는 docker.io/chaany로 통일했다.
3.0 들어가며
- 컨테이너는 앱·런타임·라이브러리를 계층(layer) 구조로 패키징한 표준 포맷이며, OCI(https://opencontainers.org/) 표준을 따른다.
- 개방형 표준(OCI) 덕분에 Docker, Jib, Buildah/Podman, Buildpacks, Shipwright(BuildKit) 등 다양한 도구로 이미지를 만들고 상호운용 가능하다.
- 이하 절에서는 Dockerfile, Jib(자바), Buildpacks, Shipwright(BuildKit) 를 macOS에서 수행하고, Buildah/Podman은 kind 클러스터 컨테이너 내부에서 실습하도록 변경했다.
3.1 Docker로 컨테이너 이미지 빌드/푸시 (Python 예제)

3.1.1 예제 소스 가져오기
# 예제 저장소
git clone https://github.com/gitops-cookbook/chapters
cd chapters/chapters/ch03/python-app
ls
3.1.2 Dockerfile 확인 (예제)
# ch03/python-app/Dockerfile
FROM registry.access.redhat.com/ubi8/python-39 # UBI 기반(무료), macOS arm64에서도 동작 사례 많음
ENV PORT 8080
EXPOSE 8080
WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
ENTRYPOINT ["python"]
CMD ["app.py"]
3.1.3 macOS에서 빌드/검증/푸시
# 변수
REGISTRY=docker.io
USER=chaany
APP=pythonapp
TAG=latest
# 빌드
docker build -f Dockerfile -t ${REGISTRY}/${USER}/${APP}:${TAG} .
# 이미지/레이어 확인
docker images | grep ${USER}/${APP}
docker inspect ${REGISTRY}/${USER}/${APP}:${TAG} | jq '.RootFS'
# 로컬 실행 확인
docker run -d --rm --name myweb -p 8080:8080 ${REGISTRY}/${USER}/${APP}:${TAG}
sleep 1
curl -s 127.0.0.1:8080 | head -n 5
docker logs myweb
# Docker Hub 로그인 및 푸시
docker login -u ${USER}
docker push ${REGISTRY}/${USER}/${APP}:${TAG}
# 정리
docker rm -f myweb
Docker 빌드는 레이어 캐시를 적극 재사용한다. COPY requirements.txt → RUN pip install → COPY . . 순서 최적화는 재빌드 속도를 좌우한다.
3.2 Docker 없이 자바 이미지를 만드는 Jib (Maven 플러그인)

3.2.1 macOS에 Java/Maven 설치
brew install openjdk@17 maven
java -version
mvn -version
3.2.2 예제 소스 및 Jib 실행
# 소스
cd ~/ && git clone https://github.com/gitops-cookbook/chapters jib-lab
cd jib-lab/chapters/ch03/springboot-app
# Docker 데몬 불필요, Dockerfile 불필요. 바로 원격 레지스트리로 빌드+푸시
# macOS는 일반적으로 linux/arm64 이미지를 생산하는 편이 자연스럽다.
REGISTRY=docker.io
USER=chaany
IMAGE=${REGISTRY}/${USER}/jib-example:latest
mvn -q -e \
-Dimage=${IMAGE} \
-Djib.to.auth.username=${USER} \
-Djib.to.auth.password="$(security find-generic-password -a ${USER} -s docker-hub -w 2>/dev/null || echo '<DOCKER_PAT_OR_PASSWORD>')" \
-Djib.from.platforms=linux/arm64 \
com.google.cloud.tools:jib-maven-plugin:3.4.6:build
# 확인
docker pull ${IMAGE}
docker run -d --rm --name myweb2 -p 8080:8080 ${IMAGE}
sleep 2
curl -s 127.0.0.1:8080/hello | head -n 1
docker rm -f myweb2
Jib은 앱 아티팩트(클래스/리소스/의존성)를 레이어링해 변경분만 다시 올리므로, 자바 서비스 반복개발에 유리하다.
3.3 Buildah/Podman은 kind 클러스터에서 진행 권장 (컨트롤플레인 컨테이너 내부 실습)
macOS 네이티브 환경에서 buildah/podman를 직접 운용하기보다, kind 노드 컨테이너 내부(우분투 베이스) 에서 설치·실행하는 방식이 가장 단순하다.

3.3.1 사전 준비
# kind 클러스터가 없으면 생성 (2장에서 이미 생성했다면 생략)
kind create cluster --name myk8s --image kindest/node:v1.32.8
kind get nodes
3.3.2 컨트롤플레인 컨테이너에 진입해 podman/buildah 설치
# 컨트롤플레인 컨테이너 이름 확인
docker ps --format 'table {{.Names}}\t{{.Image}}' | grep myk8s
# 컨테이너 내부 진입
docker exec -it myk8s-control-plane bash
# 컨테이너 내부 (우분투 베이스)
apt-get update
mkdir -p /usr/share/man/man1
apt-get install -y podman buildah curl jq ca-certificates
podman version
buildah version
3.3.3 Buildah로 이미지 빌드 → Podman으로 실행 → Docker Hub(chaany)로 푸시
# 컨테이너 내부 계속
# 샘플 정적 웹 서버 이미지 생성 (httpd)
cat > Dockerfile <<'EOF'
FROM registry.access.redhat.com/ubi9/httpd-24
COPY index.html /var/www/html/index.html
EXPOSE 8080
CMD ["/usr/sbin/httpd","-D","FOREGROUND","-f","/etc/httpd/conf/httpd.conf","-k","start","-e","debug","-E","/dev/stderr","-DFOREGROUND"]
EOF
cat > index.html <<'EOF'
<html>
<head><title>Cloudneta CICD Study</title></head>
<body><h1>Hello from Buildah on kind!</h1></body>
</html>
EOF
# buildah 빌드 (컨테이너 내부의 buildah-daemonless)
REGISTRY=docker.io
USER=chaany
IMG=${REGISTRY}/${USER}/gitops-website:buildah-latest
buildah build -t ${IMG} .
# podman으로 컨테이너 실행 테스트 (컨테이너 내부 포트 노출)
podman run -d --name myweb -p 8080:8080 -it ${IMG}
podman ps
curl -s 127.0.0.1:8080 | head -n 1
# Docker Hub 푸시 (컨테이너 내부에서 레지스트리 로그인)
podman login ${REGISTRY} -u ${USER} -p '<YOUR_DOCKER_PAT_OR_PASSWORD>'
buildah push ${IMG}
# 정리
podman rm -f myweb
exit
3.3.4 호스트에서 이미지 확인 및 실행
# 호스트(macOS)로 돌아와서
docker pull docker.io/chaany/gitops-website:buildah-latest
docker run -d --rm --name web-bh -p 8080:80 docker.io/chaany/gitops-website:buildah-latest
sleep 1
curl -s 127.0.0.1:8080 | head -n 1
docker rm -f web-bh
buildah/podman는 kind 노드 컨테이너 내부에서 빌드/검증/푸시까지 수행하고, 결과 이미지는 호스트에서도 그대로 사용할 수 있다.
3.4 Buildpacks로 Dockerfile 없이 이미지 빌드 (Node.js 예제)
3.4.1 pack 설치
brew install buildpacks/tap/pack
pack version
3.4.2 Node.js 앱 빌드/실행/푸시
cd ~/ && git clone https://github.com/gitops-cookbook/chapters buildpacks-lab
cd buildpacks-lab/chapters/ch03/nodejs-app
ls
cat package.json
# 추천 빌더 확인
pack builder suggest | sed -n '1,12p'
# Apple Silicon(macOS)에서 linux/arm64 타겟으로 빌드
REGISTRY=docker.io
USER=chaany
IMAGE=${REGISTRY}/${USER}/nodejs-app:latest
pack build ${IMAGE} \
--platform linux/arm64 \
--builder heroku/builder:24
# 로컬 확인
docker run -d --rm --name nodeapp -p 3000:3000 ${IMAGE}
sleep 2
curl -s 127.0.0.1:3000 | head -n 3
# 푸시
docker login -u ${USER}
docker push ${IMAGE}
# 정리
docker rm -f nodeapp
Buildpacks는 앱 소스(package.json, pom.xml, requirements.txt 등)를 탐지(Detection) 후 알맞은 빌드팩을 자동 선택해 컨테이너 이미지를 만든다. 대규모 팀·플랫폼에서 표준화된 빌드 경험을 제공하기 적합하다.
3.5 Shipwright(쿠버네티스 빌드 프레임워크) + BuildKit 전략으로 K8s에서 빌드
전제: kind 클러스터(myk8s)가 실행 중이어야 한다. (2장에서 생성)
실습 후 Go app이 layer에 존재하는 Image를 얻을 수 있다.
3.5.1 Tekton + Shipwright 설치 (버전은 예제 기준)
# Tekton Pipelines (예: v0.70.0)
kubectl apply -f https://storage.googleapis.com/tekton-releases/pipeline/previous/v0.70.0/release.yaml
# Ready 확인(시간 소요)
kubectl get ns | grep tekton
kubectl get all -n tekton-pipelines
kubectl get all -n tekton-pipelines-resolvers
# Shipwright Builds (예: v0.11.0)
kubectl apply -f https://github.com/shipwright-io/build/releases/download/v0.11.0/release.yaml
# CRD/리소스 확인
kubectl get crd | grep shipwright
kubectl get all -n shipwright-build
# 샘플 빌드 전략(여러 전략 포함: buildkit, buildah, buildpacks 등)
kubectl apply -f https://github.com/shipwright-io/build/releases/download/v0.11.0/sample-strategies.yaml
# 전략 목록 확인
kubectl get clusterbuildstrategy
Kaniko는 최근 아카이브 이슈가 있어, BuildKit 또는 Buildpacks 전략을 쓰는 구성을 추천한다.
3.5.2 Docker Hub 푸시용 시크릿 생성 (chaany 계정)
REGISTRY_SERVER="https://index.docker.io/v1/"
REGISTRY_USER="chaany"
REGISTRY_PASSWORD="<YOUR_DOCKER_PAT_OR_PASSWORD>" # Personal Access Token 권장
EMAIL="dev@example.com"
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 push-secret
3.5.3 BuildKit 전략 기반 Build + BuildRun (Golang 샘플)
# Build (BuildKit 사용) - shipwright sample 사용
cat <<'YAML' | kubectl apply -f -
apiVersion: shipwright.io/v1alpha1
kind: Build
metadata:
name: buildkit-golang-build
spec:
source:
url: https://github.com/shipwright-io/sample-go
contextDir: docker-build
strategy:
name: buildkit
kind: ClusterBuildStrategy
dockerfile: Dockerfile
output:
image: docker.io/chaany/sample-golang:latest
credentials:
name: push-secret
YAML
kubectl get builds
kubectl get build buildkit-golang-build -o yaml | sed -n '1,60p'
# BuildRun 생성 (빌드 시작)
cat <<'YAML' > buildrun-go.yaml
apiVersion: shipwright.io/v1alpha1
kind: BuildRun
metadata:
generateName: buildkit-golang-buildrun-
spec:
buildRef:
name: buildkit-golang-build
YAML
kubectl create -f buildrun-go.yaml
# 빌드 파드 모니터링
kubectl get pods -w
3.5.4 빌드 결과 확인/로그/정리
# 완료 후 상태
kubectl get buildruns.shipwright.io
kubectl logs -l clusterbuildstrategy.shipwright.io/name=buildkit -c step-source-default --tail=200
kubectl logs -l clusterbuildstrategy.shipwright.io/name=buildkit -c step-build-and-push --tail=200
# Docker Hub에서 이미지 확인 후, 로컬 실행 테스트
docker pull docker.io/chaany/sample-golang:latest
docker run -d --rm --name golang-sample -p 8080:8080 docker.io/chaany/sample-golang:latest
sleep 2
curl -s 127.0.0.1:8080 | head -n 5
docker rm -f golang-sample
# (선택) 정리
# kubectl delete build,buildrun --all

참고
- Dockerfile 빌드: 가장 직관적. 레이어 캐시 활용과 명령 순서 최적화가 중요.
- Jib(자바): Docker/Daemon 없이 빌드·푸시. CI 친화적이며 레이어링이 효율적.
- Buildpacks: Dockerfile 없이도 언어/프레임워크 자동 감지로 표준화된 이미지 생성.
- Shipwright(+Tekton): K8s 네이티브 빌드 API. BuildKit/Buildpacks 등 전략(Strategy)을 바꿔 확장.
- macOS에서 현업/학습 난이도는 Docker → Buildpacks → Jib → Shipwright(BuildKit) 순으로 높아진다. 로컬 단일 노드 kind로도 CI-유사 파이프라인 감을 충분히 잡을 수 있다.
'스터디(Study) > CI·CD Study' 카테고리의 다른 글
| GitOps Cookbook 6장: 클라우드 네이티브 CI/CD (0) | 2025.10.25 |
|---|---|
| GitOps Cookbook 5장: 헬름 (0) | 2025.10.25 |
| GitOps Cookbook 4장: 커스터마이즈 (0) | 2025.10.18 |
| GitOps Cookbook 2장: 실습 준비 (0) | 2025.10.18 |
| GitOps Cookbook 1장: 소개 (0) | 2025.10.18 |

댓글