youtube.nixfred.com nixfred.com

Kubernetes Crash Course for Absolute Beginners [NEW]

Nana Janashia teaches all of Kubernetes in one hour. It starts with what container orchestration is and why microservices made it necessary, walks the cluster architecture of master and worker nodes, then explains every component you use day to day (pods, services, ingress, ConfigMaps, secrets, volumes, deployments, and StatefulSets) by building one example app. The second half is hands on: install Minikube and kubectl, write four YAML files, and deploy a MongoDB database with a Node.js web app reachable in a browser through a NodePort service. A reader finishes able to stand up a real application on Kubernetes.

Published Sep 30, 2021 1:12:03 video 59 min read Added Jun 16, 2026 Open on YouTube →

At a glance

Nana Janashia teaches the whole of Kubernetes in a single sitting, and she does it by building one small application and letting each component enter the story only when the application actually needs it. The first half is concepts: what container orchestration is, why the rise of microservices made it unavoidable, how a cluster is split into a master node running the control plane and worker nodes running your containers, and then pods, services, ingress, ConfigMaps, Secrets, volumes, Deployments, and StatefulSets, each introduced as the fix for a specific problem the previous slide just created. The second half is hands on: install Minikube, start a one node cluster with the Docker driver, write four YAML files, and deploy a MongoDB database plus a Node.js web app that reads its database endpoint from a ConfigMap and its credentials from a Secret, reachable in a browser through a NodePort service. This page rebuilds the entire course in her order, with every command in a shell block, every manifest printed in full and valid, and every field explained rather than pasted. Follow it top to bottom and you finish with the same running application she finishes with.

The plan she lays out (0:00)

She opens with the promise: everything you need to know to get started with Kubernetes, in one hour. She has taught hundreds of thousands of people to advance their DevOps skills through her YouTube channel, her online courses, and the DevOps educational program.

The overview of the hour, in four movements:

  1. What Kubernetes is, why we need it, and why it became so popular.
  2. The Kubernetes architecture, so you see how Kubernetes actually works in the background.
  3. The main Kubernetes components you need in order to work efficiently with it day to day.
  4. A hands on demo project, so you finish with real practical experience rather than slides.

She is honest about the shape of the thing before starting: Kubernetes is a very popular but also a very complex technology, so a crash course gets you your first experience and no more. If you want to go from there to building, configuring, and managing clusters from scratch, and to passing the CKA exam from the Linux Foundation, that is what her Kubernetes Administrator course exists for. Then: we have a lot to cover, so let us jump right into it.

What Kubernetes is, and why microservices forced it (1:44)

The definition first, and it is worth reading slowly because every word in it is load bearing.

Kubernetes is an open source container orchestration framework which was originally developed by Google.

At the foundation, it manages containers. Docker containers, or containers from some other technology, it does not care. Which means, in practice, that Kubernetes helps you manage applications that are made up of hundreds or maybe thousands of containers, and it helps you manage them across different environments: physical machines, virtual machines, cloud environments, or even hybrid deployments spanning several of those at once.

So what problem does it actually solve? She walks the history chronologically, because the answer is historical rather than technical.

The rise of microservices caused increased usage of container technologies, because containers offer the perfect host for small, independent applications. That is the fit: one small service, one image, one runtime environment, no shared machine state. But the rise of containers plus the rise of microservices produced a second order effect nobody designed for. Applications are now comprised of hundreds, sometimes thousands, of containers. Managing that many containers across multiple environments using shell scripts and self made tools can be really complex, and sometimes it is simply impossible.

That specific scenario, and not any single vendor's ambition, is what created the need for container orchestration technologies.

The three things an orchestrator guarantees (3:02)

What tools like Kubernetes do is guarantee three features, and she names them explicitly because they are the reason the complexity is worth paying for.

  1. High availability. In simple words, the application has no downtime. It is always accessible by users.
  2. Scalability. You can scale your application up fast when load increases and more users are hitting it, and scale it back down just as easily when the load drops. The application becomes flexible about load rather than provisioned for a guess.
  3. Disaster recovery. If the infrastructure has a problem, data is lost, servers explode, something bad happens in the data center, then the infrastructure has to have some mechanism to back the data up and restore it to the latest state, so the application loses no data and the containerized application can pick up from the latest state after recovery.

All three are functionalities that container orchestration technologies like Kubernetes offer out of the box. Hold on to the third one in particular, because when she gets to etcd you will see exactly where the backup comes from.

The cluster architecture (4:33)

A Kubernetes cluster is made up of at least one master node, and connected to it, a set of worker nodes.

Every node in the cluster, master and worker alike, runs a kubelet process. The kubelet is the Kubernetes process that makes it possible for the cluster to talk to itself, node to node, and to actually execute tasks on those nodes, such as running application processes.

Each worker node has containers of different applications deployed on it. Depending on how the workload is distributed you will have a different number of containers running on each worker node. Worker nodes are where the actual work happens: this is where your applications run.

Which raises the obvious question. If the workers run the applications, what is running on the master node?

The master node processes (5:37)

The master node runs several Kubernetes processes that are absolutely necessary to run and manage the cluster properly. Four of them matter to you immediately.

API server. It is itself a container, and it is the entry point to the Kubernetes cluster. This is the process that all the different Kubernetes clients talk to: a UI (the Kubernetes dashboard, for instance), an API (scripts and automation tooling), and a command line tool. All three roads lead to the API server. Nothing reaches the cluster any other way.

Controller manager. It keeps an overview of what is happening in the cluster: whether something needs to be repaired, whether a container died and needs restarting, and so on. It is the process that notices reality has drifted from what you asked for.

Scheduler. It is responsible for scheduling containers onto different nodes based on workload and on the available server resources on each node. She stresses that this is an intelligent process, not a round robin: it decides which worker node the next container should land on by weighing the resources free on each worker against the load that container needs.

etcd. A key value store that holds, at any moment, the current state of the Kubernetes cluster. All the configuration data lives inside it, and all the status data of every node and every container inside those nodes. This is the cluster brain. And this is where the backup and restore promised earlier actually comes from: recovery is made from etcd snapshots, because you can recover the whole cluster state from one.

The virtual network, and why the master is the fragile part (7:09)

One more component, and she calls it very important: the virtual network that spans every node in the cluster. In simple words, the virtual network turns all the nodes inside a cluster into one powerful machine that has the sum of the resources of the individual nodes.

Two consequences follow from the split, and both are practical.

First, worker nodes are usually much bigger than the master. They carry most of the load because they run the applications, potentially hundreds of containers each, so they need the resources. The master runs a handful of master processes and does not need nearly as much.

Second, and pointing the other way, the master node is much more important than any individual worker. If you lose access to the master node, you cannot access the cluster at all any more. Which means you absolutely have to have a backup of your master at all times. In production environments you would run at least two masters inside your Kubernetes cluster, and in most cases more than two, so that when one master goes down the cluster continues to function smoothly on the others.

One master, many workers, and exactly one door in Kubernetes clients UI / dashboard API / scripts kubectl YAML / JSON MASTER NODE (control plane) API server the only entry point Scheduler picks the node by free resources Controller manager watches for drift, repairs it etcd cluster brain, snapshots = backup WORKER NODE 1 kubelet kube-proxy container runtime (Docker) app pod db pod WORKER NODE 2 kubelet kube-proxy container runtime (Docker) app pod db pod virtual network the virtual network spans every node and makes the cluster behave as one machine
Figure 1. The asymmetry is the point. Workers are big because they carry hundreds of containers; the master is small but irreplaceable, because losing it means losing access to the cluster entirely. That is why production runs at least two masters. Every client request, from a dashboard click to a kubectl apply, enters through the API server and nowhere else, and every piece of state it decides on lands in etcd.

What runs on every worker (5:05)

The master side is the interesting half architecturally, but the worker side is where your code lives, and it is three processes deep. The container runtime (Docker in this course, since Minikube ships with Docker packaged inside it) is what actually starts and stops containers. The kubelet, the one she names explicitly, is the Kubernetes agent on the node: it takes the pod specifications handed down from the API server, tells the runtime to start those containers, and reports back what is actually running. kube-proxy is the third, and it is the piece that makes the service abstraction later in this course real: it maintains the network rules on each node so that a request addressed to a service IP is forwarded to one of the pods behind it, wherever that pod happens to be running.

Together with the virtual network, that trio is why a pod on worker 1 can reach a pod on worker 2 by name and never think about which machine is which.

Node and pod: the smallest unit (9:29)

From here she stops drawing infrastructure and starts building an application, because the components make far more sense as answers than as definitions. The use case she builds is deliberately plain: a web application with a simple database. Every component from this point on enters because that application needs it.

Start with the basic setup of a worker node, or in Kubernetes terms just a node, which is a simple server, physical or virtual.

The basic component, and the smallest unit of Kubernetes, is a pod. A pod is an abstraction over a container. It creates a running environment, a layer on top of the container, and it exists for two reasons:

  1. Kubernetes wants to abstract away the container runtime. If the pod is the unit, the container technology underneath can be replaced without the rest of Kubernetes caring.
  2. You do not have to work with Docker directly. You interact with the Kubernetes layer, and Kubernetes talks to whatever container technology is installed.

So the application setup becomes an application pod, which is our own application, and a database pod with its own container.

An important convention lands here: a pod is usually meant to run one application container inside it. You can run multiple containers in one pod, but usually that only happens when you have one main application container plus a helper container or a side service that has to run alongside it.

She points out how unremarkable this looks so far: one server, two containers, an abstraction layer on top. The interesting part is what happens when they try to talk to each other.

Pods get IPs, and pods are ephemeral (10:45)

Kubernetes offers a virtual network out of the box, and on that network each pod gets its own IP address. Not the container, the pod. Each pod can communicate with every other pod using that address, which is internal, obviously not public. So the application container can reach the database using its IP.

Then the catch, and it is the one that generates the next four components:

Pod components in Kubernetes are ephemeral, which means that they can die very easily.

If the database container crashes, or the application inside it crashes, or the node runs out of resources, the pod dies. A new one gets created in its place, and the new pod gets a new IP address. Which is deeply inconvenient if you were addressing the database by IP, because now you have to adjust that address every time a pod restarts.

Service and ingress (12:19)

The fix for the moving IP is a service: a static, permanent IP address that gets attached to a pod. Your application gets its own service, the database pod gets its own service, and here is the property that makes it work:

The life cycles of service and the pod are not connected.

Even if the pod dies, the service and its IP stay. The endpoint never has to change again.

