Skip to main content

Install the operator

Goal: install the AgentFlowEngine operator and bring up an engine from one custom resource.

Prerequisites​

  • A cluster you can kubectl apply to, with a kubeconfig.
  • The afe image loaded or pushed where the cluster can pull it.
  • kubectl on your machine.

The operator is namespace-scoped and reference-first. It creates and owns the stateless objects: the serve and worker Deployments, the Services, the config ConfigMap, the Ingress and the ScaledObject. The namespaces, the worker's RBAC, the envSecret, the data Secrets and the storage, runtime and ingress classes are your manifests. They ship as examples under deploy/operator/admin/.

Steps​

  1. Apply your admin manifests:

    kubectl apply -f deploy/operator/admin/namespace.yaml
    kubectl apply -f deploy/operator/admin/rbac.yaml
    kubectl apply -f deploy/operator/admin/env-secret.yaml
    kubectl apply -f deploy/operator/admin/data-secrets.yaml
    kubectl apply -f deploy/operator/admin/classes.yaml

    Fill the Secrets first. The repository commits empty values, never a credential. Keep the classes your cluster already provides.

  2. Install the operator, its CRDs and its RBAC:

    make operator-install # kubectl apply -k deploy/operator
    kubectl -n afe rollout status deployment/afe-operator
  3. Create the source ConfigMap from your flow folder. A prompt must be inline text or a file in the same ConfigMap, because a ConfigMap has no folders:

    kubectl -n afe create configmap afe-source --from-file=config/
  4. Write the AgentFlowEngine and apply it. Every secret is a reference, never a value:

    apiVersion: afe.dev/v1alpha1
    kind: AgentFlowEngine
    metadata:
    name: afe
    namespace: afe
    spec:
    config:
    configMapRef:
    name: afe-source
    afe:
    store:
    external:
    secretRef:
    name: afe-postgres
    key: dsn
    broker:
    external:
    secretRef:
    name: afe-redis
    key: AFE_REDIS_URL
    sandbox:
    namespace: afe-sandbox
    envSecret: afe-sandbox-env
    deployment:
    image:
    repository: ghcr.io/agentflowengine/afe
    tag: "0.7.0"
    api:
    replicas: 2
    apiTokenSecretRef:
    name: afe-secrets
    key: AFE_API_TOKEN
    workers:
    replicas: 2
    concurrency: 4
    # The model key and the Git token both stay worker-only; serve never holds a credential.
    envSecretRefs:
    - { name: afe-secrets, key: OPENROUTER_API_KEY }
    - { name: afe-secrets, key: GITHUB_TOKEN }
  5. Watch the installation become ready:

    kubectl -n afe get agentflowengine afe -o wide
    kubectl -n afe get pods
    kubectl -n afe get agentflowengine afe \
    -o jsonpath='{.status.conditions[*].type}{"\n"}'

    The Ready condition is the AND of the required ones. status.revision is the configuration revision the workloads run.

  6. Reach the API. Without an Ingress, forward the Service:

    kubectl -n afe port-forward svc/afe-api 8765:8765
    export AFE_API_TOKEN=$(kubectl -n afe get secret afe-secrets \
    -o jsonpath='{.data.AFE_API_TOKEN}' | base64 -d)
    afe tickets

Troubleshooting​

ConfigValidated=False The operator could not validate the folder it built from the ConfigMap and the generated Runtime. The condition message carries the same per-field messages afe validate prints. Fix the manifests in the ConfigMap and re-apply, or update the CR if the error is in spec.afe.

RevisionPinned=False, reason RevisionMismatch spec.config.revision does not match the computed revision. The operator names both hashes and publishes nothing, so the running workloads stay as they are. Set the pin to the computed revision, or remove it.

Ready=False, reason ResourceConflict An object with a desired name exists without the operator's ownerReference. The operator adopts nothing. Delete the foreign object, or rename it, then let the next reconcile run.

StoreReady=False, reason CloudNativePGMissing The CR asks for a managed store but the postgresql.cnpg.io CRD is not installed. Install CloudNativePG, or switch spec.afe.store to external.

The worker Pod crash-loops with invalid configuration: model '…': set … The worker resolves the model providers, so it needs every model key. Name the key in deployment.workers.envSecretRefs: the operator projects it into the workers only. serve runs no harness and calls no provider, so no credential reaches it, neither the model keys nor the Git token.

See also​