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 deployed through 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. | An agreed service name, owning team, target stack and deployment controller. |
| 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, a separate approved Halo RFC for each of PRP, PRX and PRD being changed, deployment and rollback steps. |
| 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 deployment ownership for the service’s environment and stack. For an existing service, trace its Helmsman entry and enablement guard, or its Flux HelmRelease and environment/stack overlay. Agree the controller with Platform Operations during onboarding for a new service. Do not configure both controllers to manage the same release.
For Helmsman, use cpp-aks-deploy for Helm and environment configuration, cpp.pipeline for image versions and the cpp-aks-deploy pipeline to run Helmsman. Follow steps 3A–6A below. For Flux, follow the Flux route.
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. Earlier pipeline setup can still change namespace-related Helm releases, so a plan-only run is not entirely side-effect free. 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
Follow the cpp-flux-config onboarding runbook:
- Add the service’s HelmRelease and
kustomization.yamlunderapps/base/services, pinning the chart version and image repository. - Reference it from
apps/base/kustomization.yamlonly if it must reach every configured environment. For one environment, reference it from that environment’sapps/environmentskustomization instead. Add environment values there and stack overrides underapps/overlays/stacks. - Set the image-tag substitution in the target cluster’s
clusters/<environment>/<cluster>/flux-cluster-vars.yaml, or override it for a single stack in that cluster’sapps.yaml. Check the Kustomization’s path andtargetNamespaceto confirm the scope. - Render each affected environment and stack overlay with
kustomize build, run the repository’s pre-commit checks and obtain the required reviews. PRD changes require an RFC number, change window and rollback plan for the repository’sprd-checkworkflow. - Merge the approved non-live change, then verify the target Flux Kustomization and HelmRelease are Ready and run the application checks below. For PRP, PRX or PRD, follow Path to Live and obtain the environment’s separate Halo RFC before merging in the approved window.
Provision the service’s databases, identities, secrets and network access before reconciliation. A manifest that renders successfully does not establish that those dependencies exist.
Verify the deployment
After deployment, record the image tag and either the pipeline run link or the Flux configuration 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 cpp-aks-deploy run or Flux reconciliation does not by itself confirm application health or business behaviour. Verify pod readiness, the health endpoint and the service tests described above.
Once the component works in non-live, continue with Path to Live.