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.yml의 Upload built images to WORKS Drive archive step에서 실행된다. 이 workflow는 stage/production 공용 산출물을 만들며 dev branch의 commit hash 4자리로 immutable tag를 계산한다.
업로드를 실행하려면 최소한 다음 값을 등록해야 한다.
- variable
WORKS_SHAREDRIVE_DOCKER_IMAGE_DIR=docker-build-image - variable
WORKS_DRIVE_SHARED_DRIVE_ID - 선택 variable
WORKS_DRIVE_PARENT_FILE_ID - secret
WORKS_DRIVE_ACCESS_TOKEN, 또는 variableWORKS_DRIVE_ACCESS_TOKEN_FILE, 또는 variableWORKS_DRIVE_ACCESS_TOKEN_CMD, 또는 refresh-token 방식의 secretWORKS_DRIVE_REFRESH_TOKEN - refresh-token 방식을 쓸 경우 secret
WORKS_DRIVE_OAUTH_CLIENT_ID, secretWORKS_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 내부 envWORKS_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-token에 0600 권한으로 캡처한다. 다만 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_TOKENsecret을 수동 갱신한다. - secret 자동 갱신이 필요하면 Gitea secret write 전용 token을 별도 설계로 추가한다.
저장 구조
기본 최상위 디렉터리는 다음 환경 변수로 지정한다.
WORKS_SHAREDRIVE_DOCKER_IMAGE_DIR=docker-build-image
이미지는 WORKS Shared Drive에서 다음 구조로 저장한다.
docker-build-image/<repository-path>/<tag>/
image.tar.zst
image.tar.zst.sha256
manifest.json
예시:
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
- 복원 명령 예시
복원은 다음 흐름으로 처리한다.
sha256sum -c image.tar.zst.sha256
zstd -d -c image.tar.zst | docker load
업로드 CLI
로컬 컨테이너를 먼저 이미지로 commit한 뒤 업로드하려면 다음처럼 실행한다.
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를 생략한다.
DOCKER_IMAGE_REF=registry.example/baron_sso/backend:v1.2606.ab12 \
scripts/docker-image/upload_works_drive.sh
실제 업로드에는 기존 백업 업로드와 같은 WORKS Drive 인증 변수를 사용한다.
WORKS_DRIVE_TARGET=sharedriveWORKS_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만 확인하려면 다음을 사용한다.
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에서 다음 세 파일을 같은 로컬 디렉터리로 내려받은 뒤 검증한다.
image.tar.zst
image.tar.zst.sha256
manifest.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
검증은 다음 조건을 모두 확인한다.
image.tar.zst.sha256checksum 성공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를 호출한다.
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 image.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이 없으므로 같은 기반 이미지가 반복 저장된다.
- 배포 전에는 반드시
image.tar.zst.sha256검증 후docker load를 수행해야 한다. - tag 없는 image ref와 digest-only image ref는 지원하지 않는다.