# Flux Instance CRD

**FluxInstance** is a declarative API for the installation, configuration
and automatic upgrade of the Flux distribution.

A single custom resource of this kind can exist in a Kubernetes cluster
with the name `flux` that must be created in the same namespace
where the flux-operator is deployed.

## Example

The following example shows a FluxInstance custom resource that
installs the upstream Flux distribution with all available components,
and configures the flux-operator to automatically upgrade Flux 
to the latest stable version:

```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: FluxInstance
metadata:
  name: flux
  namespace: flux-system
  annotations:
    fluxcd.controlplane.io/reconcile: "enabled"
    fluxcd.controlplane.io/reconcileEvery: "1h"
    fluxcd.controlplane.io/reconcileTimeout: "5m"
spec:
  distribution:
    version: "2.x"
    registry: "ghcr.io/fluxcd"
  components:
    - source-controller
    - kustomize-controller
    - helm-controller
    - notification-controller
    - image-reflector-controller
    - image-automation-controller
  cluster:
    type: kubernetes
    size: medium
    multitenant: false
    networkPolicy: true
    domain: "cluster.local"
  storage:
    class: "standard"
    size: "10Gi"
  commonMetadata:
    labels:
      app.kubernetes.io/name: flux
  kustomize:
    patches:
      - target:
          kind: Deployment
        patch: |
          - op: replace
            path: /spec/template/spec/nodeSelector
            value:
              kubernetes.io/os: linux
          - op: add
            path: /spec/template/spec/tolerations
            value:
              - key: "CriticalAddonsOnly"
                operator: "Exists"
```

You can run this example by saving the manifest into `fluxinstance.yaml`.

**1.** Apply the resource on the cluster:

```shell
kubectl apply -f fluxinstance.yaml
```

**2.** Run `kubectl get fluxinstance` to see the status of the resource:

```console
$ kubectl -n flux-system get fluxinstance
NAME   AGE   READY   STATUS                           REVISION
flux   59s   True    Reconciliation finished in 52s   v2.3.0@sha256:4cc5babdb1279ad0177bf513292deadbfa3f7b7c3da0be7fa53b39ab434f7219
```

**3.** Run `kubectl describe fluxinstance` to see the reconciliation status components, conditions and events:

```console
$ kubectl -n flux-system describe fluxinstance flux
Status:
  Components:
    Digest:      sha256:161da425b16b64dda4b3cec2ba0f8d7442973aba29bb446db3b340626181a0bc
    Name:        source-controller
    Repository:  ghcr.io/fluxcd/source-controller
    Tag:         v1.3.0
    Digest:      sha256:48a032574dd45c39750ba0f1488e6f1ae36756a38f40976a6b7a588d83acefc1
    Name:        kustomize-controller
    Repository:  ghcr.io/fluxcd/kustomize-controller
    Tag:         v1.3.0
    Digest:      sha256:a67a037faa850220ff94d8090253732079589ad9ff10b6ddf294f3b7cd0f3424
    Name:        helm-controller
    Repository:  ghcr.io/fluxcd/helm-controller
    Tag:         v1.0.1
    Digest:      sha256:c0fab940c7e578ea519097d36c040238b0cc039ce366fdb753947428bbf0c3d6
    Name:        notification-controller
    Repository:  ghcr.io/fluxcd/notification-controller
    Tag:         v1.3.0
    Digest:      sha256:aed795c7a8b85bca93f6d199d5a14bbefaf925ad5aa5316b32a716cfa4070d0b
    Name:        image-reflector-controller
    Repository:  ghcr.io/fluxcd/image-reflector-controller
    Tag:         v0.32.0
    Digest:      sha256:ab5097213194f3cd9f0e68d8a937d94c4fc7e821f6544453211e94815b282aa2
    Name:        image-automation-controller
    Repository:  ghcr.io/fluxcd/image-automation-controller
    Tag:         v0.38.0
  Conditions:
    Last Transition Time:  2024-06-03T12:20:57Z
    Message:               Reconciliation finished in 52s
    Observed Generation:   1
    Reason:                ReconciliationSucceeded
    Status:                True
    Type:                  Ready
  Last Applied Revision:    v2.3.0@sha256:4cc5babdb1279ad0177bf513292deadbfa3f7b7c3da0be7fa53b39ab434f7219
  Last Attempted Revision:  v2.3.0@sha256:4cc5babdb1279ad0177bf513292deadbfa3f7b7c3da0be7fa53b39ab434f7219
Events:
  Type    Reason                   Age    From             Message
  ----    ------                   ----   ----             -------
  Normal  Progressing              6m20s  flux-controller  Installing revision v2.3.0@sha256:4cc5babdb1279ad0177bf513292deadbfa3f7b7c3da0be7fa53b39ab434f7219
  Normal  ReconciliationSucceeded  5m9s   flux-controller  Reconciliation finished in 52s
```

