About this video
What You'll Learn
- Walk through kubectl commands to create and inspect pods from YAML specs in a local Kubernetes cluster.
- Build and update multi-container pods with sidecar patterns, then observe replica-based rollout behavior.
- Configure ConfigMaps and secrets, expose a container via port-forwarding, and manage scope with namespaces.
David Simmons joins with zero Kubernetes experience and gets walked through kubectl, pods, deployments, multi-container pods, services, ConfigMaps, Secrets, namespaces, port-forwarding, and DaemonSets on a Docker for Mac cluster.
Jump to a chapter
Full transcript
Generated from the English captions. Timestamps jump the player to that moment.
Read the full transcript
1:00 Introductions
1:02 Hello, and welcome to today's session. Today, I am joined by David Simmons, head of developer relations request DB, and we are going to take a look at Kubernetes. How are you, David? I'm great. I love the sig sig v there at the end of your countdown. That's awesome. Yeah. I wanted to do something that is kinda geeky and took inspiration from the IT crowd. I really like the their intro and the ending where it's kinda windows crashes and it it does that weird trailing thing. Yep. But I I don't have the creative expertise to actually do anything that intricate, flashing a
1:38 red banner on the screen. I got that better. You got that better. Yeah. I love the IT crowd too. That's that's fantastic. Oh, yeah. It's so funny. So today's session, let's let's start with a question actually. In a word, what is your knowledge or expertise of Kubernetes? Well, the the word I would choose, I probably don't wanna say on on a a live private, but I so here's my thing. And this is why I sort of, you know, talk to you about doing this is I understand the point of Docker for the most part. I don't like using it mostly because the
1:50 What is David's knowledge of Kubernetes?
2:19 Mac version of Docker will suck the life out of absolutely any machine so far. And so Kubernetes is just, like seems to me to be just extra Docker, and I don't get it. Because I don't most of that, you know, people say, oh, I'm gonna run, you know, these 16 Docker containers. Like, if I tried to run 16 Docker containers on this laptop, it would die, and it's a brand new Mac laptop. So Yeah. I like that description. Kubernetes is extra docker. I think we'll try and build on that today a little bit. But you're right.
2:56 Definitely right. But docker for Mac, where it is the easiest way to kind of have a working Kubernetes control planning on a Mac. The battery consumption is is pretty ridiculous. I am very vigilant on closing it now whenever I definitely do not need it. So that's great. We're starting from essentially a fresh slate and you're gonna keep me right as we kind of go through today's I guess it's a tutorial of sorts where I will do stuff with Kubernetes. You're gonna probe me with loads of questions. We're gonna try and get something working on Kubernetes and
3:30 hopefully, I have the ability to explain what the hell I'm doing, which is questionable at best, but we will see how we get on. That's where the fun part is. Yeah. So what I would say for the people that are watching on YouTube, feel free to liberally use the comments. If you wish to ask questions, we will make sure that we try and tackle them as we go. So leave comments, we will address them. I think what I'll do is just share my screen and we'll dive straight in. This maybe seems a bit brave, but
4:05 there. Awesome. Okay. So this is just the Kubernetes website. What I would say today is I am I would say rather knowledgeable in Kubernetes. I know what I'm doing, but I have not memorized all of the YAML in the world. So where I am not able to generate the YAML for my Versus Code Editor, I will be using the documentation and that is okay. Nobody expects you to remember how to type tens of thousands of different combinations of YAML. We'll just normalize that. Then I was just telling somebody that I'm mentoring. The number of times I still have
4:40 to Google, you know, how to do a four loop in whatever given language I happen to be using that day is ridiculous. I've been coding for thirty years. So don't don't ever let somebody tell you that you should know all this stuff. Oh, yeah. For sure. Definitely. Like, the longer you do this, the more you forget, and you always have to kinda look that stuff up. It's Mhmm. Natural. In fact, I would think people that are good at this are people that are really good at understanding the problem, but enough to ask the right question
5:06 to then go find the answer rather than just inherently knowing the answer. Right. Alright. So let's I just reset my Kubernetes cluster, which is what the screen is here. It's done. Now, I am gonna type a few commands. I don't and then we'll we'll backtrack a little bit and talk about what Kubernetes is doing, but our main way that we are going to consume Kubernetes today is through the kube control command line application, which we can run on our terminal. And the first primitive that we're gonna cover today is a concept of a pod. So when I run get pods, you'll see
5:30 Containers
5:40 that I have nothing. So that's just me doing the whole magician sleeve thing. Right? There's nothing pre running here. This is an empty vanilla generic Docker for Mac Kubernetes cluster. So let's back up a little bit and I'll go back to just our nice little talking mode. As let's try and break down and understand what we should cover as a backstory or context first. So containers, the docker a bit of this conversation. Kubernetes is a control plane for managing and orchestrating containers across one or more machines. If we were to explain a container, then we have to kinda get down into
6:22 some Linux primitives. So a container has a way of using the Linux kernel to segment certain aspects of the the process that is running to protect it from the rest of the host. Right. That maybe is that sounds a little bit more complicated than I maybe intended it to be. No. The the container part makes sense to me and and sort of having something to control all the different containers makes sense to me. But coming from you know, having grown up in the the old world, you know, client server, you know, each sort of server has its own
7:03 part in this. A lot of what I don't get is how how you can spin up extra containers and have the rest of the containers know about what's going on. Right? And how this actually helps me rather than, why don't I just have, you know, a big server that can do this and and call it a day? Hi, doggy. Yeah. Rawkode. So you're comfortable with the container. Excellent. And you wanna understand the sum of the magic components of what Kubernetes is doing. Yes. So with that, let's go straight into, like, let's go into the pod one zero one
7:40 Pods
7:42 then. So let me just make sure this is readable. So Oh, I have to save that as a file. Okay. So I'm on computer. It could it it could entirely turn into a a a live session of me yelling at my dogs, by the way. Just so we know. That that's I'm perfectly comfortable with that. Don't you worry about it. Now, I'm gonna just quickly get this to as minimal as I need it to be and then we'll go through the different components of this. So we can't deploy a container to Kubernetes, really. What we deploy to Kubernetes,
8:27 it's a primitive called a pod, and a pod is a collection of one or more containers. So Okay. With with Docker, you could do Docker run NGINX, and what that does is it creates Linux name spaces and control groups to kinda wrap that process up in its own little bubble. Yep. But Kubernetes doesn't do that. It actually creates the bubble and then puts containers inside of it and it can have more than one container that share the same resources within that bubble. I mean, I'm not comfortable with that analogy, but it's what I just blurbed out my
8:58 mouth. So I'm gonna stick with it for now. Okay. It actually that actually makes sense to me, which is either really good or really scary depending. Excellent. So we've got a concept of a pod and we can think of it as a container for now, but it's it's important to understand that it can be one or more containers and it's not it's not directly mappable. Now Kubernetes is all YAML driven. You can use JSON, but you know, that would be a bit cruel. YAML is slightly a bit easier to work with because we have the option of doing
9:32 comments as well. So when we describe the YAML for any resource in Kubernetes, so you know this format works for every different type of resource that we're gonna work with today. Then generally what we have is an API version and a kind. The API version and kind perform or they're like a key that says this is the object type that we're working with. So you know, imagine there was a b two pod and a b one pod, although that's not the These two are directly linked and will very rarely change. We then have the option to pass and
10:03 submit a data. So you know, this is just pretty much as it looks. We have the ability to say the name of this pod is going to be NGINX and we can apply some labels to it, which allow us to query those pods using our own selectors from the command line. Okay. So while that is important, the start of that, it doesn't actually affect what we run when we apply this to the cluster. To do that, we have something called a spec or a specification and we have the the most important key in a pod is to list the containers
10:32 that this pod is going to have. Okay. And we're only gonna have one for the time being, but this pod spec here, or this container spec is very similar to what you would do on the command line with a docker container run or docker run command. Right. So we can give it a name, we tell it the image that we wish to run, and I'm just going to give this a hint that it exposes a port for us. We're saying NGINX has a port 80 that will be available where I can send requests to this container.
11:00 And that's it. So that means that I can do a cube control apply. We use the dash f, so flag to say that we want to apply a file and I can pass in our pod dot yaml. Okay. And that creates a pod. Now because I know my muscle memory is gonna kick in soon, I'll clarify that I am very likely just to start typing key as just an alias or cube control. Oh, well now I've just broken that alias for cube control. What I meant was that k is alias to cube control. So I can really run get pods
11:42 and what we see here is that we have a pod called NGINX, which is what we called it. We can see this ready but here it says one of one. That means one container was in the spec and we have one running and the status is here. It has not been restarted and it was created twenty four seconds ago. So when you applied that pod dot yaml, it not all it it basically it it started that pod and started it running. Yes. That is correct. So we can go into the details of how this kind of declarative approach works from the
12:19 API point of view or the or the, you know, We we can talk about how the controllers within Kubernetes work if you want or we can keep focusing on the workload a bit. So that's entirely up to you. Let let's do the workload a bit because that's that's Alright. So we'll just go in the assumption for now and maybe we'll we'll change that later. But when you apply something to the cluster, something creates that and it works. That's I'm happy with that assumption for Okay. So we have a few a few introspection commands that become really important
12:47 when working with our Kubernetes clusters. So you know, we've seen that we ran get pods which gets me a list of pods. I can also add a name to that to fetch a single pod which does nothing differently right now. Right. But one really important thing when you're working with Kubernetes is that sometimes you'll actually want to get a bit more information. So you can use the dash o flag, which just means get me this pod information in YAML and we can actually see a lot more information about what is going on underneath the hood here.
13:18 One other option we have is wide, which just gives us again a bit more information. So the dash o yaml one is slightly more important because it's a really good hacky way of then writing pod2.yaml and then being able to generate fake resources. But we won't cover that just now because I'll end up rambling. So that's a pod. One or more containers, we create the YAML, we apply it. One thing is really important about pods is that they are the lowest common denominator or the primitive or the atomic unit of what we make run inside Kubernetes.
13:59 However, what is really important is that this is an immutable pods back. Pods cannot be changed. So if I were to kind of prove that, let's say I want to do NGINX two or if that's Yeah. Let's do that NGINX two and then I try to reapply. You can see here that the pod NGINX is invalid spec forbidden, pod updates may not change fields other than container image or active deadline seconds or tolerations. So you cannot modify anything particularly useful about a pod directly. Once it's running? Oh, yes. Once it's been applied. Yeah. Even if it failed, you still wouldn't be able
14:48 to modify it. So our only option now would be to delete it. However, I think that I guess there's one more important command here. We applied it. We created it. We done a get pods. We can also run a cube control logs on our pods to pull out that log information if we need to do any sort of debugging to work out why something is crashing. Okay. Alright. Let's delete that. Delete it correctly. Alright. When you ask you like a delete command, it will wait until that resource has been cleaned up, so you may find that it just hangs there
15:31 for a little bit and it's quite normal, nothing to worry about. It goes away. We can then run get pods and we're back to where we started. Any questions on that little bit of surface data that we touched so far? No. But it managed to make this the fan spin up on my laptop, so I'm wondering how you did that because, you know, rocker. Yeah. Yep. Don't worry. Mine's just taken off too. So Okay. So we don't work with pods. I think that's that's really important as import wordfuffle there. As important as understanding pods are
16:00 Deployments
16:11 and as port as important as they are, we never work with them directly. We have other abstractions within the Kubernetes API that allows us to work with them in a slightly more manageable fashion. Okay. So what I'm gonna do is just create a new file and call this deployment dot yellow. So when you first in fact, when you first or even a thousand days into deploying to Kubernetes, the deployment object as the de facto right now for if you wanna take your application and run it on Kubernetes, you use the deployment spec. It is a
16:50 super set of a pod that comes with a controller that does loads of magic stuff. Magic stuffs includes modifying or at least rotating the pods when the spec changes, scaling up, scaling down, handling update strategies, all of that magical mystery stuff that we're gonna try and cover. I am using a Versus code plugin for Kubernetes. That means I do not need to take a lot of YAML for the common resources. So that's why you can see it being templated out like this. Yep. And I'm gonna use engine x as a a base for most of the stuff we
17:26 deploy today, because I think we're all familiar with it, we know what it is and there's no magic there. I am gonna continue to remove this resources block. In fact, I'll do it one more time to show why it's kinda there. You can see all the squiggles I get. That is my editor telling me that you should not apply a Kubernetes resource without resource management because it could eat up all your resources. So I can kinda silence that to one line while pushing an empty block. And you'll see, there's a couple of things different from this,
18:04 but still very very similar to what we kind of played with with the pod. So you can see that our object key, the combination of API version and kind has changed. Mhmm. The fact that this has changed from v one to apps just means that we've dropped out of the core namespace, which is where the pod lives, and we're now into an application specific namespace, which is handled by a different seg, the working groups and segs of Kubernetes project all handled different API touch points. The object that we're now deploying with is called a deployment
18:33 and it still has some metadata that we can apply to it. We still wanna be able to name the object that we put in the cluster. Okay. Now this bit here, but this pod and container spec has not changed. It's just slightly deeper and Right. The YAML structure. And what we have here is the actual deployment spec and the bottom bit is the pod spec within the deployment spec. So when we create a deployment, we're saying we want to deploy this pod, but we have some we have some information that surrounds or encapsulated that that is really important.
19:14 And the most important thing with the deployment is something called labels and selectors. Now, I think it may be best to apply this first and then double back on the selectors when we have something running that we can maybe take a look at. Okay. Okay. So we applied that just like we did the pod only this time, you know, it's got a different prefix before it. It doesn't say pod and we can run get deployments and we see something better similar to what we had with our pod spec. Yep. So we have the name. We still got one
19:55 of one containers. Now we don't have something called the status. We got up to date and available. We'll talk about why this spec is a little bit different. But what's important is if we run get pods, you'll find that it does still create a pod of bars. It's just called it's it's just now a managed pod. Right. So it's got that it's got the ugly string on the end of it because it's managed by somebody else, something else. Right? Yes. So this is a three piece tuple, and each segment in this tuple identifies a different layer of abstraction.
20:37 So let me try and explain how the deployment actually works. When you create a deployment, it gets created on the cluster and nothing happens. There is a deployment controller that notices that object and then it creates something called a replica set. Get replica sets. And you can see the the now got a two piece tuple. Yep. So so this is the deployment name and then this is the identifier for the replica set. And then there's a controller that monitors the replica sets and goes, oh, we need pods and then this is the pod ID. So we got this layer of command. Right.
21:16 Deployment creates deployment creates replica sets, replica sets create pods and we create a deployment. Now it's very confusing, it can be a little bit difficult to understand and that's just to do with the way that Kubernetes works, so that's controller model and people, know the controls are only responsible for one really small part of the API. So disregard that unless you really wanna know about it, we can talk about it later. What we really care about is we created a deployment and we get a pod out the other side. If we just pretend our view here is get deployments
21:52 and pods, you can just do a get with a comma and it'll pull out multiple types. Okay. So you can see we've got our deployment, we have our pod. Yep. Okay. Next. Labels and selectors. So because I've already that it's good now that I covered that that hierarchy of abstraction. The deployment controller needs a way to know which replica sets it created. The replica set controller needs a way to know which pods it created, so that if I delete the replica set, it deletes the pod and if I delete the deployment, it deletes the replica sets.
22:29 These labels are used to do that matching. At least they form a a base of the matching. So if I do a describe on deployment NGINX. Let's see. You can see that this has a selector that says all of the replica sets and it doesn't say here replica set, but because we've kinda covered that hierarchy we know. Any replica set that says app equals NGINX is gonna be controlled somehow by this resource. I can then do a describe on the replica set. Excuse me. And we should see our label as app equals engine x. Yep. And of course, if
23:17 I do a describe all the way down the tree, we're gonna see labels app equals engine x. Labels are a way to identify how the different layers of abstractions are actually owned or controlled or operated etcetera. Does that make sense? Yes, it does. Awesome. Good. Now because this is employment, we can modify anything we want. So let's keep the name the same. Let's not confuse the the per Kubernetes and let's do app engine x tutorial. Now these do need to match up, otherwise we're gonna have a mesh match in the selector. So if I say this and I try
24:00 and apply this, it should hopefully complain. Yeah. So these do always have to match otherwise you'll have resources that were created that were not operated by their controller. Right. And we can modify the containers. So say that I don't want to run NGINX. What about if I wanna run httpd? So I'm gonna change that image and I will change the name of the container. And while I'm here, just for good measure, there are many other fields on the deployment spec that we can change. The most important one is the replicas. What if I wanna scale this deployment? I
24:35 can set the replicas to five. And if I apply this, I broke it. You changed the name. So, yeah, these bets are immutable because I'd already created the deployment. So I'll cheat and just modify the name to create a new resource. And I will delete the old deployment like so. And we'll pretend that all worked. So deployments, we now have this new one and you can see that we're we're starting to scale up. So we have two available at five, five available out of five. So pretty quick. It doesn't take a lot of effort to scale the service.
25:18 You can imagine if this was a production thing and I want you to be able to scale on demand or in reaction to metrics or whatever. It's as simple as modifying my YAML and saying, I need more of these, please. So you can modify the scale of it in, you know, at runtime, basically. Right? You can add more or remove or remove them, and it will scale appropriately? That is correct. So let's assume we come in here and we're like, alright. We've weathered the storm, whatever magic event happened on Twitter. We now can, you know, maybe
25:53 comfortably go back down to just having two replicas. We just reapply our deployment.yaml. I'm gonna run a get pods with dash w which just means watch and I was too slow. I mean, it's already scaled that resource down for me. So yeah. So yeah. We can modify the spec and that's just comes down to the way that Kubernetes works. Whenever you apply NF into the cluster, those controllers set in the background and monitor the spec. Whenever that spec changes, it goes out of its way to do a reconciliation loop and get the cluster into the state
26:25 that we declaratively define. Which explains why you can't really change the name in the on a on a running cluster because then it would not understand what it's supposed to change, and it would cause all sorts of mayhem. That's a good a good point. I had actually thought up of that change on the selector on an existing deployment. It would actually put you in a moment of flux where it didn't know which resources to clean up or create. So if that makes sense. There are some letter immutable fields across it, you'll have them at one point or another and if you're
27:00 Multi-container Pods
27:01 anything like me, you'll forget. But we can use test deployment spec now as a basis for most workloads that we wanna deploy to our cluster. Okay. Any any questions on that or are we happy? No. We're happy. And we can add other services to that that pod by just adding more containers to the pod. Is that the idea? Or now I'm really gonna confuse it. No. So there are use cases. So this is a really common pattern in Kubernetes called sidecar. Sidecar is generally a name that we use for any pod that has multiple containers.
27:42 Something that you may wish to do and a better software that we're both familiar with would be deploying Telegraph. Mhmm. So assuming we wanted to do have a sidecar container, a Telegraph container running next to our application and scraping metrics and our Prometheus based pool sale operation, then we could add a container like so, and then I can just reapply this. And what we're gonna see here is our new one here has ready zero of two. Now that just means that it's currently pulling the telegraph image. Yep. I can run a a watch on this with dash w and
28:17 it will work this time. And we'll see that change as the image pulls. It's now spinning up the pods, so it's now killing the old pods. So you know, it spun up the new one the first, waited until it was almost running, started tearing down the old one and then the other one gets terminated. What we can do now is run get pods and you see that we have two pods, each with two pods both running and happy. So that is this is a pattern that is used to enrich or augment the functionality of a container or application with some
28:50 Services and Load Balancing
28:51 other piece of functionality. However, you would not use this pattern to deploy every service in your application as a single deployment. What you would do is have multiple deployments. So let's let's add something then to this. Let's add a new file, and we call this our deployment two, very unique and original name. Yep. There what image should we deploy? We can just deploy NGINX again. But we'll give it a name that's not NGINX. We'll just pretend. Because that image is already in my cluster. I don't need to pull anything new, which is Right. Really a
29:39 good thing. So let's pretend this is some stateful database application, Oracle DB because you know, why not? We'll call our selectors. We'll just make this match as well, so we don't have any conflicts. But we're still just gonna deploy NGINX and then we're gonna continue to pretend it's Oracle. And I'm not going to expose any ports. Alright. We will, cause we're gonna show off some of the networking functionality that we get with Kubernetes. Okay. So this is our second deployment. It's Oracle DB and we can apply it in the same fashion. We run get deployments
30:26 and pods. And you can see that we now have two deployments. We have our engine x tutorial. We have Oracle DB. Right. And we have our collection of pods. Yep. Okay. Now we want this stuff to talk to each other. We do. And I always have a hard time with this with Docker containers because it's like, well, that's running in a Docker container. You can't talk to it. I wanna talk to it. Alright. Let's see if we can make that happen then. So primitives were covered thus far are pods and deployments. There is another really important one called a
31:05 service. And that service provides DNS based discovery of the other services within our Kubernetes cluster. So it's called a service.yaml. And we have auto complete, which makes my life a lot easier. So we'll expose our engine x one and we'll make it available on port 80. We don't need to specify a target port as long as I'm not getting this wrong in my brain. The target port will default to the port. So Okay. What this channel says is I want a service to exist called NGINX. That name will be created as a DNS resolution within
31:51 the cluster, so I can then query NGINX as if it were a URL. The selector is the same as what we had in our deployment. So selector says all of the pods that have this label app engine x, we will allow to answer requests for the engine x service. Okay. So this could also based on our current examples be Oracle DB. Okay. And we have to tell it which port, so we can publish services on any port that we want, port 80, port four forty three, port 53, whatever. Because this is a web service, I'm gonna
32:27 export it on port 80 and we can apply Like so. Now what command do you think we run to list the services? Probably get services. Yeah. It's not a trick question. That's what I guess is is nice. The entire Kubernetes API surface is mostly just the restful API and then the commands that we use to query that become very intuitive very quickly. Well, what we can see here is that we have an NGINX service of type cluster IP. Cluster IP just means that it's gonna generate an IP within the service IP range for the cluster.
33:09 You can see here we got a 10Dot105Dot193Dot142. Right. Right. Not exported externally and the port that we defined is also there. So if we want to see this working, we can go inside of a port. So very much like docker exec, we have the ability to ability to do cube control exec and I'll jump inside this Oracle DB container and I have a bash shell here. Right. Do I have curl? I do have curl. Excellent. That makes my life a little bit easier. So I can do curl http engine x. No, I can't. Alright. We may have our first
33:53 problem. Ah, the labels were wrong. Okay. So now we're into debugging a service. Okay. Because when I created this deployment, I updated these selectors with the new ones. So my selector on the service, if I split screen here. Yep. Is NGINX and not NGINX tutorial. Exactly. Now the way you debug this in Kubernetes is to describe our service. Now what's important here is our endpoints are none. That's this is the first indicator that the service you've created, you've made a mess of it. Because it's not there's yeah. There's no endpoint to the service. Exactly. So I'm never gonna be able to create
34:35 it. So we can fix that with tutorial. We reapply our service and before I even query it, I'm just going to scrape this thing again and right away we've got two endpoints that are happy to answer that question of can I speak to engine x? Yep. Alright. So let's try that exec again. Is my curl there? Yep. And you can see if I curl engine x the service name, I get a response from our engine x deployment pods. Great. And that works ubiquitously across your Kubernetes cluster. So why don't we tackle the very explicit DNS name that happens here.
35:19 Now it's not the NGINX as a valid domain name. What is actually happening here is that it's being completed by the DNS within the cluster to s v c.cluster.local. Like so. And this is a predetermined format that works in almost every Kubernetes cluster. So this is the service name NGINX, then we get dot followed by the namespace, which I know we've not covered yet, followed by the resource type. So SVC is just short for service and then this cluster dot local is the cluster domain name. Now most cluster ship with cluster dot local. I think it's rare that
36:02 I see this changed. However, I guess it is important to know that it's not gonna be there a % of the time. Whoever spends up the Kubernetes cluster can pick anything they want. You can have david dot lol cat or something. So because of the way the DNS resolution works, I can query that at each level. This is something in DNS resolution called end dots it's configured within the cluster. So you got a lot of flexibility with service discovery. Now something that something else that is really cool about this because it's not cool enough that you get
36:38 DNS based resolution. You also get rounds robbing load balancing. So so it's also doing the load balancer as well as the because I saw that it when you did the describe the service, it had two endpoints. So it will basically load balance between those two endpoints. That is correct. Now let's visualize that. Let's modify our image here. No. So this is an image that exists on the public Docker registry. Is from the functions as a service project open fast and the node info name just means that this container will respond with whatever the host name is
37:22 called. Now because of Kubernetes networking, the host name is the pod name. You can see here on the Oracle one that this is the the name of my pod. So if I reapply our deployment one, we should see those all will be rotating. Yep. So the first one's on its way. Let's just watch. It's pulling in that functions node info. Now it's replacing the other two. We just got one more to go. Alright. We're good. So these are now these two parts here are running the node info. Don't break. Okay. The node info image. So I'm gonna jump back into Oracle and
38:12 just run this again. So we're gonna see different output. This is no longer going to be the output from NGINX or Apache web server. That was unexpected. Ah, the port has changed. I never thought of that. Okay. So this port is actually eighty eighty in that container. Okay. So now we need to target port. So I'm still going to expose it on port 80. I don't wanna change my curl command. Right. I want it I want it to work like that. So now the target port and the port are actually different. So we just specify it like so.
38:49 So now I need to reapply our deployment.yaml and our service. And we can do that in one line or with two dash f flags. Okay. We shouldn't actually need to wait. That should all restart pretty quickly. Quicker than that. Come on. I guess the shutdown is actually what's making it take a little bit longer than I thought it would. I'll be patient. I'm very patient. Okay. So we got two new ones running and the old one's shutting down, that's okay, but we have these two which are twenty seconds old. So we go back into Oracle DB and
39:31 we can hopefully curl NGINX. Perfect. Yep. And it gives you the host name. Yeah. So now we have the host name, the platform, the architecture, how many CPUs are available and the uptime. And if I hit this more than once, there we go. You see the host name changed on the third try. Now we've only got two two pods. So it did take a couple of tries, but you can see we are getting load balancing across those service endpoints. So another really cool kind of quality of life thing that you get for free that used to be really difficult or,
40:04 you know, configure an h a proxy to do, you know, the load balancing part. It can be a little bit cumbersome. This is nice. Right? Yeah. So my question about all of this is, you know, how much overhead am I adding with all of this? I know that, you know, Docker, at least on Docker Mac, is is just a resource pig. So am I am I adding a ton of overhead to whatever I'm doing, you know, just to get this this little bit of niceness? Yeah. I mean, there's no there there is a cost. It's not free
40:43 of course. There are many, not many. There are a few components that need to be running on the the bare metal for this to work. The Docker for Mac is a slightly unique situation and that because Mac doesn't understand container primitives directly, Docker for Mac does run a virtual machine that virtual machine running is gonna be a battery sync. So let's just talk about maybe the bare metal experience rather than the Docker for Mac one because I think that's that's just something we have to live with if we if we run Macs. So on a bare metal environment, the overhead for
41:15 running containers with Kubernetes will be there is a cubelet process on the machine, which is responsible for start and stopping and handling the containers. There is a cube proxy or a CNI implementation. So there is some sort of networking on the machine that actually knows how to do all the IP table manipulation. So there's a cost there. There is also across the cluster, but not across every node, there is API servers, schedulers, and etcd. Oh, and DNS. So those those four control plane components which have to be scheduled somewhere, if not on all the working nodes. Well,
41:59 probably not on all the working nodes, but they have to be scheduled somewhere and highly available. So there is a cost. It's actually not too bad considering the things you get for free. Because if you were gonna do this manually, I mean besides all the automation you would have to write to dynamically reconfigure HAProxy as services come and go. This is probably a little bit cheaper, but with the painful point of, well, shit. You need to learn all this stuff now. So, you know, choose your battle. Yeah. Yep. Okay. So we covered pods. We covered deployments.
42:33 We have covered discovery and load balancing across pods with services. Now we've only looked at one service type, which was the cluster IP. That is the default, that is why there's nothing in my YAML that says this is cluster IP, but you can pretend that we had this line here, so that is just the default. There are other service types. I don't think they're gonna be particularly important for today. They are typically used to expose services from the cluster outside of the cluster. Okay. How about configuration? So what do we have running right now? Okay. Let's do this. Let's change our functions
43:15 ConfigMaps & Secrets
43:28 as a service back to engine x. Oh, that's a good point. We could do that too. Okay. Sorry. Too many ideas. I'll leave telegraph in. We change this port back, and we'll leave all that of it. So really all I wanna do right now is get our get our engine x back to normal. We'll give that a few seconds. So Okay. What we're gonna do now is we wanna inject some arbitrary information into this NGINX pod so that we can change the behavior. Right now responding with the NGINX and hello world style page or basic default page isn't
44:26 terribly useful. So we wanna see how we can pass in some sort of configuration to change that behavior. We may even just do that to configure Telegraph to probe engine x or something like that. But we we wanna show how we can configure the the processes running within our pods. Okay. Now to do that, we need a new resource type. So let's call this config map dot yaml. Config maps. And we'll call this NGINX. Now config maps are YAML definitions of key value pairs that live inside of our cluster. So I could have username Rawkode.
45:17 I could have index.HTML and use YAML's multilane thingamajiggy to say hello. I am Rawkode. And if I want, I could do some sort of list. So I could do numbers One, two, three. Why is this yelling at me? It is a string. Why am I failing at YAML? Because it's YAML. This I every time I think there's nothing wrong with my YAML, I'm always proven wrong. So the YAML linter is my friend. My YAML is fine. Mhmm. Okay. I'm just gonna assume it's wrong and Versus Code is just a little bit confused. So let's apply our config map.
46:41 And the type got an array is bit oh, okay. Yeah. It's right. I'm wrong. Config map key value pairs cannot have sub types. So let's just do numbers like this. Just me being silly. Okay. So we can apply that. And now we have something called a configuration map available inside of our cluster. We can do get config maps. We see engine x. We can query engine x. We can use the output toggle that we were using earlier, and we can see our data is now stored here inside of our config map. Okay. That is now in a position
47:20 where we can consume this within our pods and deployments and inject the inside of the containers. And there are two ways we can do this. So let's open this. What should we do first? Let's do exposing these as environment variables. So we can do env from, contact map reference, give it the name of engine x. So these three lanes here tell our deployment that there is a config map called engine x that we want to expose as environment variables within the container. Okay. I can reapply my deployment. And what we will do is just to
48:18 connect and to one of those pods. That was just restarted. Let's try again. Oh, there's two pods. Yeah. So sorry. There's two containers. You need to specify the container name when there are two. So dash c nginx and then run bash. I was getting confused about which one I wanted to run-in. And that pod is away because that's the one that should just wait until all the pods have restarted before I get inside of them, shouldn't I? Alright. So this ID has changed, so let's do this. Okay. So now we've got a proper pod name. We tell it which container and
49:07 we want to run bash. Finally. There you go. We can run the e n v command and we'll see here HTML equals hello, I am Rawkode. We have numbers equals numbers and username equals Rawkode. So now I have a way to dynamically configure my application as long as it understands environment variables. So for things like if you were, for instance, running a a database that had a that you had to pass in a a key for inserts, you could run and they can get that from an environment variable. You pass it in there, and then all of the the various
49:54 pods pick up that value. Right? That is correct. Yes. Now we have another option. If we don't want if our application cannot be configured through environment variables, we have the ability to use a volume. So in our deployment spec here, we can see volumes. We'll call this config. The volume can come from somewhere. So we can see here that it is a config map with the name NGINX. So this says define a volume called config with the contents of the config map NGINX. Okay. Now that doesn't do anything on its own. We then have to mount
50:43 the volume into the container that we want to have it. So here, we can do volume mounts, mount path, I'll call it config, and the volume that we wish to mount is config. Yeah. Okay. So now we can come back over here. I love that when you just do one of these introduction to Kubernetes things, it's just, hey, look at all of this YAML. Yeah. I'm really sorry. No. And I don't know whether it's really scary or or but it's actually starting to make sense. So that should probably scare people that are watching this because it's actually starting to make sense
51:20 to me. Well, that's good. I'm glad that I'm not just bombarding you with YAML. Okay. So we're gonna go back inside one of our new pods, not one of our old pods. And just so I don't have the old one, I will copy and paste. We specify the container and we specify the command. So we still have our environment variables here. Yep. However, we should now have this conflict directory. Yep. Where I can cat each of those values like so. I know that's a little bit difficult to see because it kinda happened in lane. But, you know Yeah. There's a Rawkode at
52:01 the start of that and the numbers here. Yep. And our multilane string. There. So those are the that's how we configure our pods with non secret information. There is something very similar to a config map called a secret, which is kind of secret, but not completely secret. Okay. So let's let's just So we're calling it secret, but it's not really secret. Yes. Unfortunately. So what I'm gonna do is YAML allows us to do three dashes to split one document into multiple types. I'm just gonna use that here. I'm gonna copy the config map, paste it, and I'm just gonna change this
52:52 to be secret. I'm going to change this to be string data. I think that's enough. We'll see. So let's reapply our conflict map and we should expect to see a secret created like so. So why does my screen share keep tearing like that? There we go. I am running Mac Big Sur. So, you know You're inside your container there, so that's probably not gonna work. Good catch. Thank you. Alright. So cool. So we reapplied that. Now you can see our contact map is unchanged. We didn't modify it. However, we did create a secret there. Yep.
53:43 We can run get secrets. You can see our engine x one is here. I'm gonna pull out that one secret pass and the negotiation. So I'd say, hey, commit back in YAML. And we have our secrets. Uh-huh. Those do those strings look secret? Not particularly. No. This is our wonderful favorite encoding, base 64. So secrets are not terribly secret. There are things and stuff one can do as a Kubernetes operator to improve the situation. But by default, our secrets are available to anyone with permission to query them. They're just sophisticated through basics before. And that is why we also specified string
54:39 data in this file. It's better than Rawk 13, I guess. But But whenever you see that equals sign, you immediately know that I'm just gonna base decode that and I've got access to whatever. But yeah. That's string data. If I had not changed that to string data, if I had stuck with data, this would have failed because it's not base 64 encoded. It would have said, hey, those values don't look encoded to the way I want. So we can pass them in a string data. Of course, when it comes to secret management, there's a whole world of tooling and other
55:11 options for Kubernetes, but this is what is baked down and built in for free. The good news is like you still do you still need authentication to the Kubernetes API. You still need a cube config that lets you do the query. Things are encrypted on the the node machines at rest, so and in transit. So there there's that plus. But have you ever get access to the cluster with this fashion, then your secrets are compromised immediately. So Well, you know, physical access is is game over for most things, so in security land. So That is true.
55:48 Alright. So any questions before we start tackling a few other bits and pieces? No. This is great. I'm actually I'm I'm actually learning stuff and and this is making sense. So Alright. When we spoke about the service DNS lookup earlier, we mentioned something called a namespace. So we'll just really really quickly cover what that is. I don't wanna spend too much more time on it. So I don't wanna spend any time on namespaces because they're super uninteresting. But Okay. They're important to know. So namespace YAML. We have a yeah. We have kind. And this is the only one I can
56:00 Namespaces
56:33 ever remember how to type. So yeah. Tada. I bet you that doesn't apply now but Oh, metadata, silly me. I was right, didn't apply. So namespaces are in the core v one group, which is why it's just v one, the kindness namespace, the namespace is called my namespace. Much like every other object, I can tell get namespaces and we have our new namespace. Now Yep. Everything that we have created thus far has been created in the default namespace. I can run get pods when I see stuff and things. Yep. And if I do get pods dash
57:24 in my namespace, no stuff in things. Oh. But namespaces are a way to logically group things depending on your own workloads and configuration setup, team dynamics, Conway's law, whatever you wish to apply to that logical grouping is entirely up to you. But namespace is a way to encapsulate encapsulate that altogether. What is funny though is you can I can't delete the name? Yeah. You can delete the namespace and it will blow away all of the resources. There's nothing in my namespace but it would have destroyed everything. I didn't realize default was Does it so what when you say it
58:08 destroys everything, that destroys the pods and everything in it or just the namespace around it? No. It should destroy all of the pods. So if we do let's just reapply this then. So let's copy this deployment. I mean, if I remember correctly, it just it doesn't really care. So we can specify the namespace and our metadata and I can say deploy to my namespace like so. We'll reapply our my namespace namespace with the deployment. We run get pods by namespace. I'll at least let them be healthy before I try and kill them. So I actually think I've
58:58 run out of resources. So let's debug that. The reason these I think these are stuck in container creating is if I describe the pod, I think it's gonna tell me that it can't allocate resources. Namespace. Oh, no. It's the contact map. Okay. Oh, you're trying to mount the the the config map from two different places? That is correct. So I'm just gonna copy in everything just so that this applies. Update the metadata. I don't even think we did anything with the secret, but I'll create it anyway. We'll apply that once more. We'll run get pods
59:52 and yeah. So there's this also weird thing where that pod is now stuck waiting for something that didn't exist. So you you kinda have to give it a wee shiggle. Give it a what? I need to hear that again. A wee shiggle. Oh, okay. That's dandy. Just give it a wee a wee shiggle and then it'll restart or so. You just delete it, it comes back. Is this still gonna fail? Did I update all the right stuff? I think it did. Oh, there we go. Just me being impatient again. So that that's now running. And we look inside our my namespace again
1:00:33 and we call get secrets, we'll see our secrets, we'll see our config map. Like that's all what we expect and we'll just delete my namespace and it's away. It's now currently deleting that secret, that config map, that deployment, that replicas there and those two pods. So, you know, careful with deleting namespaces. I was gonna say, so deleting namespaces can be extremely destructive. It can be. There's a concept in Kubernetes called a a validating webhook. What you'll find is most production clusters won't allow you to issue a delete against the namespace anyway because of the validating webhook. They'll be like,
1:01:15 hey, are you really sure you wanna be doing this? So alright. So we've covered pods, deployments, contact maps, services, and namespaces. What else is fun? Who was it the other day that posted that they took out the entire web service for some application for the entire country of Norway because YAML misinterpreted the word no in their YAML file. Hi. That's one of my biggest gripes with YAML is its ability to take billion logic from anywhere it wants. No. It's just true. False zero one is infuriating. Yeah. But I hadn't read that story. You'll need to share that with me.
1:02:03 Now I'm sure I'm forgetting stuff. We'll call it pressure. However, I do have a workshop that I've given before and I'm gonna see what I would cover in that. So we did pods. We didn't do port forwarding, so we can take a look at that. We did deployments. We did a little bit of port forwarding when you when you pushed one port to you exposed one port as a 80 max to eighty eighty. Yeah. That that is true. You're right. So oh, the big nasty world of R back. Don't know if I wanna touch that on
1:02:30 Port Forwarding
1:02:48 the stream. Alright. So let's see. Let's come back to our configuration here. So we have this deployment dot YAML. Let's spin this back up again. Yeah. Let's do that and then we'll do something with that telegraph container, so we can see the the cool perks from having multiple container pods and why they're useful. So but we still have that running, don't we? Cool. Yes. That's still running. So there's a command we can use on the on the command line configuring, called port forward, where we can specify the name of a pod followed by a host container port triples.
1:03:34 So on the left hand side of this colon, we say this is the host port we want to expose this pod on and we want to forward traffic to the Container Port 80. Okay. And that's really good for one to actually hack your application from your own machine. So I can just fire open a browser now. Yep. Go to local host on Port 8080, and it pushes me through to the container Port 80 where NGINX is greeting me with his welcome hello world estail page. Yep. Alright. So let's try and do something with this telegraph now.
1:04:14 Now the one of the coolest things about containers within a pod is that they share the same TCP stack. What does that mean? Right. Let's go inside NGINX. Only I'm not gonna end NGINX. I'm gonna go into telegraph container and I'm gonna run bash. I don't think I'll have p s. Oh, I do. Okay. So we can see here we have pad one which is telegraph, doing this telegraphy thing. And then my two processes here. Yep. There is no engine x running in this container. However, if I do a curl on local host, we do get NGINX back.
1:05:04 So this is to do with the containers within the pods sharing the same TCP stack. Meaning that they both respond on local host provided that don't try to open the same port, otherwise things will start to break. So the reason I like this sidecar pattern is the telegraph in theory could be configured to fetch metrics from NGINX on local host without because this doesn't actually go over a TCP stack. It's using the networking within the container, so there's no overhead of opening a TCP socket and blah blah blah. You know, it's it's a lot simpler than that.
1:05:43 So in theory, we could create a config map which tells Telegraph to use the NGINX plugin on local host and go and fetch the status page from NGINX and then spit out metrics to to somewhere. There's quite a lot of of benefit there. Okay. Let's cover one more primitive of Kubernetes and we'll see if there are any questions and then I think we will be done. Maybe. We do have a comment from Rick Brown, a former colleague of David and I's. He has sworn at Yamal for years. It still doesn't make sense. Yamal is the devil we're stuck with, not
1:05:50 DaemonSets
1:06:29 the one we have to enjoy, unfortunately. I don't think I've ever spoken to anyone who's been like, yay, Kubernetes. I get to write more YAML. I just YAML fatigue is real. Yes. It is. And pretty much everything these days is is now turning to YAML. Yeah. That's what I'm saying. YAML. YAML. YAML. Okay. So the the the last primitive, I think, is important for today. I mean, we have covered a large chunk. Like, see, if I were to say your average Kubernetes consumer or developer, the API touch points that they're gonna use within the cluster is 95%
1:07:12 deployments with a sprinkling or dash of conflict maps and secrets. And There's not really much more to go into there. Now there are few things on the deployment we can dig into with regards to liveness probes. We can maybe cover that. But there is one more primitive here that is useful, And that is a daemon set. So I'm gonna deploy telegraph. Now we don't need replicas and there's a reason for that. We do still need our selectors. Let's remove that. I'll get this to a stage where I think there's a a slim hope that it'll
1:08:02 work and then we can go through it. I'm not confident of course. So alright. I don't think, can't remember the API version and maybe apps v one or it may just be v one. We'll find out for trial and error and fire. We do not need a replica because a daemon set deploys one instance of the spec on every node within a cluster. Okay. That makes sense. Replicas is a few tail. When I say nodes in the clusters, we can run get nodes. That's just docker for desktop, so I only have one node. So this should run one telegraph d s,
1:08:41 which is a telegraph image with no configuration. Assuming the API version is right, which it is. Perfect. Well done. So now I can run and get pods and you see we have this. So the parent object is different. It's no longer a deployment, but it still has a similar level of abstraction to the point where eventually a pod is created. However, we can run get daemon sets and we can see here that we have one desired because we have one node and we have one available. So a daemon set is the kind of process you would run,
1:09:25 know, telegraph as a really good example because you probably wanna get hardware metrics or bare metal metrics, node based metrics from every machine in the cluster, CPU, memory, failed size, all that kind of stuff. And a daemon set would be the definitive way to do that in the Kubernetes world. So maybe I'm getting this wrong, but it seems that a daemon set is basically, like, run this run this daemon on each container in the cluster. Right? Exactly. I run this container in every node in the cluster. Right. Okay. Yeah. Yes. Okay. Cool. So I don't think there's much more to cover
1:10:11 in today's session. I think I'm happy with that. I am. Actually, this I learned a this has been great. I'm hoping it was useful for somebody that was watching as well than, you know, watching me be dumb, which is entertaining in and of itself, I'm sure. But Yeah. I mean, I I think what I'll kinda caveat this session with and that, you know, this is not you've learned everything there is to know about Kubernetes because obviously the the details and the intricate nature of some of the components goes much deeper than this. But this is, know, if you were to
1:10:48 start developing against Kubernetes tomorrow, this would be enough to get you working and not banging your head off of too many walls. Right. Just working with deployments, contact maps. I mean, that is most of the the thing you're doing. Now there are things we could get into. We could talk about helm package manager in Kubernetes for deploying third party applications, you know, not your own code to Kubernetes. Then there's a whole other world of stuff we could cover there. There's then the day one and day two stuff. There's security, performance, management, RBAC. Like, there's so much stuff. But because
1:11:20 I didn't notice overwhelm. I did notice that all that stuff was running as root, which is probably not such a great idea if you don't have to run it as root. Yeah. So all of the containers are running by root, is an ideal. There's things like security to context and the seccomp we can get into. Not only that, but, you know, every Kubernetes command I've run is as a cluster admin of this cluster. I'm not I'm not taking advantage of leveraging the role based access control within Kubernetes to restrict my access. So I cannot delete a namespace with every
1:11:53 resource in the world under it. So and although this was never meant to be a guide to everything Kubernetes. This is Yeah. E commerce guide to Kubernetes to get people and yourself comfortable enough to deploy those primitives that you use day in and day out. And I think what we've covered is a really good representation of those challenges and Yeah. Our our tasks. This is great. This has been awesome. Alright. Do you have any final questions before I let you get back to your day? Not that I can think of. This has been super fun.
1:12:31 Alright. Well, thank you very much for taking the time out of your day and joining me and letting me just throw loads and loads of Yamal at you. I know it must have been extremely uncomfortable, but I do appreciate your time. It was a pleasure. Yeah. It was a pleasure. No. I learned a lot. Thank you. Thanks for taking the time. Cheers, David. I will speak to you soon. Have a good day, everyone. Bye. Bye.
Technologies featured
Meet the Cast
Stay ahead in cloud native
Tutorials, deep dives, and curated events. No fluff.
Comments