Courseiva
KCNAChapter 12 of 12Objective 1.2

Cloud Native Application Design Principles

How can a single application keep running smoothly when hundreds of thousands of users access it at the same time, without crashing? This is the exact problem that cloud native design principles solve, and it is one of the most important topics on the KCNA exam. Understanding these principles will help you build applications that are resilient, scalable, and easy to manage — even if you have never touched a server in your life.

12 min read
Intermediate
Updated Jul 24, 2026
Editorial oversight: Johnson Ajibi· Security Systems Architect · MSc IT Security · IEEE Senior Member

A simple way to picture Cloud Native Application Design Principles

The Restaurant Kitchen Analogy

Have you ever wondered why some restaurants can serve a perfect meal in minutes, while others collapse into chaos during a dinner rush?

Imagine running a restaurant. Traditionally, if you wanted to change the menu, you'd have to close down, repaint, replace all the stoves, and retrain every chef. That is what old-school IT did with servers: log in, manually apply patches, upgrade software, fix configs, all while praying nothing breaks.

Now, think of a modern cloud-native restaurant. Every dish is a self-contained 'pod' — a sealed, pre-prepared meal box. Each pod contains exactly the ingredients, cooking instructions, and serving plate needed. The chef never tweaks a live dish; if the recipe changes, they throw the old pod away and grab a freshly built one from the freezer. This is immutable infrastructure: you never modify a running server; you replace it entirely.

The menu itself is not a scribbled notepad. It is a digital file that declares exactly what dishes should exist, how many portions, and how they interconnect. This is a declarative deployment. The kitchen system reads the menu and makes reality match it automatically. If a dish runs out, a new one spins up. If the menu says three vegan options, the kitchen ensures three exist.

Finally, the restaurant runs on twelve golden rules: one codebase per dish, explicit ingredient lists, no secret off-menu substitutions, and logs that tell you exactly what every pod did. Those are the twelve factors. So when a beginner asks 'how can apps survive crashes and keep running?', the answer is: design them like a cloud-native kitchen.

How It Actually Works

Cloud native application design principles are a set of best practices that help developers build applications that work reliably in modern, distributed environments like the cloud. The three most important pillars are the 12-factor app methodology, immutable infrastructure, and declarative deployments. Let us break each one down from the ground up, with no assumed knowledge.

What is a cloud native application? A cloud native application is a piece of software designed specifically to run in a cloud environment — that means it can handle traffic spikes, recover from failures automatically, and be updated without downtime. Before cloud native, most applications were 'monolithic': one giant codebase that ran on a single server. If the server failed, the app went down. If you wanted to update, you took the whole app offline. Cloud native flips that model entirely: apps are broken into smaller pieces called microservices, each running in its own isolated container (like a lightweight virtual machine). Containers can be started, stopped, and moved across servers in seconds.

Twelve-factor app methodology This is a checklist of twelve rules, created by developers at Heroku, that makes applications cloud-ready. The factors are:

One codebase, one app: Every app has a single codebase tracked in version control (like Git). Different deployments (staging, production) use different copies of the same codebase, not different code.

Explicit dependencies: All libraries and tools your app needs must be declared in a manifest file (like package.json for Node.js or requirements.txt for Python). Never rely on system-level tools being present.

Configuration in the environment: Login credentials, database URLs, API keys are stored in environment variables, not hardcoded in the code. This keeps secrets secure and allows the same code to run in dev, test, and production.

Backing services as attached resources: A database, a message queue, a cache — treat these as resources you connect to via a URL, not as part of your app. If you switch from MySQL to PostgreSQL, you just change the URL.

Strict separation of build, release, run: The build stage compiles code. The release stage combines the build with config. The run stage executes the release. You never change code at runtime.

Stateless processes: Each instance of your app should be disposable. It stores no local state. Any data that must persist goes into a backing service (like a database). If an instance dies, a new one starts fresh.

Port binding: Your app should export its own HTTP server (like Express for Node.js or Flask for Python), not rely on an external web server like Apache.

Concurrency: Scale horizontally — run multiple identical copies of your app behind a load balancer, not by making one instance bigger.

Disposability: Start up quickly and shut down gracefully. If a process crashes, it should not corrupt data.

Dev/prod parity: Keep development, staging, and production environments as similar as possible to avoid surprises.

Logs as event streams: Do not manage log files. Your app writes logs to stdout (standard output) as a stream of events. The execution environment collects and routes them.

