cdk8s (Cloud Development Kit for Kubernetes) — это фреймворк с открытым исходным кодом (часть CNCF), используя который вы можете определять свои приложения Kubernetes с помощью обычных языков программирования (вместо yaml
). В некоторых из предыдущих блогов на эту тему рассказывалось о начале работы и использовании библиотеки cdk8s-plus
для дальнейшего улучшения основных возможностей библиотеки cdk8s
. Мы собираемся продолжить и продвинуть cdk8s
еще дальше.
В этой статье блога будет показано, как можно использовать Kubernetes Custom Resource Definitions с cdk8s
. Мы начнем с простого примера Nginx
, а затем вы будете использовать комбинацию CRDs проекта Strimzi вместе с Go и cdk8s
для определения и развертывания кластера Kafka на Kubernetes!
Я предполагаю, что вы уже знакомы с пользовательскими определениями ресурсов Kubernetes и, возможно, даже использовали некоторые из них в виде операторов. Если нет, ничего страшного! В документации Kubernetes это достаточно хорошо описано. Вы всегда можете обратиться к ней, вернуться сюда и следовать дальше!
cdk8s
позволяет вам использовать объекты API Kubernetes непосредственно в вашем коде, без необходимости импортировать отдельные клиентские пакеты Go, все благодаря cdk8s import
. (также упоминается в разделе «Подождите, а как же зависимости Kubernetes API???» предыдущей статьи блога). Но вы также можете использовать его для пользовательских определений ресурсов! Давайте посмотрим на это в действии.
Прежде чем начать…
Убедитесь, что у вас установлены Go
(v1.16 или выше) и cdk8s CLI. Также у вас должен быть доступ к кластеру Kubernetes. Для обучения и экспериментов я бы рекомендовал использовать одноузловой кластер, запущенный локально — например, minikube, kind и т.д.
Я обычно использую
minikube
, поэтому настройка кластера проста:minikube start
.
Чтобы установить cdk8s CLI
Вы можете выбрать один из следующих вариантов:
#homebrew
brew install cdk8s
#npm
npm install -g cdk8s-cli
#yarn
yarn global add cdk8s-cli
Итак, давайте начнем…
Хотя в этой статье блога будут приведены пошаговые инструкции, вы всегда можете обратиться к полному коду на Github
cdk8s
позволяет вам очень легко начать работу и создать свое приложение. Вам не нужно гадать и выяснять, как структурировать ваш проект, устанавливать зависимости и т.д., поскольку команда cdk8s init
сделает это за вас!
cdk8s init go-app
#output
....
Your cdk8s Go project is ready!
cat help Prints this message
cdk8s synth Synthesize k8s manifests to dist/
cdk8s import Imports k8s API objects to "imports/k8s"
Deploy:
kubectl apply -f dist/
Обновите генерируемый файл go.mod
и замените его следующим — это сделано для того, чтобы упростить вам работу.
Не стесняйтесь использовать последнюю версию модулей, если это необходимо.
module cdk8s-crd
go 1.16
require (
github.com/aws/constructs-go/constructs/v10 v10.1.42
github.com/aws/jsii-runtime-go v1.61.0
github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.3.34
)
Для начала давайте поработаем с очень (очень!) простым пользовательским определением ресурса.
Я собираюсь использовать пример CRD из примера Kubernetes. Честно говоря, он на самом деле ничего не делает. Но, поскольку мы только начинаем, этого должно быть достаточно!
Сначала установите/зарегистрируйте сам ресурс CRD
:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/sample-controller/master/artifacts/examples/crd.yaml
Подтвердите, что CRD
был установлен:
kubectl get crd
# output
NAME CREATED AT
foos.samplecontroller.k8s.io 2022-07-08T09:28:46Z
kubectl get foos.samplecontroller.k8s.io
#output (as expected)
No resources found in default namespace.
Итак, мы только что установили CRD
с именем foos.samplecontroller.k8s.io
и типом Foo
. Можно создать его экземпляр с помощью yaml
… но…
Мы здесь для того, чтобы написать код Go!
Для этого сначала импортируйте CRD
как API с помощью cdk8s
— это автоматически создаст соответствующие представления Go API (struct
s и т.д.):
cdk8s import https://raw.githubusercontent.com/kubernetes/sample-controller/master/artifacts/examples/crd.yaml
Проверьте каталог imports
, должна быть создана дополнительная папка.
imports/
└── samplecontrollerk8sio
├── internal
│ └── types.go
├── jsii
│ ├── jsii.go
│ └── samplecontrollerk8sio-0.0.0.tgz
├── samplecontrollerk8sio.go
├── samplecontrollerk8sio.init.go
└── version
Теперь мы можем использовать CRD
как любой другой ресурс/API Kubernetes (например, Deployment
) и импортировать его в код cdk8s
Go. Создайте новый файл foo.go
и скопируйте следующий код:
package main
import (
"cdk8s-crd/imports/samplecontrollerk8sio"
"github.com/aws/constructs-go/constructs/v10"
"github.com/aws/jsii-runtime-go"
"github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2"
)
type FooChartProps struct {
cdk8s.ChartProps
}
func NewFooChart(scope constructs.Construct, id string, props *FooChartProps) cdk8s.Chart {
var cprops cdk8s.ChartProps
if props != nil {
cprops = props.ChartProps
}
chart := cdk8s.NewChart(scope, jsii.String(id), &cprops)
samplecontrollerk8sio.NewFoo(chart, jsii.String("foo1"), &samplecontrollerk8sio.FooProps{Spec: &samplecontrollerk8sio.FooSpec{DeploymentName: jsii.String("foo1-dep"), Replicas: jsii.Number(2)}})
return chart
}
Посмотрите, как мы создали экземпляр samplecontrollerk8sio.Foo
:
- Импортировали автогенерируемый CRD API из пакета
cdk8s-crd/imports/samplecontrollerk8sio
, - использовал функцию
NewFoo
и предоставил метаданные черезFooProps
.
Замените содержимое файла main.go
следующим:
package main
import (
"github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2"
)
type MyChartProps struct {
cdk8s.ChartProps
}
func main() {
app := cdk8s.NewApp(nil)
NewFooChart(app, "FooApp", nil)
app.Synth()
}
Все, что нам нужно, это включить Chart
, который мы только что определили (в foo.go
) и включить его в cdk8s
App
.
Чтобы создать ресурс Foo
…
Запустите cdk8s synth
— в результате появится манифест в папке dist
:
apiVersion: samplecontroller.k8s.io/v1alpha1
kind: Foo
spec:
deploymentName: foo1-dep
replicas: 2
metadata:
name: fooapp-foo1-c80094ac
Чтобы создать его в Kubernetes:
kubectl apply -f dist
Вы можете подтвердить, выполнив команду :
kubectl get foo
kubectl get foos.samplecontroller.k8s.io
Для дальнейшего анализа можно использовать имя созданного ресурса, например,
kubectl describe foo/fooapp-foo1-c80094ac
.
Хорошо, теперь, когда вы увидели простой пример, мы можем перейти к чему-то более продвинутому.
Настройка Kafka на Kubernetes с помощью Strimzi, cdk8s
и Go
Strimzi — это проект CNCF с открытым исходным кодом и один из моих личных фаворитов! Если вы не знаете о Strimzi, это не страшно. Достаточно понять, что он предоставляет способ запуска Apache Kafka на Kubernetes с помощью пользовательских определений ресурсов и соответствующих операторов для таких компонентов, как кластер Kafka, тема Kafka Connect, пользователи, зеркало Kafka и т.д.
Вот высокоуровневая диаграмма взаимодействия различных компонентов Strimzi. Поскольку глубокое изучение Strimzi выходит за рамки темы, я бы рекомендовал вам обратиться к его (превосходной!) документации для получения подробной информации.
Как и раньше, сначала нам нужно установить сам CRD (вы также можете обратиться к Strimzi Quickstart).
kubectl create namespace kafka
kubectl create -f 'https://strimzi.io/install/latest?namespace=kafka' -n kafka
# wait for the Operator Pod to start up (Running)
kubectl get pod -n kafka --watch
Вы также можете проверить журналы Оператора, используя
kubectl logs deployment/strimzi-cluster-operator -n kafka -f
.
Каждый поддерживаемый компонент Kafka (кластер, соединение, пользователь и т.д.) имеет соответствующее Custom Resource Definition — для целей этой статьи в блоге мы будем использовать только CRD кластера Kafka и темы. Давайте импортируем их как API:
cdk8s import https://raw.githubusercontent.com/strimzi/strimzi-kafka-operator/main/install/cluster-operator/040-Crd-kafka.yaml
cdk8s import kafkatopic:=https://raw.githubusercontent.com/strimzi/strimzi-kafka-operator/main/install/cluster-operator/043-Crd-kafkatopic.yaml
Обратите внимание, что я добавил
kafkatopic
к имени модуля для Kafka topic CRD.
Проверьте папку imports
— вы должны увидеть две дополнительные папки с именами kafkastrimziio
и kafkatopic_kafkastrimziio
.
Снова пришло время для кода на Go
Создайте файл kafka_strimzi.go
и скопируйте код из репозитория Github:
Или вы также можете просто сделать следующее:
curl -o kafka.go https://raw.githubusercontent.com/abhirockzz/cdk8s-for-go-developers/master/part3-crd/kafka_strimzi.go
.
Здесь я проведу вас через важные части кода. Начните с функции NewKafkaChart
, которая создает новую Chart
.
func NewKafkaChart(scope constructs.Construct, id string, props *KafkaChartProps) cdk8s.Chart {
//.... ommitted for brevity
chart := cdk8s.NewChart(scope, jsii.String(id), &cprops)
Посмотрите, как определяется кластер Kafka с помощью структуры kafkastrimziio.KafkaProps
(для более детального изучения каждого из этих компонентов вы можете обратиться к документации Strimzi). Мы указываем версию Kafka, количество узлов/реплик (мы будем придерживаться одноузловой реплики), как раскрыть кластер и т.д.
//....
&kafkastrimziio.KafkaProps{
Spec: &kafkastrimziio.KafkaSpec{
Kafka: &kafkastrimziio.KafkaSpecKafka{
Version: jsii.String("3.2.0"),
Replicas: jsii.Number(1),
Listeners: &[]*kafkastrimziio.KafkaSpecKafkaListeners{
{
Name: jsii.String("plain"),
Port: jsii.Number(9092),
Type: kafkastrimziio.KafkaSpecKafkaListenersType_INTERNAL,
Tls: jsii.Bool(false),
},
},
//....
Затем мы добавляем необходимые настройки для кластера Kafka (в соответствии с тем, что у нас только одноузловой кластер), а также хранилища (для данного примера подойдет эфемерное хранилище).
//...
Config: map[string]interface{}{
"offsets.topic.replication.factor": 1,
"transaction.state.log.replication.factor": 1,
"transaction.state.log.min.isr": 1,
"default.replication.factor": 1,
"min.insync.replicas": 1,
"inter.broker.protocol.version": "3.2",
},
Storage: &kafkastrimziio.KafkaSpecKafkaStorage{
Type: kafkastrimziio.KafkaSpecKafkaStorageType_EPHEMERAL,
},
//...
Наконец, мы настраиваем Zookeeper, а также оператор Entity, который обрабатывает темы Kafka (а также пользователей, хотя здесь мы его не используем).
//...
Zookeeper: &kafkastrimziio.KafkaSpecZookeeper{
Replicas: jsii.Number(1),
Storage: &kafkastrimziio.KafkaSpecZookeeperStorage{
Type: kafkastrimziio.KafkaSpecZookeeperStorageType_EPHEMERAL,
},
},
EntityOperator: &kafkastrimziio.KafkaSpecEntityOperator{
TopicOperator: &kafkastrimziio.KafkaSpecEntityOperatorTopicOperator{},
}}})
//...
Чтобы подключить его, обновите файл main.go
:
func main() {
app := cdk8s.NewApp(nil)
//NewFooChart(app, "FooApp", nil)
NewKafkaChart(app, "KafkaApp", nil)
app.Synth()
}
Чтобы создать кластер Kafka с помощью CRD…
Следуйте обычному рабочему процессу:
# generate manifest (check it in dist folder)
cdk8s synth
# apply it (note the kafka namespace)
kubectl apply -f dist/ -n kafka
Подождите, пока будут созданы ресурсы:
KAFKA_CRD_INSTANCE_NAME=$(kubectl get kafka -n kafka -o=jsonpath='{.items[0].metadata.name}')
kubectl wait kafka/$KAFKA_CRD_INSTANCE_NAME --for=condition=Ready --timeout=300s -n kafka
Когда все ресурсы кластера Kafka будут созданы, вы должны увидеть следующее сообщение — kafka.kafka.strimzi.io/<name of your Kafka CRD instance> condition met
. Кластер Kafka теперь готов, и мы можем протестировать его, используя старый добрый производитель и потребитель Kafka на основе CLI (инструкции в Strimzi quickstart).
BOOSTRAP_SERVER=$(kubectl get kafka -n kafka -o=jsonpath='{.items[0].metadata.name}')-kafka-bootstrap
kubectl -n kafka run kafka-producer -ti --image=quay.io/strimzi/kafka:0.29.0-kafka-3.2.0 --rm=true --restart=Never -- bin/kafka-console-producer.sh --bootstrap-server $BOOSTRAP_SERVER:9092 --topic test-topic
kubectl -n kafka run kafka-consumer -ti --image=quay.io/strimzi/kafka:0.29.0-kafka-3.2.0 --rm=true --restart=Never -- bin/kafka-console-consumer.sh --bootstrap-server $BOOSTRAP_SERVER:9092 --topic test-topic --from-beginning
Вот и все на сегодня!
Пора закругляться…
Вы узнали, как объединить Kubernetes Custom Resource definition с cdk8s
. Это действительно мощный инструмент и означает, что вы можете продолжать использовать код (в данном случае написанный на Go) для определения встроенных ресурсов Kubernetes (таких как Deployment
s и т.д.), а также пользовательских ресурсов!
Вам понравилось то, что вы попробовали?
Что ж, вы можете продолжить обучение! Пара предложений:
- Вы можете попробовать обновить существующий код, чтобы добавить ресурс
Deployment
, который ссылается на клиентское приложение Kafka (сначала вы должны написать его и упаковать как контейнер Docker) и может получить доступ к созданному вами кластеру Kafka. Изучите, как можно получить параметры подключения… - Созданный нами кластер Kafka был настроен только на внутренний доступ. Изучите варианты его внешнего доступа (см. документацию Strimzi) и обновите код, чтобы реализовать это (это должно быть небольшое изменение). Какие объекты Kubernetes будут затронуты этим?
Счастливого кодирования!