본문 바로가기
CI&CD

[Shipwright] Docker 없이 Kubernetes에서 컨테이너 이미지 빌드하기

by interlude-3 2025. 10. 16.

1. Shipwright란?

Shipwright는 Kubernetes 환경에서 컨테이너 이미지의 빌드와 관리를 자동화하는 것을 목표로 하는 오픈소스 프로젝트입니다.


기존 개발자들은 컨테이너 이미지를 빌드하기 위해 로컬 환경이나 별도의 CI/CD 서버에 Docker를 설치하고 docker build 명령어를 통해 이미지를 생성해 왔습니다.


이제는 Shipwright를 통해 Docker에 의존하지 않고 Kubernetes 클러스터 내부에서 이미지를 직접 빌드할 수 있습니다.
복잡했던 Docker 빌드 과정을 쿠버네티스 워크플로우 안으로 통합하여, 개발 및 배포 파이프라인의 효율성과 보안을 향상시킬 수 있습니다.
 
Shipwright는 다음과 같은 빌드 도구를 지원합니다.

빌드 도구 설명
Buildah OCI 표준 기반 이미지 빌드 도구. rootless 모드를 지원하여 안전하게 빌드 가능. Dockerfile 또는 명령형 빌드 방식 지원.
BuildKit Docker가 사용하는 고성능 빌드 엔진. 빠르고 캐시를 효율적으로 관리. Dockerfile 기반 병렬 빌드 지원.
Buildpacks Dockerfile 없이 소스 코드만으로 이미지 자동 생성. 언어나 프레임워크를 감지해 런타임 환경을 자동 구성.
Kaniko Kubernetes나 CI/CD 파이프라인에서 Dockerfile을 기반으로 이미지 빌드.

 
Shipwright는 빌드 엔진 자체를 직접 구현하지 않습니다. 대신 Tekton을 기반으로 표준화된 API와 실행 환경을 제공하여, Kaniko나 Buildpacks와 같은 다양한 빌드 툴들을 하나의 일관된 인터페이스로 통합하는 추상화 계층 역할을 수행합니다.
 
Shipwright가 동작하면 빌드 작업은 Kubernetes Pod 내부에서 실행되고, 빌드가 완료된 이미지는 사용자가 지정한 컨테이너 레지스트리에 자동으로 Push됩니다.
 

 

Shipwright

Why shipwright? Shipwright.io provides a straightforward approach to build container images of your code within your Kubernetes cluster by defining a minimal YAML configuration.

shipwright.io

 


2. Shipwright는 언제 사용하면 좋을까?

Shipwright는 Docker 데몬이 없는 환경, 보안이 중요한 환경, 또는 여러 개발팀이 공용 빌드 플랫폼을 써야 하는 환경에서 특히 유용합니다.

  • 사용 사례
  1. 빌드 전략의 표준화 (대규모 마이크로서비스 환경)
    수십 개의 마이크로서비스를 운영하는 대규모 조직에서, 각 팀이 Dockerfile, Buildpacks 등 제각각의 방식으로 이미지를 빌드하고 있을 때 유용합니다. Shipwright는 ClusterBuildStrategy를 통해 전체 조직에 걸쳐 빌드 방식을 단일화하고 일관성을 유지하게 합니다.
  2. 보안 강화 (DooD 문제 해결)
    Kubernetes 클러스터 내에서 Docker 데몬을 실행할 필요가 없어, 루트 권한으로 실행되는 Docker-in-Docker(DooD) 환경에서 발생할 수 있는 잠재적인 보안 위험을 제거합니다.
  3. 리소스 효율성과 확장성
    빌드 작업이 클러스터의 Pod 단위로 격리되어 실행되므로, 클러스터 리소스를 효율적으로 활용하며 빌드 요청이 폭주해도 유연하게 확장할 수 있습니다.
  • 주요 장점
  1. 빌더 유연성
    Docker 데몬 없이 BuildKit, Buildah, Buildpacks 등 다양한 빌더 엔진을 선택하여 이미지를 빌드할 수 있습니다.
  2. Tekton 기반의 확장성 및 효율성 확보
    빌드가 Pod 단위로 실행되어 클러스터 리소스를 효율적으로 활용하며 고가용성을 확보합니다.
  3. 빌드 전략 표준화 및 재사용 가능
    ClusterBuildStrategy와 BuildStrategy를 통해 빌드 방식을 일관되게 정의하고 재사용할 수 있습니다.
  4. Kubernetes 네이티브 통합
    Pod, PVC, Secret 등 기존 Kubernetes 리소스와 자연스럽게 연동되어 빌드 환경 관리가 용이합니다.
  5. Operator 기반 자동 관리
    Shipwright Operator가 설치, 업그레이드, Custom Resource Definition(CRD) 관리를 자동으로 수행하여 운영 부담을 줄여줍니다.