Next question: you want your application to be reachable from a browser, so you create an external service, a service that opens communication from external sources. But you would obviously not want your database open to public requests, so the database gets an internal service instead. Internal versus external is simply a type you specify when creating the service, which is exactly the type: NodePort line that appears in the demo later.

Except the URL an external service gives you is not very practical. What you get is the HTTP protocol, plus the IP address of the node (not the service), plus the port number of the service:

http://<node-ip>:<service-port>

Fine for test purposes when you want to check something fast, wrong for an end product. For a real product you want a secure protocol and a domain name:

https://my-app.com

That is what ingress is for. Instead of the request hitting the service directly, the request goes first to ingress, and ingress does the forwarding to the service.

She takes stock at this point, honestly: this is a very simple setup, one server, a couple of containers, some services, and nothing yet where the real advantages of Kubernetes come forward. They are coming, step by step.

ConfigMap and Secret (14:31)

Pods talk to each other through services, so the application has a database endpoint, let us say mongodb-service, that it uses to reach the database. Where does that endpoint normally live? In an application properties file, or as an external environment variable, but usually inside the built image of the application.

Which means that if the service name changes to, say, mongodb, you have to adjust that URL in the application, rebuild the application at a new version, push it to the repository, pull that new image into your pod, and restart the whole thing. All of that for a string.

So Kubernetes has a component called ConfigMap: your external configuration for your application. A ConfigMap holds configuration data such as the URLs of a database or of other services you use, and you connect it to the pod so that the pod receives the data the ConfigMap contains. Change the service endpoint later and you adjust the ConfigMap. That is the entire change. No new image, no cycle.

Part of the external configuration is also the database username and password, which can change during the deployment process too. But putting a password or other credentials into a ConfigMap in plain text would be insecure, even though it is external.

For that, Kubernetes has Secret. A Secret is just like a ConfigMap, with one difference: it is used to store secret data such as credentials, and it is stored not in plain text but in base64 encoded format.

She is careful, and correct, about what that does and does not buy you:

Of course, base64 encoding a secret doesn't make it automatically secure.

Secret components are meant to be encrypted using third party tools, because Kubernetes does not encrypt them out of the box. There are tools for this from cloud providers, and separate third party tools you can deploy into Kubernetes to encrypt your Secrets, and that is what makes Secrets actually secure.

What goes where: a database user could reasonably live in a ConfigMap, but passwords, certificates, anything you do not want other people to have access to, goes into a Secret. And just like a ConfigMap, you connect it to your pod so the pod can read from it. Both can be consumed the same two ways: as environment variables (which is what the demo does) or as a properties file mounted into the container.

Volume: data that survives a restart (17:52)

The database pod holds data, or generates data, and with the setup as it stands, if the database container or pod gets restarted, that data is gone. Obviously problematic, since you want database data and log data persisted reliably and long term.

The component for that is volumes. A volume attaches physical storage on a hard drive to your pod. That storage can be either:

Now when the database pod or container restarts, the data is still there.

Then comes the sentence that matters more than the mechanism, and she says it twice in different words:

Think of storage as an external hard drive plugged into the Kubernetes cluster, because the point is Kubernetes cluster explicitly doesn't manage any data persistence.

Which means you, as the Kubernetes user or administrator, are responsible for backing the data up, replicating it, managing it, and making sure it is kept on proper hardware. Kubernetes does not take care of it. It is worth internalizing that on day one rather than after an incident.

Deployment and StatefulSet (19:46)

Everything is running, a user can reach the application through a browser. So what happens when the application pod dies, or you have to restart it because you built a new container image? You get downtime, a window where users cannot reach your application, which is a very bad thing in production.

This is exactly the advantage of distributed systems and containers. Instead of relying on one application pod and one database pod, replicate everything on multiple servers. Add a second node, run a replica of the application on it, and connect that replica to the same service.

Which reveals a second job the service was doing all along:

Service is also a load balancer, which means that the service will actually catch the request and forward it to whichever pod is least busy.

So a service is two things at once: a persistent static IP with a DNS name so endpoints stop moving, and a load balancer across the pods behind it.

But you do not create the second replica by hand. You define a blueprint for the application pod and specify how many replicas of it you want. That blueprint is a Deployment.

In practice you would not be working with pods, you would not be creating pods, you would be creating Deployments.

Because that is where you set the replica count, and where you scale up or down later. The abstraction stack is now two layers tall: a pod is a layer of abstraction on top of containers, and a Deployment is another layer of abstraction on top of pods, one that makes it convenient to replicate them and configure them. With a Deployment in place, when one replica of your application pod dies, the service forwards requests to another, and the application stays accessible.

Why the database cannot use a Deployment (22:04)

The natural next thought is: replicate the database the same way. If the database pod dies, the application is down regardless of how many application replicas exist.

But you cannot replicate a database with a Deployment, and the reason is state. The database has state, which is its data. If you clone it, all the replicas need to access the same shared data storage, and something has to manage which pods are currently writing to that storage and which are reading from it, in order to avoid data inconsistencies.

That mechanism, on top of the replication feature, is what another Kubernetes component provides: StatefulSet. It is meant specifically for applications like databases. MySQL, MongoDB, Elasticsearch, or any other stateful application should be created using StatefulSets and not Deployments. She calls it a very important distinction, and it is the one most beginners get wrong first.

A StatefulSet, just like a Deployment, takes care of replicating the pods and scaling them up or down, while additionally making sure database reads and writes are synchronized so no inconsistencies arise.

And then the caveat that saves people months, delivered without hedging:

Deploying database applications using StatefulSets in a Kubernetes cluster can be somewhat tedious, so it's definitely more difficult than working with Deployments.

Which is why it is common practice to host database applications outside the Kubernetes cluster entirely, keep only the stateless applications (which replicate and scale with no problem) inside the cluster, and have them talk to the external database. That is a legitimate architecture, not a cop out.

DeploymentStatefulSet
What it is forStateless applications: web apps, APIs, workers, anything that keeps nothing important on local diskStateful applications: MySQL, MongoDB, Elasticsearch, any database
ReplicationYes, set replicas and Kubernetes maintains that countYes, same idea
Scaling up and downYes, and it is trivialYes, but ordered and constrained by the data
Shared data storageNot its problem, pods hold nothing worth keepingIts whole problem: replicas share storage, so reads and writes must be synchronized
Pod identityInterchangeable, any replica serves any requestSticky, replicas are not interchangeable
Ease of useeasy, this is the default object you reach fortedious, materially harder to operate correctly
Common escape hatchNone neededRun the database outside the cluster and point the app at it

With two replicas of the application pod and two replicas of the database, both load balanced, the setup is genuinely robust: if node 1 is rebooted or crashes outright and nothing can run on it, node 2 still has application and database pods on it, and the application stays accessible while the two lost replicas are recreated. That is how you avoid downtime, and it is the payoff for all of the previous abstractions.

The component recap (25:10)

She summarizes before moving to the hands on half, and the summary is worth keeping as a mental index.

ComponentWhat it isThe problem it solvesWhen you reach for it
PodAn abstraction layer over a container, the smallest unit in Kubernetes, one main app container eachDecouples Kubernetes from the container technology, so you never talk to Docker directlyAlmost never directly, you get pods from Deployments
ServiceA permanent IP address plus DNS name in front of a set of pods, and a load balancer across themPods are ephemeral and get a new IP on every restartEvery application needs one, internal by default
IngressThe entry point that routes external traffic into the cluster before it reaches a serviceAn external service gives you http://node-ip:port, which is not a product URLWhen you want HTTPS and a real domain name
ConfigMapExternal configuration in plain key value pairs, connected to a podConfig baked into an image means a rebuild and redeploy for a URL changeEndpoints, hostnames, feature flags, anything non secret
SecretThe same idea, base64 encoded, meant to be encrypted by third party toolingCredentials in a ConfigMap would sit in plain textPasswords, certificates, tokens
VolumePhysical storage, local or remote, attached to a podContainer restarts wipe everything the container wroteDatabases and logs, with backup remaining your job
DeploymentA pod blueprint with a replica count, an abstraction on top of podsA single pod means downtime whenever it dies or is updatedEvery stateless application, this is your default
StatefulSetThe same blueprint plus synchronized reads and writes and stable pod identityDatabase replicas sharing storage would corrupt each otherDatabases, if you insist on running them in cluster

Just these core components, she notes, are enough to build genuinely powerful Kubernetes clusters.

Before the practical half she gives a shout out to the sponsor, Kasten, whose K10 is a data management platform for Kubernetes that takes most of the backup and restore burden off cluster administrators, with a simple UI and logic that does the heavy lifting.

Kubernetes configuration: everything is YAML sent to the API server (26:28)

So how do you actually create these components? All configuration in a Kubernetes cluster goes through the master node, specifically through the API server.

Kubernetes clients (a UI such as the Kubernetes dashboard, an API call which could be a script or a curl command, or a command line tool such as kubectl) all talk to the API server, which is the main entry point and the only entry point into the cluster. And the requests they send have to be in either YAML or JSON format.

The example she walks through is a Deployment: a template or blueprint for creating pods. It tells Kubernetes to create two replica pods called my-app, each pod replica running a container based on my-image, plus the environment variables and port configuration for that container inside the pod.

The critical property of these requests:

The configuration requests in Kubernetes are declarative. We declare what is our desired outcome from Kubernetes, and Kubernetes tries to meet those requirements.

Which is what turns configuration into self healing. Declare two replica pods of the my-app Deployment. One of those pods dies. The controller manager sees that the desired state and the actual state now differ, actual is 1 and desired is 2, so it goes to work restarting the second replica automatically until the declaration is true again.

Every configuration file has three parts (28:18)

Putting a Deployment and a Service configuration side by side, the structure is identical.

Part 1: metadata. Where the metadata of the component you are creating lives, most obviously its name.

Part 2: specification. Every component's configuration file has a spec section where you put every kind of configuration you want applied to that component. The attributes inside are specific to the kind of component: a Deployment has attributes that only apply to Deployments, a Service has its own.

Above both sits the pair of lines that declare what you are creating at all, apiVersion and kind, and she flags something that trips everyone up: the API version differs per component, and you have to look it up per component. It is apps/v1 for a Deployment and v1 for a Service, and there is no way to guess it.

Part 3: status. This one you never write. It is automatically generated and edited by Kubernetes. Kubernetes continuously compares the desired state against the actual state of the component, and if the status and the desired state do not match, it knows there is something to fix, and it tries to fix it.

This is the basis of the self healing feature that Kubernetes provides.

Concretely: you specify two replicas of an nginx Deployment. You apply the file, which is what "apply" means, creating the Deployment. Kubernetes adds the status of your deployment and updates it continuously. If the status at some point says only one replica is running, Kubernetes compares that status with the specification and knows another replica needs to be created.

