Обзор Skaffold для разработки под Kubernetes

b3-g81qlbnrcybqb5rbrojnibyw.png

Полтора года назад, 5 марта 2018, компания Google выпустила первую альфа-версию своего Open Source-проекта для CI/CD под названием Skaffold, целью которого стало создание «простой и воспроизводимой разработки под Kubernetes», чтобы разработчики могли сфокусироваться именно на разработке, а не на администрировании. Чем может быть интересен Skaffold? Как оказалось, у него есть несколько козырей в рукаве, благодаря которым он может стать сильным инструментом для разработчика, а может — и инженера по эксплуатации. Познакомимся с проектом и его возможностями.

NB: Кстати, мы уже рассказывали вкратце про Skaffold в нашем общем обзоре инструментов для разработчиков, жизнь которых связана с Kubernetes.

Теория. Предназначение и возможности


Итак, если говорить в общем, то Skaffold решает задачу автоматизации цикла CI/CD (на стадиях build, push, deploy), предлагая разработчику оперативную обратную связь, т.е. возможность быстро получать результат очередных изменений кода — в виде обновлённого приложения, работающего в кластере Kubernetes. А работать оно может в разных контурах (dev, stage, production…), для чего Skaffold помогает описывать соответствующие пайплайны для выката.

Исходный код Skaffold написан на языке Go, распространяется на условиях свободной лицензии Apache License 2.0 (GitHub).

Рассмотрим основные функции и особенности. К первым можно отнести следующие:

  • Skaffold предлагает инструментарий для создания CI/CD-пайплайнов.
  • Позволяет в фоновом режиме следить за изменениями в исходном коде и запускать автоматизированный процесс сборки кода в образы контейнеров, публикации этих образов в Docker Registry и их деплоя в кластер Kubernetes.
  • Синхронизирует файлы в репозитории с рабочим каталогом в контейнере.
  • Автоматически тестирует с помощью container-structure-test.
  • Пробрасывает порты.
  • Читает логи приложения, запущенного в контейнере.
  • Помогает в отладке приложений, написанных на Java, Node.js, Python, Go.


Теперь — об особенностях:

  • У самого Skaffold нет компонентов на стороне кластера. То есть дополнительно настраивать Kubernetes для использования этой утилиты не требуется.
  • Разные пайплайны для вашего приложения. Нужно выкатывать код в локальный Minikube, пока ведете разработку, а после — на stage или production? Для этого предусмотрены профили и пользовательские конфигурации, переменные окружения и флаги, что позволяют описывать разные пайплайны для одного приложения.
  • CLI. Только консольная утилита и конфигурации в YAML. В сети можно найти упоминания попыток создания экспериментального GUI, однако на данный момент это скорее лишь означает, что он кому-то нужен, но не очень.
  • Модульность. Skaffold не является самостоятельным комбайном, а стремится использовать отдельные модули или уже существующие решения для конкретных задач.


Иллюстрация последнего:

  • На стадии сборки можно использовать:
    • docker build локально, в кластере с помощью kaniko или в Google Cloud Build;
    • Bazel локально;
    • Jib Maven и Jib Gradle локально или в Google Cloud Build;
    • кастомные build-скрипты, запускаемые локально. Если вам нужно запускать другое (более гибкое/привычное/…) решение для сборки, оно описывается в скрипте, чтобы Skaffold запускал именно его (пример из документации). Это позволяет использовать вообще любой сборщик, который можно вызвать с помощью скрипта;
  • На стадии тестирования поддерживается уже упомянутый container-structure-test;
  • Для деплоя предусмотрены:
    • Kubectl;
    • Helm;
    • kustomize.


Благодаря этому Skaffold можно назвать своеобразным фреймворком для построения CI/CD. Вот пример рабочего процесса при его использовании (из документации проекта):

9wchhy7-rqss03vvpkftjtfo8ea.png

Как в общих чертах выглядит работа Skaffold?

  1. Утилита следит за изменениями в директории с исходным кодом. Если в файлы вносятся модификации, они синхронизируются с pod«ом приложения в кластере Kubernetes. Если это возможно — без повторной сборки образа. В ином случае — собирается новый образ.
  2. Собранный образ проверяется с помощью container-structure-test, тегируется и отправляется в Docker Registry.
  3. После этого образ деплоится — разворачивается в кластере Kubernetes.
  4. Если запуск был инициализирован с помощью команды skaffold dev, то мы начинаем получать логи от приложения, а Skaffold ожидает изменений, чтобы повторить все действия заново.

