All right. Good afternoon. So Lab 5 help. You've requested it. Here it is. We need help. Anyone want to start? Yep. OK, library, we went over all the different functions and what we're supposed to do. So first off, we did lecture 14 where we did the MMU simulator, where we essentially go back to it. So this is what's given to you and what we kind of did before setting up the page table so we can translate address A, B, C, 1, 2, 3. We can all see that, hopefully. So there are any questions about that before we start anything else because you should understand how that works first. So all good. We set up an L2 table. Make sure the index points to an L1. L1 points to L0. That has our actual mapping. That points to the data because we're using a three level page table here. So this is what it would look like just to set it all up that you don't have to do. This is just to set up L2 points to L1 points to L0 points to a valid entry that has, in this case, read, write, set. And then it sets the root page table, which is supposed to simulate that register that's used for the actual hardware MMU whenever it does a translation. This is just purely simulating it so you can get a chance to manage page tables yourself because the kernel does that and you're not allowed to do that. So we just simulate it in software. So this is simulating it changing what root page table the MMU uses because it just points to a single L2. So this points to an L2. And then whenever we do, so there's functions that are just used for testing that simulate actually writing to an address and reading from an address. So in this case, we write to a virtual address ABC because we set it up so that is actually a valid address. So we can see what we read to it. We can write to it. We can read to it to see that we actually wrote to it. And that's the default thing we're kind of given. So then the thing you could add is like, OK, well, let's test our fork copy. So what happens on a fork? Well, one thing that could happen on a fork is the new child has page tables that look exactly the same as the parents, but are completely independent in actual physical memory. So if the parent has an L1 or an L2 page table, I have an L2 page table. If it has a valid entry for index 0, I have a valid entry for index 0. And whatever index 0 points to that L1 page table, if it has a valid entry for index 5, I have a valid entry for index 5. And those L1 page tables are, again, completely independent. And same with the last step. So if it has a valid entry for index 188, I think ABC goes to. Then I have a valid index for ABC. And it points to another page that's a different physical page of memory. So if one process changes the value at that address, the other process doesn't see it, but it's valid. Because they're exact copies, they look exactly the same. So we're good with the kind of high level goal of the lab. So API functions that you will have to use and you will find useful. So there's this header file. It has everything that you don't have to use everything. So they're kind of organized here. All this MMU stuff is mostly used for testing. And this will be the only one you use. Because in the fork, you need to know what L2 table to copy. And it's just whatever it currently is. So I would use this to figure out which L2 page table I need to copy. And that would lead me to copy literally everything else. Aside from this, there are pages.  All you have is physical memory. So this is supposed to simulate all the pages. They're supposed to be physical pages. So if you ask for a new page, it will give you a new physical page. But of course, you're not managing the memory yourself. It's already done for you. But that gives you a new physical page. Free a page, just like new and free. If you want to deallocate something, well, you free it. And then you can use that page again for something else. You probably never even need to call this. This one's just used for testing to see how many pages you use just to sanity check. So if you do a copy, well, if there were, if you were doing the fork copy and copying everything, if there are four pages in use by the page table, well, if I do a copy of everything, then there should now be eight. Because I should have my own independent copy of it, and there should be eight pages now. This is git page table pointer. So these two are mostly used. You'll find useful when you're implementing the copy on right. So this will flatten up page. And essentially here, you give it a pointer to a page, and it will give you an index for it. And it will be, the first page will be index zero, and then it'll go up to how many pages there are, which is in here. So there's max pages. So you can keep track of the number of references to a page by just making an array, and then you can get an index. You can turn a page into an index. So if you want to count the number of references to a page, you can make an array of size max pages, and then use this function to get its index. And then this just does the opposite. If you give it an index, it'll give you a pointer to that page at the beginning of the page. So the page table ones, how they are all set up, our page table index, will, given a virtual address and then what level you want to access, it will give you the index at, it will give you that index for that level. So for this, let's go back to where is it, main. So if we did that for like A, B, C, D, or A, B, C, D, 1, 2, 3, well, if we split that between my L1, L2, L0, then let's go here, then it would look something like that. So if I give it the virtual address, A, B, C, 1, 2, 3, and ask for the index at 1, then it will spit out 5. If I ask for the index at 0, it'll spit out 188. If I ask it for the index at 2, it'll spit out 0. So that's a way to get that. And then this one will give you a PT entry and that will be a pointer to a page table entry. And a page table entry, remember, is that 8-byte thing and you don't know quite exactly where the data actually is in that. It's just 8-bytes and you have to use other functions to actually figure out the values because if you actually just print it out the number, it might not line up with what you expect, so you should use the other numbers. So this takes a page table, so a page and an index, and then it will just give you a pointer to that index. Basically, it's just doing an array access and giving you the pointer. This one will do those two things in one step, so if you give it a page table virtual address at its level, it will directly give you a page table index, so you don't have to go through the two-step process. It just uses one and then the other. And then these two things, ppn to page, will, given a ppn or a physical page number, it will just turn it into a page like a valid pointer to a page and it'll be aligned to a page. Basically, it's just going to shift everything over by 12 bits and make the offset zero. And then this will do the opposite. So given a page, it will convert that page to ppn number. And in this case, we're assuming like it's that risk five setup, so we're assuming a ppn is 44 bits, so it's a 64-bit number, but only the lower 44 bits are actually going to be used. And then all the rest of these functions take a page table entry and they let you play with the bits. So this one will set the valid bit to zero, given an entry which is just a pointer to a page table entry. This will set valid to one and this will return what valid is. So if I want to check if something's valid, I would call that if it returns zero, it's not valid. If it returns one, it is valid. And then the exact same thing for all the other permissions here. And then the last one is getting the ppn out of the entry because you're not quite sure where it is and the other ones to set it. And then after that, we just have our two forks. So any questions about that? OK, so let's start off a goal with the lab so we can start it a bit. And should I do this first? Yeah. So just to be clear with what we're doing, so we're kind of assuming that we're given a certain number of physical pages. So in this case, if I called these our physical pages, well, say my memory starts at byte zero, which is actually a valid address, and I have eight pages. Well, if I have eight pages, I could call them page zero, one, two, three, four, five, six, seven. And that page number I'm calling them, that's the ppn. That's just the physical page number. So if I broke it down into the address ranges because we're dealing with four kilobyte pages, page one will have valid addresses from zero to zero FFF. Then page one, one zero zero zero to one FFF, which is hopefully 4,096 bytes, so on and so forth. So any questions about those pages whatsoever? So our page table entry, what it contains, it's just a number, it's eight bytes, and it contains, what, five things. The ppn, which is 44 bits, which you don't know where it is in that 64-bit number, so that's why you have to use the helper functions. And then there's a custom bit that you can set at will, which you'll find useful for when you do copy on write. And then there's read write, which are actually checked when you do that VMS write or read. So it actually checks that permission to make sure you have it. Otherwise, it generates a page fault, which you can optionally handle. And I guess we can see that. And then a valid bit, so to say that this entry is valid. And for new page and everything, by default, they're all zero initialized, so everything is completely invalid. So any questions about that? Yeah. So the read and write bits, so if you're actually accessing memory, like from your L0 table, if you're trying to read to that, the MMU will check that it actually has read permission, so it's actually allowed to read. So if I tried to do here, let's go back to. So yeah, we can just do it here. So first thing I do is write. Well, here I set permissions on that page with what I'm allowed to do. So if I do something like this, where I just don't set it, by default, it will be zero. And if I do that, I'll say fatal page fault, because you tried to access ABC123. And it gives you some more information, like where the page table is. It'll say level zero, so the last access. And this is the page table entry itself. It's pointing to this page, which is valid. That's fine. And these are the flags. So read, it's read and valid, so write isn't valid. And I tried to write to it. Yeah, so that stuff's actually checked by the MMU. OK, any other questions? OK, well, I guess we can start looking at it more. All right, so let's get started with, wow, please close, with fork. So if I were to start fork from scratch, well, we don't want to return just the root page table, because that's essentially doing nothing. And you're making both processes share the same L1 page table. So if one changes memory, the other will change it. They'll see it. Nothing is independent anymore. That's really, really bad. So we want to use the parent one to copy from. So that's what's given by the new page table. So we can just name it better if we want. So that's the parent's L2 page table. So we want to create a copy. So if we want to create a copy, we can call it childL2. So here, we know we need to get a new page, because we want to make them completely independent. So we need a new page. So we would need something. So we need a new page. And right now, that new page is 0. So if we do something silly, like just return it, well, then it should generate a page fault because it has 0 valid entries. So let's go into main. So here, I just added a call to it at the end. So we can just play with it and test it. So if I go ahead and do this, so that should create a new L2 page table. And then if you're testing it to simulate context switching processes and actually swapping the address space, we would do something like the testing code you're given does something like VMS. Set a root page table. And we would set that to the child. Oops, child. Wow, why my root page table? So we would do something like that. So now, whenever we access memory, it's going to use the MMU, or the simulated MMU, is going to use the new page tables we gave it. So now, if we do something like, I don't know, let's try and write a 3 to that address. So if we do something like that, so we'll get a fatal page fault. And it'll say, hey, you're trying to write to this address. This is the page table. So that was the one we got from the new page. And it says it failed when it was trying to do the level 2 entry. So that was the first step it made. And saying our page table entry, well, it said that it points to the physical page number 0, which is not valid, because that's like a null pointer. So it's not actually mapped in your process. And there are no flags. It's not valid. It's not anything. So there's no way it could work. All right, everyone good? Questions about that at all? OK, well, I am not going to do this for you, but I will listen. So in this function, if I want to see all of the valid entries in the parent's L2 page table, how would I do that? Yeah, so I can do a for loop of all the entries and just check them out. So there's going to be 0, or we do a for loop. i starts at 0. It's indexed. And then i is less than. We have num pte entries, because there's a certain number of entries per page. There are all the pte entries fit on a page. It's already defined for you, but we've done this calculation like 1,000 times. So this would be 512, but it's given to you, so you don't even need to know that. So we could loop over every single pte entry. So the function we have to do that to get an entry is this one. So we could just get an entry from an index if we want to check it out, because we don't have a virtual address. We're just looking over the page table and just seeing what it has. So we would use this guy. And our page table we're looking at is the parent's L2, because that's currently what we want to copy from, and our index. So now every time, we will have a pointer to a pte entry, and then we can ask questions about it. So if we don't ask questions to it about it, I did a little helper function here that will just print the pte entry. So we can see. So what do we expect to happen if we actually run that now? So the comment was we set the read flags initially to 1 for all of them. So this is the parent's table here. So it's L2. It got an entry for whatever this virtual address is, and then set the physical page number to point to an L1 page table, and then we set the valid bit. So how many entries are in my L2 page table? 1. And I'm printing out 512 entries here. So I should probably expect 1 to be valid, and the rest to all be 0. So let's go ahead and Sandy check ourselves. So if I do that, yeah, there's a lot of 0s, a lot of 0s, a lot of 0s, and then at the very top, hey, there's a valid one, because the first index it uses was 0 in this case. So it's actually pointing to the L1 page table, and it's valid. So it would actually follow that it wouldn't generate a page fault immediately. Cool. So do, do, do. All right, so what would I do if I just didn't want to print all of the stupid entries that are not valid? Yeah. Yeah, just check. If it's valid, I can do something like if not VMS was a PTE valid, and then surprisingly, it takes an entry. So I can do something like this. So if it's not valid, I can go ahead and ignore it. So if I want to just skip anything that's invalid, because I don't have to do anything. If it's invalid, it doesn't lead anywhere. I wouldn't have to copy a page. I wouldn't have to do anything like that. So if I do that, whoops, yeah. So up here, I still have some other codes. So up here, it just prints one page table entry because I only have one valid entry now. All right, anywhere else I should go with this? Yeah, yeah, yeah. So here, we can kind of pseudocoder steps here. So if there is a valid entry here, well, so if I'm looking at L2 entries and I find a valid one, it means it points to an L1 entry. And there's not going to be any tricky things where two L2 entries points to the same L1 because that would be weird and make your lives harder. And that's not the purpose of this. So if it's actually valid, then it points to an L1 entry and yeah, we would have to make a new one because we want our own copy of that. So I need to make a new L1 and then I would point to it for this entry. And then I'd have to go through and then essentially do the same thing for L1. Any valid entries in L1 while they point to an L0, I have to make a new page for that, each one of those. Copy it, make sure it points to that. Copy, make sure the permissions are the same. In this case, it just needs to be valid. So not a big deal. And then when we get to the end, the L0 points to a natural page. We'd want to probably copy all the permissions and then make it point to a new page so that they're completely independent now. So yeah, the comment is three nested four loops. You could do that. I would suggest not doing that. Essentially, it'd probably be a bit cleaner if it was recursive. And you just change the level. The only thing that's different between them is the level, right? So your base case is 0. At 0, I know I'm pointing to actual physical memory. So you could probably do a recursive thing for this. You could do three, four loops, I guess, be really kind of ugly. And you'd be repeating yourself a lot. But I guess you could do that, which why would you need to do that? Yeah, so with the banks in we did to actually using threads for that makes it go slower. If I didn't, there's one thing that artificially slows it down, but these operations are so fast. The overhead of threads is too much. And there's data races and stuff. So by the time you prevent everything, it's just way slower than just running on a single CPU. Yeah. So here, let's go to this. So for ABC123, how it's kind of set up is that, well, it just grabs a page. It says, OK, I'll use page 0. Let's see. I'll use this for the parents L2. So it would grab that, make an entry for 0. And the ppn would point to an L1. And it would probably have a valid bit set. So the ppn would probably point to another one. This would be given as the L1 page table. It would have an entry for 5. ppn valid 1 points to another one. Maybe I use this page for L0. It has an entry for 180, whatever. And then this one actually matters for read, write, and all the permissions. So it would point to the actual page. We had write on, read on, valid on, something like that. And then our data is stored there. So if we actually tried to access ABC123, well, we would go whatever 123 bits in Texas into this page. And then there'd be four bytes there that we're going to treat as an int. All this does is just write ints to it. So if we write a value of 1 there, it would just be in there. So what you should do is when you do a fork and you're just doing the first copy one, well, you're making a new L2 page table. It should probably have an entry for 0 that points to a different one. L1 has that same entry, points to a new L0. And then you're saying that, well, why don't we keep all the permissions the same here or no valid? And the ppn we point here. OK, so if we do do that, say we are doing, so this would be in blue is the child, red is the parent. So right now, they point to the same data. And if the parent changes the value of, say, we called it x or whatever, so changed x after the fork from 1 to 2, then if we change back to the child, what's the value of x? 2, which is that what we want? No. So we need to do another copy here. So the only way this works is if we rewind and remember fork is supposed to be exact copies at the time of the fork. So whoops. So I would have to, if the value is 1 at the time of the fork, I have to copy all the data that is on this and put it here and then point to it. So now if I try and change the value of x in the parent, it changes its value of x. If I try to change it in the child, it changes my value of x. But where you actually start sharing the page, what you suggest is when you do copy on right. So that's the idea behind copy on right. So I try and share the page as long as I can, because if they're both reading, I don't have to actually make that physical copy of the page. I can just share it as long as they're both reading. I'm all good. And I delay the right to try and, yeah, I delay the right as long as possible. So now if one of them tries to do a right, the idea behind that is, well, when you actually make the copy, so what kind of what we alluded to in lecture, when I make the copy, well, I can do something like this and just set the right bit as zero. So now if either one of them tries to write to that page, it is going to go and generate a page fault. So go here. So it will generate a page fault and you are allowed to do things here. So it will, you can modify PTA entries here, you can allocate new pages, you can do whatever you want here. And whenever you return from the page fault handler, the MMU will retry the request once. And succeed. So at a really high level, so you'll get into the details of why you need that custom bit set. So your tools are, you have a custom bit and you can keep track of the number of references to a page. But basically what you would want to do is change that right permission to zero. Whenever a page fault happens in either the processes because either the parents can write that generates the page fault or the child, you don't know, you don't really care. You'll just be, the only page table you'll be able to modify is the one that currently generated the page fault. So let's just, for argument's sake, say the child did it. So the child tried to write, it generated a page fault and it wasn't allowed to write. So I have to make it allowed to write but I want to do it safely. So in the page fault handler, that's when you would stop pointing to this. You would get a new page, copy all the data. I guess you don't really have to copy the one you're about to modify but that would be a pain in the butt. So then you copy the page, you change where the PTE entry points to. So it points to its own new page and then you turn the right permission back on. And then whenever the MMU retries it, it can actually write to it and it's a different page. Yep. So the question is, can I go to the other page table and turn the right on as well? And yeah, that gets to be the trick of it because you won't. So whatever the page fault that gets generated is only for whatever, however it currently got there. So you'll have no way of knowing what other ones point to it unless you do like some really tricky stuff that you don't need to do that. So yeah, so my suggestion is to keep track of the number of references to a page to know whether or not you should do anything. So if there's only one reference to a page, you have a unique one. So here you wouldn't be able to modify it so its right permission would still be off. So one thing you wanna be careful of is if I write through the parent now, if I switch back to the parent and then I try and do it right to that address again, well, it's the only one pointing to that page now even though it doesn't have right permission because it got turned off before. Well, now it's the only one pointing to it so I can just actually turn the right permission back on and I don't have to do anything. So that's one of the tricks, yeah. Yeah, so the question is, does the copy on write just apply to the data pages or apply to the other page tables as well? So copy on write only applies to the data pages because if you actually shared page tables, then if you allocate new memory in one process, then another memory, the other process has it too, which would be weird. So it'd be a bit weird if you're running your program and then just new memories available that got mallocked by another process that's supposed to be independent and a whole bunch of other weird things can happen with that. So yeah, if they shared page tables too, not in this, but you could just, if you wanted to screw with another process and that was true, you could just free all your pages and then it's freed for them too so they crash immediately. Yeah, a page, so remember I said one thing you can do using, what is it? So using, what are the pages? Using this, whoops, that's my bad. So using this to get index from a page, I said one thing you can do is just create an array of the number of references to a page because there are max pages and it's supposed to represent physical memory so it's not gonna ever change. Like you don't just shove more RAM in your machine and you can use it, at least. Yeah, you have to reboot to use more memory. So you can just create an array that keeps track of the number of references to each pointer and then if you wanna turn it to an index, then you can use this. Yeah, as long as it's safe to do so, you copy the page, doesn't matter who started it. So the question is, like whenever I, wait, am I on this? Okay, so it was whenever I had this entry and then got the entry, it was all 000. That was your question? Yeah, here? So yeah, so when I do new page, it just returns the base pointer to the start of a page and it's all full of zeros. So it's just 4,996 bytes of zero which since valid being zero means it's invalid, they're all invalid entries. Yeah. Yeah, so you can do other things. So yeah, I guess you could do three, four loops unless if you really want, you might be repeating yourself a bunch. And then when you do copy and write, you do another three, four loops. Eh, you can probably do better than that but I guess I'm not your parents. Yeah, you could also just, instead of doing that, if you don't like the recursive solution, instead of doing like three, four loops, just how about doing two? So what about one for the, what level you're on and then one for the entries? So that would probably be a bit better. Also, I mean, if you want to do what every programmer does which is kind of just looking at code, reading code, well, the MMU has to go through all of them and you can see what it does. So it has a four loop that goes through the number of levels. Starts at two and it's defined and then essentially we'll actually do the correct index because this is for a specific entry but if you want to go over every entry, well, this is your loop per level and then you'd have an inner loop that goes over every entry. So you could do it with four or two, four loops if you don't like recursion. Any other questions, comments, concerns? So if you, like if you have multiple processes pointing all to the same page, no. So that's just describing what happens with the page fault handler. So the page fault handler, it will call it just on a single memory access. So on a single memory access, it will call it if it fails and generate a page fault and then it will let you do something, modify the page tables as you wish and then it will try that again and if it doesn't work because the permissions weren't set or whatever, it will just actually exit the process for you but each access is independent so you're allowed to fix it up one at a time. Like it doesn't happen just once. So for copy on write, like with this when you're originally sharing, let's see here. So when we're originally sharing and we turn the write permission off, whenever someone tries to write to it it will generate a page fault, right? Whenever it gets to the L zero. So whatever generates a page fault, you have one chance to fix it. So to fix it, that's when you like say the child did it. It would, you should copy the page and then make the child point to it, turn on the write permission so that when it tries doing that again, it would actually work this time. Yeah, and then if it switches to the parent and tries again, well the parent would now generate a page fault and wouldn't exit immediately because for every operation, you get one chance to fix it. So if it went back to the parent now and then tried to write to that same spot here, if it followed through everything, the parent's write is also off, that would generate a page fault and you can handle it. Yeah, yeah, so in this case, so you would still have the virtual address so when I went through and fixed it up here, so when the child tries to access it and I fixed it up and copied the page and set the write permission back, well, I didn't change the parents as part of that at all. Yes, well, so you would set the number of references like refs to one after that, but there's no way in your page fault handler, you can figure out every processes like L2 page table that eventually has an entry that points to it because this is an entry you would like just to turn the write permission back on, which is currently off. You can't just go and go change another process as page tables while you shouldn't because you can just wait, right? I can wait, let the page fault happen and then I'll notice that, hey, my write permission's off, but hey, I'm pointing to a page that I have the only reference to so I just turn the write permission back on and then it works. Yeah, so when the page fault happens, it immediately calls this page fault handler. No, this is all simulated, so the kernel doesn't care, right?  Yeah, yeah, so if you look at the code which is pretty much the MMU sim we went out except that I have a page fault, it calls a page fault. So one of the functions says that if it should generate a page fault and then if it does, if it hasn't faulted before, it will call page fault handler and if this is the second time calling it where it's faulted before, it will say, yeah, too bad and then exit. So this is, yeah, so this is where it happens. It literally just calls your function. But yeah, if you actually did this on real hardware, it would generate an interrupt. So there would be a page fault, which would be an interrupt, but this is just like a software interrupt. Well, it's not even really an interrupt because I'm calling it directly, but it's supposed to simulate like a page fault interrupt. Yeah, a page fault interrupt that you have no choice not to ignore. Any other questions or go over the test cases or whatever? So yeah, I added 12 test cases now based off feedback to make sure that we have done it correctly. So yeah, so for all this code, like you should just call that get root page table once because that's what you're copying from. That's it. Don't call set page table root page table at all because that's meant to simulate actually context switching. You're not supposed to do that when you're just setting up page tables and all that stuff. But most of the other functions you should know how to use. Yep, yep, yeah. For both of them, you're just returning the new child L2. Sorry, what do you mean? So you write the page fault handler just here. So this actually is called on a page fault like, so right now the main I have, right, generates a page fault because I create a new child and it's just full of nothing and I return it. So then I try and do a write to that same virtual address which won't work. So in here, for this it calls the page fault handler. So I just have right now we can fix it. I could change the entry or do whatever. So yeah, and yeah, that's a good point. So for this too, whatever you do the copy, you shouldn't have to fix up anything in the page fault handler because if a page fault happens and you made an exact copy of it, then a page fault should have happened, right? Didn't point to valid memory, it didn't have the right permissions, whatever. So this page fault handler fixing stuff up should only be applicable for the copy on write stuff. Okay, and yeah, sorry if any of this was unclear at the beginning. I thought I just kind of copy and pasted the MMU SIM and thought everyone was good with it, but yeah, sorry, I should have probably documented it more, but hopefully this helps. So yeah, and it's not a lot of code. You should be able, if you don't do like three levels of four loops should be like 100 lines of code. Any other last minute questions, concerns, anything? I assume everyone be working on it like Friday or over the weekend or Monday day? Yeah, Monday, yeah, okay. Yeah, I remember engineering undergrad, it was terrible. All right, anything else? All right, well, good luck, pulling for you. We're all in this together.


