컨테이너 이미지 재현성은 Dockerfile 문자열을 다시 실행하는 문제가 아니라, base·의존성·도구·환경·외부 입력 전체를 같은 조건으로 고정하고 결과 차이를 설명하는 문제입니다. 바이트 단위 동일성, 기능 동등성, 출처 증거를 분리해 어느 보장을 실제로 얻었는지 판단합니다.
Dockerfile과 전체 빌드 입력의 재현성 범위
FROM에 움직이는 tag를 쓰고 패키지 저장소의 최신 버전을 설치하면 Dockerfile이 같아도 며칠 뒤 다른 바이트가 들어옵니다. dependency lockfile이 있어도 빌드 스크립트가 외부 URL에서 최신 파일을 받으면 입력이 다시 바뀝니다. 재현성은 소스 한 파일보다 전체 빌드 입력의 문제입니다.
같은 기능을 수행하는 산출물과 bit-for-bit 같은 digest를 만드는 것은 다른 목표입니다. 어느 수준이 필요한지 정하고 차이가 생기는 계층을 분리해 조사합니다.
빌드 입력 그래프의 고정·기록
재현 실패를 좁히는 순서는 base digest·플랫폼, lockfile과 저장소 응답, 도구 버전·설정, 환경 값, 압축·파일 메타데이터입니다. 예를 들어 같은 Dockerfile에서 digest가 다르면 먼저 입력 manifest와 플랫폼을 비교하고, 입력이 같을 때만 timestamp·경로·레이어 순서를 산출물 차이의 후보로 봅니다.
| 입력 | 고정·기록할 것 | 남는 변동 |
|---|---|---|
| base image | digest·플랫폼 | multi-arch manifest의 대상 선택 |
| 의존성 | lockfile·저장소·무결성 정보 | 설치 스크립트·선택 의존성 |
| build tool | 컴파일러·패키지 도구·설정 | native 플랫폼 차이 |
| 외부 다운로드 | 버전·정확한 URL·검증값 | 서버 응답 변경·가용성 |
| 환경 | locale·시각·경로·환경 변수 | 비결정적 생성 코드 |
FROM의 base digest를 고정하면 tag가 나중에 움직여도 고정한 base 이미지 콘텐츠를 가리킬 근거가 생깁니다. 다만 architecture가 다르면 선택되는 플랫폼 이미지와 native 산출물이 달라질 수 있으므로 독립 재빌드의 비교 환경을 먼저 맞춰야 합니다.
환경을 맞춘 뒤 빌드 결과의 digest를 비교하고, 빌드 시각·파일 mtime·압축 순서·절대 경로가 결과에 들어가는지도 산출물 차이와 함께 확인합니다. 사용하는 도구가 지원하는 재현 설정과 비교 결과를 함께 기록해 bit 재현성인지 기능 동등성인지 판단합니다.
그림을 글로 읽기
- 소스·digest·lock·도구·환경
- 통제된 build 실행
- 이미지 digest·구성·provenance
- 독립 재빌드·기능·보안 검사
- 소스·digest·lock·도구·환경 → 통제된 build 실행: 모든 입력 기록
- 통제된 build 실행 → 이미지 digest·구성·provenance: 산출물 생성
- 이미지 digest·구성·provenance → 독립 재빌드·기능·보안 검사: 비교·검증
Cache Hit와 독립 재현 증거의 구분
검증 보고에는 적어도 빌드 입력 식별자, 캐시 사용 여부, 산출물 digest, 기능 검사 결과를 분리해 남깁니다. 캐시 hit로 동일 digest가 나온 경우는 “이번 실행이 캐시된 결과를 재사용했다”는 증거이지 독립 빌드가 같은 결과를 만들었다는 증거가 아니므로, 두 주장을 같은 상태로 기록하지 않습니다.
같은 로컬 캐시를 재사용해 같은 이미지가 나온 것은 새 입력으로 재빌드해 같다는 증거와 다릅니다. 깨끗한 환경·캐시 없는 경로·별도 머신에서 빌드하고 레이어·manifest·실행 파일·패키지 목록의 차이를 봅니다. timestamp만 다르면 기능 동등과 byte 동등 중 어떤 기준을 만족했는지 구분합니다.
빌드 중 네트워크를 완전히 없앨 수 없다면 필요한 다운로드와 검증 범위를 좁히고 예상하지 못한 최신값 fetch를 발견합니다. reproducible이라는 라벨보다 입력·출력 hash와 재실행 절차가 중요합니다.
빌드 비밀과 산출물·로그 잔류 방지
ARG·ENV·RUN 문자열에 자격을 넣으면 레이어·history·로그·캐시에 남을 수 있습니다. 지원되는 build secret 전달을 쓰고 스크립트가 원문을 출력하거나 파일로 복사하지 않게 합니다. multi-stage build로 도구와 임시 파일을 최종 이미지에서 제외해도 중간 산출물·원격 캐시의 접근 통제는 필요합니다.
비신뢰 PR의 빌드 코드에 운영 자격을 제공하지 않습니다. 빌드·서명·배포 주체를 분리하고 최소 권한을 적용합니다. 최종 이미지 검사뿐 아니라 빌드 로그·cache·provenance에 민감값이 들어가지 않는지도 확인합니다.
입력 고정과 보안 업데이트의 양립
digest와 lockfile을 영원히 고정하면 알려진 취약점도 함께 고정됩니다. 알려진 취약점이 발견되면 의도적인 업데이트 PR에서 새 입력을 검토하고, 새 digest·lockfile을 다시 고정해 재빌드한 뒤 기능 회귀를 확인하고 점진 배포합니다. provenance는 누가 어떤 입력으로 만들었는지를 추적하는 자료이고, 서명은 허용된 발급자의 산출물인지 대조하는 근거입니다. SBOM은 구성 목록이므로 알려지지 않은 취약점이나 악성 행위가 없다는 보증서로 사용하지 않습니다.
독립 재빌드의 digest·파일 차이와 실제 시작·핵심 기능·취약 구성 검사를 따로 기록합니다. 현재 작업에서는 컨테이너 이미지를 빌드하거나 외부 registry에 올리지 않았습니다. 이 노트는 재현·출처·안전성의 구분을 설명합니다.