Introduction
Modern application delivery demands reliable builds, consistent deployments, and controlled release processes. Rebuilding an application for every environment is liable to bring inconsistencies and it can be challenging to confirm that the version of the application that was tested by QA gets to the Production.The build once, deploy anywhere approach tackles this problem by building the application artifact once and promoting it across environments without rebuilding.
The release process begins with a release branch followed by the developer changes and required JAR pipelines. Jenkins builds the application and creates a Docker image pushing the image to Amazon Elastic Container Registry (Amazon ECR). Optimizing Docker image sizes during this build process improves deployment efficiency, exploring best practices for reducing Docker image sizes with multi-stage builds.
The deployment pipeline then deploys the image to Test. After QA completes a sanity test an approval pipeline is used to control the promotion to higher environments like UAT and Production. Helm, Kubernetes and ArgoCD support environment specific configuration and deployment. This approach separates application build from deployment and promotion thus creating a consistent, traceable, release control process.
Key takeaways
- Build once: Create the application artifact and Docker image once for each release candidate.
- Test before promotion: Complete QA sanity testing before promoting the release.
- Reuse the same artifact: Promote the validated image across Test, UAT, and Production.
- Separate configuration: Use Helm values to manage environment-specific settings.
- Control releases: Implement approval gates for higher environments.
- Maintain traceability: Associate each image with its release version and source revision.
Why adopt a build-once approach?
The approach prevents applications that have been built for different environments to produce varied dependencies, build parameters or source revisions. Consequently the artifact deployed to Production could differ from the one tested by QA.The build-once approach avoids unnecessary rebuilds during promotion. Once Jenkins has created the release artifact the promotion process involves testing, approval and deployment.The workflow is as follows:
Build → Test → QA sanity → Approval → UAT → Production
Every environment uses the same application image, the deployment configuration can change per environment. This approach improves artifact consistency, troubleshooting, minimises duplicate build operations and makes release traceability easier.
How the release process works
- Create the release branch
The release pipeline creates a release branch. Developers make the required changes on the branch, this becomes the source for the next build.The team then runs the required JAR pipelines, JAR 2.0 and JAR 2.2 according to the release requirements.The application build begins once the required preparation steps have been successfully completed.
- Build the application with Jenkins
Jenkins handles the application build process. The build pipeline checks out the release branch, performs the required build steps and creates the application artifact. The pipeline then packages the application into a Docker image and pushes the image to Amazon ECR. The team should record the release version, Git commit SHA, Jenkins build number and image tag. This information helps identify the exact artifact associated with a release. Once the build succeeds and passes the required checks the promotion process should reuse the existing artifact instead of building the application again.
- Store the Docker image in Amazon ECR
Amazon ECR is a central repository for storing and retrieving Docker images. After Jenkins has created the image it pushes the image to the appropriate ECR repository. Deployment pipelines will retrieve that image when deploying the application to different environments. A unique image tag helps identify each release. Using the same image tag across environments ensures that Test, UAT and Production receive the same artifact.
Deploying to Test and completing QA sanity
Once the image is in Amazon ECR, the deployment pipeline deploys it to Test. Helm manages the Kubernetes deployment configuration whilst ArgoCD synchronises the desired configuration with the target Kubernetes environment. The deployment process should verify that the application has started successfully, health checks passed and critical functionality is working as expected. QA will perform sanity testing to validate the release. If the application fails validation the team resolves the problem and repeats the necessary checks before continuing. A successful deployment does not signify that the release is ready for promotion. Once QA has completed the required checks the release proceeds to the approval stage.
Promoting the same build to higher environments
The approval pipeline provides a controlled checkpoint before the release advances to higher environments.The process follows these steps:
- Jenkins builds the application and publishes the Docker image.
- The deployment pipeline deploys the image to Test.
- QA completes sanity testing.
- The approval pipeline requests authorisation for promotion.
- An authorised stakeholder approves the release.
- The deployment process promotes the same image to UAT.
- The team completes the required Production approval.
- The deployment process promotes the approved image to Production.
Approval authorises promotion, it does not trigger another application build. This separation helps maintain a clear record of the artifact that passed validation and reached Production.
Managing deployments with Helm, Kubernetes and ArgoCD
Different environments will have different operational requirements. Production may need more replicas and higher resource limits than test but this does not require a new application image. Helm values files manage these deployment settings. Teams can also configure environment specific endpoints and feature settings separately to the application artifact. ArgoCD supports GitOps based deployment by synchronising Kubernetes environments with the desired configuration stored in Git.
Each tool has a distinct responsibility:
1. Jenkins: Builds the application and publishes Docker images.
2. Amazon ECR: Stores the application images.
3. Helm: Manages deployment configuration.
4. ArgoCD: Synchronises the desired configuration with Kubernetes.
5. Kubernetes: Runs and manages the application.
For more information, explore steps to update an Amazon EKS cluster and end-to-end container hardening on Amazon EKS.
Jenkins pipelines and their responsibilities
The Jenkins setup is divided into different responsibilities rather than putting the entire release process into one pipeline. Some of the important pipelines in the flow are:
Pipeline | Purpose |
release-pipeline | Creates the release branch |
build-pipeline | Builds the application |
deploy-pipeline | Deploys the build |
approval-pipeline | Will approve tag for higher-environment promotion |
Each pipeline handles a specific responsibility, making the release process easier to follow and troubleshoot. Clear dependencies also prevent failed builds or unsuccessful QA checks from advancing to later stages.
Build once vs rebuild for every environment
Rebuild for Every Environment | Build Once |
Application is built multiple times | Application is built once |
Different artifacts can be generated | Same artifact is promoted |
Build is repeated for higher environments | Higher environments reuse the existing build |
More dependency on the build process during deployment | Deployment is separated from the build |
Harder to guarantee that Test and Production use the same build | Same artifact can be promoted |
The build-once approach does not eliminate environment-specific testing. Each environment still requires appropriate deployment checks and release controls. It simply removes unnecessary application rebuilds from the promotion process.
Best practices for reliable application promotion
A few practices help maintain consistency throughout the release lifecycle.
- Never rebuild during promotion
Reuse the existing artifact across environments. If an application change becomes necessary, create a new build and repeat the required validation.
- Separate configuration from application code
Manage environment-specific settings through Helm values and an appropriate secret-management mechanism.
- Use immutable image references
Record image tags and use the same image reference across environments.
- Enforce validation and approval gates
Prevent releases from advancing when required tests or approvals fail.
- Maintain traceability
Record the source commit, Jenkins build number, image tag, and deployment history.
For production deployments requiring advanced traffic management and service visibility, implementing a service mesh like Istio provides fine-grained control over application communication and observability.
- Plan for rollback
Retain previously approved images and maintain deployment records to support recovery when a release causes problems.
Conclusion
The build-once, deploy-anywhere approach separates application builds from deployment and promotion, helping teams maintain consistency throughout the release life-cycle. Jenkins builds the application and publishes the Docker image to Amazon ECR. The deployment pipeline delivers the image to Test, where QA performs sanity testing. After the required approvals, the team promotes the same image to UAT and Production.
Helm manages deployment configuration, Kubernetes runs the application, and ArgoCD supports GitOps-based deployments. The key principle is simple: build once, validate the artifact, and promote that same artifact across environments.
By avoiding unnecessary rebuilds and maintaining clear approval controls, teams can improve artifact consistency, simplify troubleshooting, and establish a more reliable CI/CD release process. To extend this reliability further and optimize infrastructure costs, teams can also implement intelligent Kubernetes autoscaling strategies with tools like Karpenter to automatically adjust resources based on real-time application demand.