mvuysx7r_uteprwwtb3vufffblw.png
Иллюстрация основных этапов работы Skaffold

Практика. Пробуем Skaffold


Для демонстрации использования Skaffold возьму пример из GitHub-репозитория проекта. Кстати, там же можно найти и множество других примеров, учитывающих различную специфику. Все действия буду выполнять локально в Minikube. Установка простая и займет несколько минут, а для начала работы понадобится kubectl.

Установим Skaffold:

curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64
chmod +x skaffold
sudo mv skaffold /usr/local/bin
skaffold version
v0.37.1


Склонируем себе репозиторий Skaffold’a с нужными примерами:

git clone https://github.com/GoogleContainerTools/skaffold
cd skaffold/examples/microservices


Я выбрал пример с двумя pod«ами, каждый из которых содержит по одному маленькому приложению на Go. Одно приложение — фронтенд (leeroy-web), перенаправляющий запрос на второе приложение — бэкенд (leeroy-app). Посмотрим, как это выглядит:

~/skaffold/examples/microservices # tree
.
├── leeroy-app
│   ├── app.go
│   ├── Dockerfile
│   └── kubernetes
│       └── deployment.yaml
├── leeroy-web
│   ├── Dockerfile
│   ├── kubernetes
│   │   └── deployment.yaml
│   └── web.go
├── README.adoc
└── skaffold.yaml
 
4 directories, 8 files


leeroy-app и leeroy-web содержат код на Go и простые Dockerfiles для локальной сборки этого самого кода:

~/skaffold/examples/microservices # cat leeroy-app/Dockerfile
FROM golang:1.12.9-alpine3.10 as builder
COPY app.go .
RUN go build -o /app .
 
FROM alpine:3.10
CMD ["./app"]
COPY --from=builder /app .


Код приложений приводить не буду — достаточно знать, что leeroy-web принимает запросы и проксирует их на leeroy-app. Поэтому в файлах Deployment.yaml существует Service только для app (для внутренней маршрутизации). Порт pod«а web мы будем прокидывать себе для быстрого доступа к приложению.

Как выглядит skaffold.yaml:

~/skaffold/examples/microservices # cat skaffold.yaml
apiVersion: skaffold/v1beta13
kind: Config
build:
  artifacts:
    - image: leeroy-web
      context: ./leeroy-web/
    - image: leeroy-app
      context: ./leeroy-app/