3. Shipwright 주요 API 리소스

Shipwright API는 크게 세 가지 핵심 리소스로 구성됩니다.

ClusterBuildStrategy/BuildStrategy 빌드 전략 정의
Build  빌드 대상 정의
BuildRun  빌드 실행 명령

 
3.1 ClusterBuildStrategy / BuildStrategy

  • 빌드 방법을 정의하는 리소스
  • Buildah, BuildKit, Buildpacks 등 전략 정의, 단계별 환경 변수 설정 등
  • ClusterBuildStrategy는 클러스터 전체 공유, BuildStrategy는 네임스페이스 단위 사용

3.2 Build

  • 빌드할 앱과 전략을 연결하는 리소스
  • Git 소스 코드, 이미지 이름, 사용할 빌드 전략 지정

3.3 BuildRun

  • Build를 실제 실행하는 리소스
  • BuildRun이 생성되면 Operator가 빌드 프로세스를 트리거하고 결과 이미지를 생성

4. Shipwright 사용 예시 : BuildKit을 이용한 이미지 빌드

4.1 Kubernetes, Tekton pipelines, OLM 사전 설치

#kubernetes 설치 확인
$ kubectl version
Client Version: v1.34.1
Kustomize Version: v5.7.1
Server Version: v1.32.8

#tekton 설치 확인
$ kubectl get crd | grep tekton
clustertasks.tekton.dev                    2025-10-15T11:44:44Z
customruns.tekton.dev                      2025-10-15T11:44:44Z
pipelineruns.tekton.dev                    2025-10-15T11:44:44Z
pipelines.tekton.dev                       2025-10-15T11:44:44Z
resolutionrequests.resolution.tekton.dev   2025-10-15T11:44:45Z
stepactions.tekton.dev                     2025-10-15T11:44:45Z
taskruns.tekton.dev                        2025-10-15T11:44:45Z
tasks.tekton.dev                           2025-10-15T11:44:45Z
verificationpolicies.tekton.dev            2025-10-15T11:44:45Z
#cert-manager 설치
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml

#OLM 설치
kubectl create -f https://github.com/operator-framework/operator-lifecycle-manager/releases/latest/download/crds.yaml
kubectl create -f https://github.com/operator-framework/operator-lifecycle-manager/releases/latest/download/olm.yaml​
#설치 환경 확인
$ kubectl get pods -A
NAMESPACE                    NAME                                                 READY   STATUS    RESTARTS       AGE
cert-manager                 cert-manager-7f6864ff99-jfmx6                        1/1     Running   0              3m16s
cert-manager                 cert-manager-cainjector-6595c6777-nsggr              1/1     Running   0              3m16s
cert-manager                 cert-manager-webhook-58fd9998b4-8phrc                1/1     Running   0              3m16s
kube-system                  coredns-668d6bf9bc-496nn                             1/1     Running   6 (14m ago)    4d14h
kube-system                  coredns-668d6bf9bc-xw5lr                             1/1     Running   6 (14m ago)    4d14h
kube-system                  etcd-myk8s-control-plane                             1/1     Running   4 (14m ago)    3d12h
kube-system                  kindnet-nkxq6                                        1/1     Running   6 (14m ago)    4d14h
kube-system                  kindnet-nrqbv                                        1/1     Running   6 (14m ago)    4d14h
kube-system                  kube-apiserver-myk8s-control-plane                   1/1     Running   7 (14m ago)    3d12h
kube-system                  kube-controller-manager-myk8s-control-plane          1/1     Running   13 (14m ago)   4d14h
kube-system                  kube-proxy-k6k4x                                     1/1     Running   6 (14m ago)    4d14h
kube-system                  kube-proxy-x7qnj                                     1/1     Running   6 (14m ago)    4d14h
kube-system                  kube-scheduler-myk8s-control-plane                   1/1     Running   13 (14m ago)   4d14h
local-path-storage           local-path-provisioner-7dc846544d-ptzln              1/1     Running   12 (13m ago)   4d14h
olm                          catalog-operator-756f5c6d9d-wn977                    1/1     Running   0              109s
olm                          olm-operator-7897776ffb-jggp5                        1/1     Running   0              109s
olm                          operatorhubio-catalog-2th4t                          1/1     Running   0              73s
olm                          packageserver-7f58549ff6-b5qs7                       1/1     Running   0              74s
olm                          packageserver-7f58549ff6-hll6t                       1/1     Running   0              74s
tekton-pipelines-resolvers   tekton-pipelines-remote-resolvers-86f56b6664-ngn5x   1/1     Running   2 (13m ago)    37h
tekton-pipelines             tekton-events-controller-99665746c-kg5sc             1/1     Running   2 (13m ago)    37h
tekton-pipelines             tekton-pipelines-controller-7595d6585d-64nb4         1/1     Running   2 (13m ago)    37h
tekton-pipelines             tekton-pipelines-webhook-5967d74cc4-bfj2m            1/1     Running   2 (13m ago)    37h

 

