1
0
forked from baron/baron-sso
Files
baron-sso/docs/works-drive-docker-image-archive.md

10 KiB

WORKS Drive Docker Image Archive

목적

WORKS Drive는 Docker Registry HTTP API v2 backend로 직접 사용하지 않는다. 대신 stage/production 공용 Docker 이미지를 docker save 결과물로 내보내고, zstd 압축 archive와 검증 파일을 WORKS Shared Drive에 보관하는 CLI 기반 이미지 산출물 저장소로 사용한다.

이 방식은 다음 상황을 목표로 한다.

  • 공용 Registry 없이 WORKS Drive 접근 권한만으로 이미지 산출물 보관
  • 작은 규모의 stage/production 배포 이미지 이관
  • docker load 기반 오프라인 배포

Gitea Actions의 shared image publish workflow는 baron_sso/<service>:<image_tag> 형태의 로컬 이미지를 빌드한 뒤 WORKS Drive archive로 업로드한다. Harbor registry login/push/pull은 이 publish 흐름의 필수 조건이 아니다. staging/production은 같은 image tag 계약을 공유하며, WORKS Drive archive를 검증한 뒤 docker load로 배포 대상 호스트에 적재하는 흐름으로 확장한다.

현재 Gitea Actions 설정 상태

2026-06-19 기준 Docker image archive 업로드 단계는 .gitea/workflows/image_publish.ymlUpload built images to WORKS Drive archive step에서 실행된다. 이 workflow는 stage/production 공용 산출물을 만들며 dev branch의 commit hash 4자리로 immutable tag를 계산한다.

업로드를 실행하려면 최소한 다음 값을 등록해야 한다.

  • 선택 variable WORKS_DRIVE_DOCKER_IMAGE_DIR=baron-sso
  • variable WORKS_DRIVE_DOCKER_IMAGE_DRIVE_ID
  • 선택 variable WORKS_DRIVE_DOCKER_IMAGE_PARENT_FILE_ID
  • secret WORKS_DRIVE_ACCESS_TOKEN, 또는 variable WORKS_DRIVE_ACCESS_TOKEN_FILE, 또는 variable WORKS_DRIVE_ACCESS_TOKEN_CMD, 또는 refresh-token 방식의 secret WORKS_DRIVE_REFRESH_TOKEN
  • refresh-token 방식을 쓸 경우 secret WORKS_DRIVE_OAUTH_CLIENT_ID, secret WORKS_OAUTH_CLIENT_SECRET

서비스 계정 JWT 방식은 upload script의 fallback으로 남아 있지만 shared image publish workflow의 기본 필수 인증값은 아니다.

WORKS Drive 토큰 운영

WORKS OAuth의 Access Token은 Developer Console 설정에 따라 1시간 또는 24시간 동안 유효하고, Refresh Token은 90일 동안 유효하다. 따라서 Gitea secret에 WORKS_DRIVE_ACCESS_TOKEN만 고정해 두는 방식은 publish workflow가 장시간 중단된 뒤 재실행될 때 실패할 수 있다.

image_publish.yml은 업로드 직전에 Resolve WORKS Drive access token step을 실행한다.

  • WORKS_DRIVE_ACCESS_TOKEN이 있으면 이를 마스킹한 뒤 해당 workflow run 안에서만 사용한다.
  • WORKS_DRIVE_ACCESS_TOKEN_FILE 또는 WORKS_DRIVE_ACCESS_TOKEN_CMD가 있으면 그 결과를 같은 방식으로 사용한다.
  • 위 값이 없고 Gitea secret WORKS_DRIVE_REFRESH_TOKEN이 있으면 workflow 내부 env WORKS_DRIVE_OAUTH_REFRESH_TOKEN으로 매핑한 뒤 grant_type=refresh_token으로 새 Access Token을 발급하고, 이후 다섯 개 이미지 업로드는 모두 이 Access Token을 공유한다.

Refresh Token Rotation이 켜져 있으면 WORKS가 refresh 응답에 새 Refresh Token을 포함할 수 있다. workflow는 이 값을 로그에 노출하지 않도록 마스킹하고 ${RUNNER_TEMP}/works-drive-rotated-refresh-token0600 권한으로 캡처한다. 다만 Gitea repository secret을 자동 갱신하려면 별도의 secret 쓰기 권한이 있는 Gitea token과 secret update 절차가 필요하므로, 기본 publish workflow는 repository secret을 직접 변경하지 않는다.

운영 권장값은 다음 중 하나다.

  • Refresh Token Rotation을 끄고 WORKS_DRIVE_REFRESH_TOKEN으로 매 run마다 Access Token만 자동 발급한다.
  • Rotation을 켠 경우 publish run에서 rotated refresh token 경고가 나오면 WORKS_DRIVE_REFRESH_TOKEN secret을 수동 갱신한다.
  • secret 자동 갱신이 필요하면 Gitea secret write 전용 token을 별도 설계로 추가한다.

저장 구조

기본 최상위 디렉터리는 다음 환경 변수로 지정한다.

WORKS_DRIVE_DOCKER_IMAGE_DIR=baron-sso

이미지는 WORKS Shared Drive에서 다음 구조로 저장한다.

baron-sso/<tag>/
  <service>.<tag>.tar.zst
  <service>.<tag>.sha256
  manifest.<tag>.json

예시:

baron-sso/v1.2606.ab12/
  backend.v1.2606.ab12.tar.zst
  backend.v1.2606.ab12.sha256
  manifest.v1.2606.ab12.json