Where the status data comes from (31:22)

An excellent question she raises and answers: where does Kubernetes get the status information it keeps writing back?

From etcd. The cluster brain, one of the master processes, holds the current status of any Kubernetes component at any time. That is the source of every status field you ever read.

Two practical notes on the files (31:54)

YAML is strict about indentation. The format itself is simple and pretty straightforward to read, but if something is indented wrongly, your file is invalid. That is the one syntax rule that will actually bite you.

Store the configuration files with your code. Since the Deployment and Service are applied to your application, it is good practice to keep these files in your application repository, usually as part of the infrastructure as code concept. Alternatively you can give the configuration files their own Git repository. Either is fine; leaving them on somebody's laptop is not.

Minikube and kubectl: a cluster on your laptop (32:39)

A production cluster looks like the architecture diagram: at least two masters, multiple worker nodes, separate responsibilities, and actual separate virtual or physical machines each representing a node. If you want to test something locally, or try out a new application or a new component quickly, standing that up is pretty difficult and possibly impossible on one laptop with finite memory and CPU.

Exactly for that use case there is an open source tool called Minikube.

Minikube is basically one node cluster where the master processes and the worker processes both run on one node.

That node comes with a Docker container runtime pre installed, so you can run containers, or pods with containers, on it immediately.

Now you have a virtual node on your local machine. You still need a way to interact with it, to create pods and other Kubernetes components on that node. That is kubectl, the command line tool for a Kubernetes cluster.

The path is the same as always: Minikube runs both master and worker processes, one of those master processes is the API server, the API server is the main entry point, and you talk to it through a client. There are three clients (a UI such as the dashboard, the Kubernetes API, and kubectl), and kubectl is the most powerful of the three, because with kubectl you can basically do anything in Kubernetes that you want. Once kubectl submits a command to the API server to create or delete components, the worker processes on the Minikube node actually make it happen.

One thing worth pinning down, because the name misleads people:

kubectl isn't just for a Minikube cluster. If you have a cloud cluster or a hybrid cluster, whatever, kubectl is the tool to use to interact with any type of Kubernetes cluster setup.

Minikube is the local cluster. kubectl is the universal client.

Installing Minikube (36:04)

There are many ways to install it depending on your operating system and its architecture, so the right move is to reference the official Minikube documentation, which lists the resource requirements and lets you select the correct options for your machine. Minikube can run either as a container or as a virtual machine, so check you have the resources before you start.

Her machine is macOS with Homebrew, so the install is one command:

# install Minikube (macOS with Homebrew; pick your own OS on the docs page)
brew install minikube

Watch the output as it runs. It installs dependencies for Minikube, and one of those dependencies is the Kubernetes CLI, which is kubectl. That is why she never installs kubectl separately: it arrives with Minikube.

Once installed, you create and start a Minikube cluster:

# start (and on first run, create) the local one node cluster
minikube start

The driver, and the two layers of Docker (37:04)

Minikube must start either as a container or as a virtual machine, so you need a container or virtual machine tool installed on your laptop for it to run inside. That tool is the driver. The drivers page lists what is supported on Linux, macOS, and Windows, and Docker is the preferred driver on all three operating systems.

This is the point she stops to clear up, because it confuses nearly everyone:

Minikube installation actually comes with Docker already installed to run those containers, but Docker as a driver for Minikube means that we are hosting Minikube on our local machine as a Docker container itself. So we have two layers of Docker.

Read it as a stack. Minikube runs as a Docker container on your machine. Inside Minikube, a separate Docker is packaged to run your application containers. The outer Docker hosts the cluster; the inner Docker runs your pods.

So if you already have Docker installed, you are ready. If not, install Docker Desktop from Docker Hub for Windows or Mac, drag and drop it into Applications, and start the Docker daemon so the whale is running before you continue.

With Docker running, start the cluster with Docker explicitly set as the driver:

# --driver=docker tells Minikube to host the cluster node as a Docker container
minikube start --driver=docker

The first run takes a while, because it has to create the cluster and download all the necessary images and components. Subsequent minikube start calls are much faster. When it finishes you have a local Kubernetes cluster on your machine (in the video, running Kubernetes 1.22, which was the latest at the time).

Check that everything inside came up:

# reports host, kubelet, apiserver and kubeconfig status for the local cluster
minikube status

All components should read as running and configured.

First contact with kubectl (40:09)

kubectl is already there as a Minikube dependency, so go straight to the cluster:

# list every node in the cluster
kubectl get node

You get exactly one node, which is the control plane and the worker node at the same time, along with its status, its Kubernetes version, and how long ago it joined the cluster.

That is the whole setup. From here on the division of labor is clean:

Minikube is basically just for the startup and for deleting the cluster, but everything else, configuring, we're going to be doing through kubectl.

The demo project: MongoDB plus a Node.js web app (41:17)

Now the knowledge gets spent. The target setup:

Two resources sit open beside the editor the whole time, and both are part of the method rather than decoration. The first is the Kubernetes documentation, which she copies the starting syntax of every component from, because that is the realistic way of working with Kubernetes: nobody memorizes the YAML. The second is Docker Hub, where the web application image she built is published publicly, so you can pull it into your own cluster exactly as she does.

Four configuration files go into a kubernetes-demo folder, in this order:

  1. mongo-config.yaml, a ConfigMap holding the MongoDB database endpoint.
  2. mongo-secret.yaml, a Secret holding the MongoDB username and password.
  3. mongo.yaml, the MongoDB Deployment plus its internal Service.
  4. webapp.yaml, the web application Deployment plus its NodePort Service.

File 1: the ConfigMap (42:44)

Creating a ConfigMap is the simplest of the four. Copy the first example from the ConfigMap documentation, name it mongo-config, and fill in the data.

apiVersion: v1
kind: ConfigMap
metadata:
  name: mongo-config
data:
  mongo-url: mongo-service

Field by field:

File 2: the Secret (44:17)

Copy the example from the Secret documentation, and take the whole thing this time, because there is one extra field.

apiVersion: v1
kind: Secret
metadata:
  name: mongo-secret
type: Opaque
data:
  mongo-user: bW9uZ291c2Vy
  mongo-password: bW9uZ29wYXNzd29yZA==

What changed relative to the ConfigMap:

Encoding is one command per value:

# -n matters: without it, echo appends a newline and you encode a value with a
# trailing \n in it, which is a classic cause of "authentication failed"
echo -n mongouser | base64
# bW9uZ291c2Vy

echo -n mongopassword | base64
# bW9uZ29wYXNzd29yZA==

Paste each result as the value. To go the other way and check what a Secret actually holds, base64 --decode reverses it:

echo -n bW9uZ291c2Vy | base64 --decode
# mongouser

Keep in mind what was said at 16:27: this is encoding, not encryption. Anyone who can read the Secret can read the password. Encrypting Secrets properly is a third party tool's job.

File 3: the MongoDB Deployment (45:49)

Third file, mongo.yaml, and this one holds both the Deployment and the Service. You can keep them in separate files, but it is a very common thing to put them together, because every Deployment needs a Service, so grouping them keeps the pair in one place.

Grab the Deployment example from the documentation and adjust it. It looks more complex than the ConfigMap or the Secret, so she walks every attribute.

The core of it is the template, which is the pod blueprint:

Template basically is a configuration of the pod within the configuration of deployment.

And the template has its own metadata and its own spec, exactly like the Deployment does, one level down. That nesting is the single most confusing thing about a Deployment manifest the first time you see it, and once you see that it is a pod manifest embedded inside a Deployment manifest, it stops being confusing.

Inside the pod's spec sits containers, a list, because a pod can hold multiple containers (though mostly one main application container). For each container you set:

That much configures the Deployment to create pods running a MongoDB 5.0 image. Now the other stuff.

Labels and selectors (48:54)

Two attributes need explaining: labels in the metadata section, and matchLabels in the selector.

In Kubernetes you can give any component a key value pair label. Pods, Deployments, ConfigMaps, anything. Labels are additional identifiers of components, on top of the name, so you can identify and address specific components by label.

Why you need them: when you have multiple replicas of the same pod, each pod gets a unique name, but they can all share the same label. So a label is how you identify every pod replica of one application at once. That is why the pod metadata always carries a label.

For pods, labels is a required field. For other components like Deployment, ConfigMap and so on, labels is optional, but it is a good practice to set them.

Then the connection: how does a Deployment know which pods belong to it? Through selector.matchLabels in the Deployment's spec. It says: every pod that matches this label belongs to this Deployment. The selector matches the pods created by this configuration because those pods carry that label in their template metadata.

Are the labels themselves prescribed? No:

These are totally up to you. You can call it whatever you want, you can call it my-key: my-value, it doesn't really matter.

But the standard and common practice in Kubernetes is to use app as the key when labeling applications, with the application name as the value. So the nginx placeholders from the docs example become app: mongo, in all three places: the Deployment's own labels, the selector's matchLabels, and the pod template's labels. The Deployment name becomes mongo-deployment.

Replicas (51:32)

The last Deployment attribute is replicas, which is as simple as it sounds: how many pods to create from this blueprint. Here it is 1, and there is a reason:

It's a database, and as you learned, if you want to scale databases in Kubernetes you should use StatefulSet and not a Deployment.

So to keep everything simple, MongoDB stays at one replica. The lesson from 22:04 is being obeyed rather than quietly ignored.

Here is the Deployment half of mongo.yaml as it stands at this point, before the environment variables are added at 56:43:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongo-deployment
  labels:
    app: mongo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mongo
  template:
    metadata:
      labels:
        app: mongo
    spec:
      containers:
      - name: mongodb
        image: mongo:5.0
        ports:
        - containerPort: 27017

The MongoDB Service, in the same file (52:04)

Every application needs a Service, so the Service goes into the same YAML file as a separate document, separated by three dashes:

---

That is basic YAML syntax for "a second document starts here", nothing specific to Kubernetes, and it is why one file can hold two objects.

Service configuration is much easier than a Deployment. Grab the Service example and adjust:

---
apiVersion: v1
kind: Service
metadata:
  name: mongo-service
spec:
  selector:
    app: mongo
  ports:
    - protocol: TCP
      port: 27017
      targetPort: 27017

The fields:

Said once more, because these two are the pair people mix up: port sets the port of the Service; targetPort tells the Service which port to forward to on the pods. They can legitimately differ, but the common standard is to set them the same just to keep things simple, which is why both read 27017 here.

Note also what is not in this Service: a type. Leave it out and you get the default, ClusterIP, an internal service, which is precisely right for a database that should never be reachable from outside the cluster.

