매번 가장 작은 작업 도커 이미지를 만드는 방법은 무엇입니까?


19

목표 : 매번 작은 작업 도커 이미지를 만들려면

흐름

REPOSITORY          TAG       IMAGE ID            CREATED             SIZE
a-docker-image      latest    x                   42 minutes ago       1.92 GB

시도

Dockerfile 끝에 정리 단계 추가 :

#clean
RUN apt-get purge -y wget
RUN rm -r a-build-dir
RUN apt-get purge -y a-package

이미지 크기를 약간 줄였습니다.

REPOSITORY          TAG       IMAGE ID            CREATED             SIZE
a-docker-image      latest    y                   2 minutes ago       1.86 GB

토론

다양한 도커 이미지를 만들었습니다. 생성 된 이미지의 크기를 줄이려고 할 때마다 항상 이미지가 너무 크다고 생각합니다. 이미지에서 모든 불필요한 패키지를 제거하는 github의 누군가가 이미 만든 스크립트를 찾고 있으므로 생성 된 이미지의 크기가 가능한 한 작습니다.

내가 말했듯이 항상 이미지 크기를 줄이려고 노력하지만 지금부터 만드는 모든 이미지가 가능한 한 작게되도록 일관되게 적용하고 싶습니다.

질문

매번 가장 작은 작업 도커 이미지를 만드는 방법은 무엇입니까?

답변:


1

단일 솔루션없이 다양한 기술이 사용됩니다. 다음 중 몇 가지를하고 싶을 것입니다.


먼저 재사용을 위해 이미지 레이어를 최적화하십시오. Dockerfile에 자주 변경되는 단계를 나중에 초기 빌드가 이전 빌드에서 캐시 될 가능성을 높이십시오. 재사용 된 계층은에 더 많은 디스크 공간으로 표시 docker image ls되지만 기본 파일 시스템을 검사하면 각 계층의 사본 하나만 디스크에 저장됩니다. 즉, 마지막 2 계층에서 50MB 만 다른 3 개의 이미지는 각각 2GB의 3 개 이미지를 의미합니다. 목록에서 2GB의 디스크 공간 만 차지합니다. 재사용 된 각 레이어를 두 번 계산합니다.

레이어 재사용으로 인해 빌드 종속성이 자주 바뀌지 않는 이미지가 코드에 복사하기 전에 이미지를 먼저 설치하는 것을 볼 수 있습니다. 다음과 같은 패턴을 가진 파이썬 예제를 참조하십시오.

FROM python
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
# note how the code is copied only after the pip install
# since code changes but requirements.txt doesn't
COPY . .
CMD ["gunicorn", "app:app"]

최소 기본 이미지를 선택하십시오. 당신은 사람들이에서 이동 볼 이유입니다 ubuntudebian:slim(슬림 변형이 적은 도구를 출시, 작은), 또는 alpine. 이렇게하면 시작점의 크기가 줄어들고 기본 이미지의 새 버전을 지속적으로 가져 오는 경우 매우 유용합니다. 그러나 기본 이미지가 거의 변경되지 않으면 레이어 재사용으로 최소 기본 이미지의 이점을 상당 부분 제거 할 수 있습니다.

선택할 수있는 가장 작은 기본 이미지는입니다 scratch. 이것은 쉘이나 라이브러리가 없으며 정적으로 컴파일 된 바이너리에만 유용합니다. 그렇지 않으면 필요하지 않은 많은 도구없이 필요한 도구가 포함 된 기본 이미지를 선택하십시오.


다음으로, 파일을 변경하거나 삭제하는 단계는 해당 파일을 작성하는 이전 단계와 결합되어야합니다. 그렇지 않으면 파일 사용 권한 변경과 같은 경우에도 쓰기시 복사를 사용하는 계층 파일 시스템은 이전 계층의 원본 파일을 가지므로 파일을 제거해도 이미지 크기가 줄어들지 않습니다. 이것이 rm명령이 결과 디스크 공간에 영향을 미치지 않는 이유 입니다. 대신 다음과 같이 명령을 연결할 수 있습니다.

RUN apt-get update \
 && apt-get install -y \
      a-package \
      wget \
 && ... \
 && apt-get purge -y wget \
 && rm -r a-build-dir \
 && apt-get purge -y a-package

