Harbor 컨테이너 레지스트리 플랫폼 구축 및 마이그레이션

문한성·2025년 9월 19일
0
post-thumbnail

프로젝트 개요

기존 Docker Registry에서 엔터프라이즈급 Harbor 플랫폼으로 전환하며, Harbor의 내장 Registry 기능을 활용한 자동 마이그레이션과 재해복구 체계를 구축한 프로젝트입니다. 7개 팀, 30명의 사용자가 사용하는 AI/ML 플랫폼의 컨테이너 레지스트리를 무중단으로 전환했습니다.

핵심 성과

  • 마이그레이션 시간 85% 단축 (Harbor Registry 기능 활용)
  • 무중단 전환 달성 (Zero Downtime)
  • 자동 백업 체계 구축 (DockerHub 복제 정책)
  • 보안 강화 (Trivy 취약점 자동 스캔)
  • 연간 $2,880 비용 절감 (Docker Hub 대비)

시스템 아키텍처

Harbor 플랫폼 구성

Infrastructure:
  - Kubernetes: v1.28
  - Harbor: v2.6.0
  - Storage: 300GB (PersistentVolume)
  - Nodes: 7대 분산 배포
  - TLS: 자체 서명 인증서

Core Components:
  - Harbor Core: API 서버, 비즈니스 로직
  - Harbor Portal: 웹 UI
  - Harbor Registry: Docker Registry v2
  - Harbor JobService: 비동기 작업 처리
  - PostgreSQL: 메타데이터 저장
  - Redis: 세션 캐시
  - Trivy: 취약점 스캐너

멀티 테넌시 구조

Harbor Platform
├── Team Projects (10개)
│   ├── team1-dev / team1-prod
│   ├── team2-dev / team2-prod
│   ├── team3-dev / team3-prod
│   ├── team4-dev / team4-prod
│   └── team5-dev / team5-prod
├── Common Resources
│   ├── base-images
│   └── shared-libraries
└── DockerHub Proxy
    └── cached-images

핵심 구현 내용

1. Harbor Registry API를 활용한 스크립트 기반 마이그레이션

Registry Endpoint 등록 및 복제 스크립트

#!/bin/bash
"""
Harbor Registry API를 활용한 마이그레이션 스크립트
기존 Docker Registry를 Harbor에 등록하고 복제 정책 생성
"""

# 색상 설정
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# Harbor 설정
HARBOR_URL="https://harbor.internal:30443"
HARBOR_USER="admin"
HARBOR_PASS="${HARBOR_PASSWORD}"

# 소스 레지스트리 설정
SOURCE_REGISTRY="legacy-registry.internal:5000"

echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}Harbor Registry 마이그레이션 시작${NC}"
echo -e "${BLUE}========================================${NC}"

# 1. 소스 레지스트리를 Harbor에 엔드포인트로 등록
register_source_registry() {
    echo -e "${YELLOW}1. 소스 레지스트리 등록 중...${NC}"
    
    REGISTRY_RESPONSE=$(curl -k -s -X POST \
        -u "${HARBOR_USER}:${HARBOR_PASS}" \
        -H "Content-Type: application/json" \
        "${HARBOR_URL}/api/v2.0/registries" \
        -d "{
            \"name\": \"legacy-docker-registry\",
            \"type\": \"docker-registry\",
            \"url\": \"${SOURCE_REGISTRY}\",
            \"description\": \"기존 Docker Registry (마이그레이션 소스)\",
            \"insecure\": true,
            \"credential\": {
                \"type\": \"basic\",
                \"access_key\": \"\",
                \"access_secret\": \"\"
            }
        }")
    
    # Registry ID 조회
    REGISTRY_ID=$(curl -k -s -u "${HARBOR_USER}:${HARBOR_PASS}" \
        "${HARBOR_URL}/api/v2.0/registries" | \
        jq -r '.[] | select(.name=="legacy-docker-registry") | .id')
    
    echo -e "${GREEN}✅ 레지스트리 등록 완료: ID=${REGISTRY_ID}${NC}"
    echo $REGISTRY_ID
}

