FLuxCD Kind of Templater
Usage: fkt
FluxCD Kind of Templater.
Flags:
-h, --help Show context-sensitive help.
-f, --config-file=STRING YAML configuration file ($CONFIG_FILE)
-b, --base-directory="." Sources and overlays base directory ($BASE_DIRECTORY)
-d, --dry-run Dry run and return error if changes are needed ($DRY_RUN)
-v, --validate Validate configuration ($VALIDATE)
-l, --logging.level="default" Log level ($LOG_LEVEL)
-o, --logging.file=STRING Log file ($LOG_FILE)
-t, --logging.format="default" Log format ($LOG_FORMAT)
---
settings:
directories:
sources: sources # path containing sources
overlays: overlays # path to place templated files
delimiters:
left: '[[[' # custom left delimiter
right: ']]]' # custom right delimiter
log:
level: debug # log level, one of none, trace, debug, info, warn, error. Default is none
format: json # log format, one of console, json. Default is console
file: 'log.txt' # log file, none infers stdout
values: # global values
global_key: global_value
global_array_keys:
- global_array_key: global_array_value
- global_array_property:
global_array_property_key: global_array_property_value
global_slices:
- global_slice_one
- global_slice_two
clusters:
path: # cluster path
annotations: # annotations for cluster, added into kustomize file, templated as `Cluster.annotations`
key: value # cluster k/v annotation example, templated as `Cluster.annotations.key`
name: name # annotation name defaults to path stem if unset
managed: true # prune cluster output directory, manage top-level kustomize.yaml file, templated as `Cluster.managed`
values: # cluster level values, supercedes global values
cluster_key: cluster_value
cluster_array_keys:
- cluster_array_slice: cluster_array_value
cluster_slices:
- cluster_slice_one
- cluster_slice_two
sources: # sources to include for cluster
example: # source path within `directories.sources`
origin: ex # overlay origin name, default is source path, accessed as `.Source.origin`
managed: true # managed source, will not remove overlay if cluster is managed and source non-existent
namespace: example # optional namespace, default to `default`, accessed as `.Source.namespace`
values: # values, overrides cluster and global leval, accessed as `.Values.<map name>`
data: test-date # `.Values.data`
With a sources/example/cm.yaml
file
apiVersion: v1
kind: ConfigMap
metadata:
name: [[[ .Source.name ]]]
data:
value: [[[ .Values.data ]]]
Cluster paths are unique within the clusters
mapping.
A managed cluster resets the cluster directory when ran, EXCEPT if source is unmanaged,
i.e. <source>.Managed
is false
. In this case, the unmanaged source path for the cluster
is:
- Not removed
- If a
kustomization.yaml
orkustomization.yml
exists, the clusterkustomization.yaml
will include the unmanaged source.
Managed source functionality is used to support FluxCD cluster bootstrap in a managed cluster.
Values are accessed as .Values.<property>
Properties are replaced if a lower-level setting updates the property. Values are not merged.
Evaluation order:
- Global
- Cluster
- Source
Templating uses sprig functions.
For example, values as:
array_keys:
- array_slice: array_value
Templated as:
keys: "[[[ keys .Values | join "," ]]]"
array_keys: [[[ first .Values.array_keys | values | first ]]]
Become:
keys: "cluster_array_keys"
array_keys: cluster_array_value
YAML multiline string values are supported, but due to templating quotes may need doubled.
For example, values as:
inline_folded: >
Several lines of text,
with some "quotes" of various 'types',
and also a blank line:
and some text with
extra indentation
on the next line,
plus another line at the end.
inline_literal: |
Several lines of text,
with some "quotes" of various 'types',
and also a blank line:
and some text with
extra indentation
on the next line,
plus another line at the end.
inline_single_quoted: 'Several lines of text,
·containing ''''single quotes''''. Escapes (like \n) don''''t do anything.
Newlines can be added by leaving a blank line.
Leading whitespace on lines is ignored.'
Templated as:
inline_folded: >[[[ nindent 4 .Values.cluster_inline_folded ]]]
inline_literal: |[[[ nindent 4 .Values.cluster_inline_literal ]]]
inline_single_quoted: '[[[ indent 4 .Values.cluster_inline_single_quoted | trim ]]]'
Become:
inline_folded: >
Several lines of text, with some "quotes" of various 'types', and also a blank line:
and some text with
extra indentation
on the next line,
plus another line at the end.
inline_literal: |
Several lines of text,
with some "quotes" of various 'types',
and also a blank line:
and some text with
extra indentation
on the next line,
plus another line at the end.
inline_single_quoted: 'Several lines of text, ·containing ''single quotes''. Escapes (like \n) don''t do anything.
Newlines can be added by leaving a blank line. Leading whitespace on lines is ignored.'
Global valuse are in the upper-level schema.
Access as .Cluster.<property>
Properties:
annotations
: kustomize annotationsmanaged
: managed booleanpath
: cluster path
Access as .Source.<property>
Properties:
name
: Source namenamespace
: Source namespaceorigin
: Source origin, allows for re-using sources
Include a flux-system
anchor in the YAML configuration
flux-system: &flux-system
flux-system:
managed: false
Add the anchor to the cluster sources property:
sources:
<<: [*flux-system]
After running fkt
, no upper-level Kustomization will exist in the cluster path.
It is safe to commit this configuration into the config repo.
In the config repo, bootstrap fluxcd into the cluster path. FluxCD will install on the cluster and
update the repository to include a flux-system
path in the cluster overlay. Pull the changes, as Flux
may have altered the default branch. Running fkt
again will add the flux-system
Kustomizations
to the cluster Kustomization.
type Config struct {
Settings *Settings `yaml:"settings"`
Values Values `yaml:"values,flow"`
Clusters map[string]*Cluster `yaml:"clusters"`
}
type Settings struct {
Delimiters struct {
Left string `yaml:"left"`
Right string `yaml:"right"`
} `yaml:"delimiters"`
Directories struct {
Sources string `yaml:"sources"`
Overlays string `yaml:"overlays"`
baseDirectory string
} `yaml:"directories"`
DryRun bool `yaml:"dry_run"`
LogConfig *LogConfig `yaml:"log"`
}
type LogConfig struct {
Level LogLevel `yaml:"level"` // One of none (panic), trace, debug, info, error
File string `yaml:"file"` // Default stdout
Format string `yaml:"format"` // One of console, json. Default console
}
type Cluster struct {
Annotations map[string]string `yaml:"annotations"`
Managed *bool `yaml:"managed"`
Values *Values `yaml:"values,flow"`
Sources map[string]*Source `yaml:"sources"`
path string
}
type Source struct {
Origin *string `yaml:"origin"`
Namespace *string `yaml:"namespace"`
Values Values `yaml:"values,flow"`
Managed *bool `yaml:"managed"`
Name string
}
A pre-commit config can be used to automatically update the cluster overlays after changing the configuration.
- repo: git@<repo>
rev: <tag>
hooks:
- id: fkt
always_run: true
args: [-l, debug]
A GitHub action.yml
is included to verify that the supplied configuration
would be unchanged to ensure the configuration output is consistent with
the overlay contents for all clusters.
Arguments:
base-directory
: Default to.
config-file
: Default toconfig.yaml
log-level
: Default towarn
- name: Validate Overlay
uses: <org>/<repo>@v0
A PAT is required to load the repo into the GH working directory.
- name: Checkout Validate Overlay Action
uses: actions/checkout@v4
with:
repository: <org><repo>
ref: <version>
token: ${{ secrets.INTERNAL_PAT }}
path: ./.github/actions/fkt
- name: Validate Overlay
id: validate-overlay
uses: ./.github/actions/fkt
with:
log-level: debug
GitHub action and pre-commit versions can update automatically after image push if
SSH_DEPLOY_PRIVATE_KEY
secret is set. A read-write
deployment key is sufficient for this
when branch protection rules are properly set.
Manage repository deployment key and set the GitHub SSH_DEPLOY_PRIVATE_KEY
action secret
with the bin/manage_deploy_key
script.