Harbor로 내부 컨테이너 레지스트리 구축하기

동관·2025년 6월 25일
post-thumbnail

Harbor란 CNCF(Cloud Native Computing Foundation)에서 관리되는 오픈소스 컨테이너 이미지 레지스트리이다.

Harbor를 써야 하는 이유

AWS EKS를 쓴다면 AWS ECR(Elastic Container Registry), GCP GKE를 쓴다면 GCP Artifact Registry를 사용하면 되는데, 왜 굳이 Harbor를 써야 하는걸까?

클라우드 컨테이너 플랫폼 서비스를 사용한다면, 일반적으로 해당 CSP 사의 클라우드 이미지 저장소를 사용하면 된다(비용도 저렴함).

아래의 경우 Harbor 도입을 고민해볼 수 있다.

외부 이미지 저장소를 사용할 수 없는 경우

개발 환경이 내부 인트라넷망으로 구성되어 외부 인터넷망과 통신할 수 없어 Docker Hub는 물론 AWS ECR, GCP Artifact Registry도 사용할 수 없는 경우라면 Harbor를 자체적으로 구성해 사용할 수 있다.

외부 이미지 저장소 인증 토큰을 주기적으로 갱신시켜야 하는 경우

AWS ECR의 경우 기본적으로 레지스트리 인증 토큰이 12시간만 유효하다.

AWS EKS 내부에서는 자체적인 절차를 통해 토큰을 갱신시킬 필요가 없지만, 다른 계정에 있는 이미지를 사용해야 하거나, 개발 환경이 아예 AWS와 분리되어있다면 12시간마다 토큰을 갱신시켜줘야 이미지를 Pull 할 수 있다.

The generated token is valid for 12 hours, which means developers running and managing container images have to re-authenticate every 12 hours manually, or script it to generate a new token, which can be somewhat cumbersome in a CI/CD environment.

이 경우 Harbor를 구축해 Harbor의 계정 만료 시간 설정을 통해 원하는 주기를 조절하여 또는 무기한으로 인증하여 사용할 수 있다.

외부 이미지 저장소 비용을 절약하려는 경우

AWS ECR, GCP Artifact Registry 등 컨테이너 이미지 저장소 비용은 일반적으로 높지 않다.

그럼에도 불구하고 저장소의 사용량이 많아 비용이 높게 책정되는 경우도 있을 것이고, 특히 이미지 취약점 스캔 비용이 높게 책정될 수 있다.

Harbor는 Trivy(기본)을 통해 이미지 취약점 스캔을 지원하기 때문에 해당 비용을 절약하기 위해 사용할 수 있다.

이 외에도 다양한 목적을 가지고 Harbor를 자체 구성하여 사용할 수 있을 것이다.

필자의 경우 외부 이미지 저장소 인증 토큰을 주기적으로 갱신시켜야 하는 경우 때문에 개발 환경(온-프레미스 쿠버네티스 클러스터)에서 사용하는 저장소를 AWS ECR에서 Harbor로 변경하여 구성해놓았다.

“갱신 그거 그냥 주기적으로 자동화시켜놓으면 되는거 아닌가요?” 라는 의문이 들 수 있지만, 필자는 관리 포인트를 가급적 줄이고 싶었고(갱신 배치 설정 및 수행 여부 확인 등), 내부 환경에 필요한 이미지를 굳이 외부에 저장할 이유는 없다고 생각했다.

AWS EKS 환경에서는 AWS ECR을 사용 중이며, GCP GKE를 사용했을 때에도 GCP Artifact Registry를 사용했다.

설치 & 사용

Kubernetes 환경에 설치하고 이를 사용해보는 간단한 예제이다.

Harbor 공식 문서를 기반하여 작성하였고 Kubernetes 클러스터에 배포할 것이기에 Helm을 통해 설치하였다.

