---
title: "Premiers pas avec Kodama sur Kubernetes"
description: "Installer PostgreSQL et NATS avec Helm, déployer Kodama, authentifier le CLI par OAuth, puis enregistrer et exécuter un premier pipeline."
canonical_url: https://optimi.com/fr/docs/kodama/premiers-pas
md_url: https://optimi.com/fr/docs/kodama/premiers-pas.md
last_updated: 2026-10-23
---

# Premiers pas

Ce guide conduit d’un cluster Kubernetes à un pipeline terminé :
**préparer les prérequis → installer les charts des backends → installer Kodama
→ authentifier le CLI → enregistrer et lancer un pipeline**. Les commandes
utilisent une installation autonome, un tenant (`t_acme`) et un projet.
Remplacez domaines, identifiants, identités cloud et plages réseau par vos valeurs.

## 1. Prérequis

| Exigence | À préparer avant l’installation |
| --- | --- |
| Kubernetes | Kubernetes 1.29+ compatible avec les charts choisis, StorageClass persistante par défaut, CNI appliquant NetworkPolicy et droits d’installation des CRD, namespaces et RBAC |
| Poste de travail | Helm, `kubectl`, `curl`, `jq`, OpenSSL et Go 1.27.2 ou une version compatible pour installer le CLI |
| Ingress HTTPS | Contrôleur ingress, `kodama.example.com`, certificat TLS et origine de rappel HTTPS accessible aux charges |
| Stockage objets | Bucket compatible S3, endpoint, région et clés d’accès limitées au périmètre |
| Git | Dépôt HTTPS avec un commit initial sur `main` et jetons distincts de lecture et de publication |
| Registre | Accès à `ghcr.io/optimiware/kodama` et aux images de travail figées par empreinte |
| OIDC | Issuer émettant des jetons d’accès JWT pour l’audience de l’usine, client OAuth public et administrateur initial désigné |
| Gestion des clés | Un KMS d’installation : AWS KMS, GCP Cloud KMS ou Scaleway Key Manager ; identité serveur autorisée à utiliser la clé d’enveloppe |
| TLS des backends | Certificat de confiance pour NATS et autorités nécessaires à la validation de PostgreSQL et des rappels runtime |

Enregistrez le client OAuth `kodama-cli`, activez **Authorization Code + S256
PKCE** et autorisez exactement `http://127.0.0.1:18999/callback` comme URL de
retour. Cet exemple utilise l’audience `https://kodama.example.com/api`.
Notez les URL de découverte, d’autorisation et de jeton de l’issuer. Un ID token
n’est pas un jeton d’accès API.

