Оптимизация файлов Dockerfile в WindowsOptimize Windows Dockerfiles

Процесс сборки Docker и получаемые образы Docker можно оптимизировать несколькими способами.There are many ways to optimize both the Docker build process and the resulting Docker images. В этой статье объясняется, как происходит процесс сборки Docker и как оптимально создавать образы для контейнеров Windows.This article explains how the Docker build process works and how to optimally create images for Windows containers.

Слои образов в сборке DockerImage layers in Docker build

Чтобы оптимизировать сборку Docker, необходимо знать, как она выполняется.Before you can optimize your Docker build, you'll need to know how Docker build works. В процессе сборки Docker используется файл Dockerfile, а также поочередно выполняются все активные инструкции, каждая в своем собственном временном контейнере.During the Docker build process, a Dockerfile is consumed, and each actionable instruction is run, one-by-one, in its own temporary container. В результате для каждой активной инструкции создается новый слой образа.The result is a new image layer for each actionable instruction.

Например, в следующем примере Dockerfile использует базовый образ ОС mcr.microsoft.com/windows/servercore:ltsc2019, устанавливает службы IIS, а затем создает простой веб-сайт.For example, the following sample Dockerfile uses the mcr.microsoft.com/windows/servercore:ltsc2019 base OS image, installs IIS, and then creates a simple website.

# Sample Dockerfile

FROM mcr.microsoft.com/windows/servercore:ltsc2019
RUN dism /online /enable-feature /all /featurename:iis-webserver /NoRestart
RUN echo "Hello World - Dockerfile" > c:\inetpub\wwwroot\index.html
CMD [ "cmd" ]

Вам может показаться, что файл Dockerfile создаст образ с двумя слоями: один для образа ОС контейнера, а второй — для служб IIS и веб-сайта.You might expect that this Dockerfile will produce an image with two layers, one for the container OS image, and a second that includes IIS and the website. Однако фактический образ состоит из нескольких слоев, и каждый из них зависит от предыдущего.However, the actual image has many layers, and each layer depends upon the one before it.

Чтобы лучше это понять, давайте применим команду docker history к образу, созданному с помощью нашего примера файла Dockerfile.To make this clearer, let's run the docker history command against the image our sample Dockerfile made.

docker history iis

IMAGE               CREATED              CREATED BY                                      SIZE                COMMENT
f4caf476e909        16 seconds ago       cmd /S /C REM (nop) CMD ["cmd"]                 41.84 kB
f0e017e5b088        21 seconds ago       cmd /S /C echo "Hello World - Dockerfile" > c   6.816 MB
88438e174b7c        About a minute ago   cmd /S /C dism /online /enable-feature /all /   162.7 MB
6801d964fda5        4 months ago                                                         0 B

Выходные данные свидетельствуют о том, что в этом образе есть четыре слоя: базовый и три дополнительных, сопоставленных с каждой инструкцией в Dockerfile.The output shows us that this image has four layers: the base layer and three additional layers that are mapped to each instruction in the Dockerfile. Нижний слой (в этом примере — 6801d964fda5) представляет базовый образ ОС.The bottom layer (6801d964fda5 in this example) represents the base OS image. Одним слоем выше находится установка служб IIS.One layer up is the IIS installation. Следующий слой включает новый веб-сайт и т. д.The next layer includes the new website, and so on.

Файлы Dockerfile можно составлять таким образом, чтобы свести к минимуму число слоев в образе, оптимизировать производительность сборки, а также повысить доступность за счет удобочитаемости.Dockerfiles can be written to minimize image layers, optimize build performance, and optimize accessibility through readability. По сути, существует множество способов выполнить одну и ту же задачу сборки образа.Ultimately, there are many ways to complete the same image build task. Понимание того, как формат файла Dockerfile влияет на время сборки и создаваемый образ, расширяет возможности автоматизации.Understanding how the Dockerfile's format affects build time and the image it creates improves the automation experience.

Оптимизация размера образаOptimize image size

В зависимости от требований к пространству при создании образов контейнеров Docker важную роль может играть размер образа.Depending on your space requirements, image size can be an important factor when building Docker container images. Образы контейнеров перемещаются между реестрами и узлом, экспортируются и импортируются и в конечном счете занимают определенное место.Container images are moved between registries and host, exported and imported, and ultimately consume space. В этом разделе вы узнаете, как свести к минимуму размер образа в процессе сборки Docker для контейнеров Windows.This section will tell you how to minimize image size during the Docker build process for Windows containers.