4.2 Shipwright Operator 설치

$ kubectl apply -f https://operatorhub.io/install/shipwright-operator.yaml
subscription.operators.coreos.com/my-shipwright-operator created

$ kubectl get pods -n olm
NAME                                                              READY   STATUS      RESTARTS   AGE
06fc6f9acd3943a2bbf23ce6e61f624bf0b34547452d28c9154fc35bcbp9g9p   0/1     Completed   0          2m16s
418f20180061387fdda860ce8e5f9eea1a4c9592b2f39f1ee5ea891c61tcxxz   0/1     Completed   0          2m16s
catalog-operator-756f5c6d9d-wn977                                 1/1     Running     0          4m50s
e117dbdcaf9187648441742de0dfaae414911cb34cbdf50d1eb7131d7afgs65   0/1     Completed   0          2m16s
olm-operator-7897776ffb-jggp5                                     1/1     Running     0          4m50s
operatorhubio-catalog-2th4t                                       1/1     Running     0          4m14s
packageserver-7f58549ff6-b5qs7                                    1/1     Running     0          4m15s
packageserver-7f58549ff6-hll6t                                    1/1     Running     0          4m15s

$ kubectl get pods -n operators
NAME                                       READY   STATUS    RESTARTS   AGE
cert-manager-6449d4767d-bcdg4              1/1     Running   0          55s
cert-manager-cainjector-7f747454fc-mtnkx   1/1     Running   0          55s
cert-manager-webhook-9cd68db58-krb22       1/1     Running   0          54s
shipwright-operator-6d67bfd5b9-bdgn2       2/2     Running   0          63s
tekton-operator-6677bcc8f5-r485n           2/2     Running   0          66s
tekton-operator-webhook-668fc5f979-vngw8   1/1     Running   0          65s

 

4.3 Shipwright 빌드 시스템 배포 (ShipwrightBuild CR 생성)

 

사용자가 shipwrightBuild CR을 생성하면 Shipwright Operator가 CRD와 Controller를 자동으로 설치해줍니다.

$ kubectl apply -f - <<EOF
> apiVersion: operator.shipwright.io/v1alpha1
> kind: ShipwrightBuild
> metadata:
>   name: shipwright-operator

  targe> spec:
>   targetNamespace: shipwright-build
> EOF
shipwrightbuild.operator.shipwright.io/shipwright-operator created

$ kubectl get pods -n shipwright-build
NAME                                           READY   STATUS    RESTARTS   AGE
shipwright-build-controller-5cb85b9876-z5qpk   1/1     Running   0          82s
shipwright-build-webhook-7858f9d8b-z4kcw       1/1     Running   0          82s

$ kubectl get crd | grep build
buildruns.shipwright.io                       2025-10-18T02:29:58Z
builds.shipwright.io                          2025-10-18T02:29:58Z
buildstrategies.shipwright.io                 2025-10-18T02:29:58Z
clusterbuildstrategies.shipwright.io          2025-10-18T02:29:58Z

$ kubectl get clusterbuildstrategy.shipwright.io
NAME                              AGE
buildah-shipwright-managed-push   10m
buildah-strategy-managed-push     10m
buildkit                          10m
buildpacks-v3                     10m
buildpacks-v3-heroku              10m
kaniko                            10m
ko                                10m
source-to-image                   10m
source-to-image-redhat            10m

 

4.4 BuildStrategy 배포 (빌드 전략 설치)

$kubectl get clusterbuildstrategy buildkit -o yaml
...
    image: moby/buildkit:v0.20.0-rootless
...

 

4.5 컨테이너 레지스트리 Push를 위한 자격 증명 Secret 생성

REGISTRY_SERVER=https://index.docker.io/v1/
REGISTRY_USER=<your_registry_user>
REGISTRY_PASSWORD=<your_registry_password>
EMAIL=<your_email>

$ kubectl create ns buildkit-test
namespace/buildkit-test created

$ kubectl create secret docker-registry push-secret \
>   --docker-server=$REGISTRY_SERVER \
>   --docker-username=$REGISTRY_USER \
>   --docker-password=$REGISTRY_PASSWORD \
>   --docker-email=$EMAIL \
>   -n buildkit-test

$ kubectl get secret -n buildkit-test
NAME          TYPE                             DATA   AGE
push-secret   kubernetes.io/dockerconfigjson   1      10s

 

4.6 Build 객체 생성

 

<Dockerfile>
# From https://github.com/homeport/gonut/tree/master/assets/sample-apps/golang

