We closed the previous lesson saying you already had a cluster, a CLI and the language of manifests, and that all that was missing was the patient. Here it is. This lesson introduces Rutas Norte S.L. in depth, the fictional company whose coach ticket sales platform we are going to deploy and operate on Kubernetes across the eleven remaining modules. It is not a decorative example: every concept you learn from now on will enter the stage because Rutas Norte needs it, and by the end of the course you will have a complete platform —secure, observable and autoscaled— built piece by piece. You will see the company's starting position, each of its six components, the target architecture, the map of which module contributes what, and the conventions we will always follow. And you will finish with the first real deployment: web-store running in your cluster and responding in your browser.

Contents

  1. The company and its current problem
  2. The six components of the platform
  3. The target architecture on Kubernetes
  4. Roadmap: what each module contributes
  5. Project conventions
  6. The first deployment: web-store in rutas-norte-dev
  7. Why this pod is fragile

  1. The company and its current problem

Rutas Norte S.L. is an intercity coach operator that sells its tickets online through the Rutas Norte platform. Thirteen people in the technical department, around 4,000 bookings a day on average and 25,000 on peak days.

Its current infrastructure:

  • Two rented machines with Docker Compose. One serves the website and the API; the other, the database.
  • Manual deployments: somebody connects over SSH, runs docker compose pull && docker compose up -d and crosses their fingers. There is a service outage of one to two minutes, so deployments only happen in the small hours of Tuesday.
  • No self-healing: in March, the API container died at 02:40 from a memory leak and nobody noticed until 07:15. Four and a half hours with no ticket sales.
  • No elasticity: at bank-holiday and holiday peaks, traffic multiplies sixfold. The answer so far has been to rent a machine sized for August and pay for it all twelve months.
  • Secrets everywhere: the PostgreSQL password lives in a .env file that has been shared by email. That database contains the name, ID number, phone and email of every customer.
  • No observability: logs are in files inside each container. Diagnosing a problem means going in over SSH and searching with grep.

The technical leadership has approved the migration to Kubernetes with four measurable goals: zero downtime on deployments, automatic recovery from failures, elastic capacity at the peaks and traceability and access control over personal data. Those four goals are, one by one, the syllabus ahead of you.

  1. The six components of the platform

These names will stay with you throughout the course. Keep them exactly as they are.

2.1. web-store

  • What it is: the public front end. An SPA served by nginx with the search results, the seat picker and the payment process.
  • State: stateless. Any replica serves any request.
  • Image: registry.rutasnorte.example/web-store:1.8.0
  • Domain: www.rutasnorte.example
  • What it needs from the cluster: several replicas, HTTP/HTTPS exposure to the outside world, injected configuration (the API URL varies per environment) and downtime-free updates.

2.2. bookings-api

  • What it is: the REST API in Node.js. It checks seat availability, calculates prices, creates bookings and issues tickets. It is the heart of the business.
  • State: stateless. All persistence lives in PostgreSQL and Redis.
  • Image: registry.rutasnorte.example/bookings-api:2.4.0
  • Domain: api.rutasnorte.example
  • What it needs from the cluster: replicas, autoscaling by load, database credentials as a secret, health probes, resource limits and restricted access to the database.

2.3. bookings-postgres

  • What it is: PostgreSQL 16 with the tables for bookings, customers, routes and departures.
  • State: stateful. It is the system's critical component.
  • Image: postgres:16
  • What it needs from the cluster: persistent storage that survives the pod being recreated, a stable network identity, credentials managed as a secret, backups and a network policy that stops just anyone connecting to it.

2.4. redis-cache

  • What it is: an in-memory cache of seat availability by departure and date. It absorbs most of the search queries and stops PostgreSQL being overwhelmed.
  • State: stateful, but expendable. If it is lost, it is repopulated from the database; only performance degrades, and only for a few minutes.
  • Image: redis:7.2-alpine
  • What it needs from the cluster: a stable name, strict memory limits and eviction policy configuration.

2.5. notifications-worker

  • What it is: a background process that consumes a queue and sends booking confirmation emails and journey reminders.
  • State: stateless, but it receives no inbound traffic: it does not need to be reachable from outside.
  • Image: registry.rutasnorte.example/notifications-worker:1.2.0
  • What it needs from the cluster: replicas scaled by queue length rather than by CPU, SMTP credentials as a secret, and a graceful shutdown so no send is lost halfway.

