5. Harbor 서버 설치 및 구성하기 (1)

Taeho Kim·2026년 1월 20일
post-thumbnail

1. 네임서버 설정

이전 단계에서 구성한 내부 DNS 서버를 Harbor 서버의 네임서버로 설정합니다.

nmcli con show

NAME    UUID                                  TYPE      DEVICE 
enp0s1  e69cd965-7eae-3ea0-a891-b56c47641dd2  ethernet  enp0s1 
lo      822b460f-14fe-47e9-bd75-6bc29a12f85c  loopback  lo    
nmcli con mod enp0s1 ipv4.dns "192.168.56.53 1.1.1.1" ipv4.ignore-auto-dns yes
nmcli con mod enp0s1 ipv6.ignore-auto-dns yes
nmcli con up enp0s1

그럼 설정한 도메인에 대해 정상적으로 질의하는 것을 확인할 수 있습니다.

[root@harbor-registry-server ~]# dig harbor.home.internal

; <<>> DiG 9.16.23-RH <<>> harbor.home.internal
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 36577
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 0d7b7a9d8778ca4b01000000696f954f5ce5c3d6ed95845b (good)
;; QUESTION SECTION:
;harbor.home.internal.          IN      A

;; ANSWER SECTION:
harbor.home.internal.   60      IN      A       192.168.56.60

;; Query time: 0 msec
;; SERVER: 192.168.56.53#53(192.168.56.53)
;; WHEN: Tue Jan 20 23:46:39 KST 2026
;; MSG SIZE  rcvd: 93

AWS S3를 Harbor의 백엔드로 이용할 예정이기 때문에 S3 통신 상태도 확인해주었습니다.

[root@harbor-registry-server ~]# curl -I https://s3.ap-northeast-2.amazonaws.com/

HTTP/1.1 405 Method Not Allowed
x-amz-request-id: DRTR1ES359RK3A4W
x-amz-id-2: sO0mf/5YU4CFWXwDK08BDnPcRitUITVQFy92c+2lNBC4sW/V7xNYV1eo5fop8k8v0KVR88GpPnoSymU7Wv+rQt+8XEgJYQaY
Allow: GET
Content-Type: application/xml
Transfer-Encoding: chunked
Date: Tue, 20 Jan 2026 14:49:26 GMT
Server: AmazonS3

2. 왜 /data를 마운트하는가?

Harbor는 내부적으로 다음을 파일시스템에 저장합니다.

  • PostgreSQL(DB) 데이터 디렉터리
  • Redis 데이터
  • Harbor 설정/시크릿/인증서 파일
  • 작업 중 임시 파일, 로그 등

해당 정보들을 저장하기 위한 외부 디스크를 /data 마운트합니다.

로컬 스토리지가 아닌 외부 블록 스토리지에 해당 정보들을 저장함으로써 다음과 같은 효과를 기대할 수 있습니다.

  • 데이터 계층 분리: OS 영역과 Harbor 운영 데이터를 분리하여, OS 업데이트/재설치 시에도 /data 볼륨을 유지할 수 있습니다.
  • 복구 용이성: Harbor 장애(설정 오류, 컨테이너 재배포 등) 발생 시 /data 볼륨만 보존하면 메타데이터(PostgreSQL/Redis)와 설정을 빠르게 복구할 수 있습니다.
  • 백업 단위 명확화: Harbor 운영 데이터는 /data로 고정되어 스냅샷/백업 정책을 단일 지점에 적용할 수 있습니다.
  • 확장/이관 용이성: 추후 Harbor 서버를 교체하거나 고가용성 구성으로 확장할 때도 /data 볼륨을 기준으로 데이터 이동과 복제 전략을 수립할 수 있습니다.
  • 책임 분리: 이미지 블롭 저장소는 S3가 담당하고, 메타데이터/설정은 블록 스토리지가 담당하는 구조로, 장애 원인과 운영 책임을 분리할 수 있습니다

3. /data 전용 디스크 마운트

1. Harbor 서버에 디스크를 추가

2. 디스크를 추가하고 부팅한 다음 확인

[root@harbor-registry-server ~]# lsblk

NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sr0          11:0    1 1024M  0 rom  
vda         252:0    0  100G  0 disk 
├─vda1      252:1    0  600M  0 part /boot/efi
├─vda2      252:2    0    1G  0 part /boot
└─vda3      252:3    0 98.4G  0 part 
  ├─rl-root 253:0    0 63.5G  0 lvm  /
  ├─rl-swap 253:1    0  3.9G  0 lvm  [SWAP]
  └─rl-home 253:2    0   31G  0 lvm  /home
vdb         252:16   0  200G  0 disk 

3. 파일시스템 생성 (XFS 권장)

[root@harbor-registry-server ~]# mkfs.xfs -f /dev/vdb

meta-data=/dev/vdb               isize=512    agcount=4, agsize=13107200 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=1    bigtime=1 inobtcount=1
data     =                       bsize=4096   blocks=52428800, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=25600, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
Discarding blocks...Done.

4. /data 마운트

mkdir -p /data
mount /dev/vdb /data
df -h /data

정상적으로 마운트되었다면 아래와 같은 정보를 출력합니다.

Filesystem      Size  Used Avail Use% Mounted on
/dev/vdb        200G  1.5G  199G   1% /data

5. 디스크를 영구적으로 마운트

UUID를 확인합니다.

[root@harbor-registry-server ~]# blkid /dev/vdb

/dev/vdb: UUID="95336391-2f40-453b-85df-2afa9298eed4" TYPE="xfs"

etc/fstab에 고정하여 재부팅에도 마운트가 유지되도록 합니다.