**4.** Run `kubectl logs` on the flux-operator pod to see the reconciliation logs:

```shell
kubectl -n flux-system logs deployment/flux-operator
```

**5.** Run `kubectl events` to see the events generated by the flux-operator:

```shell
kubectl -n flux-system events --for FluxInstance/flux
```

**6.** Run `kubectl delete` to remove the FluxInstance resource and
   to uninstall Flux without affecting any Flux-managed workloads:

```shell
kubectl -n flux-system delete FluxInstance/flux
```

## Writing a FluxInstance spec

As with all other Kubernetes config, a FluxInstance needs `apiVersion`,
`kind`, and `metadata` fields. The name of a FluxInstance object must be a
valid <a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/names#dns-subdomain-names" target="_blank" rel="noopener noreferrer">DNS subdomain name</a>.

A FluxInstance also needs a
<a href="https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status" target="_blank" rel="noopener noreferrer">`.spec` section</a>.

### Distribution configuration

The `.spec.distribution` field is required and specifies the Flux distribution to install.

Example using the upstream Flux distribution:

```yaml
spec:
  distribution:
    version: "2.x"
    registry: "ghcr.io/fluxcd"
```

#### Distribution version

The `.spec.distribution.version` field is required and specifies the version of the Flux distribution to install.
The version field value must be a valid <a href="https://semver.org/" target="_blank" rel="noopener noreferrer">semver</a> range or an exact version.

Example using a semver range to configure the automatic upgrade
to the latest Flux minor version:

```yaml
spec:
  distribution:
    version: "2.x"
```

Example using a semver range to configure the automatic upgrade
to the latest Flux patch version of the `2.3` series:

```yaml
spec:
  distribution:
    version: "2.3.x"
```

Example using an exact version to install a specific Flux version:

```yaml
spec:
  distribution:
    version: "2.3.0"
```

#### Distribution registry

The `.spec.distribution.registry` field is required and specifies the container registry
where the Flux distribution images are pulled from.

Example using the upstream Flux distribution registry:

```yaml
spec:
  distribution:
    version: "2.x"
    registry: "ghcr.io/fluxcd"
```

#### Distribution registry mirrors

The `.spec.distribution.variant` field is required, when specifying a third-party
registry where the Flux distribution images are pulled from. This is useful for registry
mirrors, for example in corporate environments.

Valid values are `upstream-alpine`, `enterprise-alpine`,
`enterprise-distroless` and `enterprise-distroless-fips`.

Example using a hypothetical `ghcr.io` mirror:

```yaml
spec:
  distribution:
    version: "2.x"
    registry: "my-ghcr-mirror.io/fluxcd"
    variant: "upstream-alpine"
```

Example using a hypothetical mirror of the ControlPlane enterprise registry:

```yaml
spec:
  distribution:
    version: "2.x"
    registry: "my-ghcr-mirror.io/controlplaneio-fluxcd/distroless"
    variant: "enterprise-distroless"
```

#### Distribution image pull secret

The `.spec.distribution.imagePullSecret` field is optional and specifies the name of the Kubernetes secret
that contains the credentials to pull the Flux distribution images from a private registry.

Example using the ControlPlane enterprise registry:

```yaml
spec:
  distribution:
    version: "2.3.x"
    registry: "ghcr.io/controlplaneio-fluxcd/distroless"
    imagePullSecret: "flux-enterprise-auth"
```

The image pull secret must be created in the same namespace where the FluxInstance is deployed
and must be of type `kubernetes.io/dockerconfigjson`.

Example generating a secret for the ControlPlane enterprise registry:

```sh
echo $ENTERPRISE_TOKEN | flux-operator create secret registry flux-enterprise-auth \
  --namespace=flux-system \
  --server=ghcr.io \
  --username=flux \
  --password-stdin
```

#### Distribution artifact

