[테크 따라잡기] EKS에서 고가용성 Private Docker Registry(Harbor) 구축하기

1
2
[테크 따라잡기]는 IT 기업 기술 스택 사례를 참고하여 구현하고 정리하는 시리즈입니다. 
오로지 기술 성장을 위해 작성할 예정이며 스터디 과정에서 얻는 인사이트를 공유하고자 합니다. 

도커 레지스트리인 Harbor에 대해 사용 사례를 조사하던 중 배울 것이 많은 테크 블로그 글을 발견하였다. 그대로 글로만 보기에는 필자가 아쉬워서 직접 구현하고 구현 과정에서 얻는 인사이트를 공유하고자 블로그 글을 작성하였다. 참고한 테크 블로그는 다음의 링크에서 확인이 가능하다.

<a href="https://engineering.linecorp.com/ko/blog/harbor-for-private-docker-registry">https://engineering.linecorp.com/ko/blog/harbor-for-private-docker-registry</a>

https://engineering.linecorp.com/ko/blog/harbor-for-private-docker-registry

블로그 글을 요약하자면, Private Docker Registry로 Harbor를 선택하여 구성하였고, 오픈소스 오브젝트 스토리지인 Minio를 통해 스토리지 고가용성을 보장하였다. 또한 사내 LDAP 서버를 이용하여 직원 정보를 Harbor와 연계하여 로그인 정보를 연계하였다고 한다.

기술 구현의 큰 틀은 같지만, 쿠버네티스 환경(AWS EKS)에서 Harbor를 배포하고 도커 이미지 백엔드 저장소로 Minio 사용하고자 한다. 또한 고가용성을 가지기 위해 다중 지역별 볼륨을 분산시키고, 백업에 대한 아키텍처를 설계하고 구현할 것이다. 아키텍처를 구현하면서 고민한 부분도 공유할 예정이다.

Harbor

Harbor는 CNCF에서의 레벨이 마지막 레벨인 Graduation(졸업) 단계인 오픈소스 도커 레지스트리이다. 도커 레지스트리 기능으로 안정성, 유용성, 커뮤니티 지원 등 여러 측면에서 충분한 성숙도를 갖춘 것으로 인정받았으며 필요 사례에 맞게 커스터 마이징이 가능하다. 대표적인 기능으로는 멀티 레파티토리 지원, 보안 스캔, 사용자 관리 권한, 이미지 사이클 관리, 마이그레이션, 저장소 복제, 스토리지 백업, 미러링 기능이 있다.

기능면에서 미러링과 복제가 헷갈릴 수 있는데 목적이 분명 다르다. 미러링은 실시간 동기화를 통해 고가용성과 데이터 안정성을 보장하는 기능인 반면, 복제는 데이터 분산, 백업 및 로드 분산을 위해 주기적으로 또는 수동으로 데이터를 복사하는 방식이다.

<a href="https://landscape.cncf.io/guide#provisioning--container-registry">https://landscape.cncf.io/guide#provisioning&ndash;container-registry</a>

https://landscape.cncf.io/guide#provisioning–container-registry

아키텍처는 다음과 같다. 중앙 하늘색 네모 부분이 harbor 구성 요소이다. 크게 네트워크단, 서비스단, 데이터 액세스 계층으로 구성된다.

<a href="https://github.com/goharbor/harbor/wiki/Architecture-Overview-of-Harbor">https://github.com/goharbor/harbor/wiki/Architecture-Overview-of-Harbor</a>