Дополнительные сведения о рекомендациях для файлов Dockerfile см. в советах по составлению файлов Dockerfile на сайте Docker.com.For additional information about Dockerfile best practices, see Best practices for writing Dockerfiles on Docker.com.

Поскольку каждая инструкция RUN создает новый слой в образе контейнера, группирование действий в одной инструкции RUN позволяет сократить число слоев в файле Dockerfile.Because each RUN instruction creates a new layer in the container image, grouping actions into one RUN instruction can reduce the number of layers in a Dockerfile. Хотя минимизация числа слоев может не влиять на размер образа, группирование связанных действий влияет на него, что видно в приведенных ниже примерах.While minimizing layers may not affect image size much, grouping related actions can, which will be seen in subsequent examples.

В этом разделе мы будем сравнивать два примера файлов Dockerfile, которые выполняют одни и те же действия.In this section, we'll compare two example Dockerfiles that do the same things. Однако в одном файле Dockerfile используется одна инструкция для каждого действия, а в другом — связанные действия сгруппированы вместе.However, one Dockerfile has one instruction per action, while the other had its related actions grouped together.

В следующем примере несгруппированный файл Dockerfile скачивает Python для Windows, устанавливает его и удаляет скачанный файл установки после завершения установки.The following ungrouped example Dockerfile downloads Python for Windows, installs it, and removes the downloaded setup file once installation is done. В этом файле Dockerfile для каждого действия предусмотрена отдельная инструкция RUN.In this Dockerfile, each action is given its own RUN instruction.

FROM mcr.microsoft.com/windows/servercore:ltsc2019

RUN powershell.exe -Command Invoke-WebRequest "https://www.python.org/ftp/python/3.5.1/python-3.5.1.exe" -OutFile c:\python-3.5.1.exe
RUN powershell.exe -Command Start-Process c:\python-3.5.1.exe -ArgumentList '/quiet InstallAllUsers=1 PrependPath=1' -Wait
RUN powershell.exe -Command Remove-Item c:\python-3.5.1.exe -Force

Полученный образ имеет три дополнительных слоя — по одному для каждой инструкции RUN.The resulting image consists of three additional layers, one for each RUN instruction.

docker history doc-example-1

IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
a395ca26777f        15 seconds ago      cmd /S /C powershell.exe -Command Remove-Item   24.56 MB
6c137f466d28        28 seconds ago      cmd /S /C powershell.exe -Command Start-Proce   178.6 MB
957147160e8d        3 minutes ago       cmd /S /C powershell.exe -Command Invoke-WebR   125.7 MB

Второй пример — это фал Dockerfile, выполняющий точно такую же операцию.The second example is a Dockerfile that performs the exact same operation. Однако все связанные действия сгруппированы в одной инструкции RUN.However, all related actions have been grouped under a single RUN instruction. Каждый шаг в инструкции RUN начинается с новой строки в файле Dockerfile, при этом для переноса строки используется символ "\".Each step in the RUN instruction is on a new line of the Dockerfile, while the '\' character is used to line wrap.

FROM mcr.microsoft.com/windows/servercore:ltsc2019

RUN powershell.exe -Command \
  $ErrorActionPreference = 'Stop'; \
  Invoke-WebRequest https://www.python.org/ftp/python/3.5.1/python-3.5.1.exe -OutFile c:\python-3.5.1.exe ; \
  Start-Process c:\python-3.5.1.exe -ArgumentList '/quiet InstallAllUsers=1 PrependPath=1' -Wait ; \
  Remove-Item c:\python-3.5.1.exe -Force

Полученный образ имеет один дополнительный слой для инструкции RUN.The resulting image has only one additional layer for the RUN instruction.

docker history doc-example-2

IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
69e44f37c748        54 seconds ago      cmd /S /C powershell.exe -Command   $ErrorAct   216.3 MB

Удаление лишних файловRemove excess files

Если в Dockerfile есть какой-либо файл, например установщик, который не требуется после его использования, его можно удалить, чтобы уменьшить размер образа.If there's a file in your Dockerfile, such as an installer, that you don't need after it's been used, you can remove it to reduce image size. Это следует делать на том же шаге, где данный файл был скопирован в слой образа.This needs to occur in the same step in which the file was copied into the image layer. Эта процедура предотвращает сохранение файла в слое образа более низкого уровня.Doing so prevents the file from persisting in a lower-level image layer.