명령 체인을 과도하게 사용하면 전제 조건이 변경 될 때마다 동일한 도구 세트를 다시 설치해야하므로 빌드 속도가 느려질 수 있습니다 (예 : wget으로 코드 가져 오기). 더 나은 대안은 아래의 다단계를 참조하십시오.


결과 이미지에 필요하지 않은 파일은 생성 단계에서 삭제해야합니다. 여기에는 패키지 캐시, 로그, 매뉴얼 페이지 등이 포함됩니다. 각 계층에서 생성되는 파일을 발견하려면 wagoodman / dive와 같은 도구를 사용할 수 있습니다. 중간 컨테이너를 잘라 내지 않고 도커 이미지를 만들고 다음과 같이 diff를 볼 수 있습니다.

# first create and leave containers from any RUN step using options on build
docker image build --rm=false --no-cache -t image_name . 
# review which layers use an unexpectedly large amount of space
docker image history image_name
# list all containers, particularly the exited ones from above
docker container ps -a 
# examine any of those containers
docker container diff ${container_id} 
# ... repeat the diff for other build steps
# then cleanup exited containers
docker container prune

그 중간 용기의 각각과 상기 DIFF 파일 추가, 변경 또는 삭제하는 단계에있는 것을 보여주는 것이다 (이러한는로 표시되고 A, C또는 D각 파일명 전). 차이점은 컨테이너 별 읽기 / 쓰기 파일 시스템이며, 이는 기록 중 복사를 사용하여 컨테이너가 이미지 상태에서 변경된 파일입니다.


이미지 크기를 줄이는 가장 좋은 방법은 제공된 이미지에서 컴파일러와 같은 불필요한 구성 요소를 제거하는 것입니다. 이를 위해 다단계 빌드를 사용하면 한 단계에서 컴파일 한 다음 결과 아티팩트 만 빌드 단계에서 애플리케이션 실행에 필요한 최소한의 런타임 이미지로 복사 할 수 있습니다. 결과 이미지와 함께 제공되지 않으므로 빌드 단계를 최적화 할 필요가 없습니다.

FROM debian:9 as build
# still chain update with install to prevent stale cache issues
RUN apt-get update \
 && apt-get install -y \
      a-package \
      wget \
RUN ... # perform any download/compile steps

FROM debian:9-slim as release
COPY --from=build /usr/local/bin/app /usr/local/bin/app
CMD [ "/usr/local/bin/app" ]

다단계는 기본 이미지로 스크래치로 실행하거나 JDK와 같은 컴파일 환경에서 JRE와 같은 런타임으로 전환 할 수있는 정적으로 컴파일 된 바이너리에 이상적입니다. 빠른 빌드를 유지하면서 이미지 크기를 크게 줄이는 가장 쉬운 방법입니다. 이전 단계에서 생성 된 파일을 변경하거나 삭제하는 단계가있는 경우 릴리스 단계에서 단계 체인을 계속 수행 할 수 있지만 대부분의 경우 COPY다른 단계에서 릴리스 단계를 이전 빌드 단계에서 경험 한 모든 레이어 팽창과 분리합니다.


레이어 재사용을 제거하면서 하나의 이미지의 크기를 줄이므로 이미지 스 쿼싱을 권장하지 않습니다. 즉, 동일한 이미지를 향후 빌드 할 때 업데이트를 보내려면 더 많은 디스크 및 네트워크 트래픽이 필요합니다. 첫 번째 예로 돌아가려면 스쿼시로 인해 이미지가 2GB에서 1GB로 줄어들 수 있지만 2.1GB 대신 3GB의 이미지가 3GB를 차지할 수는 없습니다.


25

A Dockerfile는 파일의 각 명령에 대해 새 레이어를 만듭니다. 레이어가 서로 잘 겹쳐져 있으므로 이전 레이어가 추가 한 파일을 제거 할 수 없습니다. 그렇기 때문에 패키지를 설치하거나 파일을 다운로드하거나 각각 별도의 명령으로 빌드를 생성 할 수 있습니다. 차후 계층에서 제거하더라도 이미지에는 여전히 존재합니다.

따라서 이것을 변경하면 :