Choisissez une version de Kodama sur [GitHub](https://github.com/optimiware/kodama/tags)
et relevez son empreinte d’image dans [GHCR](https://github.com/optimiware/kodama/pkgs/container/kodama).
Utilisez la même version pour le chart, l’image serveur et le CLI :

```sh
export KODAMA_REF=0.0.1
export KODAMA_DIGEST='sha256:remplacer-par-empreinte-image-publiee'
export FACTORY=https://kodama.example.com
export TENANT_ID=t_acme

kubectl create namespace kodama-backends
kubectl create namespace kodama-system
umask 077
mkdir -p credentials runtime-secrets migration-secrets
```

`0.0.1` est un exemple : utilisez le tag choisi et sa véritable empreinte.
Conservez les identifiants générés hors du contrôle de version.

## 2. Installer les charts Helm des backends

Ce parcours utilise les charts officiels **CloudNativePG** pour PostgreSQL et
**NATS** pour JetStream. S3, Git, registre, OIDC et KMS utilisent les services
préparés précédemment.

```sh
helm repo add cnpg https://cloudnative-pg.github.io/charts
helm repo add nats https://nats-io.github.io/k8s/helm/charts/
helm repo update
helm search repo cnpg/cloudnative-pg --versions
helm search repo cnpg/cluster --versions
helm search repo nats/nats --versions
```

Figez les versions des charts. Les exemples utilisent les versions suivantes ;
vérifiez leur compatibilité avec le cluster et conservez ces références avec
les valeurs d’installation :

```sh
export CNPG_OPERATOR_VERSION=0.29.1
export CNPG_CLUSTER_VERSION=0.9.0
export NATS_CHART_VERSION=2.15.1
```

### PostgreSQL

Installez l’opérateur, puis créez des secrets de connexion distincts pour
migration et runtime :

```sh
helm upgrade --install cnpg cnpg/cloudnative-pg \
  --namespace cnpg-system --create-namespace \
  --version "$CNPG_OPERATOR_VERSION" --wait --timeout 10m

printf %s "$(openssl rand -hex 32)" > credentials/db-migration-password
printf %s "$(openssl rand -hex 32)" > credentials/db-runtime-password
kubectl -n kodama-backends create secret generic kodama-db-migration \
  --type=kubernetes.io/basic-auth --from-literal=username=kodama_migration \
  --from-file=password=credentials/db-migration-password
kubectl -n kodama-backends create secret generic kodama-db-runtime \
  --type=kubernetes.io/basic-auth --from-literal=username=kodama_runtime \
  --from-file=password=credentials/db-runtime-password
```

Enregistrez `postgres-values.yaml` :

```yaml
fullnameOverride: kodama-postgres
type: postgresql
version:
  postgresql: "17"
cluster:
  instances: 3
  enableSuperuserAccess: false
  storage:
    size: 20Gi
  initdb:
    database: kodama
    owner: kodama_migration
    secret:
      name: kodama-db-migration
  roles:
    - name: kodama_runtime
      ensure: present
      login: true
      superuser: false
      bypassrls: false
      passwordSecret:
        name: kodama-db-runtime
```

```sh
helm upgrade --install kodama-postgres cnpg/cluster \
  --namespace kodama-backends --version "$CNPG_CLUSTER_VERSION" \
  -f postgres-values.yaml --wait --timeout 10m
kubectl -n kodama-backends wait cluster/kodama-postgres \
  --for=condition=Ready --timeout=600s
```

L’endpoint d’écriture est
`kodama-postgres-rw.kodama-backends.svc.cluster.local:5432`. L’utilisateur de
migration possède la base ; le rôle runtime doit rester non propriétaire,
sans privilèges superutilisateur ni contournement de RLS. Le hook de migration
Kodama lui attribue les permissions applicatives.

### NATS JetStream

Créez un jeton partagé et le Secret TLS avec le certificat émis. Son nom DNS
doit résoudre vers le service NATS depuis les Pods serveur Kodama ; cet exemple
utilise `nats.internal.example.com` et un certificat reconnu par le magasin
de confiance de l’image serveur.

```sh
printf %s "$(openssl rand -hex 32)" > runtime-secrets/nats-token
kubectl -n kodama-backends create secret generic kodama-nats-auth \
  --from-file=token=runtime-secrets/nats-token
kubectl -n kodama-backends create secret tls kodama-nats-tls \
  --cert=credentials/nats-tls.crt --key=credentials/nats-tls.key
```

Enregistrez `nats-values.yaml` :

```yaml
fullnameOverride: kodama-nats
config:
  jetstream:
    enabled: true
    fileStore:
      pvc:
        enabled: true
        size: 20Gi
  nats:
    tls:
      enabled: true
      secretName: kodama-nats-tls
  merge:
    authorization:
      token: << $NATS_TOKEN >>
container:
  env:
    NATS_TOKEN:
      valueFrom:
        secretKeyRef:
          name: kodama-nats-auth
          key: token
natsBox:
  enabled: false
```

```sh
helm upgrade --install kodama-nats nats/nats \
  --namespace kodama-backends --version "$NATS_CHART_VERSION" \
  -f nats-values.yaml --wait --timeout 10m
kubectl -n kodama-backends get service kodama-nats
kubectl -n kodama-backends get pods,pvc
```

Faites pointer `nats.internal.example.com` vers le service avec le DNS privé
du cluster. Cet exemple utilise un serveur NATS persistant. Configurez
réplication et sauvegardes selon vos objectifs de disponibilité ; la persistance
seule ne constitue pas de la haute disponibilité.

## 3. Installer le chart Helm Kodama

Téléchargez le chart avec l’archive de la version correspondante :

```sh
curl --fail --location \
  "https://github.com/optimiware/kodama/archive/refs/tags/${KODAMA_REF}.tar.gz" \
  --output kodama-release.tar.gz
tar -xzf kodama-release.tar.gz
export KODAMA_CHART="$PWD/kodama-${KODAMA_REF}/deploy/helm/kodama"
```

### Préparer les Secrets d’installation

Générez les clés aléatoires brutes et la clé de signature runtime :

```sh
openssl rand -out runtime-secrets/cursor-key 32
openssl rand -out runtime-secrets/idempotency-hash-key 32
openssl ecparam -name prime256v1 -genkey -noout \
  -out runtime-secrets/runtime-signing-key
```

Placez les fichiers suivants dans les répertoires indiqués. Les mots de passe
des URL PostgreSQL doivent être encodés pour une URL ; les valeurs hexadécimales
générées ci-dessus n’exigent aucun échappement.

| Répertoire/fichier | Valeur |
| --- | --- |
| `migration-secrets/database-migration-url` | `postgresql://kodama_migration:PASSWORD@kodama-postgres-rw.kodama-backends.svc.cluster.local:5432/kodama?sslmode=verify-full&sslrootcert=/secrets/ca.crt` |
| `runtime-secrets/database-runtime-url` | Même endpoint, avec `kodama_runtime` et son propre mot de passe |
| Dans les deux répertoires : `ca.crt` | Bundle contenant l’autorité PostgreSQL et les racines nécessaires à Git |
| `runtime-secrets/runtime-ca.crt` | Bundle d’autorités de l’origine de rappel HTTPS |
| `runtime-secrets/s3-access-key`, `s3-secret-key` | Identifiants limités au bucket des artefacts |
| `runtime-secrets/git-read-token`, `git-write-token` | Identifiants de lecture du dépôt et de publication |

CloudNativePG expose son autorité PostgreSQL générée dans le Secret
`kodama-postgres-ca`, clé `ca.crt`. Incluez ce certificat dans le bundle de
l’installation en conservant les racines publiques/privées nécessaires aux
autres connexions.

Enregistrez `runtime-secrets/git-credentials.json` avec l’URL du dépôt :

```json
[
  {
    "ref": "secret://installation/repository-read",
    "username": "git",
    "passwordFile": "git-read-token",
    "urlPrefix": "https://git.example.com/acme/application.git",
    "tenants": ["t_acme"]
  },
  {
    "ref": "secret://installation/repository-write",
    "username": "git",
    "passwordFile": "git-write-token",
    "urlPrefix": "https://git.example.com/acme/application.git",
    "tenants": ["t_acme"]
  }
]
```

Créez les Secrets dans le namespace de la release, ainsi que le certificat ingress :

```sh
kubectl -n kodama-system create secret generic kodama-runtime \
  --from-file=runtime-secrets/
kubectl -n kodama-system create secret generic kodama-migration \
  --from-file=migration-secrets/
kubectl -n kodama-system create secret tls kodama-tls \
  --cert=credentials/kodama-tls.crt --key=credentials/kodama-tls.key
```

### Définir les valeurs d’installation

Enregistrez `kodama-values.yaml`. Cet exemple sélectionne AWS KMS et un rôle
IAM serveur ; utilisez le bloc fournisseur et l’identité équivalents de votre
cloud. Remplacez domaines, bucket, identifiants de rôle/clé et CIDR. Configurez
CNI et adressage pour rendre ces destinations exactes accessibles aux charges.

```yaml
profile: external
authority:
  mode: standalone
installation:
  id: acme-factory
image:
  repository: ghcr.io/optimiware/kodama
secrets:
  runtime: {existingSecret: kodama-runtime}
  migration: {existingSecret: kodama-migration}
migration:
  runtimeRole: kodama_runtime
serviceAccounts:
  server:
    annotations:
      eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/kodama-server
kms:
  provider: aws
  aws:
    keyId: alias/kodama
    region: eu-west-1
ingress:
  enabled: true
  className: nginx
  host: kodama.example.com
  tls: {enabled: true, secretName: kodama-tls}
config:
  nats:
    url: tls://nats.internal.example.com:4222
  s3:
    endpoint: https://s3.eu-west-1.amazonaws.com
    region: eu-west-1
    bucket: acme-kodama-artifacts
    prefix: kodama/
    pathStyle: false
    credentials: static
  git:
    url: https://git.example.com/acme/application.git
  registry:
    url: https://ghcr.io
  oidc:
    issuer: https://identity.example.com
    audience: https://kodama.example.com/api
    cliClientId: kodama-cli
    redirectUri: http://127.0.0.1:18999/callback
  tls:
    customCA: true
execution:
  tenants:
    - namespace: kodama-tenant-acme
      tenantId: t_acme
  rbac:
    manageSecrets: true
  runtime:
    url: https://kodama.example.com
    signingGeneration: 1
    egress:
      - name: runtime-callback
        cidr: 192.0.2.10/32
        ports: [{port: 443}]
  network:
    egress:
      - name: git
        cidr: 203.0.113.10/32
        ports: [{port: 443}]
      - name: object-storage
        cidr: 198.51.100.0/24
        ports: [{port: 443}]
      - name: registry
        cidr: 203.0.113.20/32
        ports: [{port: 443}]
```

Les CIDR sont fictifs, pas des plages IP de fournisseurs. Les charges tenants
ne doivent pas joindre PostgreSQL ou NATS. L’accès serveur aux backends est
distinct de la politique de sortie des charges.

```sh
helm lint --strict "$KODAMA_CHART" -f kodama-values.yaml \
  --set-string image.tag="$KODAMA_REF" \
  --set-string image.digest="$KODAMA_DIGEST"
helm upgrade --install kodama "$KODAMA_CHART" \
  --namespace kodama-system -f kodama-values.yaml \
  --set-string image.tag="$KODAMA_REF" \
  --set-string image.digest="$KODAMA_DIGEST" \
  --wait --timeout 10m

kubectl -n kodama-system rollout status deployment/kodama --timeout=300s
curl --fail "$FACTORY/readyz"
```

Le hook de migration précède le serveur. Attendez la réussite de readiness
avant de continuer. Sinon, examinez
`kubectl -n kodama-system logs deployment/kodama` et le Job de migration ;
vérifiez que la release prend en charge le KMS et la configuration choisis.
Consultez [l’exploitation](/fr/docs/kodama/exploitation) pour le diagnostic.

## 4. Installer le CLI et s’authentifier avec OAuth

Installez le CLI depuis la même archive de version publiée :

```sh
mkdir -p "$HOME/.local/bin"
GOBIN="$HOME/.local/bin" go -C "$PWD/kodama-${KODAMA_REF}" install ./cmd/kodama
export PATH="$HOME/.local/bin:$PATH"
kodama --help
```

Configurez l’origine et les endpoints du document de découverte OIDC :

```sh
kodama context set --context acme --select \
  --factory "$FACTORY" --tenant "$TENANT_ID" \
  --issuer https://identity.example.com \
  --authorization-endpoint https://identity.example.com/authorize \
  --token-endpoint https://identity.example.com/token \
  --client-id kodama-cli --scopes openid,kodama \
  --redirect-uri http://127.0.0.1:18999/callback
kodama auth login
kodama context show
```

Le navigateur ouvre votre fournisseur d’identité. Après connexion, le code
d’autorisation revient au callback local et le CLI l’échange avec son vérificateur
PKCE. Les identifiants utilisent le trousseau du système. `--credential-store file`
sélectionne explicitement des fichiers protégés de mode `0600`. Choisissez les
scopes émettant un jeton pour l’audience de l’usine ; `openid,kodama` est illustratif.

### Créer le premier projet

Initialisez une fois le tenant et son administrateur avec la
**[procédure de bootstrap](/fr/docs/kodama/exploitation#initialiser-le-premier-tenant)**.
Utilisez `t_acme`, comme dans le namespace d’exécution, et le sujet OIDC vérifié
de l’administrateur désigné. Conservez son `TOKEN` de courte durée pour le
paramétrage initial, puis terminez le nettoyage des identifiants temporaires.

En tant qu’administrateur initial, utilisez dans `TOKEN` un jeton d’accès API
issu du flux OAuth du fournisseur. La procédure de bootstrap explique cette
configuration ponctuelle. Enregistrez `project.json` :

```json
{
  "key": "application",
  "displayName": "Application",
  "activeWipLimit": 5,
  "settings": {
    "repository": {
      "id": "repo_application",
      "url": "https://git.example.com/acme/application.git",
      "baseRef": "refs/heads/main",
      "checkoutSecretRef": "secret://installation/repository-read",
      "publisherSecretRef": "secret://installation/repository-write"
    }
  }
}
```

```sh
curl --fail-with-body -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' --data-binary @project.json \
  "$FACTORY/api/v1/tenants/$TENANT_ID/projects" > project-result.json
export PROJECT_ID="$(jq -r .id project-result.json)"
export USER_ID="$(curl --fail -H "Authorization: Bearer $TOKEN" \
  "$FACTORY/api/v1/me" | jq -r .id)"

jq -n --arg user "$USER_ID" --arg project "$PROJECT_ID" \
  '{userId:$user, projectId:$project, role:"engineer"}' > engineer-binding.json
curl --fail-with-body -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' --data-binary @engineer-binding.json \
  "$FACTORY/api/v1/tenants/$TENANT_ID/memberships"
kodama context use --context acme --project "$PROJECT_ID"
```

Ce tutoriel ajoute le rôle ingénieur à l’administrateur pour le premier essai.
En équipe, attribuez-le plutôt à l’identifiant existant de l’ingénieur. Le rôle
administrateur ne confère pas à lui seul les permissions ingénieur ou reviewer.

## 5. Enregistrer et lancer le premier pipeline

Enregistrez `hello.yaml`. L’image Alpine figée n’exige ni source applicative,
ni fournisseur de modèles, ni identifiant de livraison ; elle produit un
petit rapport conservé.

```yaml
apiVersion: kodama/v1alpha1
kind: Pipeline
metadata:
  name: hello
spec:
  inputs:
    name: {type: string, default: monde}
  steps:
    - id: hello
      kind: container
      image: docker.io/library/alpine:3.22@sha256:5291449c3df73caf6ed85e649dec1b9e818b39a5d8c871e97afc13e9cd5e8fa8
      workspace: {access: none}
      command: ["/bin/sh", "-ec"]
      args: ['printf "Bonjour %s\n" "$NAME" > /kodama/outputs/report.txt']
      env:
        NAME: ${{ inputs.name }}
      timeoutSeconds: 60
      outputs:
        report: {type: artifact, path: /kodama/outputs/report.txt}
```

Créez `first-run.md` décrivant l’objectif et `acceptance.json` contenant
`[{"id":"AC-1","text":"Le rapport contient le nom fourni."}]`. Créez puis
activez l’élément de travail :

```sh
kodama work create --kind task --title "Premier pipeline" \
  --spec-file first-run.md --acceptance-file acceptance.json \
  --output json > work.json
export WORK_ID="$(jq -r .id work.json)"
kodama work transition "$WORK_ID" --to ready \
  --if-version "$(jq -r .version work.json)" --output json > ready.json
kodama work transition "$WORK_ID" --to active \
  --if-version "$(jq -r .version ready.json)"
kodama workspace provision --work "$WORK_ID" --output json > workspace.json
export WORKSPACE_ID="$(jq -r .id workspace.json)"
kodama workspace get "$WORKSPACE_ID" --output json
```

Même une étape sans source appartient à une exécution liée à un travail avec
une référence source figée. Attendez que l’espace soit `available`, puis capturez
son commit accepté et la révision de contenu courante :

```sh
kodama workspace get "$WORKSPACE_ID" --output json > workspace.json
export SOURCE_COMMIT="$(jq -r .acceptedCommit workspace.json)"
export CONTENT_REVISION="$(kodama work get "$WORK_ID" --output json | jq -r .contentRevision)"

kodama pipeline validate --file hello.yaml
kodama pipeline register --file hello.yaml --output json > definition.json
export DEFINITION_ID="$(jq -r .id definition.json)"
kodama run start --work "$WORK_ID" --definition "$DEFINITION_ID" \
  --content-revision "$CONTENT_REVISION" --source-commit "$SOURCE_COMMIT" \
  --input name=Acme --idempotency-key first-hello-001 \
  --output json > run.json
export RUN_ID="$(jq -r .id run.json)"
kodama run watch "$RUN_ID" --exit-on-terminal --timeout 5m
kodama run steps "$RUN_ID" --output json
kodama run logs "$RUN_ID" --step hello --tail 50
```

L’exécution doit atteindre `succeeded` et l’étape `hello` exposer un artefact
`report` contenant `Bonjour Acme`. C’est une sortie fichier, qui n’apparaît donc
pas nécessairement dans stdout. Utilisez l’identifiant retourné avec l’API des
artefacts pour obtenir ses métadonnées et informations de téléchargement.

Si la réponse de soumission se perd, répétez la commande identique avec la même
clé. Une entrée différente exige une nouvelle clé. Une exécution réussie laisse
la finalisation métier à une action humaine explicite.

Continuez avec les **[exemples CI/CD, agentiques, processus et signaux
métier](/fr/docs/kodama/guide-developpeur)**.
