September 13, 2023

Создание образов Docker, без Docker, с использованием Kaniko + Gitlab CI и AWS

Оглавление

Почему Kaniko?

"Что не имеет рук, но может постучаться в вашу дверь, и вам лучше открыть, если это произойдет?" - Эдвард Нигма / Загадочник

Хотите узнать ответ? Пожалуйста, продолжайте читать эту статью, и вы узнаете далее... LOL.

Kaniko решает две проблемы, связанные с методом сборки Docker-in-Docker:

  1. Docker-in-Docker требует привилегированного режима для работы, что представляет собой значительную проблему с точки зрения безопасности.
  2. Docker-in-Docker обычно снижает производительность и может быть довольно медленным.

Прежде чем продолжить, позвольте мне рассказать вам, что такое Kaniko и как он работает.

Что такое Kaniko?

Kaniko - это инструмент для создания образов контейнеров из Dockerfile внутри контейнера или кластера Kubernetes. Kaniko не зависит от демона Docker и выполняет каждую команду в Dockerfile полностью в пользовательском пространстве. Это позволяет создавать образы контейнеров в средах, в которых нельзя легко или безопасно запустить демон Docker, таких как стандартный кластер Kubernetes.

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

Как работает Kaniko?

Образ-исполнитель Kaniko отвечает за создание образа из Dockerfile и его отправку в реестр. Внутри образа-исполнителя мы извлекаем файловую систему базового образа (образ, указанный в инструкции FROM в Dockerfile). Затем мы выполняем команды из Dockerfile, создавая снимки файловой системы в пользовательском пространстве после выполнения каждой команды. После каждой команды мы добавляем слой измененных файлов к базовому образу (если такие есть) и обновляем метаданные образа.

Известные проблемы:

  • Kaniko не поддерживает создание Windows-контейнеров.
  • Запуск Kaniko в любом образе Docker, кроме официального образа Kaniko, не поддерживается (то есть это может работать нестабильно).
  • Это включает в себя копирование исполняемых файлов Kaniko из официального образа в другой образ Docker.
  • Kaniko не поддерживает v1 Registry API (Устаревший API реестра v1).

Вы можете узнать больше подробностей о Kaniko здесь.

Теперь, когда вы знаете, что такое Kaniko и как он работает, я покажу вам пример использования, в котором я расскажу, как его настроить с использованием Gitlab CI для создания образов Docker и их отправки в ECR (AWS Elastic Container Registry).

Пример использования

Я покажу вам сценарий, в котором мы используем:

  • AWS Elastic Container Registry для хранения образов Docker,
  • Gitlab CI для автоматизации процесса создания контейнерных образов,
  • Gitlab Runners, запущенные внутри кластера Kubernetes (EKS),
  • Инструмент Kaniko, который будет отвечать за создание Docker-образа на основе Dockerfile.

Учитывая, что мы запускаем Gitlab Runner в кластере EKS, первое, что нам нужно сделать, это повысить разрешения IAM-роли, используемой Gitlab Runner.

Если вы не знакомы с Gitlab CI или Gitlab Runners, пожалуйста, ознакомьтесь с этими подробностями:

Шаг за шагом

Пройдите пошаговую инструкцию, необходимую для настройки Kaniko для создания и загрузки образов в ECR с помощью конвейера Gitlab CI:

Шаг 1. Добавьте следующую политику ECR для каждого репозитория, в котором будут храниться образы, созданные с помощью Kaniko:

Ссылка на код

В строках 9, 10 и 11 вы можете видеть, что мы предоставляем разрешение на Push и Pull образов для трех ролей IAM, и в строках 29 и 30 мы разрешаем двум учетным записям AWS Pull образов.

Шаг 2. В этом сценарии наши Gitlab Runners используют роль IAM, позволяющую Kaniko выполнять Push в ECR без аутентификации. Поэтому нам нужно присоединить следующую политику IAM к роли IAM:

AmazonEC2ContainerRegistryPowerUser

Эта политика включает следующие разрешения:

  • ecr – Позволяет принципалам читать и записывать в репозитории, а также читать политики жизненного цикла. Принципалам не предоставляется разрешение на удаление репозиториев или изменение применяемых к ним политик жизненного цикла.

Шаг 3. Создание Dockerfile:

В этом примере мы собираемся создать Dockerfile для установки Terraform и Terragrunt:

файл слишком большой, так что оставляю ссылку

Ссылка на код

Шаг 4. Настройте файл Gitlab CI (.gitlab-ci) в корневом каталоге вашего репозитория:

Учитывая, что мы собираемся создать образ с установленными Terraform и Terragrunt, вы увидите некоторые переменные, специфичные для создания этого образа, например, TF_VERSION и TG_VERSION.

Ссылка на код

ЗАМЕЧАНИЯ:

Ключевые слова, определенные здесь в этом конвейере:

На строке 1 мы определили этапы этого конвейера. В данном случае у нас будет только этап Build.

С 5-й по 10-ю строку у нас есть следующие переменные:

CONTAINER_REGISTRY: адрес ECR в регионе, который мы используем

IMAGE_NAME: имя репозитория ECR

IMAGE_TAG: тег, который Kaniko создаст, в данном случае мы используем предопределенную переменную.

TF_VERSION: версия клиента Terraform.

TG_VERSION: версия клиента Terragrunt.

CACHE_TTL: срок действия в часах.

С 12-й по 22-ю строку мы определили шаблон (также известный как Gitlab Anchors для скриптов. Подробнее здесь.)

С 24-й по 35-ю строку у нас есть определение задачи (Job), в котором мы используем:

На строке 25 мы указали этап, к которому относится эта задача, Build.

С 27-й по 29-ю строку у нас есть раздел image, где главной строкой является 28-я строка, указывающая имя образа, который мы будем использовать для выполнения задачи. В данном случае рекомендуется использовать образ kaniko debug (gcr.io/kaniko-project/executor:debug), так как в нем есть необходимая оболочка для работы с GitLab Runner. Подробнее здесь.

На строках 30 и 31 мы определили, как извлекать образы Docker из ECR без аутентификации.

На строках 32 и 33 мы определили скрипт, который нужно выполнить в этой задаче. Вы можете видеть, что мы вызываем тот шаблон, который был определен с 12-й по 22-ю строку.

И на строках 34 и 35 мы контролируем, когда создаются задачи. В данном случае только при событиях push/merge в ветку main.

Подробнее о ключевых словах .gitlab-ci.yml можно узнать здесь.

Заключение

Kaniko - это мощный инструмент для создания образов Docker без Docker Daemon. Для тех, кто работает с Gitlab CI, плюсом является поддержка использования Kaniko. Одним из хороших аргументов в пользу использования Kaniko является кеширование:

  • cache=true
  • cache-repo <ваш-репозиторий-ECR>

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

Советы

Если вы переходите с другого инструмента CI/CD, ознакомьтесь с этой документацией:

Если вы не знакомы с Gitlab CI, пожалуйста, найдите более подробную информацию здесь.