# 2. 팀별 복제 정책 생성
create_team_replication_policies() {
    local REGISTRY_ID=$1
    
    echo -e "${YELLOW}2. 팀별 복제 정책 생성 중...${NC}"
    
    # 팀 프로젝트 배열
    TEAM_PROJECTS=(
        "team1-dev"
        "team1-prod"
        "team2-dev"
        "team2-prod"
        "team3-dev"
        "team3-prod"
        "team4-dev"
        "team4-prod"
        "team5-dev"
        "team5-prod"
    )
    
    POLICY_IDS=()
    
    for PROJECT in "${TEAM_PROJECTS[@]}"; do
        echo -n "  ${PROJECT} 정책 생성..."
        
        POLICY_RESPONSE=$(curl -k -s -X POST \
            -u "${HARBOR_USER}:${HARBOR_PASS}" \
            -H "Content-Type: application/json" \
            "${HARBOR_URL}/api/v2.0/replication/policies" \
            -d "{
                \"name\": \"migrate-${PROJECT}\",
                \"description\": \"Migration policy for ${PROJECT}\",
                \"src_registry\": {
                    \"id\": ${REGISTRY_ID}
                },
                \"dest_registry\": null,
                \"dest_namespace\": \"${PROJECT}\",
                \"filters\": [
                    {
                        \"type\": \"name\",
                        \"value\": \"${PROJECT}/**\"
                    }
                ],
                \"trigger\": {
                    \"type\": \"manual\"
                },
                \"enabled\": true,
                \"deletion\": false,
                \"override\": true,
                \"speed\": -1
            }")
        
        # Policy ID 추출
        POLICY_ID=$(curl -k -s -u "${HARBOR_USER}:${HARBOR_PASS}" \
            "${HARBOR_URL}/api/v2.0/replication/policies" | \
            jq -r ".[] | select(.name==\"migrate-${PROJECT}\") | .id")
        
        if [ -n "$POLICY_ID" ]; then
            POLICY_IDS+=($POLICY_ID)
            echo -e " ${GREEN}✅ (ID: ${POLICY_ID})${NC}"
        else
            echo -e " ${RED}${NC}"
        fi
    done
    
    echo "${POLICY_IDS[@]}"
}

# 3. 병렬 복제 실행
execute_parallel_replication() {
    local POLICY_IDS=($@)
    
    echo -e "${YELLOW}3. 병렬 복제 실행 중...${NC}"
    
    EXECUTION_IDS=()
    
    # 모든 정책을 동시에 실행
    for POLICY_ID in "${POLICY_IDS[@]}"; do
        echo -n "  정책 ${POLICY_ID} 실행..."
        
        EXEC_RESPONSE=$(curl -k -s -X POST \
            -u "${HARBOR_USER}:${HARBOR_PASS}" \
            -H "Content-Type: application/json" \
            "${HARBOR_URL}/api/v2.0/replication/executions" \
            -d "{\"policy_id\": ${POLICY_ID}}")
        
        # Execution ID 추출
        EXEC_ID=$(curl -k -s -X POST \
            -u "${HARBOR_USER}:${HARBOR_PASS}" \
            -H "Content-Type: application/json" \
            -d "{\"policy_id\": ${POLICY_ID}}" \
            -I "${HARBOR_URL}/api/v2.0/replication/executions" | \
            grep -i location | sed 's/.*\/\([0-9]*\).*/\1/' | tr -d '\r')
        
        if [ -n "$EXEC_ID" ]; then
            EXECUTION_IDS+=($EXEC_ID)
            echo -e " ${GREEN}✅ (Execution ID: ${EXEC_ID})${NC}"
        else
            echo -e " ${RED}${NC}"
        fi
    done
    
    echo "${EXECUTION_IDS[@]}"
}

