About this video
What You'll Learn
- Run Laravel database migrations with Kubernetes init containers before app startup.
- Wire application configuration and secrets through ConfigMaps and Kubernetes Secrets.
- Deploy CronJobs, queue workers, and safer rollout strategies for Laravel workloads.
Alex Bowers joins David to take a Laravel app from a basic deploy to a production-grade Kubernetes setup, wiring up MariaDB via Helm, ConfigMaps and Secrets, init-container migrations, CronJob schedulers, queue worker Deployments, and update strategies.
Jump to a chapter
- 0:00 Holding Screen
- 0:45 Introductions
- 0:48 Introduction
- 1:32 Project Setup and Topics to Cover
- 2:40 Context: what do we need to do?
- 4:00 Reviewing Docker Files
- 6:00 Getting the app deployed to Kubernetes
- 6:21 Planning Database Migrations
- 12:05 Deploying the Database
- 15:25 Adding Database Service
- 16:49 Debugging Database Deployment
- 18:10 Introduction to Resource Limits
- 18:15 Kubernetes resource constraints
- 20:50 ImagePullPolicies: working with local images
- 20:52 Debugging Image Pull Policy
- 22:20 Initial Application Errors and Permissions
- 24:00 Adding volumes for ephemeral / cache data
- 24:40 Managing File Permissions with Volumes (emptyDir)
- 35:00 Configuring our applications with ConfigMaps
- 35:18 Configuration Management with ConfigMaps
- 41:36 Debugging Config and Logging
- 51:50 Generating Application Key
- 53:19 Application Successfully Running
- 55:00 Kubernetes secrets
- 55:01 Managing Secrets
- 1:00:40 Database migrations
- 1:01:15 Database Migrations (Init Container)
- 1:06:04 Discussing Init Container Idempotency
- 1:07:00 Jobs and CronJobs for scheduled tasks and queues
- 1:07:16 Scheduled Tasks and Queue Jobs Overview
- 1:07:50 Implementing Scheduled Tasks (CronJob)
- 1:12:08 Debugging Scheduled Tasks
- 1:14:26 Implementing Queue Workers (Deployment)
- 1:18:23 Discussing Queue Workers and Resource Allocation
- 1:22:00 Safe updates with deployment update strategies
- 1:22:38 Discussing Release and Deployment Strategies
- 1:26:36 Conclusion
Full transcript
Generated from the English captions. Timestamps jump the player to that moment.
Read the full transcript
0:48 Introduction
0:48 Hey. Hello and welcome to today's episode of Rawkode live. I am your host Rawkode. Today we're diving back into our Laravel on Kubernetes journey and I am joined by a previous guest friend and budding conference joiner beer drinker Alex Bowers. Hey mate, how are you? I'm good. Thanks. You? I'm I'm alright. Actually, I'm doing quite well. I'm excited to come back to my my Laravel stuff here and and see what we're doing. Like we've done well, sorry. I I think I've done five or six episodes on this now. You joined us for one of those and
1:25 you reached out and said, there's still a few things that we haven't covered yet. Do you wanna give us well, first, just a little introduction about yourself and then we'll talk about what we wanna try and cover today. Yeah. Sure. So I'm Alex. I am a lead developer at a ecommerce platform in The UK called ShopBlocks. We use Laravel a lot, and we're working towards moving into Kubernetes and Docker alongside some of our previous infrastructure stuff using. And that's basically why I reached out because some of the previous streams have some topics which more collaboration or
1:32 Project Setup and Topics to Cover
2:05 haven't been covered yet. So, hopefully, we can cover those today and and if not today soon. I've got a full list of full list of stuff to cover on the post and note here, so we'll see where we get to in it, but there's quite a few things in there. We'll certainly try and cross a few of them off, and I'm always more than happy to schedule more of these if we want in the future. And I really wanna make sure that we cover everything that teams like yours need to get their Laravel application running on Kubernetes
2:34 successfully. So we'll do our best. Alright. Why don't we talk a little bit about what you're prepared? So we're not using like a real production grade application today. Right? You you've put something together that is gonna be is it close to that? Is it gonna use the components that are missing last time? Give us a little flavor on that. Yeah. So what I've created is not something anybody would ever use in production. It's got two endpoints. One of them creates some jobs, and one of them is a sends an email. The email that says, hello,
2:40 Context: what do we need to do?
3:09 world. Like, it's very minimalist, but it adds things to the queue. It has some scheduled tasks to run-in the background. It does some it has some assets which can be compiled and just things like that, which every team will have. None of them will be as basic as this, but if you get the infrastructure down to run a scheduled task, it doesn't matter what the task is. If you've got stuff in the background to run queues, it doesn't matter what the queue job is. So we've just got some simple code to run that stuff. Alright. Sweet. Let me just pull up the
3:45 the repository. So it's on gethub.com username Alex bevers slash Laravel dash example dash project. I already have this cloned here. We have a live share configured so I I should see yep. There's your name there. So we're now in a position where we can try to address some of those concerns and that we're missing. Do you wanna just quickly run through that list you've and then we're trying to say what is best to kick things off with? Yeah. So one of the things that's probably best to start with, I guess, is migrations. Literally every application I can ever think of requires migrations
4:00 Reviewing Docker Files
4:23 to run. And you've touched this briefly in the past showing well, not showing, but saying how it would be done. And I think the example still had, like, a b c as, like, the art into into the the the worker. So that's that's probably the main one. There's the two big things beyond that, I guess, is queue jobs and schedule jobs. So on a normal server, you'd run supervisor, and you'd have several different workers scheduled to run-in the background to run a specific command called q work. Obviously, it isn't gonna be exactly the same as
5:01 that in Kubernetes, so the but it'll be similar, I assume. And then there's also scheduled task, which normally you'd use a contract for on your server. That's I believe it's like a scheduled tasks built into Kubernetes. So I assume that's how we manage that as well. But those are the three main things I'd say, which most applications will make use of at some point. Beyond that, there's a couple of things like managing your secrets. So you got EUV stuff, how that could be released in config map. That's less likely to be an issue because you can just inject it in the Docker
5:40 file sorry, in your Docker image. Then there's also things like asset deployment, which you covered in the past. So that's less of an issue then. Yeah. Alright. Yeah. There there there's a fair amount in there. Let's let's just see what we can get through it and then if we need to schedule more time, we will definitely do that and take it all. I think because you've gone to the effort to produce this application, what we'll try and do is I'll just try and send as many pull requests as I can to it during this episode as
6:00 Getting the app deployed to Kubernetes
6:09 we kinda work through this together and anything else. We'll just try and make this the default example for Kubernetes on file or Laravel on Kubernetes actually. Alright. So let's see database migrations first then. Let's see what you've got in place for actually running this on Kubernetes and in fact, I I I don't have any Kubernetes right now. Hold on. Let me start Docker. Okay. So we do have a Docker compose file. That is a default one that comes with Laravel. I've not touched that whatsoever. That's a development environment only, I think. Something new that came with Laravel
6:21 Planning Database Migrations
6:46 a few months ago from Laravel sale. Fun fact. I sent a pull request to the Laravel project three or four years ago with a Docker file and they said, sorry. We don't wanna support Docker. Just there you go. Just throwing that out there. I'm not better. Just saying. They now they now have, like, a first party product called Vapor, which is to deploy onto AWS Lambda. And so I assume that's pushed much more on the getting Docker working because they now make money from it. So Alright. Well, I'm just clicking the magic reset Kubernetes because I can't remember the last thing I
7:23 was doing, but that's to be fair. So that's now reset and we'll wait for that to become healthy. Let's see. So that Docker compose file, that is not anything I've touched at all. I've not done anything for development. All I've done is create two Docker files, which are inside resources ops Docker. I've got two in there. I've got an n engine x one and one f p m one. Those are the files which I've started. Okay. Well, I mean, this this won't work by default unless we use sale. I I don't actually see a Docker file
8:04 here. Am I being silly? So inside it's inside of the vendor. So when you do a page install, you will get a a vendor file vendor folder which has Laravel sale in there, and that has different times. You can specify which one, and it will compile based that. Alright. That's the half composer. I don't alright. I don't believe that you would require Laravel sale for this. That would just be for development environment only. With with Yeah. Let's Yeah. You're right. I'm I'm I'm gonna get sidetracked there. I was gonna start putting together a development environment for
8:43 this. And to be honest I think that's what you've been covered mostly. Sorry. I'd I'd yeah. I I don't think it's important. I'm just gonna create a Docker file. We just want an image with this application in it. That's that's all I need. And I'm gonna use Have you done it? It creates a Docker file, which will build an PM and the engine x image separately. Where are those? Resources ops. Ah, is this based on prior art from other episodes? Is well, that's exactly a copy of the previous streams. Alright. Okay. Good. So we don't need I separated them out into
9:20 two separate rather than having the make file specify individual targets. I've made it so that they are just two separate two separate jobs because the overlap was very minimal. Oh, that's I think that's a good or bad idea but that's yeah. It's embedded. Alright. And you've already added make target. This is already my favorite episode ever because you've done all the work. Okay. Let's build these then. So I'll just make sure I got the target names. We'll do build. Let's build FPM first and then we'll do build NGINX. Okay. So that's gonna give us our two
9:57 images which you know, for anyone that's watching, go watch the previous episodes, we'll add the links into the description afterwards. It walks you through the entire process. We're gonna assume that we're starting from the point we've already built your FPM NGINX images and pushed them to some container registry and we're gonna try and get this working on Kubernetes with all the bells and whistles that we've omitted previously. Are you going to be doing this on Kubernetes locally? I assume are you going to be doing this on production cloud environment? I'm just gonna use Docker for Mac unless
10:32 you feel there's a reason we would need to have an alternative cluster. But I don't think The only thing that I would say, purely because I don't know much about it locally is external load balances and how those sort things work, but that can be covered in a far later episode anyway. Yeah. I have I have done previous episodes on ingress and load balancing on Kubernetes that aren't they're not Laravel specific and I don't think they have to be. No. So that's a problem. IP and all that sort of thing should be fine. Yeah. That's that's that'll be alright. I mean, we
11:01 can talk a little bit about how the the services and the ingress work together, but I don't think I I don't need a cloud environment just to kinda show that off. Yeah. That that's fine. I don't think there's anything else that I could think of that is massively different from development or local environment to production environment. So Alright. Well, it looks like we do have a little bit of time to kill while this builds. Maybe I should have kicked that off previously. However, if anyone watching has any questions that they want us to address, feel free to
11:32 drop that in the comments or drop me a tweet at Rawkode. So let me try and understand the migration path here. So we're gonna be using the artisan command, which I don't think is ever important in here. We went through this previously. Yeah. Which has to run a DB migrate. Is that correct? It's PHP artisan migrate. So does that I I need a database deployed to my Kubernetes cluster then. Right? Yes. I've not touched anything to do that yet. Alright. Sweet. Finally, something I can do. Okay. That yeah. I've tested this locally with MySQL. It shouldn't make any difference because it's all
12:05 Deploying the Database
12:13 using the RM. But yeah. Alright. What database do you want? Let's get MySQL eight. Well, MariaDB 10 or whatever is here. Alright. So I'm assuming you don't really need me to go through the production deployment mechanisms for MariaDB. We're happy just to use something that's MariaDB on Kubernetes. Right? Yeah. Yeah. So personally for me, I avoid running any databases myself anyway. Just probably use managed services. Save so much effort and well, some people I guess will be running in this. Well, if anyone that is going, hey, I wanna know how to do it under production. Just use helm. Go and use
12:54 the go and use work from other people. There's a helm chart says the artifact hub. Let's talk about that actually. So artifact hub. This is from the CNCF. It hosts all of the CNCF projects artifacts. Go figure. Helm is one of those where we can just say, hey, give me MariaDB. We could filter on helm charts if we wanted. We click this and everything you need to know to get a pretty production grade deployment or MariaDB is gonna be here. You can use helm, you tweak the values based on whatever you need and you deploy it.
13:28 Probably what I would recommend. However, for today, I'm not gonna do that just because I just want something quick. What I am gonna do is check the environment bars I need. I know I need to set the MySQL root password, maybe a user database. I just wanna make sure I got the version right. So it looks like we're on 10 is okay. And if I just search for my SQL root password, these are the variables that I have available to configure this image. And I'm gonna drop these in. So we're just gonna say environment. We'll get some space.
14:06 Let's do my SQL. I'm pretty sure there's a random route. Let's not get too fancy today. Okay. Let's set a user and we'll set a value of Laravel. We'll set the password Laravel. Host no. We don't need the host database database. We'll just call it all Laravel. Was that standard? Is that what you would do in your application? Would you tweak it more than that? So I would personally name the database something relevant, but obviously, is Yeah. I think this is relevant. Perfect. So Laravel is yeah. Fine. Alright. Okay. Cool. And happily, that is also
15:09 the default that we have in the dot m b file. So Oh, is it? Yeah. The username and password are both different, but that's easy to change. Alright. Okay. Let's deploy this. Oh, no. We need to expose this. Okay. So one of the things we want to do is when we apply this deployment to Kubernetes, it's gonna create the pods that run MariaDB for us. We're gonna by default, the replicas will be one but we'll make that a bit more explicit. So we're gonna run one of these. However, what we want to do is make sure we can have service discovery around
15:25 Adding Database Service
15:46 this pod which could be pods so that we can use DNS to actually speak to it. So I'm I'm gonna add a service MariaDB. The selector has to match what we have above So you can see app MiriDB matches the same labels we apply to the deployment. We don't need the target port because this is a pretty simple setup. We're just gonna say port three three zero six. So that should be Oh yeah. Good. Those are built as well, which is handy. So let's deploy. Was it resources ops Kubernetes, MaryDB. Let's check my cluster. There we go. Too many clusters.
16:43 And we should be able to run, Get pods. Oh, we have an error. I broke it because I never set a random root password and I never set root password. Yeah. That's the one I want. It just means that I I won't actually know the root password which I think is good. So value. And what do do then? You go into the secrets to extract it or Well, we already have this user with this database configured. So we're making sure that we're That's the root password. Right. Yeah. Yeah. It's just the root password. So Yeah.
16:49 Debugging Database Deployment
17:18 We can just apply that over the top. We're gonna get pods watch. We can already see that we have one MariaDB running. The error one is now terminating and that is good. Alright. Database. Do we require anything else? What's the queue processing? First of all, sorry. What are we using for the queue? So the queue can just by default use MySQL. You can use Redis. You can use, like, webMQ and all that sort of stuff. But by default, you can just make it run using the database. So I'm just going to assume that that's the sensible way to
18:00 do it. Okay. And this deployment that we have here let's see. Replicas one. Actually, got all of them. Sorry. Can you say again, Alex? I'm not sure why it's got all those things on the line. They didn't have that online. That is complaining because I am not setting the resources required. So it's telling me that I could straight pods I think. Let's see. Resource limits. Yeah. Okay. So there we go. So we can minimize that to a single line. Yeah. My my editor is just like put you know, in production you don't want to deploy things without resource
18:15 Kubernetes resource constraints
18:48 limits. You don't want them to just start consuming all the CPU and memory across your cluster. So you would see constraint as to something that I consider to be safe. Is that per container or is that a part or is that per node or Yeah. Per container. So I mean, if we look at this as an example, right, you know, we've got engine x here which really requires nothing. So we can see that the limits on this CPU. Now complete is only gonna get me so far. Let's say 500 mem. NGINX probably isn't gonna require
19:26 too much. As I connect with it once. No memory limit. I did set memory limit. Is it memory? Is it memory? You're correct. Cool. Thanks, man. So we can set that there and then FPM is probably gonna require more. So I think what we'll do just for the for fun, let's just actually set these really low and we'll see them crash. We'll try and boost them if we need to. Let's see what happens. Yep. Okay. Let's apply this. So we're just gonna apply our deployment. I don't what have I got wrong? Hard to pick it. The error here, it
20:17 seems to be complaining. Okay. My limits can't be unmarshaled. Quantities must match the regular expression. Okay. So it doesn't want m I b. I think it just wants m. You've got m I b on two places. Of course, I do. Thanks. Okay. Now we can run get pods. Kind of expect that to fail. Now we got an image pill policy problem. You've this set to always. This is a local cluster. So we actually want this to be never because the image doesn't exist on a remote repository or remote registry. Okay. So we can just apply that over
20:52 Debugging Image Pull Policy
21:08 the top. And so what the way image pool policy works is that you know, actually seems quite healthy with those figures. So we'll leave it for now. But I do expect that to crash before the end of the episode. Well we try running anything. Yeah. Yeah. You had image pools policy to always and there are times and places where you want to use always definitely. However when you have an image like this that let's talk about how this is resolved by Kubernetes first. When you do not provide a host for the registry, this assumes that your image
21:43 is this. It assumes that you're an official image on the docker registry. This is a hangover from when docker was pretty much the the facto container runtime and that it assumed you were always gonna pull from the docker hub and that doesn't exist. So when you have an image pool policy is always in your cluster, the controllers are gonna reach out and try to get the latest hash for that image, it doesn't exist, it fails and it exits. So for local images, what you actually need to do is image pool policy never and just make sure it's available on the host.
22:18 And it's running and it's happy. However, our application probably isn't gonna work. First we haven't done those database migrations that we actually wanna be doing And secondly, it doesn't know where MariaDB is yet. Well, if you try and access it, you should I assume get error pages using in the level of a page. Yeah. I wish I would assume so for sure. So let's port forward as this port 80? No. Yeah. Yeah. Okay. Yeah. It is. Okay. So we'll make that available on port eighty eighty locally. I'm gonna browse to there. Alright. Well, our first problem is that we
22:20 Initial Application Errors and Permissions
23:00 need somewhere to store our logs and we're getting a permission denied on that. Let's take a look at what's going on. So I'm gonna jump inside of this pod. I hope we got access to bash. Oh, it's an Alpine one, not mine. Okay. So we have access to bash. I didn't look in the Dockerfile where Well, I think. Let me just check. Yeah. That's our application. No. That's missing most of it. That's this is engine actual. Right? Oh, you mean engine actual? Oh, sorry. I put in the Yeah. How is this deployed? Oh, the names are quite verbose.
23:58 Yeah. I didn't know we're gonna not call in something just like FPM as a good idea, so I wouldn't should focus on it. Okay. Here is our application. We are actually the root user, so that directory failure here, storage logs. I'm assuming storage doesn't exist. No. Storage exists by default. What the engine access running as WW data there into? Oh, sorry. The m PHPFPM. Let's see. Of course. Right. So obviously it's a good idea to not run containers as well. Well, there is a little bit of juggling that has to be done with file system
24:40 Managing File Permissions with Volumes (emptyDir)
24:46 permissions. So let's see the best way to handle this as to provide temporary or ephemeral storage for things like that where we can control the volume that we wanna make available. So let's do okay. So we can add a volume to our spec. Let's call this logs. I think it's a name logs We want a empty there. I don't think that needs any configuration, size limit, medium, yep. We can just I can't remember. When in doubt, look it up. Kubernetes empty there. Think seems to remember that empty there if there's anything that does wipe it out as
25:44 well. Is that correct? So is that Well, yeah. We're just using it for cache. Okay. It's not Yeah. Until the empty object. So for logs and cache, yeah. I'm totally okay with that plus to be honest, we're actually gonna remove your logging to not be to a fail and we're gonna move that to standard out. So that's maybe something we could do first. However, let's let's try and do it this way so we can show it working And then we'll change it up a little bit. So we now have this volume available. So empty charges means get create an empty
26:14 volume ephemeral when a container or pod dies, get rid of it. That's it. Now we wanna provide logging for our FPM. So we're gonna come in here and we're gonna see if we have oh, not volume devices, it's volume mounts. We're gonna have logs We wanna mode path of our w html storage logs and we don't need any other flags. Now this name here just has to match what we have here, which does meant it to this location. There is a way to configure the empty their permissions via the security context. Let's see if we can pull that out
27:02 our fingers. So we can set let's see if I can find this. Alright. Well, let's try that in a second. Let's see what we have first because tomorrow's I can't remember. We can set effect. Maybe it depends on the version of Kubernetes I've got. And this is probably revealing too much now that that doesn't entirely useful to the people watching but the security context has changed a lot with the recent version of Kubernetes which is one twenty which I actually think I'm running Version. Yeah. Client and one nineteen there. Okay. So we might be okay.
27:50 We'll apply first and then I'll walk through the all those things that are going through my head. So let's get pods and Alex keep me honest here if there's anything I say that is gibberish just ask me to elaborate on it because sometimes I can be bad for that. That makes sense for me so far. Sweet. Okay. Well, if anyone watching is like, I have no idea what the hell this madman is talking about. Just comment and I will explain it. I promise. Yeah. I've got I've got chat open as well. So if any comments,
28:20 ask questions I can. Sweet. So I just need this container name. I'm gonna change that next time I deploy this just to be APM so it's easy for me to use in the command line. So we have storage. Yeah. When logs are stolen by route so we still need to fix that. Now they'll be owned by ever the user of the processes. So we could change the security context of that and do run as ID w w data. Oh, no. Not gonna say that anymore. 82. Is that ID always going to be the same or
29:09 Yeah. It's built into your image. So But like, next time you do the build, would it be 82 stuff? No. That'll be set by what the APM, I that that I would not expect that to change. Right. You should be safe. I don't think you can do this. The reason why is that this security context runs on the the node essentially is configured as part of the namespaces that are set up. So you will need to use the numeric ID. Let's try and I'm gonna rename this actually. Let's do that now. So we're gonna just call that's the image Where's
29:47 the name? There we go. Let's just call this fpm so it's easier for me to get in and we'll call this one engine x. Okay. Now we can apply. Make sure it's running. And we're gonna exec IT and to this or FTM and ash. And you can see when I type ID, I am now WW data. So I run PS everything as WW data. This is a much saner configuration and I'm hoping the empty dir it's done. Okay. So we need to fix that. And if you don't have the empty dir at all, would that not just make
30:32 it work? Because Laravel will create a folder if they need it. Hey. So you're Okay. I'll get date account, yeah. Yeah. You're you're actually correct. Maybe I'm over complicating this a little bit. But also, how come how come the files are still in by root? Is that because when we built the image, it was running as roots? Yes. Because do the do those files not need to be owned by WW data as well so that FDM can process them? No. They're readable by anyone. Something else I would normally do as well is enable read only file system.
31:14 So, you know I actually don't want you to be able to write to anything which is why the empty there is important because that will be somewhere we can write to. Yeah. I just wish I could remember the file system thing that I want here. So we're gonna look it up. So Kubernetes security context and there is an FS use FS group. Is that it? There's FS group. Yeah. Why is that not all completing for me? So this might just be the version of Kubernetes I've got. It doesn't have this flag anymore. Let's just put it in and see what
31:56 happens. It's really yelling at me, isn't it? Unknown field. Okay. Yeah. That must have been removed then. So let's see. Kubernetes m two dir user permissions. There is a way. If it's group. Damn it. Surely, can remove it. They would've got like a deprecation flag to tell you what anyone's got. That seems sensible. No. So it's definitely FS group which is good because I knew that's what it was. I just don't know how to hand I mean we could use it in a container. I'd like to try and avoid that of course. In fact, am I doing that in the
32:51 wrong place? That's what it is. So this is the security in context for the pod. I bet you if I yeah. There we go. That should create. So do we want the user to be on on the spec, not on the pod or not? It depends what user we have inside the engine x. So let's let's take a look at that. Take a look at our password file, which is our source of users. Yeah. Engine x runs as one zero one and we don't have access to w w w data here. At least, I mean, don't
33:42 see it. Yeah. No. W w w data is a Yeah. Let's try this. Just curiosity more than anything there. So because you're using 82 for the FS group, but that would be applying it to the engine x one as well, would it not? Yep. There's no empty terse there. So Ah, right. So any applies if there's empty there. Well, maybe. So it will be There we go. So So you get empty there on the engine x one as well, you wouldn't be able specify the f s quick for each individual container. I'll pop that, would you?
34:24 Because they have different IDs. No. For that, I then be using an an a container that has a root user that changes the permission on the empty there which would be reused across the end of containers. We can we can cover that if we think that it's important let's just try and let's try and get this working first and then we can maybe do some cleanup. So you can see here we've got our group right access to here. And in fact, that empty door just came with explicit permissions for anybody anyway. So we actually didn't need to do that, but it's I
34:57 think it's that configuration parameter hopefully is useful for others if you're looking at a similar situation. Let's put forward. Eighty eighty. So we should be able to write the logs. And now it's complaining that we've got some configuration mission. So this is gonna be that dot ENV file that you mentioned. Right? Yes. Is. Yeah. Okay. So now we need a config map. So let's create config map dot YAML spec this out. This is our Laravel config map. Okay. So there is a secret value in here. I'm not that fussed about it being secret because I'm just gonna delete the key and
35:18 Configuration Management with ConfigMaps
35:54 play account probably. I'm never gonna use that mail thingy again. So I'm just not gonna be too fussed about exposing Yeah. You could you could just after the after this screen share, you can just click the refresh button and watch out your views. Right. Nice. Okay. So we we really just want this ENV file to be exposed as environment variables and a conflict map is ideal way to do that. Now some of this isn't actually some of this I would bake into my image. I'm not gonna get dogmatic about that now and we can talk
36:29 about that once I've got it working. But like, know, the app name isn't something I'm gonna wanna change per environment. ConfigMaps to me should only ever change variance for environmental things. Everything else should be baked into the image. The app name yeah. I'd probably put it in the docker image somewhere. Yeah. There is something built into Laravel already as well, which is you can sort of cache the what I call, config. So which is the dot m v files and other things that are used for the application. They can all get cached, and there's a
37:09 command to do that. So it doesn't actually read anything from the environment. However, that would require it to be then stored within the actual image itself, but enough. So I guess that's a decision that you can make. I'm sure there's a yeah. We'll talk about that in a moment. I'm sure I could, like reject. I'm I'm kinda looking at it going, I'll just be quicker to type it. But it's the better me going, I could just reject all this. I am gonna do it. So Yeah. So what we want to do is What you want to do is just change
37:45 the equals to a column enter. Yep. Why is that not let me oh, does my Versus code VEM not support that? Time for trustee command d on the guess, you know you know it's gonna happen or just command f. Yeah. Let's just do it this way. So change equals to a colon space. Go. And then, okay. So now we need to yeah. That needs to be a string. Billions not supported. Now we want our host. So this is gonna be the service name that we've provided, which I believe is MariaDB. We can run get services.
38:38 Yep. So we have our database available at that name on that port. That's our database. Our username is Laravel and our password is Laravel. This would be a secret. Let's get it working with Sarah and then clean it up. Don't let me forget that. Yeah. I won't. Don't worry. Broadcast driver, I don't know what that means. I don't know what that means. Just think we don't use it. So I think all those ones, we didn't care about that. The session driver actually we don't we're not using sessions in this. We're fine. We can know that. In production,
39:10 I would normally change that to Redis or database. Do we need the AWS access stuff? No. That's just because you can but with the file system plug ins, you can upload straight to us by by default, so that's all. How come it's complaining about numbers like 25, 20 five? I thought YAML supports integers and that. It does. What's it saying? I think the contact map just expects a string to be honest. Yeah. Like everything strings is We're not running memcached. We're not running reddish. No. I can also go. Alright. I think that will be enough. So let's apply that
40:11 now and then update our deployment to use it. So this is really easy. What needs to is it NGINX or is it FPM? Both? FPM would be what requires it because it's PHP for a process that's running. Yes. Okay. So ENV from ConfigMapRef. The name of the conflict map. Oh, what did they call it? Laravel? Yep. Yep. So does that just, like, basically export inside of the image before it was it? Yes. It will take all of these keys and make them environment variables, which is how Laravel works. I don't even need to change anything.
41:01 Yep. So let's reapply our deployment. So that would behave basically the exact same way as if you'd baked into the image before you deployed it at all, I guess. It would just be a Linux environment variable. Mhmm. Yep. Alright. Let's see how far we are now. The application key might not like that. I'm not sure. Oh, okay. Let's check our logs. Yeah. But that's one of the things I was gonna complain about next, right, is we'd actually don't want to log to a file in any container environment. That is generally a full path. And you
41:36 Debugging Config and Logging
41:47 wanna log the standard out. So first let's look at the logs and then change that. So our problem is it's trying to write to something and we have a read only fail system. What's it trying to write to? Oh, it caches your views. So framework views is like it's a cache thing because it comes with something called blade, which is a template language like Twig and that sort of stuff on that sort of stuff thing. So it tries to write those two problems. Yes. And I don't think there's always an opportunity as I have no idea how
42:30 to do that. But that's just this framework folder. Right? Yeah. Yeah. I assume that all of those have been trying to do it into sessions, cache. I don't know what testing is as you when you want tests and also views. Okay. So that's all empty. So what I'm gonna do is empty that too. Yep. Believe that they wanna try and keep this as a read only file system for as long as possible before I've met defeat. So we'll bring in this cache and we're gonna mount that. So would you normally have like a a temp to sort of things that could
43:09 be written to for say, if somebody was to upload a file that needed processing before getting moved on to that s three, would you have, like, a temp to configure which is Rawkode and then we got? Yes. So I would definitely use the volumes key up here to provide something that was ephemeral. Now I would use an empty dir definitely for like a local Kubernetes environment and some production environments. I may like if I need to guarantee that file exists after a pod restart, I'd probably use like a persistent volume or a host path depending on how
43:40 my cluster is configured but I would use a volume of some kind for anything that needs right access. The reason being this like, you know most attacks especially against PHP based content management systems is generally through some really contrived and illegal upload that executes an arbitrary script and then rewrites over your code And you could just say you know, that's one read only file system argument to stop solve that. As long as you don't mind going through the process of making sure you could write to your logs and your cache which I'm gonna try and do now.
44:14 Let's try. We deploy. Let's get our pods. Oh, and let's change the login to standard out. Like, we don't wanna log to a file anyway. We wanna be able to use the logs command. So how do I configure that with Laravel? Change the ENV to STDERR. Just send it out. So what am I changing? Change stack there to STDERR. Is that correct? One one d. Awesome. Okay. Yeah. Yeah. Yeah. That was it. There's also I'm sure that's your rate to standard out. Right? Yeah. That just send it straight to standard out. Okay. Let's do that.
44:57 Let's reapply and make sure I'm in the position that I kinda wanna be in. So I'll yeah. That's the config map I need to deploy. And then I'll easily delete the pod to get that new configuration. So now I should be able to run logs against this. And I have the FPM logs. Now if you hit the browser, you should see something logged, I think, because I don't think we fixed the error that we have before, did we? I hope so. Let me run the port forward from another location. We can keep our logs up.
45:43 I was gonna split my terminal, but I think that's just gonna make it more confusing. Alright. So there is our logs. But something's logging. So that's looks like that's in the next setup. No. No. That's FBM. And we got a 500. Okay. So the Laravel log configuration is obviously obviously not quite as simple as that. I'm assuming that we're still gonna have something in that storage logs. Yeah. Yep. Let's just cat it. So what failed on car and valley? Hang on. Sorry. You just put unable to create Unable to create logger. Standard out is not defined.
46:46 Just oh, so I trusted you. So It's option. I'm looking at the code now. It is there. If you open up the code in configs last I'd expect it to be dev standard out. Like that. That's good. That's what it's here for. Right? So log to standard out. And there's another option which we can just use our log, which will put it in the FPM log by default, and that should put it into the standard log for standard error log. Alright. What we have already should work, so I don't understand it. That won't work because that
47:55 where it's being passed through to monologue, the PHP logging library. I see. Okay. FPM. The pod. Yeah. We're gonna have to add a service so I don't have to keep doing that, but let's do it one more time for now. Alright. Let's go back in. FPM storage logs cat log. Did that fail to set up? Please provide a valid cache path. Unable to create configured logger. Is this because of the empty dev that you created framework? I think it expects for the cash flow to exist. You might create multiple entities. I don't think it might not create that
49:17 file folder. Okay. I'm also worried about this logger. Yeah. No. That that's definitely an issue. So I need to create a good logger, but to me I'll leave that as an exercise for another day set up logging rather than And if you change up to syslog, you just try that one last one last thing for syslog because that should put it straight through as well, would it not? No. Syslog may look for syslog in the container which one exists. Oh, okay. Alright. Let's ignore it. And let's do cash and we're gonna need sessions. And again, I don't really wanna spend too
50:09 much time fighting on things that aren't that important. So I can always just disable that if this doesn't work. Is there anything else required in the framework directory? Views. Views. I think there's one called testing as well. We measure main model. I don't know what testing is. Right. Do I have them here? Storage, framework, cache sessions, testing, Right. Okay. I mean, I I would just expect it to create them if they're not there. I find that. I I I do as well, but that's all I can choose. Okay. Modifier deployment. Oh, yeah. I've got to actually add them.
51:06 So we need testing sessions. Yes. Alright. Take 16. But we're not gonna get any logs. Okay. So let's just fix the port forward. Right. That's progress. We're not gonna white screen anymore. So let's see where we are. FPM ash storage logs cat log. So now it's complaining. Oh, yes. So it doesn't like my I just put in a random string there. What's that supposed to be? There's some r sank commands. HP r s n key colon generate. If you just run that inside of the APM container, that should key colon generate. It's trying to write it to ENV. Don't
51:50 Generating Application Key
52:25 I'll create one locally and just send it here. Can I not just print it out? Yeah. Right. Sure. Well, there we go. Okay. Okay. Cool. Nice. I hate it when tools are fighting against me rather than doing my bidding. Right. Okay. I've noticed it with three sixty four before that's interesting. Or maybe that's just a help. No. No. It's all up. That's fine. Alright. Let's just apply that whole directory for a bit of quickness. Make sure our pods rotate. Oh, I only change the config map. So I need to delete my pods myself. And now we can put forward again.
53:18 And finally, I'm really hoping we see a database migration that are here. Oh, our application worked. It really might get nice because we're not acquiring any databases at the moment. But that is proving that the asset completion works as well because that's using tailwind to get the data there. Alright. It's production now. I'll see you later. Thanks. So that's actually covered one of the things on the list anyway, though. That's the secrets and environment stuff. There is something on my list, has happened a few times whilst you've been doing that, which I assume is not the right way of
53:19 Application Successfully Running
53:57 doing it. You've just been deleting pods to get it to basically redeploy. Uh-huh. Probably a better way of doing it than that, I assume. Unfortunately, not. So the the problem is is that when you modify a config map, it gets updated in real time pretty much within your deployment. So like the files will just be synced up to there as a fail man. I think the environment variables. I think they still update in real time, I can confirm but I'm not a % confident. Your application is really expected to notice those changes and reload but most applications don't.
54:35 One of the ways to get around it is to include the shove, the conflict map as an annotation on your deployment which forces a reload every time you modify the conflict map. It's a bit hacky and there are some controllers that can also run inside the cluster that monitor for changes in the conflict map and rotate your pods for you. So there's a few ways to do it but honestly for the this kind of environment, the lean is the right way to do it. However, somebody who said that we tackled that we haven't was secrets.
55:01 Managing Secrets
55:03 I wouldn't put a secret in this file. Sure. Yeah. So let's fix that. Let's take out this app key and let's create a secret channel. I know and this is really good if it's gonna feel weird because I'm solving one problem at a very similar way to the conflict map anyway and I'll try do my best to explain why this is more, why this is better. So, So this is a secret. I am storing this as Yamo and my repository right now. So it's no more secret than a config map. Granted. However, you're very unlikely to apply your secrets
55:52 to your cluster in this way. You may be using vault or some other KMS system to provide these as to get these into your cluster but you want them to be a secret inside of your cluster because they have different RBAC rules compared to a conflict map, Right? It's generally conflict maps have loose our back. Most people can have access to them. They're also consumable from within the pods. You wanna be able to lock that down and you wanna be able to lock the pods down as well so that nobody can exec into it and just grab the secret.
56:21 So while from a very naive perspective and look at it, naive is the wrong word, from a very well from this example it doesn't seem like we're improving the security at all just by using the secrets you are as long as you get them into the environment correctly. The other thing I wanna kinda cover is that well, for a start this will fail. There's two keys on a secret. String data and data actually expects your data to be base 64 encoded. So if I do base 64, paste this in and grab this. In fact, that's not gonna work because of
57:04 the new lane. So let me just copy that properly. We should actually done like echo dash n, which means no new line. Right? Yeah. And then base 64 and this will get us add to value. So both of these are correct. So when I apply and the fact, let's just change this. So we'll call this string key instead of that key. I can't remember if the Kubernetes control plane will allow me to have data and string data but we're gonna push our luck and see what happens. So yeah, it doesn't care. Cool. Now we should actually see that both these
57:46 values are the same. So we'll grab our Laravel dash o Yamo. If I could spell secret. If we look at the data fields, yeah. You see we actually get the same value here. So string data is a helper that when you apply something to the cluster at knows that you haven't base 64 encoded it yet and it will base 64 encoded for you regardless you get the same value at other end. String data, a helper good in some environments data base 64 encoded, not a secret but again you wouldn't apply secrets typically in this fashion.
58:27 For production use cases you would use like SOPs, Fry Mozilla, sealed secrets or my personal favorite, the Kapitan project. So these all handle it slightly differently. Stops and sealed secrets will use well in fact they all they all do it the same way, they all encrypt stuff but the way that you interact with the tool is slightly different. I don't know if it's gonna be like a quick thingy here. No, because you don't have a Kubernetes specific thing. It doesn't matter. So stops allows you to encrypt it and store the encrypted file within get which means
59:05 you can apply it. You just have to remember your continuous integration pipeline to be to decrypt it before you do the the apply and there are some things that can run-in a cluster to try and make that easier and more secure, but it's a really good way of doing it. Sealed secrets does the same. It stores a private key inside of your Kubernetes cluster. You can use the sealed secrets command line to reach out, encrypt the value and you get a text based secret like this with obviously an encrypted string which is still secret and then finally there's the Kapitan project which
59:36 does secret management and hooks up to all the key messes and vault. So if you're already deploying to cloud provider web at key mess, this is honestly, this is just the best way to do it and you can define them and you have all and they'll be they'll be encrypted for you and only decryptable and a cluster that access to that KMS, so you can use cloud provider I'm rules. I'm not gonna say any more about it because secrets would be deviate and has done a path of a lot of time and I don't wanna take up too much of
1:00:01 your time and in fact we only have like twenty five minutes left. So let's see. Did that all make sense? That wasn't too much waffle. That makes sense to me. I need to do something kind of similar in Ansible where you use Ansible Bolt, but that would have you'd have the encrypted locally, so in here, and then when you're trying to play it and try and deploy it, you use you provide your vault key, which is just the password you type in at deployment time and encrypt it and send the values over. We do something kinda similar to what sounds
1:00:32 like a soft one. And no surprises. We pass our secret through in exactly the same way. There are finer grade controls, can mount on specific keys and make them optional, change the names within the container, there's a bunch of stuff you can do. Okay. Let's make sure we haven't broken anything. Let's apply that whole directory. Here's our new pod port forward. We should still see. Right. Okay. Can't believe we started off saying, let's run database migrations. We're like fair chunk of our way through this. We haven't done it yet. So let's actually run these migrations now. So Kubernetes expects us to
1:01:15 Database Migrations (Init Container)
1:01:27 leverage something called an edit container. Now if we go to our container definition here, we can just say edit containers and we can provide it a name, we'll call this database migrations and it takes pretty much is that same spec that you're using for the fact that is the same spec for your containers, you're just trying to override the behavior in a way that makes sense for you to run certain commands. So you know here I'm gonna say run FPM. The thing I wanna change is that I need access to well, I wanna run a
1:02:05 different command. I wanna run PHP and then I'm gonna provide some arcs. The arcs are gonna be artisan DB. Is that right? Just just migrate. Maybe Just migrate. So just PHP artisan migrate. Yep. And then you'll also need to do double dash false, I think, because it will by default for a warning saying you're running this in a production environment. Alright. Let's just do it. I'm feeling an entry point because it that needs to enter at the Kubernetes doesn't call it an entry point. So in Kubernetes, they use same language. So it's command and args,
1:02:49 whereas Docker, yes, they would call an entry point. So what mean is for the file path of where you're running PHP or send from. No. Because every time I've exec into that container, you have put me into the work in there which seems to be the correct location. Okay. If I manage to set up properly, that is pure coincidence. Yeah. And your Docker file. Now let me just because you haven't done it for NGINX but you have done it for for FPM. So That's here. Work there. Okay. Yeah. You you would want that in your NGINX one
1:03:21 as well. Now I forgot to set the image pool policy to never, which is why that's failing. So let's top that up. So you don't have expect to never in because you're doing this locally. If I was doing this on a production, you get rid all of the neighbors and the actual path of the image would be private.docker.com/whatever. Yeah. You would include the container registry. I like to run my own registry within my clusters that caches the images. I generally use a pool policy of, you know, if it's not available, if it's not present on the on the machine.
1:03:56 I don't do an always pool generally because I do use I I don't use ephemeral tags like latest and such that, you know, I would use a proper content You just need something. Yeah. So alright. Let's see why this is failing. I'm assuming that the migrate command is trying to write to a fail probably and that my we're gonna have to sacrifice my read only fail system, but let's see. I don't believe that it does write any files. We want the logs for the database migrations. We're getting connection refused. Okay. So Did do you create
1:04:33 I didn't give it the environment variables. Ah, okay. Yeah. That is So we need this to be copied to here. Let's reapply and see what we got. It worked. You don't seem convinced. I typically check the database to make sure my breaking work, but, you know Alright. So let's grab this. Let's do see database migrations. Yep. There we go. Oh, okay. Yeah. That worked. Is there an endpoint in your Laravel application that will allow us to consume that database at all? Yep. So I've created a few endpoints. One of them is called create dash posts,
1:05:26 and that will create just five five posts in the areas. Create slash post or dash post? Like so? Yep. I know that's a little difficult to read, but So that should've done it. I didn't give any up, by the way. It thought it'd in white. That's fine. Can I is there a get posts? That is a get post. Oh, no. No. Sorry. No. If you go to slash posts. There you go. That works. Js. But yeah. Here you go. Great. Awesome. So is working. That's Yeah. Really simple. I mean, and it containers they are the best way to handle this thing. Of
1:06:04 Discussing Init Container Idempotency
1:06:07 course there are caveats. I'm not gonna say go and add this to all applications immediately. They need to be at important. You have to be able to run them. These will like in fact, let's show that when I scale this up to five, those migrations are gonna run on every deployment every time I kill a pod. So you really need to make sure that they don't collide. There's locking, you know, you're gonna potentially have to running close to each other and they have to be item potent. So I'm assuming with the ORM that Laravel is using that you get all that free.
1:06:39 Most ORMs do provide something like that so you should be good. I'm not sure about other issues though because they are quite good on, like, the whole, like, high availability side of things. So I'd assume that that's something to do. I would assume your your migrate commander does a lock on the entire database. And in fact, we could probably trigger that by, you know, deleting the database, spending it back up empty, running a migrate, and trying to create posts at the same time or get posts at the same time. We'd probably see it wait for a while before it
1:07:00 Jobs and CronJobs for scheduled tasks and queues
1:07:09 got access to the table again or the database. Okay. What what's next on your list? What we've got? Twenty minutes. So queue jobs is probably the big one. Queue and scheduled jobs. Alright. So Kubernetes exposes a primitive called jobs, which are just like cron jobs. I don't think I'm gonna be able to oh, I do. I love this plugin. So we have, you know, just like all our other Kubernetes manifests, really simple specification and we can specify this is the time to second time to live seconds after finished. Who knows what that is to have help?
1:07:16 Scheduled Tasks and Queue Jobs Overview
1:07:49 Later on the job is finished execution. Yeah. Whatever. Okay. We specify the container and we specify the command. Now, you'll also wanna be able to tweak when this runs. I'm using the wrong object. Crack up. Is that Cronghold? I'm gonna show my own ignorance. I've never been able to remember how this works there. Kubernetes. I spent a lot of my time in documentation. There we go. There is a thing called cron jobs. Yeah. I just couldn't remember what this was. So it's not too much because I've seen like online but Alright. That's batch v one.
1:07:50 Implementing Scheduled Tasks (CronJob)
1:08:35 Some things just prefer to v one and some things refer to like something document.vone. Yeah. I'm not sure why that yelled at me then. Maybe it's because the spec was wrong or maybe it never maybe that's not been promoted yet actually. So yeah. Okay. It's not cron jobs haven't had a view on yet but jobs have so There you go. Let's just copy the whole thing and modify it to to do our bidding. So we'll call this Laravel. I'm just gonna keep calling everything Laravel. We can use regular cron sales syntax to specify the job.
1:09:11 I don't know how to generate that most of the time. I just do $5. Yeah. Cron maker. I think this is the one I use. Just say run every five minutes. Why wouldn't you just do star star star star star? I have we because you want it to run every minute? The current helper and the Laravel then inside inside of the the console kernel determines what jobs inside of that should run and at what frequency. So you would run this every minute. Okay. So I guess I don't understand. I I've never built a Laravel application, so let's
1:09:58 try and cover a few basic questions then. Now as the queue processor, a long running process that should be deployed as a deployment or as a cron job that runs regularly? Oh, sorry. Sorry. It depends are we dealing with acute job here or are we dealing with the scheduled tasks? Because there there's two things that need to be in anyway. Okay. So I'm assuming the scheduled tasks is a cron job. Right? Yes. Okay. And you would just star star star star star star It's just straight up every minute when it and then all you do is you have
1:10:29 like, the migrate command, you have one entry point which is just a schedule call on run, I think. Yeah. Schedule call on run. Once you've run that every minute, it just deals with itself based on your PHP code. Okay. So we'll call this scheduled. This is the same FPM image. What command are we running? Schedule colon run. Is that all? Believe so. Let me just check if there's a force that's needed. Yeah. No. That's it. Alright. Let's apply it. So jobs and then like all the other Kubernetes resources, we type get jobs. Oh, no. A cron job. I call that
1:11:28 a job. Yeah. Here we go. Okay. And we can wait. Let's within a minute, should see a pod to get scheduled, which will spin up, run that command, shut that down and then that'll loop every minute doing the same thing. And by pure coincidence, we're about to hit quarter past and I've got a job in there that every five minutes sends an email. So we should see that it sends an email. Just pure coincidence on that, but we should see that actually executes that job and just what we are gonna do. So we should see
1:11:57 that email. What was that? Was it mail Mail trap. The I o. Yeah. So Oh, it crashed. Oh, no. Is it trying to write to a file? It will be, won't it? I don't think it should write to a file. Alright. Let's see. Unless it ends up maybe it writes like a cache file thing. Oh, no. Could not open input fail schedule run. What have I got wrong? Oh, you did get the artisan. Artisan. Hello. What? I didn't know from that. Software crashed. Okay. No. We actually had a few comments there as well. We were too busy focused on that. So
1:12:08 Debugging Scheduled Tasks
1:12:53 Frank and Nate both commented that we missed the hours and thank you. So that's the fact I kind of I don't know if I applied that because I got really confused when you disappeared and then realized the software crashed. Yeah. That's right. These things like reconnect and stuff. Yeah. So it says unchanged. Here we go. So we we this is now completing every minute. We've had two of them since the crash. Obviously, this one failed. So do we know what not to kill itself off immediately as soon as it's got the exit? There's no need for a time to life
1:13:33 on that. Is that because it's never going to reuse the same command again? We'll leave it for now. I don't think it's terribly important. Well, they clean themselves up once the CTL gets hit, I guess then. Yeah. Did that just crash again? Oh, that's that's just a broken one. So I can just delete that. Because would that not mean that every minute a new pod is created and that isn't being cleared out. Eventually, we're just gonna have memory from that. No. These ones are gone. They're completed. So they they don't take up any resources anymore.
1:14:09 So Oh, okay. Okay. So that seems okay. I guess if we wait another two minutes, we should see the email come in here Yeah. At at twenty past. But you said there was one other type of job, so let's try and handle that one then. Yeah. So this is the more, I guess, complicated one. What you can have in Laravel is queue jobs. So you can queue it up using various different queue drivers, SES, and you can play database, Redis, all those sort of things. But the way of using that is the same server doesn't make any difference to us.
1:14:26 Implementing Queue Workers (Deployment)
1:14:51 What we want to do there is have a command that's running long term. It's a long running process in the background that runs the r s n q colon work. That's all that we require. But then it gets a bit more complicated than that. You can have different named queues and have different number of workers per queues and and things like that, I guess. Yeah. That's just gonna be a new deployment for me. I mean, long run-in process means it's a deployment. I wanna be able to scale up and down depending on how many workers I want as well as tweaking the
1:15:24 parameters. So, know, we could I mean, we probably would just copy this and call it queue worker. We're not gonna need the NGINX so we can remove that. Mhmm. Do we do you think we'll need logs, cache test? I'm gonna in fact, you know, I'm just gonna keep it. I don't wanna I think we'd need it all because the framework will still hit those. Well, maybe not like views and stuff, but if they're bad, it's gonna be easy to do. Alright. So we update our labels to be queue worker queue worker and then we just modify the command. We
1:16:07 don't need container at all. And here we're just gonna see, we don't specify the command we're using the and built one. So here we just say PHP again. We specify the args. We're gonna run sorry. What was the command? Artisan. Artisan and then q colon work. Q work. Colon. Colon. Yeah. And then you need to pass so that will work by default. That will run the what's called all the three queues in Laravel are named, and the default one is just called default. But what you can do is you can then pass through double dash q equals
1:16:49 and give it a concept based string of different queues. So you could put just default that and that from the default one. So you you have different high high and low priority queues. You can make the high priority queue have 10 workers, low priority have two workers, and that's something for the purpose. Yeah. And and that's that exact reason is why I would use its own deployment for each of the different queue semantics I've got so that I can really define the quality of service and how quickly I need to process and how many workers and how
1:17:13 many replicas. Like not all queues, I would imagine at least in applications I've written in the past would be considered equal and I'd wanna be able to tweak that. It may seem like, I'll just add a new pod, add a new container to my main pod but I don't think that would be necessarily the right way to handle that. Let's apply. Where are we? Queue workers. Right. We now have five queue workers. Can we do we can we confirm that? Yes. We can. So in the rooms, if you go to slash queue dash jobs, it
1:17:49 will should send three emails. Oh, first of all, if we check the email provider, we should have an email from the con job in there now. Tada. Nice. So that means the cron's working. That's great. And so all new alignment. That's all working fine. Now if you hit q dash jobs, it should send three more emails off. There we go. There we have our queue workers. Easy peasy. So there's something that you can because Pigfy isn't really designed for long running, at least it was never initially designed for long running jobs. It's kind of basically a a sort of
1:18:23 Discussing Queue Workers and Resource Allocation
1:18:32 hacky way of doing it. The key worker is that moment. And so you can sometimes get many issues with that. So Laravel does provide something called max jobs, which is another flag in your past, which means that it'll kill off that that worker and send, like, an exit signal to it after x number of jobs. If you were to do that with the container, would that spin up a new one, which is what you'd expect? Or would that then start, like, a whole cascade of issues? Yeah. What what I would use is the resource limits here. You know, I I've already
1:19:06 defined how much how many resources I'm happy for these queue workers to consume. So like Kubernetes is gonna restart it when it when it starts to break these limits anyway. Okay. You wouldn't really need to hook into the Laravel aspect there. I would just rely on the container scheduling to go, hey, I don't really want you to consume in 14 gig of RAM, I'm gonna restart you now. That's cool. So That's that's his job. Don't have yourself. That's fine. And what's the 500 m? That wasn't really covered earlier, I guess, for the CPU. So a single CPU is
1:19:35 broken down into 1,000 units. I think they're called milli cores. So you can say this is essentially me saying the half a core. This this process is restricted to half a core of the host machine. Does that does that translate to roughly, like, every one and two instructions? Like, so if there's two pods on there, both given half a core, they will, like, sort of alternate who can get access or is or is that just like No. So it depends on how many cores are available on the machine. So like, I'm not sure if I'm gonna be able
1:20:07 to get that information from Kubernetes here. In fact, let's see how permissive our thing is. So containers don't necessarily obscure the view of the proc fail system. So typically you can just pop in here and you'll still see the actual host information. So you could see here I've got processors which means if I set this to 4,000 m and scale this, we've got it set on five. Yeah. We won't see all five of those schedule. We should see that fail. So yeah. There we go. We we have pending queue workers and if I describe one of those, it'll tell me that the
1:21:01 resources aren't available and sufficient CPU. Okay. Right. Not it's not like how it allocates it. So Well, it's because we're using a limit. Right? I mean, I could have said requests which means I kinda want this but it's not a hard request, know, if it's available, give me it. Whereas a limit is like, it's actually gonna set aside half a quart for that process and it's gonna set aside 50 mega ram for that process and it won't allow me to schedule. So there's still contention for any pods that are running on the machine, they're still competing for resources dependent on the instructions
1:21:42 we're sending but the scheduler is gonna go, I know at some point this is gonna have 4,000 milli cores of CPU and I'm not gonna schedule anything that tries to go beyond that. Whereas if I leave this as request, we should see that adjust I think it will actually schedule most of the time. Because they're not using that many at that time. Oh, no. I okay. So the scheduler is gonna say no as well. Alright. So but yeah. The request is kinda given the scheduler a hand of what you need. The limits means restart the process of every goes
1:22:00 Safe updates with deployment update strategies
1:22:16 beyond it and then the schedule will do its best to make sure you schedule on a note where it's not gonna have too much contention for those So Okay. Yeah. That makes sense. Okay. That is actually to be fair, everything apart from one thing on my list for the pretty much. So What did we not cover? Release cycle. So how would you not go about doing the natural like full on release? Not necessarily with like CI's of thought. You build a new image, it needs to be deployed. Can you go in with QCTL, delete the pods?
1:22:38 Discussing Release and Deployment Strategies
1:22:50 How would you automate that or something? No. I mean it'll it'll handle that for you so let's assume and we can do this in two minutes. So yeah, let's use our queue worker. Right? So firstly, let's just remove these limits so we can get all five and let's change the image. Let's say instead of, you know, normally we would change the tag here to be v 54 or whatever. Right? But what if I just wanna say deploy engine x? So the way that this works is if I just deploy this and run this really quickly,
1:23:23 is it oh, container errors. Let's just take off all this stuff that we don't need. The security context is why that's failing and the command won't exist. But there's a whole lot of why that was failing. So so again for trying to do it too quickly. Right. Okay. That's pretty generic. So let's reapply that and then run this. What we're gonna see is that and it's it's fast so it's difficult. Right? But we actually spun up two new ones before shutting down the first one then we spun up a third and then we started scheduling two more after that and
1:24:01 then it starts terminating. So on top of a deployment object, actually have the ability to specify the the strategy and then we can have a type and a rolling update, rolling update which allows us to specify a search or a max unavailable. So the deployment already knows how to do safe deploys with new images. You have to tell it to do the rolling update which is actually happens by default and you get a max surge of one I think. You can also use percentages so you could say that I want 25% of my pods to be unavailable. That means
1:24:42 that it will sacrifice, let's assume, sorry, lots of information. Let's assume I have 10 pods running, if I have a max unavailable of 25%, it's gonna be able to shut down 25% of those pods which is two. If it was 50% it would shut down five and then it would spin up new ones. If we go with a surge approach what we say is I have 10 with a max surge of 50, I'll actually schedule up to 15 and then once five are healthy shut down five and then spin up more. Okay. So so with that in
1:25:12 combination or we use one or the other? You can only use one or the other. So you can let's let's double check. Right? Because I've been wrong a few times a day anyway but I didn't care. Okay. I guess you can use them both together. I thought you could only pick one. So, here I could say I I always need at least 75% to be running and I don't mind scheduling over provisioning by 50%. And then the scheduler will work all out for you. You don't need to worry about it too much. Okay. Okay. So in terms of
1:25:42 when when you do release, you'd normally have a your deployment process, your CIO, whatever, would tag a new version of the image and then would you do, like, a cube apart a cube CTL apply and that would then start pulling in the new images for you? It's it's definitely how I would start my, you know, my continuous integration deployments ever would just reply over the top with that new tag or whatever I'm using and that Kubernetes had up from there and then eventually you can start to look at things like, you know, get ops, continuous deployment from within the cluster and get
1:26:18 a little bit more sophisticated doing progressive rollouts making sure that, you know, the metrics don't change for the first ten minutes at 10% traffic and then scaling up. We could do a couple of more episodes on that. I'm not gonna be able to do it justice and like ten seconds but Yeah. You could definitely start with a cube control apply and then take it from there. Okay. That sounds good. Alright. That's cool. Everything I think so. Yeah. We we covered it a lot. What I'll suggest is I hope people find this useful. Leave comments or anything that you
1:26:36 Conclusion
1:26:46 want us to tackle on a future episode. I'm sure Alex would be happy to join me. Alex and I'll have our own conversations and work out what else we can do in the future. We definitely wanna I've already got an idea of what we should probably hate before, so we'll cover that out of outside of the screen. Alright. Well, thank you for joining me, Alex. It was an absolute pleasure. I had fun doing that. I'll see you for the next one. Goodbye, everyone. Cheers.
Technologies featured
Meet the Cast
Stay ahead in cloud native
Tutorials, deep dives, and curated events. No fluff.
Comments