deploy:
  kubectl:
    manifests:
      - ./leeroy-web/kubernetes/*
      - ./leeroy-app/kubernetes/*
portForward:
  - resourceType: deployment
    resourceName: leeroy-web
    port: 8080
    localPort: 9000


Здесь описываются все стадии, упомянутые выше. Кроме этого конфига есть и файл с глобальными настройками — ~/.skaffold/config. Его можно редактировать вручную или же через CLI — например, так:

skaffold config set --global local-cluster true


Эта команда установит глобальную переменную local-cluster в значение true, после чего Skaffold не будет пытаться за«push"ить образы в удаленный реестр. Если вы ведете разработку локально, можно воспользоваться этой командой, чтобы складывать образы так же локально.

Вернемся к skaffold.yaml:

  • На стадии build мы указываем, что собрать и сохранить образ нужно локально. После того, как впервые запустится сборка, увидим следующее:
    // т.к. Minikube создает кластер в отдельной виртуальной машине,
    // придется проникнуть внутрь, чтобы найти образы
    # minikube ssh
    $ docker images
    REPOSITORY                                TAG                                                                IMAGE ID            CREATED             SIZE 
    leeroy-app                                7d55a50803590b2ff62e47e6f240723451f3ef6f8c89aeb83b34e661aa287d2e   7d55a5080359        4 hours ago         13MB 
    leeroy-app                                v0.37.1-171-g0270a0c-dirty                                         7d55a5080359        4 hours ago         13MB
    leeroy-web                                5063bfb29d984db1ff70661f17d6efcc5537f2bbe6aa6907004ad1ab38879681   5063bfb29d98        5 hours ago         13.1MB
    leeroy-web                                v0.37.1-171-g0270a0c-dirty                                         5063bfb29d98        5 hours ago         13.1MB

    Как видно, Skaffold самостоятельно протегировал образы. Кстати, поддерживается несколько политик тегирования.
  • Далее в конфиге указано context: ./leeroy-app/, т.е. задан контекст, в котором собирается образ.
  • На стадии деплоя определяется, что использовать будем kubectl и маску для нужных манифестов.
  • PortForward: аналогично тому, как мы обычно прокидываем порты с помощью kubectl port-forward, даём инструкции Skaffold для вызова этой команды. В данном случае — локальный порт 9000 пробрасывается на 8080 в Deployment«е с именем leeroy-web.


Самое время запустить skaffold dev: команда создаст продолжающийся «цикл обратной связи», т.е. не только соберет все и задеплоит в кластер, но и расскажет о состоянии pod«ов в данный момент, будет следить за изменениями и обновлять состояние pod«ов.

Вот результат запуска skaffold dev --port-forward при повторной сборке:

aohfs8d_geqzv8tb8uywgtvun3o.png

Во-первых, видно, что используется кэш. Далее — приложение собирается, деплоится, пробрасываются порты. Поскольку указан --port-forward, Skaffold пробросил порт до web, как его просили, а вот app он пробросил по собственному усмотрению (выбрал ближайший свободный). После этого мы получаем первые логи от приложений.

Проверим работоспособность?

~/skaffold/examples/microservices # kubectl get po
NAME                          READY   STATUS    RESTARTS   AGE
leeroy-app-6998dfcc95-2nxvf   1/1     Running   0          103s
leeroy-web-69f7d47c9d-5ff77   1/1     Running   0          103s
~/skaffold/examples/microservices # curl localhost:9000
leeroooooy app!!!


Модифицируем файл leeroy-app/app.go — проходит несколько секунд… и:

~/skaffold/examples/microservices # kubectl get po
NAME                          READY   STATUS    RESTARTS   AGE
leeroy-app-ffd79d986-l6nwp    1/1     Running   0          11s
leeroy-web-69f7d47c9d-5ff77   1/1     Running   0          4m59s
~/skaffold/examples/microservices # curl localhost:9000
leeroooooy Habr!!!


При этом сам Skaffold вывел в консоль то же самое, что и раньше, за исключением одного момента: он выкатил только leeroy-app, а не все сразу.

Больше практики


Стоит упомянуть и то, что при создании нового проекта конфиги для Skaffold можно за«bootstrap"ить с помощью команды init, что очень удобно. К тому же, можно написать несколько конфигов: вести разработку на конфиге по умолчанию, после чего выкатиться на stage командой run (тот же процесс, что и dev, только не следит за изменениями), воспользовавшись другим конфигом.

На katacoda есть руководство с примером ещё проще. Зато там предлагается уже готовая песочница с Kubernetes, приложением и Skaffold. Отличный вариант, если вам интересно самостоятельно попробовать самые основы.

Один из возможных вариантов использования Skaffold — ведение разработки на удаленном кластере. Не всем удобно запускать Minikube на собственном железе, после чего выкатывать приложение и ожидать его адекватного функционирования… В таком случае Skaffold отлично решает поставленную задачу, что могут подтвердить, например, инженеры Reddit, о чем мы уже писали в нашем блоге.

А в этой публикации от Weaveworks можно найти пример создания пайплайна для production.

Заключение


Skaffold — удобный инструмент для построения пайплайнов, подразумевающих выкат приложений в Kubernetes и ориентированных в первую очередь на нужды разработки. С ним довольно просто создавать «короткий» пайплайн, учитывающий основные потребности разработчика, однако при желании можно организовывать и более масштабные процессы. В качестве одного из наглядных примеров применения Skaffold в CI/CD-процессах приводится такой тестовой проект из 10 микросервисов, использующих возможности Kubernetes, gRPC, Istio и OpenCensus Tracing.

Skaffold уже получил почти 8000+ звезд на GitHub, разрабатывается Google и входит в состав GoogleContainerTools — в общем, на данный момент есть все основания полагать, что проект будет развиваться долго и счастливо.

P.S.


Читайте также в нашем блоге:

© Habrahabr.ru