# 4. 복제 진행 상황 모니터링
monitor_replication_progress() {
    local EXECUTION_IDS=($@)
    
    echo -e "${YELLOW}4. 복제 진행 상황 모니터링...${NC}"
    
    while true; do
        ALL_COMPLETED=true
        TOTAL_SUCCESS=0
        TOTAL_FAILED=0
        TOTAL_PROGRESS=0
        
        echo -e "\n${BLUE}현재 복제 상태:${NC}"
        
        for EXEC_ID in "${EXECUTION_IDS[@]}"; do
            STATUS_INFO=$(curl -k -s -u "${HARBOR_USER}:${HARBOR_PASS}" \
                "${HARBOR_URL}/api/v2.0/replication/executions/${EXEC_ID}")
            
            STATUS=$(echo "$STATUS_INFO" | jq -r '.status')
            TOTAL=$(echo "$STATUS_INFO" | jq -r '.total // 0')
            SUCCESS=$(echo "$STATUS_INFO" | jq -r '.success_task_count // 0')
            FAILED=$(echo "$STATUS_INFO" | jq -r '.failed_task_count // 0')
            
            case $STATUS in
                "InProgress")
                    echo "  Execution ${EXEC_ID}: 🔄 진행 중 (${SUCCESS}/${TOTAL})"
                    ALL_COMPLETED=false
                    TOTAL_PROGRESS=$((TOTAL_PROGRESS + 1))
                    ;;
                "Succeed")
                    echo "  Execution ${EXEC_ID}: ✅ 완료 (${SUCCESS} 이미지)"
                    TOTAL_SUCCESS=$((TOTAL_SUCCESS + SUCCESS))
                    ;;
                "Failed")
                    echo "  Execution ${EXEC_ID}: ❌ 실패 (성공: ${SUCCESS}, 실패: ${FAILED})"
                    TOTAL_FAILED=$((TOTAL_FAILED + FAILED))
                    ;;
                *)
                    echo "  Execution ${EXEC_ID}: 📊 ${STATUS}"
                    ALL_COMPLETED=false
                    ;;
            esac
        done
        
        echo -e "\n${BLUE}전체 진행 상황:${NC}"
        echo "  성공한 이미지: ${TOTAL_SUCCESS}개"
        echo "  실패한 이미지: ${TOTAL_FAILED}개"
        echo "  진행 중인 작업: ${TOTAL_PROGRESS}개"
        
        if $ALL_COMPLETED; then
            echo -e "\n${GREEN}🎉 모든 복제 작업이 완료되었습니다!${NC}"
            break
        fi
        
        echo -e "\n30초 후 다시 확인..."
        sleep 30
    done
}

# 메인 실행 로직
main() {
    # 1. 소스 레지스트리 등록
    REGISTRY_ID=$(register_source_registry)
    
    # 2. 팀별 복제 정책 생성
    POLICY_IDS=($(create_team_replication_policies $REGISTRY_ID))
    
    # 3. 병렬 복제 실행
    EXECUTION_IDS=($(execute_parallel_replication "${POLICY_IDS[@]}"))
    
    # 4. 진행 상황 모니터링
    monitor_replication_progress "${EXECUTION_IDS[@]}"
    
    # 5. 최종 결과 요약
    echo -e "\n${BLUE}========================================${NC}"
    echo -e "${BLUE}마이그레이션 완료${NC}"
    echo -e "${BLUE}========================================${NC}"
    echo "총 프로젝트: ${#POLICY_IDS[@]}개"
    echo "실행된 작업: ${#EXECUTION_IDS[@]}개"
}

# 스크립트 실행
main

2. DockerHub 백업 복제 스크립트

Harbor API를 통한 자동 백업 구성

#!/bin/bash
"""
DockerHub 백업 복제 정책 설정 스크립트
Production 이미지를 DockerHub에 자동 복제
"""

# 색상 설정
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# Harbor 정보
HARBOR_URL="https://harbor.internal:30443"
HARBOR_USER="admin"
HARBOR_PASS="${HARBOR_PASSWORD}"

# DockerHub 정보
DOCKERHUB_USER="company-backup"
DOCKERHUB_TOKEN="${DOCKERHUB_TOKEN}"

echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}DockerHub 백업 복제 설정${NC}"
echo -e "${BLUE}========================================${NC}"

