Dockerfile — это текстовый файл, который Docker использует для создания образов, включая пользовательские инструкции и форматы. Образы можно создавать из Dockerfile с помощью команды docker build. Пользователи могут настраивать в соответствии со своими потребностями с помощью унифицированных синтаксических команд.Благодаря этому унифицированному файлу конфигурации они могут быть распределены по разным файлам.Когда их нужно использовать, они могут быть автоматически созданы в соответствии с файлом конфигурации, что решает сложность построения изображения для разработчиков процесс.
Использование Dockerfile
Dockerfile описывает шаги по сборке объекта, где каждая инструкция выполняется отдельно. За исключением инструкции FROM, все остальные команды будут выполняться на основе изображения, сгенерированного предыдущей инструкцией.После выполнения будет сгенерирован новый слой изображения, и новый слой изображения будет наложен на исходное изображение, чтобы сформировать новое изображение. Окончательное изображение, сгенерированное Dockerfile, формируется путем наложения слоев изображений поверх базового изображения.
Инструкции по Dockerfile
Основной формат Dockerfile выглядит следующим образом:
# Comment
INSTRUCTION arguments
В Dockerfile инструкции (INSTRUCTION) не чувствительны к регистру, но рекомендуется использовать верхний регистр, чтобы отличить их от параметров.
Docker будет выполнять инструкции в файле Docker последовательно. Первой должна быть инструкция FROM, которая используется для указания базового образа для сборки образа. Строки, начинающиеся с # в Dockerfile, являются комментариями, а # в других местах рассматриваются как параметры.
Инструкции в Dockerfile включают FROM, MAINTAINER, RUN, CMD, EXPOSE, ENV, ADD, COPY, ENTRYPOING, VOLUME, USER, WORKDIR, ONBUILD, а неправильные инструкции будут игнорироваться. Ниже подробно описаны некоторые важные инструкции Docker.
FROM
Формат:FROM <image> 或者 FROM <image>:<tag>
Функция инструкции FROM состоит в том, чтобы предоставить базовый образ для следующих инструкций, поэтому Dockerfile должен использовать инструкцию FROM в качестве первой инструкции без комментариев. Извлекать изображения из общедоступных репозиториев изображений легко, а в качестве базового образа можно выбрать любое допустимое изображение.
Инструкция FROM может появляться в Dockerfile несколько раз, что приведет к созданию нескольких образов. Значение тега по умолчанию — самое последнее.Если изображение, указанное параметром image или тегом, не существует, будет возвращена ошибка.
ENV
Формат:ENV <key> <value> 或者 ENV <key>=<value> ...
Директива ENV может объявлять переменные среды для контейнера, созданного образом. И в Dockerfile переменные среды, объявленные инструкцией ENV, будут интерпретироваться и использоваться следующими конкретными инструкциями (т. е. ENV, ADD, COPY, WORKDIR, EXPOSE, VOLUME, USER).
Когда другие инструкции используют переменные среды, формат$variable_name
или${variable_name}
. Если вы добавите косую черту \ перед переменной, ее можно экранировать. как\$foo
или\${foo}
будет преобразован в$foo
и${foo}
, а не значение, хранящееся в переменной среды. Кроме того, директива ONBUILD не поддерживает замену среды.
COPY
Формат:COPY <src> <dest>
Команда COPY копирует указанный файл или каталог и добавляет его в новый образ.Путь к скопированному файлу или каталогу в образе<dest>
.<src>
Можно указать несколько источников, но они должны быть относительными путями в корне контекста.
нельзя просто использовать формуCOPY ../something /something
такая инструкция. также,<src>
Подстановочные знаки можно использовать для указания на все файлы или каталоги, соответствующие подстановочным знакам, например, COPY home* /mydir/ означает добавить все файлы, начинающиеся с «hom», в каталог /mydir/.
<dest>
Это может быть файл или каталог, но это должен быть абсолютный путь в целевом образе или относительный путь относительно WORKDIR (WORKDIR — это путь, указанный инструкцией WORKDIR в файле Docker, который используется для установки рабочего каталога для других инструкции).
как<dest>
Заканчивается обратной косой чертой /, чтобы указать на каталог; в противном случае он указывает на файл.<src>
То же самое справедливо. как<dest>
это файл, то<src>
будет написано в<dest>
в противном случае<src>
Содержимое указанного файла или каталога будет скопировано в<dest>
в каталоге.
когда<src>
При указании нескольких источников<dest>
Должен быть каталог. если<dest>
не существует, будут созданы каталоги, которых нет в пути.
ADD
Формат:ADD <src> <dest>
Инструкции ADD и COPY очень похожи по функциям, обе поддерживают функцию копирования локальных файлов на зеркало, но инструкция ADD также поддерживает и другие функции.<src>
Это может быть URL-адрес, указывающий на сетевой файл, в этом случае, если<dest>
Укажите на каталог, URL-адрес должен быть полным путем, чтобы вы могли получить имя файла сетевого файла, файл будет скопирован и добавлен в<dest>/<filename>
.
Например, добавьте http://example.com/config.property/файл создания/config.property.
<src>
Также может указывать на локальный сжатый архив, который будет извлечен при копировании в контейнер, например ADD sxample.tar.xz/. Однако, если файл в URL является архивным файлом, он не будет извлечен.
Хотя функции ADD и COPY аналогичны, обычно рекомендуется COPY, потому что COPY поддерживает только локальные файлы, что более прозрачно, чем ADD.
EXPOSE
Формат:EXPOSE <port> [<port>/<protocol>...]
Инструкция EXPOSE сообщает Docker, что контейнер прослушивает указанный сетевой порт во время выполнения. Вы можете указать, прослушивает ли порт TCP или UDP, если протокол не указан, по умолчанию используется TCP.
Эта команда только объявляет, какой порт намеревается использовать контейнер, а не автоматически сопоставляет порты на хост-компьютере.Это можно указать с помощью docker -p во время выполнения.
EXPOSE 80/tcp
EXPOSE 80/udp
USER
Формат:USER <user>[:<group] 或者 USER <UID>[:<GID>]
Директива USER устанавливает имя пользователя и группу пользователей (необязательно). Инструкции RUN, CMD и ENTRYPOINT после этого будут выполняться с заданным пользователем.
WORKDIR
Формат:WORKDIR /path/to/workdir
Инструкция WORKDIR устанавливает рабочий каталог, и следующие инструкции RUN, CMD, ENTRYPOINT, COPY и ADD будут выполняться в этом рабочем каталоге. Если этот рабочий каталог не существует, он будет создан автоматически.
Директиву WORKDIR можно использовать несколько раз в Dockerfile. Если указан относительный путь, он будет относиться к пути предыдущей инструкции WORKDIR. Например
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
Вывод /a/b/c
RUN
Формат 1:RUN <command>
(формат оболочки)
Формат 2:RUN ["executable", "param1", "param2"]
(формат exec, рекомендуется)
Команда RUN создаст контейнер на основе образа, созданного предыдущей командой, запустит команду в контейнере и отправит контейнер в качестве нового образа после завершения выполнения команды, а новый образ будет использоваться следующей командой в Докерфайл.
Две формы инструкции RUN представляют два способа выполнения команды в контейнере. При использовании формата оболочки команда запускается через /bin/sh -c.
При использовании формата exec команда запускается напрямую, контейнер не вызывает программу-оболочку, то есть в контейнере нет программы-оболочки.
Параметры в формате exec будут проанализированы Docker как массив JSON, поэтому вместо одинарных необходимо использовать двойные кавычки. Поскольку формат exec не выполняется в оболочке, аргументы переменных среды не подставляются.
например, выполнениеRUN ["echo", "$HOME"]
команда $HOME не выполняет подстановку переменных. Если вы хотите запустить программу оболочки, команда может быть записана какRUN ["/bin/bash", "-c", "echo", "$HOME"]
.
CMD
Существует 3 формата инструкции CMD.
Формат 1:CMD <command>
(формат оболочки)
Формат 2:CMD ["executable", "param1", "param2"]
(формат exec, рекомендуется)
Формат 3:CMD ["param1", "param2"]
(предоставьте аргументы инструкции ENTRYPOINT)
Инструкции CMD предоставляют значения по умолчанию для среды выполнения контейнера, которые могут быть инструкцией или некоторыми параметрами. В Dockerfile может быть несколько инструкций CMD, но допустима только последняя инструкция CMD.
Формат CMD ["param1", "param2"] используется, когда команда CMD используется в сочетании с командой ENTRYPOINT. Параметры команды CMD будут добавлены к команде ENTRYPOING. При использовании форматов оболочки и exec команда выполняется так же, как и в контейнере, инструкция RUN такая же.
Разница в том, что команда RUN выполняет команду при построении образа и создает новый образ; команда CMD не выполняет никаких команд при построении образа, а по умолчанию использует команду CMD как первую команду, выполняемую при запуске контейнера. Если пользователь указывает параметр команды при запуске команды запуска docker в интерфейсе командной строки, он переопределяет команду в инструкции CMD.
ENTRYPOINT
Инструкция ENTRYPOINT имеет два формата.
Формат 1:ENTRYPOINT <command>
(формат оболочки)
Формат 2:ENTRYPOINT ["executable", "param1", "param2"]
(формат исполняемого файла, рекомендуемый формат)
Инструкция ENTRYPOINT похожа на инструкцию CMD тем, что позволяет контейнеру выполнять одну и ту же команду при каждом запуске, но между ними есть различия. В Dockerfile может быть несколько инструкций ENTRYPOINT, но допустима только последняя инструкция ENTRYPOINT.
При использовании формата оболочки команда ENTRYPOINT игнорирует любые команды CMD и аргументы команды запуска docker и запускается в bin/sh -c. Это означает, что процесс команды ENTRYPOINT является дочерним процессом bin/sh -c, PID процесса в контейнере не будет равен 1, и он не может принимать сигналы Unix. то есть при использованииdocker stop <container>
команда, процесс команды не получает сигнал SIGTERM.
Рекомендуется использовать формат exec.При использовании этого формата параметры команды, передаваемые при запуске docker, перезаписывают содержимое команды CMD и добавляются к параметрам команды ENTRYPOINT. Из использования ENTRYPOINT видно, что CMD может быть параметром или инструкцией, а ENTRYPOINT может быть только командой; кроме того, параметры рабочей команды, предоставляемые командой запуска docker, могут переопределять CMD, но не ENTRYPOINT.
Практический опыт работы с Dockerfile.
использовать теги
Пометьте зеркало, чтобы помочь вам понять функцию зеркала.
Тщательно выбирайте базовое изображение
При выборе базового образа старайтесь выбирать ширину плеч текущей официальной библиотеки образов.Разные образы имеют разные размеры.В настоящее время размер образов Linux определяется следующим соотношением:
busybox < debian < centos < ubuntu
При этом при сборке собственного образа Docker устанавливайте и обновляйте только необходимые пакеты. Кроме того, образ Debian более рекомендуется, чем образ Ubuntu, потому что он очень легкий (в настоящее время его размер составляет менее 100 МБ) и по-прежнему является полной версией.
Максимально используйте кеш
Демон Docker будет последовательно выполнять инструкции в файле Dockerfile, и как только кеш станет недействительным, последующие команды не смогут использовать кеш. Чтобы эффективно использовать кеш, необходимо обеспечить преемственность инструкций, стараться помещать одни и те же части всех файлов Dockerfile в начало, а разные части в конец.
Правильное использование команд ADD и COPY
Когда в разных частях Dockerfile нужно использовать разные файлы, не добавляйте эти файлы в образ за один раз, а добавляйте их по мере необходимости, что также способствует повторному использованию кеша Docker.
Кроме того, учитывая размер образа, не рекомендуется использовать команду ADD для получения сжатого пакета по удаленному URL-адресу. Вместо этого следует использовать RUN wget или RUN curl. Это удаляет файлы, которые больше не нужны после распаковки, и избавляет от необходимости добавлять слой к изображению.
Неправильный способ:
ADD http://example.com/big.tar.xz /usr/src/things/
RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
RUN make -C /usr/src/things all
Правильный путь:
RUN mkdir -p /usr/src/things \
&& curl -SL http://example.com/big.tar.xz \
| tar -xJC /usr/src/things \
&& make -C /usr/src/things all
Инструкция RUN
Обратная косая черта \ может использоваться для разделения нескольких строк при использовании длинных инструкций RUN. Чаще всего команда RUN используется для запуска команды apt-wget В этом случае обратите внимание на следующие моменты.
Не используйте инструкцию RUN apt-get update для отдельной строки. Это может вызвать проблемы с кэшированием при обновлении репозиториев, что приведет к сбою команды RUN apt-get install. Таким образом, RUN apt-get update и RUN apt-get install должны быть написаны в одной строке. например, RUN apt-get update && apt-get install -y package-1 package-2 package-3
Избегайте использования команд RUN apt-get upgrade и RUN apt-get dist-upgrade. Потому что в непривилегированном контейнере некоторые необходимые пакеты не смогут обновиться. Если вам нужно обновить пакет (например, пакет-1), используйте команду RUN apt-get install -y package-1 напрямую.
Команды CMD и ENTRYPOINT
Команды CMD и ENTRYPOINT указывают команды по умолчанию, которые должны выполняться контейнером, и их рекомендуется использовать в комбинации. Используйте команду ENTRYPOINT в формате exec, чтобы установить фиксированные команды и параметры по умолчанию, а затем используйте команду CMD, чтобы установить переменные параметры.
Например следующий пример:
FROM busybox
WORKDIR /app
COPY run.sh /app
RUN chmod +x run.sh
ENTRYPOINT ["/app/run.sh"]
CMD ["param1"]
Содержимое run.sh следующее:
#!/bin/sh
echo "$@"
Результат вывода после запуска — param1, порядок CMD и ENTRYPOINT в Dockerfile не важен (CMD можно писать до и после ENTRYPOINT).
Вы можете столкнуться с этой проблемой при сборке dockerfile в системе Windows.
standard_init_linux.go:207: exec user process caused "no such file or directory"
Это связано с тем, что формат файла sh - dos, который здесь необходимо изменить на unix, и никаких дополнительных инструментов загружать не нужно.Как правило, когда git установлен на нашей машине, он поставляется с git bash, введите git bash , используйте vi для редактирования и изменяйте его в режиме командной строки (:set ff=unix).
Не делайте сопоставление портов в Dockerfile
Использование команды EXPOSE в файле Docker, несмотря на то, что порт контейнера может быть сопоставлен с портом хоста, нарушает переносимость Docker, и такой образ может запускать только один контейнер на хосте. Таким образом, сопоставление портов должно быть указано с параметром -p в команде запуска docker.
# 不要再Dockerfile中做如下映射
EXPOSE 80:8080
# 仅暴露80端口,需要另做映射
EXPOSE 80
Практика написания Dockerfile
DockerFile для службы Java
FROM openjdk:8-jre-alpine
ENV spring_profiles_active=dev
ENV env_java_debug_enabled=false
EXPOSE 8080
WORKDIR /app
ADD target/smcp-web.jar /app/target/smcp-web.jar
ADD run.sh /app
ENTRYPOINT ./run.sh
Вы можете видеть, что базовый образ — это openjdk, а затем установлены две переменные среды, порт доступа к службе — 8080 (это означает, что server.port = 8080 указан в приложении springboot), а рабочий каталог — /app. Команда (./run.sh), которая будет запускаться при запуске образа, задается ENTRYPOINT. Содержимое этого скрипта следующее:
#!/bin/sh
# Set debug options if required
if [ x"${env_java_debug_enabled}" != x ] && [ "${env_java_debug_enabled}" != "false" ]; then
java_debug_args="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"
fi
# ex: env_jvm_flags="-Xmx1200m -XX:MaxRAM=1500m" for production
java $java_debug_args $env_jvm_flags -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -jar target/smcp-web.jar
Если мы хотим указать некоторые параметры jvm, мы можем указать это, установив env_jvm_flags в переменной окружения.
Maven Dockerfile
Dockerfile maven также очень хорошо написан, здесь я опубликую его для справки.
FROM openjdk:8-jdk
ARG MAVEN_VERSION=3.6.3
ARG USER_HOME_DIR="/root"
ARG SHA=c35a1803a6e70a126e80b2b3ae33eed961f83ed74d18fcd16909b2d44d7dada3203f1ffe726c17ef8dcca2dcaa9fca676987befeadc9b9f759967a8cb77181c0
ARG BASE_URL=https://apache.osuosl.org/maven/maven-3/${MAVEN_VERSION}/binaries
RUN mkdir -p /usr/share/maven /usr/share/maven/ref \
&& curl -fsSL -o /tmp/apache-maven.tar.gz ${BASE_URL}/apache-maven-${MAVEN_VERSION}-bin.tar.gz \
&& echo "${SHA} /tmp/apache-maven.tar.gz" | sha512sum -c - \
&& tar -xzf /tmp/apache-maven.tar.gz -C /usr/share/maven --strip-components=1 \
&& rm -f /tmp/apache-maven.tar.gz \
&& ln -s /usr/share/maven/bin/mvn /usr/bin/mvn
ENV MAVEN_HOME /usr/share/maven
ENV MAVEN_CONFIG "$USER_HOME_DIR/.m2"
COPY mvn-entrypoint.sh /usr/local/bin/mvn-entrypoint.sh
COPY settings-docker.xml /usr/share/maven/ref/
ENTRYPOINT ["/usr/local/bin/mvn-entrypoint.sh"]
CMD ["mvn"]
Вы можете видеть, что он создан на основе базового образа openjdk, сначала скачайте пакет maven, а затем установите его. Затем установите две переменные среды MAVEN_HOME и MAVEN_CONFIG и, наконец, запустите его через mvn-entrypoint.sh.
Двухэтапная сборка интерфейсных сервисов
У меня есть служба внешнего интерфейса со следующей структурой каталогов:
$ ls frontend/
myaccount/ resources/ third_party/
js, vue и т. д. размещаются в каталоге myaccount, а css, изображения и т. д. — в resources. Third_party ставит сторонние приложения.
Здесь принято двухэтапное построение, то есть результат построения предыдущего этапа используется в качестве данных построения следующего этапа.
FROM node:alpine as builder
WORKDIR '/build'
COPY myaccount ./myaccount
COPY resources ./resources
COPY third_party ./third_party
WORKDIR '/build/myaccount'
RUN npm install
RUN npm rebuild node-sass
RUN npm run build
RUN ls /build/myaccount/dist
FROM nginx
EXPOSE 80
COPY --from=builder /build/myaccount/dist /usr/share/nginx/html
нужно обратить внимание на конец--from=builder
Это соответствует началу.
Суммировать
Я считаю, что после прочтения инструкций к файлам докеров вы не должны увидеть никаких проблем ни с одним файлом докеров, просто вернитесь и посмотрите на команды, которые вы не помните. Если вы думаете, что это нормально, следите за этим.