Admin processes as one-off tasks: Administrative tasks (database migrations, reports) run as isolated processes, identical to the application code, not on custom servers.

Immutable infrastructure In traditional IT, when you needed to update a server, you would ssh into it, run commands, install patches, and tweak config files. This is 'mutable' infrastructure — it changes over time. The problem is that manual changes lead to configuration drift: no two servers end up the same. A server that has been patched over 3 years might behave differently from a fresh one, causing mysterious bugs.

Immutable infrastructure means that once a server (or container) is deployed, you never change it. If you need an update, you build a new image (a frozen snapshot of the entire system), test it, and replace the old instances with the new ones. The old instances are destroyed. This guarantees that every running instance is identical. In practice, this is achieved with container images (like Docker images) and tools like Kubernetes that orchestrate rolling updates.

Declarative deployments This is closely related to immutable infrastructure. 'Declarative' means you state what you want, not how to achieve it. Instead of writing a script that says 'step 1: create server step 2: install Docker step 3: copy files step 4: start app' (that is imperative), you write a configuration file that says 'I want three copies of this app, running on port 80, with this version'. Kubernetes reads that file (often a YAML file) and makes the current state match the desired state. If one copy crashes, Kubernetes automatically starts a new one. If you change the desired state, Kubernetes handles the transition.

Why does this matter for the KCNA exam? Because cloud native is not just a buzzword — it is the foundation of modern IT infrastructure. The exam will test whether you understand the differences between these principles and older approaches, and whether you can identify situations where each principle applies.

The three pillars of cloud native application design: 12-factor methodology, immutable infrastructure, and declarative deployments.

Walk-Through

1

Understand the 12-factor app rules

Begin by memorising all twelve factors and their core idea. This foundation underpins cloud native design. For the exam, you need to recognise scenarios that violate each factor.

2

Package the application as a container image

Write a Dockerfile that defines how to build a self-contained image with the application code and all dependencies. This image is immutable — once built, it never changes.

3

Externalise all configuration

Move database URLs, API keys, and environment-specific settings into environment variables or secrets. The same container image can now run in dev, staging, and production by injecting different configs.

4

Declare the desired state in a manifest file

Write a Kubernetes YAML file that specifies the number of replicas, the container image, ports, and resource limits. This is a declarative deployment: you tell the system what you want, not how to achieve it.

5

Apply the manifest and let the orchestrator reconcile

Use a tool like kubectl apply to submit the manifest to Kubernetes. The Kubernetes control loop automatically creates the required pods, monitors their health, and replaces any that fail.

6

Perform rolling updates by replacing the image

When you need to update the application, build a new container image, push it to a registry, and update the manifest with the new image tag. Kubernetes gradually replaces old pods with new ones, ensuring zero downtime.

What This Looks Like on the Job

Imagine you are the sole IT person at a fast-growing e-commerce startup that gets featured on a popular TV show. Overnight, traffic goes from 1,000 users a day to 100,000. Your old application — a monolithic PHP app running on a single server — cannot handle the load. Users get timeouts. The server CPU is pegged at 100%. You need to redesign the app to be cloud native.

Here is what you would actually do, step by step:

First, you break the monolithic PHP app into microservices. You extract the product catalogue, the shopping cart, and the payment processing into separate codebases, each with its own Git repository. This is the 'one codebase, one app' rule from the 12 factors. Each microservice becomes a separate Docker image stored in a container registry (like Docker Hub or Google Container Registry).

Second, you move all configuration — database connection strings, API keys for Stripe, email server credentials — into environment variables. You store these in a secret management tool like Kubernetes Secrets or HashiCorp Vault. The code itself contains no passwords. This is factor 3: config in the environment.

Third, you design each microservice to be stateless. The shopping cart does not store cart data locally; every time it needs to remember a user's items, it writes to a Redis cache or a PostgreSQL database. If a shopping cart container crashes, a new one starts and reads the state from the backing service. This is factor 6: stateless processes.

Fourth, you write a Kubernetes Deployment manifest as a YAML file. It declares: 'I want three replicas of the product catalogue, each listening on port 8080.' You apply that file with kubectl apply -f manifest.yaml. Kubernetes creates three identical containers (pods) across your cluster. This is a declarative deployment. You did not write a script to create each pod; you declared the desired state and Kubernetes made it happen.