# 1. 기존 복제 정책 정리
cleanup_existing_policies() {
    echo -e "${YELLOW}1. 기존 복제 정책 삭제...${NC}"
    
    # DockerHub 백업 관련 정책 조회 및 삭제
    POLICIES=$(curl -k -s -u "${HARBOR_USER}:${HARBOR_PASS}" \
        "${HARBOR_URL}/api/v2.0/replication/policies" | \
        jq -r '.[] | select(.name | contains("dockerhub-backup")) | .id')
    
    for POLICY_ID in $POLICIES; do
        echo "  복제 정책 삭제 중: ID=$POLICY_ID"
        curl -k -X DELETE -u "${HARBOR_USER}:${HARBOR_PASS}" \
            "${HARBOR_URL}/api/v2.0/replication/policies/${POLICY_ID}"
        echo -e "  ${GREEN}✅ 정책 ${POLICY_ID} 삭제됨${NC}"
    done
}

# 2. DockerHub Registry Endpoint 생성
create_dockerhub_endpoint() {
    echo -e "${YELLOW}2. DockerHub Registry Endpoint 생성...${NC}"
    
    ENDPOINT_RESPONSE=$(curl -k -s -X POST \
        -u "${HARBOR_USER}:${HARBOR_PASS}" \
        -H "Content-Type: application/json" \
        "${HARBOR_URL}/api/v2.0/registries" \
        -d "{
            \"name\": \"dockerhub\",
            \"type\": \"docker-hub\",
            \"url\": \"https://index.docker.io\",
            \"insecure\": false,
            \"credential\": {
                \"type\": \"basic\",
                \"access_key\": \"${DOCKERHUB_USER}\",
                \"access_secret\": \"${DOCKERHUB_TOKEN}\"
            },
            \"description\": \"Docker Hub registry for production backup\"
        }")
    
    # 생성된 엔드포인트 ID 가져오기
    REGISTRY_ID=$(curl -k -s -u "${HARBOR_USER}:${HARBOR_PASS}" \
        "${HARBOR_URL}/api/v2.0/registries" | \
        jq -r '.[] | select(.name=="dockerhub") | .id')
    
    echo -e "${GREEN}✅ Docker Hub 엔드포인트가 생성되었습니다. (ID: ${REGISTRY_ID})${NC}"
    echo $REGISTRY_ID
}

# 3. Production 프로젝트별 백업 정책 생성
create_backup_policies() {
    local REGISTRY_ID=$1
    
    echo -e "${YELLOW}3. Production 프로젝트 백업 정책 생성...${NC}"
    
    # Production 프로젝트 배열
    PROD_PROJECTS=(
        "team1-prod"
        "team2-prod"
        "team3-prod"
        "team4-prod"
        "team5-prod"
    )
    
    for PROJECT in "${PROD_PROJECTS[@]}"; do
        echo -n "  ${PROJECT} 백업 정책 생성..."
        
        POLICY_RESPONSE=$(curl -k -s -X POST \
            -u "${HARBOR_USER}:${HARBOR_PASS}" \
            -H "Content-Type: application/json" \
            "${HARBOR_URL}/api/v2.0/replication/policies" \
            -d "{
                \"name\": \"dockerhub-backup-${PROJECT}\",
                \"description\": \"Backup ${PROJECT} images to Docker Hub\",
                \"src_registry\": null,
                \"dest_registry\": {
                    \"id\": ${REGISTRY_ID}
                },
                \"dest_namespace\": \"${DOCKERHUB_USER}\",
                \"dest_namespace_replace_count\": 1,
                \"filters\": [
                    {
                        \"type\": \"name\",
                        \"value\": \"${PROJECT}/**\"
                    },
                    {
                        \"type\": \"tag\",
                        \"value\": \"{v*.*.*,latest}\"
                    }
                ],
                \"trigger\": {
                    \"type\": \"event_based\"
                },
                \"enabled\": true,
                \"deletion\": false,
                \"override\": true,
                \"speed\": -1
            }")
        
        # Policy ID 확인
        POLICY_ID=$(curl -k -s -u "${HARBOR_USER}:${HARBOR_PASS}" \
            "${HARBOR_URL}/api/v2.0/replication/policies" | \
            jq -r ".[] | select(.name==\"dockerhub-backup-${PROJECT}\") | .id")
        
        if [ -n "$POLICY_ID" ]; then
            echo -e " ${GREEN}✅ (ID: ${POLICY_ID})${NC}"
        else
            echo -e " ${RED}${NC}"
        fi
    done
}