All right, I think we can get started. Thanks for joining the session about Podman desktop. So this session is about some really cute little seals. And if there they are. So Podman desktop is a fairly new project that is kind of trying to address some pain points, especially for developers or for people working with containers on their local machine, especially with kind of the more recent changes in the strategy of the company Docker and Docker desktop. There was kind of a need from the community for an open source project. So this is Podman desktop. So before we talk about Podman desktop, maybe to give you a little bit of background on the project Podman itself, which sits behind Podman desktop. So Podman itself is a way to interact with containers. It's a very fast and lightweight way of working with containers. So there's no big kind of daemon like you would have with Docker. So it allows for a much faster experience. Of course, it's open source. It's also more secure because it's by default, rootless. And so you can use rootless containers and don't necessarily need elevated privileges. And of course, it's compatible with the normal containers that you would build, even if you built a container with Docker or with Builda or with any kind of open container initiative. So OCI compliant containers. So for those who aren't familiar with how to use Podman, it's very similar to Docker. So you can use it to run, build, push container images. But you can also use it to create pods, kind of as the name would imply, and allows you to work a little bit more closely with Kubernetes. So for example, in terms of images, again, if you're familiar with Docker, where you would do Docker push or Docker pull is exactly the same with Podman. And in fact, you could just kind of alias Docker to Podman. And then you can use Podman to use with Docker commands to they're fairly compatible. So you can see here, like if I want to list my container images, I can just do Podman images. If I want to build my container, it's just Podman build and so on and so forth. And then if I want to run my container, I can just do a Podman run. I can look at the containers that are running with Podman PS or attached to a container and so on. So again, if you're familiar with Docker, this is exactly the same, right? What's a little bit different with Podman is that you can also create pods, which is kind of interesting. So if you know Kubernetes in the concept of pods, this is exactly the same. So you have multiple containers that can go in one pod and they share, for example, network and resources, which can be kind of interesting. And I'll show that in a little demo later on as well, where I'll show a particular use case that could be interesting. So in terms of the architecture of Podman, you can see that compared to this is how the Docker daemon works. Podman does not use root context by default. So that's kind of an architectural difference that makes it more flexible and usable. So Podman and Podman Desktop, they're developed by Red Hat, which is also the company that I work for. And our container philosophy is built on kind of make tools that do kind of one thing and do it well instead of having Docker daemon, which can do a lot of things, but uses a lot of resources and is kind of beefy. So we have different tools for different purposes. So you can see Podman for managing and running containers. Podman Desktop, which we'll dive into a little bit more. But there's also projects like Builda specifically for building container images in different ways. There's Scopio to interact with registries. And so you can, for example, go and inspect images remotely without having to pull them down, which is something that the Docker command couldn't do. I'm not sure if it can do right now. And for example, CRUN2 as a container runtime. So there's a bunch of different projects. There's also Project Cryo for Kubernetes and stuff like that. So that's all the projects that Red Hat works on. So one of them, of course, is Podman Desktop. That's why we're here today. So Podman Desktop is a tool mostly focused on the application developers to be able to work with containers without being experts in all the different Docker commands. Like me, for example, I'm a software engineer. And I started working with containers a while ago, maybe 10 years ago. Yeah, I think just about. And so it was really learning about how to run containers, how to build containers. Very complicated. If you're just an application developer, you want to be able to focus on your code. So with Podman Desktop, it's trying to make that a little bit easier. So with a nice UI that allows you to do different things, like building containers, like running containers, creating pods, but also interacting with Kubernetes and creating Kubernetes resources. It's, of course, has support for OCI registries. So Docker Hub, for example, or Queda.io, or GitHub Registry, your local registry, your private registry, so it can plug into those in terms of those pods that I was talking about. So you can create pods from containers just from the UI. You can just select. I want to create a pod with this container and this container, and then it'll create a pod, and then they can share the network. You can generate Kubernetes YAML directly from those pods as well, so you can just say, hey, now creates a Kubernetes manifest that has a definition of this pod, and then I can deploy that directly to Kubernetes that might run on my local machine or remotely as well. And so speaking of Kubernetes, so Podman tries to make life a little bit easier in that respect, too. For example, OpenShift is an implementation of Kubernetes, but also any kind of other Kubernetes. The only thing is that, for example, with OpenShift, Podman Desktop can help you even create an OpenShift local on your local machine, so that makes it easy to work with OpenShift locally. So that makes it very easy for developers. It also can enable you to create, for example, a mini-cube on your local machine or a kind cluster, so Kubernetes in Docker. So it supports all sorts of different ways of dealing with containers. And then you can also extend Podman Desktop with different capabilities, so the same way as you can with more recent Docker Desktop, so you can use those same extensions, Docker Desktop extensions. You can use them in Podman Desktop as well. So for example, you can see there in this example, there's like disk usage extension, a log explorer, and an OpenShift extension that can help you with your local development to have some insight into what's going on. You can also extend the platform itself, so Podman Desktop itself. So you can see that you can add more registries. You can add menus and actions the way that you see fit. You can see, for example, also different container runtime, so you don't necessarily need to use Podman Engine with Docker Desktop. You can also, or sorry, with Podman Desktop, you can also use Docker runtime if you have a Docker runtime on your local machine and you would like to use Podman Desktop for a nice UI experience. That's possible as well. You can use Lima, so that's also possible. So it's trying to, again, make it meet the developers where they are and make it easy. So let's see this in some demos, right? Because that's way more fun and interesting to see this in action. So let's go and look at Podman Desktop. So I have it running here. And so if I go to my dashboard, so when I open Podman Desktop, by the way, you can install Podman Desktop on Windows, on Mac, on Linux. So on Windows, it uses WSL. And on Mac, I think you can just install it and on Linux, it just runs natively, which is what I'm using here. We are at open-source summit after all, right? And so here we can see Podman. We can see that it's running this particular version. It says Docker socket compatibility. It's not reachable, that makes sense, because I'm not running Docker on my machine. I'm running Podman. And so we can see that, for example, I have a developer sandbox from Red Hat running and it notices that. And I also have an instance of OpenShift Local on my local machine. And it's also noticing that that's installed and that it stopped and I could start it up and we'll see that in a minute. I'll be honest, running a Kubernetes full-blown, Kubernetes instance on your local machine takes a little bit of resources, right? So I'll run this in a little bit and then we'll see that my fan might start blowing a little bit. And then we can see here some of the extensions that exist for Podman Desktop. So in this case, I have, of course, Podman as my container runtime and I also have a Docker compatibility installed. So when I run Docker commands on my local machine, they're automatically translated to Podman commands. And we can also see, for example, I have OpenShift Local, I have Kubernetes and Docker and then developer sandbox. So I can quickly see at a glance what's there. So of course, let's look at our containers. And so I have a few images already here, but let's start from the beginning, right? So I have a little project here. So this is based on, it's a Java application. Any Java developers here? Not very many, I'm a little disappointed in you. I'm a Java developer. So this is based on Quarkus. So Quarkus is a Java stack that runs much faster, has a much smaller footprint and works really well with containers and Kubernetes. So I already created the source code for this file and I have a, what's cool with Quarkus is that it supplies Docker files kind of when you instantiate a project. So I have, for example, here, this Docker file that I can use to run my application in a container with the JVM. And so let's now start using this, right? So I'm gonna build my containers. So I'm gonna go to build an image and then I can select a container file and we go to source main and it was in the Docker folder. So here we have, let's choose this Docker file JVM and then I can specify the build context which is actually in a different folder. So you can select that as well. Quarkus observability in this case and then I can give it some random name or I can specify a specific name. Let's call this one Quarkus observability. And then build. So for developers, this should be fairly straightforward, right? I mean, yes, they have to have a Docker file somewhere or a container file, but from there we can build a container image pretty easily so we can see that it was successfully tagged so we created a new container image and now we can be done with that and here it is 22 seconds ago and it was created so we can run it. Now you're gonna see that it's not gonna run perfectly because it has a dependency on a database on an external database and on a tracing stack so based on Yeager, but let's run it anyway. So again, we can choose kind of what is a container name or let it define whatever it wants. We can set a specific entry point into this container. We can just leave that as it is. We could supply the volumes. Something that's cool with Docker desktop is so it notices what port you're trying to expose from your image. If I was already using this port for another application it would notice that and it would map different ports to your container so that's also something that sometimes developers struggle with like, hey, how do I map ports and everything? So that's also out of the box and then we can set environment variables and then do some more advanced stuff such as networking or make this rootful container if we need extra options. But in this case, I'm just gonna leave it simple like that and we're gonna run it's, let's see, I'm gonna make this a little bit smaller so I can see what I'm doing and then start this container. So now I'm running this container and we see that there's an error just as I was expecting because it's trying to connect to a database that's not running. And so if you're familiar with running containers they run in their own kind of network so what you could do to solve this what I can do is I can start up a container image as well but it's still not gonna find it because it's not in the same network. So there's two solutions to this. So you could use a Docker compose file and then define kind of, hey, this uses the same network which is also supported by Podman desktop. So this is one path, I'm going down a different path and that is I'm gonna create a pod with my different containers and then they will share the same network because they are in the same pod. So I'm selecting the container that I just started, right? The carcass observability and then with those other two containers that I'd already created and configured with environment variables. So I knew that they have the same, that the database has the same username and password than what my application is requiring. So then here we can see we can create a pod with those three different containers and let's see if it works, right? Everybody crossing their fingers with me. So we're creating the pod and probably I will have an error the first time, let's see. So it's this one and I see all the logs of the different containers here and it's actually not able to find my database because it wasn't started up yet, right? So my application container is starting at the same time as the database and so the database wasn't up and running yet so I just need to quickly restart it. So I click on the containers there. I'm gonna restart my container one more time and now we can see that it is actually running and able to connect with the Postgres database that I'm also running on my local machine. And so let's take a look and see if this is working. So this is on local host 8080 and we can see that, yay, we have our application running and I actually have this little endpoint fruit that should return some fruits and maybe I haven't configured it to actually populate it with data but let's imagine that there was some data in this database. I could add it and rebuild it but I think maybe then we'll run out of time. So that's how developers can fairly easily create containers, see their containers, manage them, create pods with them so we can now delete this. And so some more things that you can do with Podman desktop. So aside from just like generally managing containers, you can prune.  So you can just say prune, which means that all the containers that aren't running at the moment are gonna be deleted. You can do the same thing for your images as well so you can delete all the images that aren't attached to a container. And then you see this play Kubernetes YAML and so let's see if maybe we'll create our pod again and then we'll create a Kubernetes YAML for it as well. So I'm gonna select this and then we can decide, do we wanna use Podman container image to run this YAML because yes, Podman desktop can also run Kubernetes YAMLs, so a pod definition for example, or we can deploy it to a Kubernetes cluster. And so this is to play a Kubernetes YAML file, but we can also create one. So let's, we can look at that here. So if we look here, we can see our logs. We can see how to open our application and browser and so on and so forth. Then in terms of the images as well so we can build our images, we can pull them down and we can also push them to a registry. So here I have a different container image and if I wanted to push this to a Kubernetes cluster, for example, I can say push an image to Kubernetes and Docker cluster because I have that extension or I can push the image to a developer sandbox cluster. So speaking of which, let's take a look here real quick. So we have, if you go to developers.redhat.com there's this developer sandbox thing here and that gives you this free kind of playground based on OpenShift, which again is a Kubernetes instance. And so by running that, I have here a namespace on Kubernetes. Let's delete our previous version of our deployment and then I'm gonna try and deploy it to there. So we can do this in a few different ways so I can try to push it from here. So let's try that. It says I don't have a running connection so I may be not connected to the right place. Let's try that. And push it. Okay, well let's go over here to one of the extensions that we have. So I have installed two extensions to my Podman desktop. One of them is an OpenShift extension that allows me to interact with OpenShift. So let's see, I believe this is the right context. So that's also something that's kind of cool with Podman desktop is if you're working with Kubernetes you need to have a Kubernetes context to be able to interact with it. So that's also something that you can add here in Podman desktop. So I have, for example, my local OpenShift that is not running but I should have this sandbox out here it is. So now I'm switching to this context, change. And now if we select an image to deploy so we can see here, let's try this one. And now I'm gonna deploy it. And so it should push fail to deploy. Yeah, nice. Thank you. The live demo effect. All right, let's try push the OpenShift and deploy. And that should push my image to the internal registry in OpenShift and then deploy it as well. So let's see if that works. So it's not there, it's in our Firefox. Okay, so we can see here that my application is actually being pushed and then we'll see if it'll start running. But you can see that you can interact with different clusters pretty easily from this thing. So you can, again, add different Docker extensions as well. So for example, I have this Aqua Trivi Docker extension to scan for container images. So this could be interesting as well for developers to kind of preemptively scan their container images to make sure that there are no vulnerabilities before they push their code and then go through their CI CD pipeline where ideally there's some sort of security scan going on, right? But that means that they have to wait for this whole cycle to happen. So it's kind of nice to be able to do that on their local machine. So in this case, the nice people at AquaSec have created this container scanning extension. So, well, we can select one image and then we would scan it. And then after a little while, it would tell me if there are any vulnerabilities in this container. So a couple more things that we could look for is for example, our volumes, right? The storage that's behind our containers. So we can see also that we can create volumes. We can collect the usage data to see how much resources and space is being used. By the way, you can do that for your containers as well to see how much memory and CPU are being used by containers when they're running. And then we can see here in our settings that we can supply, for example, registries that we're connected to. So in this case, I have a connection to a Quay registry to push my extension or to push my container images. Then we can also see where we can add more extensions to Podman Desktop itself. And then if we wanted to add some more desktop extensions from Docker Desktop, we can do that here. And so that's a real quick overview of Podman Desktop. So as you can see, you can manage containers with it, but you can actually kind of make this into a nice short feedback loop for developers to work with containers and then also interact with Kubernetes. So Podman Desktop is available for free. It's a fully open source license. So there's no kind of anything that you need to do other than just go to podman desktop.io and try it out. So what's next for Podman? So it's a project that's still in, well, it's in full development, it is stable, but there's a lot of new features still being added. So for example, improvements in terms of windows with Hyper-V support, try to make containers start up even faster, enhancements for the Kubernetes YAMLs that are being generated. So right now it creates a pod YAML. So let's see, perhaps, because in Kubernetes it might be easier to work with deployments and services, so it can maybe generate those. And then, yeah, there's some more kind of development going on in this project. And Podman Desktop is open for suggestions, so you can definitely provide any kind of things that you think are missing. It's an open source project, so if you're so inclined, definitely contribute as well. And here's some links to get started with Podman and Podman Desktop. So as you can see, podman-destout.io is where you can get started. If you have any issues, the community is very responsive and is very eager to help you out. And you get really cute seals to look at when you go to those websites, so. If you wanna learn more about Podman, in particular, so there's a free ebook that's available on developers.redhat.com. So the developers.redhat.com program is very nice, they sponsor some of the books that we write, and then because they sponsor them, they can make them available for you to download for free, which is nice. So if you're interested in Java development, apparently there are not very many here, but there's some books here. I'm writing a book on serverless Java, by the way, that should come out pretty soon, and hopefully Red Hat will sponsor that one as well. But yeah, so take a look at any of those. And then I think that's it. So I hope this was interesting, and if you have any questions, I think we still have a little bit of time. So who has questions? I have stickers, if that was a question. Thanks. Yes, regarding the selection where you clicked together the podman, the pod, is there a way to also configure those, and will they also be shown in the interface? Because the dependency restarting is quite tedious, I guess. Yeah, yes. Trying to think where exactly you would do that. So yeah, you can configure the network topology and all that. Now, if you want to have more control over it, I would recommend using Docker compose file to really define specific properties and values, because most of what the podify does is use the properties that you've defined when you create a container image, and when you start the container, so it's gonna use most of those properties. But yes, you can. I think there's a lot of improvements still that will go into podman this of itself. If you use the podman in the CLI, you can customize the pods a little bit more as well. Thanks. Two really quick ones. Number one, does this use build under the hood for the podman build sub-command? I'm just wondering, because my understanding is that this was more runtime oriented thing versus build up, which kind of has that responsibility until I saw your presentation. Right, yeah, so it's a good question, because originally podman did use build up for the podman build command, and I think right now it's built into podman itself, so it doesn't use build up anymore. Probably uses the same similar bits to do its build, but it's not using build up anymore, I believe. Okay, I'm just wondering how you think about the kind of separation of responsibilities. Like if you need anything more advanced, you end up going to build up, and you get a cross compatible image, but it's just more feature rich then. Right, yeah, okay. Yeah, yeah, because with build up you can also build using basically kind of a bash command, like a set of bash commands. Whereas with podman build, it's just using kind of the classic container files. Right, right, so it's not very sophisticated, right, got it. Okay, so that's number one, number two real quick. So having come from a company that dealt with the harsh realities of Docker desktop's licensing change, I'm curious how much of that fed the momentum for this to be where it is now? Do you think that this would have, should I, just looking at this from a macro level, should I be drawing the correlation that this is kind of really stepped into the spotlight because of those types of changes for enterprises? Yeah, for sure, yeah, yeah. So there's definitely, because of the demand from the market, there was a lot more priority put into podman desktop to kind of prioritize this as a project because that's something that the communities was really needing. And Red Hat was happy to fill that spot, of course, but yeah, I mean, there's definitely a correlation between the two, yeah. Do you know how podman works on Mac OS? How's the, is it like a VM, like Docker desktop does? And, yeah, because an extending question is like how volume mounts work because that's one part of Docker desktop that works really great on Mac OS is like the volume mount. Right, yes, it uses the same kind of VM concept. Other than that, I'm not a Mac user, so I don't know exactly if it works the same way in terms of volume mounts, but I would assume so. I haven't heard anything with kind of, oh yeah, the volumes that doesn't work with Mac, for sure it does, but yeah. Thanks. Yeah, and then same with Windows, of course, that uses WSL and then also a virtual environment. Maybe I can answer that. I'm using podman on Mac, so. There we go. Perfect. Does it work? Mostly, there's a small hitch with the, well, how the volume mounts are working. Whenever I sleep this thing and wake it back up, the same one Mac, I don't know if it matters. I need to restart the virtual machine, so it's using this podman machine command to create the virtual machine so I can just manage it that way. But the volume mounts break when I sleep, then wake it up. Interesting, create an issue for that. Yeah. Any more questions? I have, at the Red Hat booth, there are little podman stickers. So they're, of course, very cute seal stickers, so definitely stopped by the Red Hat booth. I have stickers, but I don't have podman stickers, so. But if you're one of the two Java developers here and you want a Quark sticker, I have those. All right. No more questions. Then I thank you very much. Arigato gozaimasu. Thank you.