Как сгладить изображение докеров?

Я сделал контейнер Docker, который довольно большой. Когда я создаю контейнер для создания изображения, изображение имеет размер около 7.8 ГБ. Но когда я export контейнер (не save изображение!) В tarball и повторно импортирует его, изображение составляет всего 3 ГБ. Конечно, история потеряна, но это ОК для меня, так как изображение "сделано" на мой взгляд и готово к развертыванию.

Как сгладить изображение/контейнер, не экспортируя его на диск и импортируя его снова? И: Это разумная идея сделать это, или я пропустил какой-то важный момент?

Ответ 1

До Docker 1.13 вы можете использовать флаг --squash.


Перед версией 1.13:

Насколько я знаю, вы не можете использовать Docker api. docker export и docker import предназначены для этого сценария, как вы уже сами уже упоминаете.

Если вы не хотите сохранять на диск, вы, вероятно, могли бы вывести выходной поток экспорта во входной поток импорта. Я не тестировал это, но попробую

docker export red_panda | docker import - exampleimagelocal:new

Ответ 2

Теперь, когда Docker выпустил многоэтапные сборки в 17.05, вы можете переформатировать свою сборку, чтобы выглядеть так:

FROM buildimage as build
# your existing build steps here
FROM scratch
COPY --from=build / /
CMD ["/your/start/script"]

В результате ваши слои среды сборки будут кэшированы на сервере сборки, но в результирующем изображении, которое вы помечаете и нажимаете, будет существовать только сглаженная копия.


Примечание. Обычно вы переформулируете это, чтобы иметь сложную среду сборки и копировать только несколько каталогов. Вот пример с Go, чтобы сделать одно бинарное изображение из исходного кода и одной командой сборки без установки. Идите на хост и компилируйте вне докеров:

$ cat Dockerfile 
ARG GOLANG_VER=1.8
FROM golang:${GOLANG_VER} as builder
WORKDIR /go/src/app
COPY . .
RUN go-wrapper download 
RUN go-wrapper install

FROM scratch
COPY --from=builder /go/bin/app /app
CMD ["/app"]

Файл go - это простой мир приветствия:

$ cat hello.go 
package main

import "fmt"

func main() {
        fmt.Printf("Hello, world.\n")
}

В сборке создаются среды, среда сборки и царапины, а затем теги:

$ docker build -t test-multi-hello .                                                                                                                              
Sending build context to Docker daemon  4.096kB
Step 1/9 : ARG GOLANG_VER=1.8
 ---> 
Step 2/9 : FROM golang:${GOLANG_VER} as builder
 ---> a0c61f0b0796
Step 3/9 : WORKDIR /go/src/app
 ---> Using cache
 ---> af5177aae437
Step 4/9 : COPY . .
 ---> Using cache
 ---> 976490d44468
Step 5/9 : RUN go-wrapper download
 ---> Using cache
 ---> e31ac3ce83c3
Step 6/9 : RUN go-wrapper install
 ---> Using cache
 ---> 2630f482fe78
Step 7/9 : FROM scratch
 ---> 
Step 8/9 : COPY --from=builder /go/bin/app /app
 ---> Using cache
 ---> 5645db256412
Step 9/9 : CMD /app
 ---> Using cache
 ---> 8d428d6f7113
Successfully built 8d428d6f7113
Successfully tagged test-multi-hello:latest

При просмотре изображений в отправляемом изображении только один бинарный файл, в то время как среда сборки составляет более 700 МБ:

$ docker images | grep 2630f482fe78
<none>                <none>              2630f482fe78        6 days ago          700MB

$ docker images | grep 8d428d6f7113
test-multi-hello      latest              8d428d6f7113        6 days ago          1.56MB

И да, он работает:

$ docker run --rm test-multi-hello 
Hello, world.