2.6. occupancy-reports

  • What it is: a scheduled task that every night at 02:30 calculates the previous day's occupancy by line and departure and leaves a report for the commercial department.
  • State: stateless, finite in execution: it starts, works for a few minutes and finishes.
  • Image: registry.rutasnorte.example/occupancy-reports:1.0.3
  • What it needs from the cluster: scheduled execution, retry control, a limit on concurrent runs and a history of results.

Comparative summary

Component State Inbound traffic Kubernetes object that will govern it Module
web-store Stateless Public (HTTP) Deployment + Service + Ingress 2, 4
bookings-api Stateless Public (HTTP) and internal Deployment + Service + Ingress + HPA 2, 4, 9
bookings-postgres Stateful Internal only, restricted StatefulSet + PVC + headless Service 5, 6
redis-cache Expendable state Internal only Deployment or StatefulSet + Service 2, 5
notifications-worker Stateless None Deployment (no Service) + KEDA 2, 9
occupancy-reports Stateless, finite None CronJob 6

That table already contains a design lesson: the type of Kubernetes object you need follows from two questions —is it stateful? and does it receive traffic?— before you write a single line of YAML.

  1. The target architecture on Kubernetes

This is the destination we will reach by the end of module 11.

flowchart TB
    U["Customers<br/>browser and mobile"]
    DNS["DNS<br/>www / api .rutasnorte.example"]
    U --> DNS

    subgraph CL["Kubernetes cluster"]
        ING["Ingress Controller<br/>TLS with cert-manager"]

        subgraph NS["namespace rutas-norte-pro"]
            SVCW["Service web-store"]
            SVCA["Service bookings-api"]
            TW1["Pod web-store"]
            TW2["Pod web-store"]
            API1["Pod bookings-api"]
            API2["Pod bookings-api"]
            API3["Pod bookings-api"]
            SVCR["Service redis-cache"]
            RED["Pod redis-cache"]
            SVCP["Service bookings-postgres"]
            PG["StatefulSet<br/>bookings-postgres-0"]
            PVC[("PVC 20 GiB")]
            WK1["Pod notifications-worker"]
            WK2["Pod notifications-worker"]
            CJ["CronJob<br/>occupancy-reports"]
        end
    end

    DNS --> ING
    ING --> SVCW
    ING --> SVCA
    SVCW --> TW1
    SVCW --> TW2
    SVCA --> API1
    SVCA --> API2
    SVCA --> API3
    API1 --> SVCR
    API2 --> SVCR
    API3 --> SVCP
    SVCR --> RED
    SVCP --> PG
    PG --- PVC
    WK1 --> SVCP
    WK2 --> SVCP
    CJ --> SVCP

Points worth reading in the diagram:

  • A single front door: the Ingress Controller terminates TLS and routes by domain to the matching Service.
  • No component knows any IPs: everything communicates through the Service name, resolved by the cluster's internal DNS.
  • bookings-postgres is the only one with a persistent disk, and it must only be reachable from bookings-api, the worker and the CronJob. That will be enforced with a NetworkPolicy in module 4.
  • notifications-worker has no Service: nobody talks to it, it consumes work and goes out to talk to others.

  1. Roadmap: what each module contributes

This table is the course's contract: it says which piece of Rutas Norte we add or improve in each module.

Module What is added or improved in Rutas Norte
1. Introduction The practice cluster, the conventions, the rutas-norte-dev namespace and the first web-store pod
2. Core components web-store and bookings-api as Deployments with replicas; internal Services; downtime-free version updates and rollback; separation into namespaces per environment
3. Configuration and secrets Store and API configuration in ConfigMaps; the PostgreSQL password and SMTP credentials in Secrets; requests and limits on every component; quotas per environment; dedicated ServiceAccounts
4. Networking Publishing www.rutasnorte.example and api.rutasnorte.example with Ingress and TLS; internal DNS between components; a NetworkPolicy isolating bookings-postgres
5. Storage A persistent volume for the database via PVC and StorageClass; volume expansion; backup and restore of the bookings
6. Advanced concepts bookings-postgres migrated to a StatefulSet; occupancy-reports as a CronJob; an init container that waits for the database; a metrics sidecar; a log agent as a DaemonSet
7. Monitoring and logging Liveness and readiness probes on every component; kubectl top; Prometheus and Grafana with a bookings-per-minute dashboard; centralized logs; incident debugging
8. Security RBAC per team and environment; unprivileged containers with a read-only filesystem; Pod Security Standards; network hardening; image signing and scanning
9. Scaling and performance HPA on bookings-api for the bank-holiday peaks; VPA for sizing; node autoscaling; scaling notifications-worker by queue length with KEDA; PodDisruptionBudgets
10. Ecosystem Packaging the platform with Helm; per-environment variants with Kustomize; continuous deployment with GitOps; moving to a managed cluster
11. Real-world cases The full production rollout; a CI/CD pipeline; a canary deployment of an API version; daily operations, runbooks and cost control
12. Certification A cross-cutting review aimed at CKA, CKAD and CKS using the platform as a test bed

  1. Project conventions