helm repo add harbor https://helm.goharbor.io
helm show values harbor/harbor > values.yaml
vi values.yaml # 본인 환경에 맞게 수정
helm install --create-namespace harbor -n harbor harbor/harbor -f values.yaml
[root@kube-master ~]# k get po -n harbor
NAME                                READY   STATUS    RESTARTS   AGE
harbor-core-86d966f68-pcxwr         1/1     Running   0          8d
harbor-database-0                   1/1     Running   0          8d
harbor-jobservice-975bf4887-mwsm6   1/1     Running   0          8d
harbor-nginx-cc75d9994-mzqtp        1/1     Running   0          8d
harbor-portal-fffc56c6-4fx77        1/1     Running   0          8d
harbor-redis-0                      1/1     Running   0          8d
harbor-registry-559f784dbd-zd8nc    2/2     Running   0          8d
harbor-trivy-0                      1/1     Running   0          8d

배포가 완료되었으면 harbor-nginx Deployment를 외부에 노출시켜 접속하면 된다.

외부로 노출시키는 방법은 Ingress, Load Balancer, NodePort 중 자유롭게 선택하면 되고 중요한 점은 Harbor는 TLS 설정없이(http://….) 브라우저에서 로그인을 시도할 시 CSRF token invalid 에러를 뱉으며 로그인이 되지 않는다.

때문에 도메인을 설정해주고 인증서 발급 후 TLS 설정을 해줘야 로그인이 가능하다.

필자는 Gateway API를 사용 중인데 도메인 설정 후 Cert-Manager를 통해 자동으로 인증서가 발급되어서 사용했고, 인증서 설정 방법은 여러가지이기 때문에(Ingress TLS, Nginx Certbot, …) 자유롭게 설정하면 된다.

웹 접속 후 초기 계정 정보를 입력하고 (admin / Harbor12345) 로그인하면 아래와 같이 홈 화면이 보인다.

Projects > +NEW PROJECT 를 통해 프로젝트를 생성하여 이미지를 저장하면 되고 docker build[HARBOR_URL]/[PROJECT_NAME]/[IMAGE_NAME]:[TAG]로 이미지를 생성하면 된다.

필자는 이미 사용 중이기 때문에 Projects 여러가지 존재한다.

Harbor에 이미지를 Push/Pull 하는 것은 User 또는 Robot Account를 만들어 수행하면 된다.

User는 웹에 접속할 수 있는 로그인 계정이고, Robot Account는 웹에 로그인할 필요없이 권한과 인증 정보만 필요할 때 사용하는 계정이다.

주로 CI/CD 스크립트에 Robot Account를 사용하면 된다.

Administration > Robot Accounts > + NEW ROBOT ACCOUNT 를 통해 계정명과 권한을 설정해주면 해당 계정에 인증할 때 사용하는 시크릿이 발급되니 저장해두고 다음 과정에 사용하면 된다.

docker login -u robot$[ROBOT_ACCOUNT_NAME] -p [ROBOT_ACCOUNT_SECRET] [HARBOR_URL]

해당 인증 후 docker push, docker pull 을 통해 성공적으로 이미지를 저장하고 가져올 수 있다.

Kubernetes ImagePullSecret

Kubernetes 클러스터에 생성할 이미지를 Harbor에 저장했다면, 적절한 인증 정보를 기입해주어야 해당 이미지를 Pull 하여 Pod가 생성될 것이다.

kubectl create secret docker-registry [SECRET_NAME] \
--docker-username=[ROBOT_ACCOUNT_NAME] \
--docker-password=[ROBOT_ACCOUNT_SECRET] \
--docker-server=[HARBOR_URL]

그 후 생성된 Secret을 Deployment Spec에 imagePullSecret으로 명시하거나 Service Accunt imagePullSecrets에 설정해주면 정상적으로 Pod를 생성할 수 있다.

취약점 스캔

생성한 Project의 Configuration에서 Vulnerability scanning - [Automatically scan images on push] 을 통해 이미지를 Push 할 때마다 취약점 스캔을 할지 정할 수 있으며, 업로드된 이미지 하나를 클릭해 조회해보면 어떤 취약점이 발견되고 어느 버전으로 업데이트 해야 하는지 확인할 수 있다.

그 외에도 다른 레지스트리와 연동해 Replication 하는 기능이나, 이미지 삭제 정책, Webhook을 설정할 수 있으니 공식 문서를 참고해 필요한 기능을 사용해보면 좋다.

참고

profile
안녕하세요. 방문해주셔서 감사합니다.

0개의 댓글