Packaging & Config

Tanka

Outil GitOps CLI Jsonnet pour Kubernetes par Grafana Labs - environments, imports jb, diff et apply, génère du YAML standard depuis Jsonnet. Apache 2.0.

Tanka est un outil CLI de configuration Kubernetes développé par Grafana Labs, basé sur Jsonnet. Il organise les manifests Kubernetes en environments (un dossier par environnement cible), chacun défini par un main.jsonnet et un fichier spec.json (URL du cluster). Tanka utilise jb (jsonnet-bundler) comme gestionnaire de paquets Jsonnet. L'approche diffère de Helm (pas de templates Go) et de Kustomize (pas de YAML brut) : Jsonnet est un langage de configuration à part entière, turing-complet, avec imports, fonctions, mixins et bibliothèques réutilisables. Grafana Labs l'utilise en production pour tous ses déploiements.


Informations essentielles

Origine : Grafana Labs  ·  Licence : Apache 2.0  ·  Architectures : x86_64, ARM64

Liens : Site officiel  ·  Documentation  ·  GitHub  ·  Releases

Support : Maintenu par Grafana Labs. Utilisé en production chez Grafana.

Stack par défaut

ComposantValeur
LangageJsonnet
Package managerjb (jsonnet-bundler)
Structureenvironments/<env>/main.jsonnet + spec.json
Bibliothèquesk8s-libsonnet (bindings K8s), kube-libsonnet, bibliothèques communautaires
Commandestk apply, tk diff, tk show, tk export

Prérequis

RessourceValeur
kubectlConfiguré avec accès cluster
jbjsonnet-bundler (gestionnaire de paquets Jsonnet)

Installation

# tk CLI - binaire Linux
TK_VERSION=$(curl -s "https://api.github.com/repos/grafana/tanka/releases/latest" \
  | grep '"tag_name"' | sed 's/.*"v\([^"]*\)".*/\1/')
curl -Lo tk "https://github.com/grafana/tanka/releases/download/v${TK_VERSION}/tk-linux-amd64"
chmod +x tk && sudo mv tk /usr/local/bin/

# Homebrew
brew install tanka

# jsonnet-bundler (gestionnaire de paquets)
go install github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb@latest

tk --version

Initialiser un projet

mkdir my-k8s-config && cd my-k8s-config

# Initialiser le projet Tanka
tk init

# Structure créée :
# ├── environments/
# │   └── default/
# │       ├── main.jsonnet    # Point d'entrée
# │       └── spec.json       # URL du cluster
# ├── lib/                    # Bibliothèques locales
# ├── vendor/                 # Bibliothèques importées via jb
# └── jsonnetfile.json        # Dépendances (comme package.json)

# Installer les bindings K8s (k8s-libsonnet)
jb install github.com/jsonnet-libs/k8s-libsonnet/1.29@main

Configurer un environment

// environments/production/spec.json
{
  "apiVersion": "tanka.dev/v1alpha1",
  "kind": "Environment",
  "metadata": {
    "name": "production"
  },
  "spec": {
    "apiServer": "https://my-cluster.example.com",
    "namespace": "production",
    "resourceDefaults": {},
    "expectVersions": {}
  }
}

Écrire des manifests en Jsonnet

// environments/production/main.jsonnet
local k = import 'github.com/jsonnet-libs/k8s-libsonnet/1.29/main.libsonnet';

local deployment = k.apps.v1.deployment;
local container = k.core.v1.container;
local containerPort = k.core.v1.containerPort;
local service = k.core.v1.service;

// Définir un Deployment
local myApp = deployment.new(
  name='my-app',
  replicas=3,
  containers=[
    container.new('my-app', 'ghcr.io/org/my-app:1.0.0')
    + container.withPorts([containerPort.newNamed(8080, 'http')])
    + container.resources.withRequests({ cpu: '250m', memory: '256Mi' })
    + container.resources.withLimits({ cpu: '500m', memory: '512Mi' }),
  ]
);

// Définir un Service
local myService = service.new(
  'my-app',
  { app: 'my-app' },
  [{ port: 80, targetPort: 8080 }]
);

// Exporter les ressources (Tanka les applique toutes)
{
  deployment: myApp,
  service: myService,
}

Bibliothèques réutilisables

// lib/webapp.libsonnet - construct réutilisable
local k = import 'github.com/jsonnet-libs/k8s-libsonnet/1.29/main.libsonnet';

{
  new(name, image, replicas=2):: {
    local deployment = k.apps.v1.deployment,
    local container = k.core.v1.container,

    deployment: deployment.new(name, replicas, [
      container.new(name, image)
      + container.withPorts([{ containerPort: 8080 }])
    ]),

    service: k.core.v1.service.new(
      name, { app: name }, [{ port: 80, targetPort: 8080 }]
    ),
  },
}
// environments/production/main.jsonnet
local webapp = import '../../lib/webapp.libsonnet';

{
  frontend: webapp.new('frontend', 'ghcr.io/org/frontend:1.0', replicas=3),
  backend:  webapp.new('backend',  'ghcr.io/org/backend:2.0',  replicas=5),
}

Commandes principales

# Prévisualiser les manifests générés (YAML)
tk show environments/production

# Diff entre l'état Git et le cluster
tk diff environments/production

# Appliquer sur le cluster
tk apply environments/production

# Exporter le YAML dans un dossier (pour GitOps pull-based)
tk export dist/ environments/production

# Lister les environments
tk env list

Mise à jour

# Binaire
curl -Lo tk "https://github.com/grafana/tanka/releases/latest/download/tk-linux-amd64"
chmod +x tk && sudo mv tk /usr/local/bin/

# Homebrew
brew upgrade tanka

Troubleshooting

# Erreur de syntaxe Jsonnet
tk show environments/production 2>&1
# Le message d'erreur indique le fichier et la ligne

# Vérifier les imports disponibles
ls vendor/

# Mettre à jour les dépendances jb
jb update

# Diff vide mais apply échoue
# Vérifier les droits RBAC kubectl

# Déboguer la valeur d'une variable Jsonnet
tk eval environments/production -e 'std.extVar("tanka.dev/environment")'

Ressources

Newsletter · 2 000+ abonnés

Reste au courant de ce qui bouge en prod

RudeOps veille devops hebdo, droit au but.

Gratuit · Sans spam · Désinscription en un clic