These rules apply in every lesson. Adopt them from now on; they are also real-world good practice.

5.1. Namespaces per environment

Namespace Use Who deploys
rutas-norte-dev Development. Fictional data, reduced resources Anyone on the team
rutas-norte-pre Pre-production. A faithful replica of production for validation The automated pipeline
rutas-norte-pro Production. Real customer data Only the pipeline, with approval

Throughout module 1 and much of module 2 we will work only in rutas-norte-dev.

5.2. Labelling scheme

Every object carries at least these three labels:

metadata:
  labels:
    app: web-store                           # the component
    app.kubernetes.io/part-of: rutas-norte   # the whole platform
    environment: dev                         # the environment

This enables queries like these, which are worth their weight in gold as the cluster grows:

kubectl get all -l app.kubernetes.io/part-of=rutas-norte -n rutas-norte-dev
kubectl get pods -l environment=pro -A
kubectl logs -l app=bookings-api -n rutas-norte-dev --tail=50

5.3. Registry and images: immutable tags

The company's image registry is registry.rutasnorte.example. The project's most important rule when it comes to images:

Every version is published with a unique, immutable tag that is never reused. latest is forbidden in every environment.

Reference Valid? Why
registry.rutasnorte.example/bookings-api:2.4.0 Yes A semantic version, immutable
registry.rutasnorte.example/bookings-api:2.4.0-a3f9c1b Yes, better It includes the commit: full traceability
registry.rutasnorte.example/bookings-api@sha256:9f3a1c... Yes, the strictest A digest: impossible to impersonate
registry.rutasnorte.example/bookings-api:latest No Two replicas of the same Deployment can end up running different code; rollback stops being reliable and you do not know what is in production

5.4. Repository structure

The one we defined in the lesson Objects, YAML Manifests and the Declarative Model:

rutas-norte/
└── k8s/
    ├── base/                # common definition
    ├── environments/
    │   ├── dev/
    │   ├── pre/
    │   └── pro/
    ├── local-environment/
    └── README.md

And the golden rule that goes with it: if a change is not in Git, it does not exist. No kubectl edit as a deployment method.

  1. The first deployment: web-store in rutas-norte-dev

Enough theory. Let us deploy the first real piece of Rutas Norte.

Step 1: check the cluster

minikube status --profile=rutas-norte
kubectl config current-context
rutas-norte
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured

rutas-norte

Step 2: create the namespace declaratively

# k8s/base/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: rutas-norte-dev
  labels:
    app.kubernetes.io/part-of: rutas-norte
    environment: dev
kubectl apply -f k8s/base/namespace.yaml
kubectl get namespace rutas-norte-dev
namespace/rutas-norte-dev created

NAME              STATUS   AGE
rutas-norte-dev   Active   3s

Note that we created it with a manifest, not with kubectl create namespace. That is a deliberate decision: the namespace is part of the project's definition and must be in Git like everything else.

And now, the productivity tip from lesson 01-05, which will save you typing -n rutas-norte-dev hundreds of times:

kubectl config set-context --current --namespace=rutas-norte-dev

Step 3: write the pod manifest

# k8s/base/web-store-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: web-store
  namespace: rutas-norte-dev
  labels:
    app: web-store
    app.kubernetes.io/part-of: rutas-norte
    environment: dev
  annotations:
    rutasnorte.example/owner: [email protected]
spec:
  containers:
    - name: nginx
      image: nginx:1.27-alpine
      ports:
        - name: http
          containerPort: 80
      resources:
        requests:
          cpu: "50m"
          memory: "64Mi"
        limits:
          cpu: "200m"
          memory: "128Mi"