echo 'UUID=95336391-2f40-453b-85df-2afa9298eed4  /data  xfs  defaults,nofail  0  2' >> /etc/fstab

6. Harbor에서 사용할 디렉터리 준비

mkdir -p /data/harbor /data/cert

4. docker-compose 설치하기

1. Docker + Compose 설치

dnf install -y yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
systemctl enable --now docker

docker version
docker compose version

5. 사설 CA + Harbor 서버 인증서 생성

[root@harbor-registry-server ~]# ls -l /data/cert
total 0

1. 인증서 디렉터리 준비

mkdir -p /data/cert
cd /data/cert

2. Root CA 생성

openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 \
  -subj "/C=KR/O=LAB/OU=CA/CN=LAB-ROOT-CA" \
  -out ca.crt

3. Harbor 서버 인증서 생성(SAN 포함)

openssl genrsa -out harbor.key 4096

cat > harbor-openssl.cnf <<'EOF'
[ req ]
default_bits       = 4096
prompt             = no
default_md         = sha256
distinguished_name = dn
req_extensions     = req_ext

[ dn ]
C  = KR
O  = LAB
OU = Harbor
CN = harbor.home.internal

[ req_ext ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = harbor.home.internal
IP.1  = 192.168.56.60
EOF

openssl req -new -key harbor.key -out harbor.csr -config harbor-openssl.cnf

openssl x509 -req -in harbor.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
  -out harbor.crt -days 825 -sha256 -extensions req_ext -extfile harbor-openssl.cnf

4. 인증서 생성 확인

ls -l /data/cert
openssl x509 -in /data/cert/harbor.crt -noout -subject -issuer -ext subjectAltName
[root@harbor-registry-server cert]# ls -l /data/cert
openssl x509 -in /data/cert/harbor.crt -noout -subject -issuer -ext subjectAltName
total 28
-rw-r--r--. 1 root root 1919 Jan 21 00:31 ca.crt
-rw-------. 1 root root 3268 Jan 21 00:31 ca.key
-rw-r--r--. 1 root root   41 Jan 21 00:31 ca.srl
-rw-r--r--. 1 root root  309 Jan 21 00:31 harbor-openssl.cnf
-rw-r--r--. 1 root root 1968 Jan 21 00:31 harbor.crt
-rw-r--r--. 1 root root 1736 Jan 21 00:31 harbor.csr
-rw-------. 1 root root 3272 Jan 21 00:31 harbor.key
subject=C=KR, O=LAB, OU=Harbor, CN=harbor.home.internal
issuer=C=KR, O=LAB, OU=CA, CN=LAB-ROOT-CA
X509v3 Subject Alternative Name: 
    DNS:harbor.home.internal, IP Address:192.168.56.60

출력에 DNS:harbor.home.internal / IP Address:192.168.56.60이 보이면 성공입니다.


6. Harbor 설치하기

1. Harbor offline installer 다운로드/압축 해제cd /opt

dnf install -y wget tar
cd /opt
wget -O harbor-offline-installer-v2.10.1.tgz \
  https://github.com/goharbor/harbor/releases/download/v2.10.1/harbor-offline-installer-v2.10.1.tgz

tar xzvf harbor-offline-installer-v2.10.1.tgz
cd harbor
ls

2. harbor.yml 만들기

cp harbor.yml.tmpl harbor.yml
vi harbor.yml
hostname: harbor.home.internal

https:
  port: 443
  certificate: /data/cert/harbor.crt
  private_key: /data/cert/harbor.key

harbor_admin_password: "Password!"

data_volume: /data

storage_service:
  s3:
    region: ap-northeast-2
    bucket: harbor-backend-7f3a9c2d
    accesskey: "${S3_ACCESS_KEY}"
    secretkey: "${S3_SECRET_KEY}"
    regionendpoint: "https://s3.ap-northeast-2.amazonaws.com"
    secure: true
    v4auth: true
    encrypt: true

AWS 계정의 Access Key와 Secret Key는 절대 노출하지 않도록 합니다.

  1. 서버에서만 환경변수로 주입
read -p "S3_ACCESS_KEY: " S3_ACCESS_KEY
echo
read -s -p "S3_SECRET_KEY: " S3_SECRET_KEY
echo
export S3_ACCESS_KEY S3_SECRET_KEY
  1. 키 파일을 따로 만들고 권한으로 숨기기

시크릿 파일 생성(권한 600)

install -m 600 /dev/null /root/harbor-s3.env
vi /root/harbor-s3.env

/root/harbor-s3.env 내용(서버에만 존재)

S3_ACCESS_KEY=AKIA...
S3_SECRET_KEY=...

설치할 때만 로드

set -a
. /root/harbor-s3.env
set +a

./prepare
./install.sh

에러 상황

  1. exec /usr/bin/python3: exec format error는 컨테이너 안 실행 파일(python3)의 CPU 아키텍처가 호스트와 달라 실행이 거부됐다는 뜻이다.
  2. 현재 환경은 arm64(Mac + UTM + Rocky arm64)인데, goharbor/prepare:v2.10.1 이미지는 linux/amd64 단일 아키텍처로 내려받혔다.
  3. docker manifest inspect 결과의 mediaType: application/vnd.docker.distribution.manifest.v2+json는 싱글-arch 매니페스트를 의미하며, 멀티아키(amd64/arm64)를 지원하는 경우처럼 manifest.list/OCI index와 platform 목록이 없다.
  4. 따라서 arm64 환경에서 amd64 이미지(prepare)를 실행하려다 exec format error가 발생했고, Harbor v2.10.1 오프라인 설치본이 arm64에 네이티브로 맞지 않는 상황이다.

profile
interested in operating Kubernetes efficiently.

0개의 댓글