Заметки программиста | Как написать элегантный Dockerfile

Docker

Управляемое чтение

Kubernetes начинается с контейнеризации, а контейнеры должны начинаться с Dockerfile.Эта статья расскажет, как написать элегантный Dockerfile.

Основное содержание статьи включает в себя:

  • Докер-контейнер

  • Dockerfile

  • Используйте сборки с несколькими заказами

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

1. Докер-контейнер

1.1 Особенности контейнера

Все мы знаем, что контейнер — это стандартная программная единица со следующими характеристиками:

  • Запускайте где угодно: контейнеры могут упаковывать код с файлами конфигурации и связанными зависимостями, обеспечивая согласованную работу в любой среде.

  • Высокое использование ресурсов: контейнеры обеспечивают изоляцию на уровне процессов, поэтому использование ЦП и памяти можно настроить более точно, что позволяет лучше использовать вычислительные ресурсы сервера.

  • Быстрое масштабирование: каждый контейнер можно запускать как отдельный процесс и совместно использовать системные ресурсы базовой операционной системы, что может повысить эффективность запуска и остановки контейнеров.

1.2 Докер-контейнеры

В настоящее время основные контейнерные движки на рынке включают Docker, Rocket/rkt, OpenVZ/Odin и т. д., а контейнерный движок, который доминирует на рынке, является наиболее используемым контейнерным движком Docker.

Контейнеры Docker — это набор процессов, изолированных от остальной системы. Все файлы, необходимые для запуска этих процессов, предоставляются другим образом. Контейнеры Linux являются переносимыми и согласованными на протяжении всего процесса от разработки до тестирования и производства. По сравнению с конвейерами разработки, основанными на повторяющихся традиционных тестовых средах, контейнеры работают намного быстрее и поддерживают развертывание на нескольких основных облачных платформах (PaaS) и локальных системах. Контейнеры Docker — хорошее решение проблемы, связанной с тем, что «среда разработки может работать нормально, но она рухнет, как только подключится к сети».

Особенности контейнеров Docker:

  • Облегченный: контейнеры обеспечивают изоляцию ресурсов на уровне процесса, а виртуальные машины — изоляцию ресурсов на уровне операционной системы, поэтому контейнеры Docker могут сэкономить больше ресурсов по сравнению с виртуальными машинами, поскольку контейнеры Docker больше не требуют работы системы уровня GuestOS.

  • Быстрота: для запуска и создания контейнеров не требуется запускать гостевую ОС, а запуск можно выполнить за секунды или даже миллисекунды.

  • Переносимость. Технология контейнеров Docker преобразует приложения, зависимые библиотеки и технологию среды выполнения в образы контейнеров, которые могут работать на разных платформах.

  • Автоматизация: оркестровка контейнеров в экосистеме контейнеров (например, Kubernetes) может помочь нам автоматизировать управление контейнерами.

2. Докерфайл

Dockerfile — это текстовый документ, используемый для описания состава файла, который содержит все команды, которые пользователь может вызывать в строке для объединения образа, а также пользователь может использовать сборку Docker для последовательного выполнения нескольких команд.

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

Синтаксис Dockerfile очень прост, всего 11 часто используемых:

2.1 Напишите элегантный Dockerfile

Есть несколько вещей, о которых следует помнить при написании элегантного Dockerfile:

  • Dockerfile не должен быть слишком длинным, чем больше слоев, тем больше будет конечный образ.

  • Собранный образ не должен содержать лишнего контента, такого как логи, временные файлы установки и т.п.

  • Попробуйте использовать базовый образ среды выполнения и не нужно помещать процесс сборки в файл Dockerfile среды выполнения.

Если вы помните о трех предыдущих пунктах, вы можете написать хороший Dockerfile.

Для вашего удобства мы используем два экземпляра Dockerfile для простого сравнения:

FROM ubuntu:16.04
RUN apt-get update
RUN apt-get install -y apt-utils libjpeg-dev \ 		
python-pip
RUN pip install --upgrade pip
RUN easy_install -U setuptools
RUN apt-get clean
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y apt-utils \
	libjpeg-dev python-pip \
         	&& pip install --upgrade pip \
    	&& easy_install -U setuptools \
    && apt-get clean

Мы смотрим на первый Dockerfile, и на первый взгляд он кажется хорошо организованным и хорошо структурированным. Посмотрите на второй Dockerfile, он компактный и неудобный для чтения, зачем так писать?

  • Преимущество первого Dockerfile в том, что при возникновении ошибки в определенном слое исполняемого процесса он исправляется и строится заново, а ранее выполненный слой повторно выполняться не будет. Это может сильно сократить время следующего билда, а его проблема в том, что пространство, занимаемое образом, тоже увеличится за счет количества слоев.

  • Второй Dockerfile решает все компоненты в один слой, что может в определенной степени уменьшить пространство, занимаемое образом, однако, если одна из групп компилирует ошибки при создании базового образа, сборка заново после исправления равносильна тому, чтобы начать все сначала Теперь уже скомпилированные ранее компоненты находятся в одном слое, и все их приходится перекомпилировать, что занимает много времени.

Из таблицы ниже вы можете увидеть размер образов, скомпилированных двумя файлами Dockerfile:

$ docker images | grep ubuntu      
REPOSITORY      TAG     IMAGE ID    CREATED     SIZE                                                                                                                                   
ubuntu          	       16.04       9361ce633ff1  1 days ago 422MB
ubuntu          	       16.04-1   3f5b979df1a9  1 days ago  412MB

Э-э... Кажется, это не имеет особого эффекта, но если Dockerfile очень длинный, вы можете рассмотреть возможность уменьшения количества слоев, потому что Dockerfile может иметь максимум 127 слоев.

