diff --git a/docs/guides/image-update.md b/docs/guides/image-update.md new file mode 100644 index 00000000..4cb80682 --- /dev/null +++ b/docs/guides/image-update.md @@ -0,0 +1,352 @@ +# Automate image updates to Git + +This guide walks you through configuring container image scanning and deployment rollouts with Flux. + +For a container image you can configure Flux to: + +- scan the container registry and fetch the image tags +- select the latest tag based on a semver range +- replace the tag in Kubernetes manifests (YAML format) +- checkout a branch, commit and push the changes to the remote Git repository +- apply the changes in-cluster and rollout the container image + +!!! warning "Alpha version" + Note that the image update feature is currently alpha and, it only supports **semver** filters. + In the future we plan to add support for other filtering options. + Please see the [roadmap](../roadmap/index.md) for more details. + +For production environments, this feature allows you to automatically deploy application patches +(CVEs and bug fixes), and keep a record of all deployments in Git history. + +For staging environments, this features allow you to deploy the latest prerelease of an application, +without having to manually edit its deployment manifests in Git. + +Production CI/CD workflow: + +* DEV: push a bug fix to the app repository +* DEV: bump the patch version and release e.g. `v1.0.1` +* CI: build and push a container image tagged as `registry.domain/org/app:v1.0.1` +* CD: pull the latest image metadata from the app registry (Flux image scanning) +* CD: update the image tag in the app manifest to `v1.0.1` (Flux cluster to Git reconciliation) +* CD: deploy `v1.0.1` to production clusters (Flux Git to cluster reconciliation) + +## Prerequisites + +You will need a Kubernetes cluster version 1.16 or newer and kubectl version 1.18. +For a quick local test, you can use [Kubernetes kind](https://kind.sigs.k8s.io/docs/user/quick-start/). +Any other Kubernetes setup will work as well. + +In order to follow the guide you'll need a GitHub account and a +[personal access token](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line) +that can create repositories (check all permissions under `repo`). + +Export your GitHub personal access token and username: + +```sh +export GITHUB_TOKEN= +export GITHUB_USER= +``` + +## Install Flux + +Install Flux with the image automation components: + +```sh +flux bootstrap github \ + --components-extra=image-reflector-controller,image-automation-controller \ + --owner=$GITHUB_USER \ + --repository=flux-image-updates \ + --branch=main \ + --path=clusters/my-cluster \ + --token-auth \ + --personal +``` + +The bootstrap command creates a repository if one doesn't exist, and commits the manifests for the +Flux components to the default branch at the specified path. It then configures the target cluster to +synchronize with the specified path inside the repository. + +!!! hint "GitLab and other Git platforms" + You can install Flux and bootstrap repositories hosted on GitLab, BitBucket, Azure DevOps and + any other Git provider that support SSH or token-based authentication. + When using SSH, make sure the deploy key is configured with write access. + Please see the [installation guide](installation.md) for more details. + +## Deploy a demo app + +We'll be using a tiny webapp called [podinfo](https://github.com/stefanprodan/podinfo) to +showcase the image update feature. + +Clone your repository with: + +```sh +git clone https://github.com/$GITHUB_USER/flux-image-updates +cd flux-image-updates +``` + +Add the podinfo Kubernetes deployment file inside `cluster/my-cluster`: + +```sh +curl -sL https://raw.githubusercontent.com/stefanprodan/podinfo/5.0.0/kustomize/deployment.yaml \ +> ./clusters/my-cluster/podinfo-deployment.yaml +``` + +Commit and push changes to main branch: + +```sh +git add -A && \ +git commit -m "add podinfo deployment" && \ +git push origin main +``` + +Tell Flux to pull and apply the changes or wait one minute for Flux to detect the changes on its own: + +```sh +flux reconcile kustomization flux-system --with-source +``` + +Print the podinfo image deployed on your cluster: + +```console +$ kubectl get deployment/podinfo -oyaml | grep 'image:' +image: ghcr.io/stefanprodan/podinfo:5.0.0 +``` + +## Configure image scanning + +Create an `ImageRepository` to tell Flux which container registry to scan for new tags: + +```sh +flux create image repository podinfo \ +--image=ghcr.io/stefanprodan/podinfo \ +--interval=1m \ +--export > ./clusters/my-cluster/podinfo-registry.yaml +``` + +The above command generates the following manifest: + +```yaml +apiVersion: image.toolkit.fluxcd.io/v1alpha1 +kind: ImageRepository +metadata: + name: podinfo + namespace: flux-system +spec: + image: ghcr.io/stefanprodan/podinfo + interval: 1m0s +``` + +For private images, you can create a Kubernetes secret +in the same namespace as the `ImageRepository` with +`kubectl create secret docker-registry`. Then you can configure +Flux to use the credentials by referencing the Kubernetes secret +in the `ImageRepository`: + +```yaml +kind: ImageRepository +spec: + secretRef: + name: regcred +``` + +!!! hint "Storing secrets in Git" + Note that if you want to store the image pull secret in Git, you can encrypt + the manifest with [Mozilla SOPS](mozilla-sops.md) or [Sealed Secrets](sealed-secrets.md). + +Create an `ImagePolicy` to tell Flux which semver range to use when filtering tags: + +```sh +flux create image policy podinfo \ +--image-ref=podinfo \ +--interval=1m \ +--semver=5.0.x \ +--export > ./clusters/my-cluster/podinfo-policy.yaml +``` + +The above command generates the following manifest: + +```yaml +apiVersion: image.toolkit.fluxcd.io/v1alpha1 +kind: ImagePolicy +metadata: + name: podinfo + namespace: flux-system +spec: + imageRepositoryRef: + name: podinfo + policy: + semver: + range: 5.0.x +``` + +Commit and push changes to main branch: + +```sh +git add -A && \ +git commit -m "add podinfo image scan" && \ +git push origin main +``` + +Tell Flux to pull and apply changes: + +```sh +flux reconcile kustomization flux-system --with-source +``` + +Wait for Flux to fetch the image tag list from GitHub container registry: + +```console +$ flux get image repository podinfo +NAME READY MESSAGE LAST SCAN +podinfo True successful scan, found 13 tags 2020-12-13T17:51:48+02:00 +``` + +Find which image tag matches the policy semver range with: + +```console +$ flux get image policy podinfo +NAME READY MESSAGE +podinfo True Latest image tag for 'ghcr.io/stefanprodan/podinfo' resolved to: 5.0.3 +``` + +## Configure image updates + +Edit the `podinfo-deploy.yaml` and add a maker to tell Flux which policy to use when updating the container image: + +```yaml +spec: + containers: + - name: podinfod + image: ghcr.io/stefanprodan/podinfo:5.0.0 # {"$imagepolicy": "flux-system:podinfo"} +``` + +Create an `ImageUpdateAutomation` to tell Flux which Git repository to write image updates to: + +```sh +flux create image update flux-system \ +--git-repo-ref=flux-system \ +--author-name=fluxcdbot \ +--author-email=fluxcdbot@users.noreply.github.com \ +--commit-template="[ci skip] update image" \ +--export ./clusters/my-cluster/flux-system-automation.yaml +``` + +The above command generates the following manifest: + +```yaml +apiVersion: image.toolkit.fluxcd.io/v1alpha1 +kind: ImageUpdateAutomation +metadata: + name: flux-system + namespace: flux-system +spec: + checkout: + gitRepositoryRef: + name: flux-system + commit: + authorEmail: fluxcdbot@users.noreply.github.com + authorName: fluxcdbot + messageTemplate: '[ci skip] update image' + interval: 1m0s + update: + setters: {} +``` + +Commit and push changes to main branch: + +```sh +git add -A && \ +git commit -m "add image updates automation" && \ +git push origin main +``` + +Note that the `ImageUpdateAutomation` runs all the policies found in its namespace at the specified interval. + +Tell Flux to pull and apply changes: + +```sh +flux reconcile kustomization flux-system --with-source +``` + +In a couple of seconds Flux will push a commit to your repository with +the latest image tag that matches the podinfo policy: + +```console +$ git pull && cat clusters/my-cluster/podinfo-deployment.yaml | grep "image:" +image: ghcr.io/stefanprodan/podinfo:5.0.3 # {"$imagepolicy": "flux-system:podinfo"} +``` + +Wait for Flux to apply the latest commit on the cluster and verify that podinfo was updated to `5.0.3`: + +```console +$ watch "kubectl get deployment/podinfo -oyaml | grep 'image:'" +image: ghcr.io/stefanprodan/podinfo:5.0.3 +``` + +## Configure image update for custom resources + +Besides Kubernetes native kinds (Deployment, StatefulSet, DaemonSet, CronJob), +Flux can be used to patch image tags in any Kubernetes custom resource stored in Git. + +The image policy marker format is: + +* `{"$imagepolicy": ":"}` +* `{"$imagepolicy": "::tag"}` + + +`HelmRelease` example: + +```yaml +apiVersion: helm.toolkit.fluxcd.io/v2beta1 +kind: HelmRelease +metadata: + name: podinfo + namespace: default +spec: + values: + image: + repository: ghcr.io/stefanprodan/podinfo + tag: 5.0.0 # {"$imagepolicy": "flux-system:podinfo:tag"} +``` + +Tekton `Task` example: + +```yaml +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: golang + namespace: default +spec: + steps: + - name: golang + image: docker.io/golang:1.15.6 # {"$imagepolicy": "flux-system:golang"} +``` + +Flux `Kustomization` example: + +```yaml +apiVersion: kustomize.toolkit.fluxcd.io/v1beta1 +kind: Kustomization +metadata: + name: podinfo + namespace: default +spec: + images: + - name: ghcr.io/stefanprodan/podinfo + newName: ghcr.io/stefanprodan/podinfo + newTag: 5.0.0 # {"$imagepolicy": "flux-system:podinfo:tag"} +``` + +Kustomize config (`kustomization.yaml`) example: + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +- deployment.yaml +images: +- name: ghcr.io/stefanprodan/podinfo + newName: ghcr.io/stefanprodan/podinfo + newTag: 5.0.0 # {"$imagepolicy": "flux-system:podinfo:tag"} +``` diff --git a/docs/guides/installation.md b/docs/guides/installation.md index 56419da9..416894cb 100644 --- a/docs/guides/installation.md +++ b/docs/guides/installation.md @@ -57,6 +57,7 @@ You can choose what components to install and for which cluster with: ```sh flux bootstrap \ --components=source-controller,kustomize-controller,helm-controller,notification-controller \ + --components-extra=image-reflector-controller,image-automation-controller \ --path=clusters/my-cluster \ --version=latest ``` diff --git a/mkdocs.yml b/mkdocs.yml index c8a89c8e..f9b443cf 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -52,6 +52,7 @@ nav: - Monitoring with Prometheus: guides/monitoring.md - Sealed Secrets: guides/sealed-secrets.md - Mozilla SOPS: guides/mozilla-sops.md + - Automate image updates to Git: guides/image-update.md - Migration: - Migrate from Flux v1: guides/flux-v1-migration.md - Migrate from the Helm Operator: guides/helm-operator-migration.md