# 4. 테스트 복제 실행
test_backup_replication() {
    echo -e "${YELLOW}4. 테스트 복제 실행...${NC}"
    
    # 첫 번째 정책으로 테스트
    TEST_POLICY_ID=$(curl -k -s -u "${HARBOR_USER}:${HARBOR_PASS}" \
        "${HARBOR_URL}/api/v2.0/replication/policies" | \
        jq -r '.[] | select(.name | startswith("dockerhub-backup-")) | .id' | head -1)
    
    if [ -n "$TEST_POLICY_ID" ]; then
        echo "  테스트 정책 ID: ${TEST_POLICY_ID}"
        
        EXEC_RESPONSE=$(curl -k -s -X POST \
            -u "${HARBOR_USER}:${HARBOR_PASS}" \
            -H "Content-Type: application/json" \
            "${HARBOR_URL}/api/v2.0/replication/executions" \
            -d "{\"policy_id\": ${TEST_POLICY_ID}}")
        
        echo -e "${GREEN}✅ 테스트 복제가 시작되었습니다.${NC}"
        
        # 복제 상태 확인
        monitor_test_replication
    fi
}

# 5. 복제 상태 모니터링
monitor_test_replication() {
    echo -e "${YELLOW}5. 복제 상태 확인 (60초 대기)...${NC}"
    
    for i in {1..12}; do
        sleep 5
        
        STATUS=$(curl -k -s -u "${HARBOR_USER}:${HARBOR_PASS}" \
            "${HARBOR_URL}/api/v2.0/replication/executions?policy_id=${TEST_POLICY_ID}&page_size=1" | \
            jq -r '.[0].status')
        
        echo "  상태 확인 ($i/12): $STATUS"
        
        if [ "$STATUS" = "Succeed" ]; then
            echo -e "${GREEN}✅ 복제가 성공적으로 완료되었습니다!${NC}"
            
            # 상세 정보 표시
            EXEC_INFO=$(curl -k -s -u "${HARBOR_USER}:${HARBOR_PASS}" \
                "${HARBOR_URL}/api/v2.0/replication/executions?policy_id=${TEST_POLICY_ID}&page_size=1" | \
                jq -r '.[0]')
            
            echo "  성공: $(echo $EXEC_INFO | jq -r '.success_task_count // 0')개"
            echo "  실패: $(echo $EXEC_INFO | jq -r '.failed_task_count // 0')개"
            break
            
        elif [ "$STATUS" = "Failed" ]; then
            echo -e "${RED}❌ 복제가 실패했습니다.${NC}"
            
            # 실패 원인 확인
            EXEC_ID=$(curl -k -s -u "${HARBOR_USER}:${HARBOR_PASS}" \
                "${HARBOR_URL}/api/v2.0/replication/executions?policy_id=${TEST_POLICY_ID}&page_size=1" | \
                jq -r '.[0].id')
            
            echo "실패 원인:"
            curl -k -s -u "${HARBOR_USER}:${HARBOR_PASS}" \
                "${HARBOR_URL}/api/v2.0/replication/executions/${EXEC_ID}/tasks" | \
                jq -r '.[0] | {status: .status, src_resource: .src_resource, dst_resource: .dst_resource}'
            break
        fi
    done
}

# 메인 실행 로직
main() {
    # 1. 기존 정책 정리
    cleanup_existing_policies
    
    # 2. DockerHub 엔드포인트 생성
    REGISTRY_ID=$(create_dockerhub_endpoint)
    
    # 3. 백업 정책 생성
    create_backup_policies $REGISTRY_ID
    
    # 4. 테스트 복제 실행
    test_backup_replication
    
    echo ""
    echo -e "${BLUE}========================================${NC}"
    echo -e "${BLUE}설정 완료${NC}"
    echo -e "${BLUE}========================================${NC}"
    echo ""
    echo "Docker Hub에서 확인: https://hub.docker.com/r/${DOCKERHUB_USER}"
    echo "이제 Production 프로젝트에 이미지를 Push하면 자동으로 DockerHub에 백업됩니다."
    echo ""
}