3. Используйте многоэтапные сборки

Docker может поддерживать многоэтапные сборки после обновления до Docker 17.05.Чтобы уменьшить размер образов, мы используем многоэтапные сборки для упаковки образов. До появления многоэтапных сборок мы обычно использовали файл Dockerfile или несколько файлов Dockerfile для создания образов.

3.1 Однофайловая сборка

Используйте один файл для сборки перед многоуровневой сборкой. Один файл должен включать все процессы сборки (включая зависимости проекта, процессы компиляции, тестирования и упаковки) в одном Dockerfile:

FROM golang:1.11.4-alpine3.8 AS build-env
ENV GO111MODULE=off
ENV GO15VENDOREXPERIMENT=1
ENV BUILDPATH=github.com/lattecake/hello
RUN mkdir -p /go/src/${BUILDPATH}
COPY ./ /go/src/${BUILDPATH}
RUN cd /go/src/${BUILDPATH} && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go install –v

CMD [/go/bin/hello]

Такой подход приносит некоторые проблемы:

  • Файл Dockerfile будет очень длинным, и удобство сопровождения будет падать экспоненциально, когда потребуется все больше и больше вещей;

  • Если слоев образа слишком много, размер образа будет постепенно увеличиваться, а развертывание будет становиться все медленнее и медленнее;

  • Код находится под угрозой утечки.

Если взять Golang в качестве примера, его время выполнения не зависит от какой-либо среды, ему нужна только среда компиляции, тогда эта среда компиляции не имеет функции задачи во время фактического выполнения.После завершения компиляции исходный код и компилятор не имеют Использование задачи Нет необходимости оставаться в зеркале.

Как видно из таблицы выше, однофайловая сборка заняла 312 МБ места.

3.2 Многофайловая сборка

Есть ли хорошее решение до того, как будут сделаны многоуровневые сборки? Да, например, использование многофайловых сборок или установка компилятора на сервер сборки, но мы не рекомендуем устанавливать компилятор на сервер сборки, потому что установка компилятора на сервер сборки приведет к тому, что сервер сборки сильно раздуется. необходимо адаптировать к нескольким версиям и зависимостям каждого языка, что чревато ошибками и высокими затратами на обслуживание. Поэтому мы только представляем способ многофайловой сборки.

Многофайловые сборки на самом деле используют несколько файлов Dockerfile и объединяют их с помощью сценариев. Допустим есть три файла: Dockerfile.run, Dockerfile.build, build.sh.

  • Dockerfile.run — это Dockerfile некоторых компонентов, которые должны быть нужны исполняемой программе, и он содержит наиболее компактную библиотеку;

  • Dockerfile.build используется только для сборки, после сборки он бесполезен;

  • Функция build.sh состоит в том, чтобы составить файлы Dockerfile.run и Dockerfile.build, извлечь вещи, созданные с помощью Dockerfile.build, а затем выполнить Dockerfile.run, который является ролью планирования.

Dockerfile.build

FROM golang:1.11.4-alpine3.8 AS build-env
ENV GO111MODULE=off
ENV GO15VENDOREXPERIMENT=1
ENV BUILDPATH=github.com/lattecake/hello
RUN mkdir -p /go/src/${BUILDPATH}
COPY ./ /go/src/${BUILDPATH}
RUN cd /go/src/${BUILDPATH} && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go install –v

Dockerfile.run

FROM alpine:latest
RUN apk –no-cache add ca-certificates
WORKDIR /root
ADD hello .
CMD ["./hello"]

Build.sh

#!/bin/sh
docker build -t –rm hello:build . -f Dockerfile.build
docker create –name extract hello:build
docker cp extract:/go/bin/hello ./hello
docker rm -f extract
docker build –no-cache -t –rm hello:run . -f Dockerfile.run
rm -rf ./hello

Выполните build.sh, чтобы завершить сборку проекта.

Как видно из приведенной выше таблицы, многофайловая конструкция значительно уменьшает размер образа, но требует управления тремя файлами, а стоимость обслуживания также выше.

3.3 Многопорядковая конструкция

Наконец, давайте взглянем на долгожданную многоэтапную сборку.

Чтобы выполнить многоэтапную сборку, нам нужно всего лишь несколько раз использовать оператор FORM в файле Docker.Каждая команда FROM может использовать другой базовый образ, и каждая команда FROM запускает новую сборку.Мы можем выбрать копирование результатов сборки. одного этапа на другой. Стадия, в финальном образе остается только результат последней сборки, так что вышеупомянутые проблемы могут быть легко решены и нужно написать только один Dockerfile. Здесь стоит отметить: нужно следить за тем, чтобы версия Docker была 17.05 и выше. Теперь поговорим о конкретной операции.

В Dockerfile вы можете использовать псевдоним для стадии «build-env»:

FROM golang:1.11.2-alpine3.8 AS build-env

Затем скопируйте файлы из образа на предыдущем этапе или из любого образа:

COPY –from=build-env /go/bin/hello /usr/bin/hello 

См. простой пример:

FROM golang:1.11.4-alpine3.8 AS build-env

ENV GO111MODULE=off
ENV GO15VENDOREXPERIMENT=1
ENV GITPATH=github.com/lattecake/hello
RUN mkdir -p /go/src/${GITPATH}
COPY ./ /go/src/${GITPATH}
RUN cd /go/src/${GITPATH} && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go install -v

FROM alpine:latest
ENV apk –no-cache add ca-certificates
COPY --from=build-env /go/bin/hello /root/hello
WORKDIR /root
CMD ["/root/hello"]

Выполняем docker build -t –rm hello3 Затем выполняем docker images, после чего смотрим на размер образа:

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

Автор: Ван Цун

Источник контента:Технологический институт CreditEase