# WORKS Drive Docker Image Archive ## 목적 WORKS Drive는 Docker Registry HTTP API v2 backend로 직접 사용하지 않는다. 대신 프로덕션 배포용 Docker 이미지를 `docker save` 결과물로 내보내고, zstd 압축 archive와 검증 파일을 WORKS Shared Drive에 보관하는 CLI 기반 보조 저장소로 사용한다. 이 방식은 다음 상황을 목표로 한다. - Harbor 또는 공용 Registry 장애 시 수동 복구용 이미지 보관 - 작은 규모의 프로덕션 배포 이미지 이관 - `docker load` 기반 오프라인 배포 Harbor는 이 흐름의 1차 이미지 저장소다. Gitea Actions의 publish workflow가 `reg.hmac.kr/baron_sso/:` 형태로 이미지를 push하고, staging/production deploy workflow는 같은 image tag를 Harbor에서 pull한다. WORKS Drive는 같은 이미지를 별도로 보관하는 복구용 archive이며, staging/prod가 평상시에 직접 pull하는 대상이 아니다. ## 현재 Gitea Actions 설정 상태 2026-06-19 기준 repo Actions 설정에서 Harbor 변수/시크릿은 등록되어 있다. - `HARBOR_ENDPOINT=https://reg.hmac.kr` - `HARBOR_HOSTNAME=reg.hmac.kr` - `HARBOR_ROBOT_ACCOUNT=robot$namecard_sso` - secret `HARBOR_ROBOT_KEY` Docker image archive 업로드 단계는 `.gitea/workflows/production_image_publish.yml`의 `Upload pushed images to WORKS Drive archive` step에서 실행된다. 단, 이 step은 다음 조건을 만족할 때만 실행된다. ```yaml if: ${{ vars.WORKS_DRIVE_DOCKER_IMAGE_ARCHIVE_ENABLED == 'true' }} ``` 현재 repo Actions 설정에는 Docker image archive용 WORKS Drive 변수/시크릿이 등록되어 있지 않다. 업로드를 켜려면 최소한 다음 값을 등록해야 한다. - variable `WORKS_DRIVE_DOCKER_IMAGE_ARCHIVE_ENABLED=true` - variable `WORKS_SHAREDRIVE_DOCKER_IMAGE_DIR=docker-build-image` - variable `WORKS_DRIVE_SHARED_DRIVE_ID` - 선택 variable `WORKS_DRIVE_PARENT_FILE_ID` - secret `WORKS_DRIVE_OAUTH_CLIENT_ID` - secret `WORKS_DRIVE_OAUTH_CLIENT_SECRET` - secret `WORKS_DRIVE_OAUTH_CLIENT_SERVICE_ACCOUNT` - secret `WORKS_DRIVE_OAUTH_CLIENT_PRIVATE_KEY` - refresh token 방식을 쓸 경우 secret `WORKS_DRIVE_OAUTH_REFRESH_TOKEN` ## 저장 구조 기본 최상위 디렉터리는 다음 환경 변수로 지정한다. ```dotenv WORKS_SHAREDRIVE_DOCKER_IMAGE_DIR=docker-build-image ``` 이미지는 WORKS Shared Drive에서 다음 구조로 저장한다. ```text docker-build-image/// image.tar.zst image.tar.zst.sha256 manifest.json ``` 예시: ```text docker-build-image/baron_sso/backend/v1.2606.ab12/ image.tar.zst image.tar.zst.sha256 manifest.json ``` Registry hostname은 저장 경로에서 제외한다. 예를 들어 `registry.example/baron_sso/backend:v1.2606.ab12`는 `baron_sso/backend/v1.2606.ab12` 아래에 저장한다. ## Manifest `manifest.json`에는 다음 정보를 기록한다. - archive format: `docker-save-zstd` - 원본 `image_ref` - repository path - tag - Docker image id - Git commit - archive 파일명, 크기, sha256 - WORKS Drive remote path - 복원 명령 예시 복원은 다음 흐름으로 처리한다. ```bash sha256sum -c image.tar.zst.sha256 zstd -d -c image.tar.zst | docker load ``` ## 업로드 CLI 로컬 컨테이너를 먼저 이미지로 commit한 뒤 업로드하려면 다음처럼 실행한다. ```bash WORKS_SHAREDRIVE_DOCKER_IMAGE_DIR=docker-build-image \ WORKS_DOCKER_COMMIT_CONTAINER=baron_backend \ DOCKER_IMAGE_REF=registry.example/baron_sso/backend:v1.2606.ab12 \ scripts/docker-image/upload_works_drive.sh ``` 이미지가 이미 로컬에 있으면 `WORKS_DOCKER_COMMIT_CONTAINER`를 생략한다. ```bash DOCKER_IMAGE_REF=registry.example/baron_sso/backend:v1.2606.ab12 \ scripts/docker-image/upload_works_drive.sh ``` 실제 업로드에는 기존 백업 업로드와 같은 WORKS Drive 인증 변수를 사용한다. - `WORKS_DRIVE_TARGET=sharedrive` - `WORKS_DRIVE_SHARED_DRIVE_ID` 또는 `WORKS_SHAREDRIVE_ID` - 선택: `WORKS_DRIVE_PARENT_FILE_ID` - `WORKS_DRIVE_ACCESS_TOKEN`, `WORKS_DRIVE_ACCESS_TOKEN_FILE`, `WORKS_DRIVE_ACCESS_TOKEN_CMD`, `WORKS_DRIVE_OAUTH_REFRESH_TOKEN`, 또는 서비스 계정 OAuth 변수 업로드 전 packaging만 확인하려면 다음을 사용한다. ```bash WORKS_DRIVE_DRY_RUN=true \ DOCKER_IMAGE_REF=registry.example/baron_sso/backend:v1.2606.ab12 \ scripts/docker-image/upload_works_drive.sh ``` dry-run도 실제 `docker save`, `zstd`, checksum, manifest 생성을 수행한다. WORKS Drive API 호출만 생략하므로 업로드 전 산출물 검증에 사용할 수 있다. ## 다운로드 및 복원 검증 CLI WORKS Drive에서 다음 세 파일을 같은 로컬 디렉터리로 내려받은 뒤 검증한다. ```text image.tar.zst image.tar.zst.sha256 manifest.json ``` checksum, manifest, zstd stream 무결성만 확인하려면 다음을 실행한다. ```bash scripts/docker-image/verify_archive.sh /path/to/downloaded/archive ``` `make` 타깃을 사용할 수도 있다. ```bash make docker-image-verify-works \ WORKS_DOCKER_IMAGE_ARCHIVE_DIR=/path/to/downloaded/archive ``` 실제 Docker image load까지 검증하려면 다음을 실행한다. ```bash WORKS_DOCKER_VERIFY_LOAD=true \ scripts/docker-image/verify_archive.sh /path/to/downloaded/archive ``` 검증은 다음 조건을 모두 확인한다. - `image.tar.zst.sha256` checksum 성공 - `manifest.json`의 `schema_version=1`, `format=docker-save-zstd` - manifest의 archive 파일명, sha256, size와 실제 파일 일치 - `zstd -t` 무결성 성공 - 선택적으로 `docker load` 성공 현재 repo에는 WORKS Drive API에서 파일을 자동 다운로드하는 CLI는 없다. 따라서 자동 다운로드 스크립트를 만들기 전까지는 WORKS Drive UI 또는 운영자가 승인한 API 도구로 세 파일을 내려받고, 위 검증 CLI로 복원 가능성을 확인한다. API로 다운로드할 때는 대상 archive 폴더의 children을 조회해 각 파일의 `fileId`를 얻은 뒤 다음 endpoint를 호출한다. ```text GET /v1.0/sharedrives//files//download ``` 검증 결과 이 endpoint는 `302 Location`을 반환한다. `curl -L`만 사용하면 리다이렉트 대상 요청에 인증 헤더가 유지되지 않아 `UNAUTHORIZED` JSON이 파일로 저장될 수 있다. 자동화할 때는 리다이렉트 대상에도 인증 헤더를 유지하도록 처리해야 한다. `curl` 기준으로는 다음 형태를 사용한다. ```bash curl -sS -L --location-trusted \ -H "Authorization: Bearer " \ -o image.tar.zst \ "https://www.worksapis.com/v1.0/sharedrives//files//download" ``` smoke 검증에는 Alpine 계열보다 운영 환경과 libc/패키지 계열 차이가 적은 Debian slim 계열을 사용한다. ```bash docker create --name baron-works-image-smoke debian:trixie-slim \ sh -c 'printf works-drive-docker-image-smoke >/works-smoke.txt' docker start -a baron-works-image-smoke WORKS_DOCKER_COMMIT_CONTAINER=baron-works-image-smoke \ DOCKER_IMAGE_REF=registry.example/baron_sso/works-smoke:works-test-ab12 \ scripts/docker-image/upload_works_drive.sh ``` 로컬 smoke 검증 예시는 다음과 같다. ```bash WORKS_DRIVE_DRY_RUN=true \ WORKS_DOCKER_IMAGE_ARCHIVE_DIR=/tmp/baron-sso-works-verify-smoke \ DOCKER_IMAGE_REF=alpine:latest \ scripts/docker-image/upload_works_drive.sh scripts/docker-image/verify_archive.sh \ /tmp/baron-sso-works-verify-smoke/alpine/latest WORKS_DOCKER_VERIFY_LOAD=true \ scripts/docker-image/verify_archive.sh \ /tmp/baron-sso-works-verify-smoke/alpine/latest ``` ## Staging/Production 계약 Action에서 `dev` 브랜치를 checkout한 뒤 한 번만 이미지를 빌드하고 immutable `image_tag`를 계산한다. staging과 production은 같은 image_tag를 입력받아 같은 registry image를 pull한다. ```text dev branch -> publish image tag vX.YYMM. -> staging deploy -> production deploy ``` WORKS Drive archive도 Action에서 push된 이미지를 다시 pull한 뒤 `docker save`로 만든다. 따라서 WORKS archive, staging, production은 모두 같은 registry image tag를 기준으로 한다. ## 제한 - 이 구조는 `docker push`/`docker pull`과 호환되는 Registry backend가 아니다. - layer deduplication이 없으므로 같은 기반 이미지가 반복 저장된다. - 배포 전에는 반드시 `image.tar.zst.sha256` 검증 후 `docker load`를 수행해야 한다. - tag 없는 image ref와 digest-only image ref는 지원하지 않는다.