https://github.com/goharbor/harbor/wiki/Architecture-Overview-of-Harbor

  • 네트워크 계층(Proxy) : Nginx 서버에 의해 형성된 리버스 프록시이다. 하버의 서비스 구성 요소는 모두 이 역방향 프록시 뒤에 있으며 Proxy를 통해 전달된다. 이를 통해 로드 밸런싱, 보안, SSL/TLS 부하 관리, 캐싱 부하 개선, 압축 개선등의 이점을 얻을 수 있다.
  • 서비스 계층(Core) : Harbor Core는 프로젝트 관리, 사용자 인증 및 권한 관리, 시스템 설정 관리, 오케스트레이션 및 이벤트 처리와 같은 다양한 핵심 기능을 담당하는 중심 컴포넌트이다. 세부 기능은 다음과 같다.
    1. 프로젝트 관리: Harbor Core는 프로젝트의 생성, 수정, 삭제 및 구성을 관리한다. 프로젝트는 사용자가 컨테이너 이미지와 Helm 차트를 구성 및 관리할 수 있는 논리적 상위 레벨의 단위이다
    2. 사용자 인증 및 권한 관리: Harbor Core는 사용자 인증 및 권한 관리를 수행한다. 이를 통해 특정 프로젝트에 대한 접근 권한을 제어할 수 있으며, 사용자는 자신의 권한 범위 내에서 이미지 및 차트를 관리할 수 있다. Harbor는 여러 인증 방식을 지원하며, 외부 인증 시스템과의 통합도 가능하다.
    3. 시스템 설정: Harbor Core는 전체 시스템에 대한 다양한 설정을 관리한다. 이에는 공통 설정, 네트워크 설정, 스토리지 설정, 보안 설정, 로깅 및 모니터링 설정 등이 포함된다.
    4. 오케스트레이션: Harbor Core는 다른 서비스 컴포넌트와의 상호 작용을 조정한다. 예를 들어 이미지 스캔 요청이 들어오면, 해당 작업을 Job Service에 전달하고, 결과를 사용자에게 전달한다.
    5. 이벤트 처리: Harbor Core는 시스템 내부의 이벤트를 처리하며, 필요한 경우 다른 컴포넌트와 상호 작용하여 작업을 수행한다. 이러한 이벤트에는 이미지 및 차트의 생성, 수정, 삭제 등이 포함된다.
  • 데이터 액세스 계층(Data Access Layer) : 3가지로 구성되며 kv-storage(Redis 작업 데이터에 대한 캐싱 스토리지), Local / Remote Storage(도커 레지스트리 저장소) , SQL Database(PostgreSQL 프로젝트, 사용자, 역할, 복제 정책, 태그 보존 정책, 스캐너, 차트 및 이미지와 같은 Harbor 모델의 관련 메타데이터를 저장)을 수행한다.

공식문서에 따르면 Harbor는 기본적으로 상태 비저장 상태이며 파드간 복제가 가능하여 파드 HA를 제공한다. 하지만 스토리지 계층 레벨에서는 사용자가 고가용성 PostgreSQL, 애플리케이션 데이터 및 PVC를 위한 Redis 클러스터 또는 이미지 및 차트를 저장하기 위한 스토리지를 구축해야 한다.

<a href="https://goharbor.io/docs/1.10/install-config/harbor-ha-helm/">https://goharbor.io/docs/1.10/install-config/harbor-ha-helm/</a>

https://goharbor.io/docs/1.10/install-config/harbor-ha-helm/

이에 따라 스토리지 계층에서의 고가용성을 구성하고자 한다. Harbor 헬름 차트를 확인하면 스토리지 관련 설정부분이 6개이다. 각 스토리지은 다음과 같다.

  1. Registry: Docker 레지스트리 스토리지이다. 컨테이너 이미지 및 Helm 차트와 같은 아티팩트를 저장하고 관리한다.
  2. ChartMuseum: Helm 차트 레포지토리 스토리지이다. Helm 차트를 저장하고 제공하는 데 사용된다.
  3. JobService: JobService의 로그 및 작업 데이터를 저장한다. JobService는 이미지 레플리케이션, 가비지 수집, 스캔 작업 등의 작업을 수행한다.
  4. Database: Harbor의 메타데이터를 저장하는 PostgreSQL 데이터베이스이다. 프로젝트, 사용자, 권한 및 구성 정보와 같은 메타데이터를 저장한다
  5. Redis: Harbor에서 사용하는 캐싱 및 메시지 큐 서비스이다.
  6. Trivy: 컨테이너 이미지의 취약점 스캔을 수행하는 오픈 소스 스캐너이다. 이 구성 요소의 볼륨은 취약점 데이터베이스 및 스캔 결과를 저장한다.

