Welcome back, everybody.
In this section, we reach the final stage of our MongoDB deployment, metamorphosis, because we're
going to deploy it through an operator okay.
So the first phase if we recap, was we manually created all of the configuration files and created
a very minimalistic deployment.
This deployment was actually very effective and suited our purposes just fine.
But then upon expanding our Kubernetes toolbox, we learned about the helm package manager, and we
learned that there are many repositories online with many, many helm charts that allow us to deploy
whatever softwares we want with minimal configuration.
So these helm charts already contain all of the configuration files that we really don't need to touch.
All we got to do is update a values.yaml file in order to steer the deployment towards whatever it is
that we want to accomplish.
Now, the final phase of our metamorphosis will be to use helm to simply deploy an operator.
An operator extends the Kubernetes API and consists of many custom controllers that watch for custom
resource definitions and based on whatever you define inside of these custom resources, whatever desired
state you define in there, your operator, through its custom controllers, will create your desired
deployment and will always be monitoring your deployment to always ensure that it's at that desired
state.
So the gist of an operator is that it consists of custom controllers that watch out for custom resources,
and based on whatever custom resources that we define, it's going to create actual Kubernetes resources
to configure our deployment and consistently monitor them to ensure that they're always at that desired
state.
Now controllers aren't a foreign concept.
We've actually been dealing with them all throughout this course, but we've only been dealing with
the core controllers that are native to Kubernetes.
So, um, a very prominent example is the deployment controller.
So whenever you set up a deployment object with a desired state of, let's say three pod replicas and
whatever pod template you want all of your pods to have, your deployment controller is what's watching
for your deployment object, creates a replica set based on whatever your desired state is, and continuously
monitors your replica.
Set objects to ensure that they're always at that state.
And that's how we get things like rolling updates.
So if I update my deployment to use another version, the deployment controller is watching this resource
and continuously updating the target resource.
Okay.
Uh, the replica set controllers, whenever the replica set objects change, it will create new paths
and monitor the pod state.
So I hope you can see the pattern.
The HPA controller consistently watches out for HPA objects and continuously monitor Pod metrics.
To know when to create and terminate new pods.
Your PV controller consistently watches out for your PVC object, and based on whatever desired state
you define, it's going to bind a persistent volume based on the requirements here, and continuously
monitor the PV status to ensure that it's in adherence to whatever we define here.
So a Kubernetes controller follows this basic pattern.
It watches out for a desired state, creates whatever resources it needs to create, and continuously
monitors them to take it from whatever its current state is to the desired state that is defined in
the resource.
So if I create, let's say, another deployment object with a new desired state.
The deployment controller, which is consistently watching out for our deployment objects, will look
at the current state of whatever the replica set objects are and update them to a desired state.
So that's why we have the controller manager running in the master node, which coordinates all of these
core controllers.
Okay.
And these benefits that we get from Kubernetes, they all come by virtue of having all of these core
controllers running in a loop, consistently watching out for whatever resources we deploy, and updating
target resources accordingly, ensuring that they get to a desired state.
But one benefit that we've yet to leverage, which we will in this section, is extensibility.
Because operators, what they do is they extend the Kubernetes API.
It provides a set of custom controllers that watch out for custom resources.
So let's note the distinction before we had your standard core controllers like like deployment controllers
which watched out for standard resources like deployments.
But operators, they extend the API in a way where now we have these custom controllers looking out
for custom resources.
And based on these custom resources that we can now define, it will create whatever deployment that
we want.
Okay.
So this simply reiterates the definition.
Uh, it the gist is it's a set of custom controllers that watch for custom resources and will create
Kubernetes resources consistently monitor these resources to always ensure that they are at whatever
desired state that we define in our CRD.
So this is a schematic that depicts, um, how an operator works.
Note how similar it is to the schematic for a Kubernetes controller.
Okay.
So you've got the operator which provides custom controllers, will watch for custom resources that
we create using custom resource definitions.
The operator will look at the desired state that we defined in our custom resource, and accordingly,
it will create Kubernetes resources that can adhere to our desired application state.
So if we look at the MongoDB operator specifically, uh, it extends the Kubernetes API in a way where
we can define a custom resource called MongoDB community and the MongoDB community custom resource.
We can define things like how we want authentication to the MongoDB database to occur.
We can specify how many MongoDB replicas that we want.
The operator will watch for our desired state and create all the Kubernetes resources that it needs
to create in order to ensure that we're at that desired application state.
Continuously monitor these resources in the event that if a failure ever happens, it can continuously
reconcile these errors and always ensure that we're adhering to whatever we defined in the custom resource.
So that's enough about that.
Uh, this is from the earlier lecture.
Um, where is the code?
What I want to do to start off this lesson is I want to uninstall the helm chart from section 12.
Helm uninstall.
Well, let's actually start by listing all of the helm releases.
All right.
The one we want to uninstall is the following.
Helm uninstall the MongoDB helm release from the namespace MongoDB.
We also want to start off on a clean slate and just stay on the safe side.
Maybe delete any PVCs PVCs services you can say service or SVC doesn't matter.
Um, statefulsets or pods that may persist in that namespace.
And good.
I wasn't expecting anything, but you can never be too safe.
Uh, the helm release upon it being uninstalled will just remove everything that came with it.
And now what I want to do is say helm search repo.
And I want to remove the Bitnami repository.
So what I can do is simply say helm repo remove bitnami.
That's gone.
So if I say helm search.
So if I say helm search repo again no repositories configured.
All right.
We're off to a clean slate.
Funds about to start.
But one more thing before we, um, get too excited.
Let's copy the following.
We'll say section 13.
Final section of this course.
Let's get started okay.
So we can start by adding the repository that has all the related helm charts.
Now we can define an alias for that repository.
We can call it MongoDB.
We can call it my MongoDB repo.
Whatever your heart desires I think MongoDB is a good enough name.
Helm repo add MongoDB.
Um, the repository from where we're going to grab all of these helm charts is they're all hosted at
the following end point.
Let me make sure I wrote this right https MongoDB Github.io.
Yep, that's the right one.
And after you've added this repository to your local helm configuration.
Um, you know what?
Just for reference, just want to reiterate that it's good practice to always update your helm repositories.
I didn't need to in this case because I just added this repository.
But whatever.
We'll search, uh, the repositories and we just have the one MongoDB has all of these different helm
charts.
Um, here is the latest chart version for each one.
What I want to do is specifically deploy the community operator for MongoDB chart version 0.10.0.
Your chart version will be different than mine, probably more up to date depending on when you're watching
this video, but for the sake of consistency, please use the same chart version as me.
All right, so what I'll do is I'll say helm install community operator I want to install.
I want to deploy the following helm chart.
I'm going to specify a version.
Use the same version as me 0.10.0.
And I want to deploy.
I want to release the contents of the helm package into my MongoDB namespace.
Okay.
Beautiful.
Now what I want to do is say kubectl get pods n MongoDB to verify the installation.
Operator up and running.
Beautiful.
Now, just to, um, vary things up, we'll say get all dash n MongoDB.
Okay.
Everything is working well.
Now what I want to do is say kubectl logs dash f Kubernetes operator.
When I output the logs of this pod inside of the namespace MongoDB and notice it says watching namespace
MongoDB.
This is really interesting.
Remember that the operator continuously watches for the presence of a custom resource.
Okay.
Um, and it's going to use whatever we defined in that custom resource to know how it's supposed to
deploy our MongoDB instance.
Okay.
So whatever desired state we define in our CRD, the operator is going to create all of the Kubernetes
resources and continuously manage them in a way to ensure that they always match our desired state.
It follows that the CRD we deploy, the custom resource we deploy, needs to be inside the namespace
MongoDB.
If it isn't, the operator isn't going to recognize that it even exists and nothing will happen if it
does.
See the custom resource inside the MongoDB namespace?
Then it's going to start orchestrating the deployment of our MongoDB app.
It's going to deploy all of these Kubernetes resources and ensure that they adhere to our desired application
state.
Okay.
How are we going to deploy a custom resource definition?
Well, this is where I urge you to start getting comfortable going on going online, reading documentation
about whatever operator you're using, what crds it provides, how the crds work, what the different
fields and all the crds mean.
Once you have a clear understanding of how they work, then you can very easily steer your operator
towards a deployment that you want to accomplish.
Okay, so I've already done that.
What I'm going to do is skip ahead towards the MongoDB.
Kubernetes operator repository, which contains a lot of samples that we can use as inspiration to.
Set up our custom resource.
Okay, so you can feel free to go through all of these.
Um, MongoDB community examples.
They demonstrate how the deployment can be manifested in different ways.
Um, this is an another example.
Um, that one looks good.
Let's go ahead and use this one.
So because this video because this code may change with time, probably will.
What I'll do is instead of linking you to the following page, I'm going to just put all of this code
in a file inside of your resources folder.
Feel free to copy it from there.
And then what I'll do.
I'll delete this values.yaml file.
And I'm going to create a new file called MongoDB community dot YAML.
All right.
Paste this in.
This is just a template that we're going to update momentarily.
I'm going to explain to you what all of these fields mean.
I'm able to because in the past I've reviewed the documentation.
I know exactly how everything works here.
So I really want to stress, when you do venture out into the wild and start deploying your own operators
and leveraging their crds, you need to be comfortable reviewing documentation, going on StackOverflow,
going on the GitHub issues, understanding what everything means before you can start configuring the
deployments.
Okay, so in this case we're going to set up the MongoDB community in such a way that it will tell the
operator to deploy a single instance of MongoDB.
So it's pretty cool how we can manage the replica sets over here.
Remember, a replica set is simply an object that dictates how many pods get created.
We just want one MongoDB instance to run.
Um, these pod deployments are really, really heavy.
We don't want to tax our local machine too much.
Um, I'm going to call this, uh, resource, um, MongoDB grade submission.
Okay.
And actually, before I continue, I want to emphasize how cool it is it that we can, uh, create a
MongoDB community object.
So, so far in this course, we've always been deploying the core objects that are native to Kubernetes
deployments, secrets, stateful sets, but operators, what they do is they extend the Kubernetes API,
and they provide us with custom resources that we can use to steer the operator towards a deployment
that we want to accomplish.
Different operators provide different custom resources.
We want to use the MongoDB community resource to steer the operator towards a MongoDB deployment that
suits us.
We're going to leave all of this the way that it is.
I'll explain what Scram authentication is in just a second.
Um, the user that we want to authenticate against, a, let's say, a grades database, we're just
going to call a user, um, and a password secret ref relies on a secret to give this user a password
that it can use to authenticate against the grades database.
So what I'm going to do here is create a MongoDB.
Admin password dot YAML.
Okay.
Uh, we can just autocomplete secret.
Call this um mongo db admin password.
What did I call it?
Admin.
Bad habit MongoDB user password.
I think that makes more sense.
Okay.
And the password I'm just going to make it password 123.
Um, what I'll do is I'll say echo dash n password 123I want a base 64.
Encode it.
All right.
Because remember anything under the data object Kubernetes assumes will be base 64 encoded.
And wherever it gets loaded in will be base base64 decoded, so this will translate to password 123
the following.
Okay, just wrap this thing up in quotes.
Cool.
Now what I can do here is reference MongoDB user password.
It's going to extract the password field.
Give it to the user to authenticate.
And now we want to give the user a role for um the grades database.
Now the MongoDB roles again you can look up there's database user roles database administration roles.
Because our grade submission API, which is authenticating against the grades database, is going to
be reading and writing to the database, removing data, updating data, inserting finding whatever
the read write role makes the most sense.
So we'll go back here and we'll give it a role of read.
Write for the grades database and the scram credentials secret that gets created.
Let's give it a name of MongoDB grade submission scram credentials.
And you're probably thinking, what the heck is this scram thing?
Ryan?
Ryan, um, let me explain.
So, um, on the server side, MongoDB uses this authentication mode to authenticate this user without
the user having to send this password over the network.
Okay.
So you'll remember that in the connection string you've got the username password the host and the port.
And the idea is that the great submission API would use the host and the port to locate the database,
send over the username, but the password doesn't get sent over in plain text.
What happens is these scram credentials.
They are derived based on whatever password we choose, and MongoDB will essentially use the Scram credentials
to basically ask the Great Submission API a question, if you will.
And the API has to compute a response based on the password.
And if MongoDB accepts the response, then authentication occurs.
So ultimately Scram is a secure way of using basic authentication against MongoDB without exposing the
password over the network.
Okay.
Um, it's the standard way of authenticating to MongoDB.
And besides, don't worry, nothing really changes on the great Submission API, and all of the Scram
related authentication is handled on the server side.
On the MongoDB side.
Okay.
All you got to do is give the secret a name and it'll take care of the rest for Statefulset.
I don't think there's anything in particular I want to modify yet.
I'm just going to stick with whatever default values we have.
There's nothing on a specifically customize, so Statefulset.
You'll remember under template is where you specify how every pod will be configured.
Um, no need for volumes for the MongoDB agent.
I'll explain why we need to modify that in just a second.
Especially if you're using a MacBook computer like myself for the same reason as last section.
So let's just go ahead and deploy this MongoDB community resource.
And remember we need to deploy it in the namespace MongoDB.
Otherwise the operator won't recognize it.
But you know what?
Just to mess around.
Let me deploy it in the default namespace first, just to show you that, you know that wouldn't really
do anything.
Am I CD into the right folder?
I'm not.
We'll CD into.
Section 13.
Oh, what am I doing?
Uh, CD into MongoDB.
There.
Clear the output.
Kubectl apply dash f MongoDB community dot YAML.
It gets applied.
Okay, but if I say kubectl get pods and the default namespace, nothing really happens.
If I say kubectl get MongoDB community.
We get the MongoDB.
Great submission custom resource, but again, nothing really happens because the operator didn't recognize
it.
The operator is looking for things inside the MongoDB namespace.
And you know what?
Let me call this file MongoDB.
Great submission dot YAML.
That just seems like a more fitting name.
Okay, so what I'm going to do is cube CTL delete the MongoDB community resource from the default namespace,
clear the output.
I'm going to apply it.
I'm going to apply this deployment.
Make sure it goes in the MongoDB namespace where the operator will recognize it okay.
0-F- file.
All right.
Now, if we go ahead and say cube CTL get uh, MongoDB community dash n MongoDB.
Okay.
At least the operator recognized the resource and I must have made a dumb mistake somewhere.
So when you make dumb mistakes, what do you do?
You debug.
We're all human.
It happens.
So let's describe this resource.
Describe, um, the MongoDB community.
Error.
And.
I knew I would have made a mistake like this.
Let me zoom out.
This is way too zoomed in.
This is called MongoDB user password.
And I referenced that.
That's.
Oh, I didn't actually apply this secret yet.
Dumb dumb.
Okay.
The next one gram.
Secret MongoDB grade submission.
Scram!
Credentials are.
Darn it, I forgot about that.
It automatically appends the scram credentials part, so you really just typically give it the same
name as the MongoDB community resource.
Let me try this again.
Cube ctl delete.
Anyways, I like getting these bugs in front of you because it shows you that you know I'm forgetful,
I'm not perfect, but as long as I'm comfortable debugging and describing my resources, outputting
logs from my operator, etc., looking at documentation, GitHub issues, whatever.
Nothing is insurmountable.
Everything is easy.
Well, not always easy, but you know, manageable cube CTL delete the MongoDB community dash dash all
resource inside of the MongoDB namespace.
Okay, we'll start by applying the secret kubectl apply dash f MongoDB user password.
Actually, before doing that, let me put this in the namespace.
Uh, MongoDB.
Really important.
Okay.
And we'll say kubectl apply dash f MongoDB.
Great submission dot YAML.
Try it out now.
Kubectl get MongoDB community.
Dash n mongo phase pending.
Beautiful.
All right.
Um, I'm going to fill up my cup of water.
I'll see you in a bit.
Okay.
Let's see what we got.
Still pending.
All right.
Let me say kubectl get pods dash n MongoDB.
All right, so we've got, uh, MongoDB.
Great submission pod, uh, MongoDB instance that's been started up by our operator, among many other
Kubernetes resources that it created.
Let me actually say kubectl get all dash n MongoDB.
It created lots and lots of resources, a stateful set of services.
But the main one I'm interested in is the pod.
At the moment there are two containers in this pod.
One of them is running, the other isn't.
I want to know which one isn't so that I can troubleshoot the issue we're debugging live.
If you're using a windows computer, chances are this worked for you.
But you know, just follow along.
Use the same configuration as me anyways because it's going to be compatible with both architectures.
Anyways.
I don't want to spoil the bug.
Let's figure out what it is.
Describe this pod inside of the MongoDB namespace.
Um, and here, um, we can see that it's the MongoDB agent container that is failing.
Okay.
The MongoDB agent, this image specifically isn't compatible with ARM 64.
Um, should run fine on your windows machine windows users, but MacBook, M1, M2, whatever.
We need to override the container for the MongoDB agent to use a different image, one that actually
supports, um, both architectures.
So what I did is I went to the Quay.io registry, went into the MongoDB repository, looked up different
image versions for the MongoDB agent, and eventually I actually ended up finding one that supports
both architectures.
Troubleshooting at its best.
Okay, so this is the registry for all the MongoDB images for the MongoDB agent.
These are different versions of the image.
We can see one right here 12.0 .32.78571.
This image version is compatible with Linux on Amd64 and Linux on ARM 64.
So what I'll do is I'll copy this over.
All right.
And I'm going to update my statefulset such that all of the pods that it manages, um, we want to update
the template such that the MongoDB agent container uses the image from the registry key.io.
Okay.
Um.
Slash MongoDB.
Slash the following.
Uh, eliminating special characters, uh, followed by the image tag that's actually compatible with
both our, uh.
I could have just copied this.
I'm such a knucklehead.
Let me copy it.
Just to be safe.
I don't trust myself.
I'll.
You know what?
You can probably paste this in yourself.
I don't need to put it in the resources folder.
Um, this I will put in the resources folder, the image version that we specifically want.
Or you can feel free to copy.
It's 12.0
.32.7857-1.
Okay.
And that's pretty much it.
Uh, the other container within the pod is working just fine.
Um, so let's go ahead and deploy this thing.
So cube CTL windows users.
Sorry you had to suffer through this.
Yours worked this whole time.
But you know, it doesn't hurt to kubectl delete MongoDB community dash dash all dash n MongoDB.
Or I could have just reapplied it.
Whatever.
And my computer is really slowing down.
Kubectl apply dash f will apply the updated
resource v1 cannot be handled as master unknown field spec dot statefulset.
Oh my bad guys, I, I, um, I ruined the template that we got.
There was originally a spec over here that I removed by mistake.
So we specify the behavior of the stateful set.
And part of that behavior is, um, defining the pod templates.
For each pod template, we specify its runtime requirements, how the containers are going to run.
We specifically overrode the MongoDB agent.
All right.
So this is my own mistake.
I didn't invent this.
It was already present in the template.
I just removed it by mistake.
Okay.
So let's say kubectl get pods dash n MongoDB.
Everything should now work.
It's initializing.
We'll give it some time.
All right.
Try it again.
Okay.
At least there's no error.
Choo choo choo choo choo.
One out of two containers is running.
We need to wait for the other one while we're doing that.
What I'm going to do is set up the URI that the great Submission API is going to need to connect to
the MongoDB instance.
Okay, so here we need to start by specifying a username.
So that's going to be user followed by password 123.
So after we've defined the credentials, then we specify the name of the service.
Okay.
So kubectl get service dash n MongoDB.
Then the name of the service is MongoDB.
Great submission service.
The namespace that it's in is MongoDB.
That doesn't change dot service dot cluster dot local 27017.
Then we're going to say slash grades.
Because remember upon the cluster IP service forwarding our request to the MongoDB database, it's going
to read this connection string.
And it's going to try to authenticate our user against a grades database.
So final URI username password host and port so that we can connect to the database followed by the
database.
We want to connect our user to I did, I buy enough time for the pod to start up.
You know what?
I think this might just be a resourcing issue.
Whether or not the MongoDB agent runs, I don't really care.
We'll still be able to establish the connection.
Kubectl describe pod dash n MongoDB.
Okay, that's all right.
We'll revisit this.
Um, what I want to do is CD out of MongoDB.
CD into the grade submission API folder.
Start by helm uninstalling the grade submission API release that exists in the grade submission namespace.
Then what I'll do is I'll reinstall the helm release using the helm chart in the current directory.
Dash n grade submission.
Let me just check over this again.
Okay.
Mongo dot service.
Dot cluster.
Dot local.
Beautiful.
Now what I'll go ahead and say is kubectl get pods dash n great submission.
Terminating.
Attempting to connect.
We'll give it some time.
Kubectl logs dash f create submission.
Connected to MongoDB.
Beautiful.
And that's pretty much it.
Guys.
You are able to deploy MongoDB using three separate methods.
You created all the deployments yourself at first.
Then you used a helm chart from the Bitnami repository.
And then we're able to use a helm chart to deploy an operator.
And then using a CRD that the operator provides, steer the operator towards a deployment that suited
our purposes.
Okay.
Look at how easy it was to set up such a complex deployment.
We had to do some troubleshooting because Arm64 wasn't supported by the image used originally for the
MongoDB agent, but we were able to fix the issue for windows users.
You wouldn't have had to change anything in the stateful set, you would have been just fine.
And notice how simple your CRD would have been, how easy it was to deploy a MongoDB instance that is
continuously being monitored by an operator.
If an error were to ever happen, the operator is continuously reconciling these errors.
Try to bring it back to the desired state that we specify in our resource right here.
I think I'm probably going to have to uninstall my great submission portal helm chart, reinstall it,
and then test everything out.
I don't feel like testing everything out.
Everything works.
Otherwise the readiness probe wouldn't have deemed this application to be ready.
Let's go ahead and check on our pods in the MongoDB namespace.
Um, unable to connect to server.
Wow.
So my Kubernetes cluster is dead.
Um.
Sorry, guys, nothing I can do.
Computer has run out of resources.
Can't really record and run these apps at the same time.
Oh, finally, our agent is up and running.
Beautiful.
I'm going to stop this demo right here because my computer is heating up.
And if I don't, it might just shut down.
Hope you enjoyed this lesson.
We've accomplished so much in this course.
Next section, we're going to wrap everything up with a very, very fun demo where we deploy our cluster
on AWS.
Okay, see you soon.