File 4: the web application (54:36)

The fourth file, webapp.yaml, starts as a copy of the whole of mongo.yaml, with the values adjusted. That is not laziness, it is the shape of the thing: Deployment plus Service is the basic configuration for any application in a Kubernetes cluster.

What changes:

Wiring the ConfigMap and Secret into the containers (56:11)

Both Deployments still need one thing: the data defined in the ConfigMap and Secret components has to reach the containers.

Start with MongoDB. When a MongoDB container starts it will create a root username and password from environment variables, and you then use those credentials to reach it from inside the cluster. How do you know which variables? You read the image documentation on Docker Hub, which names them. They are MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD, and she notes these are effectively required fields in most databases: without them you will not be able to access the thing at all.

So the next question is how to pass environment variables to an application running inside a container. Also easy: an env attribute on the container, holding a list of environment variables with names and values.

        env:
        - name: MONGO_INITDB_ROOT_USERNAME
          value: mongouser

name is the environment variable name, value is its value. You could hardcode the username right there like that. But the whole point of files 1 and 2 was to avoid it, so instead you reference the Secret with valueFrom and secretKeyRef:

        env:
        - name: MONGO_INITDB_ROOT_USERNAME
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: mongo-user
        - name: MONGO_INITDB_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: mongo-password

Read it as a two step lookup: name is the name of the Secret component (mongo-secret, from metadata.name in file 2) and key is the key inside that Secret's data block. Kubernetes finds the Secret with that name, gets the value stored under that key, and substitutes it as the value of the environment variable. The password is now a reference, never a literal, in the manifest you commit to Git.

With that, the MongoDB configuration file is complete, and when the pod starts, a user with those credentials is created.

The web app needs three values (59:16)

When the web application starts it must connect to the database, so it needs three things: where the database is, and which username and password to authenticate with. She has already built the application to expect all three as environment variables with specific names, so the Deployment passes them in:

        env:
        - name: USER_NAME
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: mongo-user
        - name: USER_PWD
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: mongo-password
        - name: DB_URL
          valueFrom:
            configMapKeyRef:
              name: mongo-config
              key: mongo-url

Two things to take from this block.

The first two are copy paste of the MongoDB block, and she calls that out as the visible payoff of external configuration:

You already see an advantage of using configuration from Secret or ConfigMap, because if you need the same information in 10 different applications, you create it once and reference it 10 times.

Note also that the environment variable names differ (USER_NAME and USER_PWD here, MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD there) while the underlying Secret keys are identical. The variable name is whatever the consuming application demands; the key is where the value lives. Those are two different namespaces.

The third one comes from the ConfigMap, and the syntax is deliberately parallel: same valueFrom, but configMapKeyRef instead of secretKeyRef, then the same name (the ConfigMap mongo-config) and key (mongo-url) pair. The value it resolves to is mongo-service, which is the DNS name of the MongoDB Service, which routes to the MongoDB pod.

The result:

We don't have any of the configuration values hardcoded in our Kubernetes configuration files, we only have references, which makes our configuration way cleaner. So if something changes, or the values change here, we don't have to adjust anything in our Deployments.

Making the web app reachable: NodePort (1:02:22)

Connectivity to the database is configured. One thing is still missing before deploying: you want to type a URL into a browser and see the application.

As covered at 12:51, external services exist for that. Right now both Service configurations are internal, because neither one specifies a type, and the default type is ClusterIP. To make the web app service external, set the type to NodePort:

spec:
  type: NodePort

NodePort is an external service type, and it requires a third port, called nodePort:

This is a port which will open on the Kubernetes nodes, on which the application will be accessible.

So the combination of the node IP address and the nodePort reaches the Service, which then reaches the pods behind it. Three ports now stack up in a NodePort Service, and they are all different jobs:

FieldWhere it livesWhat it isValue here
nodePortOn the node, open to the outside worldThe port you hit from your browser, at the node's IP30100
portOn the Service, inside the clusterThe port the Service itself listens on for in cluster traffic3000
targetPortOn the pods behind the ServiceWhere the Service forwards to, must equal containerPort3000

And nodePort is not a free choice. The range is defined by Kubernetes:

It has to be within the range of 30000 and 32767.

Anything in that range is fine, so 30000 or 30100, it does not really matter. She uses 30100, and that completes the web app configuration file. What is on disk now is a simple but genuinely realistic configuration: an application, its database, and external configuration, all in the cluster.

Applying everything, in dependency order (1:03:54)

The Minikube cluster is already running but has no components in it. Order matters here, and it is worth stating why rather than just following along.

The external configuration goes first, because the MongoDB and web app Deployments reference the ConfigMap and Secret, so those have to exist by the time the Deployments are created. Then the database, because the web application depends on it and should find it already up. Then the web app.

The command is kubectl apply with -f, which stands for file, taking a Kubernetes configuration file as input and creating whatever is defined inside it:

# 1. external configuration first: the Deployments reference these by name
kubectl apply -f mongo-config.yaml
# configmap/mongo-config created

kubectl apply -f mongo-secret.yaml
# secret/mongo-secret created

# 2. the database next: the web app depends on it
kubectl apply -f mongo.yaml
# deployment.apps/mongo-deployment created
# service/mongo-service created

# 3. finally the web application
kubectl apply -f webapp.yaml
# deployment.apps/webapp-deployment created
# service/webapp-service created

Notice that the third and fourth commands each report two objects created, because each of those files holds two YAML documents separated by ---.

One browser request, all the way down Browser minikube-ip:30100 nodePort MINIKUBE CLUSTER (one node: control plane and worker) webapp-service type: NodePort, port 3000 targetPort 3000 webapp pod k8s-demo-app:v1.0 containerPort 3000 DB_URL = mongo-service mongo-service ClusterIP, port 27017 targetPort mongo pod mongo:5.0 containerPort 27017 mongo-config ConfigMap: mongo-url mongo-secret Secret: user, password dashed lines are env var references: valueFrom secretKeyRef / configMapKeyRef nothing outside the cluster can reach mongo-service, because it has no NodePort
Figure 2. Only one of the two services has a door to the outside. The web app is reachable at the node IP on port 30100; MongoDB is reachable only from inside the cluster, by the name mongo-service, which is a literal string stored in a ConfigMap and injected as DB_URL. Change the Service name and you change one line of the ConfigMap, not the application image.

Interacting with the cluster (1:05:40)

Everything applied cleanly, but "seems fine" is not a state. Check what actually exists.

# every component created in the cluster: deployments, the pods behind them,
# the ReplicaSets in between, and all the services
kubectl get all

The output shows mongo-deployment and webapp-deployment, each with one replica running, the pods behind them, and both services, with webapp-service listed as type NodePort, which is what tells you it is reachable externally.

What kubectl get all does not show is the ConfigMap and the Secret. Those need their own commands:

kubectl get configmap
kubectl get secret

The general shape she draws out of that:

Displaying any component is pretty easy using kubectl. You just do kubectl get and the name of the component, like pod, and you get a list of those components with some additional data.

kubectl get pod
kubectl get service
kubectl get deployment
kubectl get node

kubectl documents itself (1:06:28)

kubectl is a very powerful tool with a lot of subcommands, and the natural documentation for it is the tool itself:

# lists every subcommand available
kubectl help

# help for one subcommand, with examples and every available option
kubectl get --help

That second form is the useful one in practice: per subcommand help gives you the examples plus the full option list, so you can navigate what is available without leaving the terminal. The online kubectl reference covers the same ground with more context.

describe: the detail view (1:07:30)

kubectl get lists. When you want more detail about one specific component, kubectl describe takes the component type and then the instance name:

# detailed output for one service
kubectl describe service webapp-service

# detailed output for one pod: how it was scheduled, container config, labels,
# and the event log, which is where you find out why a pod will not start
kubectl describe pod webapp-deployment-<hash>

For a pod that gives you the status of how the pod was scheduled, the container configuration, the labels, and more. It is the first command to reach for when something is not running and you do not know why.

logs: what the container is saying (1:08:02)

When applications are running in your cluster you want to check the logs, to troubleshoot, to debug, or just to confirm everything is fine inside the pod.

# the logs of the container inside that pod
kubectl logs webapp-deployment-<hash>

# -f follows, streaming new log lines as they arrive
kubectl logs -f webapp-deployment-<hash>

The pod name is the long generated one you copy out of kubectl get pod, made of the Deployment name plus the ReplicaSet hash plus the pod hash. That naming is exactly the reason labels exist: names are unique per pod and therefore unmemorable, labels are shared and therefore addressable.

A close relative worth knowing, since a shell inside a container answers questions logs cannot:

# open an interactive shell inside the running container
kubectl exec -it webapp-deployment-<hash> -- /bin/bash

And the command that undoes an apply, which is the other half of the workflow:

# delete by file, removing exactly what that file created
kubectl delete -f webapp.yaml

# or delete one named object
kubectl delete deployment webapp-deployment

Opening it in a browser (1:08:34)

The last step is validating that the application really is reachable from a browser. Get the service:

# svc is the accepted short form of service
kubectl get service
kubectl get svc

That gives you the port. But which IP address goes in front of it? The rule for NodePort:

The NodePort service is always accessible at the IP address of the cluster node.

All the worker nodes the cluster has, and here there is exactly one, the Minikube node. So you need the Minikube node's IP:

minikube ip

Or from the other direction, with kubectl, using the wide output format:

# -o wide prints extra columns, including the node's internal IP
kubectl get node -o wide

Both produce the same address. And -o wide is not special to nodes:

You can use the -o wide option for any other get command, for services, pods and so on, to get some additional information.

kubectl get pod -o wide
kubectl get svc -o wide

Now put the two halves together and open it:

http://<minikube-ip>:30100

There it is: the web application, connected to MongoDB. And she validates the connection rather than assuming it, which is the right instinct: edit something in the app and save it, because that request goes to the database, then refresh the page and confirm the change is still there. Data survived a round trip through the pod, the internal Service, and Mongo. The wiring is real.

What you just built (1:10:39)

So we deployed an application with its database in Kubernetes, which is a blueprint configuration for most common application setups you're gonna have.

That is the honest claim about this demo: it is small, but the shape (a stateless application, a database, external configuration, an internal service, one external entry point) is the shape of most real deployments. You also collected a working set of kubectl commands, and, just as important, the habit of referencing the official Kubernetes documentation to configure and create components rather than trying to remember YAML.

She closes by pointing at the two next steps she maintains: the Kubernetes Administrator course if you want to build and administer clusters from scratch and sit the CKA, and the complete DevOps educational program, a six month program covering all the concepts and technologies, Kubernetes included, needed to get started in DevOps or cloud engineering.