RUN apt-get update -y
RUN apt-get install -y wget a-package
# ...
RUN apt-get purge -y wget
RUN rm -r a-build-dir
RUN apt-get purge -y a-package

이에:

RUN apt-get update -y \
    && apt-get install -y wget a-package \
    && mkdir a-build-dir \
    && wget http://some-site/very-big-source-code.tar.gz \
    && tar xzvf very-big-source-code.tar.gz \
    && do-some-compilation \
    && apt-get purge -y wget \
    && cd .. \
    && rm -rf a-build-dir \
    && apt-get purge -y a-package

훨씬 작은 이미지를 얻을 수 있습니다.


또 다른 옵션 은 이미지를 만든 후 스쿼시 하는 것입니다. Q : 새로운 기능은 어떻게 docker --squash작동합니까?


또 다른 옵션은 얇은 기본 이미지를 선택하는 것입니다. 예를 들어, 데비안 대신 Alpine Linux 를 기본으로 사용하는 이미지는 180-250mb 대신 10-15mb 만 사용합니다. 그리고 이것은 자신의 응용 프로그램과 데이터를 추가하기 전에입니다. Docker Hub의 많은 공식 기본 이미지 에는 알파인 버전이 있습니다.


3
2.371.47 GB
030

4

아마 정답은 아니지만 대안을 제시 할 가치가 있습니다.

Chef의 서식지는 이를 염두에두고 만들어졌으며 원하지 않는 외부 배포 / 기본 이미지로드없이 필요한 모든 종속성이 포함 된 패키지를 만들었습니다.

간단한 nodejs 앱 으로이 블로그 게시물 의 컨테이너 크기에서 중요한 내용을 추출하십시오 .

michael@ricardo-2:plans_pkg_part_2$ docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
mfdii/node-example   latest              36c6568c606b        40 minutes ago      655.9 MB
node                 latest              04c0ca2a8dad        16 hours ago        654.6 MB
mfdii/mytutorialapp  latest              534afd80d74d        2 minutes ago       182.1 MB

mdfii/node-examplemfdii/mytutorialapp서식 파일로 생성 된 도커 이미지 인 반면 클래식 도커 파일의 도커 이미지입니다.

규모가 주요 관심사이고 서식지 계획의 학습 곡선을 따라가는 경우 이것이 해결책이 될 수 있습니다.


0

다이빙 을 사용할 수도 있습니다

docker run --rm -it \
    -v /var/run/docker.sock:/var/run/docker.sock \
    wagoodman/dive:latest <dive arguments...>

크기를 줄이기 위해 도커 이미지에서 어떤 폐기물을 제거 할 수 있는지에 대한 보고서를 얻습니다.


0

재사용 가능한 개발 계층을 갖고 싶지만 전달을위한 디스크 사용량을 줄이려면 다음과 같이 병합 된 "전달 계층"을 생성 할 수 있습니다.

  1. 이미지를 사용하는 컨테이너가 있는지 확인하십시오 (없는 docker run IMAGE echo경우 echo 명령을 사용할 수있는 경우 와 같은 것을 사용하십시오)
  2. (아마도 사용하여 컨테이너 ID 찾기 docker container ls -l)
  3. 파이프 docker export하기 위해 docker import병합 된 레이어를 만들 수있는 (같은 docker export 20f192c6530a | docker import - project:merged)

이렇게하면 개발 계층이 유지되지만 더 작고 병합 된 이미지를 제공 할 수 있습니다.



0

simple .. docker ps는 현재 실행중인 이미지를 확인하십시오. 아래의 간단한 파일 예는 ..

우분투 16에서

MAINTAINER sreeni (이메일 / 도메인)

실행 apt-get 업데이트

실행 apt-get install -y nginx

진입 점 [“/ usr / sbin / nginx”,”-g”,”daemon off;”]

EXPOSE 80 (포트)

간단한 도커 파일 ...

docker 명령 아래에서 사용하십시오.

docker run -d -p 80:80 --localhost 또는 IP 주소 확인 후 웹 서버 ubuntu16 (이미지 이름) 이름 : 80 (브라우저를 열고 확인하십시오)


1
답변의 서식을 수정하십시오 ...
Pierre.Vriens
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.