6개의 스토리지 중 고가용성 구성을 위한 스토리지는 3개이다.

  • Registry : 도커 이미지 저장소
  • ChartMuseum : helm 차트 저장소
  • Database : Harbor 메타데이터 저장소

Harbor에서는 스토리지로 block storage, file storage, object stroage 로 설정이 가능하다. 다만, 저장소의 성능 및 활용 특성으로 저장소별 스토리지를 설정해야 한다. 헬름 차트를 확인하면 도커 이미지 저장소는 object 스토리지로 나머지 저장소는 블록 스토리지로 설정 추천하는데 이유는 다음과 같다.

도커 이미지 저장소를 object storage(예: Amazon S3)로 사용하는 이유:

  • 확장성: Object storage는 거의 무제한의 저장 용량을 제공하므로, 많은 도커 이미지를 저장할 수 있다.
  • 내구성: Object storage는 데이터를 여러 물리적 위치에 자동으로 복제하므로, 데이터 손실의 위험이 낮다.
  • 비용 효율: 일반적으로 object storage는 용량 당 비용이 낮고, 저장된 데이터에 따라 비용이 증가한다.

기타 저장소를 블록 스토리지(예: AWS EBS)로 저장하는 이유:

  • 높은 IOPS: EBS는 높은 IOPS(Input/Output Operations Per Second) 성능을 제공하므로, 데이터베이스 작업에 적합하다.
  • 지연 시간 최소화: 블록 스토리지는 데이터베이스 작업에 필요한 빠른 읽기/쓰기 작업이 가능하다.
  • 일관된 성능: EBS는 일관된 성능을 제공하여 데이터베이스 작업의 안정성을 보장한다.
  • 스냅샷 및 백업: EBS 볼륨의 스냅샷을 쉽게 생성할 수 있으며, 데이터베이스 백업 및 복구를 용이하게 한다.

추천 스토리지에 따라 스토리지 구성할 것인데 도커 이미지 저장소로는 Minio 오브젝트 스토리지를 사용할 것이다. 그리고 나머지 저장소는 AWS EBS를 사용할 것이다. 또한 백업을 위해 오픈소스 백업 솔루션인 Velero를 사용할 것이다. 종합하여 AWS 아키텍처를 구성하자면 다음과 같다.

eks2.drawio (3).png

통신 시나리오에 따라 색깔을 달리 표현했다.이어서 통신 시나리오 및 세부 컴포넌트(MiniO)을 알아보겠다.

  • users (보라선) : Harbor에 접속해서 도커 이미지를 확인할 수 있는 개발자 및 레지스트리 관리자이다. Harbor 도메인을 통해 ELB를 거쳐 harbor ingress 로 통신한다.
  • Storage(파랑선) : 스토리지 볼륨 연계도이다. 설계 목적과 같이 Harbor Registry 저장소는 Minio로 나머지 저장소는 PV(EBS) 로 적재했다.
  • Backup(초록선) : 백업 툴인 Velero를 통해 S3 에 데이터를 백업시킨다.
  • Admin(빨강선) : 인프라 관리자는 Bestion server에 접속하여 쿠버네티스 및 인프라를 관리한다.

Minio

MinIO 는 AWS의 S3 SDK와 호환되는 오픈소스 Object Storage이다. Minio 모드 중 Distributed Mode는 Minio의 분산 모드로, 여러 서버 또는 노드 간에 데이터를 분산 저장하고 관리할 수 있다. 분산 모드는 높은 가용성, 내구성, 그리고 스케일 아웃 확장성을 제공한다.

구성시 중요한 점으로 Distributed MinIO 의 디스크이다. 분산 모드에서는 최소 4개의 디스크가 필요하다. 분산스토리지의 데이터 복구 기능으로 Erasure Coding 알고리즘을 채택하기 때문인데 원본 데이터를 여러 조각으로 나누고, 각 조각에 대해 패리티 정보를 생성하여 분산 저장한다. 이에따라 데이터 복구에 N/2 데이터 블록과 N/2 패리티 블록 조건을 만족해야 하며 최소 4개 이상의 디스크를 사용하는 것을 권장하기 때문이다. 이렇게 구성하면 최대 패리티에서 MinIO는 삭제 세트당 최대 절반의 드라이브 손실을 허용할 수 있다.