The complete manifests

All four files, in the order she creates them and in the order you apply them. Copy them into a folder, run the four kubectl apply commands, and you have the same setup.

mongo-config.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: mongo-config
data:
  mongo-url: mongo-service

mongo-secret.yaml (values are echo -n mongouser | base64 and echo -n mongopassword | base64; encode your own before using this anywhere real)

apiVersion: v1
kind: Secret
metadata:
  name: mongo-secret
type: Opaque
data:
  mongo-user: bW9uZ291c2Vy
  mongo-password: bW9uZ29wYXNzd29yZA==

mongo.yaml (Deployment and internal Service in one file, split by ---)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongo-deployment
  labels:
    app: mongo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mongo
  template:
    metadata:
      labels:
        app: mongo
    spec:
      containers:
      - name: mongodb
        image: mongo:5.0
        ports:
        - containerPort: 27017
        env:
        - name: MONGO_INITDB_ROOT_USERNAME
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: mongo-user
        - name: MONGO_INITDB_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: mongo-password
---
apiVersion: v1
kind: Service
metadata:
  name: mongo-service
spec:
  selector:
    app: mongo
  ports:
    - protocol: TCP
      port: 27017
      targetPort: 27017

webapp.yaml (Deployment and external NodePort Service)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp-deployment
  labels:
    app: webapp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: webapp
  template:
    metadata:
      labels:
        app: webapp
    spec:
      containers:
      - name: webapp
        image: nanajanashia/k8s-demo-app:v1.0
        ports:
        - containerPort: 3000
        env:
        - name: USER_NAME
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: mongo-user
        - name: USER_PWD
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: mongo-password
        - name: DB_URL
          valueFrom:
            configMapKeyRef:
              name: mongo-config
              key: mongo-url
---
apiVersion: v1
kind: Service
metadata:
  name: webapp-service
spec:
  type: NodePort
  selector:
    app: webapp
  ports:
    - protocol: TCP
      port: 3000
      targetPort: 3000
      nodePort: 30100

The full run, start to browser

minikube start --driver=docker
minikube status

kubectl apply -f mongo-config.yaml
kubectl apply -f mongo-secret.yaml
kubectl apply -f mongo.yaml
kubectl apply -f webapp.yaml

kubectl get all
kubectl get configmap
kubectl get secret

minikube ip           # then open http://<that-ip>:30100 in a browser

Key takeaways

Chapters

Notable quotes

"Kubernetes is an open source container orchestration framework which was originally developed by Google." (1:44)

"Managing those loads of containers across multiple environments using scripts and self made tools can be really complex and sometimes even impossible." (3:02)

"Kubelet is actually a Kubernetes process that makes it possible for the cluster to talk to each other, to communicate to each other, and actually execute some tasks on those nodes." (4:33)

"An API server is actually the entry point to the Kubernetes cluster." (5:37)

"etcd key value storage basically holds at any time the current state of the Kubernetes cluster. The backup and restore that we mentioned previously is actually made from these etcd snapshots." (6:37)

"If you lose a master node access, you will not be able to access the cluster anymore." (8:11)

"Pod components in Kubernetes are ephemeral, which means that they can die very easily." (11:16)

"The life cycles of service and the pod are not connected, so even if the pod dies the service and its IP address will stay." (12:21)

"Of course, base64 encoding a secret doesn't make it automatically secure. The secret components are meant to be encrypted using third party tools." (16:27)

"Think of a storage as an external hard drive plugged in into the Kubernetes cluster, because the point is Kubernetes cluster explicitly doesn't manage any data persistence." (19:01)

"Service is also a load balancer, which means that the service will actually catch the request and forward it to whichever pod is least busy." (20:32)

"In practice you would not be working with pods, you would not be creating pods, you would be creating deployments." (21:33)

"Deploying database applications using StatefulSets in Kubernetes cluster can be somewhat tedious, so it's definitely more difficult than working with deployments. That's why it's also a common practice to host database applications outside of the Kubernetes cluster." (23:39)

"The configuration requests in Kubernetes are declarative form, so we declare what is our desired outcome from Kubernetes and Kubernetes tries to meet those requirements." (27:46)

"This is the basis of the self healing feature that Kubernetes provides." (30:20)

"YAML is very strict about the indentations, so for example if you have something wrongly indented here, your file will be invalid." (31:54)

"Minikube is basically one node cluster where the master processes and the worker processes both run on one node." (33:27)

"kubectl isn't just for Minikube cluster. If you have a cloud cluster or a hybrid cluster, whatever, kubectl is the tool to use to interact with any type of Kubernetes cluster setup." (35:31)

"For pods, labels is a required field. For other components like deployment, ConfigMap etc, labels is optional, but it is a good practice to set them." (49:26)

"Port attribute sets the port of the service, and target port tells service to which port it should forward the request to the pods." (54:06)

"If you need the same information in 10 different applications, you create it once and reference it 10 times." (1:00:16)

"Node port range is actually defined in Kubernetes, so we can't just type anything we want. It has to be within the range of 30000 and 32767." (1:03:24)

"We deployed an application with its database in Kubernetes, which is a blueprint configuration for most common application setups you're gonna have." (1:10:39)

Resources mentioned

The core tooling

Containers and images

People, courses, and the sponsor

Where it stands

The course was published in September 2021 against Kubernetes 1.22, and the concepts in it have aged well, which is the nature of a design that has not moved much. Pods, services, ingress, ConfigMaps, Secrets, volumes, Deployments, StatefulSets, and the control plane split are all exactly as described. Every manifest on this page still applies cleanly on a current cluster, and apps/v1 and v1 are still the right API versions for these objects.

Four things have shifted underneath the vocabulary since, and they are worth knowing before you take this into a modern cluster.

"Master node" is now "control plane node". The Kubernetes project moved off the master and slave terminology; the kubectl get node output she reads on screen already says control-plane for exactly that reason. The architecture is unchanged, the word is not.

Docker is no longer the container runtime inside Kubernetes. Kubernetes removed the dockershim in version 1.24, released in 2022, so clusters now run containerd or CRI-O as the runtime. This does not affect anything on this page: your images are still built by Docker and are still OCI images, Docker remains the preferred Minikube driver, and pods run identically. It only changes what is running on the worker under the kubelet, which is precisely the abstraction the pod exists to hide.

Ingress has a successor in progress. The Gateway API is the project's newer, more expressive answer to routing external traffic, and it is where new work is going. Ingress is not going away and remains the thing to learn first, but on a greenfield cluster in 2026, Gateway API deserves a look.

Secrets deserve one more layer than she had room for. Her warning at 16:27 is still exactly right and still routinely ignored. Modern clusters back it up with encryption of Secret data at rest in etcd, and Git friendly workflows tend to use Sealed Secrets or the External Secrets Operator so that a base64 blob never lands in a repository at all. If you take one habit from this course into production, take that one.

