Starting a new component
This guide takes a new component from its initial design to a tested deployment and a managed CPP release. It covers CCM AKS applications using Helmsman or Flux. For virtual-machine, Alfresco or AMP workloads, obtain the component-specific deployment runbook from Platform Operations during service onboarding.
From an idea to a working service
Follow these steps in order for a new application in a CPP CCM AKS stack. Infrastructure changes and shared libraries use the relevant build and provisioning steps; they do not need an application deployment.
| Step | What to do | What you need before continuing |
|---|---|---|
| 1. Agree the component | Complete service onboarding: name the owner, check the architecture, identify dependencies and agree the first non-live stack and deployment controller. | An agreed service name, owning team, target stack and Helmsman or Flux route. |
| 2. Create the repository | Follow repository and build setup. | Source ownership, a README, reviewed changes and a build that runs locally. |
| 3. Build and publish | Configure the CPP build pipeline and publish the deployment image. | Passing checks, published dependencies and the exact container image repository and tag. |
| 4. Provision dependencies | Set up infrastructure, secrets and connectivity. Start provisioning while developing the service. | Required databases, identities, secrets and network access exist in the target stack. |
| 5. Deploy and test | Follow deployment steps below for the selected controller. | Ready pods, a responding health endpoint, smoke and integration test results, logs and monitoring. |
| 6. Take the service live | Follow Path to Live with Crime Release Management. | Release evidence, approved RFC, deployment and rollback steps for PRP and PRD. |
| 7. Operate the service | Use live service for environment availability and outbound IP configuration. | The owning team can support the service and its external connections. |
Use the CPP onboarding steps to obtain personal access before starting. Tools and configuration, Helm charts and CPP Artifactory provide supporting reference material throughout this journey.
1. Select the image-build route
CPP uses two image-build routes. Confirm which one applies before changing deployment configuration.
- Central context-service build:
cpp-docker-imageslists established context services inmetadata-contexts.json. Its Jenkins seed creates an image-build job for each listed service. The job checks out the mapped service repository, builds the files under itsdockerdirectory, pushes<service>-service:<tag>to the CPP Azure Container Registry and updates the matching image tag incpp.pipelineunlessskipVersionRegistryUpdateis selected. - Service-owned build: the service repository’s own pipeline builds and publishes the image. Obtain the exact pipeline URL and image repository from the service owner.
ADO definition 345, docker-images, builds the standalone and base images defined inside cpp-docker-images; the current context-service jobs are generated Jenkins jobs. Do not describe definition 345 as the build job for a context service.
Whichever route is used, record the exact image tag. The deployment controller consumes an existing image; it does not compile the service.
2. Select the deployment route
Check the configuration for the target environment:
- a service represented by an application entry in
cpp-aks-deploy/helmsman.tomlis deployed through the Helmsman route below - a service represented by a
HelmReleaseundercpp-flux-config/appsis deployed by Flux
A service can be under migration and use Flux in one environment while Helmsman still manages it elsewhere. Record the controller for every target environment; do not enable the same Kubernetes release through both controllers in the same environment and stack.
Helmsman route
3A. Add the service to cpp-aks-deploy
Create a branch in cpp-aks-deploy. Add:
- an application entry in
helmsman.toml - common values in
ansible/group_vars/<service>_values.yaml.j2 - environment values in
ansible/group_vars/<environment>/<service>_values.yaml.j2only when they differ from the common values - stack values in
ansible/group_vars/<environment>/<stack>/<service>_values.yaml.j2only when they differ for that stack
Names in angle brackets are notation: replace them with the real service, environment, stack and secret names in configuration. They are not literal filenames or values.
Use the chart selected during onboarding. Existing CCM application patterns include springboot-app and wildfly-app; do not select one only because a neighbouring service uses it. The pipeline renders the common values first, then environment values, then stack values. A later file overrides the same setting from an earlier file.
4A. Set the version to deploy
Create or update the service’s <service>_image_tag entry in cpp.pipeline/aks-pipeline.versions.yml. The central context-service build updates this entry automatically unless skipVersionRegistryUpdate is selected. For another build route, set it to the image tag produced in step 1.
helmsman_set_service_enabled.sh derives the matching <service>_enabled variable from image-tag variables, except for variables in its exclusion list and variants routed by image_tag_config.yaml.
The cpp.pipeline branch containing this change is passed to the deployment pipeline as CPP Pipeline Branch. Keep the cpp-aks-deploy branch and the cpp.pipeline branch separate: the first contains the Helm and environment configuration; the second selects image versions.
5A. Add runtime configuration
Put non-secret settings in the values files described in step 3A. CPP CCM AKS currently supports two different secret mechanisms:
- HashiCorp Vault: put an Ansible lookup such as
lookup('vault', 'secret/<environment>/<stack>/<secret-name>')in the common, environment or stack.yaml.j2values file described in step 3A.CPP-AKS-DEPLOYreceives its Vault address and token from an Azure DevOps variable group and resolves the lookup while rendering the Helm values. - Azure Key Vault: set
secretProvider.create: trueand list the provisioned Key Vault and secret mappings undersecretProvider.keyVaultsin the service values. The shared charts contain Secrets Store CSISecretProviderClasstemplates, and the pod receives those secrets at runtime. This route also requires the workload identity and Key Vault access to have been created for the service.
Do not choose a secret mechanism from the environment name. Use HashiCorp Vault only when its path has been provisioned, or Azure Key Vault only when the vault entry, workload identity and access have been provisioned. Do not put a secret value in Git, a pipeline parameter or documentation. A reference to a secret is safe to commit; its value is not.
6A. Deploy to non-live
Use the CPP-AKS-DEPLOY Azure DevOps pipeline. Queue it with:
- Branch/tag: the
cpp-aks-deploybranch containing the new service configuration - Environment: the approved non-live environment:
dev,ste,sitornft - Stack: the approved CCM stack, for example
devccm08 - Cluster: leave blank unless Platform Operations has supplied a cluster name
- CPP Pipeline Branch: the
cpp.pipelinebranch containing the image tag - deploy-service: clear for a plan-only run; selected for a run that performs the plan and then applies it
Leave delete_ns, deploy_idam and create_db clear unless the approved change explicitly requires them. They are separate platform operations, not normal application-deployment options.
First run with deploy-service clear and review the complete Helmsman plan. Helmsman compares the desired state for the stack, so confirm that the plan does not contain an unrelated service change. Then run with deploy-service selected.
A non-pull-request run enters the manual-validation job before the deployment job. For non-live, the current job resumes automatically after one minute if nobody responds; it is not a blocking approval gate.
Flux route
3B. Add the service to cpp-flux-config
Follow the cpp-flux-config onboarding runbook. It defines the current file layout and includes worked examples. In summary:
- add the base
HelmReleaseand itskustomization.yamlunderapps/base/services/<service>/ - reference it from
apps/baseonly if it must run in every configured environment; otherwise reference it from the required environment or stack overlay - put environment-specific settings and Azure Key Vault mappings in an environment patch
- add the image-tag variable to each target cluster’s
flux-cluster-vars.yaml, with a stack override only when one stack must use a different tag - run
kustomize buildfor every affected environment and stack before raising the PR
The repository’s automated onboarding workflow is a non-production proof of concept. It covers DEV, NFT and SIT, and STE stack 50 only. It does not create Key Vault secrets or onboard a service to PRP or PRD.
After merge, Flux reconciles the committed configuration on its configured interval. The current repository sets this to five minutes. An operator with access can request an immediate reconciliation with the exact command in the repository runbook.
Verify either route
After deployment, record the image tag and either the pipeline run link or the Flux commit and reconciliation result. Confirm:
- the deployed workload is available and its pods are Ready
- the service health endpoint responds
- the service smoke test and required integration tests pass
- logs show no new error from the service while the recorded smoke and integration tests run, and Dynatrace shows the expected service activity without a new alert
A successful Helmsman pipeline or Flux reconciliation proves that the deployment controller completed without reporting an error. It does not prove that the pods are Ready or that the service’s business behaviour works; the checks above provide that evidence.
Once the component works in non-live, continue with Path to Live.