Kubernetes Helm 기반 Harbor 설치 및 운영 가이드
대상: Kubernetes 환경에 Helm Chart로 Harbor를 설치하는 경우
범위: Ingress 기반 HTTPS, 사설 CA, StorageClass/PVC, Trivy 온라인·오프라인 DB 관리
설치 전 Harbor Helm Chart와 Chart가 설치하는 Harbor App Version을 확인한다.
1. 개요 및 사전 준비
Harbor는 OCI/Docker 이미지, Helm OCI Chart, SBOM 등의 클라우드 네이티브 아티팩트를 저장·배포하는 컨테이너 레지스트리다.
Kubernetes 환경에서는 Harbor 공식 Helm Chart를 사용하여 설치할 수 있다. 다중 노드 고가용성 환경에서는 고가용성 Ingress Controller, 공유 가능한 PVC 또는 Object Storage, 외부 PostgreSQL 및 외부 Redis 구성을 권장한다.
1.1 단일 노드와 HA 구성 비교
| 구분 | 단일 노드 구성 | HA 구성 |
|---|---|---|
| Ingress | 단일 Ingress Controller 가능 | 고가용성 Ingress Controller 필요 |
| Registry Storage | RWO PVC 가능 | RWX PVC 또는 Object Storage 권장 |
| PostgreSQL | Harbor 내부 DB 가능 | 외부 HA PostgreSQL 권장 |
| Redis | Harbor 내부 Redis 가능 | 외부 HA Redis 또는 Sentinel 권장 |
| Harbor Replica | 기본값 1 | Core, Portal, Registry 등 2 이상 |
| Job Log | PVC 또는 DB | DB 저장 권장 |
Harbor Helm 기반 HA 구성에서는 외부 Endpoint, PostgreSQL, Redis, 공유 스토리지 또는 Object Storage를 사용자가 제공해야 한다. Harbor Chart가 외부 인프라의 고가용성을 자동 구성하지는 않는다.
1.2 사전 요구사항
| 항목 | 권장 사항 |
|---|---|
| Kubernetes | 지원 중인 Kubernetes 버전 |
| Helm | Helm v3 |
| Ingress Controller | ingress-nginx, Envoy Gateway, ALB 등 |
| DNS | Harbor FQDN이 Ingress 또는 LoadBalancer IP를 가리켜야 함 |
| StorageClass | 동적 PVC Provisioning 가능해야 함 |
| 인증서 | 공인 CA 또는 사설 CA 인증서 |
| Container Runtime | containerd 또는 CRI-O 권장 |
| 모니터링 | Prometheus, Grafana 연동 권장 |
1.3 네임스페이스 및 Helm Repository 준비
export HARBOR_NAMESPACE="harbor"
export HARBOR_RELEASE="harbor"
export HARBOR_FQDN="harbor.example.internal"
kubectl create namespace "${HARBOR_NAMESPACE}"
helm repo add harbor https://helm.goharbor.io
helm repo update
helm search repo harbor/harbor --versions | head -n 10
현재 Chart의 기본 설정 파일을 내려받는다.
mkdir -p ~/harbor-helm
cd ~/harbor-helm
helm show values harbor/harbor > values.yaml
운영 환경에서는
latest성격의 무고정 설치보다 Chart Version을 명시해 설치하는 것을 권장한다.
helm search repo harbor/harbor --versions
2. 사설 CA 인증서와 trust-ca 구성
운영 환경에서는 HTTPS를 사용한다. 여기서는 10년 유효기간의 사설 Root CA를 만들고, Harbor FQDN에 대한 서버 인증서를 생성한다.
Root CA 인증서는 Harbor Portal 접속 사용자, Docker/Podman 클라이언트, Kubernetes 노드의 containerd 또는 CRI-O에 배포해야 한다.
2.1 환경 변수 설정
export HARBOR_FQDN="harbor.example.internal"
export HARBOR_IP="10.10.10.20"
export CA_DAYS=3650
export SERVER_DAYS=3650
mkdir -p ~/harbor-pki
cd ~/harbor-pki
2.2 10년 사설 Root CA 생성
openssl genrsa -out harbor-root-ca.key 4096
chmod 600 harbor-root-ca.key
openssl req -x509 -new -nodes \
-key harbor-root-ca.key \
-sha256 \
-days "${CA_DAYS}" \
-out harbor-root-ca.crt \
-subj "/C=KR/ST=Seoul/L=Seoul/O=Example/OU=Platform/CN=Example Harbor Root CA"
CA 인증서 정보를 확인한다.
openssl x509 -in harbor-root-ca.crt -noout \
-subject \
-issuer \
-dates
harbor-root-ca.key는 Root CA 개인 키다. Kubernetes Secret이나 Harbor Namespace에 저장하지 않고 별도 PKI 서버 또는 보안 저장소에 보관한다.
2.3 SAN 포함 Harbor 서버 인증서 생성
TLS 클라이언트는 CN만이 아니라 SAN(Subject Alternative Name)을 검증한다. FQDN과 필요 시 Ingress/LoadBalancer IP를 SAN에 포함한다.
cat > "${HARBOR_FQDN}.cnf" <<EOF
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
[req_distinguished_name]
C = KR
ST = Seoul
L = Seoul
O = Example
OU = Platform
CN = ${HARBOR_FQDN}
[v3_req]
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = ${HARBOR_FQDN}
IP.1 = ${HARBOR_IP}
EOF
서버 개인 키와 CSR을 생성한다.
openssl genrsa -out "${HARBOR_FQDN}.key" 4096
chmod 600 "${HARBOR_FQDN}.key"
openssl req -new \
-key "${HARBOR_FQDN}.key" \
-out "${HARBOR_FQDN}.csr" \
-config "${HARBOR_FQDN}.cnf"
Root CA로 서버 인증서를 서명한다.
openssl x509 -req \
-in "${HARBOR_FQDN}.csr" \
-CA harbor-root-ca.crt \
-CAkey harbor-root-ca.key \
-CAcreateserial \
-out "${HARBOR_FQDN}.crt" \
-days "${SERVER_DAYS}" \
-sha256 \
-extensions v3_req \
-extfile "${HARBOR_FQDN}.cnf"
인증서의 SAN과 CA 체인을 검증한다.
openssl x509 \
-in "${HARBOR_FQDN}.crt" \
-noout \
-text | grep -A1 -E "Subject:|Subject Alternative Name"
openssl verify \
-CAfile harbor-root-ca.crt \
"${HARBOR_FQDN}.crt"
2.4 Harbor Ingress TLS Secret 생성
Harbor Namespace에 TLS Secret을 생성한다.
kubectl -n "${HARBOR_NAMESPACE}" create secret tls harbor-ingress-tls \
--cert="${HARBOR_FQDN}.crt" \
--key="${HARBOR_FQDN}.key"
Secret 내용을 확인한다.
kubectl -n "${HARBOR_NAMESPACE}" get secret harbor-ingress-tls
2.5 Harbor 내부 Component용 CA Bundle Secret
사설 CA 인증서가 필요한 내부 연동, 외부 Object Storage, 프록시, 복제 대상 Registry 등을 위해 CA Bundle Secret을 생성한다.
kubectl -n "${HARBOR_NAMESPACE}" create secret generic harbor-ca-bundle \
--from-file=ca.crt=harbor-root-ca.crt
확인한다.
kubectl -n "${HARBOR_NAMESPACE}" describe secret harbor-ca-bundle
2.6 Rocky Linux/RHEL trust-ca 등록
Harbor에 Push/Pull하는 모든 Linux 노드에 적용한다.
sudo cp harbor-root-ca.crt \
/etc/pki/ca-trust/source/anchors/harbor-root-ca.crt
sudo update-ca-trust extract
등록 여부를 확인한다.
trust list | grep -i -A2 "Example Harbor Root CA"
2.7 Docker Client CA 등록
Docker를 사용하는 노드에는 FQDN별 Registry CA도 등록한다.
sudo mkdir -p "/etc/docker/certs.d/${HARBOR_FQDN}"
sudo cp harbor-root-ca.crt \
"/etc/docker/certs.d/${HARBOR_FQDN}/ca.crt"
sudo systemctl restart docker
검증한다.
docker login "${HARBOR_FQDN}"
2.8 containerd 노드 CA 등록
Kubernetes 노드의 Runtime이 containerd라면 모든 Worker Node에 적용한다.
sudo mkdir -p "/etc/containerd/certs.d/${HARBOR_FQDN}"
sudo cp harbor-root-ca.crt \
"/etc/containerd/certs.d/${HARBOR_FQDN}/ca.crt"
sudo tee "/etc/containerd/certs.d/${HARBOR_FQDN}/hosts.toml" > /dev/null <<EOF
server = "https://${HARBOR_FQDN}"
[host."https://${HARBOR_FQDN}"]
capabilities = ["pull", "resolve", "push"]
ca = "/etc/containerd/certs.d/${HARBOR_FQDN}/ca.crt"
EOF
sudo systemctl restart containerd
RKE2, k3s, OpenShift, EKS, GKE, AKS 등은 별도 Private Registry CA 배포 방식을 제공할 수 있으므로, 해당 배포판의 공식 방법을 우선 적용한다.
3. Helm 기반 Harbor 설치
3.1 StorageClass 확인
Harbor는 기본적으로 PVC를 사용한다. 먼저 기본 StorageClass를 확인한다.
kubectl get storageclass
예시 출력:
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE
rook-ceph-block rook-ceph.rbd.csi.ceph.com Delete Immediate
nfs-client (default) cluster.local/nfs-client Delete Immediate
운영 환경에서는 StorageClass와 데이터 특성에 따라 다음을 검토한다.
| Harbor 구성 요소 | 권장 스토리지 |
|---|---|
| Registry 이미지 데이터 | Object Storage 또는 고성능 PVC |
| PostgreSQL | 저지연 Block Storage |
| Redis | 저지연 Block Storage |
| Jobservice 로그 | PVC 또는 Database |
| Trivy Cache/DB | PVC |
| HA Registry | RWX PVC 또는 Object Storage |
3.2 values.yaml 예시
다음은 ingress-nginx, 사설 CA TLS Secret, 내부 DB/Redis, PVC, Trivy 활성화 기준의 예시다.
expose:
type: ingress
tls:
enabled: true
certSource: secret
secret:
secretName: harbor-ingress-tls
ingress:
className: nginx
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
hosts:
core: harbor.example.internal
externalURL: https://harbor.example.internal
harborAdminPassword: "CHANGE_THIS_ADMIN_PASSWORD"
secretKey: "CHANGE_ME_16CHAR"
caSecretName: harbor-ca-bundle
caBundleSecretName: harbor-ca-bundle
persistence:
enabled: true
# helm uninstall 이후 PVC 자동 삭제 방지
resourcePolicy: "keep"
persistentVolumeClaim:
registry:
storageClass: "nfs-client"
accessMode: ReadWriteOnce
size: 200Gi
jobservice:
jobLog:
storageClass: "nfs-client"
accessMode: ReadWriteOnce
size: 10Gi
database:
storageClass: "nfs-client"
accessMode: ReadWriteOnce
size: 20Gi
redis:
storageClass: "nfs-client"
accessMode: ReadWriteOnce
size: 10Gi
trivy:
storageClass: "nfs-client"
accessMode: ReadWriteOnce
size: 20Gi
imageChartStorage:
type: filesystem
filesystem:
rootdirectory: /storage
trivy:
enabled: true
resources:
requests:
cpu: 200m
memory: 512Mi
limits:
cpu: "1"
memory: 1Gi
severity: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL"
ignoreUnfixed: false
vulnType: "os,library"
securityCheck: "vuln,config,secret"
skipUpdate: false
skipJavaDBUpdate: false
offlineScan: false
dbRepository:
- "mirror.gcr.io/aquasec/trivy-db"
- "ghcr.io/aquasecurity/trivy-db"
javaDBRepository:
- "mirror.gcr.io/aquasec/trivy-java-db"
- "ghcr.io/aquasecurity/trivy-java-db"
proxy:
httpProxy: ""
httpsProxy: ""
noProxy: "127.0.0.1,localhost,.local,.internal,.svc,.cluster.local"
components:
- core
- jobservice
- trivy
metrics:
enabled: true
serviceMonitor:
enabled: false
cache:
enabled: false
expireHours: 24
database:
type: internal
internal:
password: "CHANGE_THIS_DATABASE_PASSWORD"
shmSizeLimit: 1Gi
redis:
type: internal
jobservice:
maxJobWorkers: 10
jobLoggers:
- file
logLevel: info
secretKey는 16자 문자열이어야 한다. 운영 환경에서는harborAdminPassword,database.internal.password,secretKey를 Git 저장소에 평문으로 보관하지 말고 External Secrets, Sealed Secrets, SOPS 등을 사용한다.
3.3 Secret 기반 관리자 비밀번호 설정
관리자 비밀번호를 values.yaml에서 분리하려면 Secret을 생성한다.
kubectl -n "${HARBOR_NAMESPACE}" create secret generic harbor-admin-password \
--from-literal=HARBOR_ADMIN_PASSWORD='CHANGE_THIS_ADMIN_PASSWORD'
values.yaml에서 다음처럼 설정한다.
existingSecretAdminPassword: harbor-admin-password
existingSecretAdminPasswordKey: HARBOR_ADMIN_PASSWORD
3.4 Helm Install
먼저 렌더링 결과를 확인한다.
helm template "${HARBOR_RELEASE}" harbor/harbor \
--namespace "${HARBOR_NAMESPACE}" \
--values values.yaml \
> harbor-rendered.yaml
차트를 설치한다.
helm upgrade --install "${HARBOR_RELEASE}" harbor/harbor \
--namespace "${HARBOR_NAMESPACE}" \
--create-namespace \
--values values.yaml \
--wait \
--timeout 15m
특정 Chart Version을 고정하려면 다음처럼 설치한다.
helm upgrade --install "${HARBOR_RELEASE}" harbor/harbor \
--namespace "${HARBOR_NAMESPACE}" \
--create-namespace \
--version "<CHART_VERSION>" \
--values values.yaml \
--wait \
--timeout 15m
3.5 설치 상태 확인
kubectl get pods -n "${HARBOR_NAMESPACE}"
kubectl get svc -n "${HARBOR_NAMESPACE}"
kubectl get ingress -n "${HARBOR_NAMESPACE}"
kubectl get pvc -n "${HARBOR_NAMESPACE}"
helm list -n "${HARBOR_NAMESPACE}"
Pod 상태가 모두 Running 또는 Completed인지 확인한다.
kubectl get pod -n "${HARBOR_NAMESPACE}" -o wide
문제가 발생하면 Helm Release 상태와 Pod 이벤트를 확인한다.
helm status "${HARBOR_RELEASE}" \
-n "${HARBOR_NAMESPACE}"
kubectl get events \
-n "${HARBOR_NAMESPACE}" \
--sort-by='.lastTimestamp'
kubectl describe pod \
-n "${HARBOR_NAMESPACE}" \
<POD_NAME>
3.6 접속 및 Push/Pull 테스트
Harbor Portal 접속 주소:
https://harbor.example.internal
로그인 정보:
ID: admin
Password: harborAdminPassword 또는 existingSecretAdminPassword의 값
Portal에서 Projects → + New Project로 이동하여 platform 프로젝트를 생성한다.
Docker Push/Pull 테스트:
export HARBOR_FQDN="harbor.example.internal"
docker login "${HARBOR_FQDN}"
docker tag nginx:1.27 \
"${HARBOR_FQDN}/platform/nginx:1.27"
docker push \
"${HARBOR_FQDN}/platform/nginx:1.27"
docker pull \
"${HARBOR_FQDN}/platform/nginx:1.27"
Kubernetes Pod에서 Harbor 이미지를 Pull하는 예시:
apiVersion: v1
kind: Pod
metadata:
name: harbor-pull-test
namespace: default
spec:
containers:
- name: nginx
image: harbor.example.internal/platform/nginx:1.27
imagePullSecrets:
- name: harbor-registry-credential
Docker Registry 인증 Secret 생성:
kubectl create secret docker-registry harbor-registry-credential \
--namespace default \
--docker-server="${HARBOR_FQDN}" \
--docker-username="<HARBOR_USER>" \
--docker-password="<HARBOR_PASSWORD>"
4. Trivy 온라인·오프라인 DB 관리
Trivy의 취약점 탐지 결과는 Vulnerability DB 최신성에 따라 달라진다.
| 데이터 | 용도 | 필요 여부 |
|---|---|---|
| Vulnerability DB | OS 및 패키지 CVE 탐지 | 필수 |
| Java DB | JAR 기반 Java 패키지 탐지 | Java 스캔 시 권장 |
| Checks Bundle | IaC 및 설정 오류 검사 | config 검사 시 필요 |
4.1 온라인 환경 Trivy 설정
온라인 환경에서는 skipUpdate: false를 유지한다.
trivy:
enabled: true
skipUpdate: false
skipJavaDBUpdate: false
offlineScan: false
securityCheck: "vuln,config,secret"
dbRepository:
- "mirror.gcr.io/aquasec/trivy-db"
- "ghcr.io/aquasecurity/trivy-db"
javaDBRepository:
- "mirror.gcr.io/aquasec/trivy-java-db"
- "ghcr.io/aquasecurity/trivy-java-db"
GitHub API Rate Limit이 문제되는 환경에서는 GitHub Token을 설정한다.
trivy:
gitHubToken: "<GITHUB_TOKEN>"
Token은 values.yaml에 직접 기록하기보다 Secret 또는 Helm Secret 관리 도구를 통해 주입한다.
온라인 환경에서 Trivy 로그를 확인한다.
kubectl logs \
-n "${HARBOR_NAMESPACE}" \
deployment/"${HARBOR_RELEASE}"-trivy \
--tail=300
Pod 이름을 직접 확인하려면 다음을 사용한다.
kubectl get pods \
-n "${HARBOR_NAMESPACE}" \
-l component=trivy
4.2 온라인 환경 DB 사전 다운로드
인터넷 연결이 가능한 중계 서버에서 Trivy DB만 미리 받을 수 있다.
mkdir -p ~/trivy-cache
trivy image \
--cache-dir ~/trivy-cache \
--download-db-only
Java JAR 스캔이 필요하면 Java DB도 받는다.
trivy image \
--cache-dir ~/trivy-cache \
--download-java-db-only
캐시 파일을 확인한다.
find ~/trivy-cache -maxdepth 3 -type f
일반적으로 확인해야 할 파일은 다음과 같다.
db/trivy.db
db/metadata.json
java-db/trivy-java.db
4.3 오프라인 환경 values.yaml 설정
폐쇄망에서는 Trivy DB의 외부 다운로드를 차단한다.
trivy:
enabled: true
skipUpdate: true
skipJavaDBUpdate: true
offlineScan: true
securityCheck: "vuln,config,secret"
persistence:
enabled: true
persistentVolumeClaim:
trivy:
existingClaim: harbor-trivy-cache
accessMode: ReadWriteOnce
size: 20Gi
offlineScan: true는 Trivy가 Java dependency 식별 등을 위해 외부 API에 접근하는 동작을 줄인다. 이 값은 DB 다운로드 자체를 막지 않으므로, 폐쇄망에서는skipUpdate: true도 함께 설정해야 한다.
4.4 오프라인 Trivy PVC 생성
NFS StorageClass 기준의 PVC 예시다.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: harbor-trivy-cache
namespace: harbor
spec:
accessModes:
- ReadWriteOnce
storageClassName: nfs-client
resources:
requests:
storage: 20Gi
적용한다.
kubectl apply -f harbor-trivy-cache-pvc.yaml
kubectl get pvc \
-n "${HARBOR_NAMESPACE}" \
harbor-trivy-cache
4.5 인터넷 구간에서 DB Package 생성
인터넷 연결 구간의 서버에서 실행한다.
export TRIVY_EXPORT_DIR="$HOME/trivy-offline"
rm -rf "${TRIVY_EXPORT_DIR}"
mkdir -p "${TRIVY_EXPORT_DIR}"
trivy image \
--cache-dir "${TRIVY_EXPORT_DIR}" \
--download-db-only
trivy image \
--cache-dir "${TRIVY_EXPORT_DIR}" \
--download-java-db-only
tar czvf "trivy-db-$(date +%F).tar.gz" \
-C "${TRIVY_EXPORT_DIR}" .
sha256sum "trivy-db-$(date +%F).tar.gz" \
> "trivy-db-$(date +%F).tar.gz.sha256"
생성 파일:
trivy-db-YYYY-MM-DD.tar.gz
trivy-db-YYYY-MM-DD.tar.gz.sha256
4.6 폐쇄망 Kubernetes에 Trivy DB 적재
폐쇄망 환경으로 tarball과 checksum 파일을 반입한다.
sha256sum -c trivy-db-YYYY-MM-DD.tar.gz.sha256
Trivy PVC에 DB를 복사할 임시 Pod를 실행한다.
apiVersion: v1
kind: Pod
metadata:
name: trivy-db-loader
namespace: harbor
spec:
restartPolicy: Never
containers:
- name: loader
image: busybox:1.36
command:
- sh
- -c
- sleep 36000
volumeMounts:
- name: trivy-cache
mountPath: /trivy-cache
volumes:
- name: trivy-cache
persistentVolumeClaim:
claimName: harbor-trivy-cache
kubectl apply -f trivy-db-loader.yaml
kubectl get pod \
-n "${HARBOR_NAMESPACE}" \
trivy-db-loader
반입한 DB 파일을 Loader Pod로 전송한다.
kubectl cp \
trivy-db-YYYY-MM-DD.tar.gz \
"${HARBOR_NAMESPACE}/trivy-db-loader:/tmp/trivy-db.tar.gz"
Pod 내부에서 DB를 풀고 Trivy Cache 경로에 배치한다.
kubectl exec \
-n "${HARBOR_NAMESPACE}" \
trivy-db-loader \
-- sh -c '
mkdir -p /trivy-cache/db
mkdir -p /trivy-cache/java-db
mkdir -p /tmp/trivy-import
tar xzvf /tmp/trivy-db.tar.gz -C /tmp/trivy-import
find /tmp/trivy-import -name trivy.db \
-exec cp -f {} /trivy-cache/db/trivy.db \;
find /tmp/trivy-import -name metadata.json \
-exec cp -f {} /trivy-cache/db/metadata.json \;
find /tmp/trivy-import -name trivy-java.db \
-exec cp -f {} /trivy-cache/java-db/trivy-java.db \;
find /trivy-cache -maxdepth 3 -type f
'
작업이 끝나면 Loader Pod를 삭제한다.
kubectl delete pod \
-n "${HARBOR_NAMESPACE}" \
trivy-db-loader
Harbor 설치 또는 업그레이드를 수행한다.
helm upgrade --install "${HARBOR_RELEASE}" harbor/harbor \
--namespace "${HARBOR_NAMESPACE}" \
--values values.yaml \
--wait \
--timeout 15m
4.7 정기 Trivy DB 업데이트
온라인 환경
온라인 환경은 skipUpdate: false를 유지한다.
DB 업데이트 상태를 확인한다.
kubectl logs \
-n "${HARBOR_NAMESPACE}" \
deployment/"${HARBOR_RELEASE}"-trivy \
--tail=300 | egrep -i "download|update|db|error"
Trivy Adapter를 재시작하려면 다음을 실행한다.
kubectl rollout restart deployment \
-n "${HARBOR_NAMESPACE}" \
"${HARBOR_RELEASE}"-trivy
kubectl rollout status deployment \
-n "${HARBOR_NAMESPACE}" \
"${HARBOR_RELEASE}"-trivy
기존 이미지의 취약점 결과를 최신 DB 기준으로 갱신하려면 Harbor Portal에서 전체 재스캔 일정을 설정한다.
Administration
→ Interrogation Services
→ Vulnerability
→ Schedule to scan all
오프라인 환경
폐쇄망은 다음 주기를 권장한다.
| 작업 | 권장 주기 | 설명 |
|---|---|---|
| 인터넷 구간 DB 다운로드 | 매일 | 신규 CVE 반영 |
| 반입 파일 SHA-256 검증 | 매 반입 | 무결성 확인 |
| Trivy PVC DB 교체 | 매일 또는 주 1회 | 보안 정책에 맞춤 |
| 전체 이미지 재스캔 | 매일 또는 매주 | 새 DB 기준 재평가 |
폐쇄망 DB 갱신 순서:
- 인터넷 구간에서 최신 DB를 내려받는다.
- tarball과 SHA-256 파일을 폐쇄망으로 반입한다.
- 무결성을 검증한다.
trivy-db-loaderPod를 실행한다.- PVC의
db/trivy.db,db/metadata.json,java-db/trivy-java.db를 교체한다. - Trivy Deployment를 재시작한다.
- Harbor Portal에서 전체 재스캔을 수행하거나 스케줄을 실행한다.
Trivy Pod 재시작:
kubectl rollout restart deployment \
-n "${HARBOR_NAMESPACE}" \
"${HARBOR_RELEASE}"-trivy
kubectl rollout status deployment \
-n "${HARBOR_NAMESPACE}" \
"${HARBOR_RELEASE}"-trivy
Appendix #1. HA 구성과 외부 서비스 설정
운영 규모가 크거나 Harbor 중단을 줄여야 한다면 내부 PostgreSQL/Redis 대신 외부 고가용성 서비스를 사용한다.
A.1 외부 PostgreSQL 설정
database:
type: external
external:
host: "postgresql-ha.example.internal"
port: "5432"
username: "harbor"
password: "CHANGE_THIS_PASSWORD"
coreDatabase: "registry"
notaryServerDatabase: "notary_server"
notarySignerDatabase: "notary_signer"
sslmode: "require"
Harbor Core Database는 사전에 생성한다.
CREATE USER harbor WITH ENCRYPTED PASSWORD 'CHANGE_THIS_PASSWORD';
CREATE DATABASE registry OWNER harbor;
A.2 외부 Redis 설정
redis:
type: external
external:
addr: "redis-ha.example.internal:6379"
password: "CHANGE_THIS_PASSWORD"
databaseIndex: "0"
Redis Sentinel 구성 예시:
redis:
type: external
external:
addr: "redis-sentinel-1.example.internal:26379,redis-sentinel-2.example.internal:26379,redis-sentinel-3.example.internal:26379"
sentinelMasterSet: "mymaster"
password: "CHANGE_THIS_PASSWORD"
databaseIndex: "0"
A.3 Object Storage 기반 Registry 설정
HA 환경에서 Registry 이미지를 Object Storage에 저장하는 S3 예시다.
persistence:
imageChartStorage:
type: s3
s3:
region: "ap-northeast-2"
bucket: "harbor-registry"
regionendpoint: "https://s3.ap-northeast-2.amazonaws.com"
secure: true
v4auth: true
rootdirectory: "/harbor"
existingSecret: "harbor-s3-credential"
S3 인증 Secret에는 다음 Key가 필요하다.
REGISTRY_STORAGE_S3_ACCESSKEY
REGISTRY_STORAGE_S3_SECRETKEY
Secret 생성 예시:
kubectl -n "${HARBOR_NAMESPACE}" create secret generic harbor-s3-credential \
--from-literal=REGISTRY_STORAGE_S3_ACCESSKEY='<ACCESS_KEY>' \
--from-literal=REGISTRY_STORAGE_S3_SECRETKEY='<SECRET_KEY>'
A.4 Harbor Helm Upgrade
업그레이드 전 현재 설정과 데이터를 백업한다.
helm get values "${HARBOR_RELEASE}" \
-n "${HARBOR_NAMESPACE}" \
-a > harbor-values-backup.yaml
kubectl get pvc \
-n "${HARBOR_NAMESPACE}"
kubectl get secret \
-n "${HARBOR_NAMESPACE}"
Repository를 업데이트하고 변경 내용을 확인한다.
helm repo update
helm diff upgrade "${HARBOR_RELEASE}" harbor/harbor \
--namespace "${HARBOR_NAMESPACE}" \
--values values.yaml
업그레이드를 수행한다.
helm upgrade "${HARBOR_RELEASE}" harbor/harbor \
--namespace "${HARBOR_NAMESPACE}" \
--values values.yaml \
--wait \
--timeout 30m
업그레이드 상태를 확인한다.
helm status "${HARBOR_RELEASE}" \
-n "${HARBOR_NAMESPACE}"
kubectl get pods \
-n "${HARBOR_NAMESPACE}"
Harbor 업그레이드 전에는 대상 Chart Version의 릴리스 노트, 지원 Kubernetes 버전, DB Migration 요구사항, Trivy 호환성을 반드시 확인한다.