Registry hostname과 image namespace는 저장 경로에서 제외한다. 예를 들어 registry.example/baron_sso/backend:v1.2606.ab12baron-sso/v1.2606.ab12/backend.v1.2606.ab12.tar.zst로 저장한다.

Manifest

manifest.<tag>.json에는 다음 정보를 기록한다.

  • archive format: docker-save-zstd
  • 원본 image_ref
  • repository path
  • tag
  • Docker image id
  • Git commit
  • archive 파일명, 크기, sha256
  • 서비스별 archive 정보 (images.<service>)
  • WORKS Drive remote path
  • 복원 명령 예시

복원은 다음 흐름으로 처리한다.

sha256sum -c backend.v1.2606.ab12.sha256
zstd -d -c backend.v1.2606.ab12.tar.zst | docker load

업로드 CLI

로컬 컨테이너를 먼저 이미지로 commit한 뒤 업로드하려면 다음처럼 실행한다.

WORKS_DRIVE_DOCKER_IMAGE_DIR=baron-sso \
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를 생략한다.

DOCKER_IMAGE_REF=registry.example/baron_sso/backend:v1.2606.ab12 \
scripts/docker-image/upload_works_drive.sh

실제 업로드에는 기존 백업 업로드와 같은 WORKS Drive 인증 변수를 사용하되, Docker image archive 대상 drive/folder는 백업 변수와 분리한다.

  • WORKS_DRIVE_TARGET=sharedrive
  • WORKS_DRIVE_DOCKER_IMAGE_DRIVE_ID
  • 선택: WORKS_DRIVE_DOCKER_IMAGE_PARENT_FILE_ID
  • WORKS_DRIVE_ACCESS_TOKEN, WORKS_DRIVE_ACCESS_TOKEN_FILE, WORKS_DRIVE_ACCESS_TOKEN_CMD, WORKS_DRIVE_OAUTH_REFRESH_TOKEN, 또는 서비스 계정 OAuth 변수

업로드 전 packaging만 확인하려면 다음을 사용한다.

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에서 다음 세 파일을 같은 로컬 디렉터리로 내려받은 뒤 검증한다.

backend.v1.2606.ab12.tar.zst
backend.v1.2606.ab12.sha256
manifest.v1.2606.ab12.json

checksum, manifest, zstd stream 무결성만 확인하려면 다음을 실행한다.

scripts/docker-image/verify_archive.sh /path/to/downloaded/archive

make 타깃을 사용할 수도 있다.

make docker-image-verify-works \
  WORKS_DOCKER_IMAGE_ARCHIVE_DIR=/path/to/downloaded/archive

실제 Docker image load까지 검증하려면 다음을 실행한다.

WORKS_DOCKER_VERIFY_LOAD=true \
scripts/docker-image/verify_archive.sh /path/to/downloaded/archive

검증은 다음 조건을 모두 확인한다.

  • <service>.<tag>.sha256 checksum 성공
  • manifest.<tag>.jsonschema_version=1, format=docker-save-zstd
  • manifest의 archive 파일명, sha256, size와 실제 파일 일치
  • zstd -t 무결성 성공
  • 선택적으로 docker load 성공

현재 repo의 scripts/docker-image/download_works_drive.shWORKS_DRIVE_DOCKER_IMAGE_DRIVE_IDIMAGE_TAG를 사용해 baron-sso/<tag>/의 archive, checksum, manifest를 내려받고 checksum/manifest 검증 후 docker load를 수행한다.

WORKS_DRIVE_DOCKER_IMAGE_DRIVE_ID=@2001000000547281 \
WORKS_DRIVE_ACCESS_TOKEN=<access-token> \
IMAGE_TAG=v1.2606.ab12 \
scripts/docker-image/download_works_drive.sh

API로 다운로드할 때는 대상 archive 폴더의 children을 조회해 각 파일의 fileId를 얻은 뒤 다음 endpoint를 호출한다.

GET /v1.0/sharedrives/<sharedDriveId>/files/<fileId>/download

검증 결과 이 endpoint는 302 Location을 반환한다. curl -L만 사용하면 리다이렉트 대상 요청에 인증 헤더가 유지되지 않아 UNAUTHORIZED JSON이 파일로 저장될 수 있다. 자동화할 때는 리다이렉트 대상에도 인증 헤더를 유지하도록 처리해야 한다. curl 기준으로는 다음 형태를 사용한다.

curl -sS -L --location-trusted \
  -H "Authorization: Bearer <access-token>" \
  -o backend.v1.2606.ab12.tar.zst \
  "https://www.worksapis.com/v1.0/sharedrives/<sharedDriveId>/files/<fileId>/download"

smoke 검증에는 Alpine 계열보다 운영 환경과 libc/패키지 계열 차이가 적은 Debian slim 계열을 사용한다.

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 검증 예시는 다음과 같다.

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를 입력받아 같은 image archive를 사용한다.

dev branch -> publish image tag vX.YYMM.<commit4> -> staging deploy -> production deploy

WORKS Drive archive는 Action에서 로컬로 빌드된 이미지를 docker save로 내보내 생성한다. 따라서 WORKS archive, staging, production은 모두 같은 immutable image tag를 기준으로 한다.

제한

  • 이 구조는 docker push/docker pull과 호환되는 Registry backend가 아니다.
  • layer deduplication이 없으므로 같은 기반 이미지가 반복 저장된다.
  • 배포 전에는 반드시 <service>.<tag>.sha256 검증 후 docker load를 수행해야 한다.
  • tag 없는 image ref와 digest-only image ref는 지원하지 않는다.