A field-by-field review, leaning on what we have learned:

  • apiVersion: v1 and kind: Pod: the Pod belongs to the core group, which is why it carries no group prefix.
  • metadata.name: a unique name within the namespace.
  • metadata.labels: the project's three labels. In module 2 they will be the ones the Service uses to find its pods.
  • metadata.annotations: informational metadata, not queryable.
  • spec.containers: a list. Here a single element, as will be usual.
  • image: nginx:1.27-alpine: we use the public nginx image because registry.rutasnorte.example is a fictional registry and does not exist. Throughout the course, whenever an image from registry.rutasnorte.example appears, mentally substitute —and substitute in your cluster— its public equivalent. An explicit tag, never latest, in line with the project convention.
  • ports: this is informational documentation; it opens nothing by itself. Real exposure will come with the Service (module 2).
  • resources: requests is what the scheduler reserves in order to decide which node it fits on; limits is the ceiling the kubelet enforces. We will study them thoroughly in module 3, but it is worth setting them from day one.

Step 4: validate and apply

kubectl apply -f k8s/base/web-store-pod.yaml --dry-run=client
kubectl apply -f k8s/base/web-store-pod.yaml
pod/web-store created (dry run)
pod/web-store created

Step 5: watch it start

kubectl get pods -w
NAME        READY   STATUS              RESTARTS   AGE
web-store   0/1     Pending             0          0s
web-store   0/1     ContainerCreating   0          1s
web-store   1/1     Running             0          4s

You are watching, live, the walkthrough from the lesson Kubernetes Architecture: Pending while the scheduler picks a node, ContainerCreating while the kubelet pulls the image and prepares the networking, Running when the container is alive. Stop it with Ctrl+C.

Step 6: inspect

kubectl get pod web-store -o wide
NAME        READY   STATUS    RESTARTS   AGE   IP           NODE          NOMINATED NODE
web-store   1/1     Running   0          45s   10.244.0.21  rutas-norte   <none>
kubectl describe pod web-store
Name:         web-store
Namespace:    rutas-norte-dev
Node:         rutas-norte/192.168.49.2
Labels:       app=web-store
              app.kubernetes.io/part-of=rutas-norte
              environment=dev
Status:       Running
IP:           10.244.0.21
Containers:
  nginx:
    Image:          nginx:1.27-alpine
    Port:           80/TCP
    State:          Running
    Ready:          True
    Restart Count:  0
    Limits:         cpu: 200m, memory: 128Mi
    Requests:       cpu: 50m, memory: 64Mi
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  50s   default-scheduler  Successfully assigned rutas-norte-dev/web-store to rutas-norte
  Normal  Pulled     49s   kubelet            Container image "nginx:1.27-alpine" already present on machine
  Normal  Created    49s   kubelet            Created container nginx
  Normal  Started    49s   kubelet            Started container nginx

The four events tell the whole story: the scheduler assigned a node, and then the kubelet obtained the image, created the container and started it. Exactly the division of responsibilities we studied.

kubectl logs web-store --tail=5
/docker-entrypoint.sh: Configuration complete; ready for start up
2026/08/05 10:22:14 [notice] 1#1: nginx/1.27.0
2026/08/05 10:22:14 [notice] 1#1: start worker processes

Step 7: see it in the browser

The pod has the IP 10.244.0.21, but that IP only exists inside the cluster. To reach it from your machine we use port-forward:

kubectl port-forward pod/web-store 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80

Open http://localhost:8080 in your browser: you will see the nginx welcome page. In Rutas Norte, that would be the ticket store's home page. Leave the command running while you test and stop it with Ctrl+C.

From another terminal you can also check it without a browser:

curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8080
200

Congratulations: you have just deployed the first Rutas Norte component on Kubernetes.

  1. Why this pod is fragile

Before celebrating too much, let us run the experiment that gives module 2 its meaning.

kubectl delete pod web-store
kubectl get pods
pod "web-store" deleted

No resources found in rutas-norte-dev namespace.

It has vanished and it does not come back. Compare that with what we said in the concepts lesson: a loose pod has no controller watching it. Nobody runs a reconciliation loop over it, because the desired state you declared was literally "let this pod exist", and by deleting it you also deleted that declaration.

The four problems with a loose pod:

