[0:15] you [0:29] [Music] [0:42] my [0:48] hey hello and welcome to today's episode [0:51] of rockwood live i am your host rock [0:53] hood [0:54] today we're diving back into our laravel [0:57] on kubernetes journey [0:59] and i am joined by a previous guest [1:02] friend [1:02] and budding conference joiner beer [1:05] drinker [1:06] alex burris hey how are you i'm good [1:09] thank you [1:10] i'm all right actually i'm doing quite [1:12] well i'm excited to [1:13] come back to my my lanravel stuff here [1:15] and and see what we're doing [1:17] like um we've done [1:20] well sorry i i think i've done five or [1:22] six episodes on this now you joined us [1:24] for one of those [1:25] and you reached out and said there's [1:27] still a few things that we haven't [1:28] covered yet do you want to give us [1:30] well first just a little introduction [1:32] about yourself and then we'll talk about [1:34] what we want to try and cover today [1:37] yeah sure so um i'm alex i am a [1:41] lead developer at a e-commerce platform [1:43] in the uk called shopblox [1:44] um we use laravel um a lot [1:48] and we're working towards moving into [1:50] kubernetes and docker alongside some of [1:52] our previous infrastructure [1:54] stuff using council um and that's [1:56] basically why i reached out because [1:58] some of the previous streams have [2:01] some topics which model operation or [2:05] haven't been covered yet so hopefully we [2:08] can cover those today [2:09] and anything else today soon i've got a [2:11] full list of um [2:13] a full list of stuff to cover on the [2:15] post and they're here so [2:16] we'll see where we get to in it but [2:18] there's quite a few things in there [2:19] we'll certainly try and cross [2:21] a few of them off and i'm always more [2:23] than happy to schedule [2:24] more of these if we want in the future [2:26] and i really want to make sure that we [2:27] cover [2:28] everything that teams like yours need to [2:31] get their laravel application running on [2:33] kubernetes successfully so we'll do our [2:36] best [2:37] um all right why don't we talk a little [2:41] bit about what you're prepared so we're [2:43] not using like a real production grade [2:45] application today right you've put [2:46] something together that is going to be [2:48] is it close to that is it going to use [2:50] the components that are missing last [2:52] time [2:52] give us a little flavor on that yeah so [2:55] what i've created is [2:57] not something anybody would ever use in [2:58] production it's got two main points [3:02] one of them creates some jobs and one of [3:05] them [3:05] is a um sends an email the email that [3:08] says hello world [3:09] like it's very minimalist but it adds [3:12] things to the queue [3:13] um it has some scheduled tasks in the [3:15] background [3:16] it does some um [3:19] it has some assets which can be compiled [3:22] and uh [3:23] just things like that which every team [3:25] will have none of them will be as basic [3:26] as this [3:27] but if you get the infrastructure down [3:28] to run a scheduled task [3:31] it doesn't matter what the task is if [3:33] you've got uh stuff in the background to [3:34] run [3:35] queues it doesn't matter what the queue [3:36] job is so we've just got some simple [3:38] code here [3:41] all right sweet let me just pull up the [3:45] the repository so it's on github.com [3:48] username alexbevers laravel dash example [3:52] dash project [3:54] um i already have this client [3:58] here um we have a live share configured [4:02] so i should see yep there's your name [4:04] there so we're now in a position where [4:06] we can try to address some of those [4:07] concerns and that we're missing do you [4:09] want to just quickly [4:10] run through that list you've got and [4:12] then we'll try and decide what is best [4:13] to kick things off with [4:15] yeah so um one of the things that's [4:18] probably best to start with i guess is [4:19] migrations [4:20] literally every application i can ever [4:21] think of requires migrations to run [4:23] and you've touched this briefly in the [4:25] past sharing well not sure about seeing [4:27] how it would be done and i think the [4:29] example still had [4:30] like abc as like the [4:33] um into the uh into the worker [4:37] so that's that's probably the main one [4:40] there's um [4:41] the two big things beyond that i guess [4:42] is queued jobs and [4:44] scheduled jobs so on a normal server you [4:47] would run [4:48] supervisor and you'd have several [4:51] different workers [4:52] scheduled to run in the background to [4:54] run a specific command called [4:56] artisan um key work [4:59] obviously it isn't going to be exactly [5:01] the same as that in kubernetes so [5:03] the but it'll be similar i assume and [5:06] then there's also scheduled tasks which [5:08] normally you'd use a current job for [5:10] on your server that's i believe [5:13] um there's like a scheduled tasks built [5:15] into kubernetes so i assume that's how [5:16] we've managed that as well [5:18] but those are the three main things i'd [5:19] say which [5:21] most applications would make use of at [5:23] some point [5:26] um beyond that there's i've got things [5:28] like [5:29] um managing your secrets um so we've got [5:32] uv [5:32] stuff how that could be released and [5:35] using config map that's [5:36] less likely to be an issue because you [5:38] can just inject it in the docker file [5:40] and sorry in your docker image um [5:44] then there's also things like asset [5:45] deployment which you've covered in the [5:46] past so that's less of an issue [5:50] all right yeah there there's a fair [5:52] amount there let's let's just see what [5:53] we can get through it and then if we [5:55] need to schedule more time we will [5:56] definitely [5:57] do that and tick it all um i think [6:00] because you've gone through the effort [6:02] to produce this application [6:04] what we're trying to do is i'll just try [6:05] and send as many pull requests as i can [6:07] to it [6:08] during this episode as we kind of work [6:10] through this together [6:12] and anything else we'll just try and [6:13] make this the default example for [6:15] kubernetes on marvel or laravel on [6:17] kubernetes actually [6:19] all right so let's see [6:22] database migrations first then let's see [6:24] what you've got in place for actually [6:25] running this on kubernetes in fact i [6:27] i don't have any kubernetes right now [6:29] hold on let me start docker [6:32] uh okay so we do have a docker compose [6:36] fail [6:37] uh that is a default one that comes with [6:39] laravel i've not touched that whatsoever [6:41] that's a development environment only i [6:42] think [6:43] something new that came with global fact [6:48] i sent a pull request to the laravel [6:49] project [6:51] three or four years ago with a docker [6:52] file and they said sorry we don't want [6:54] to support docker [6:55] just there you go just throw that out [6:57] there i'm not better [6:58] just saying now they now have like a [7:02] first-party [7:03] product called vapor which is to [7:07] deploy onto aws lambda and so i assume [7:09] that's pushed much more [7:11] on the um getting docker working because [7:14] they now make money from it so [7:17] all right well i'm just clicking the [7:19] magic reset [7:21] kubernetes because i can't remember the [7:22] last thing i was doing but that's to be [7:24] fair so that's now reset and we'll [7:25] wait for that to become healthy let's [7:29] see [7:30] the docker compose file that is not [7:32] anything i've touched on i've not done [7:34] anything [7:34] for development all i've done is create [7:36] two docker files which are inside [7:38] resources ops [7:39] docker um i've got two in there i've got [7:43] an [7:43] nginx one and one fpm one [7:47] um those are the files which i've [7:50] started okay well i mean this [7:54] this won't work by default unless we use [7:57] sale [7:58] um [7:58] [Music] [8:03] i don't actually see a docker file here [8:05] am i being silly [8:06] um so inside it's inside of the vendor [8:10] um so when you do computer install [8:12] you'll get a [8:14] vendor file uh a vendor folder which has [8:16] laravel sale in there and that has [8:18] different [8:18] times you can specify which one and it [8:20] will compile it based on that [8:23] all right let's the half composer [8:26] i don't uh all right [8:29] um i don't believe that you would [8:31] require a large sale for this that would [8:33] just be for development environment only [8:36] um you're right i'm going to get [8:40] sidetracked there i was going to start [8:41] putting together a development [8:42] environment for this and to be honest [8:44] i think that's what you can come up with [8:47] yeah i i [8:47] i don't think it's important i'm just [8:49] going to create a docker file we just [8:50] want an image with this application in [8:52] it [8:52] that's that's fine i'm going to use [8:55] if you've done it it creates a docker [8:56] file which will [8:59] build and pm in the nginx image [9:02] separately [9:03] where are those resources ops [9:10] yeah is this based on prior art from the [9:13] other episodes [9:14] exactly a copy of the previous streams [9:17] all right okay good so we talked about [9:19] i separated them out into two separate [9:21] rather than having the [9:22] make file specify individual targets [9:25] i've made it so that [9:26] they are just two separate two separate [9:29] jobs because the overlap was very [9:31] minimal [9:32] so i think that's a good or bad idea but [9:36] all right and you've already added make [9:37] target that this is already [9:39] my favorite episode ever because you've [9:41] done all the work okay [9:43] let's build these then so i'll just [9:46] make sure i've got the target names [9:48] we'll do build let's build fpm [9:50] first and then we'll do build engine x [9:56] okay so that's going to give us our two [9:57] images which [9:59] you know for anyone that's watching go [10:02] watch the previous episodes we'll add [10:03] the links into the description [10:05] afterwards [10:06] it walks you through the entire process [10:07] we're going to assume [10:09] that we're starting from the point where [10:11] you've already built your fpm nginx [10:12] images and pushed them to some container [10:14] registry and we're going to try and get [10:16] this working on kubernetes with [10:18] all the bells and whistles that we've [10:19] omitted previously [10:21] um are you going to be doing this on [10:23] kubernetes locally i assume are you [10:24] going to be doing this on [10:25] a production cloud environment [10:30] i'm just going to use docker for mac [10:31] unless you feel there's a reason we [10:33] would need to have an [10:34] alternative cluster but i don't think [10:37] the only thing that i would say [10:39] purely because i don't know much about [10:40] it locally is external load balancers [10:42] and how those sort of things work [10:44] but that can be covered in a far later [10:45] episode anyway [10:47] yeah i have i have done previous [10:49] episodes on ingress and advancing on [10:51] kubernetes [10:52] that aren't they're not larval specific [10:53] and i don't think they have to be [10:55] [Music] [10:57] um [10:59] that's that'll be all right i mean we [11:01] can talk a little bit about how the [11:03] the services and the angers work [11:04] together but i don't think [11:06] um i i don't need a cloud environment to [11:08] kind of show that off [11:10] yeah i don't think there's anything else [11:13] that i could think of that is massively [11:16] different [11:17] from development or local environment [11:22] all right well it looks like we do have [11:24] a little bit of time to kill while this [11:25] builds maybe i should have kicked that [11:27] off [11:27] previously however if anyone watching [11:29] has any questions that they want us to [11:31] address feel free to drop that in the [11:32] comments [11:33] or drop me a tweet [11:36] at raw code so [11:40] let me try and understand the migration [11:43] path here so we're going to be using the [11:45] artisan command [11:47] which i don't think is ever important in [11:49] here we went through this previously [11:50] yeah [11:51] which has to run a db migrate is that [11:54] correct php migraines [11:58] so does that i i need a database [12:00] deployed to my kubernetes cluster then [12:02] right [12:02] uh yes i've not touched anything to do [12:04] that yet all right [12:05] sweet finally something i can do okay um [12:09] that [12:10] i've tested this locally with mysql [12:12] shouldn't make any difference because [12:13] it's all [12:14] using the orm but yeah all right what [12:16] database do you want [12:18] uh let's go manually well movie dvd 10 [12:22] or whatever [12:25] all right so i'm assuming you don't [12:27] really need me to go through [12:28] the production deployment mechanisms for [12:30] murray db we're happy just to use [12:32] something that's [12:33] mariadb on kubernetes right yeah yeah [12:36] but personally for me i avoid running [12:38] any databases myself anyway i'd just [12:40] rather use managed services [12:42] save so much effort and um [12:45] but some people i guess will be running [12:48] images [12:49] well for anyone that is going hey i [12:51] wanna know how to do it under production [12:52] just use helm go and use the you're [12:55] gonna use work from other people there's [12:57] a helm chart says the artifact hub let's [12:59] talk about that actually so [13:02] artifact hub this is from the cncf it [13:06] hosts all of the [13:07] cncf project artifacts go figure helm is [13:10] one of those [13:11] where we can just say hey give me [13:12] mariadb we could filter it on helm [13:15] charts if we wanted [13:17] we click this and everything you need to [13:19] know to get a [13:20] pretty production grade deployment or [13:22] maybe is going to be here you can use [13:23] helm [13:24] you tweak the values based on whatever [13:25] you need and you deploy it [13:27] um probably what i would recommend [13:30] however for today [13:31] i'm not going to do that just because i [13:35] just want something quick [13:36] what i am going to do is check the [13:38] [Music] [13:40] environment bars that i need i know i [13:41] need to set the mysql root password [13:43] maybe a user movement database [13:44] i also want to make sure i got the [13:45] version right so it looks like running [13:47] 10 is okay [13:48] and if i just search for my [13:52] sql password [13:55] these are the variables that i have [13:57] available to configure this image [14:00] and i'm going to drop these n so we're [14:02] just going to say environment [14:04] i'll get some space let's do [14:08] uh mysql [14:11] i'm pretty sure there's a random root [14:15] not get too fancy today [14:17] [Music] [14:19] okay let's set a user and uh we'll set a [14:22] value of [14:23] laravel and we'll set the password [14:31] laravel um [14:34] horse no we don't need the host uh [14:38] database yeah [14:49] uh we'll just call it laravel was that [14:51] standard is that what you would do in [14:52] your application would you tweak it more [14:53] than that [14:54] um so i would personally name the [14:58] database something relevant but [14:59] obviously this [15:00] is yeah i think this is relevant except [15:04] is yeah fine all right okay cool [15:07] and happily that is also the default [15:09] that we have in the inv [15:10] file oh is it uh [15:13] yeah the name and password for different [15:16] but [15:17] that's easy to change all right okay [15:20] uh let's deploy this oh no we need to [15:24] expose this okay so [15:26] uh one of the things we want to do is [15:28] when we apply this deployment to [15:30] kubernetes it's going to create the pods [15:32] that run mario db followers [15:33] we're going to by default the replicas [15:35] will be one but we'll make that a bit [15:37] more explicit so we're going to run one [15:38] of these [15:40] however what we want to do is [15:43] make sure we can have service discovery [15:46] around [15:47] this pod which could be pods so that we [15:50] can use dns to actually speak to it [15:52] so i'm going to add a service [15:56] of ready b [15:59] uh the selector has to match what we [16:02] have above [16:03] so you can see app mirror db matches the [16:05] same labels we applied to the deployment [16:08] uh we don't need the target port because [16:10] this is a pretty simple setup we're just [16:12] going to say [16:13] port 306 so that should be [16:16] oh yeah good those are built as well [16:18] which is handy [16:19] so let's deploy uh was it resources [16:24] ops uh kubernetes murray do we [16:34] let's check my cluster [16:37] oh there we go too many clusters [16:43] and we should be able to run get pods [16:46] oh we have an error i broke it um [16:50] because i never set a random root [16:51] password and i never said root password [16:55] yeah that's the one i want it just means [16:58] that [16:58] i won't actually know the root password [17:00] which i think is good so value [17:05] what do you do then you go into the [17:06] secrets to extract it [17:08] or well we already have this user with [17:10] this database configured [17:12] so we're making sure that that's the [17:14] root password right yeah [17:15] yeah it's just the root password [17:18] we can just apply that over the top [17:20] we'll run a get pods watch [17:22] we can already see that we have one [17:23] mirror db running the error one is now [17:26] terminating [17:27] and that is good all right database [17:31] do we require anything else [17:36] um what's the q processing [17:40] first of all why do we use them for the [17:42] queue [17:43] so the queue can just by default use [17:46] mysql [17:47] um you can use redis you can use [17:50] um like wrap mq and all that sort of [17:52] stuff but by default you can just make [17:54] it one [17:55] using the database so i'm just going to [17:58] assume that that's the [17:59] essential way of doing it um okay [18:03] uh and this deployment that we have here [18:07] uh let's see [18:10] uh replicas one label [18:18] that is complaining because i am not [18:20] setting the resources required [18:23] and so it's telling me that i could have [18:25] stray pods i think [18:29] oh no let's see [18:32] resource limits yeah okay so [18:40] there we go so we can minimize that to a [18:41] single line yeah my [18:43] my editor is just like you put and you [18:45] know in production you don't want to [18:47] deploy things without resource damage [18:48] you don't want them to just start [18:49] consuming [18:50] all the cpu and memory across your [18:52] cluster so you would say [18:53] constrain nest is something that i [18:55] consider to be safe [18:57] is that a container or is that uh [19:00] noodle yeah per container so i mean if [19:02] we look at this as an example right you [19:04] know we've got engine x here which [19:07] really requires nothing um so we can say [19:10] that the limits on this [19:13] uh cpu [19:18] now completes only going to get me so [19:19] far say 500 [19:22] mm nginx probably isn't going to require [19:26] too much uh as [19:29] i'm going to kill whether it wants [19:34] no memory limit i did that very limited [19:38] is it memorize it memory [19:41] you're correct cool thanks man [19:45] so we can set that there and then fpm is [19:47] probably going to require more so i [19:48] think what we'll do just [19:49] for the for fun let's just actually set [19:52] these really [19:53] low and we'll see them crash we'll try [19:56] and boost them if we need [19:57] we'll see what happens let's apply [20:01] this so we're just going to apply our [20:02] deployment i don't [20:04] oh what have i got wrong [20:14] uh hard to pick at the editor here it [20:17] seems to be complaining [20:24] okay my limits can't be unmarshaled [20:27] quantities must match the regular [20:28] expression [20:32] uh okay so it doesn't want mib i think [20:34] it just wants a m [20:39] you thought it might be on two places of [20:42] course i do [20:43] thanks okay [20:47] now we can run get pods [20:50] kind of expect that to fail well we've [20:52] got an image pull policy problem [20:54] and you've got this set to always this [20:55] is a local cluster [20:57] and so we actually want this to be never [21:01] because the image doesn't exist on a [21:03] remote repository a remote registry [21:06] okay so we can just apply that over the [21:08] top [21:10] and so what the way image pro policy [21:12] works [21:13] is that you know uh it actually seems [21:16] quite healthy with those [21:17] figures so we'll leave it for now but i [21:18] do expect that to crash before the end [21:19] of the episode [21:20] when we tried winning anything yeah yeah [21:23] so [21:24] you had the image pulls policy to always [21:26] and there are times and places where you [21:28] want to use always definitely [21:30] however when you have an image like this [21:32] that [21:33] let's talk about how this is resolved by [21:35] kubernetes first when you do not provide [21:37] a host for the registry [21:40] this assumes that your image is [21:45] this [21:49] it assumes that you're an official image [21:51] on the docker registry this is a [21:52] hangover from when [21:53] docker was pretty much the de facto [21:56] container runtime [21:57] and that it assumed you were always [21:58] going to pull from the docker hub [22:01] and that doesn't exist so when you have [22:02] an image pull policy that's always in [22:04] your cluster the controllers are going [22:05] to reach out and try to get the latest [22:07] hash [22:07] or for that image it doesn't exist it [22:10] fails and it exits [22:12] so for local images what you actually [22:13] need to do is the image pro policy never [22:15] and just make sure it's available on the [22:16] host [22:18] and it's running and it's happy however [22:21] our application probably isn't going to [22:23] work first we haven't done those [22:25] database migrations that we actually [22:26] want to be doing and secondly it doesn't [22:29] know where mariadb is yeah but if you [22:32] try and access it you should [22:34] i assume get error pages using in the [22:37] lava lava page yeah i i would assume so [22:40] for sure [22:42] so let's port forward is this port 80 [22:45] no yeah yeah okay [22:48] yeah it is okay uh so we'll make that [22:50] available in port 8080 locally [22:54] and we'll browse to there [22:58] all right well our first problem is that [23:00] we need somewhere to store our logs [23:02] and we're getting a permission denied on [23:05] that [23:06] let's take a look at what's going on [23:12] so i'm going to jump inside of this part [23:15] i hope we've got access to bash [23:19] oh it's an alpine one not mine okay so [23:21] we have access to that [23:27] i didn't look in the dock for fail where [23:30] well i think [23:38] yeah that's their application uh no [23:40] that's missing most of it [23:43] that's this is engine xl right are you [23:46] in the engineering oh sorry for your [23:48] knee [23:50] yeah how's this deployed [23:55] oh the names are quite for both uh [23:59] yeah i didn't know whether or not [24:00] calling something just like fpm was a [24:02] good idea so i went [24:04] okay here is our application we are [24:07] actually the root user so that [24:08] um directory failure here storage logs [24:12] i'm assuming storage doesn't exist [24:14] oh it doesn't um no storage exists by [24:16] default [24:22] ah well the engine x is running as www [24:25] data they're inter [24:27] oh sorry dm php fpm [24:32] uh let's see ah of course right [24:36] uh so obviously it's a good idea to [24:39] run containers there's root uh well [24:42] there is a little bit of juggling that [24:44] has to be done with fail system [24:46] permissions [24:48] so let's let's see the best way to [24:51] handle [24:52] this is to provide [24:55] temporary or ephemeral storage for [24:58] things like that where we can control [25:00] the volume that we want to make [25:01] available [25:03] so let's do uh [25:07] okay so we can add a volume to our spec [25:11] and let's call this logs [25:15] i think it's a name logs [25:19] and we want a empty dir [25:25] i don't think that needs any [25:26] configuration size limit medium me up we [25:29] can just [25:33] oh i can't remember when in doubt look [25:36] at that kubernetes empty there [25:39] um please seem to remember about empty [25:41] div if there's anything that does wipe [25:43] it out as well [25:44] is that correct or is that well yeah [25:45] we're just using it for cache okay it's [25:47] not [25:48] it's empty object so for logs and cache [25:51] yeah i'm totally okay with that plus to [25:53] be honest we're actually going to remove [25:55] your logging to not be to a file and [25:57] we're going to move that to standard out [25:58] so that's maybe something we could do [26:00] first however [26:01] let's let's try and do it this way so we [26:03] can show it working [26:05] um and then we'll we'll change it up a [26:09] little bit [26:09] so we now have this volume available so [26:12] empty [26:12] just means create an empty volume [26:14] ephemeral when a container or pod dies [26:17] get rid of it that's it now we want to [26:20] provide logging for our fpm [26:22] so we're going to come in here and we're [26:23] going to see if we have not volume [26:25] devices it's volume mounts [26:28] um we're going to have logs [26:34] uh we want a mount path of w [26:38] html storage [26:41] logs and we don't need any other flags [26:45] now this name here just has to match [26:46] what we have here which [26:47] does mount it to this location [26:52] there is a way to configure [26:55] the emptor um permissions via the [26:58] security context [27:00] let's see if we can pull that out our [27:02] fingers [27:04] so we can set um let's see if i can find [27:08] this [27:11] [Music] [27:17] all right well let's try that in a [27:18] second let's see what we have first [27:20] because tomorrow i can't remember we can [27:21] sit [27:22] in fact maybe it depends on the version [27:25] of kubernetes i've got [27:27] and it's i'm probably revealing too much [27:30] now [27:31] that it isn't entirely useful to the [27:33] people watching but the security context [27:35] has changed a lot with the recent [27:37] version of kubernetes which is 120 [27:39] which i actually think i'm running uh [27:42] version yeah [27:46] well client and 119 there okay so we [27:48] might be okay [27:50] we'll apply first and then i'll walk [27:52] through the all those things that are [27:53] going through my head [27:55] uh so let's get pods and alex keep me [27:59] honest here if there's anything i say [28:00] that is gibberish just ask me to [28:02] elaborate on it because sometimes i can [28:03] be bad for that [28:06] sweet okay well if anyone watching is [28:11] like [28:11] i have no idea what the hell this madman [28:13] is talking about just [28:14] comment and i will explain it i promise [28:17] yeah i've got that doctrine [28:18] open as well so if any comments um ask [28:20] questions [28:23] i just need this container name [28:27] i'm going to change that next time i [28:28] deploy this just to be fpm so it's easy [28:31] for me to use the command line [28:34] so we have storage yeah when logs are [28:37] still owned by root [28:39] so we still need to fix that [28:43] now they'll be owned by ever the user of [28:45] the processes [28:47] so we could just change the security [28:49] context of that [28:51] and do [28:54] run as [28:58] id www data oh no i'm not inside that [29:02] anymore [29:04] 82 is that id always going to be the [29:08] same [29:08] or yeah it's built into your image so [29:12] next time you do the build would it be [29:14] 82 still [29:16] no that'll be set by the fpm right that [29:20] i would not expect that to change uh [29:22] right you should be safe [29:24] um i don't think you can do this the [29:26] reason why is that this security context [29:28] runs on [29:29] the the node essentially is configured [29:31] as [29:32] part of the name species are set up so [29:36] uh you will need to use the numeric id [29:39] let's try and i'm going to rename this [29:43] actually let's do that so we're going to [29:46] just call [29:46] that's the image where's the name there [29:48] we go let's just call this fpm so it's [29:50] easier for me to get enough [29:52] and we'll call this one nginx [29:55] okay now we can apply [29:59] make sure it's running and we're gonna [30:03] exec it entered this [30:08] or ftm and ash [30:12] and you can see when i type id i am now [30:14] ww data [30:16] if i run ps everything is www this is a [30:19] much [30:20] saner configuration and i'm hoping the [30:23] empty dare [30:26] all right okay so we need to fix that [30:28] and if you don't have the empty [30:29] developer would that not [30:31] just make it work because [30:35] will create that folder if they need it [30:38] hey [30:39] so you're okay but [30:42] yeah yeah you're you're actually correct [30:45] um maybe i'm over complicating this a [30:47] little bit [30:49] but also how come how come the files are [30:52] still in by root [30:53] is that because when we built the image [30:54] it was running as groups [30:58] yes um because [31:01] do the do those files not need to be [31:03] owned by wwe data as well so that [31:06] fbm can process them no they're readable [31:09] by anyone [31:10] uh something else i would normally do as [31:12] well is enable read-only file system [31:14] so you know i actually don't want you to [31:15] be able to write to anything which is [31:16] why the empty dart's important because [31:18] that will be somewhere we can write to [31:21] yeah i just wish i could remember the [31:23] file system thing that i want here [31:26] so we're going to look it up [31:29] so kubernetes security context [31:34] and there is an fsu's fs group is that [31:37] it [31:42] where's that password [31:47] yeah why is that not all completing for [31:49] me so this might just be the version of [31:50] kubernetes i've got [31:51] it doesn't have this flag anymore um [31:55] let's just put it in and see what [31:59] oh happens really yelling at me isn't it [32:05] unknown okay yeah that must have been [32:07] removed then [32:10] so let's see kubernetes [32:13] empty their user permissions [32:18] there is a way fs group [32:22] damn it [32:26] surely if they remove that they want to [32:27] put like a deprecation flag to tell you [32:28] what anyone's called [32:34] no [32:38] but it's definitely fs group which is [32:40] good because i knew that's what it was i [32:41] just [32:42] don't know how to handle i mean we could [32:43] use it in a container i'd like to try [32:45] and avoid that of course uh [32:49] in fact am i doing it in the wrong place [32:51] that's what it is [32:53] so this is the security context for the [32:55] pod i bet you if i [32:59] yeah there we go [33:04] um that should create [33:09] so do we want the user to be [33:12] on um [33:16] on the spec not on the pod or not [33:19] uh it depends what user we have inside [33:23] the engine x [33:25] so let's let's take a look at that [33:29] and take a look at our password file [33:31] which is our source of users [33:34] yeah engine externs is 101 and we don't [33:37] have access to [33:38] www data here at least i mean i [33:41] don't see yeah no [33:45] data is a fpm yeah [33:49] let's try this um [33:52] just out of curiosity more than anything [33:54] there so [33:57] because you'll use the 82 for the fs [33:59] group [34:00] but that would be applying it to the [34:02] engine next one as well [34:04] yep there's no empty dirt there so ah [34:06] right so any applies if there's enough [34:08] to do it [34:12] well maybe well yeah there we go [34:15] so if you haven't on the nginx one as [34:18] well [34:18] you wouldn't be able to specify the fs [34:20] script for each individual container [34:22] ipod there would you because they have [34:24] different ids [34:27] no for that i'd then be using an [34:28] internet container that has a [34:30] root user that changes the permission [34:33] on the empty there which would be reused [34:35] across the inner containers [34:38] we can we can cover that if we think [34:40] that it's important [34:42] um but let's just try and let's try and [34:44] get this working first and then we can [34:45] maybe do some cleanup [34:46] so you can see here we've got our uh [34:49] grip right access to here and in fact [34:51] that empty door just came with explicit [34:53] permissions for anybody anyway so we [34:55] actually didn't need to do that but i [34:57] think it's [34:58] that configuration parameter hopefully [35:00] is useful for others if you're looking [35:02] at a similar situation [35:04] let's put forward [35:08] so [35:12] 8080 so we should be able to write the [35:14] logs [35:18] and now it's complaining that we've got [35:19] some configuration missions so this is [35:21] going to be that dot env file that you [35:22] mentioned right [35:24] uh yes it is okay so now we need a [35:26] contact map [35:29] so um let's create [35:33] config map dot yaml [35:37] spec this out this is our light of l [35:40] config map [35:42] um [35:45] okay [35:49] so there is a secret value in here i'm [35:51] not that fussed about it being secret [35:52] because i'm just going to delete the key [35:53] and play account probably i'm never [35:55] going to use that mail thingy again [35:57] so i'm just not going to be too fussed [36:00] about [36:01] exposing them yeah you could you could [36:03] just um after the [36:05] after this um screenshot you can just [36:07] click the refresh button and [36:09] watch out it will be used right nice [36:10] okay so [36:13] we we really just want this env fail to [36:15] be exposed [36:16] as environment variables and a conflict [36:19] map is our [36:20] ideal way to do that now some of this [36:22] isn't actually [36:24] some of this i would bake into my image [36:26] i'm not going to get [36:27] dogmatic about that right now and we can [36:29] talk about that uh [36:31] once i've got it working but like you [36:33] know the app name [36:34] isn't something i'm going to want to [36:36] change per environment [36:38] conflict maps to me should only ever [36:40] change variants [36:42] for environmental things everything else [36:44] should be baked into the image so the [36:46] app name [36:47] yeah i would probably put it in a docker [36:49] image somewhere [36:50] yeah there is something built into [36:52] laravel already [36:54] as well which is um [36:57] you can sort of cache the uh what they [37:01] call config [37:02] so um which is their.emv files and other [37:06] things that [37:06] are used for the application they can [37:08] all get cached and there's a command to [37:09] do that so [37:10] it doesn't actually read anything from [37:11] the environment however that would [37:13] require it to be [37:14] then stored within the actual image [37:17] itself but [37:17] not so i guess that's [37:21] a decision that you can make i'm sure [37:23] there's some [37:24] yeah we'll talk about that uh in a [37:26] moment i'm sure i could like [37:28] regex i'm i'm kind of looking at it [37:29] going i'll just be quicker to type it [37:32] because i bet me going i could just [37:33] reject all this [37:41] so what we want to do is [37:44] all you want to do is just change the [37:45] equals to a column answer yeah [37:52] why is that not letting me register oh [37:53] does my vs code them not support that [37:59] time for trusty command on um [38:02] you know you know what's going to happen [38:05] or just come on death [38:07] yeah let's just do it this way so [38:10] change equals paracolon space [38:16] go [38:20] and then and then okay so now we need to [38:24] yeah that needs to be a string billion's [38:27] not supported [38:29] now we want our host so this is going to [38:30] be the service name that we've provided [38:34] which i believe is mariadb we can run [38:37] get [38:37] services [38:42] yep so we have our database available at [38:44] that name [38:45] on that port that's our database our [38:47] username is laravel and our password as [38:49] laravel [38:50] and this would be a secret let's get it [38:53] working without and then clean it up [38:54] don't let me forget that yeah [38:58] broadcast driver i don't know what that [38:59] means i don't know what that means i [39:00] don't think we don't use it [39:01] so you can ignore all of those ones we [39:03] didn't care about that the session [39:04] driver actually [39:05] um that wouldn't we're not using [39:07] sessions in this bitcoin you can know [39:08] that [39:09] um in production i would normally change [39:10] that to uh redis or database [39:16] do we need the aws access stuff no [39:20] that's just because you can buy with the [39:23] file system [39:24] plugins you can upload straight to s3 by [39:27] um [39:28] by default so that's all guys [39:35] how come it's complaining about numbers [39:37] like 25 25 [39:40] i thought yeah we'll support introducing [39:42] that [39:44] it does uh [39:48] what's it saying [39:52] i think the config map just expects a [39:54] string to be honest [39:56] yeah like everything strings [39:59] we're not running memcached we're not [40:01] running red [40:02] no all right i think [40:08] that will be enough so let's apply that [40:11] now [40:12] and then update our deployment to use it [40:15] so this is really easy um [40:19] what needs to is it nginx or is it fpm [40:22] both [40:23] um fpm would be what requires it because [40:25] it's the php for every [40:26] process that's running yes okay so env [40:30] from fun effect map ref [40:36] uh [40:38] the name of the conflict map oh what did [40:41] they call it laravel [40:43] yep yep [40:46] uh does that just like basically [40:50] export inside of the image before it [40:52] deploys it [40:54] yes it will take all of these keys and [40:57] make them environment variables which is [40:58] how larval works i don't even need to [41:00] change anything [41:03] so let's reapply our deployment [41:08] so that would behave basically the exact [41:10] same way as [41:11] if you'd baked it into the image before [41:13] you deployed it at all [41:14] i guess it would just be a linux [41:18] environment [41:22] all right let's see how far we are now [41:27] the application key might not like that [41:28] i'm not sure okay [41:33] all right let's check our logs [41:36] yeah now that's one of the things i was [41:39] going to complain about next right is we [41:41] actually don't want to log to a fail in [41:42] any container environment [41:44] that is generally a full power and you [41:46] want to log the standard [41:48] out so first let's look at the logs [41:51] and then change that [41:55] so our problem is [42:01] it's trying to write to something then [42:02] we have a read-only fail system [42:04] what's it trying to write to [42:08] um oh it caches your views [42:11] so framework views is like um [42:14] it's a cash thing because it comes with [42:17] something called blade [42:18] which is a template language like twig [42:21] that sort of style of um [42:23] that sort of style thing so it tries to [42:24] write those two [42:26] problems yes and if everything is always [42:31] but that's just this framework folder [42:32] right yeah [42:36] yeah assume that all of those have been [42:38] trying to do it into sessions cache [42:40] they're not testing these as you when [42:41] you want tests and also views [42:44] okay so that's all empty so what i'm [42:46] going to do is empty there that too [42:52] i want to try and keep this as a [42:53] read-only file system for as long as [42:55] possible before i admit defeat [42:58] so we'll bring in this cache and we're [43:01] going to mount that [43:04] so would you normally have like a [43:07] attempter sort of thing that could be [43:09] written to for [43:11] say if somebody was to upload a file [43:13] that needed processing before getting [43:14] moved on to like s3 would you have like [43:16] attempter [43:17] configured which is wrapped up and only [43:18] that [43:20] yes so i would definitely use the [43:22] volumes key up here to provide something [43:24] that was ephemeral now i would use an [43:26] empty dirt definitely for [43:28] like a local kubernetes environment and [43:30] some production environments [43:31] i may like if i need to guarantee that [43:34] file exists after a pod restart i'd [43:36] probably use like a [43:37] persistent volume or a host path [43:39] depending on how my cluster is [43:40] configured but [43:41] i would use a volume of some kind for [43:43] anything that needs right access [43:45] the reason being is like you know most [43:48] attacks especially against [43:49] uh php based content management systems [43:52] is generally through [43:53] some really contrived and illegal upload [43:56] that executes an arbitrary script and [43:57] then rewrites over your code [44:00] and you could just you know just one [44:01] read-only file system argument [44:04] just stops all that as long as you don't [44:06] mind going through the process [44:08] uh of making sure you could write to [44:10] your logs in your cache [44:11] which i'm going to try and do now so [44:14] let's try uh redeploy [44:18] let's get our pods oh and let's change [44:20] the login to standard out like we don't [44:21] want to log to file anyway we want to be [44:23] able to use the logs command [44:25] so how do i configure that with laravel [44:28] um [44:28] change the env to sdd err [44:32] [Music] [44:34] so what am i changing change stuck there [44:36] to std [44:37] er [44:40] is that correct okay [44:44] yeah yeah that'll do it [44:49] um there's also actually a standard out [44:51] right [44:52] yeah that just send it straight to [44:53] something okay let's do that [44:56] uh let's reapply [44:59] and make sure i'm in the position that i [45:01] kind of want to be in so uh [45:04] yeah that's the conflict map i need to [45:05] deploy [45:08] and then i'll need to delete the pod to [45:10] get that new configuration [45:17] so now i should be able to run logs [45:20] against this [45:23] and i have the fpm logs you know if you [45:26] hit the [45:29] uh browser you should see something [45:30] locked i think because i don't think [45:32] we've fixed the error that we have [45:33] before did we [45:35] uh i hope so uh let me run the port [45:38] forward from another location [45:40] we can keep our logs up oh it's going to [45:44] split my terminal but i think that's [45:45] just going to make it more confusing [45:48] all right so there is our logs [45:57] well something's logging perhaps [46:08] configuration is obviously not quite as [46:11] simple as that [46:13] i'm assuming that we're still going to [46:15] have something in that [46:17] storage logs [46:26] yep [46:30] this is cat so [46:33] what field [46:36] on car and valley [46:40] um i'm i don't go to create logger [46:44] standard out is not defined just oh so [46:47] i trusted you so you're an option [46:51] okay now [46:56] if you open up the code in conflicts [46:58] like i would expect it to be [46:59] dev standard though like that um [47:06] let's google that's what it's here for [47:08] right so log [47:09] to standard [47:25] and there's another option which we can [47:26] just use error log which will put it in [47:28] the [47:29] fpm log by default and that should put [47:31] it into the standard [47:32] log first [47:36] all right what we have already should [47:50] work [47:52] no that won't work because um [47:56] it's being passed through to monologue [47:57] the um php [48:00] body library [48:04] let's see [48:12] okay fpm [48:25] yeah we're gonna have to add the service [48:26] so i don't have to keep doing that but [48:28] let's do it more time for now [48:41] all right let's go back in [48:49] uh fpm [48:51] [Music] [48:53] storage logs cat lock [48:58] did that field to set up please provide [49:00] a valid cache path [49:06] uh unable to create configured bloggers [49:08] is this because of the empty dev but you [49:10] create a framework i think it expects [49:12] for the cache form to exist you might [49:13] need to create multiple empty first [49:16] i don't think it might not create that [49:17] folder okay [49:19] i'm also worried about this logo yeah no [49:22] that's definitely an issue [49:23] um so unable to create complete logo [49:26] would to me [49:31] i'll leave that as an exercise for [49:32] another day set up logging um rather [49:34] than [49:35] if you drink it up to syslog you just [49:38] try that one last [49:38] uh one last thing because i should put [49:40] it straight through as well would it not [49:42] no syslog may look for syslog in the [49:44] container which won't exist [49:47] oh okay all right let's ignore it [49:50] um [49:55] and let's do [50:00] cash and we're going to need sessions [50:07] and again i don't really want to spend [50:09] too much time fighting on things that [50:10] aren't that important so i can always [50:12] just disable that if this doesn't work [50:13] is there anything else required in the [50:15] framework directory [50:17] um views views [50:23] i think there's one called testing as [50:24] well with measurement i don't know what [50:25] testing [50:26] is [50:31] do i have them here uh storage [50:35] framework cache sessions testing tools [50:38] right okay [50:42] i mean i haven't just expected to create [50:44] them if they're not there [50:45] i find that i i do as well but that's [50:48] all i can [50:49] and okay modifier deployment [50:55] oh yeah i've got to actually add them [51:06] so we need testing [51:10] sessions fears [51:16] all right take 16. [51:22] well we're not going to get any logs [51:23] okay so [51:25] let's just fix the port forward [51:38] right that's progress we're not getting [51:40] a white screen anymore [51:42] so let's see what we are [51:46] fpm ash storage logs [51:49] cat log so now it's complaining [51:53] oh yeah so it doesn't like my i just put [51:55] a random string there what's that [51:57] supposed to be [51:58] um there's some sound commands hpr sound [52:00] key colon generate [52:02] um if you just run that inside of the [52:04] fpm container [52:06] that should um [52:11] key colon generate [52:22] it's trying to write it to env um i'll [52:25] create one locally and just send it here [52:28] can i not just print it out yeah [52:31] sure there we go okay okay cool nice [52:35] i hate it when tools are fighting [52:36] against me rather than [52:38] doing my bedding right okay [52:42] um um and i've never seen it with [52:45] basically [52:48] well maybe that's just a helper [52:54] all right uh let's just apply the whole [52:56] directory for a bit of quickness [52:58] make sure our pods rotate [53:02] oh i only changed the config map so i [53:03] need to delete my pods myself [53:10] and now we can report forward again [53:18] and finally i'm really hoping we see a [53:20] database migration letter here [53:24] oh our application the reason why you're [53:27] getting that works because we're not [53:28] requiring any databases [53:30] at the moment but that is proving that [53:32] the asset compilation works as well [53:33] because [53:34] that's using um terawin to get the data [53:37] there [53:38] all right it's production now i'll see [53:40] you there thanks [53:45] um so that's actually covered one of the [53:46] things on the list anyway though that's [53:48] the [53:48] secrets and environment stuff there is [53:51] some [53:51] thing on my list which has happened a [53:53] few times whilst you've been doing that [53:54] which [53:56] i assume it's not the right way of doing [53:57] it you've just been deleting pods [53:59] to get it to basically redeploy [54:04] um probably a better way doing it than [54:07] that i assume [54:09] unfortunately not so that the problem is [54:11] is that [54:13] when you modify a conflict map it gets [54:14] updated in real time [54:16] pretty much within your deployment um [54:20] so like the files will just be synced if [54:22] there's a fail mount i think the [54:23] environment variables [54:25] i think they still update in real time i [54:27] can confirm but i'm not 100 confident [54:29] your application is really expected to [54:30] notice those changes and reload [54:32] uh but most applications don't and one [54:35] of the ways to get around it [54:36] is to include the sha of the conflict [54:39] map [54:40] as an annotation on your deployment [54:41] which forces a reload every time [54:43] you modify the config map it's a bit [54:45] hacky [54:46] and there are some controllers that can [54:48] also run inside the cluster that monitor [54:49] for changes in the contact map and [54:51] rotate your pods for you [54:53] so there's a few ways to do it but [54:55] honestly for like this kind of [54:57] environment [54:57] the lean is the right way to do it [55:00] however something you said that we [55:01] tackled that we haven't was secrets [55:03] um i wouldn't put a secret in this file [55:07] so let's fix that let's take out this [55:09] app key [55:11] and let's create a secret channel [55:14] i know and this is really gonna it's [55:17] gonna feel weird [55:18] because [55:21] i'm solving one problem in a very [55:24] similar way to the conflict map anyway [55:26] and i'll try and do my best to explain [55:27] why this is [55:28] uh more why this is better [55:32] so [55:37] so this is a secret [55:41] i am storing this as ammo and my [55:43] repository right now so it is no more [55:45] secret than a config map [55:47] granted however you're very you're [55:50] unlikely to apply your [55:52] secrets to your cluster in this way um [55:54] you may be using vol [55:55] or some other kms system to provide [55:58] these as [55:59] and to get these into your cluster but [56:01] you want them to be a secret inside of [56:03] your cluster because they have different [56:04] r back [56:05] rules compared to a config map right as [56:07] generally config maps have [56:09] loose airbag most people can have access [56:12] to them [56:12] they're also consumable from within the [56:14] pods you want to be able to lock [56:16] that down and you want to be able to [56:17] lock the pods down as well so that [56:18] nobody can execute into it and just grab [56:20] the secret [56:21] um so well from a very [56:24] naive perspective and look at it and i [56:26] use the wrong word from a very [56:28] well from this example it doesn't seem [56:30] like we're improving the security at all [56:31] just by using the secrets [56:33] you are as long as you get them into the [56:34] environment correctly [56:36] the other thing i want to kind of cover [56:37] is that uh well first [56:39] little fail um there's two keys on a [56:42] secret [56:45] string data and data and and [56:49] actually expects your data to be base64 [56:52] encoded [56:53] so if i do base64 paste this [56:56] in and grab this [57:02] in fact that's not going to work because [57:03] of the new line [57:05] so let me just copy that properly [57:09] and we should actually have done like [57:11] echo dash [57:13] and which means no new line right [57:16] yeah and then base 64 and this will get [57:19] its agile value [57:25] so both of these are correct so when i [57:28] apply [57:28] and in fact let's just change this so [57:31] we'll call this string key instead of [57:33] that key [57:33] i can't remember if the kubernetes [57:35] control plane will allow me to have data [57:37] and string data but we're going to push [57:38] our look and see what happens [57:40] so yeah it doesn't care [57:43] cool now we should actually see that [57:45] both these values are the same [57:48] um so we'll grab our ladder bell dash oh [57:52] yamaha [57:54] i think it's built secret [57:59] and if we look at the data fields yeah [58:02] you see we actually get the same value [58:03] here [58:04] so string data is a helper that when you [58:06] apply something to the cluster [58:08] it knows that you haven't base64 encoded [58:10] it yet and it will base64 encode it for [58:12] you [58:13] regardless you get the same value at the [58:15] other end so string data [58:16] a helper good in some environments uh [58:20] data base64 encoded not a secret [58:23] but again you wouldn't apply secrets [58:25] typically in this fashion [58:27] for production use cases you would use [58:29] like sops fry mozilla [58:32] uh sealed secrets are my personal [58:35] favorite the capitan [58:37] project um so these all handle it [58:39] slightly differently [58:40] um sops and sealed secrets will use well [58:43] in fact they all they'll do the same way [58:44] they'll encrypt stuff but the way that [58:46] you interact with the tool is slightly [58:47] different [58:48] um i don't know if there's gonna be like [58:51] a quick thingy here [58:57] no because we don't have a kubernetes [58:59] specific thing it doesn't matter [59:01] so sops allows you to encrypt it and [59:02] store the encrypted file within get [59:04] which means you can apply it you just [59:06] have to remember your continuous [59:07] integration pipeline to [59:09] to decrypt it before you do the the [59:10] apply and there are some things that can [59:13] run in a cluster to try and make that [59:14] easier and more secure [59:16] but it's a really good way of doing it [59:17] sealed secrets does the same [59:19] it stores a private key inside of your [59:21] kubernetes cluster [59:22] you can use the sealed secrets command [59:24] line to reach out encrypt a value [59:26] and you get a text-based secret like [59:29] this [59:29] with obviously an encrypted string which [59:32] is still secret [59:33] and then finally there's the capitan [59:35] project which [59:36] does secret management it hooks up to [59:38] all the kmscs and vault [59:39] so if you're already deploying to a [59:41] cloud provider with a kms this is [59:43] honestly this is just the best way to do [59:45] it and you can define them in your ammo [59:47] and they'll be [59:48] they'll be encrypted for you and only [59:49] decryptable and a cluster that has [59:51] access to that kms so you can use cloud [59:53] provider i am rules [59:55] i'm not going to say any more about it [59:56] because secrets would be deviating us [59:58] down a path [59:59] of a lot of time and i don't want to [60:00] take up too much of your time [60:02] and in fact we only have like 25 minutes [60:04] left so [60:06] let's see did that all make sense that [60:09] wasn't too much waffle [60:12] something kind of um with ansible where [60:14] you use that scoreboard [60:16] but that would have you'd have the [60:18] encrypted locally sorting gate and then [60:19] when you're trying to apply it [60:20] and try and deploy that you use you [60:22] provide your volt key which [60:24] is just the battery if you type in it [60:26] deployment time and decrypt it and send [60:28] the values over [60:30] something to kind of similar to what [60:31] sounds like um [60:37] and no surprises we pass our secret [60:40] through [60:41] in exactly the same way there are finer [60:43] grade controls you can mount in specific [60:45] keys [60:46] and make them optional change the names [60:48] within the container [60:49] there's a bunch of stuff you can do okay [60:52] um [60:53] let's make sure we haven't broken [60:54] anything [60:57] let's apply that whole directory [61:03] here's our new pod [61:06] port forward [61:09] and we should still see right okay [61:14] uh i can't believe we started off saying [61:16] let's run database migrations we're like [61:20] a fair chunk of our way through this we [61:22] haven't done it yet so let's actually [61:24] run these migrations now [61:25] so kubernetes expects us to leverage [61:28] something called an init container [61:30] and now if we go to our container [61:32] definition [61:35] here and we can just say edit containers [61:39] and we can provide it a name we'll call [61:41] this database [61:42] migrations and it takes pretty much that [61:45] same spec [61:46] that you're using um for in fact it is [61:49] the same spec for your containers [61:51] you're just trying to overwrite the [61:53] behavior in a way that makes sense for [61:55] you to run certain commands so [61:56] you know here i'm going to say run fpm [61:59] and the thing i want to change [62:01] is that i need access to [62:04] well i want to run a different command i [62:07] want to run [62:08] php and then i'm going to provide some [62:10] arcs [62:12] the arcs are going to be artisan [62:16] db is that right yeah just just migrate [62:21] just migrate so just php our design [62:23] migrate [62:25] yeah and then you'll also need to do um [62:27] double dash [62:28] false i think because it will by default [62:30] for a warning sign you're running this [62:32] in a production environment all right [62:38] let's just do it i'm feeling it an entry [62:41] point because it [62:42] that needs to enter at the bottom [62:44] kubernetes doesn't call it an entry [62:45] point so in kubernetes use same language [62:47] so it's command and args [62:49] whereas docker yes they would call it [62:52] what i mean is um for the file path of [62:56] where you're running php [62:57] from uh do you know because [63:01] every time i've exec into that container [63:03] you've put me into the working door [63:04] which seems to be the correct location [63:07] okay if i might just set up properly [63:08] that is pure coincidence [63:10] yeah and your docker file let me just [63:13] because you haven't done it for nginx [63:14] but you have done it for um for fpm [63:17] so yeah that's yeah yeah okay yeah you [63:20] would want that in your [63:21] next one as well uh now i forgot to set [63:23] the image pull policy to never which is [63:25] why that's failing [63:26] so let's top that up [63:30] so you'd only have it never in because [63:33] you're doing this locally if i was doing [63:34] this on a production you get rid of all [63:36] of the nethers and [63:37] the actual path of the image would be [63:42] private.com yeah you always include the [63:45] container registry [63:46] i like to run my own registry within my [63:48] clusters the caches the images i [63:50] generally use a pool policy [63:52] if you know if it's not available if [63:54] it's not present on [63:56] on the machine i don't do an always pull [63:58] generally because i do [64:00] i don't use ephemeral tags like [64:02] lyricists and such that you know i would [64:03] use a proper [64:04] um content [64:08] all right let's see why this is failing [64:10] i'm assuming that the migrate command is [64:12] trying to rate to a fail [64:14] probably and that my we're going to have [64:17] to sacrifice my read-only fail system [64:19] but [64:19] let's i don't believe it does write any [64:21] files [64:22] all right so we want the logs for the [64:24] database migrations [64:26] we're getting connection refused okay [64:29] so did you [64:32] create i didn't give it the environment [64:34] variables [64:38] so we need this to be copied [64:41] to here [64:44] let's reapply [64:48] and see what we got [64:53] it worked [64:56] you don't seem convinced uh [64:59] i typically check the database to make [65:01] sure my breaking work [65:03] all right so let's scrap this let's just [65:06] see [65:07] database migrations [65:11] um yep there we go no okay [65:15] is there an endpoint in your laravel [65:17] application that will allow us to [65:19] consume that database at all yep so [65:22] i've created a few endpoints one of them [65:24] is called create dash [65:26] posts and that will create just five um [65:29] by posting the various [65:34] create slash post or dashboard [65:37] all right like so uh yep [65:40] i know that's a little difficult to read [65:42] but so that should have done it [65:44] i didn't give any up or don't we thought [65:46] i'd be in white that's right kind of [65:47] get posts that is a geckos oh no no [65:51] sorry um now if you go to slash posts [65:56] there you go but yeah yeah [65:59] great awesome so migrations is working [66:02] yeah really simple i mean any containers [66:05] they are the best way to handle this [66:06] thing of course there are caveats i'm [66:08] not going to say go and add this to all [66:09] applications immediately [66:11] they need to be an important you have to [66:14] be able to run them these will [66:15] like in fact let's show that when i [66:17] scale this up to five [66:19] those migrations are going to run on [66:20] every deployment every time i kill a pod [66:22] so you really need to make sure [66:24] that they don't collide [66:27] there's locking you know you're going to [66:29] potentially have two running very close [66:30] to each other and they have to be out [66:32] important [66:34] so i'm assuming with the orm that [66:37] laravel is using that you get all that [66:38] for free [66:39] most orms do provide something like that [66:41] so you should be good [66:43] i'm not sure about issues so because [66:45] they are quite [66:46] good on like um [66:49] the whole like high availability side of [66:51] things so i'd assume that that's [66:53] important [66:53] i would assume your migrate commander [66:55] does a lot on the entire database [66:57] and in fact we could probably trigger [66:59] that by you know [67:01] deleting the database spinning it back [67:02] up empty running a migrate and trying to [67:04] hit [67:04] create posts at the same time or get [67:06] posted at the same time we'd probably [67:07] see it wait for a while before it got [67:09] access to the table again oh the [67:10] database [67:11] okay what's next on your list what we've [67:13] got uh 20 minutes [67:15] so q jobs is probably the big one huge [67:18] schedule address [67:20] all right so kubernetes exposes a [67:22] primitive [67:24] called jobs and which are just like [67:26] crunch ups [67:30] uh i don't think i'm going to be able to [67:32] oh i do [67:33] i love this plugin so [67:36] we have you know just like all other [67:38] kubernetes manifest really simple [67:39] specification [67:41] and we can specify this is the time to [67:43] second [67:44] time to live seconds after finished who [67:46] knows where that is to have help [67:49] uh late time job is finished execution [67:52] yeah whatever okay [67:53] we specify the container and we specify [67:55] the command now [67:57] you'll also want to be able to tweak [67:58] awareness runs [68:00] and i'm using the wrong object [68:07] crown job [68:11] i'm going to show my own ignorance i've [68:13] never been able to remember how this [68:14] works now [68:20] kubernetes i spent a lot of my time in [68:22] documentation [68:25] there we go there is a thing called cron [68:26] jobs yeah i just couldn't remember what [68:28] this [68:29] was because i've seen like online but [68:33] all right some things just refer to v1 [68:37] and some things referred to like [68:38] something documented.b1 yeah [68:41] um i'm not sure why that yelled at me [68:44] then maybe it's because the spec was [68:45] wrong [68:47] or maybe never maybe that's not been [68:49] promoted yet actually [68:51] so yeah okay [68:54] um it's not crown jobs haven't had a v1 [68:56] yet but jobs have so [68:58] there we go let's just copy the whole [69:01] thing and modify it or [69:02] to do our bidding so we'll call this [69:04] ladderville i'm just going to keep [69:06] calling everything maribel [69:07] we can use regular cron cell syntax to [69:09] specify the job [69:11] um i don't know how to generate that [69:13] most of the time [69:17] yeah crowdmaker i think this is the one [69:19] i use [69:21] let's just say run every five minutes [69:31] uh why wouldn't you just do um style [69:35] i have because you wanted to run every [69:36] minute [69:38] at the crown helper in the laravel [69:42] um then inside and inside of the [69:46] console kernel determines what jobs [69:48] inside of there should run [69:50] and what frequency so you would run this [69:52] every minute [69:54] okay so i guess i don't understand i've [69:56] never built a laravel application so [69:58] let's try and cover a few basic [69:59] questions then [70:00] um now is the queue processor [70:04] a long-running process that should be [70:06] deployed as an employment or [70:07] is it actually a cron job that runs [70:09] regularly uh sorry so it depends [70:11] are we dealing with a huge job here [70:12] where we're dealing with the scheduled [70:14] tasks because there's two things that [70:16] need covering anyway [70:18] uh okay so i'm assuming the schedule [70:19] tasks the chrome job right [70:21] yes okay so you can give it to the star [70:23] star star star star [70:24] just straight up every minute and then [70:28] all you do is you have like the migrate [70:30] command you have one entry point which [70:31] is just [70:32] a schedule call on run [70:40] yeah schedule call on run um once you've [70:44] done that [70:45] every minute it just deals with itself [70:46] based on your hp [70:52] okay so we call this scheduled [70:56] uses the same fbm image what command are [70:58] we running [70:59] um schedule call on run [71:03] is that all uh let me just check if [71:06] there's some forces [71:13] all right let's apply it so [71:17] air jobs and then like all the other [71:20] kubernetes resources we type get jobs oh [71:26] not a crown job [71:27] i called it a job yeah here we go [71:30] and we can wait uh let's within a minute [71:34] we should see a pod get scheduled [71:35] which will spin up run that command shut [71:37] that down and then that'll look every [71:39] minute doing the same thing [71:41] and by pure coincidence we're about to [71:43] hit quarter past [71:45] and i've got a job in there but every [71:46] five minutes sends an email [71:48] so we should see you know just [71:51] pure for instance on that but [72:00] [Music] [72:08] so oh it crashed [72:11] i don't know is it trying to rate her [72:14] fail [72:16] um it will be won't it i don't think it [72:19] should write [72:21] uh all right let's see unless it ends up [72:23] maybe it writes like a cache file thing [72:25] oh no could not open input failed [72:27] schedule run what have i got wrong [72:29] oh you can give it a second [72:47] we actually had a few comments there as [72:49] well which we were too busy focused on [72:51] that so [72:52] uh frank and nate both commented that we [72:55] missed the artisan [72:56] thank you uh [73:01] so that's that archive it i don't know [73:03] if i applied that because [73:05] i i got really confused when you [73:07] disappeared and then realized the [73:08] software crashed so [73:09] yes these things reconnect and stuff [73:14] so it says unchanged [73:18] there we go so we this is now completing [73:20] every minute [73:21] we've had two of them since the crash [73:24] obviously this one failed [73:25] um so do we not want that to kill itself [73:28] off immediately [73:29] as soon as it's got the exit and there's [73:32] no need for a time to life on that is [73:34] that because [73:34] it's never going to reuse the same [73:35] command again [73:38] we'll leave it for now i don't think [73:39] it's terribly important [73:42] um will they clean themselves up once [73:44] the ttl gets hit i guess [73:48] yeah did that just crash again oh that's [73:51] that's just a broken one so i can just [73:52] delete that [73:56] because would that not mean that every [73:58] minute a new pod is created and that [74:00] isn't being cleared out [74:02] so eventually we're just running out of [74:03] memories [74:05] no these ones are gone they're completed [74:07] so they don't take up any resources [74:08] anymore [74:09] so okay so that seems okay [74:14] uh i guess if we wait another two [74:15] minutes we should see [74:17] the email come in here yeah [74:20] at 20 past um but you said there was one [74:22] other type of job so let's try and [74:24] handle that one then [74:26] yeah so this is the more um [74:30] i guess complicated one um what you can [74:33] have [74:33] in laravel is um huge jobs so you can [74:37] queue it up using both different queue [74:39] drivers [74:40] with ses and you can play database redis [74:42] rather mq all those sort of things [74:44] um but the way of using that is the same [74:47] so it doesn't make any difference to us [74:50] um what we want to do there is have a [74:54] command that's running [74:55] longer it's a long running process in [74:56] the background that [74:58] um runs the rsan q colon work [75:02] and that's all that we require [75:06] um but then it gets a bit more [75:07] complicated than that you can have [75:08] different named queues and have [75:10] different number of workers per cues and [75:12] things like that i guess [75:14] yeah that's just going to be a new [75:15] deployment for me i mean long-running [75:17] process means it's a deployment i want [75:19] to be able to scale up and down [75:20] depending on how many workers i want [75:22] as well as tweaking the parameters so [75:25] you know we could [75:26] i mean we probably would just copy this [75:29] uh and call it q [75:32] worker [75:36] and we're not going to need the nginx so [75:37] we can remove that [75:45] do we do you think we'll need logs cache [75:47] test i'm going to affect you know i'm [75:48] just going to keep it i don't want to [75:49] i think we'd need it all because the [75:51] framework would still hate those well [75:53] maybe not like views and stuff but [75:58] all right so we update our labels to be [76:00] q worker [76:03] worker and then we just modify the [76:05] command [76:06] we don't need our init container at all [76:12] and here we're just going to say [76:15] oh we don't specify the command we're [76:16] using the unbuilt one [76:18] so here we just say php again [76:22] we specify the args and we're going to [76:24] run sorry what was the command artisan [76:27] artisan and then q column work [76:32] cola yeah [76:35] and then you need to pass so that will [76:37] work by default [76:38] that will run the what's called uh all [76:41] the three queues in marbella named and [76:42] the default is just called default [76:44] but what you can do is you can then pass [76:46] through double dash queue equals [76:49] and give it a conceptual string of [76:50] different queues so you can [76:52] just default that and that from the [76:53] default one um so if you have different [76:56] higher my priority queues you can make [76:57] the high priority queue have ten workers [76:59] low priority you have [77:00] two workers yeah and that's [77:03] that exact reason is why i would use its [77:05] own deployment [77:07] for each of the different queue [77:08] semantics i've got so that i can really [77:09] define the quality of service and how [77:11] quickly i need to process [77:12] and how many workers and how many [77:13] replicas not all cues i would imagine [77:16] at least in applications i've written in [77:17] the past would be considered equal [77:19] and i'd want to be able to tweak that it [77:21] may seem like oh i'll just add a new pod [77:23] a new container to my main pod but [77:26] i don't think that would be necessarily [77:27] the right way to handle that [77:30] let's apply [77:35] where are we [77:38] cute workers right we now have five [77:40] queue markers can we [77:42] do we can we confirm that yes we can so [77:45] in the groups if you go to slash q [77:48] jobs it will should send three emails [77:52] oh first of all if we check the email [77:54] provider we should have an email from [77:55] the cron dropping there now [78:00] [Music] [78:10] jobs it should send [78:13] three more emails up here we go [78:17] we have our keyworkers easy peasy [78:20] um so there's something that you can [78:22] because php isn't really designed for [78:24] long running at least it was never [78:26] initially designed for long-running jobs [78:28] um it's kind of basically a sort of [78:32] hacky way of doing it [78:34] the key workers there at the moment and [78:36] so you can sometimes get remember the [78:37] issues with that [78:39] so reliable does provide something [78:40] called max jobs which is another flag in [78:42] your past which means that you'll kill [78:43] off that [78:44] that worker sends like an exit signal to [78:47] it after [78:48] x number of jobs if you were to do that [78:51] with [78:51] the container would that spin up a new [78:55] one which is what you'd expect [78:57] or would that then start like a whole [78:59] cascade of issues [79:02] yeah what i would use is the resource [79:04] limits here you know i've already [79:06] defined how much how many resources i'm [79:08] happy for these queue workers to consume [79:10] so like kubernetes is going to restart [79:12] it when it [79:12] when it starts to break these limits [79:14] anyway so you wouldn't really need to [79:17] hook into the laravel aspect there i [79:19] would just rely on the container [79:20] scheduling [79:21] to go hey i don't really want you [79:22] consuming 14 giga ram so i'm going to [79:24] restart you know [79:26] okay that's cool so that's his job [79:29] and what's the 500m that wasn't really [79:31] covered earlier i guess [79:32] it wasn't you so a single cpu is broken [79:36] down into 1000 units [79:38] and i think they're called millicourse [79:40] so you can say this is essentially me [79:42] saying that half a core [79:43] this this process is restricted to half [79:45] a core on the host machine [79:47] does that does that translate to roughly [79:50] like every one and two instructions [79:52] like so if there's two pods on there [79:55] both given half a core [79:56] they will like sort of alternate who can [79:59] get access [80:00] or is what is that just like no so it [80:03] depends on how many cores are available [80:04] on the machine [80:05] so like uh i'm not sure if i'm gonna be [80:07] able to get that information from [80:09] kubernetes here [80:10] in fact uh let's see how permissive our [80:14] thing is so [80:18] containers don't necessarily obscure the [80:20] view of the proc file system [80:22] and so typically you can just pop in [80:25] here [80:27] and you'll still see the actual host [80:28] information so you can see here i've got [80:30] eight processors which means [80:32] if i set this to [80:36] 4000 m [80:40] and scale this we've got it set on five [80:43] yeah we won't see all five of those [80:45] scheduled we should see that fail [80:47] so [80:53] yeah there we go we we have pending [80:56] queue workers [80:56] and if i describe one of those it'll [81:00] tell me [81:01] that the resources aren't available and [81:03] sufficient cpu [81:05] okay right so not it's not like [81:09] um how it allocates it so well it's [81:12] because we're using a limit right [81:13] i mean i could have said uh [81:18] requests which means i kind of want this [81:22] but it's not a hard request you know if [81:24] it's available give me it [81:25] and whereas a limit is like it's [81:27] actually going to set aside [81:28] half a quart for that process and it's [81:31] going to set aside 50 mega ram for that [81:33] process [81:33] and it won't allow me to schedule so [81:36] there's still contention [81:38] for any pods are running on the machine [81:40] they're still competing for resources [81:41] depending on the instructions they're [81:42] sending [81:43] but the scheduler is going to go i know [81:45] at some point this is going to have [81:48] 4 000 millicourse of cpu and i'm not [81:50] going to schedule anything that tries to [81:51] go beyond that [81:52] whereas if i leave this as requests we [81:55] should see [81:56] that it just i think it will actually [81:58] schedule most of them [82:01] because they're not using that menu at [82:03] that time [82:05] oh no ash okay so the schedule is gonna [82:07] say no as well all right [82:09] so but yeah the request is kind of [82:11] giving the scheduler a hint of what you [82:13] need [82:13] the limits means restart the process if [82:15] it ever goes beyond it [82:17] and then the scheduler will do its best [82:18] to make sure you get scheduled on the [82:20] nodes where it's not going to have too [82:21] much contention for those resources [82:23] okay yeah that makes sense okay that is [82:28] actually too bad everything apart from [82:31] one thing on my list [82:33] pretty much so what did we not cover [82:37] um release cycle so how would you might [82:40] go about doing a natural like [82:41] full-on release not necessarily with [82:43] like ci and stuff but you build a new [82:45] image it needs to be deployed [82:46] do you go in with cube ctl delete the [82:49] pubs [82:50] how would you want to make that last i [82:52] think no i mean it'll handle it for you [82:54] so let's assume [82:56] and we can do this in two minutes [82:59] so uh yeah let's use our q worker right [83:02] um so firstly let's just remove these [83:05] limits um [83:06] so we can get all five and let's change [83:08] the image let's say [83:09] instead of you know normally we would [83:10] change the tag here to be v [83:13] 54 or whatever right but what if i just [83:15] want to say deploy [83:16] engine x so the way that this works [83:19] is if i just deploy this and run this [83:22] really quickly [83:23] is it oh container errors [83:27] let's just take off all this stuff that [83:28] we don't need the security context is [83:30] why that's failing uh [83:34] and the command won't exist but there's [83:36] a whole lot of why that was failing [83:37] so uh [83:41] that's what i get for trying to do it [83:42] too quickly right okay that's [83:44] pretty generic so let's reapply that and [83:47] then run this [83:48] but what we're going to see is that and [83:51] it's [83:51] it's fast so it's difficult right but we [83:54] actually spun up [83:56] two new ones before shutting down the [83:57] first one then we spun up a third and [83:59] then we started scheduling two more [84:00] after that and then it starts [84:02] terminating [84:03] so on top of a deployment object you [84:05] actually have the ability to specify [84:07] the the strategy [84:11] and then we can have a type and a ruling [84:15] update [84:17] rolling update which allows us to [84:19] specify a search [84:21] or a max of unavailable so the [84:24] deployment already knows how to do [84:26] safe deploys with new images you have to [84:28] tell it to do the rolling update which [84:30] is [84:30] actually happens by default and you get [84:32] a max surge of [84:34] one i think um you can also use [84:37] percentages [84:38] so you could say that i want 25 of my [84:40] pods to be unavailable that means that [84:42] it will sacrifice let's assume sorry [84:45] lots of information [84:47] let's assume i have 10 pods running if i [84:49] have a max unavailable 25 [84:51] it's going to be able to shut down 25 of [84:53] those pods which is [84:54] two if it was 50 it would shut down five [84:57] and then it would spin up new ones [84:59] if we go with a surge approach what we [85:01] say is i have 10 [85:03] with a max surge of 50 i'll actually [85:04] schedule up to 15 [85:06] and then once five are healthy shut down [85:08] five and then spin up more [85:10] okay so in combination [85:13] will you use one or the other you can [85:15] only use one another so you can [85:17] let's let's double check right because [85:19] i've been wrong a few times a day anyway [85:20] but [85:22] oh it doesn't care okay i guess you can [85:24] use them both together i thought you [85:25] could only pick one so yeah here i could [85:27] say [85:27] i i always need at least 75 [85:30] to be running and i don't mind [85:32] scheduling over provisioning by 50 [85:34] and then the scheduler will work it all [85:35] out for you you don't need to worry [85:37] about it too much [85:38] okay okay so in terms of [85:41] um when when you do a release you'd [85:44] normally have [85:44] a um your deployment process your ci or [85:49] whatever would [85:50] tag a new version of the image and then [85:53] would you [85:54] do like a cube apply a cube ctl apply [85:58] and that would then start pulling in the [85:59] new images for you it's definitely how [86:01] i would start my you know my continuous [86:04] integration deployment server would [86:06] just reply over the top with that new [86:08] tag [86:09] or sha whatever i'm using and let [86:10] kubernetes head up from there and then [86:12] eventually you can start to look at [86:13] things like [86:14] you know get ops continuous deployment [86:16] from within the cluster [86:18] and get a little bit more sophisticated [86:19] doing progressive rollouts making sure [86:21] that [86:22] you know the metrics don't change for [86:23] the first 10 minutes at 10 [86:25] traffic and then scaling up we could do [86:27] a couple of more episodes than that i'm [86:29] not going to be able to do it justice [86:30] in like 10 seconds but yeah yeah you [86:33] could definitely start with a cube [86:34] control apply [86:35] and then take it from there okay that's [86:37] something all right [86:39] i think so yeah we covered it a lot so [86:42] what i'll suggest is i hope people find [86:44] this useful leave comments for anything [86:45] that you want us to tackle in a future [86:47] episode i'm sure alex would be happy to [86:48] join me [86:49] alex and i'll have our own conversations [86:51] and work out what else we can do in the [86:52] future we definitely [86:54] already got an idea above which you'll [86:55] probably hate me for so we'll cover that [86:57] outside of the screen all right well [87:00] thank you for joining me alex it was an [87:01] absolute pleasure i had fun doing that [87:03] i'll see you for the next one [87:04] goodbye everyone cheers [87:29] [Music] [87:39] you