Containerization

Containerization: CI/CD Pipelines for 12-Factor Applications

In my last posts, I covered how the 12-Factor methodology shapes modern applications, and how Spring Boot helps translate those principles into production-ready microservices. Once the application foundation is in place, the next step is to automate build, test, and quality checks — ensuring every change is consistent, reliable, and deployment-ready.

This post focuses on CI/CD as the enabler of discipline and quality, while containerization and orchestration will be covered in the next post.

1. Automate the Build

  • Use Maven to manage dependencies and standardize builds.
  • Leverage Jenkins to automate compilation, packaging, and artifact generation.
  • Ensure the build process is repeatable and deterministic, so the same code produces the same artifact across environments.
  • Package applications into JAR / WAR files as the unit of deployment.

Automated builds with Jenkins create a foundation where every commit can be compiled, packaged, and verified without manual steps.

2. Embed Quality Gates

Quality gates enforce standards and catch issues early:

  • SonarQube: code smells, duplication, and standards enforcement.
  • CAST: architecture compliance and technical debt tracking.
  • Checkmarx: security vulnerability scanning to shift security left.
  • Unit & Integration Tests: automated tests with coverage thresholds prevent regressions.

Integrating these tools into Jenkins pipelines ensures the CI/CD process is not just a delivery mechanism but a quality enforcer.

3. Align Environments

CI/CD ensures consistent execution across dev, staging, and production:

  • Automates environment setup and configuration.
  • Injects secrets securely, avoiding hardcoding.
  • Externalizes environment-specific values, aligning with 12-Factor principles like config separation and parity across environments.

4. Extend Beyond Functional Requirements

CI/CD is also the right place to embed non-functional requirements (NFRs):

  • Logging streamed to Splunk for centralized analysis.
  • Monitoring with Datadog for observability and alerting.
  • Messaging pipelines integrated with Kafka for scalability and decoupling.

Automation here ensures applications are production-ready, not just feature-complete.

5. Prepare for Containerization

Once builds pass all gates, the artifacts are fully production-ready. These artifacts — whether JARs or WARs — serve as the foundation for the next stage: packaging into Docker containers. Containers make applications portable, immutable, and easily deployable, bridging CI/CD with orchestration in Kubernetes, the focus of the next post.

Automation is not just about speed; it’s about consistency, discipline, and trust. A robust CI/CD pipeline, implemented in Jenkins, enforces 12-Factor practices, embeds NFRs, and accelerates feedback loops while reducing human error.

With build, test, and quality gates in place, teams are ready to containerize applications with Docker and orchestrate them with Kubernetes, moving one step closer to cloud-native microservices.

Containerization: Building 12-Factor Microservices with Spring Boot

In my last post, I explored how the 12-Factor App principles serve as a blueprint for building cloud-ready applications. In this post, I shift focus to a practical enabler of those principles: Spring Boot.

Spring Boot has become the go-to framework for building microservices-based applications that are cloud-native and production-ready. Why? Because it brings together the power of the Spring ecosystem with a level of developer productivity that directly aligns with 12-Factor principles.

Spring Boot is built on top of the Spring framework, which itself provides several foundational advantages:

  • Dependency Injection: Spring’s core feature, simplifying the management of components and making applications loosely coupled and testable.
  • Spring MVC: A module that streamlines the creation of web applications and REST APIs, which are fundamental in microservices architectures.

Spring Boot takes these strengths further by accelerating application development and production readiness:

  • Rapid development: Through Spring Initializr, starter projects, auto-configuration, and developer tools, teams can bootstrap applications quickly.
  • Production-ready by design: Spring Boot accelerates key non-functional requirements (NFRs):
    • Logging and error handling baked in.
    • Profiles and configuration properties to separate environments cleanly.
    • Actuator for health checks and monitoring.
    • Embedded servers for simplified deployment.

This combination allows teams not only to build apps quickly but also to meet the robustness, scalability, and observability expectations of modern cloud environments.

Building a 12-Factor App with Spring Boot
Spring Boot provides out-of-the-box support to implement each of the 12-Factor principles in practice. A few highlights:

  • Codebase: Use Git for a single codebase per service, keeping our Spring Boot app modular and clean.
  • Dependencies: Declared explicitly in pom.xml using Spring Boot starters.
  • Config: Externalized with application.properties or application.yml, augmented with profiles for environment-specific values.
  • Backing services: Treat databases, message brokers, and caches as attached resources. For example, integrate Kafka for event streaming and inject it via configuration rather than hardcoding.
  • Processes: Applications run as stateless processes, packaged into lightweight containers with Docker, and deployed onto Kubernetes for orchestration, scaling, and resilience.
  • Logs: Streamed to standard output and shipped to tools like Splunk for centralized analysis and alerting.
  • Admin/management: Exposed via Spring Boot Actuator endpoints, and extended with observability platforms like Datadog to monitor performance, reliability, and resilience.

By mapping Spring Boot’s features directly to the 12-Factor methodology, we move beyond theory into tangible implementation.