Problem Consequence for Rutas Norte
It is not recreated if it dies It reproduces exactly the four-and-a-half-hour overnight outage the company suffered in March
It cannot be scaled To have three copies you would have to write three manifests with three different names
It cannot be updated without downtime Changing the image means deleting and recreating: there is an interval with no service
It has no stable address Every recreation changes the IP, and nobody knows where to connect

The solution is the hierarchy you already know from the conceptual map: Deployment → ReplicaSet → Pod. A Deployment declares "I want 3 replicas of this image", the ReplicaSet keeps them alive come what may, and a Service gives them a stable name.

Recreate the pod to leave the cluster as it was and close the module with the platform up and running:

kubectl apply -f k8s/base/web-store-pod.yaml
kubectl get pods
pod/web-store created

NAME        READY   STATUS    RESTARTS   AGE
web-store   1/1     Running   0          5s

Common Mistakes and Tips

  • Applying in the wrong namespace. If kubectl get pods shows nothing, check the namespace with kubectl config view --minify | grep namespace or use -A. Declaring metadata.namespace explicitly in every manifest, as we do here, removes the problem at the root.
  • Using registry.rutasnorte.example literally. It is a fictional registry: it does not exist. The pod would sit in ImagePullBackOff. In the practical exercises always use the equivalent public image (nginx, postgres, redis, node).
  • Believing ports.containerPort exposes the pod. It does nothing by itself: it is documentation. Real access comes with port-forward (for testing), a Service (module 2) or an Ingress (module 4).
  • Settling for port-forward as the solution. It is a single-user debugging tool, tied to your terminal. It is never a way to expose a service.
  • Creating loose pods and getting used to it. This has been a deliberate exercise to understand the fragility. From module 2 onwards, everything goes in Deployments.
  • Forgetting resources. Without requests, the scheduler cannot plan properly; without limits, a runaway container can take down its neighbours. Set them from the start even if the tuning comes later.
  • Tip: create the repository with the k8s/ structure right now and make a commit with namespace.yaml and web-store-pod.yaml. Working this way from the very first lesson is the difference between finishing the course with a reproducible platform and finishing with a cluster full of things nobody knows how were created.

Exercises

Exercise 1: Designing the platform on paper

Without writing any manifest, complete a table with the six Rutas Norte components and, for each one, answer: (a) is it stateful?, (b) does it receive inbound traffic and from where?, (c) which Kubernetes object will govern it?, and (d) what would happen today, with Docker Compose, if the machine hosting it were shut down? Then justify in three lines why redis-cache and bookings-postgres, both being "stateful", get very different treatment.

Exercise 2: Deploying and exploring redis-cache

Following every project convention, create the manifest k8s/base/redis-cache-pod.yaml for a redis-cache pod in rutas-norte-dev with the public image redis:7.2-alpine, port 6379, the project's three labels and requests of 50m of CPU and 64Mi of memory. Then:

  1. Validate it without touching the cluster and apply it.
  2. Check that it is Running and find out its IP and its node.
  3. Get into the container and check that Redis responds by running redis-cli ping.
  4. Show only the Rutas Norte platform pods using the common label.

Exercise 3: Demonstrating the fragility and anticipating the solution

  1. Simulate an application crash by killing the main process of the web-store container with kubectl exec, and watch what happens with --watch. Does the container come back? Does the RESTARTS counter change? Does the pod's IP change?
  2. Now delete the whole pod with kubectl delete pod and watch again. Does it come back?
  3. Explain the difference between the two cases, stating which component acts in each.
  4. Write in two sentences which object you would need for the second case to also recover on its own.

Solutions

Solution 1

Component (a) State (b) Inbound traffic (c) Object (d) If the machine goes down today
web-store No Public, from the internet Deployment + Service + Ingress The website stops responding entirely
bookings-api No Public and internal Deployment + Service + Ingress + HPA Bookings can neither be queried nor created
bookings-postgres Yes Internal, restricted StatefulSet + PVC A total outage and a risk of data loss if the disk is not replicated
redis-cache Yes, expendable Internal Deployment or StatefulSet + Service Performance degradation; the service continues with direct database queries
notifications-worker No None Deployment (no Service) Confirmation emails pile up unsent
occupancy-reports No, finite None CronJob The overnight report is not generated

