Docker 실무 가이드 · Part 6

이미지 최적화와 보안

빌드는 되지만 운영에 올리기 전에 손봐야 할 것들 정리하기

작성 기준2026년 7월

이 파트에서 다루는 내용

이미지가 커지는 이유멀티스테이지 빌드레이어 캐시 활용운영 배포 전 보안 기준
01

동작하는 이미지와 배포해도 되는 이미지는 다릅니다

Dockerfile을 처음 작성하면 대개 동작은 합니다. 문제는 그 이미지가 1GB를 넘고, 빌드 도구가 그대로 들어 있고, root로 실행된다는 점입니다.

개발 중에는 드러나지 않습니다. 배포가 느려지고, 보안 점검에서 지적을 받고, 컨테이너가 침해됐을 때 피해가 커지는 시점에 문제가 됩니다.

이미지가 커지는 원인
진단
  • 빌드 도구와 컴파일러가 최종 이미지에 남음
  • 의존성 설치 캐시를 지우지 않음
  • 무거운 베이스 이미지를 그대로 사용
  • 소스 전체를 복사하면서 불필요한 파일까지 포함
커진 이미지의 비용
영향
  • 배포할 때마다 전송 시간이 늘어납니다
  • 레지스트리 저장 비용이 늘어납니다
  • 포함된 패키지가 많을수록 취약점 노출면이 넓어집니다
  • 폐쇄망 반입 시 파일 크기 제약에 걸립니다
docker images이미지별 크기 확인. 최적화 대상 파악의 시작
docker history <이미지>레이어별 크기 확인. 어느 단계에서 커졌는지 추적
docker build --progress=plain -t app .빌드 각 단계 출력을 자세히 확인
02

멀티스테이지 빌드로 빌드 도구를 남기지 않습니다

빌드에는 컴파일러와 패키지 매니저가 필요하지만, 실행에는 결과물과 런타임만 있으면 됩니다.

멀티스테이지 빌드는 빌드 단계와 실행 단계를 나누고, 최종 이미지에는 필요한 결과물만 복사합니다. 이것만으로 이미지 크기가 크게 줄어듭니다.

  • 빌드 단계에서 소스를 컴파일하거나 번들을 만듭니다.
  • 실행 단계는 런타임만 포함한 가벼운 베이스에서 시작합니다.
  • 빌드 단계의 결과물만 실행 단계로 복사합니다.
  • 빌드 도구, 소스, 중간 산출물은 최종 이미지에 포함되지 않습니다.
자바 애플리케이션
예시

빌드 단계는 JDK로 jar를 만들고, 실행 단계는 JRE만 포함합니다. Spring Boot 코스에서 다룬 방식과 같습니다.

프런트엔드 애플리케이션
예시

빌드 단계에서 정적 파일을 만들고, 실행 단계는 웹 서버 이미지에 결과물만 복사합니다. React 코스의 빌드 산출물이 여기로 이어집니다.

베이스 이미지 선택
판단

가벼운 변형본을 쓰면 크기가 줄지만 일부 라이브러리 호환 문제가 생길 수 있습니다. 무작정 가장 작은 것을 고르지 말고 동작 확인이 필요합니다.

태그 고정
재현성

베이스 이미지에 latest를 쓰면 빌드 시점마다 내용이 달라집니다. 버전을 명시해 같은 결과가 나오게 합니다.

03

레이어 순서가 빌드 속도를 결정합니다

Docker는 각 명령을 레이어로 만들고 변경되지 않은 레이어는 재사용합니다. 다만 한 레이어가 바뀌면 그 아래 모든 레이어를 다시 만듭니다.

그래서 자주 바뀌는 것을 뒤에 두는 것이 원칙입니다. 소스 코드는 매번 바뀌지만 의존성 목록은 그렇지 않습니다.

잘못된 순서
매번 재설치

소스 전체를 먼저 복사하고 의존성을 설치하면, 코드 한 줄만 고쳐도 의존성을 다시 내려받습니다.

권장 순서
캐시 활용

의존성 목록 파일만 먼저 복사해 설치하고, 그다음에 소스를 복사합니다. 의존성이 바뀌지 않으면 설치 단계가 캐시됩니다.

dockerignore
필수

빌드 컨텍스트에서 제외할 대상을 정합니다. node_modules, 빌드 결과물, 로컬 설정이 들어가면 캐시가 매번 깨지고 크기도 커집니다.