# 스크립트 실행
main

3. 병렬 복제 실행 관리

#!/usr/bin/env python3
"""
Harbor 복제 작업 병렬 실행 및 관리
여러 프로젝트를 동시에 마이그레이션
"""

import concurrent.futures
from typing import List, Dict

class ParallelReplicationManager:
    def __init__(self, harbor_url: str, harbor_auth: tuple):
        self.harbor_url = harbor_url
        self.harbor_auth = harbor_auth
        self.api_base = f"{harbor_url}/api/v2.0"
        
    def execute_parallel_migration(self, policies: List[int], max_workers: int = 5):
        """여러 복제 정책을 병렬로 실행"""
        
        with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
            futures = {}
            
            # 각 정책별로 복제 실행
            for policy_id in policies:
                future = executor.submit(self._execute_single_replication, policy_id)
                futures[future] = policy_id
            
            # 결과 수집
            results = []
            for future in concurrent.futures.as_completed(futures):
                policy_id = futures[future]
                try:
                    result = future.result()
                    results.append({
                        'policy_id': policy_id,
                        'status': result['status'],
                        'statistics': result.get('statistics', {})
                    })
                    
                    # 실시간 진행 상황 출력
                    total = result['statistics'].get('total', 0)
                    success = result['statistics'].get('success', 0)
                    failed = result['statistics'].get('failed', 0)
                    
                    print(f"Policy {policy_id}: Total={total}, Success={success}, Failed={failed}")
                    
                except Exception as e:
                    logging.error(f"Policy {policy_id} 실행 실패: {e}")
                    results.append({
                        'policy_id': policy_id,
                        'status': 'failed',
                        'error': str(e)
                    })
            
            return results
    
    def _execute_single_replication(self, policy_id: int) -> Dict:
        """단일 복제 정책 실행 및 모니터링"""
        
        # 복제 시작
        response = requests.post(
            f"{self.api_base}/replication/executions",
            json={"policy_id": policy_id},
            auth=self.harbor_auth
        )
        
        if response.status_code != 201:
            raise Exception(f"복제 시작 실패: {response.text}")
        
        execution_id = int(response.headers['Location'].split('/')[-1])
        
        # 완료까지 대기
        while True:
            exec_response = requests.get(
                f"{self.api_base}/replication/executions/{execution_id}",
                auth=self.harbor_auth
            )
            
            if exec_response.status_code == 200:
                execution = exec_response.json()
                
                if execution['status'] in ['Succeeded', 'Failed', 'Stopped']:
                    # 최종 통계 조회
                    tasks_response = requests.get(
                        f"{self.api_base}/replication/executions/{execution_id}/tasks",
                        auth=self.harbor_auth
                    )
                    
                    tasks = tasks_response.json() if tasks_response.status_code == 200 else []
                    
                    return {
                        'status': execution['status'],
                        'statistics': {
                            'total': len(tasks),
                            'success': len([t for t in tasks if t['status'] == 'Succeeded']),
                            'failed': len([t for t in tasks if t['status'] == 'Failed'])
                        }
                    }
            
            time.sleep(10)

4. 복제 정책 모니터링 대시보드

#!/usr/bin/env python3
"""
Harbor 복제 상태 모니터링 및 리포팅
"""