The `.spec.distribution.artifact` field is optional and specifies the OCI artifact URL
containing the Flux distribution manifests. When specified, the operator will pull the
artifact on a regular interval to determine the latest Flux version available
including CVE patches and hotfixes. When not specified, the operator will use
the artifact embedded into its container image. This is the recommended setting
for air-gapped environments.

Example using the official distribution artifact:

```yaml
spec:
  distribution:
    version: "2.x"
    registry: "ghcr.io/fluxcd"
    artifact: "oci://ghcr.io/controlplaneio-fluxcd/flux-operator-manifests"
```

#### Distribution artifact pull secret

The `.spec.distribution.artifactPullSecret` field is optional and specifies the name of the Kubernetes secret
that contains the credentials to pull the Flux distribution manifests from a private registry.

Example using a private registry:

```yaml
spec:
  distribution:
    version: "2.3.x"
    registry: "ghcr.io/controlplaneio-fluxcd/distroless"
    artifact: "oci://private.registry.com/controlplaneio-fluxcd/flux-operator-manifests"
    artifactPullSecret: "flux-private-auth"
```

The manifest pull secret must be created in the same namespace where the FluxInstance is deployed
and must be of type `kubernetes.io/dockerconfigjson`.

### Components configuration

The `.spec.components` field is optional and specifies the list of Flux components to install.

When not specified, the operator will install the default set of components: `source-controller`,
`kustomize-controller`, `helm-controller` and `notification-controller`.

The supported components are:

```yaml
spec:
  components:
    - source-controller
    - kustomize-controller
    - helm-controller
    - notification-controller
    - image-reflector-controller
    - image-automation-controller
    - source-watcher
```

Note that the `source-watcher` component requires Flux v2.7.0 or later.

### Cluster configuration

The `.spec.cluster` field is optional and specifies the Kubernetes cluster configuration.

Example using the OpenShift cluster configuration:

```yaml
spec:
  cluster:
    type: openshift
    size: medium
    multitenant: true
    multitenantWorkloadIdentity: true
    objectLevelWorkloadIdentity: true
    tenantDefaultServiceAccount: "flux"
    tenantDefaultDecryptionServiceAccount: "flux-decryption"
    tenantDefaultKubeConfigServiceAccount: "flux-kubeconfig"
    networkPolicy: true
    domain: "cluster.local"
```

#### Cluster type

The `.spec.cluster.type` field is optional and specifies the type of the Kubernetes cluster.
This field is used to enable specific configuration for AKS, EKS, GKE and OpenShift clusters.

The supported values are `kubernetes` (default), `openshift`, `azure`, `aws` and `gcp`.

#### Cluster size

The `.spec.cluster.size` field is optional and specifies the size of the Kubernetes cluster.
The size is used to determine the vertical scaling profile for the Flux controllers based on
the number of applications and the deployment frequency.

The supported values are `small`, `medium` and `large` which correspond to the following
configuration for Flux `kustomize-controller` and `helm-controller`:

| Size       | Concurrency | CPU limit | Memory limit | Requeue deps |
|------------|-------------|-----------|--------------|--------------|
| **small**  | 5           | 1000m     | 512Mi        | 10s          |
| **medium** | 10          | 2000m     | 1Gi          | 5s           |
| **large**  | 20          | 3000m     | 3Gi          | 5s           |

For all sizes, the `source-controller` is configured to cache artifacts
and the concurrency is set between 2 and 10.

The `small` size is suitable for edge clusters with limited resources (Raspberry Pi) or
for clusters with tens of apps and moderate deployment frequency.

The `medium` size is suitable for clusters with hundreds of apps, while the `large`
size is for clusters with up to a thousand apps and high deployment frequency.