Fifth, you handle the traffic spike. Because your app is stateless and deployed declaratively, you can simply edit the YAML file to say 'replicas: 20' and reapply it. Kubernetes automatically creates 17 more pods across available servers. The load balancer distributes incoming requests to all 20 pods. No manual server provisioning.

Finally, a security vulnerability is discovered in the product catalogue code. Instead of patching the running containers (which would be mutable and risky), you rebuild the Docker image with the fix, push it to the registry, and update the YAML file with the new image tag. Kubernetes performs a rolling update: it gradually replaces old pods with new ones, ensuring zero downtime. If something goes wrong, you can roll back to the previous version instantly because the old image still exists.

In this scenario, you used every major cloud native principle: 12-factor app design, immutable infrastructure (new images, no patching of live containers), and declarative deployments (YAML manifests, Kubernetes reconciliation).

How KCNA Actually Tests This

The KCNA exam (objective 1.2) will test your understanding of three specific areas: 12-factor apps, immutable infrastructure, and declarative deployments. Here is exactly what you need to know for each.

12-factor app methodology The exam loves to list the twelve factors and ask you to match a scenario to the correct factor. For example, a question might describe 'an application that stores database passwords in the source code' and ask which 12-factor rule is violated. The answer is factor 3: 'Config in the environment'. You must memorise all twelve factors by name and what each one means. Trap: the exam might describe a scenario that sounds like one factor but actually describes another. For instance, 'using a different database in development than in production' violates factor 10 (dev/prod parity), not factor 4 (backing services). Practise distinguishing between them. - Key factor definitions to memorise: factor 2 (dependencies), factor 6 (stateless processes), factor 9 (disposability), factor 11 (logs as event streams). - Trap pattern: the exam may present 'logs are written to a file on the local disk' as a correct practice. It is not — logs must be written to stdout (factor 11). - Trap pattern: 'admin tasks run on a separate server with different configuration' — that violates factor 12 (admin processes run identically to app code).

Immutable infrastructure The exam will ask you to compare mutable vs immutable approaches. Expect a question like: 'Which approach ensures that every instance of an application is identical?' Answer: immutable infrastructure. You must know that immutable infrastructure rebuilds from a golden image rather than patching running servers. - Key concept: a container image is immutable. Once built, you do not modify it. If you need to change something, you build a new image and replace the running containers. - Trap pattern: 'You can SSH into a running container to debug an issue' — while possible, this is not immutable best practice. Immutable means you should treat containers as disposable and debug by checking logs, not by logging in. - Trap pattern: 'Immutable infrastructure is slow because you always have to rebuild everything.' The reality is that building new images is automated and fast (seconds to minutes), and the benefits of consistency far outweigh the cost.

Declarative deployments The exam will test the difference between declarative and imperative approaches. A typical question: 'An administrator writes a script that runs commands to create a server, install software, and start a service. Is this declarative or imperative?' Answer: imperative. Declarative means you define the desired end state, not the steps. - Key concept: Kubernetes uses a declarative model. You write YAML files describing what you want, and the Kubernetes control loop (the reconciliation loop) continuously makes the current state match the desired state. - Trap pattern: 'Declarative deployments require more manual work.' In fact, declarative deployments reduce manual work because you let the system handle change automatically. - Trap pattern: 'Applying a YAML file is the same as running kubectl create.' Not exactly — kubectl create is imperative (you are telling Kubernetes to create a specific resource). kubectl apply is declarative (you are telling Kubernetes to make the cluster match the configuration file).

Expect 2-3 questions on this objective in the exam. They are usually scenario-based: you read a short description and choose which principle applies, or identify which 12-factor rule is being described.

Key Takeaways

The 12-factor app methodology ensures cloud native applications are portable, scalable, and resilient across different environments.

Immutable infrastructure means you never modify a running server or container; you replace it entirely with a new image.

Declarative deployments use configuration files to specify the desired state, and the system automatically reconciles the current state to match.

A stateless process (factor 6) stores no local data, relying entirely on backing services for persistence, which enables horizontal scaling and crash recovery.

In cloud native design, logs are treated as a stream of events written to stdout, not as files managed by the application itself.

The difference between declarative and imperative is 'what vs how': declarative states the goal, imperative lists the steps to achieve it.

Easy to Mix Up

These come up on the exam all the time. Here's how to tell them apart.

Immutable Infrastructure

Servers/containers are never modified in place; they are replaced with new images.