В следующем примере файла Dockerfile пакет Python загружается, выполняется, а затем удаляется.In the following example Dockerfile, the Python package is downloaded, executed, then removed. Все это выполняется в рамках одной операции RUN и создает всего один слой образа.This is all completed in one RUN operation and results in a single image layer.

FROM mcr.microsoft.com/windows/servercore:ltsc2019

RUN powershell.exe -Command \
  $ErrorActionPreference = 'Stop'; \
  Invoke-WebRequest https://www.python.org/ftp/python/3.5.1/python-3.5.1.exe -OutFile c:\python-3.5.1.exe ; \
  Start-Process c:\python-3.5.1.exe -ArgumentList '/quiet InstallAllUsers=1 PrependPath=1' -Wait ; \
  Remove-Item c:\python-3.5.1.exe -Force

Оптимизация скорости сборкиOptimize build speed

Несколько строкMultiple lines

Чтобы оптимизировать скорость сборки Docker, можно разделить операции на несколько отдельных инструкций.You can split operations into multiple individual instructions to optimize Docker build speed. Несколько операций RUN повышают эффективность кэширования, так как для каждой инструкции RUN создаются отдельные слои.Multiple RUN operations increase caching effectiveness because individual layers are created for each RUN instruction. Если какая-либо инструкция уже выполнялась в другой операции сборки Docker, такая кэшированная операция (слой образа) используется повторно, что приводит к сокращению времени выполнения сборки Docker.If an identical instruction was already run in a different Docker Build operation, this cached operation (image layer) is reused, resulting in decreased Docker build runtime.

В следующем примере загружаются и устанавливаются распространяемые пакеты Apache и Visual Studio, после чего ненужные больше файлы удаляются.In the following example, both Apache and the Visual Studio Redistribute packages are downloaded, installed, and then cleaned up by removing files that are no longer needed. Все это выполняется в рамках одной инструкции RUN.This is all done with a single RUN instruction. При изменении любого из этих действий все они перезапускаются.If any of these actions are updated, all actions will rerun.

FROM mcr.microsoft.com/windows/servercore:ltsc2019

RUN powershell -Command \

  # Download software ; \

  wget https://www.apachelounge.com/download/VC11/binaries/httpd-2.4.18-win32-VC11.zip -OutFile c:\apache.zip ; \
  wget "https://download.microsoft.com/download/1/6/B/16B06F60-3B20-4FF2-B699-5E9B7962F9AE/VSU_4/vcredist_x86.exe" -OutFile c:\vcredist.exe ; \
  wget -Uri http://windows.php.net/downloads/releases/php-5.5.33-Win32-VC11-x86.zip -OutFile c:\php.zip ; \

  # Install Software ; \

  Expand-Archive -Path c:\php.zip -DestinationPath c:\php ; \
  Expand-Archive -Path c:\apache.zip -DestinationPath c:\ ; \
  start-Process c:\vcredist.exe -ArgumentList '/quiet' -Wait ; \

  # Remove unneeded files ; \

  Remove-Item c:\apache.zip -Force; \
  Remove-Item c:\vcredist.exe -Force; \
  Remove-Item c:\php.zip

Итоговый образ имеет два слоя — один для базового образа ОС, а второй для всех операций из одной инструкции RUN.The resulting image has two layers, one for the base OS image, and one that contains all operations from the single RUN instruction.

docker history doc-sample-1

IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
9bdf3a21fd41        8 minutes ago       cmd /S /C powershell -Command     Invoke-WebR   205.8 MB
6801d964fda5        5 months ago                                                        0 B

По сравнению с предыдущим примером здесь те же действия поделены между тремя инструкциями RUN.By comparison, here are the same actions split into three RUN instructions. В этом случае каждая инструкция RUN кэшируется в слое образа контейнера, а при последующих сборках Dockerfile повторно выполняются только измененные инструкции.In this case, each RUN instruction is cached in a container image layer, and only those that have changed need to be rerun on subsequent Dockerfile builds.

FROM mcr.microsoft.com/windows/servercore:ltsc2019

RUN powershell -Command \
    $ErrorActionPreference = 'Stop'; \
    wget https://www.apachelounge.com/download/VC11/binaries/httpd-2.4.18-win32-VC11.zip -OutFile c:\apache.zip ; \
    Expand-Archive -Path c:\apache.zip -DestinationPath c:\ ; \
    Remove-Item c:\apache.zip -Force