Spring Boot doesn’t just speed up development—it embeds cloud-native best practices into the foundation of our applications. When combined with CI/CD, Docker, Kubernetes, Kafka, Splunk, and Datadog, it becomes a powerful accelerator for building scalable, portable, and resilient microservices.

Containerization: Practical Steps for CI/CD, Containers and Kubernetes

In my last post, I revisited the 12-Factor App Principles – a blueprint for building applications that are portable, resilient, and scalable. This post takes the next step: how do we actually build containerized apps that bring those principles to life? I have been exploring this journey for a while: starting with a Spring Boot application, applying 12-Factor discipline, and then setting up pipelines, containers, and orchestration. Here are the four high-level steps for moving from principles to practice.

1. Build the application with 12-factor principles

An app needs to be designed for the cloud from day one:

  • A clean codebase tracked in version control.
  • Explicitly declared dependencies (no hidden assumptions).
  • Config externalized into the environment—not baked into code.
  • Stateless processes that can scale horizontally.
  • Logs treated as event streams, not files.

This ensures the foundation is right before we even think about containers.

2. Automate build & quality gates via CI/CD

A reliable build pipeline is the backbone of cloud-ready apps. This is where we codify consistency and quality:

  • Use Maven or Gradle to manage dependencies and standardize builds.
  • Leverage Jenkins to automate compilation, packaging, and artifact generation.
  • Code quality checks via SonarQube (for code smells, duplication), CAST (for architecture, technical debt, and maintainability), and Checkmarx (for security vulnerabilities).
  • Test coverage integrated into the pipeline to catch regressions early.
  • Environment setup so dev, staging, and prod remain aligned.

This is also the right stage to embed non-functional requirements – such as security, performance, and maintainability – into the software delivery lifecycle.

3. Containerize the Application

Once the pipeline is humming, the next step is to containerize:

  • Write a Dockerfile that packages our app into a lean, immutable image.
  • Follow best practices: use minimal base images, avoid hardcoding secrets, and leverage multi-stage builds.
  • Validate disposability: fast startup, graceful shutdown, and statelessness.

The container becomes the unit of deployment, fully aligned with the principles we started with.

4. Orchestrate & Deploy

Finally, deploy the containerized app in an orchestrated environment:

  • Deploy to Kubernetes for enterprise-grade orchestration – scaling, self-healing, and rolling updates.
  • Manage configuration using ConfigMaps (non-sensitive configs like DB hostnames, log levels) and Secrets (sensitive values like passwords, tokens, certificates). This approach ensures container images remain immutable, while environment-specific values are injected securely at runtime.
  • Validate resilience: scale pods up and down, perform rolling upgrades, and monitor logs as event streams.

This step is where our app truly becomes cloud-native: portable across environments, scalable under load, and manageable at enterprise scale.

The 12-Factor methodology comes to life when combined with automation, containerization, and orchestration. By following these four steps, teams move from abstract principles to concrete, cloud-ready deployments.

Containerization: 12-Factor App Principles

One of my blog readers reminded me recently that it has been a while since he saw a tech piece from me. In parallel, I have been immersed in containerization work and it gave me the nudge to reflect on how we design and build modern, cloud-ready applications. This post marks the beginning of a blog series where I will walk through the journey of building a versatile application: from principles to deployment.

We will start with the foundations – The 12-Factor App Principles. From there, we will move into a hands-on Spring Boot app (Java is still home turf for me), then look at containerizing it with Docker, and finally deploying on Kubernetes. I believe that writing software today is no longer just about what the app does, but how it runs anywhere—with consistency, reliability, and scalability.

Why 12-Factor Still Matters

Introduced in 2011 by Heroku, the 12-Factor methodology offers a pragmatic blueprint for building SaaS applications that are portable and resilient. For those of us who grew up in the world of monoliths and app servers, this feels like the architectural decluttering we always needed but did not know how to articulate.

Let’s briefly explore each of the 12 principles as a set of operating philosophies that guide how we write, organize, and deploy our code in a modern landscape.

  1. Codebase – One codebase per app that serves many deploys from configurations.
  2. Dependencies – Explicitly declare and isolate dependencies.
  3. Config – Store config in the environment and not the code.
  4. Backing Services – Treat backing services as attached resources.
  5. Build, Release, Run – Strictly differentiate build, release and run stages.
  6. Processes – Execute app as one or more stateless processes.
  7. Port Binding – Expose services through port binding.
  8. Concurrency – Scale out by running more instances. This principle will come alive when we get to Kubernetes.
  9. Disposability – Fast startup and graceful shutdown to maximise robustness.
  10. Dev / Prod Parity – Keep development, staging and production as similar as possible.
  11. Logs – Treat logs as event streams.
  12. Admin Processes – Run admin / management processes as one-off tasks independently.

The 12-Factor methodology lays the foundation for building applications that are portable, resilient, and scalable. In the next post, we will bring these principles to life with a Spring Boot project designed with the cloud in mind.