FROM ghcr.io/shipwright-io/shipwright-samples/golang:1.18 AS build

COPY main.go .
ENV CGO_ENABLED=0
RUN go build \
    -ldflags "-s -w -extldflags '-static'" \
    -o /tmp/helloworld \
    main.go

FROM scratch
COPY --from=build /tmp/helloworld ./helloworld
ENTRYPOINT [ "./helloworld" ]
EXPOSE 8080​

 

<main.go>

// Copyright The Shipwright Contributors
//
// SPDX-License-Identifier: Apache-2.0

package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"strconv"
	"syscall"
)

func main() {
	ctx := context.Background()
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, os.Interrupt, syscall.SIGTERM)

	port := 8080
	if strValue, ok := os.LookupEnv("PORT"); ok {
		if intValue, err := strconv.Atoi(strValue); err == nil {
			port = intValue
		}
	}

	srv := &http.Server{Addr: fmt.Sprintf(":%d", port)}
	go func() {
		http.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
			fmt.Fprintf(w, "Hello, World! I am using %s by the way.", runtime.Version())
		})

		if err := srv.ListenAndServe(); err != http.ErrServerClosed {
			log.Fatalf("failed to start server: %v", err)
		}
	}()

	<-signals
	log.Printf("shutting down server")
	if err := srv.Shutdown(ctx); err != nil {
		log.Fatalf("failed to shutdown server: %v", err)
	}
}​

 

<build.yaml>
apiVersion: shipwright.io/v1beta1
kind: Build
metadata:
  name: sample-go-build
  namespace: buildkit-test
  annotations:
    build.shipwright.io/build-run-deletion: "true" # 빌드 완료 후 BuildRun 자동 삭제
spec:
  strategy:
    name: buildkit
    kind: ClusterBuildStrategy
  source:
    type: Git
    contextDir: docker-build
    git:
      url: "https://github.com/shipwright-io/sample-go.git"
  output:
    image: "docker.io/riachoi/sample-go:latest"
    pushSecret: push-secret

 

> build 배포 완료

$ kubectl get build -A
NAMESPACE       NAME              REGISTERED   REASON      BUILDSTRATEGYKIND      BUILDSTRATEGYNAME   CREATIONTIME
buildkit-test   sample-go-build   True         Succeeded   ClusterBuildStrategy   buildkit            27s

 

4.7 Buildrun 배포

<buildrun.yaml>

apiVersion: shipwright.io/v1beta1
kind: BuildRun
metadata:
  generateName: sample-go-buildrun-
  namespace: buildkit-test
spec:
  build:
    name: sample-go-build

 

>> buildrun 배포 완료

$ kubectl get pods -n buildkit-test -w
NAME                                 READY   STATUS     RESTARTS   AGE
sample-go-buildrun-5tfpk-2x7pk-pod   2/3     NotReady   0          13s
sample-go-buildrun-5tfpk-2x7pk-pod   1/3     NotReady   0          72s
sample-go-buildrun-5tfpk-2x7pk-pod   0/3     Completed   0          82s
sample-go-buildrun-5tfpk-2x7pk-pod   0/3     Completed   0          83s

$ kubectl get buildrun -n buildkit-test
NAME                       SUCCEEDED   REASON      STARTTIME   COMPLETIONTIME
sample-go-buildrun-5tfpk   True        Succeeded   2m29s       67s
 
 
 

Installation

Install Shipwright on your Kubernetes cluster.

shipwright.io


5. BuildRun 생성 시 동작 과정

  1. BuildRun 리소스가 배포되면
  2. Shipwright Operator가 Tekton TaskRun 자동 생성
  3. Tekton은 TaskRun을 기반으로 빌드용 Pod 생성
  4. Git 리포지토리가 자동으로 복제되어 Pod 내부 /workspace/source에 마운트
  5. BuildKit 컨테이너가 /workspace/source 디렉터리 Dockerfile을 읽어 Docker 없이 이미지 빌드
  6. 빌드가 완료되면 결과 이미지를 output.image에 지정된 컨테이너 레지스트리로 Push
  7. TaskRun 상태(Succeeded / Failed)가 Update되면 Shipwright Operator는 해당 상태를 BuildRun 리소스에 반영

=> 모든 과정이 Pod 단위로 관리되며, kubectl logs로 빌드 로그 확인이 가능합니다.


 

Shipwright를 활용하면 복잡한 빌드 환경 설정이나 Docker 데몬 관리에 신경 쓸 필요 없이 Kubernetes 환경에서 컨테이너 빌드를 네이티브하게(외부 도구 없이) 관리할 수 있습니다.
 
kubectl apply 명령어 한 줄로 이미지 빌드부터 푸시까지 자동화되는 클라우드 네이티브 빌드 환경을 만들어 보세요.