redis-cache and bookings-postgres get different treatment because Redis's state is rebuildable: if it is lost, it is repopulated from the database and only performance degrades. PostgreSQL's state is the business's source of truth: losing it means losing bookings and customers' personal data. That is why PostgreSQL demands persistent storage, a stable identity, backups and network isolation, whereas Redis only needs a memory limit and an eviction policy.

Solution 2

# k8s/base/redis-cache-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: redis-cache
  namespace: rutas-norte-dev
  labels:
    app: redis-cache
    app.kubernetes.io/part-of: rutas-norte
    environment: dev
spec:
  containers:
    - name: redis
      image: redis:7.2-alpine
      ports:
        - name: redis
          containerPort: 6379
      resources:
        requests:
          cpu: "50m"
          memory: "64Mi"
        limits:
          cpu: "200m"
          memory: "256Mi"
kubectl apply -f k8s/base/redis-cache-pod.yaml --dry-run=client
kubectl apply -f k8s/base/redis-cache-pod.yaml
kubectl get pod redis-cache -o wide
kubectl exec -it redis-cache -- redis-cli ping
kubectl get pods -l app.kubernetes.io/part-of=rutas-norte
PONG

NAME          READY   STATUS    RESTARTS   AGE
redis-cache   1/1     Running   0          32s
web-store     1/1     Running   0          14m

Solution 3

# 1. Kill the process inside the container
kubectl get pods -w &
kubectl exec web-store -- kill 1
web-store   1/1   Running   0          15m
web-store   0/1   Error     0          15m
web-store   1/1   Running   1 (2s ago) 15m

The container does come back: RESTARTS goes from 0 to 1 and the pod's IP does not change, because it is the same pod. The one that recovers it is the kubelet, applying the restartPolicy: Always a pod has by default. The kubelet restarts containers inside an existing pod.

# 2. Delete the whole pod
kubectl delete pod web-store
kubectl get pods
No resources found in rutas-norte-dev namespace.

The pod does not come back. There is no controller watching over its existence.

  1. The difference lies in who acts and on what: the kubelet watches the containers inside the pods assigned to it and restarts them if they die, but it cannot recreate a pod that no longer exists as an object in the API. Recreating pods is the job of a kube-controller-manager controller, and a loose pod has none associated with it: by deleting it, you deleted the desired state itself.

  2. You need a Deployment, which creates a ReplicaSet whose controller permanently maintains the declared number of replicas. With it, the desired state stops being "let this specific pod exist" and becomes "let N pods with these characteristics exist", so deleting one immediately triggers the creation of another.

Conclusion

You now know the project that gives the whole course its meaning. Rutas Norte S.L. is a company with entirely real problems —overnight outages with no response, demand peaks on bank holidays and in the holiday season, deployments with service downtime and badly protected customer personal data— and its platform is made up of six pieces with clearly different needs: two stateless front ends, a critical stateful database, an expendable cache, a worker with no inbound traffic and a scheduled nightly task. You have the target architecture, the map of which module contributes what, and the conventions —namespaces per environment, the labelling scheme, immutable image tags and a k8s/ structure versioned in Git— that we will apply without exception.

And, above all, you have already deployed your first component: web-store running in rutas-norte-dev, inspected with get, describe and logs, and visible in your browser through port-forward. You have also seen its weak spot first-hand: a loose pod that, once deleted, never comes back.

With this you close module 1. You know what Kubernetes is, how it is built, what every term means, you have a working cluster, you have command of kubectl and you understand the declarative model. Module 2, Core Kubernetes Components, starts exactly where this lesson ends: we will turn that fragile pod into a Deployment with several replicas that recovers on its own, we will first learn what exactly a Pod is inside and how a ReplicaSet keeps it alive, and we will give web-store and bookings-api a stable address with Services. The Rutas Norte platform really starts to take shape.

Kubernetes Course

Module 1: Introduction to Kubernetes

Module 2: Core Kubernetes Components

Module 3: Configuration and Secret Management

Module 4: Networking in Kubernetes

Module 5: Storage in Kubernetes

Module 6: Advanced Kubernetes Concepts

Module 7: Monitoring and Logging

Module 8: Kubernetes Security

Module 9: Scaling and Performance

Module 10: Kubernetes Ecosystem and Tooling

Module 11: Case Studies and Real-World Applications

Module 12: Preparing for Kubernetes Certification

© Copyright 2026. All rights reserved