Пробуем новый ЯП Pkl для создание манифестов Kubernetes
Не так давно Apple выпустили раннюю версию своего нового языка программирования специального назначения – Pkl, предназначенного для написания конфигураций. Несмотря на то, что этот язык, по сути, только родился, он уже способен на некоторые интересные вещи. В этой статье опробуем Pkl путём написания YAML манифестов для Kubernetes.
Что такое Pkl?
Pkl (читается, как Pickle) – это, как я уже выше написал, ЯП специального назначения для создания конфигураций. Синтаксис напоминает HCL и Nginx, только с кучей вспомогательных функций.
Pkl поддерживает валидацию полей через проставленые типов, проверки
типа if
, циклы, функции, наследование и GET http запросы.
Всё это в настолько примитивном виде, на сколько это возможно.
Перевести код на Pkl вы можете в JSON, YAML, XML и другие форматы. Он также может генерировать код на Go, Java, Kotlin и Swift, но в статьей это рассматривать не будем.
Пример
name = "Swallow"
job {
title = "Sr. Nest Maker"
company = "Nests R Us"
yearsOfExperience = 2
}
{
"name": "Swallow",
"job": {
"title": "Sr. Nest Maker",
"company": "Nests R Us",
"yearsOfExperience": 2
}
}
Манифесты Kubernetes на Pkl
Для примера я взял манифесты своего pet-проекта, которые
включают в себя Deployment
, Service
и Ingress
ресурсы, и всё переписал на Pkl.
Deployment манифест
apiVersion: apps/v1
kind: Deployment
metadata:
name: davy-page-blog
namespace: davy
spec:
selector:
matchLabels:
app: davy-page-blog
template:
metadata:
labels:
app: davy-page-blog
spec:
containers:
- name: davy-page
image: image:v0.0.81
imagePullPolicy: IfNotPresent
resources:
...
readinessProbe:
...
livenessProbe:
...
imagePullSecrets:
- name: vault-registry-secret
Service манифест
apiVersion: v1
kind: Service
metadata:
name: davy-page-blog
namespace: davy
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
name: http
selector:
app: davy-page-blog
Ingress манифест
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: davy-page-blog
namespace: davy
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- davy.page
secretName: davy-tls
rules:
- host: davy.page
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: davy-page-blog
port:
number: 80
Основная задача заключалась в том, чтобы взять за основу текущие манифесты, которые
у меня использовались для поднятия одного стенда, и создать конфигурацию на Pkl, с помощью которой,
я смогу легко генерировать манифесты для трех разных окружений: prod-type-1
, prod-type-2
и beta-(0..999)
.
Для валидации конфигов уже есть готовый модуль pkl-k8s. Он содержит в себе типизированные объекты для ресурсов Kubernetes. Если вы будете добавлять в будущий k8s ресурс поля, которых там не должно быть, или будете корректным полям выставлять некорректные значения, то при сборке конфига получите ошибку.
По итогу у меня получился вот такой главный файл, который создаёт необходимые манифесты для стендов любого типа:
import "@k8s/K8sResource.pkl"
import "./DavyPageStand.pkl"
stand = new DavyPageStand.Stand {
args = new {
// Все аргументы, которые нужны берутся из ENV переменных.
// Если их вдруг нет, то выставится либо дефолтное значение, либо null.
type = read?("env:TYPE") ?? "blog"
version = read?("env:VERSION") ?? "v0.0.81"
id = read?("env:ID")
}
}
output {
value = new Listing<K8sResource> {
stand.deployment
stand.service
stand.ingress
}
renderer = (K8sResource.output.renderer as YamlRenderer) {
isStream = true
}
}
Для гибкости, если вдруг нужно подредактировать, в полученных объектах, конкретные поля, можно сделать та к (в моём понимаение это костыль, и так смысл есть делать, только если нужно прям супер срочно что-то починить и нет желания смотреть другие Pkl файлы):
...
value = new Listing<K8sResource> {
(stand.deployment) {
metadata {
name = "test"
}
spec {
template {
spec {
containers {
// меняем образ только у контейнера с таким именем
[[name == "davy-page"]] {
image = "bruh"
}
}
}
}
}
}
stand.service
stand.ingress
}
...