설치 캐시 정리
크기 절감

패키지 매니저 캐시를 설치와 같은 레이어에서 지웁니다. 다음 레이어에서 지우면 이미 이전 레이어에 남아 크기가 줄지 않습니다.

자주 하는 실수

파일을 지우는 명령을 별도 레이어로 두면 이미지 크기가 줄지 않습니다. 레이어는 이전 상태를 그대로 갖고 있기 때문에, 만들지 않는 것과 나중에 지우는 것은 결과가 다릅니다.

04

운영 배포 전에 확인할 보안 기준

컨테이너는 기본적으로 root로 실행됩니다. 애플리케이션이 침해됐을 때 컨테이너 안에서 할 수 있는 일이 많아진다는 뜻입니다.

아래 항목은 운영 이미지에 올리기 전에 확인해야 할 최소 기준입니다.

비root 사용자로 실행
필수

전용 사용자를 만들어 실행합니다. 침해 시 영향 범위를 줄이는 가장 기본적인 조치입니다.

비밀정보를 이미지에 넣지 않기
필수

빌드 인자나 파일로 넣으면 이미지 레이어에 남아 누구나 꺼낼 수 있습니다. 실행 시점에 주입합니다. Git 코스의 저장소 위생과 같은 원칙입니다.

베이스 이미지 갱신
정기

베이스 이미지에 포함된 패키지에서 취약점이 발견됩니다. 애플리케이션을 안 고쳐도 주기적으로 다시 빌드해야 합니다.

취약점 스캔
자동화

이미지에 포함된 패키지의 알려진 취약점을 검사합니다. CI 단계에 넣어 배포 전에 확인합니다. Jenkins 코스의 파이프라인에 붙일 수 있습니다.

불필요한 도구 제거
권장

운영 이미지에 셸 도구나 네트워크 도구가 많을수록 침해 시 활용될 여지가 커집니다. 디버깅용은 별도 이미지로 분리합니다.

읽기 전용 파일시스템
심화

쓰기가 필요 없다면 파일시스템을 읽기 전용으로 실행합니다. 필요한 경로만 볼륨으로 열어 둡니다.

docker run --user 1000:1000 app지정한 사용자로 실행
docker run --read-only app파일시스템을 읽기 전용으로 실행
docker run --memory=512m --cpus=1 app자원 한도 지정. 한 컨테이너가 서버를 잠식하지 않게 함
docker history --no-trunc <이미지>레이어 명령 전체 확인. 비밀정보 포함 여부 점검
05

태그 전략과 폐쇄망 반입

이미지 이름과 태그를 어떻게 정하느냐가 배포 사고와 직결됩니다. 특히 latest 하나로 운영하면 어떤 버전이 돌고 있는지 알 수 없습니다.

latest 만 쓰지 않기
원칙

무엇이 배포됐는지 추적할 수 없고 롤백할 대상도 지정할 수 없습니다. 버전이나 커밋 식별자를 태그로 씁니다.

권장 태그 구성
실무
  • 릴리스 버전 태그: 롤백 대상 지정
  • 커밋 식별자 태그: 어떤 소스로 만들었는지 추적
  • 환경 태그는 참조용으로만 사용
폐쇄망 반입
국내 SI

외부 레지스트리에 접근할 수 없는 환경에서는 이미지를 파일로 저장해 반입합니다. 이때 이미지 크기가 반입 절차의 제약이 됩니다.

사내 레지스트리
권장

외부 이미지를 그대로 끌어 쓰지 않고 사내 레지스트리에 미러링해 씁니다. 외부 장애와 정책 변경에 영향을 덜 받습니다.

docker tag app:latest registry.example.com/app:1.4.0레지스트리 주소와 버전을 붙여 태그
docker push registry.example.com/app:1.4.0레지스트리에 업로드
docker save -o app-1.4.0.tar app:1.4.0이미지를 파일로 저장. 폐쇄망 반입용
docker load -i app-1.4.0.tar저장한 파일에서 이미지 복원
운영 기준

이미지는 한 번 만들어 여러 환경에 그대로 씁니다. 환경마다 다시 빌드하면 같은 태그인데 내용이 다른 이미지가 생깁니다. 환경별 차이는 이미지가 아니라 실행 시점 설정으로 처리합니다.

체크

이 파트 완료 기준