When Flux manages thousands of apps,
the recommended scaling strategy is to use [sharding](#sharding-configuration).

#### Cluster multitenant

The `.spec.cluster.multitenant` field is optional and specifies whether to enable Flux
<a href="https://fluxcd.io/flux/installation/configuration/multitenancy/" target="_blank" rel="noopener noreferrer">multi-tenancy lockdown</a>.
By default, it is `false` (disabled).

The `.spec.cluster.tenantDefaultServiceAccount` is optional and specifies the default
service account used by Flux when reconciling `Kustomization` and `HelmRelease`
resources found in the tenant namespaces.

#### Cluster workload identity

The workload identity configuration provides fine-grained control over service account
usage across Flux controllers, enabling secure multi-tenant deployments in cloud environments.

##### Object-level workload identity

The `.spec.cluster.objectLevelWorkloadIdentity` field is optional and specifies whether to
enable the object-level workload identity feature gate and RBAC for the Flux controllers.
This feature allows Flux resources to specify their own service accounts via the
`spec.serviceAccountName` field.

Version requirements:

- Flux v2.6.0 and later: Supported for `source-controller`, `kustomize-controller`,
  `notification-controller`, `image-reflector-controller`, and `image-automation-controller`
- Flux v2.7.0 and later: Additionally supported for `helm-controller`

Example:

```yaml
spec:
  cluster:
    objectLevelWorkloadIdentity: true
```

##### Multitenant workload identity

The `.spec.cluster.multitenantWorkloadIdentity` field is optional and enables workload identity
multi-tenancy lockdown. When enabled, Flux controllers will use tenant-specific service accounts
as defaults, preventing cross-tenant access in workload identity scenarios.

Requirements:

- Requires `objectLevelWorkloadIdentity: true`
- Available in Flux v2.7.0 and later
- Designed for cloud environments with workload identity (AWS IRSA, Azure Workload Identity, GCP Workload Identity)

Example:

```yaml
spec:
  cluster:
    objectLevelWorkloadIdentity: true
    multitenantWorkloadIdentity: true
```

##### Service account configuration

When `multitenantWorkloadIdentity` is enabled, you can configure default service accounts
for different controller operations:

- `.spec.cluster.tenantDefaultServiceAccount` (optional): Default service account for
  `source-controller`, `notification-controller`, `image-reflector-controller`, and
  `image-automation-controller` operations. Defaults to `"default"`. (Also used by
  `kustomize-controller` and `helm-controller` for Kubernetes API operations when
  [`.spec.cluster.multitenant`](#cluster-multitenant) is set to `true`.)
- `.spec.cluster.tenantDefaultDecryptionServiceAccount` (optional): Default service account
  for `kustomize-controller` SOPS decryption operations. Defaults to `"default"`.
- `.spec.cluster.tenantDefaultKubeConfigServiceAccount` (optional): Default service account
  for `kustomize-controller` and `helm-controller` remote cluster access via
  `spec.kubeConfig.configMapRef`. Defaults to `"default"`.

Complete example:

```yaml
spec:
  cluster:
    objectLevelWorkloadIdentity: true
    multitenantWorkloadIdentity: true
    tenantDefaultServiceAccount: "flux-tenant"
    tenantDefaultDecryptionServiceAccount: "flux-decryption"
    tenantDefaultKubeConfigServiceAccount: "flux-kubeconfig"
```

Use cases:

- **Cloud workload identity**: Each tenant namespace has service accounts bound to cloud IAM roles
- **Secret management**: Different service accounts for decryption operations (e.g. SOPS with cloud KMS)
- **Multi-cluster**: Separate service accounts for accessing remote clusters via cloud IAM
- **Zero-trust**: Prevent controllers from accessing resources outside their intended scope

See the complete workload identity documentation for CNCF Flux
<a href="https://fluxcd.io/flux/integrations/" target="_blank" rel="noopener noreferrer">here</a>.

#### Cluster network policy

The `.spec.cluster.networkPolicy` field is optional and specifies whether to restrict network access
to the Flux namespace from other namespaces. By default, network policy is enabled.

#### Cluster domain

The `.spec.cluster.domain` field is optional and specifies the cluster internal domain name.
By default, the domain is set to `cluster.local`.

### Storage configuration

The `.spec.storage` field is optional and specifies the persistent storage for Flux internal artifacts.
When specified, the operator will create a persistent volume claim named `source-controller` with
the specified storage class and size and mount it to the Flux source-controller `/data` volume.

#### Storage class

The `.spec.storage.class` field is required and specifies the storage class to use for the persistent volume claim.

Example using the standard storage class:

```yaml
spec:
  storage:
    class: "standard"
    size: "10Gi"
```

#### Storage size

The `.spec.storage.size` field is required and specifies the size of the persistent volume claim.

### Sharding configuration

The `.spec.sharding` field is optional and specifies the sharding configuration for the Flux controllers.

Example:

```yaml
spec:
  sharding:
    key: "sharding.fluxcd.io/key"
    shards:
      - "shard1"
      - "shard2"
    storage: persistent
```

For each shard, the operator will create a separate set of controllers, e.g.:

```console
$ kubectl -n flux-system get deployments -l app.kubernetes.io/part-of=flux
NAME
source-controller
source-controller-shard1
source-controller-shard2
kustomize-controller
kustomize-controller-shard1
kustomize-controller-shard2
helm-controller
helm-controller-shard1
helm-controller-shard2
```

Note that only the `source-controller`, `kustomize-controller` and `helm-controller` controllers
support sharding.

To assign a resource to a specific shard, add the `sharding.fluxcd.io/key` label with the shard value,
e.g.: `sharding.fluxcd.io/key: shard1`.

#### Sharding key

The `.spec.sharding.key` field is optional and specifies the sharding key label to use for the Flux controllers.
By default, the key is set to `sharding.fluxcd.io/key`.

#### Shards

The `.spec.sharding.shards` field is required and specifies the list of sharding values to use for the Flux controllers.

### Sharding storage

The `.spec.sharding.storage` field is optional and specifies the storage type to use
for the source-controller shards.

The supported values are `ephemeral` (default) and `persistent`.
When set to `persistent`, the operator will create a persistent volume claim for each shard using
the storage class and size specified in the `.spec.storage` field.

### Common metadata

The `.spec.commonMetadata` field is optional and specifies common metadata to be applied to all Kubernetes resources
part of the Flux instance.

It has two optional fields:

- `labels`: A map used for setting <a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/" target="_blank" rel="noopener noreferrer">labels</a>
  on an object. Any existing label will be overridden if it matches with a key in
  this map.
- `annotations`: A map used for setting <a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/" target="_blank" rel="noopener noreferrer">annotations</a>
  on an object. Any existing annotation will be overridden if it matches with a key
  in this map.

Example common metadata:

```yaml
spec:
  commonMetadata:
    labels:
      app.kubernetes.io/name: flux
    annotations:
      toolkit.fluxcd.io/tenant: sre-team
```

### Kustomize patches

The `.spec.kustomize.patches` field is optional and specifies the Kustomize patches to apply to the Flux controllers.

Example:

```yaml
spec:
  kustomize:
    patches:
      - target:
          kind: Deployment
          name: "(kustomize-controller|helm-controller)"
        patch: |
          - op: replace
            path: /spec/template/spec/volumes/0
            value:
              name: temp
              emptyDir:
                medium: Memory
```

### Reconciliation configuration

The reconciliation behaviour can be configured using the following annotations:

- `fluxcd.controlplane.io/reconcile`: Enable or disable the reconciliation loop. Default is `enabled`, set to `disabled` to pause the reconciliation.
- `fluxcd.controlplane.io/reconcileEvery`: Set the reconciliation interval. Default is `1h`.
- `fluxcd.controlplane.io/reconcileArtifactEvery`: Set the artifact reconciliation interval. Default is `10m`.
- `fluxcd.controlplane.io/reconcileTimeout`: Set the reconciliation timeout. Default is `5m`.

To trigger an immediate reconciliation, the following annotation can be set to the current timestamp:

- `reconcile.fluxcd.io/requestedAt`: Set to the current timestamp to trigger an immediate reconciliation.
- `reconcile.fluxcd.io/forceAt`: Set to the current timestamp to trigger a forced reconciliation, migrating all Flux resources to their latest API version.

To force a reconciliation with the Flux Operator CLI:

```sh
flux-operator -n flux-system reconcile instance flux --force
```

### Sync configuration

The `.spec.sync` field is optional and specifies the Flux sync configuration.
When set, a Flux source and a Flux Kustomization are generated to sync
the cluster state with the source repository.

The Flux objects are created in the same namespace where the FluxInstance is deployed
using the namespace name as the Flux source and Kustomization name. The naming convention
matches the one used by `flux bootstrap` to ensure compatibility with upstream, and
to allow transitioning a bootstrapped cluster to a FluxInstance managed one.

Sync fields:

- `kind`: The source kind, supported values are `GitRepository`, `OCIRepository` and `Bucket`.
- `url`: The URL of the source repository, can be a Git repository HTTP/S or SSH address, an OCI repository address or a Bucket endpoint.
- `ref`: The source reference, can be a Git ref name e.g. `refs/heads/main`, an OCI tag e.g. `latest` or a Bucket name.
- `path`: The path to the source directory containing the kustomize overlay or plain Kubernetes manifests to sync from.
- `pullSecret`: The name of the Kubernetes secret that contains the credentials to pull the source repository. This field is optional.
- `provider`: The provider name used for OIDC-based authentication.
   Supported values are `aws`, `azure` and `gcp` for `OCIRepository`/`Bucket`,
   and `azure` or `github` for `GitRepository`. This field is optional.
- `interval`: The sync interval. This field is optional, when not set the default is `1m`.
- `name`: The name of the generated Flux source and Kustomization objects.
   This field is optional, when not set the default is the FluxInstance namespace name.
   Note that this field is considered immutable, and cannot be changed after the FluxInstance is created.

#### Sync from Git over HTTP/S

Example:

```yaml
spec:
  sync:
    kind: GitRepository
    url: "https://gitlab.com/my-group/my-fleet.git"
    ref: "refs/heads/main"
    path: "clusters/my-cluster"
    pullSecret: "git-token-auth"
```

If the source repository is private, the Kubernetes secret must be created
in the same namespace where the FluxInstance is deployed, and have the following format:

```yaml
apiVersion: v1
kind: Secret
metadata:
  name: git-token-auth
  namespace: flux-system
type: Opaque
stringData:
  username: "git-username"
  password: "git-token"
```

To generate the secret with the Flux Operator CLI:

```sh
flux-operator create secret basic-auth git-token-auth \
  --namespace=flux-system \
  --username=git-username \
  --password=git-token
```

#### Sync from Git over SSH

Example:

```yaml
spec:
  sync:
    kind: GitRepository
    url: "ssh://git@github.com/my-org/my-fleet.git"
    ref: "refs/heads/main"
    path: "clusters/my-cluster"
    pullSecret: "git-ssh-auth"
```

If the source repository is private, the Kubernetes secret must be created
in the same namespace where the FluxInstance is deployed, and have the following format:

```yaml
apiVersion: v1
kind: Secret
metadata:
  name: git-ssh-auth
  namespace: flux-system
type: Opaque
stringData:
  identity: |
    -----BEGIN OPENSSH PRIVATE KEY-----
    ...
    -----END OPENSSH PRIVATE KEY-----    
  known_hosts: |
    github.com ecdsa-sha2-nistp256 AAAA...  
```

To generate the secret with the Flux Operator CLI:

```sh
flux-operator create secret ssh git-ssh-auth \
  --namespace=flux-system \
  --private-key-file=my-private.key \
  --knownhosts-file=./known_hosts
```

#### Sync from OCI over HTTP/S

Example:

```yaml
spec:
  sync:
    kind: OCIRepository
    url: "oci://ghcr.io/my-org/my-fleet-manifests"
    ref: "latest"
    path: "clusters/my-cluster"
    pullSecret: "oci-token-auth"
```

If the container registry is private, the Kubernetes secret must be created
in the same namespace where the FluxInstance is deployed, and be of type `kubernetes.io/dockerconfigjson`:

```yaml
apiVersion: v1
kind: Secret
metadata:
  name: oci-token-auth
  namespace: flux-system
type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: "base64-encoded-docker-config"
```

To generate the secret with the Flux Operator CLI:

```sh
flux-operator create secret registry oci-token-auth \
  --namespace=flux-system \
  --server=ghcr.io \
  --username=ghcr-username \
  --password=ghcr-token
```

#### Sync from S3-compatible storage over HTTP/S

Example:

```yaml
spec:
  sync:
    kind: Bucket
    url: "minio.my-org.com"
    ref: "my-bucket-fleet"
    path: "clusters/my-cluster"
    pullSecret: "bucket-auth"
```

If the Bucket is private, the Kubernetes secret must be created
in the same namespace where the FluxInstance is deployed, and have the following format:

```yaml
apiVersion: v1
kind: Secret
metadata:
  name: bucket-auth
  namespace: flux-system
type: Opaque
stringData:
  accesskey: "my-accesskey"
  secretkey: "my-secretkey"
```

### Resources migration configuration

The `.spec.migrateResources` field is optional and instructs the operator to migrate
the Flux custom resources stored in Kubernetes etcd to the latest API version as
specified in the Flux CRDs. The migration runs after the Flux distribution is upgraded
from a minor version to another and only when a new API version is introduced.

By default, the field value is set to `true`. Note that disabling the migration may
result in upgrade failures due to deprecated API versions being removed in future Flux releases.

## FluxInstance Status

### Conditions

A FluxInstance enters various states during its lifecycle, reflected as Kubernetes Conditions.
It can be [reconciling](#reconciling-fluxinstance) while applying the resources on the cluster,
it can be [ready](#ready-fluxinstance),
it can [fail during reconciliation](#failed-fluxinstance),
or it can [fail due to misconfiguration](#stalled-fluxinstance).

The FluxInstance API is compatible with the **kstatus** specification,
and reports `Reconciling` and `Stalled` conditions where applicable to
provide better (timeout) support to solutions polling the Kustomization to
become `Ready`.

#### Reconciling FluxInstance

The flux-operator marks a FluxInstance as _reconciling_ when it starts
the reconciliation of the same. The Condition added to the FluxInstance's
`.status.conditions` has the following attributes:

- `type: Reconciling`
- `status: "True"`
- `reason: Progressing` | `reason: ProgressingWithRetry`

The Condition `message` is updated during the course of the reconciliation to
report the action being performed at any particular moment such as
building manifests, detecting drift, etc.

The `Ready` Condition's `status` is also marked as `Unknown`.

#### Ready FluxInstance

The flux-operator marks a FluxInstance as _ready_ when the Flux configuration was
built and applied on the cluster and all health checks are observed to be passing.

When the FluxInstance is "ready", the flux-operator sets a Condition with the
following attributes in the FluxInstance’s `.status.conditions`:

- `type: Ready`
- `status: "True"`
- `reason: ReconciliationSucceeded`

#### Failed FluxInstance

The flux-operator may get stuck trying to reconcile and apply a
FluxInstance without completing. This can occur due to some of the following factors:

- The distribution artifact is not accessible.
- The distribution version is not available.
- The kustomization of the Flux components fails to build.
- Garbage collection fails.
- Running health checks fails.

When this happens, the flux-operator sets the `Ready` Condition status to False
and adds a Condition with the following attributes to the FluxInstance’s
`.status.conditions`:

- `type: Ready`
- `status: "False"`
- `reason: ArtifactFailed | BuildFailed | HealthCheckFailed | ReconciliationFailed`

The `message` field of the Condition will contain more information about why
the reconciliation failed.

While the FluxInstance has one or more of these Conditions, the flux-operator
will continue to attempt a reconciliation with an
exponential backoff, until it succeeds and the FluxInstance is marked as [ready](#ready-fluxinstance).

#### Stalled FluxInstance

The flux-operator may fail the reconciliation of a FluxInstance object terminally due
to a misconfiguration. When this happens, the flux-operator adds the `Stalled` Condition
to the FluxInstance’s `.status.conditions` with the following attributes:

- `type: Stalled`
- `status: "True"`
- `reason: BuildFailed`

Misconfigurations can include:

- The build of the Flux manifests fails. In this case the condition reason is `BuildFailed`.

When this happens, the flux-operator will not attempt to reconcile the FluxInstance
until the misconfiguration is fixed. The `Ready` Condition status is also set to `False`.

### History

With `.status.history` the operator tracks the reconciliation attempts over time, providing insights
into the FluxInstance's behavior which can be used for audit, anomaly detection and debugging purposes.

The history is stored as a list of snapshots, ordered by last reconciliation time. Each snapshot contains:

- `digest`: A SHA256 digest that uniquely identifies the Flux configuration being reconciled
- `firstReconciled`: The timestamp when this particular configuration was first reconciled
- `lastReconciled`: The timestamp of the most recent reconciliation attempt for this configuration
- `lastReconciledDuration`: How long the most recent reconciliation attempt took
- `lastReconciledStatus`: The status of the most recent reconciliation (e.g., `ReconciliationSucceeded`, `BuildFailed`, `ReconciliationFailed`)
- `totalReconciliations`: The total number of reconciliations for this configuration
- `metadata`: Additional information about the reconciliation, including the Flux semantic version being applied

The operator deduplicates entries based on the digest and status.
The history is automatically truncated to keep only the 5 most recent entries.

Example:

```yaml
status:
  history:
    - digest: sha256:43ad78c94b2655429d84f21488f29d7cca9cd45b7f54d2b27e16bbec8eff9228
      firstReconciled: "2025-07-15T10:11:00Z"
      lastReconciled: "2025-07-15T11:12:00Z"
      lastReconciledDuration: 2.818583s
      lastReconciledStatus: ReconciliationSucceeded
      totalReconciliations: 2
      metadata:
        flux: "v2.6.4"
    - digest: sha256:ec8dbfe61777b65001190260cf873ffe454451bd2e464bd6f9a154cffcdcd7e5
      firstReconciled: "2025-06-14T13:10:00Z"
      lastReconciled: "2025-07-15T10:00:00Z"
      lastReconciledDuration: 4.813292s
      lastReconciledStatus: ReconciliationSucceeded
      totalReconciliations: 120
      metadata:
        flux: "v2.6.3"
```

### Components status

In order to provide visibility into the Flux components that are installed,
the flux-operator records the status of each component in the `.status.components` field,
including the image repository, tag and digest.

Example:

```text
Status:
  Components:
    Digest:      sha256:161da425b16b64dda4b3cec2ba0f8d7442973aba29bb446db3b340626181a0bc
    Name:        source-controller
    Repository:  ghcr.io/fluxcd/source-controller
    Tag:         v1.3.0
    Digest:      sha256:48a032574dd45c39750ba0f1488e6f1ae36756a38f40976a6b7a588d83acefc1
    Name:        kustomize-controller
    Repository:  ghcr.io/fluxcd/kustomize-controller
    Tag:         v1.3.0
```

### Inventory Status

In order to perform operations such as drift detection, garbage collection, upgrades, etc.,
the flux-operator needs to keep track of all Kubernetes objects that are
reconciled as part of a FluxInstance. To do this, it maintains an inventory
containing the list of Kubernetes resource object references that have been
successfully applied and records it in `.status.inventory`. The inventory
records are in the format `id: <namespace>_<name>_<group>_<kind>, v: <version>`.

Example:

```yaml
status:
  inventory:
    entries:
      - id: flux-system_source-controller__ServiceAccount
        v: v1
      - id: flux-system_source-controller__Service
        v: v1
      - id: flux-system_source-controller_apps_Deployment
        v: v1
```

### Last applied revision

`.status.lastAppliedRevision` is the last revision of the Flux distribution
that was successfully applied to the cluster.

The revision is in the format `<version>@sha256:<digest>`. 

The version is the Flux distribution exact semver version that was applied to the cluster.

The digest is the SHA256 hash of the Flux distribution manifests and customisations
that was applied to the cluster.

### Last attempted revision

`.status.lastAttemptedRevision` is the last revision of the Flux distribution
that was attempted to be applied to the cluster.

Example:

```text
Status:
  Last Applied Revision:    v2.3.0@sha256:4cc5babdb1279ad0177bf513292deadbfa3f7b7c3da0be7fa53b39ab434f7219
  Last Attempted Revision:  v2.3.0@sha256:4cc5babdb1279ad0177bf513292deadbfa3f7b7c3da0be7fa53b39ab434f7219
```

## FluxInstance Metrics

The Flux Operator exports metrics for the FluxInstance resource.
These metrics are refreshed every time the operator reconciles the instance.

Metrics:

```text
flux_instance_info{uid, kind, name, exported_namespace, ready, suspended, registry, revision}
```

Labels:

- `uid`: The Kubernetes unique identifier of the resource.
- `kind`: The kind of the resource (e.g. `FluxInstance`).
- `name`: The name of the resource (e.g. `flux`).
- `exported_namespace`: The namespace where the resource is deployed (e.g. `flux-system`).
- `ready`: The readiness status of the resource (e.g. `True`, `False` or `Unknown`).
- `reason`: The reason for the readiness status (e.g. `Progressing`, `BuildFailed`, `HealthCheckFailed`, etc.).
- `suspended`: The suspended status of the resource (e.g. `True` or `False`).
- `registry`: The container registry used by the instance (e.g. `ghcr.io/fluxcd`).
- `revision`: The Flux revision installed by the instance (e.g. `v2.3.0@sha256:75aa209c6a...`).

Example:

```text
flux_instance_info{
   exported_namespace="flux-system",
   kind="FluxInstance",
   name="flux",
   ready="True",
   reason="ReconciliationSucceeded",
   registry="ghcr.io/fluxcd",
   revision="v2.3.0@sha256:75aa209c6a2e25b97114ccf092246d02ab4363bc136edefc239d2a88da882b63",
   suspended="False",
   uid="16ca7202-9319-445b-99d0-617c25bda182"
}
```