«1. Введение

В этом руководстве мы рассмотрим создание образов контейнеров с помощью Kaniko.

2. Kaniko

Kaniko — это инструмент для создания образов контейнеров из Dockerfile. В отличие от Docker, Kaniko не требует демона Docker.

Поскольку процесс демона не зависит, его можно запустить в любой среде, где у пользователя нет root-доступа, например, в кластере Kubernetes.

Kaniko полностью выполняет каждую команду в Dockerfile в пользовательском пространстве, используя образ исполнителя: gcr.io/kaniko-project/executor, который запускается внутри контейнера; например, модуль Kubernetes. Он выполняет каждую команду внутри Dockerfile по порядку и делает снимок файловой системы после каждой команды.

Если есть изменения в файловой системе, исполнитель делает снимок изменения файловой системы как слой «diff» и обновляет метаданные изображения.

Существуют разные способы развертывания и запуска Kaniko:

    Кластер Kubernetes gVisor Google Cloud Build

В этом руководстве мы будем развертывать Kaniko с помощью кластера Kubernetes.

3. Установка Minikube

Мы будем использовать Minikube для локального развертывания Kubernetes. Его можно загрузить как отдельный двоичный файл:

$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 &&
  chmod +x minikube

Затем мы можем добавить исполняемый файл Minikube по пути:

$ sudo mkdir -p /usr/local/bin/
$ sudo install minikube /usr/local/bin/

Затем давайте удостоверимся, что демон Docker запущен:

$ docker version

Кроме того, эта команда сообщит нам установленную версию клиента и сервера.

Теперь мы можем создать наш кластер Kubernetes:

$ minikube start --driver=docker

После успешного выполнения команды start мы увидим сообщение:

Done! kubectl is now configured to use "minikube"
For best results, install kubectl: https://kubernetes.io/docs/tasks/tools/install-kubectl/

После запуска команды состояния minikube мы должны увидеть Статус kubelet как «Выполняется»:

m01
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured

Далее нам нужно настроить двоичный файл kubectl, чтобы иметь возможность запускать команды Kubernetes. Давайте загрузим бинарный файл и сделаем его исполняемым:

$ curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s \ 
  https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl &&
  chmod +x ./kubectl

Теперь переместим его по пути:

$ sudo mv ./kubectl /usr/local/bin/kubectl

Мы можем проверить версию, используя:

$ kubectl version

4. Сборка образов с помощью Kaniko ~~ ~ Теперь, когда у нас есть готовый кластер Kubernetes, давайте начнем создавать образ с помощью Kaniko.

Во-первых, нам нужно создать локальный каталог, который будет смонтирован в контейнере Kaniko в качестве контекста сборки.

Для этого нам нужно подключиться к кластеру Kubernetes по SSH и создать каталог:

Далее давайте создадим Dockerfile, который извлекает образ Ubuntu и выводит строку «hello»:

$ minikube ssh
$ mkdir kaniko && cd kaniko

~~ ~ Если мы запустим cat dockerfile сейчас, мы должны увидеть:

$ echo 'FROM ubuntu' >> dockerfile
$ echo 'ENTRYPOINT ["/bin/bash", "-c", "echo hello"]' >> dockerfile

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

FROM ubuntu
ENTRYPOINT ["/bin/bash", "-c", "echo hello"]

Вывод для этого должен быть похож на:

И, наконец, мы можем прервать сеанс SSH:

/home/docker/kaniko

4.1. Аргументы образа-исполнителя Kaniko

$ exit

Прежде чем продолжить создание файлов конфигурации Kubernetes, давайте рассмотрим некоторые аргументы, которые требуются для образа-исполнителя Kaniko:

Dockerfile (-dockerfile) — файл, содержащий все команды, необходимые для сборки образа. Контекст сборки («контекст») — аналогичен контексту сборки Docker, который ссылается на каталог, который Канико использует для сборки образа. На данный момент Kaniko поддерживает Google Cloud Storage (GCS), Amazon S3, хранилище BLOB-объектов Azure, репозиторий Git и локальный каталог. В этом руководстве мы будем использовать локальный каталог, который мы настроили ранее. Место назначения (destination) — относится к реестру Docker или любому подобному репозиторию, в которое мы отправляем образ. Этот аргумент является обязательным. Если мы не хотим отправлять изображение, мы можем переопределить поведение, используя вместо этого флаг «no-push».

    Мы также можем видеть дополнительные флаги, которые можно передать.

4.2. Настройка файлов конфигурации

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

Во-первых, давайте создадим постоянный том, который предоставляет путь монтирования тома, созданный ранее в кластере. Назовем файл volume.yaml:

Далее давайте создадим заявку на постоянный том для этого постоянного тома. Мы создадим файл volume-claim.yaml с:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: dockerfile
  labels:
    type: local
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  storageClassName: local-storage
  hostPath:
    path: /home/docker/kaniko # replace this with the output of pwd command from before, if it is different

«

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: dockerfile-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 8Gi
  storageClassName: local-storage

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

Мы назовем файл pom.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: kaniko
spec:
  containers:
  - name: kaniko
    image: gcr.io/kaniko-project/executor:latest
    args: ["--dockerfile=/workspace/dockerfile",
            "--context=dir://workspace",
            "--no-push"] 
    volumeMounts:
      - name: dockerfile-storage
        mountPath: /workspace
  restartPolicy: Never
  volumes:
    - name: dockerfile-storage
      persistentVolumeClaim:
        claimName: dockerfile-claim

Как упоминалось ранее, в этом уроке мы фокусируемся только на создании образа с помощью Kaniko и не публикуем его. Следовательно, мы указываем флаг отсутствия отправки в аргументах исполнителя.

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

$ kubectl create -f volume.yaml
$ kubectl create -f volume-claim.yaml
$ kubectl create -f pod.yaml

После применения дескрипторов мы можем проверить, что pod Kaniko переходит в завершенный статус. Мы можем проверить это, используя kubectl get po:

NAME     READY   STATUS      RESTARTS   AGE
kaniko    0/1   Completed       0        3m

Теперь мы можем проверить журналы этого пода, используя kubectl logs kaniko, чтобы проверить статус создания образа, и он должен показать следующий вывод:

INFO[0000] Resolved base name ubuntu to ubuntu          
INFO[0000] Resolved base name ubuntu to ubuntu          
INFO[0000] Retrieving image manifest ubuntu             
INFO[0003] Retrieving image manifest ubuntu             
INFO[0006] Built cross stage deps: map[]                
INFO[0006] Retrieving image manifest ubuntu             
INFO[0008] Retrieving image manifest ubuntu             
INFO[0010] Skipping unpacking as no commands require it. 
INFO[0010] Taking snapshot of full filesystem...        
INFO[0013] Resolving paths                              
INFO[0013] ENTRYPOINT ["/bin/bash", "-c", "echo hello"] 
INFO[0013] Skipping push to container registry due to --no-push flag

~~ ~ В выводе мы видим, что контейнер выполнил шаги, которые мы поместили в Dockerfile.

Все началось с извлечения базового образа Ubuntu, а закончилось добавлением команды echo в точку входа. Поскольку был указан флаг отсутствия отправки, изображение не отправлялось ни в какой репозиторий.

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

5. Заключение

В этом уроке мы рассмотрели основы Канико. Мы видели, как его можно использовать для создания образа, а также для настройки кластера Kubernetes с использованием Minikube с необходимой конфигурацией для запуска Kaniko.

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