To manage an application stack holistically, a Declaration is required. From this declaration, desired state can be calculated, i.e. what changes need to be made for an environment to be aligned to the declaration. The tool used in this example is Helmsman, however, another tool, Helmfile has fundamentally the same configuration constructs. Each gather one or more Helm applications to create an application stack. Only the necessary components will be updated if a change is determined, based on a calculated state change.
graph TD
subgraph Test
subgraph stack1["Declaration"]
subgraph app1["Helmchart"]
serv1["service"]
appt1["pod"]
end
subgraph app2["Helmchart"]
serv2["service"]
appp2["pod"]
end
end
end
subgraph Prod
subgraph stack2["Declaration"]
subgraph app3["Helmchart"]
serv3["service"]
appt3["pod"]
end
subgraph app4["Helmchart"]
serv4["service"]
appp4["pod"]
end
end
end
serv1 --> appt1
serv2 --> appp2
serv3 --> appt3
serv4 --> appp4
classDef AppStack fill:LightBlue
class stack1,stack2 AppStack
classDef dotted stroke-dasharray: 2, 2
class stack1,stack2 dotted
classDef dashed stroke-dasharray: 5, 5
class app1,app2,app3,app4 dashed
The build-time process uses the declaration to determine the Helm charts that are required at deploy time. These are downloaded and included in the package, this has the advantage of not having to manage registry access at deploy time and ensures the charts are immutable within the release package.
There is no “compiled” output for the source files described above, so the self-contained release package capability of Continuous Delivery Automation Framework (CDAF) is used to produce a portable, re-usable deployment artefact, i.e. build once, deploy many.
graph LR
subgraph ci["Continuous Integration"]
persist[(persist)]
end
release.ps1
subgraph cd["Continuous Delivery"]
test
prod
end
persist -->
release.ps1 --> test
release.ps1 --> prod
classDef blue fill:#007FFF
class release.ps1 blue
classDef dashed stroke-dasharray: 5, 5
class ci,cd dashed
The deployment uses an Environment argument is a symbolic link to the settings that need to be detokenised at deploy time, e.g.
This example is the deploy time process for Helmsman, although it is fundamentally the same for Helmfile. The tokenised application stack declaration is de-tokenised to apply the correct name_space at deploy time.
helm.tsk
sed -i -- "s•name_space•*****•g" ranger.yaml
the resulting deployment
helmsman --apply -f ranger.yaml ranger-chart
_ _
| | | |
| |__ ___| |_ __ ___ ___ _ __ ___ __ _ _ __
| '_ \ / _ \ | '_ ` _ \/ __| '_ ` _ \ / _` | '_ \
| | | | __/ | | | | | \__ \ | | | | | (_| | | | |
|_| |_|\___|_|_| |_| |_|___/_| |_| |_|\__,_|_| |_| version: v3.11.0
Helm-Charts-as-Code tool.
WARNING: helm diff not found, using kubectl diff
INFO: Parsed [[ ranger.yaml ]] successfully and found [ 1 ] apps
INFO: Validating desired state definition
INFO: Setting up kubectl
INFO: Setting up helm
INFO: Setting up namespaces
INFO: Getting chart information
INFO: Chart [ /solution/deploy/ranger-chart ] with version [ 0.1.0 ] was found locally.
INFO: Charts validated.
INFO: Preparing plan
INFO: Acquiring current Helm state from cluster
INFO: Checking if any Helmsman managed releases are no longer tracked by your desired state ...
INFO: No untracked releases found
NOTICE: -------- PLAN starts here --------------
NOTICE: Release [ ranger ] in namespace [ test ] will be installed using version [ 0.1.0 ] -- priority: 0
NOTICE: -------- PLAN ends here --------------
INFO: Executing plan
NOTICE: Install release [ ranger ] version [ 0.1.0 ] in namespace [ test ]
NOTICE: Release "ranger" does not exist. Installing it now.
NAME: ranger
LAST DEPLOYED: Sun Aug 7 03:42:51 2022
NAMESPACE: test
STATUS: deployed
REVISION: 1
NOTES:
1. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace test -l "app.kubernetes.io/name=ranger-chart,app.kubernetes.io/instance=ranger" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace test $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace test port-forward $POD_NAME 8080:$CONTAINER_PORT
NOTICE: Finished: Install release [ ranger ] version [ 0.1.0 ] in namespace [ test ]
The key to using Helm charts rather than simply authoring Kubernetes YAML definitions is the use of templates. This way a deployment pattern can be defined once, with only the deploy time, application specific, values being changed.
From the Helm template the health probes are hard coded, replace these with shared definitions, .Values.service.port & .Values.service.probeContext.
The .Values.service.port is already defined in the generated values file, but .Values.service.probeContext is not, so add this to the values definition.
values.yaml
service:
type: ClusterIPport: 8000probeContext: /
Now replace single values file with a file for each application being deployed based on this pattern. Create additional app definitions in Helmsman
Some changes cannot be updated in place, an example of this is the service port. If this is changed, the chart version has be updated or the existing deployment manually removed.