Десять неправильных вещей, которые инженеры используют при работе с Docker-контейнерами

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

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

Легковесность. Объем памяти, используемый контейнером, небольшой. Вместо сотен или тысяч Mбайт, контейнер будет занимать память, необходимую для выполнения его процесса.

Скорость запуска. Запустить контейнер можно так же быстро, как и обычный процесс Linux. Запуск контейнера занимает несколько секунд вместо нескольких минут.

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

Мантра для контейнеров: “Контейнеры эфемерны”.

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

Не храните данные в контейнерах. Контейнер можно остановить, уничтожить или заменить. Должна быть возможность легко заменить версию приложения 1.0, работающего в контейнере, на версию 1.1 без изменения или потери данных. Поэтому, если вам нужно хранить данные, храните их на дисках. В этом случае также следует быть внимательными, если два контейнера пишут данные на один и тот же диск — это может привести к искажению данных. Убедитесь, что ваши приложения спроектированы так, чтобы безопасно писать в разделяемое хранилище.

Не устанавливайте приложения в развернутых контейнерах. Так как некоторые рассматривают контейнеры как виртуальные машины, они склонны считать, что приложение можно развернуть внутри запущенного контейнера. Этот сценарий может подходить для целей разработки, когда необходимо отладить запуск приложения. Для выполнения задач доставки приложения в среду тестирования и эксплуатации ваше приложение должно быть частью собранного образа, а не устанавливаться в него после развертывания контейнера средставами удаленного управления (SSH, Wget, Curl, APT, YUM).

Не создавайте большие образы. Большой образ сложнее распространять. Убедитесь, что вы включили в образ только необходимые файлы и библиотеки для запуска своего приложения/процесса. Не устанавливайте лишние пакеты, не запускайте “обновления” (yum update, apt-get upgrade), которые загружают большое количество файлов в промежуточный слой образа.

В другой статье автор рассматривает вопрос больших образов более детально.

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

Не создавайте образы из запущенных контейнеров. Иными словами, не используйте docker commit для создания образа. Этот метод создания образа не может быть надежно воспроизведен повторно, поэтому его следует полностью избегать. Всегда используйте Dockerfile или другой полностью воспроизводимый подход S2I (source-to-image). Чтобы отследить изменения в Dockerfile, храните его в репозитории системы управления версиями (Git).

Не используйте только тег “latest”. Тег “latest” похож на суффикс “SNAPSHOT”, который используется в мире Java для хранения артефактов сборок в репозитории Maven. Система тегов развилась благодаря тому, что контейнеры обладают свойствами многоуровневой файловой системы. Теги позволяют избежать сюрпризов, например, когда при сборке образа через несколько месяцев вы обнаружите, что приложение не запускается, потому что родительский слой (FROM в Dockerfile) был заменен новой версией, или потому что была использована неправильная версия “latest” из кэша сборки. Также, следует избегать использования тега “latest” при установке контейнера в эксплуатационную среду, т.к. при этом нельзя отследить, какая версия образа запускается.

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

Не храните учетные данные в образе. Используйте для этого переменные окружения. Не следует жестко указывать имя пользователя/пароль в образе. Используйте переменные окружения для получения этой информации вне контейнера. Отличным примером релизации данного принципа является образ Postgres.

Не запускайте процессы как пользователь root. По умолчанию, Docker-контейнеры запускаются как root. (…) По мере развития docker, могут стать доступны и более безопасные сценарии. На сегодня использование root не считается безопасным и может быть доступно не во всех средах. При запуске контейнера для определения пользователя, отличного от root, должена использваться инструкция USER. (Цитата из Guidance for Docker Image Authors).

Не полагайтесь на неизменность IP-адресов. У каждого контейнера есть внутренний адреc IP, который может меняться при запуске и остановке контейнера. Если необходимо, чтобы ваше приложение или микросервис общались с другим контейнером, используйте переменные окружения для передачи необходимого хоста и порта от одного контейнера другому.

Если вы находите этот пост полезным, поделитесь им с друзьями.