Configuration is baked into the image at build time, ensuring consistency.

Rollbacks are simple: redeploy the previous image.

Mutable Infrastructure

Servers are updated via SSH or management tools (patch, upgrade, edit).

Configuration drifts over time as different servers receive different patches.

Rollbacks are difficult because the old state may not be reproducible.

Declarative Deployments

You define the desired end state in a config file (YAML/JSON).

The system automatically handles the steps to reach the desired state.

Idempotent: applying the same config multiple times produces the same result.

Imperative Deployments

You write a script with step-by-step commands (create, install, start).

You are responsible for handling errors and ensuring correct ordering.

Not inherently idempotent: running the script twice might cause errors.

12-Factor App (Stateless)

Each process instance is disposable and stores no local state.

Horizontal scaling is straightforward: add more instances behind a load balancer.

Failures are isolated; one instance crashing does not affect others.

Traditional Monolith (Stateful)

The application stores user session data, files, or cache on the local filesystem.

Scaling typically requires vertical scaling (more CPU/RAM on the same server).

If the single server crashes, all state is lost and the entire app goes down.

Watch Out for These

Mistake

Cloud native means the application must run on a public cloud like AWS or Azure.

Correct

Cloud native is an approach to designing applications; it does not require a specific cloud provider. You can run cloud native apps on-premise, in a private data centre, or on any cloud.

The word 'cloud' in 'cloud native' misleads beginners into thinking it is about a specific vendor rather than architectural patterns.

Mistake

Immutable infrastructure means you never update your software.

Correct

It means you never update a running instance; you replace it with a new updated one. Updates still happen, but via full image replacements rather than in-place patches.

The word 'immutable' sounds like 'unchanging', so beginners think updates are forbidden. The focus should be on the method of updating, not the absence of change.

Mistake

The 12-factor app rules are only for new applications; you cannot apply them to existing apps.

Correct

You can incrementally refactor an existing monolithic app to follow 12-factor principles. Many organisations migrate legacy apps by extracting microservices one at a time.

Beginners see the list as an all-or-nothing requirement, but the principles are guidelines that can be adopted gradually.

Mistake

Declarative deployments mean you write no scripts at all.

Correct

Declarative deployments still involve writing configuration files and sometimes scripts to generate those files. The key difference is that the configuration describes the desired state, not the procedural steps.

People hear 'declarative' and think it means 'no coding'. In fact, you still write YAML or JSON — you just write 'what' instead of 'how'.

Mistake

Containers and virtual machines are basically the same thing.

Correct

Containers share the host OS kernel and are lightweight (megabytes), while VMs each run a full OS (gigabytes). This difference directly impacts how cloud native apps are packaged and deployed.

Both provide isolation, so beginners assume they are interchangeable, but the architectural implications — especially for immutability and disposability — are very different.

Do You Actually Know This?

Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.

Frequently Asked Questions

What is the difference between immutable and mutable infrastructure?

Mutable infrastructure allows in-place changes (like SSHing into a server to install a patch). Immutable infrastructure replaces the entire server or container with a new one that has the changes baked in.

Do I need to use Kubernetes to have immutable infrastructure?

No, but Kubernetes makes it much easier. You can implement immutable infrastructure with other tools like Docker Swarm, Nomad, or even manual scripts, but Kubernetes provides built-in orchestration for rolling updates and self-healing.

What happens if a 12-factor app crashes?

Because it is stateless and writes logs to stdout, a new instance can be started quickly with no data loss (assuming the backing database is unaffected). The orchestrator detects the crash and restarts a new container automatically.

Is 'cloud native' the same as 'microservices'?

No. Microservices is one way to architect cloud native applications, but cloud native also includes principles like immutable infrastructure, declarative deployments, and the 12-factor methodology. A cloud native app can be a monolith if it follows the 12 factors.

Can I apply 12-factor principles to a legacy .NET application?

Yes, but it requires work. You would need to externalise config, remove local file storage, and refactor state into a database. Many organisations do this gradually by extracting one microservice at a time.

What is a 'backing service' in the 12-factor app context?

A backing service is any service the app consumes over the network as part of its normal operation — databases, message queues, caches, email services, etc. They are treated as attached resources, accessed via a URL or connection string.

Terms Worth Knowing

Keep going

You've finished Cloud Native Application Design Principles. Continue through the KCNA study guide to build a complete picture of the exam.

Done with this chapter?