Full transcript
hello and welcome to the kubernetes crash course where i will teach you everything you need to know to get started with kubernetes in one hour i am nana and i have taught hundreds of thousands of people how to advance their devops skills through my youtube channel online courses and the devops educational program if you're new here be sure to subscribe because i upload new videos all the time now let's look at an overview of what you will learn first of all we'll see what is kubernetes and why do we need it and why did it become so popular second we will go through the kubernetes architecture and you will see how kubernetes actually works in the background after that we will cover main kubernetes components that you need to learn to work efficiently with kubernetes and finally we will do a hands-on demo project to get your first practical experience with kubernetes now kubernetes is a very popular but also a very complex technology so this crash course will help you get your first experience to get started with kubernetes but if by the end of the video you decide to deepen your knowledge in kubernetes and are thinking about a career as a kubernetes administrator my new complete kubernetes administrator course will be a great resource for you where you will learn how to build configure and manage kubernetes clusters from scratch the course is also dedicated to help you pass the cka exam from linux foundation to become a certified kubernetes administrator now we have a lot to cover in this video so let's jump right into it so let's jump in right into the definition what is kubernetes so kubernetes is an open source container orchestration framework which was originally developed by google so on the foundation it manages containers be docker containers or from some other technology which basically means that kubernetes helps you manage applications that are made up of hundreds or maybe thousands of containers and it helps you manage them in different environments like physical machines virtual machines or cloud environments or even hybrid deployment environments so what problems does kubernetes solve and what are the tasks of a container orchestration tool actually so to go through this chronologically the rise of microservices caused increased usage of container technologies because the containers actually offer the perfect host for small independent applications like microservices and the rise of containers and the micro service technology actually resulted in applications they're now comprised of hundreds or sometimes maybe even thousands of containers managing those loads of containers across multiple environments using scripts and self-made tools can be really complex and sometimes even impossible so that specific scenario actually caused the need for having container orchestration technologies so what those orchestration tools like kubernetes do is actually guarantee following features one is high availability in simple words high availability means that the application has no downtime so it's always accessible by the users a second one is scalability which means you can scale your applications fast when you have more load on it and more users are trying to access it and the same way you can easily scale it down when the load goes down so it makes your application more flexible to adjust to the increasing or decreasing load and the third one is disaster recovery which basically means that if an infrastructure has some problems like data is lost or the servers explode or something bad happens with the service center the infrastructure has to have some kind of mechanism to back up the data and to restore it to the latest state so that application doesn't actually lose any data and the containerized application can run from the latest state after the recovery and all of these are functionalities that container orchestration technologies like kubernetes offer so how does the kubernetes basic architecture actually look like the kubernetes cluster is made up with at least one master node and then connected to it you have a couple of worker nodes where each node has a cubelet process running on it and cubelet is actually a kubernetes process that makes it possible for the cluster to talk to each other to communicate to each other and actually execute some tasks on those nodes like running application processes each worker node has containers of different applications deployed on it so depending on how the workload is distributed you would have different number of docker containers running on worker nodes and worker nodes are where the actual work is happening so here is where your applications are running so the question is what is running on masternode masternode actually runs several kubernetes processes that are absolutely necessary to run and manage the cluster properly one of such processes is an api server which also is a container an api server is actually the entry point to the kubernetes cluster so this is the process which the different kubernetes clients will talk to like ui if you're using kubernetes dashboard an api if you're using some scripts and automating technologies and a command line tool so all of these will talk to the api server another process that is running on master node is a controller manager which basically keeps an overview of what's happening in the cluster whether something needs to be repaired or maybe if a container died and it needs to be restarted etc and another one is scheduler which is basically responsible for scheduling containers on different nodes based on the workload and the available server resources on each node so it's an intelligent process that decides on which worker node the next container should be scheduled on based on the available resources on those worker nodes and the load that that container needs and another very important component of the whole cluster is actually an etcd key value storage which basically holds at any time the current state of the kubernetes cluster so it has all the configuration data inside and all the status data of each node and each container inside of that node and the backup and restore that we mentioned previously is actually made from these etcd snapshots because you can recover the whole cluster state using that etcd snapshot and last but not least also a very important component of kubernetes which enables those nodes worker nodes masternodes talk to each other is the virtual network that spans all the nodes that are part of the cluster and in simple words virtual network actually turns all the nodes inside of a cluster into one powerful machine that has the sum of all the resources of individual nodes one thing to be noted here is that worker knows because they actually have most load because they are running the applications on inside of it usually are much bigger and have more resources because they will be running hundreds of containers inside of them whereas master node will be running just a handful of master processes like we see in this diagram so it doesn't need that many resources however as you can imagine masternode is much more important than the individual worker nodes because if for example you lose a masternode access you will not be able to access the cluster anymore and that means that you absolutely have to have a backup of your master at any time so in production environments usually you would have at least two masters inside of your kubernetes cluster but in more cases of course you're going to have multiple musters where if one muster node is down the cluster continues to function smoothly because you have other masters available in this video we're going to learn about the main kubernetes components that we as kubernetes administrators or users will be working with most of the time to make it easier to understand all these components i'm gonna build a simple use case of a web application with a simple database and i'm gonna show you step by step how each component in kubernetes helps you deploy such an application setup and what is the role of each of these components so let's start with the basic setup of a worker node or in kubernetes terms a node which is a simple server a physical or virtual machine and the basic component or the smallest unit of kubernetes is a pod so what pod is is basically an abstraction over a container so if you're familiar with docker containers or container images so basically what pod does is it creates this running environment or a layer on top of the container and the reason is because kubernetes wants to abstract away the container runtime or container technologies so that you can replace them if you want to and also because you don't have to directly work with docker or whatever container technology you use in a kubernetes so you only interact with the kubernetes layer so we have an application pod which is our own application and that will maybe use a database pod with its own container and this is also an important concept here pod is usually meant to run one application container inside of it you can run multiple containers inside one pod but usually it's only the case if you have one main application container and the helper container or some side service that has to run inside of that pod and as you see this is nothing special you just have one server and two containers running on it with a abstraction layer on top of it so now let's see how they communicate with each other in kubernetes world so kubernetes offers out of the box a virtual network which means that each pod gets its own ip address not the container the pod gets the ip address and each pod can communicate with each other using that ip address which is an internal ip address obviously it's not the public one so my application container can communicate with database using the ip address however pod components in kubernetes also an important concept are ephemeral which means that they can die very easily and when that happens for example if i lose a database container because the container crashed because the application crashed inside or because the nodes the server that i'm running them on ran out resources the pod will die and a new one will get created in its place and when that happens it will get assigned a new ip address which obviously is inconvenient if you are communicating with the database using the ip address because now you have to adjust it every time pod restarts and because of that another component of kubernetes called service is used so service is basically a static ip address or permanent ip address that can be attached so to say to each pod so my app will have its own service and database pod will have its own service and the good thing here is that the life cycles of service and the pod are not connected so even if the pod dies the service and its ip address will stay so you don't have to change that endpoint anymore so now obviously you would want your application to be accessible through a browser right and for this you would have to create an external service so external services a service that opens the communication from external sources but obviously you wouldn't want your database to be open to the public requests and for that you would create something called an internal service so this is a type of a service that you specify when creating one however if you notice the url of the external service is not very practical so basically what you have is an http protocol with a node ip address so of the node not the service and the port number of the service which is good for test purposes if you want to test something very fast but not for the end product so usually you would want your url to look like this if you want to talk to your application with a secure protocol and a domain name and for that there is another component of kubernetes called ingress so instead of service the request goes first to ingress and it does the forwarding then to the service so now we saw some of the very basic components of kubernetes and as you see this is a very simple setup we just have a one server and a couple of containers running and some services nothing really special where kubernetes advantages or the actual cool features really come forward but we're gonna get there step by step so let's continue so as we said pods communicate with each other using a service so my application will have a database endpoint let's say called mongodb service that it uses to communicate with the database but whether you configure usually this database url or endpoint usually you would do it in application properties file or as some kind of external environmental variable but usually it's inside of the built image of the application so for example if the endpoint of the service or service name in this case changed to mongodb you would have to adjust that url in the application so usually you'd have to rebuild the application with a new version and you have to push it to the repository and now you'll have to pull that new image in your pod and restart the whole thing so a little bit tedious for a small change like database url so for that purpose kubernetes has a component called config map so what it does is it's basically your external configuration to your application so config map would usually contain configuration data like urls of a database or some other services that you use and in kubernetes you just connect it to the pod so that pod actually gets the data that config map contains and now if you change the name of the service the endpoint of the service you just adjust the config map and that's it you don't have to build a new image and have to go through this whole cycle now part of the external configuration can also be database username and password right which may also change in the application deployment process but putting a password or other credentials in a config map in a plain text format would be insecure even though it's an external configuration so for this purpose kubernetes has another component called secret so secret is just like config map but the difference is that it's used to store secret data credentials for example and it's stored not in a plain text format but in base 64 in encoded format but of course basics before encoding a secret doesn't make it automatically secure the secret components are meant to be encrypted using third-party tools in kubernetes because kubernetes doesn't encrypt them out of the box and there are tools for that from cloud providers or separate third-party tools that you can deploy on kubernetes to encrypt your secrets and that will make secrets secure so secret would contain things like credentials and of course i mean database user you could also put in config map but what's important is the passwords certificates things that you don't want other people to have access to would go in the secret and just like config map you just connect it to your pod so that pod can actually see those data and read from the secret you can actually use the data from configmap or secret inside of your application pod using for example environmental variables or even as a properties file so now let's see another very important concept generally which is data storage and how it works in kubernetes so we have this database pod that our application uses and it has some data or it generates some data with this setup that you see now if the database container or the pod gets restarted the data would be gone and that's problematic and inconvenient obviously because you want your database data or log data to be persisted reliably long term and the way you can do it in kubernetes is using another component of kubernetes called volumes and how it works is that it basically attaches a physical storage on a hard drive to your pod and that storage could be either on a local machine meaning on the same server node where the pod is running or it could be on a remote storage meaning outside of the kubernetes cluster it could be a cloud storage or it could be your own premise storage which is not part of the kubernetes cluster so you just have an external reference on it so now when the database pod or container gets restarted all the data will be there persisted it's important to understand the distinction between the kubernetes cluster and all of its components and the storage regardless of whether it's a local or remote storage think of a storage as an external hard drive plugged in into the kubernetes cluster because the point is kubernetes cluster explicitly doesn't manage any data persistence which means that you as a kubernetes user or an administrator are responsible for backing up the data replicating and managing it and making sure that it's kept on a proper hardware etc because it's not taking care of kubernetes so now let's see everything is running perfectly and a user can access our application through a browser now with this setup what happens if my application pod dies right crashes or i have to restart the pod because i built a new container image basically i would have a downtime where a user can reach my application which is obviously a very bad thing if it happens in production and this is exactly the advantage of distributed systems and containers so instead of relying on just one application part and one database part etc we are replicating everything on multiple servers so we would have another node where a replica or clone of our application would run which will also be connected to the service so remember previously we said the service is like a persistent static ip address with a dns name so that you don't have to constantly adjust the end point when a pod dies but service is also a load balancer which means that the service will actually catch the request and forward it to whichever part is least busy so it has both of these functionalities but in order to create the the second replica of the my application pod you wouldn't create a second part but instead you will define a blueprint for a my application pod and specify how many replicas of that pod you would like to run and that component or that blueprint is called deployment which is another component of kubernetes and in practice you would not be working with pods or you would not be creating pods you would be creating deployments because there you can specify how many replicas and you can also scale up or scale down the number of replicas of pots that you need so with pot we said that pot is a layer of abstraction on top of containers and deployment is another abstraction on top of pots which makes it more convenient to interact with the pods replicate them and do some other configuration so in practice you would mostly work with deployments and not with pods so now if one of the replicas of your application pod would die the service will forward the requests to another one so your application would still be accessible for the user so now you're probably wondering what about the database pod because if the database part died your application also wouldn't be accessible so we need a database replica as well however we can't replicate database using a deployment and the reason for that is because database has a state which is its data meaning that if we have clones or replicas of the database they would all need to access the same shared data storage and there you would need some kind of mechanism that manages which parts are currently writing to that storage or which pods are reading from the storage in order to avoid data inconsistencies and that mechanism in addition to replicating feature is offered by another kubernetes component called statefulset so this component is meant specifically for applications like databases so mysql mongodb elasticsearch or any other stateful applications or databases should be created using stateful sets and not deployments it's a very important distinction and stateful said just like deployment would take care of replicating the pots and scaling them up or scaling them down but making sure the database reads and writes are synchronized so that no database inconsistencies are offered however i must mention here that deploying database applications using stateful sets in kubernetes cluster can be somewhat tedious so it's definitely more difficult than working with deployments where you don't have all these challenges that's why it's also a common practice to host database applications outside of the kubernetes cluster and just have the deployments or stateless applications that replicate and scale with no problem inside of the kubernetes cluster and communicate with the external database so now that we have two replicas of my application pod and two replicas of the database and they're both load balanced our setup is more robust which means that now even if node one the whole node server was actually rebooted or crashed and nothing could run on it we would still have a second node with application and database pods running on it and the application would still be accessible by the user until these two replicas get recreated so you can avoid downtime so to summarize we have looked at the most used kubernetes components we start with the pods and the services in order to communicate between the parts and the ingress component which is used to route traffic into the cluster we've also looked at external configuration using config maps and secrets and data persistence using volumes and finally we've looked at pod blueprints with replicating mechanisms like deployments and stateful sets where stateful set is used specifically for stateful applications like databases just using these core components you can actually build pretty powerful kubernetes clusters before moving on i want to give a shout out to castin who made this video possible kessen's k10 is the data management platform for kubernetes k10 basically takes off most of the load of doing backup and restore in kubernetes from the cluster administrators it has a very simple ui so it's super easy to work with and has an intelligent logic which does all the heavy lifting for you and with my link you can download k10 for free and get 10 nodes free forever to do your kubernetes backups so make sure to check out the link in the video description and now let's continue so now that we have seen the basic concepts of kubernetes how do we actually create those components like pods and services to configure the kubernetes cluster all the configuration in kubernetes cluster actually goes through a master node with the process called api server which we mentioned briefly earlier so kubernetes clients which could be a ui a kubernetes dashboard for example or an api which could be a script or a curl command or a command line tool like cubectl they all talk to the api server and they send their configuration requests to the api server which is the main entry point or the only entry point into the cluster and these requests have to be either in yaml format or json format and this is how example configuration in yaml format actually looks like so with this we are sending a request to kubernetes to configure a component called deployment which is basically a template or a blueprint for creating pods and in this specific configuration example we tell kubernetes to create two replica pods for us called my app with each pod replica having a container based on my image running inside in addition to that we configure what the environment variables and the port configuration of this container inside of the pod should be and as you see the configuration requests in kubernetes are declarative form so we declare what is our desired outcome from kubernetes and kubernetes tries to meet those requirements meaning for example since we declare we want two replica parts of my app deployment to be running in the cluster and one of those parts dies the controller manager will see that the ease and shoot states now are different the actual state is one part our desired state is 2 so it goes to work to make sure that this desired state is recovered automatically restarting the second replica of that pod so here i have examples of a deployment and service configuration files side by side so the first thing is that every configuration file in kubernetes has three parts the first part is where the metadata of that component that you're creating resides and one of the metadata is obviously name of the component itself the second part in the configuration file is specification so each component's configuration file will have a specification where you basically put every kind of configuration that you want to apply for that component the first two lines here as you see is just declaring what you want to create here we are creating deployment and here we're creating a service and this is basically you have to look up for each component there's a different api version so now inside of the specification part obviously the attributes will be specific to the kind of a component that you're creating so deployment will have its own attributes that only apply for deployment and the service will have its own stuff but i said there are three parts of a configuration file and we just see metadata and the specification so where's the third part so the third part will be a status but it's going to be automatically generated and edit by kubernetes so the way it works is that kubernetes will always compare what is the desired state and what is the actual state or the status of that component and if the status and desired state do not match then kubernetes knows there's something to be fixed there so it's gonna try to fix it and this is the basis of the self-healing feature that kubernetes provides for example here you specify you want two replicas of nginx deployment so when you apply this when you actually create the deployment using this configuration file that's what apply means kubernetes will add here the status of your deployment and it will update that state continuously so for example if a status at some point will say just one replica is running then kubernetes will compare that status with the specification and we'll know there is a problem there another replica needs to be created sap now another interesting question here is where does kubernetes actually get the status data to automatically add here or update continuously that information comes from the icd remember the cluster brain one of the master processes that actually stores the cluster data so it cd holds at any time the current status of any kubernetes component and that's where the status information comes from so as you see the format of the configuration files is yemel that's why the extension here and generally it's pretty straightforward to understand it's a very simple format but yaml is very strict about the indentations so for example if you have something wrongly indented here your file will be invalid but other than that it's pretty simple another thing is where do you actually store those configuration files a usual practice is to store them with your code because since the deployment and service is going to be applied to your application it's a good practice to store these configuration files in your application code so usually it will be part of the whole infrastructure as a code concept or you can also have its own git repository just for the configuration files so in this video i'm going to show you what mini cube and cube ctl are and how to set them up so first of all let's see what is mini cube usually in kubernetes world when you are setting up a production cluster it will look something like this so you would have multiple masters at least two in a production setting and you would have multiple worker nodes and master nodes and the worker nodes have their own separate responsibility so as you see on the diagram you would have actual separate virtual or physical machines that each represent a note now if you want to test something on your local environment or if you want to try something out very quickly for example deploying new application or new components and you want to test it on your local machine obviously setting up a cluster like this will be pretty difficult or maybe even impossible if you don't have enough resources like memory and cpu etc and exactly for the use case there's this open source tool that is called a mini cube so what a mini cube is is basically one node cluster where the master processes and the worker processes both run on one node and this node will have a docker container runtime pre-installed so you will be able to run the containers or the pods with containers on this node so now that you have this virtual node on your local machine that represents mini cube you need some way to interact with that cluster so you need a way to create pods and other kubernetes components on the node and the way to do it is using cubectl which is a command line tool for kubernetes cluster so let's see how it actually works remember we said that minicube runs both master and work processes so one of the master processes called api server is actually the main entry point into the kubernetes cluster so if you want to do anything in the kubernetes if you want to configure anything create any component you first have to talk to the api server and the way to talk to the api server is through different clients so you can have a ui like a dashboard you can talk to it using kubernetes api or a command line tool which is cubectl and cubectl is actually the most powerful of all the three clients because with cube cdl you can basically do anything in the kubernetes that you want and throughout this video tutorials we're going to be using cube ctl mostly so once the cube ctl submits commands to the api server to create components delete components etc the work processes on minicube node will actually make it happen so they will be actually executing the commands to create the parts to destroy the parts to create services etc so this is the mini cube setup and this is how cubectl is used to interact with the cluster an important thing to note here is that kipctl isn't just for minikube cluster if you have a cloud cluster or a hybrid cluster whatever cube ctl is the tool to use to interact with any type of kubernetes cluster setup so that's important to note here so now that we know what mini cube and cube ctl are let's actually install them to see them in practice now let's see how to install and run mini cube there are many different ways depending on your operating system and its architecture so the best way is to reference the official documentation and here as you see minicube can run either as a container or a virtual machine and these are the resource requirements to run minicube on your machine so make sure you have enough resources for installation you just select the correct data for your machine in my case it's going to be mac os with a home homebrew installation and with one simple brew installed mini cube command i can basically install mini cube like this and as you see the latest mini cube version has been installed once minicube is installed we want to actually start or create a mini cube cluster which is also super easy as you see we simply execute a mini cube start however as i mentioned minicube must start either as a container or a virtual machine so we need either a container or a virtual machine tool installed on our laptop to run mini cube and this is going to be the driver for mini cube and opening the drivers page you see the list of supported drivers for linux mac os and windows and you see that docker is actually the preferred driver for running mini cube on all operating systems now this may be a little bit confusing because as you know inside the kubernetes cluster we run docker containers and it's important to note here that mini cube insulation actually comes with docker already installed to run those containers but docker as a driver from minicube means that we are hosting minicube on our local machine as a docker container itself so we have two layers of docker mini cube running is a docker container and inside mini cube we have docker packaged in minikube to run our application containers and for hosting minicube on our machine we can use docker so if you have docker already installed on your machine you're all set up to start a mini cube cluster if not also not a problem you can easily install it from here so clicking on install docker link this will take me to docker hub where i have docker desktop installation for windows and mac so i'm simply going to click in in my case docker desktop for mac and i'm gonna download and install docker and once downloaded just install it drag and drop into the applications folder and now we can start the docker daemon from the applications and as you see docker is starting up so the download and installation may take some time but once docker is installed and running we can switch back to the terminal and start the mini cube cluster using mini cube start command passing docker as a driver option using the driver flag with docker value and let's execute and this may also take a while when you're running it first time because it needs to actually create the cluster and download all the necessary images and components so the next time you do mini cube start it should actually go faster and as you see this command created a local kubernetes cluster on our machine with the latest kubernetes version 1.22 and now we can check the status of the cluster using minicube status command and we see that all the components inside are running and everything is configured and now start to actually interact with our cluster using command line tool and cubectl actually gets installed as a dependency when we install minicube which you see right here installing dependencies for minicube and kubernetes cli is actually cube ctl and that means we already have that available we don't have to install it so now i can do cube ctl get node and this will display all the nodes in the cluster in our case we just have one node which is control plane and the worker node at the same time and we see information for each node like the status the kubernetes version that it's running as well as when it was added to the cluster so with this we now have an actual kubernetes cluster running locally on our machine and we can start deploying applications in it so from this point on we are going to be interacting with the mini cube cluster using cubectl command line tool so minicube is basically just for the startup and for deleting the cluster but everything else configuring we're going to be doing through cubectl now we have enough knowledge to deploy a very simple but realistic application setup in a kubernetes cluster we will deploy a mongodb database and a web application which will connect to the mongodb database using external configuration data from config map and the secret and finally we will make our web application accessible externally from the browser so let's get right in so i have two resources here we're going to reference the kubernetes documentation to create our components which is a realistic way of working with kubernetes and also a docker hub where i have the web application image that i created which is publicly accessible so you can also pull it directly from the docker hub in your kubernetes cluster so first let's go ahead and create all the kubernetes configuration files that we need for deploying our application setup and for that i'm going to go to visual studio code where i have a kubernetes demo folder open and in this folder we're going to create four kubernetes configuration files that we need we're going to create a config map with mongodb database endpoint we're going to create a secret with username and password for mongodb and then we're going to create a configuration file for deploying a mongodb application and its service and then we're going to create kubernetes configuration file for deploying our simple demo app application with its service so the first file will be called config.yml and creating a config map in kubernetes is super simple for the syntax we can reference kubernetes documentation so i'm going to copy the first part here paste it in and that's basically the main syntax we're starting from let's call our config map config so we have the metadata and then we have the actual contents of this config map within the data attribute we have all the key value pairs that we define as external configuration within this config map in our case we just have one which we're going to call url as a key and of course we need a value for the mongodb url and the value will be the service that we're going to create for mongodb application and we're going to call that service service and in a couple of minutes you're going to see how to create this service and that will be basically all the configuration we need for creating config map so that one is done let's now go ahead and create secret dot yaml which will hold the username and password for mongodb application again to reference documentation i'm going to take this one and let's actually copy the whole thing so we have the secret kind instead of config map let's call this secret we have type opaque which is the generic type for defining secret data basically and we have the same data attribute here and let's actually create our own values let's call this [Music] user and password and as you already learned the values in secret are base64 encoded so we can just set the values plain text we have to encode them first and encoding values is super easy we're just gonna do echo and let's call it user base 64. encode it and the same way let's do paste those values and this will be our secret configuration and now when we create deployments for our applications we can reference any of the values defined in the secret or config map so let's see how that works again let's create a new file and let's call this dot yaml this is going to be a configuration file where we're going to create deployment and service for mongodb you can have separate files for them but it's a very common thing to put them together because all the deployments need services so you have them grouped in one yaml file and again let's reference the documentation for the deployment example syntax and we can then adjust the values as we need and as you see deployment configuration file looks a little bit more complex than configmap or a secret so let's go through the configuration and understand all these attributes so we have the metadata section and the specification and these are basically deployment specific configuration that we have in the specification section and let's start with the main part of the deployment which defines the blueprint for the pots and that blueprint is defined as a template so template basically is a configuration of the part within the configuration of deployment and you see that template section has its own metadata and own spec or specification just like deployment has its metadata and specification right so this part actually configures the pod within a deployment and in the specification of the pod we have the definition of containers so this is a list of containers as you learned you can have multiple containers in a pot but mostly one main application per pot and this is where we define which image will be used to create this pod in our case this is going to be a mongodb image and if we search for in docker hub that's basically the image name and you can find all the text in the text section and we're going to use the tag 5.0 so one go 5.0 that's where we define the image of the container within the pot we can name this mongodb this is just the name of the container and we also have the port where the container will listen and let's check our image and as you see mongodb starts at this port so we can just copy it and paste it in here so this basically just configures our deployment to create pods with a mongodb image version 5.0 so that's the core of a deployment now let's see what is all this other stuff here first of all we have this labels attribute in the metadata section and then we also have match labels attribute so what is this about in kubernetes you can give any component a key value pair labels so you can label anything from pod to deployment to configmap etc and labels basically are additional identifiers of the components in addition to the name for example so you can identify and address specific components using their labels now why do we need them first of all when we have multiple replicas of the same part each part will get a unique name however they can share the same label so we can identify all the part replicas of the same application using a specific label that all of them share and that's why in the metadata of the pod we always have this label so for pods labels is a required field for other components like deployment configmap etc labels is optional but it is a good practice to set them now when we create pod replicas how does deployment know which parts actually belong to it or how does kubernetes know which pods belong to which deployments and that is defined using this part right here so selector match labels is in the specification of the deployment as you see and this defines that all the parts that match this label belong to this deployment so that's why we have match labels here so this selector will match the pods created with this configuration because they have label app engine x now are these labels given or can you select any key value pairs well these are totally up to you you can call it whatever you want you can call it my key my value it doesn't really matter however the standard and a common practice in kubernetes is to use app key in the labels when labeling your applications and the value will obviously be whatever application you have so let's actually change and set the values to instead of nginx because that's our application and of course we want to match label app and let's also change this one right here to deployment and finally last attribute we have here is replicas which is super simple and straightforward this just defines how many pods you want to create using this blueprint in our case let's do just one replica because it's a database and as you learned if you want to scale databases in kubernetes you should use stateful set and not a deployment to keep everything simple we're going to stick to one replica and that basically configures our mongodb deployment and the pod blueprint now let's add a service configuration because every application needs a service in kubernetes and that's going to be a separate yaml unit or yaml section and we're going to separate it using three dashes which is basic yaml syntax nothing specific to kubernetes and again let's grab a service example and adjust it as we need now service configuration is much easier than the deployment as you see first let's change the name let's call it service and remember this is the end point which we will use to access and that's what we defined right here so this is the name of the service and in the specification we have service specific attributes first of all we have the selector attribute which you already know from here now why do we need a selector in service because as you know service needs to forward the request that it gets to its endpoint pods how does service know which pods belong to it and which ones it should forward the requests to well using the same label selector as we saw on deployment so this should match the label of the pods that will belong to the service which is and that's how service and pods will find each other and then we have the ports configuration which is also super simple service is accessible within the cluster using its own ip address and the port and we define its port right here and this can be any port that we decide on this could be 80 8080 doesn't really matter and we have the target port which is the port of the pods that belong to the service and logically enough the target port should always be the same as the container port because that's where the application in the pod is accessible that's where the service should forward the request to so again very important port attribute sets the port of the service and target port tells service to which port it should forward the request to the pods and this should be same as the container port port and target port values can be different or again it's a common standard to select the same port for the service as well just to keep things simple so let's save this and that's our configuration for mongodb deployment and service now i'm going to copy this whole thing create a deployment in service for web application for our kubernetes demo application and let's call this webapp dot yaml paste everything in and we can just adjust all these values in the service and deployment all the labels and label selectors of course and right here we of course need the correct image of our web application going back to our docker hub this is the name of my image and again this is publicly accessible so you can use it as well the tag is v 1.0 and there you go so this is a very simple node.js application which starts on port 3000 so that's why we need to define container port on 3000 and container port is same as target port on the service and we can set the service port to the same value and this will configure service for our web application so this is the basic configuration for deployment and service for any application in but we have one more thing to configure in our deployment components for both and web app which is we need to pass the data defined in the config and secret components first of all when starting a mongodb application we need to set user name and password so when mongodb application starts it will automatically generate username and password for mongodb and we can then use that to access it in our now how do we know how username and password can be configured in a mongodb on startup well we go to the image documentation and right here we see the environment variable names for username and password and these are actually required fields in most of the databases we have to set them otherwise we won't be able to access them so the next question is how do we configure environment variables in a container configuration so how do we pass environment variables to this application running inside the container well that's also very easy we have n attribute for that which is a list of environment variables with names values that's it so very simple so name is the environment variable name and value is the environment variable value so let's copy the name so this is the environment variable name that mongodb expects and we have to set a value whatever we want the username to be now we can directly set the username right here like this or in our case we're going to reference them from secret and config components how do we do that also pretty simple we do value from and we want to reference it from the secret so we do secret key ref and under that we have the name of the secret which we called secret and the key which is user so kubernetes will basically find a secret with this name and get the value set for this key and substitute it as a value for this environment variable and the same way we're gonna configure a password so let's take the password that's the name of the environment variable same secrets component this time with a different key and that's it so our mongodb configuration file is complete and when it starts a user with these credentials will be created when our web application starts it will need to connect to the database so we need to give this web application information about the database endpoint where can it access the database and which username and password to use to authenticate with the database and i have already configured this application inside to expect all these values as environment variables with specific names so we're going to pass these three pieces of data as environment variables to the web app application so let's do again the name of the environment variable the first one i actually called username and we can actually copy the same configuration and paste it here and you already see an advantage of using configuration from secret or config because if you need the same information in 10 different applications you create it once and reference it 10 times the second environment variable is for password and i called this one user pwd and finally our application needs the database endpoint which will be db url and this value is not in the secret but in configmap and how do we access value from config map very similar as the secret so we have the same value from and instead of secret key ref we have map kirev or key reference and then we have name which we called config and key which is the name of the key and that's it so we don't have any of the configuration values hard coded in our kubernetes configuration files we only have references which makes our configuration way cleaner so if something changes or the values change here we don't have to adjust anything in our deployments so connectivity with the database is configured and there is one last thing missing in our web application configuration before we deploy all this which is making it accessible from the browser we want to be able to type in some url and access our web application from the browser right and as you learned we have external services for that so we will need to adjust the service configuration a little bit right now these service configurations both of them are internal services so to make it external all we need to do is set a type which is by default cluster ip so that's the default type if we don't specify the type but we're going to set it to node port so node port is an external service type and it requires a third port which is called a node port so what is a node port port this is a port which will open on the kubernetes nodes on which the application will be accessible so on the node ip address in node port combination we will be able to access this service which will then access the pods behind it and node port range is actually defined in kubernetes so we can't just type anything we want here like this it has to be within the range of thirty thousand and thirty two thousand seven hundred sixty seven so anything within this range is fine as a value so we can do 30 000 or 30 100 doesn't really matter so let's set this as a value and this completes the web app configuration file now we have a very simple but also pretty realistic for deploying an application with its database with external configuration in the cluster so as a final step we're just gonna create all these components one by one in kubernetes so i'm gonna open a terminal and we already have a mini cube cluster running but there are no components inside so first we need to create the external configurations because they need to be there when we create mongodb and web application deployments because they reference those configurations so let's create config and secret first to do that we have cube ctl apply command with minus f which stands for file which takes a kubernetes configuration file as an input like this and creates whatever is defined inside and as you see config was created now let's create longer secret next we're gonna create a database because our web application depends on so it should start first and again let's do cube ctl apply with mongo.yaml as an input and as you see deployment and service were created and finally let's deploy our web application and there you go so everything seems fine but of course we want to check all the parts and all the components that were created in the cluster so for that i'm going to actually switch to command line so that we can see it better and first we're going to do cube ctl get all which gives you all the components created in the cluster which includes deployments the pods behind the deployment and all the services and as you see we have deployment and web app deployment parts each one with one replica running and we have the services for mongodb and web app and web app service is of node port type which means we can access it externally however we don't see configmap and secret here we can get them using kubectl get config map and cubectl get secret commands so as you see displaying any component is pretty easy using cube ctl you just do kubectl get and the name of the component like pod and you get a list of those components with some additional data and cubesatl is actually a very powerful tool and it has a bunch of sub-commands so as a natural documentation for cubectl to basically have an overview and see what you can do with it you can always use cubectl help as a documentation which lists all the sub-commands you can use with it one of them which we already used get and for each sub-command like cube ctl get you can also get some help and basically see all the examples plus all the available options so you can navigate all the options you have here so cube ctl get is obviously the most common command you're going to use to list all the components if you want to see more details about a certain component you can use cube ctl describe command for it a name of the component like a service for example and the actual instance of that component like web app service and this will give you more detailed output about that specific component same way you can also do cube ctl describe pod and then name of the pod like this one and this will give you details about your pot including the status of how the pod was scheduled the container configuration labels etc and finally of course when you have applications running in your cluster you want to check the logs to troubleshoot debug or just make sure that everything is fine within the pod and you can do that very easily using kubectl locks command and just specifying name of the pot like this this gives you logs of the container inside and you can even stream the logs using minus f option so the final step we want to validate that our application is also accessible from the browser and for that we actually configured the service and we can actually get the service using service or svc comment so how do we access this service from the browser because this is the port we're going to use to access it but which ip address is it accessible at well the node port service is always accessible at the ip address of the cluster node so all the work nodes that the cluster has in our case we just have one which is the mini cube so we need the ip address of the mini cube to get we just do mini cube ip or using kubernetes we can also get get node which gives you mini cube a white output or a longer output than what you see here which will give you the ip address of the node which is the same as this one right here and by the way you can use the all white option for any other get command for services pods etc to get some additional information like this so let's grab the mini cube ip address and access the application at this port which is 30 and there you go this is our web application which is connected to mongodb and we can also validate that by editing something and saving because this request goes to and if we refresh the changes should still be there awesome so we deployed an application with its database in kubernetes which is a blueprint configuration for most common application setups you're gonna have plus you also learn a couple of cubesitl commands as well as how to reference the kubernetes official documentation to help you configure and create all the components i hope i helped you learn a lot about kubernetes with this crash course and you feel much more confident with kubernetes now if you're serious about learning kubernetes in depth i actually have two more resources for you as i mentioned at the beginning if you want to really become an expert in kubernetes and learn how to build and administer a cluster from scratch then my complete kubernetes administrator course will be a perfect resource for you but if your goal is rather to become a devops engineer then our complete devops educational program will be the best fit for you where during a six-month program you learn all the necessary concepts and technologies including kubernetes which you need to get started in devops or cloud engineering if you're interested you can find the links in the video description below and with that thank you for watching and see you in the next video