배포

설치 환경 : EKS 클러스터 (k8s 1.24), AWS Ubuntu 인스턴스 솔루션 최소 요구 사항 Harbor (CPU 2 core , 4GB, 40 GB) Distributed MinIO ( CPU 1~2 core, 2~4GB, 분산 Minio) Velero ( CPU 1 core, 1GB, 디스크 공간 알아서..) 원활한 테스트를 위해 약 CPU 5 core 이상, 메모리 8기가 이상이 필요하다. 필자의 경우 워크노드를 c5a.2xlarge 로 3개($0.344 *2) 설성하여 테스트를 진행하였다.

Distributed MinIO 배포

설치는 minio helm 참고하여 구성하였다.

1
2
3
4

helm repo add minio https://charts.bitnami.com/bitnami
helm repo update
helm fetch minio/minio --untar --version 12.2.1

구성 옵션별로 수정은 다음과 같다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# values-minio.yaml 
mode: distributed

auth:
  rootUser: admin
  rootPassword: "admin1234"

statefulset:
  replicaCount: 2
  zones: 2
  drivesPerNode: 1

provisioning:
  config: 
    - name: region
      options:
        name: ap-northeast-2

ingress:
  enabled: true 
  hostname: minio.hanhorang.link
  path: /*
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}, {"HTTPS":9090}]'
    alb.ingress.kubernetes.io/certificate-arn: {ACM arn 입력}

persistence:
  storageClass: "kops-csi-1-21"
  • 분산 모드에서 인스턴스 설정은 statuefulset에서 설정한다.
    • replicaCount: 각 zones당 실행되는 실행되는 파드의 수를 설정한다.
    • zones: AWS의 가용영역이라 생각하면 된다. 분산스토리지로 사용할 영역 개수를 지정한다.
    • drivesPerNode: 각 워커 노드에 연결된 디스크 수를 1개로 설정한다. 이 설정에 따라 각 MinIO 파드는 하나의 디스크를 사용하게 된다.

배포

1
2
kubectl create ns minio
helm install minio minio/minio -f values-minio.yaml -n minio --version 12.2.1

배포 완료후, 도메인으로 접속하여 확인해보자. 도메인은 헬름 차트의 ingress.hostname에 입력한 값이다.

minio1.png

어드민 계정은 차트에서 admin / admin1234 로 설정되어 있다. 로그인을 하자.

로그인이 완료되면 다음과 같은 화면을 확인할 수 있다.

minio2.png

Harbor 연동을 위하여 접속한 Minio 에서 버킷 생성과 Access Key를 발급받아야 한다. 버킷 이름과 Access keys는 Harbor 구성 헬름 차트에서 필요하다.

  • 버킷 생성

    초기 화면 Object Brower 에서 버킷 생성이 가능하다.

  • Access Key 발급

    Access Keys 에서 발급받자.

    Minio3.png

    Create 버튼 잊지말고 클릭하자.

    Access Key 발급 후 MINIO 동작 권한을 등록해야 한다. 생성한 키를 클릭하면 정책 입력 칸이 나온다. 아래 정책을 입력하도록 하자.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "admin:*"
                ]
            },
            {
                "Effect": "Allow",
                "Action": [
                    "kms:*"
                ]
            },
            {
                "Effect": "Allow",
                "Action": [
                    "s3:*"
                ],
                "Resource": [
                    "arn:aws:s3:::*"
                ]
            }
        ]
    }
    

Harbor 배포

Harbor 구성도 마찬가지로 helm로 배포할 것이다. 먼저 헬름 차트를 가져오겠다.

1
2
3
4
helm repo add harbor https://helm.goharbor.io
helm repo update 
# 차트 얻기
helm show values **harbor/harbor** > values.yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#values-harbor.yaml 
# network 설정
expose:
  tls:
    certSource: none
  ingress:
    hosts:
      core: harbor.hanhorang.link
      notary: notary.hanhorang.link
    controller: alb
    className: alb
    annotations: 
      alb.ingress.kubernetes.io/scheme: internet-facing
      alb.ingress.kubernetes.io/target-type: ip
      alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
      alb.ingress.kubernetes.io/certificate-arn: {ACM arn 입력}

externalURL: https://harbor.hanhorang.link
# Storage 설정 
persistence:
  persistentVolumeClaim:
    registry:
      storageClass: "kops-csi-1-21"
    chartmuseum:
      storageClass: "kops-csi-1-21"
    database:
      storageClass: "kops-csi-1-21"
   
  imageChartStorage:
    disableredirect: true
    type: s3 
    s3: 
      region: ap-northeast-2
      bucket: registry 
      accesskey: <minio-access-key>
      secretkey: <minio-secret-key>
      regionendpoint: http://minio.minio.svc.cluster.local:9000

# HA 
core:
  replicas: 3
  • 스토리지 연동은 persistence에서 진행한다. registry 부분 연동은 imageChartStorage에서 설정한다.
  • imageChartStorage.s3 에서 minio 에서 발급받은 키를 입력한다.
  • imageChartStorage.s3.regionpoint 는 minio 의 DNS 정보를 입력했다. 인그래스로 설정이 가능하나, 다음과 같은 에러로 DNS 로 설정하였다. 네트워크 설정으로 오류 발생시 다음의 메세지를 확인하자.

🧐 minio 네트워크 설정 관련 트러블슈팅

regionendpoint 설정에 따라 에러가 발생하여 정리한다.

1
kubectl logs harbor-core-5b7864c575-rnfm9 -n harbor
  • regionendpoint: minio.hanhorang.link 의 경우 도메인은 minio의 ALB 도메인 주소이다. Minio 는 S3와 호환되는 SDK를 가지고 있다. 아래 로그 메세지의 경우 포트를 지정하지 않아 생긴 오류다.

    1
    2
    3
    4
    5
    
    2023-03-21T16:59:40Z [ERROR] [/server/v2.0/handler/project.go:509][requestID="2236a0c4-55cd-4e5c-989d-1b9f941efb25"]: failed to populate properties for project library, error: get chart count of project 1 failed: http error: code 500, message InvalidArgument: S3 API Requests must be made to API port.
            status code: 400, request id: , host id: 
    2023-03-21T16:59:40Z [ERROR] [/server/v2.0/handler/project.go:509][requestID="2236a0c4-55cd-4e5c-989d-1b9f941efb25"]: failed to populate properties for project test, error: get chart count of project 2 failed: http error: code 500, message InvalidArgument: S3 API Requests must be made to API port.
            status code: 400, request id: , host id: 
    2023-03-21T16:59:42Z [ERROR] [/lib/http/error.go:56]: {"errors":[{"code":"UNKNOWN","message":"get chart count of project 2 failed: http error: code 500, message InvalidArgument: S3 API Requests must be made to API port.\n\tstatus code: 400, request id: , host id: "}]}
    
  • regionendpoint: minio.hanhorang.link:9000 경우 포트 9000을 추가하니 Timeout이 발생한다. harbor ALB에서 다시 minio ALB로 거치는 과정에서 시간이 초과된 것으로 예상된다.

    1
    2
    3
    4
    5
    
    2023-03-21T16:55:40Z [ERROR] [/server/v2.0/handler/project.go:509][requestID="a0aed46e-4d11-4459-af04-2efa9f94cbf3"]: failed to populate properties for project library, error: get chart count of project 1 failed: get content failed: send request GET /library/index.yaml failed: Get "http://harbor-chartmuseum/library/index.yaml": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
    2023-03-21T16:55:40Z [ERROR] [/server/v2.0/handler/project.go:509][requestID="a0aed46e-4d11-4459-af04-2efa9f94cbf3"]: failed to populate properties for project test, error: get chart count of project 2 failed: get content failed: send request GET /test/index.yaml failed: Get "http://harbor-chartmuseum/test/index.yaml": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
    2023-03-21T16:55:56Z [ERROR] [/server/v2.0/handler/project.go:509][requestID="8e0c7248-9425-4862-b066-9b4b29151105"]: failed to populate properties for project test, error: get chart count of project 2 failed: get content failed: send request GET /test/index.yaml failed: Get "http://harbor-chartmuseum/test/index.yaml": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
    2023-03-21T16:55:56Z [ERROR] [/server/v2.0/handler/project.go:509][requestID="8e0c7248-9425-4862-b066-9b4b29151105"]: failed to populate properties for project library, error: get chart count of project 1 failed: get content failed: send request GET /library/index.yaml failed: Get "http://harbor-chartmuseum/library/index.yaml": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
    2023-03-21T16:56:29Z [ERROR] [/lib/http/error.go:56]: {"errors":[{"code":"UNKNOWN","message":"get chart count of project 2 failed: get content failed: send request GET /test/index.yaml failed: Get \"http://harbor-chartmuseum/test/index.yaml\": context deadline exceeded (Client.Timeout exceeded while awaiting headers)"}]}
    
  • regionendpoint: minio.minio.svc.cluster.local:9000 경우

    도메인 연결의 최소로 하기 위해 CoreDNS를 사용했다. 그러나 HTTP 설정으로 에러가 발생했다.

    1
    
    2023-03-21T16:35:45Z [ERROR] [/lib/http/error.go:56]: {"errors":[{"code":"UNKNOWN","message":"get chart count of project 2 failed: http error: code 500, message RequestError: send request failed\ncaused by: Get \"https://minio.minio.svc.cluster.local:9000/minio-test?prefix=test\": http: server gave HTTP response to HTTPS client"}]}
    
  • regionendpoint: http://minio.hanhorang.link:9000

    HTTP를 붙이니 정상적으로 연동이 확인된다. 쿠버네티스 내부에서 연결하는 것이라 HTTPS 트래픽 부하를 최소화하는 목적으로 HTTP를 사용하여 설정했다.

1
2
3
kubectl create ns harbor

helm install harbor harbor/harbor -f values-harbor.yaml --namespace harbor --version 1.11.0

배포 확인

헬름차트에서 입력 harbor 도메인으로 접근하면 로그인 화면이 나온다. 초기 admin 유저의 접속 정보는 admin / Harbor12345 이다. 로그인하면 레지스트리 정보가 나온다.

harbor.png

harbor-login.png

New Project 버튼을 눌러 레지스트리 프로젝트에 버킷을 생성하자

harbor-create.png

연동 테스트

임의의 도커 이미지 PULL & PUSH 하여 Harbor 레지스트리, Minio 버킷에 데이터가 저장되는 지 확인해보자.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
docker pull nginx && docker pull busybox && docker images

docker tag busybox harbor.$KOPS_CLUSTER_NAME/test/busybox:0.1
echo 'Harbor12345' > harborpw.txt
cat harborpw.txt | docker login harbor.$KOPS_CLUSTER_NAME -u admin --password-stdin
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

docker push harbor.$KOPS_CLUSTER_NAME/test/busybox:0.1
The push refers to repository [harbor.hanhorang.link/test/busybox]
baacf561cfff: Pushed 
0.1: digest: sha256:acaddd9ed544f7baf3373064064a51250b14cfe3ec604d65765a53da5958e5f5 size: 528

harbor-push.png

minio-push.png

Harbor에 이미지가 저장되고 이어서 minio 버킷에 하버 데이터가 저장된 것을 확인할 수 있다!

이어서

이번 블로그 글에서는 Harbor와 minio를 통해 EKS에서 고가용성 Private Docker Registry(Harbor) 구축을 하였다. 아키텍처 설계를 하면서 스토리지 특성에 대해 딥하게 다룰 수 있는 계기가 되었고, CNCF의 졸업 레벨의 시스템(Harbor)의 아키텍처를 구체적으로 분석할 수 있었다. 느끼는 거지만 간단하면서도 각 컴포넌트가 세부적으로 분산되어 처리된다는 점과 스토리지 연동 부분에서 사례 참고가 되었다.

아키텍처 구축이 끝이 아니다. 운영 레벨의 기능들이 남았다. 다음 글에서는 Velero를 통한 백업과 LDAP 서버와의 연동, Harbor의 기능들에 대해 살펴보겠다.