본문 바로가기
J-H-T/Harbor

[OCI Artifact] Open Container Initiative (컨테이너 이미지와 Registry가 서로 호환되도록 표준 규격을 만드는 표준)

by METAVERSE STORY 2026. 8. 10.
반응형

 

 

이름에 전부 Image, Artifact가 붙어서 처음 보면 “결국 이미지 아닌가?” 싶습니다. 😄 그런데 핵심은 “컨테이너 실행용 파일인가, 아니면 OCI 규격을 이용해 저장하는 다른 종류의 패키지인가?”입니다.

가장 먼저 큰 그림부터 잡으면 쉽습니다.

Harbor
│
├─ Container Image
│    └─ Docker Image
│
└─ OCI Artifact
     ├─ Helm Chart
     ├─ SBOM
     ├─ Signature
     └─ 기타 OCI 패키지

즉, Container Image와 Docker Image는 실제 컨테이너 실행을 위한 이미지이고, OCI Artifact는 이미지뿐 아니라 Helm Chart 같은 다른 산출물까지 Registry에 저장할 수 있게 만든 더 넓은 개념입니다. OCI Registry는 컨테이너 이미지 외 다른 artifact 유형도 저장·배포할 수 있도록 확장되어 있습니다. (https://opencontainers.github.io)

1. 먼저 Container Image가 뭘까? 🐳

Container Image는 쉽게 말해:

컨테이너를 실행하기 위해 필요한 프로그램 + 라이브러리 + 설정을 포장한 실행 패키지

입니다.

Docker 공식 문서에서도 container image를 컨테이너 실행에 필요한 파일, 바이너리, 라이브러리, 설정을 포함하는 표준 패키지로 설명합니다. (Docker Documentation)

예를 들어 Python 웹서비스가 있다고 하겠습니다.

내 프로그램
app.py

필요한 Python
Python 3.12

필요한 라이브러리
Flask
requests
numpy

이걸 하나의 이미지로 묶습니다.

Container Image

├─ Linux 파일
├─ Python 3.12
├─ Flask
├─ requests
├─ numpy
└─ app.py

그리고 Kubernetes가 이것을 가져가서:

Container Image
       ↓
Container 실행
       ↓
Pod

하게 됩니다.

예:

containers:
  - name: web
    image: harbor.company.com/myproject/web:v1

여기서 web:v1이 Container Image입니다.


2. Docker Image는 뭐가 다른가?

여기서 중요한 포인트입니다.

Docker Image는 Container Image의 대표적인 형태라고 이해하면 됩니다.

쉽게 비유하면:

자동차
└─ 현대자동차

처럼 생각하면 됩니다.

Container Image
└─ Docker Image

과거에는 Docker가 컨테이너 생태계를 크게 주도해서 사람들이 흔히:

Container Image
=
Docker Image

처럼 불렀습니다.

실무에서도 여전히 거의 그렇게 말합니다.

예:

docker build -t myapp:v1 .

그러면:

myapp:v1

이라는 컨테이너 이미지가 만들어집니다.

그래서 이것을:

Docker Image

라고도 하고,

Container Image

라고도 부릅니다.

FROM python:3.12

COPY app.py /app/app.py

RUN pip install flask

CMD ["python", "/app/app.py"]

실행:

docker build -t myapp:v1 .

결과:

myapp:v1

이게 Docker로 만든 Container Image입니다.


3. 그러면 OCI는 뭐야? 🤔

여기서부터 중요합니다.

OCI는:

Open Container Initiative

의 약자입니다.

쉽게 말하면:

컨테이너 이미지와 Registry가 서로 호환되도록 표준 규격을 만드는 단체/표준

입니다.

왜 이런 표준이 필요했을까요?

예전에는:

Docker가 만든 Image
    ↓
Docker가 실행

라는 Docker 중심 구조였습니다.

그런데 Kubernetes가 커지면서:

Docker
containerd
CRI-O
Podman
Harbor
ECR
ACR
GHCR

등 수많은 제품이 등장했습니다.

만약 각각 자기 방식으로 이미지를 만들었다면:

Docker Image
→ Docker에서만 사용

Podman Image
→ Podman에서만 사용

containerd Image
→ containerd에서만 사용

같은 문제가 생깁니다.

그래서 OCI라는 공통 표준을 만든 것입니다.

OCI Image Specification은 이미지 manifest, config, layer 등 컨테이너 이미지를 구성하는 표준 구조를 정의합니다. (https://opencontainers.github.io)


4. 비유하면 USB 규격과 비슷합니다

이렇게 생각하면 쉽습니다.

과거:

회사 A 전용 케이블
회사 B 전용 케이블
회사 C 전용 케이블

너무 불편합니다.

그래서:

USB-C 표준

을 만들어 여러 장비에서 사용할 수 있게 합니다.

컨테이너도 비슷합니다.

         OCI 표준
            │
   ┌────────┼─────────┐
   ↓        ↓         ↓
Docker   containerd  Podman

Registry도:

         OCI 표준
            │
   ┌────────┼─────────┐
   ↓        ↓         ↓
Harbor     ECR       GHCR

처럼 OCI 규격을 이해할 수 있습니다.


5. OCI Image는 그러면 뭐야?

OCI 규격으로 표현된 컨테이너 실행용 이미지입니다.

대략 이런 구조를 가집니다.

OCI Image
│
├─ Manifest
│
├─ Config
│
└─ Layers
     ├─ Layer 1
     ├─ Layer 2
     └─ Layer 3

예를 들어:

FROM ubuntu:24.04
RUN apt install python3
COPY app.py /app/

라고 했다면 개념적으로:

Layer 1
Ubuntu

Layer 2
Python 설치

Layer 3
app.py

처럼 여러 Layer로 저장됩니다.

OCI에서는 이런 이미지의 구성과 참조 관계를 표준화합니다. OCI 문서에서는 OCI image를 root filesystem 변경사항과 컨테이너 실행 파라미터의 집합으로 정의합니다. (https://opencontainers.github.io)


6. 그런데 OCI Artifact는 또 뭐야? 📦

여기가 오늘 질문의 가장 중요한 부분입니다.

Artifact는 그냥:

저장하고 배포할 가치가 있는 산출물

이라고 생각하면 됩니다.

OCI가 발전하면서 이런 생각이 나왔습니다.

Registry라는 좋은 저장소가 있는데

왜 Container Image만 저장하지?

Helm Chart도 저장하고
SBOM도 저장하고
Signature도 저장하면 안 돼?

그래서 OCI Registry를 컨테이너 이미지 이외의 artifact 저장에도 활용할 수 있게 되었습니다. (Open Container Initiative)

즉:

OCI Registry

├─ Container Image
├─ Helm Chart
├─ SBOM
├─ Signature
├─ Attestation
└─ 기타 Artifact

가 가능해진 것입니다.


7. 아주 중요한 관계

정확하게는 이렇게 보면 됩니다.

             OCI Artifact
                  │
        ┌─────────┴──────────┐
        │                    │
Container Image         Helm Chart 등
        │
   Docker Image

다만 실무에서는 OCI Artifact라는 말을 컨테이너 이미지가 아닌 OCI Registry 저장물을 가리킬 때 좁은 의미로 쓰기도 합니다.

그래서 Harbor 화면에서:

Artifacts

라고 나오면 반드시:

Docker Image만 있음

을 의미하는 것이 아닙니다.


8. Helm은 뭐였지?

Helm은 Kubernetes의 패키지 관리자입니다.

예를 들어 Kubernetes에 nginx를 설치하려면 원래 YAML 파일이 여러 개 필요할 수 있습니다.

deployment.yaml
service.yaml
configmap.yaml
ingress.yaml
secret.yaml

복잡하죠.

Helm은 이것들을 하나의 패키지처럼 묶어줍니다.

my-nginx-chart
│
├─ Chart.yaml
├─ values.yaml
└─ templates
     ├─ deployment.yaml
     ├─ service.yaml
     └─ ingress.yaml

그리고 패키징하면:

my-nginx-1.0.0.tgz

가 됩니다.

이것을 Helm Chart라고 합니다.


9. Helm/OCI Artifact는 뭐야?

과거 Helm Chart는 보통 별도의 Helm Repository에 저장했습니다.

예:

Helm Client
     ↓
Helm Repository
     ↓
myapp-1.0.0.tgz

그런데 이제 Helm은 OCI Registry도 사용할 수 있습니다.

Helm Client
     ↓
Harbor
     ↓
OCI Registry
     ↓
myapp Helm Chart

Helm 공식 문서에 따르면 Helm은 OCI 기반 Registry에 패키징된 Helm Chart를 저장하고 공유할 수 있으며, Helm 3.8부터 OCI 지원이 기본적으로 활성화되어 있습니다. (Helm)

예를 들어:

helm push myapp-1.0.0.tgz \
oci://harbor.company.com/helm

라고 할 수 있습니다.

그러면 Harbor 안에:

Harbor
└─ helm
    └─ myapp
        └─ 1.0.0

형태로 저장됩니다.

이게 바로 Helm OCI Artifact입니다.


10. 가장 중요한 차이 ⭐

Container Image와 Helm Chart는 목적이 완전히 다릅니다.

Container Image

실제 프로그램을 실행합니다.

Container Image
     ↓
containerd
     ↓
Container
     ↓
Application 실행

예:

nginx:1.29
python:3.12
pytorch:2.x
myapp:v1

Helm Chart

Container Image를 어떻게 Kubernetes에 배포할 것인지 정의합니다.

Helm Chart
     ↓
Kubernetes YAML 생성
     ↓
Deployment
Service
Ingress
ConfigMap
PVC
...

즉 Helm Chart 자체가 실행되는 게 아닙니다.


11. 예를 들어 Harbor에 둘 다 있을 수 있습니다

예를 들어 우리가 myapp이라는 서비스를 만든다고 해보겠습니다.

Harbor:

harbor.company.com

project: myapp

├─ backend
│    ├─ v1.0
│    ├─ v1.1
│    └─ v1.2
│
└─ myapp-chart
     ├─ 1.0.0
     ├─ 1.1.0
     └─ 1.2.0

그런데 실제 내용은 다릅니다.

backend:v1.2

Container Image

Ubuntu
Java
Spring Boot
app.jar
설정

myapp-chart:1.2.0

Helm Chart

Deployment.yaml
Service.yaml
Ingress.yaml
ConfigMap.yaml
values.yaml

즉:

Container Image
=
"무엇을 실행할 것인가?"

Helm Chart
=
"그걸 Kubernetes에서 어떻게 실행할 것인가?"

이 차이가 핵심입니다.


12. 실제 배포 흐름으로 보면 바로 이해됩니다

개발자가 프로그램을 만듭니다.

Source Code
     ↓
Build
     ↓
Container Image
     ↓
Harbor

예:

harbor.company.com/app/backend:v1

그리고 Helm Chart에는:

image:
  repository: harbor.company.com/app/backend
  tag: v1

replicaCount: 3

같은 설정이 들어갑니다.

전체 흐름:

                 Harbor
                    │
       ┌────────────┴────────────┐
       │                         │
Container Image              Helm Chart
backend:v1                  myapp:1.0.0
       │                         │
       │                   배포 방법 정의
       │                         │
       └──────────┬──────────────┘
                  ↓
                Helm
                  ↓
             Kubernetes
                  ↓
          Deployment 생성
                  ↓
                Pod
                  ↓
        backend:v1 Image Pull
                  ↓
            Container 실행

이 그림을 이해하면 거의 끝입니다.


13. Kubernetes 입장에서 보면 더 쉽습니다

예를 들어:

helm install myapp \
oci://harbor.company.com/helm/myapp

를 실행합니다.

먼저 Helm이 Harbor에서:

Helm Chart

를 가져옵니다.

그 안에는:

kind: Deployment

containers:
- name: backend
  image: harbor.company.com/app/backend:v1

같은 내용이 있습니다.

그 다음 Kubernetes가 Deployment를 생성하고 Pod를 만들면서 다시 Harbor에서:

backend:v1

이라는 Container Image를 Pull합니다.

즉 Harbor에 두 번 접근할 수도 있습니다.

① Helm
   ↓
Harbor
   ↓
Helm Chart Pull


② Kubernetes Node
   ↓
Harbor
   ↓
Container Image Pull

중요한 차이입니다.


14. SBOM도 OCI Artifact가 될 수 있습니다

OCI Artifact가 Helm만 의미하는 것은 아닙니다.

예를 들어 SBOM:

Software Bill of Materials

즉:

이 이미지 안에
어떤 소프트웨어가 들어있는지
목록

입니다.

예:

backend:v1

├─ Ubuntu 24.04
├─ OpenSSL 3.x
├─ Python
├─ Flask
└─ requests

이런 정보를 담은 SBOM을 이미지와 연결해서 Registry에 보관할 수도 있습니다.

예:

Harbor

backend:v1
   │
   ├─ Container Image
   │
   ├─ SBOM
   │
   └─ Signature

OCI 1.1에서는 이미지나 다른 artifact 간의 관계를 표현하는 기능도 정식 규격에 포함되었습니다. (Open Container Initiative)


15. Signature도 Artifact입니다

예를 들어 보안상:

이 이미지는
우리 회사 CI/CD가 정상적으로 만든 이미지인가?

를 확인하고 싶습니다.

그러면:

backend:v1
    │
    └─ Signature

를 붙일 수 있습니다.

개념적으로:

Container Image
backend:v1

      +

Digital Signature

      ↓

"회사 CI가 만든 정상 이미지"

처럼 사용할 수 있습니다.


16. 그래서 Harbor에서 Artifact라는 말을 많이 쓰는 이유

Harbor를 보다 보면:

Project
 → Repository
   → Artifacts

라는 표현을 볼 수 있습니다.

처음에는:

왜 Images라고 안 하고 Artifacts라고 하지?

라고 생각할 수 있습니다.

그 이유가 바로:

Harbor가 이제
Container Image만 저장하는 게 아니기 때문

입니다.

예를 들어 Repository 안에:

Container Image
Helm Chart
Signature
SBOM
기타 OCI Artifact

등을 다룰 수 있기 때문입니다.


17. 표로 한 번 정리해보겠습니다

구분의미실행 가능?대표 예

Container Image 컨테이너 실행 패키지 nginx, Python 앱
Docker Image Docker 생태계에서 만든/부르는 Container Image nginx:latest
OCI Image OCI 표준을 따르는 Container Image myapp:v1
OCI Artifact OCI Registry에 저장 가능한 더 넓은 산출물 종류에 따라 다름 Helm, SBOM, Signature
Helm Chart K8s 배포 패키지 myapp-1.0.0.tgz
Helm OCI Artifact OCI Registry에 저장한 Helm Chart oci://harbor/.../myapp

18. 이미지라는 단어 때문에 헷갈리지 않는 방법

이렇게 외우시면 됩니다. ⭐

Container Image

프로그램 실행용 패키지

Docker Image

Container Image를
Docker 관점에서 부르는 이름

OCI Image

표준 규격을 따르는 Container Image

OCI Artifact

OCI Registry에 넣을 수 있는
여러 종류의 패키지

Helm OCI Artifact

OCI Registry에 넣은
Kubernetes Helm Chart

19. 컨테이너 이미지와 Helm의 관계를 식당으로 비유 🍜

이 비유가 가장 쉽습니다.

Container Image = 음식 재료가 준비된 밀키트

🍜 Container Image

면
육수
고기
양념

실제로 실행할 프로그램이 들어 있습니다.

Helm Chart = 조리법 + 식당 운영 지침

📋 Helm Chart

밀키트 3개 준비
냄비 3개 사용
8000번 포트 사용
외부 손님에게 공개
냉장고 10GB 사용

즉:

Container Image
=
무엇을 실행하는가

Helm Chart
=
어떻게 배포하는가

입니다.


20. 온프레미스 Kubernetes + Harbor에서는 이렇게 보시면 됩니다

실제 기업 환경을 기준으로 하면:

                Harbor
                  │
        ┌─────────┴──────────┐
        │                    │
     Images              OCI Artifacts
        │                    │
        │              ┌─────┼──────┐
        │              │     │      │
    Backend:v1       Helm   SBOM  Signature
    Frontend:v2      Chart
        │              │
        └──────┬───────┘
               ↓
             CI/CD
               ↓
            ArgoCD
               ↓
             Helm
               ↓
          Kubernetes
               ↓
              Pod
               ↓
        Container 실행

따라서 Harbor를 단순히 “Docker 이미지 저장소”라고만 이해하면 조금 부족합니다.

현재 개념으로는:

Harbor = OCI Registry

컨테이너 이미지뿐 아니라 Helm Chart와 각종 OCI Artifact까지 관리할 수 있는 저장소

라고 이해하는 편이 더 정확합니다. Helm도 OCI Registry에 차트를 직접 저장하고 설치하는 방식을 공식 지원합니다. (Helm)

⭐ 최종 핵심 3줄

Docker Image ⊂ Container Image

Container Image = 프로그램 실행용

OCI Artifact = Container Image + Helm/SBOM/Signature 등까지 포괄하는 더 큰 저장 개념

그리고 다음에 Nexus → Harbor → Helm → ArgoCD → Kubernetes를 연결해서 보면, “왜 Nexus에는 JAR을 넣고 Harbor에는 Image와 Helm Chart를 넣는지”가 한 번에 정리됩니다.

 

반응형

댓글