RUN powershell -Command \
    $ErrorActionPreference = 'Stop'; \
    wget "https://download.microsoft.com/download/1/6/B/16B06F60-3B20-4FF2-B699-5E9B7962F9AE/VSU_4/vcredist_x86.exe" -OutFile c:\vcredist.exe ; \
    start-Process c:\vcredist.exe -ArgumentList '/quiet' -Wait ; \
    Remove-Item c:\vcredist.exe -Force

RUN powershell -Command \
    $ErrorActionPreference = 'Stop'; \
    wget http://windows.php.net/downloads/releases/php-5.5.33-Win32-VC11-x86.zip -OutFile c:\php.zip ; \
    Expand-Archive -Path c:\php.zip -DestinationPath c:\php ; \
    Remove-Item c:\php.zip -Force

Полученный образ имеет четыре слоя — один для базового образа ОС и по одному для каждой из трех инструкций RUN.The resulting image consists of four layers; one layer for the base OS image and each of the three RUN instructions. Так как каждая инструкция RUN выполняется в отдельном слое, при всех последующих запусках этого файла Dockerfile или аналогичного набора инструкций из другого Dockerfile будет использоваться кэшированный слой образа, что сокращает время сборки.Because each RUN instruction ran in its own layer, any subsequent runs of this Dockerfile or identical set of instructions in a different Dockerfile will use cached image layers, reducing build time.

docker history doc-sample-2

IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
ddf43b1f3751        6 days ago          cmd /S /C powershell -Command  Sleep 2 ;  Inv   127.2 MB
d43abb81204a        7 days ago          cmd /S /C powershell -Command  Sleep 2 ;  Inv   66.46 MB
7a21073861a1        7 days ago          cmd /S /C powershell -Command  Sleep 2 ;  Inv   115.8 MB
6801d964fda5        5 months ago

Как показано в следующем разделе, при работе с кэшами образов порядок выполнения инструкций играет важную роль.How you order the instructions is important when working with image caches, as you'll see in the next section.

Порядок инструкцийOrdering instructions

Файл Dockerfile обрабатывается сверху вниз, при этом каждая инструкция сравнивается с кэшированными слоями.A Dockerfile is processed from top to the bottom, each Instruction compared against cached layers. При обнаружении инструкции без кэшированного слоя она и все последующие инструкции обрабатываются в новых слоях образа контейнера.When an instruction is found without a cached layer, this instruction and all subsequent instructions are processed in new container image layers. Поэтому порядок инструкций имеет важное значение.Because of this, the order in which instructions are placed is important. Инструкции, которые останутся постоянными, располагайте ближе к началу файла Dockerfile.Place instructions that will remain constant towards the top of the Dockerfile. Инструкции, которые могут изменяться, располагайте ближе к концу файла Dockerfile.Place instructions that may change towards the bottom of the Dockerfile. Это снижает вероятность отмены существующего кэша.Doing so reduces the likelihood of negating existing cache.

Следующие примеры демонстрируют, как порядок инструкций в файле Dockerfile влияет на эффективность кэширования.The following examples show how Dockerfile instruction ordering can affect caching effectiveness. В этом простом файле Dockerfile имеется четыре нумерованных папки.This simple example Dockerfile has four numbered folders.

FROM mcr.microsoft.com/windows/servercore:ltsc2019

RUN mkdir test-1
RUN mkdir test-2
RUN mkdir test-3
RUN mkdir test-4

Полученный образ имеет пять слоев — один для базового образа ОС и по одному для каждой инструкции RUN.The resulting image has five layers, one for the base OS image and each of the RUN instructions.

docker history doc-sample-1

IMAGE               CREATED              CREATED BY               SIZE                COMMENT
afba1a3def0a        38 seconds ago       cmd /S /C mkdir test-4   42.46 MB
86f1fe772d5c        49 seconds ago       cmd /S /C mkdir test-3   42.35 MB
68fda53ce682        About a minute ago   cmd /S /C mkdir test-2   6.745 MB
5e5aa8ba1bc2        About a minute ago   cmd /S /C mkdir test-1   7.12 MB
6801d964fda5        5 months ago                                  0 B