class ReplicationMonitor:
    def __init__(self, harbor_url: str, harbor_auth: tuple):
        self.harbor_url = harbor_url
        self.harbor_auth = harbor_auth
        self.api_base = f"{harbor_url}/api/v2.0"
    
    def generate_migration_report(self) -> Dict:
        """마이그레이션 종합 리포트 생성"""
        
        # 모든 복제 정책 조회
        policies = requests.get(
            f"{self.api_base}/replication/policies",
            auth=self.harbor_auth
        ).json()
        
        report = {
            'total_policies': len(policies),
            'active_policies': 0,
            'executions': [],
            'statistics': {
                'total_replicated': 0,
                'total_size': 0,
                'success_rate': 0
            }
        }
        
        for policy in policies:
            if policy['enabled']:
                report['active_policies'] += 1
            
            # 최근 실행 내역 조회
            executions = requests.get(
                f"{self.api_base}/replication/executions",
                params={'policy_id': policy['id'], 'limit': 5},
                auth=self.harbor_auth
            ).json()
            
            for execution in executions:
                tasks = requests.get(
                    f"{self.api_base}/replication/executions/{execution['id']}/tasks",
                    auth=self.harbor_auth
                ).json()
                
                exec_summary = {
                    'policy_name': policy['name'],
                    'execution_id': execution['id'],
                    'status': execution['status'],
                    'start_time': execution['start_time'],
                    'end_time': execution.get('end_time'),
                    'total_tasks': len(tasks),
                    'succeeded': len([t for t in tasks if t['status'] == 'Succeeded']),
                    'failed': len([t for t in tasks if t['status'] == 'Failed'])
                }
                
                report['executions'].append(exec_summary)
                report['statistics']['total_replicated'] += exec_summary['succeeded']
        
        # 성공률 계산
        total_tasks = sum(e['total_tasks'] for e in report['executions'])
        total_succeeded = sum(e['succeeded'] for e in report['executions'])
        
        if total_tasks > 0:
            report['statistics']['success_rate'] = (total_succeeded / total_tasks) * 100
        
        return report

성능 및 효과

Harbor Registry 기능 활용 효과

메트릭수동 마이그레이션Harbor Registry API개선율
총 이미지 수2,847개2,847개-
마이그레이션 시간48시간7.2시간85% 단축
동시 처리 수1개10개10배 향상
수동 작업100%10%90% 자동화
오류 복구수동자동 재시도완전 자동화

복제 정책 운영 현황

정책 유형개수빈도평균 처리 시간
레거시 마이그레이션11회성7.2시간
DockerHub 백업5Push 이벤트30초
크로스 리전 복제2실시간15초
개발→운영 프로모션10수동 트리거2분

트러블슈팅 경험

1. 대용량 이미지 복제 시 타임아웃

문제: 10GB 이상 이미지 복제 중 타임아웃 발생
해결:

# Harbor 설정 조정
policy_update = {
    "speed": -1,  # 속도 제한 해제
    "decoration": {
        "timeout": 3600  # 타임아웃 1시간으로 증가
    }
}

2. 동시 복제 시 리소스 부족

문제: 10개 이상 동시 복제 시 Harbor JobService OOM
해결:

# JobService 리소스 증설
resources:
  limits:
    memory: 4Gi  # 2Gi → 4Gi
    cpu: 2000m
  requests:
    memory: 2Gi
    cpu: 1000m

3. Registry 인증 토큰 만료

문제: 장시간 복제 중 소스 레지스트리 토큰 만료
해결:

  • Registry credential refresh 로직 추가
  • Harbor 2.6.0의 자동 토큰 갱신 기능 활용

교훈

  1. Harbor 내장 기능 활용의 중요성

    • Registry API로 복잡한 스크립트 불필요
    • 내장 재시도 로직으로 안정성 향상
  2. Event-driven 복제의 효율성

    • Push 이벤트 기반 실시간 백업
    • 불필요한 스케줄 작업 제거
  3. 병렬 처리 최적화

    • JobService 워커 수 조정 필요
    • 네트워크 대역폭 고려한 동시 실행 수 결정

프로젝트 성과 요약

Harbor의 내장 Registry 복제 기능을 최대한 활용하여, 복잡한 스크립트 없이도 효율적인 마이그레이션과 백업 체계를 구축했습니다. 특히 병렬 복제 실행Event-driven 백업으로 운영 효율성을 극대화했습니다.

기술 스택: Harbor API, Kubernetes, Python, Docker Registry V2, PostgreSQL, Redis

profile
기록하고 공유하려고 노력하는 DevOps 엔지니어

0개의 댓글