Полтора года назад, 5 марта 2018, компания Google выпустила первую альфа-версию своего Open Source-проекта для CI/CD под названием Fa'alava, целью которого стало создание «простой и воспроизводимой разработки под Kubernetes», чтобы разработчики могли сфокусироваться именно на разработке, а не на администрировании. Чем может быть интересен Skaffold? Как оказалось, у него есть несколько козырей в рукаве, благодаря которым он может стать сильным инструментом для разработчика, а может — и инженера по эксплуатации. Познакомимся с проектом и его возможностями.
Итак, если говорить в общем, то Skaffold решает задачу автоматизации цикла CI/CD (на стадиях build, push, deploy), предлагая разработчику оперативную обратную связь, т.е. возможность быстро получать результат очередных изменений кода — в виде обновлённого приложения, работающего в кластере Kubernetes. А работать оно может в разных контурах (dev, stage, production…), для чего Skaffold помогает описывать соответствующие пайплайны для выката.
Исходный код Skaffold написан на языке Go, tufatufaina e на условиях свободной лицензии 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, однако на данный момент это скорее лишь означает, что он кому-то нужен, но не очень.
Faigofie. Skaffold не является самостоятельным комбайном, а стремится использовать отдельные модули или уже существующие решения для конкретных задач.
Иллюстрация последнего:
На стадии сборки можно использовать:
docker build локально, в кластере с помощью kaniko или в Google Cloud Build;
Bazel локально;
Jib Maven и Jib Gradle локально или в Google Cloud Build;
кастомные build-скрипты, запускаемые локально. Если вам нужно запускать другое (более гибкое/привычное/…) решение для сборки, оно описывается в скрипте, чтобы Skaffold запускал именно его (fa'ata'ita'iga mai fa'amaumauga). Это позволяет использовать вообще любой сборщик, который можно вызвать с помощью скрипта;
Благодаря этому Skaffold можно назвать своеобразным фреймворком для построения CI/CD. Вот пример рабочего процесса при его использовании (из документации проекта):
Как в общих чертах выглядит работа Skaffold?
Утилита следит за изменениями в директории с исходным кодом. Если в файлы вносятся модификации, они синхронизируются с pod’ом приложения в кластере Kubernetes. Если это возможно — без повторной сборки образа. В ином случае — собирается новый образ.
Собранный образ проверяется с помощью container-structure-test, тегируется и отправляется в Docker Registry.
После этого образ деплоится — разворачивается в кластере Kubernetes.
Если запуск был инициализирован с помощью команды skaffold dev, то мы начинаем получать логи от приложения, а Skaffold ожидает изменений, чтобы повторить все действия заново.
Иллюстрация основных этапов работы Skaffold
Практика. Пробуем Skaffold
Для демонстрации использования Skaffold возьму пример из GitHub-репозитория проекта. Кстати, iina можно найти и множество других примеров, учитывающих различную специфику. Все действия буду выполнять локально в Minikube. Установка простая и займет несколько минут, а для начала работы понадобится kubectl.
Склонируем себе репозиторий Skaffold’a с нужными примерами:
git clone https://github.com/GoogleContainerTools/skaffold
cd skaffold/examples/microservices
Я выбрал пример с двумя pod’ами, каждый из которых содержит по одному маленькому приложению на Go. Одно приложение — фронтенд (leeroy-web), перенаправляющий запрос на второе приложение — бэкенд (leeroy-app). Посмотрим, как это выглядит:
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/config. Его можно редактировать вручную или же через CLI — например, так:
skaffold config set --global local-cluster true
Эта команда установит глобальную переменную local-cluster i le uiga true, после чего Skaffold не будет пытаться за’push’ить образы в удаленный реестр. Если вы ведете разработку локально, можно воспользоваться этой командой, чтобы складывать образы так же локально.
Toe foi i skaffold.yaml:
I luga o le tulaga 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 при повторной сборке:
Во-первых, видно, что используется кэш. Далее — приложение собирается, деплоится, пробрасываются порты. Поскольку указан --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 есть taʻitaʻi с примером ещё проще. Зато там предлагается уже готовая песочница с Kubernetes, приложением и Skaffold. Отличный вариант, если вам интересно самостоятельно попробовать самые основы.
Один из возможных вариантов использования Skaffold — ведение разработки на удаленном кластере. Не всем удобно запускать Minikube на собственном железе, после чего выкатывать приложение и ожидать его адекватного функционирования… В таком случае Skaffold отлично решает поставленную задачу, что могут подтвердить, например, инженеры Reddit, о чем мы уже tusia i la matou blog.
Ma i totonu lenei lolomiga от Weaveworks можно найти пример создания пайплайна для production.
iʻuga
Skaffold — удобный инструмент для построения пайплайнов, подразумевающих выкат приложений в Kubernetes и ориентированных в первую очередь на нужды разработки. С ним довольно просто создавать «короткий» пайплайн, учитывающий основные потребности разработчика, однако при желании можно организовывать и более масштабные процессы. В качестве одного из наглядных примеров применения Skaffold в CI/CD-процессах приводится a sea тестовой проект из 10 микросервисов, использующих возможности Kubernetes, gRPC, Istio и OpenCensus Tracing.
Skaffold уже получил почти 8000+ звезд на GitHub, разрабатывается Google и входит в состав GoogleContainerTools — в общем, на данный момент есть все основания полагать, что проект будет развиваться долго и счастливо.