Следующий файл Dockerfile теперь немного изменился (в качестве третьей инструкции RUN используется новый файл).This next Dockerfile has now been slightly modified, with the third RUN instruction changed to a new file. При запуске сборки Docker для этого файла Dockerfile три первых инструкции, которые идентичны инструкциям з прошлого примера, используют кэшированные слои образа.When Docker build is run against this Dockerfile, the first three instructions, which are identical to those in the last example, use the cached image layers. Однако поскольку измененная инструкция RUN не кэшируется, для нее и всех последующих инструкций создается новый слой.However, because the changed RUN instruction isn't cached, a new layer is created for the changed instruction and all subsequent instructions.

FROM mcr.microsoft.com/windows/servercore:ltsc2019

RUN mkdir test-1
RUN mkdir test-2
RUN mkdir test-5
RUN mkdir test-4

При сравнении идентификаторов нового образа с образом в первом примере этого раздела можно заметить, что первые три слоя снизу вверх являются общими, а четвертый и пятый — уникальными.When you compare the image IDs of the new image to that in this section's first example, you'll notice that the first three layers from bottom to top are shared, but the fourth and fifth are unique.

docker history doc-sample-2

IMAGE               CREATED             CREATED BY               SIZE                COMMENT
c92cc95632fb        28 seconds ago      cmd /S /C mkdir test-4   5.644 MB
2f05e6f5c523        37 seconds ago      cmd /S /C mkdir test-5   5.01 MB
68fda53ce682        3 minutes ago       cmd /S /C mkdir test-2   6.745 MB
5e5aa8ba1bc2        4 minutes ago       cmd /S /C mkdir test-1   7.12 MB
6801d964fda5        5 months ago                                 0 B

Косметическая оптимизацияCosmetic optimization

Регистр инструкцийInstruction case

В инструкциях Dockerfile не учитывается регистр, однако принято использовать верхний регистр.Dockerfile instructions are not case-sensitive, but the convention is to use upper case. Это улучшает удобочитаемость, разделяя вызов инструкции и операцию инструкции.This improves readability by differentiating between the Instruction call and instruction operation. В следующих двух примерах сравниваются файлы Dockerfile с инструкциями, написанными в верхнем и нижнем регистре.The following two examples compare an uncapitalized and capitalized Dockerfile.

Ниже приведен файл Dockerfile с инструкциями в нижнем регистре:The following is an uncapitalized Dockerfile:

# Sample Dockerfile

from mcr.microsoft.com/windows/servercore:ltsc2019
run dism /online /enable-feature /all /featurename:iis-webserver /NoRestart
run echo "Hello World - Dockerfile" > c:\inetpub\wwwroot\index.html
cmd [ "cmd" ]

Далее приведен тот же Dockerfile, но с инструкциями в верхнем регистре:The following is the same Dockerfile using upper-case:

# Sample Dockerfile

FROM mcr.microsoft.com/windows/servercore:ltsc2019
RUN dism /online /enable-feature /all /featurename:iis-webserver /NoRestart
RUN echo "Hello World - Dockerfile" > c:\inetpub\wwwroot\index.html
CMD [ "cmd" ]

Перенос строкLine wrapping

Длинные и сложные операции можно разделить на несколько строк с помощью символа обратной косой черты \.Long and complex operations can be separated onto multiple lines by the backslash \ character. Следующий файл Dockerfile устанавливает распространяемый пакет Visual Studio, удаляет файлы установщика и затем создает файл конфигурации.The following Dockerfile installs the Visual Studio Redistributable package, removes the installer files, and then creates a configuration file. Все эти три операции указаны на одной строке.These three operations are all specified on one line.

FROM mcr.microsoft.com/windows/servercore:ltsc2019

RUN powershell -Command c:\vcredist_x86.exe /quiet ; Remove-Item c:\vcredist_x86.exe -Force ; New-Item c:\config.ini

Команду можно разбить на части с помощью обратной косой черты, чтобы каждая операция из инструкции RUN была указана в отдельной строке.The command can be broken up with backslashes so that each operation from the one RUN instruction is specified on its own line.

FROM mcr.microsoft.com/windows/servercore:ltsc2019

RUN powershell -Command \
    $ErrorActionPreference = 'Stop'; \
    start-Process c:\vcredist_x86.exe -ArgumentList '/quiet' -Wait ; \
    Remove-Item c:\vcredist_x86.exe -Force ; \
    New-Item c:\config.ini

Дополнительные материалы и справочникиFurther reading and references

Dockerfile в WindowsDockerfile on Windows

Рекомендации по составлению файлов Dockerfile на сайте Docker.comBest practices for writing Dockerfiles on Docker.com