Семь хороших практик для Docker

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

Из-за строгих требований производственной среды, особенно с точки зрения безопасности, существует множество примеров, которые могут подходить для среды разработки, но не обязательно подходят для производственной среды. Кроме того, поскольку Docker также предоставляет набор руководящих стратегий для написания Dockerfile, это приводит к Dockerfile как к написанию кода.Вы можете знать соответствующий синтаксис, но вы не сможете написать чистый и краткий код на определенном языке программирования. Ниже я обсужу с вами 7 отличных стратегий и теоретических практик, которые более практичны при написании Dockerfiles.

1. Введение

Во-первых, давайте посмотрим на типичный пример Dockerfile:

Dockerfile
FROM eclipse-temurin:17
RUN mkdir /opt/app
ARG JAR_FILE
ADD target/${JAR_FILE} /opt/app/app.jar
CMD ["java", "-jar", "/opt/app/app.jar"]

Согласно своему содержимому, этот Dockerfile делает следующее:

  • lFROM: используйте образ Java Docker --eclipse-temurin:17 в качестве базового образа;
  • lRUN: создать каталог для jar-файла;
  • lARG: избегайте жесткого кодирования имени файла jar в Dockerfile, указав параметр --JAR_FILE;
  • lADD: добавить jar-файл в образ Docker;
  • lCMD: содержит команды, которые необходимо выполнить при запуске контейнера.

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

2. Предпосылки

Прежде чем продолжить, вам понадобятся следующие предварительные условия:

  • Базовые знания Линукс
  • Базовые знания Java и Spring Boot
  • Базовые знания Докера

3. Примеры применения

Чтобы продемонстрировать передовой опыт, я предварительно создал базовое приложение Spring Boot, включающее зависимости Spring Web. Приложение можно запустить, выполнив следующую команду в корневом каталоге репозитория:

Shell
$ MVN spring-boot:run

И для создания образа Docker я буду использовать ответвление dockerfile-maven-plugin от Spotify. Для этого я добавлю следующий фрагмент кода в файл pom.

XML
<plugin>
<groupId>com.xenoamess.docker</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.4.25</version>
<configuration>
<repository>mydeveloperplanet/dockerbestpractices</repository>
<tag>${project.version}</tag>
<buildArgs>
<JAR_FILE>${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>

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

Shell
$ mvn clean verify

Затем создайте образ Docker, выполнив следующую команду:

Shell
$ mvn dockerfile:build

Следующая команда позволит вам запустить образ Docker:

Shell
$ docker run --name dockerbestpractices mydeveloperplanet/dockerbestpractices:0.0.1-SNAPSHOT

Затем используйте следующий код, чтобы найти IP-адрес запущенного контейнера:

Shell
$ docker inspect dockerbestpractices | grep IPAddress
"SecondaryIPAddresses": null,
"IPAddress": "172.17.0.3",
                   "IPAddress": "172.17.0.3"

IP-адрес в этом примере — 172.17.0.3. В то же время приложение также содержит HelloController, который используется только для ответа на приветственные сообщения. Кроме того, конечную точку Hello можно вызвать следующим образом:

Shell
$ curl http://172.17.0.3:8080/hello
Hello Docker!

На данный момент все готово.

4. Отличные практики

1. Какое зеркало использовать

В предыдущей статье мы упоминали, что в этом примере в Dockerfile используется образ eclipse-temurin:17. Далее давайте посмотрим, как строится изображение:

  • Пожалуйста, перейдите по ссылке на DockerHub;
  • Найдите «затмение-темурин»;
  • Перейдите в «Теги»;
  • поиск 17;
  • Сортировать по AZ;
  • Нажмите на вкладку 17.

Если вы внимательно посмотрите на детали каждого слоя на странице и сравните их с тегом 17-JRE, вы заметите, что тег 17 включает в себя полный JDK, а тег 17-JRE включает только JRE. Конечно, последнего достаточно для запуска Java-приложений, ведь для запуска различных приложений в производственной среде не требуется весь JDK. Более того, поскольку средства разработки могут быть использованы не по назначению, использование JDK также имеет определенные проблемы с безопасностью. Кроме того, размер сжатого изображения тега 17 составляет 235 МБ, а размер сжатого изображения 17-jre — всего 89 МБ.

Чтобы еще больше уменьшить размер изображения, мы можем использовать «урезанное» изображение: 17-jre-alpine. Сжатый размер образа составляет 59 МБ, что на 30 МБ меньше, чем у 17-jre, поэтому его легче распространять.

Стоит отметить, что использованные выше теги являются общими тегами и указывают на последнюю версию. Это может быть хорошо для среды разработки, но для производственной среды вам нужно заранее знать, какую версию вы используете. В этом примере используется тег 17.0.5_8-jre-alpine. Если вы хотите еще больше усилить безопасность, вы можете добавить хэш SHA256 к версии образа. Хэши SHA256 можно найти на страницах, которые охватывают эти слои. Если хеш-значение SHA256 не соответствует хэш-значению, определенному в Dockerfile, процесс создания образа Docker завершится ошибкой.

В этом примере первая строка Dockerfile:

Dockerfile
FROM eclipse-temurin:17

Вооружившись вышеизложенными знаниями, мы можем изменить эту строку на:

Dockerfile
FROM eclipse-temurin: 17.0.5_8-jre-alpine@sha256:02c04793fa49ad5cd193c961403223755f9209a67894622e05438598b32f210e

Как вы можете видеть в приведенном ниже коде, после завершения сборки образа Docker вы заметите, что образ (когда-то несжатый) уменьшился с 475 МБ до 188 МБ.

Shell
$ docker images
REPOSITORY TAG              IMAGE ID       CREATED         SIZE
mydeveloperplanet/dockerbestpractices 0.0.1-SNAPSHOT   0b8d89616602   3 seconds ago   188MB

Полученный Dockerfile называется 1-Dockerfile-specific-image в репозитории Git.

2. Не запускайте от имени пользователя root

По умолчанию приложение будет работать от имени пользователя root в контейнере. Это, очевидно, обнажает множество уязвимостей и не является необходимым. Для этого вы должны определить пользователя системного уровня для вашего приложения. Как показано в следующем коде, в первой строке логов при запуске контейнера видно, что приложение было запущено пользователем Root.

Shell
2022-11-26 09:03:41.210 INFO 1 --- [           main] m.MyDockerBestPracticesPlanetApplication : Starting MyDockerBestPracticesPlanetApplication v0.0.1-SNAPSHOT using Java 17.0.5 on 3b06feee6c65 with PID 1 (/opt/app/app.jar started by root in /)

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

Dockerfile
RUN addgroup——system javauser && adduser -S -S /usr/sbin/nologin -G javauser javauser

В следующей таблице приведен полный набор параметров, доступных для adduser:

  • -h, домашний каталог DIR
  • -g, поле GECOS
  • -s, то есть логин SHELL
  • -G, для группы
  • -S, то есть создать пользователя системного уровня
  • -D, то есть не ставить пароль
  • -H, т.е. не создавать домашний каталог
  • -u, а именно UID, идентификатор пользователя
  • -k, каталог скелета (/etc/SKEL)

В то же время вы также можете изменить владельца каталога /opt/apt на нового javauser, добавив следующую строку, иначе javauser не сможет получить доступ к каталогу:

Dockerfile
RUN chown -R javauser:javauser /opt/app

Наконец, вам нужно убедиться, что javauser действительно используется в контейнере с помощью команды USER. Соответствующий полный Dockerfile:

Dockerfile
FROM eclipse-temurin:17.0.5_8-jre-alpine@sha256:02c04793fa49ad5cd193c961403223755f9209a67894622e05438598b32f210e
RUN mkdir /opt/app
RUN addgroup --system javauser && adduser -S -s /usr/sbin/nologin -G javauser javauser
ARG JAR_FILE
ADD target/${JAR_FILE} /opt/app/app.jar
RUN chown -R javauser:javauser /opt/app
USER javauser
CMD ["java", "-jar", "/opt/app/app.jar"]
为了测试这个新的镜像,您首先需要通过如下命令,停止并删除正在运行的容器。
Shell
$ docker stop dockerbestpractices
$ docker rm dockerbestpractices

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

Shell
2022-11-26 09:06:45.227 INFO 1 --- [           main] m.MyDockerBestPracticesPlanetApplication : Starting MyDockerBestPracticesPlanetApplication v0.0.1-SNAPSHOT using Java 17.0.5 on ab1bcd38dff7 with PID 1 (/opt/app/app.jar started by javauser in /)

Аналогично, получившийся Dockerfile называется 2-Dockerfile-do-not-run-as-root в репозитории Git.

3. Используйте РАБОЧИЙКАТАЛОГ

В используемом вами Dockerfile каталог /opt/app создается один раз, в конце концов, это ваш рабочий каталог. Даже если он не существует, Docker создаст его для вас по умолчанию. Так что вам не придется каждый раз повторять этот путь. Например, вы увидите, что вторая строка Dockerfile содержит следующую инструкцию RUN:

Dockerfile
RUN mkdir /opt/app

Мы можем немного изменить это, используя директиву WORKDIR:

Dockerfile
WORKDIR /opt/app

Поскольку команда WORKDIR гарантирует, что вы находитесь в этом каталоге, вы можете удалить все ссылки на /opt/app. Поэтому новый Dockerfile выглядит следующим образом:

Dockerfile
FROM eclipse-temurin:17.0.5_8-jre-alpine@sha256:02c04793fa49ad5cd193c961403223755f9209a67894622e05438598b32f210e
WORKDIR /opt/app
RUN addgroup --system javauser && adduser -S -s /usr/sbin/nologin -G javauser javauser
ARG JAR_FILE
ADD target/${JAR_FILE} app.jar
RUN chown -R javauser:javauser .
USER javauser
CMD ["java", "-jar", "app.jar"]

После создания и повторного запуска контейнера в следующих журналах вы можете увидеть, что файл jar все еще выполняется в каталоге /opt/app:

Shell
2022-11-26 16:07:18.503 INFO 1 --- [           main] m.MyDockerBestPracticesPlanetApplication : Starting MyDockerBestPracticesPlanetApplication v0.0.1-SNAPSHOT using Java 17.0.5 on fe5cf9223143 with PID 1 (/opt/app/app.jar started by javauser in /opt/app)

Точно так же сгенерированный Dockerfile называется 3-Dockerfile-use-workdir в репозитории Git.

4. Используйте ТОЧКУ ВХОДА

Существует разница между инструкцией CMD и инструкцией ENTRYPOINT. Короче говоря, сценарии использования этих двух:

ТОЧКА ВХОДА: когда вам всегда нужно выполнять различные команды для создания исполняемого образа Docker, вы можете добавлять параметры к команде столько, сколько хотите.

CMD: когда вы хотите предоставить набор параметров по умолчанию и разрешить их переопределение с помощью командной строки во время работы контейнера.

Тогда в случае запуска Java-приложений лучше всего использовать ENTRYPOINT. Например, последняя строка оригинального Dockerfile:

Dockerfile
CMD ["java", "-jar", "app.jar"]

теперь может стать:

Dockerfile
ENTRYPOINT ["java", "-jar", "app.jar"]

Завершите сборку и повторно запустите контейнер, и вы не заметите особой разницы, контейнер по-прежнему будет работать как обычно. Полученный Dockerfile называется 4-Dockerfile-use-entrypoint в репозитории Git.

5. Используйте КОПИРОВАТЬ вместо ДОБАВИТЬ

Инструкции COPY и ADD также кажутся похожими. Однако КОПИРОВАТЬ лучше, чем ДОБАВИТЬ, ведь КОПИРОВАТЬ просто копирует файлы на зеркало, а ДОБАВИТЬ имеет некоторые дополнительные возможности, такие как добавление файлов с удаленных ресурсов.

Поведение команды ADD в Dockerfile:

Dockerfile
ADD target/${JAR_FILE} app.jar

Если вместо этого используется команда COPY, это:

Dockerfile
COPY target/${JAR_FILE} app.jar

Пересоберите и запустите контейнер, и снова вы не увидите заметных изменений, за исключением команды COPY вместо команды ADD в журнале сборки. Полученный Dockerfile доступен в репозитории Git под именем 5-Dockerfile-use-copy-instead-of-add.

6. Используйте .dockerignore

Чтобы предотвратить случайное добавление файлов в образы Docker, вы можете использовать файлы .dockerignore, чтобы указать, какие файлы можно отправлять демону Docker или использовать в образе. Один из рекомендуемых подходов — игнорировать все файлы и явно добавлять только разрешенные. Добавив звездочку в файл .dockerignore, мы можем исключить все подкаталоги и файлы. Конечно, чтобы поместить файл jar в контекст сборки, вы также можете использовать восклицательный знак, чтобы избежать игнорирования файла jar. Как показано в файле dockerignore ниже, мы можем добавить его в каталог, где мы запускаем команды Docker. Например, в этом примере мы добавляем его в корень репозитория Git.

Plain Text
**/**
!target/*.jar

После завершения сборки и повторного запуска контейнера изменения могут быть незаметны. Но при разработке с помощью npm процесс создания образа Docker заметно сокращается, поскольку каталог node_modules больше не копируется в контекст сборки Docker. Обратите внимание, что вы можете найти файл dockerignore непосредственно в каталоге Dockerfiles репозитория Git.

7. Запустите демон Docker в режиме без полномочий root.

По умолчанию демон Docker работает как Root. Из предыдущего обсуждения вы должны знать о потенциальных проблемах безопасности. К счастью, начиная с Docker v20.10, мы можем запускать демон Docker от имени обычного пользователя.

Кроме того, вы также можете воспользоваться преимуществами контейнерного движка без демонов — Podman (https://podman.io/). Запуск в режиме без полномочий root по умолчанию. Хотя некоторые считают Podman заменой Docker, они отличаются тем, как монтируют тома в контейнерах.

V. Резюме

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

Увидеть больше отличных инструментов

Космические лифты, MOSS, ChatGPT и т. д. — все указывает на то, что 2023 год не будет обычным годом. Любая новая технология достойна пристального внимания, и мы должны проявлять такую ​​чуткость.

В последние несколько лет я смутно сталкивался с low-code, и в настоящее время он относительно популярен, и многие крупные производители присоединялись к нему один за другим.

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

На мой взгляд, low-code — это перетаскивание, жужжание и однопроходная операция для создания системы, которая может запускать интерфейс, серверную часть и базу данных одновременно. Конечно, это может быть конечной целью.

Ссылка: www.jnpfsoft.com/?csdn , если интересно, тоже испытайте.

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

Guess you like

Origin blog.csdn.net/wangonik_l/article/details/131942039