 I'm here to talk about building Rails applications with Docker, just general applications, anything I talked to you about today you can certainly apply to whatever kind of application you're building. I like to give very practical examples that you can go home and like sit on your couch or wherever and actually do the stuff I talk about, so I'm just going to use Rails as a basis for that. I do work at Codeship, I'm an engineer there, I work on a lot of Docker stuff, we also have a lot of Rails and Ruby at Codeship. I'm not going to really talk about what Codeship does during this talk, I'll mention it very briefly but we do have a booth in the lounge area if you want to talk to myself, or Kurt is also here, actually I'm not wearing my Codeship shirt but he is, look for the big anchor that says always keep shipping. So today I'm going to talk about a couple of things, I'm going to give you an introduction to containers, how are they different from virtual machines, like how do they work together, I'll talk to you about the Docker ecosystem. Docker started off as just a really small project and now has blossomed into this enormous kind of ecosystem with all sorts of tools, it can be a little confusing as to which thing does what and what purpose it has, so I'll kind of demystify that a little bit, and then finally we'll work through some examples of working with Docker on a Rails project, so I'll fire up a couple different Rails projects, we'll run them in Docker, we'll do some fancy migration stuff, it should be pretty good, so I'm going to do a lot of live demoing, so if you want to silently give an offering of some sort to the demo gods, I would very much appreciate it. All right, so the first thing that we'll talk about, before we get into the practical examples, I really want to make sure that you understand exactly what it is that we're working with, so I'm going to give you a really brief introduction to containerization first before we start hands-on stuff. And if you have heard about containers or have maybe worked with containers, chances are you've probably worked with Docker, I want to make one point really incredibly super clear, so much that it gets its own slide is that Docker and containers are not the same thing, Docker is a tool that manages containers, it's not a container, so you'll use Docker as your interface to manage containers, there are lots of other kinds of containers or containerization techniques other than Docker, Docker just sort of wrapped it up and put a cute little whale on it and everyone loves to use it, it's so much easier to use before you had to like root around an LXC and like with namespaces and certain things, and you certainly could like LXC and other containers have existed for much longer than Docker has, Docker's just made it so much easier to work with them. So what does Docker do actually? So Docker will build your images to run as containers, Docker will execute code inside those containers for you. Docker now, aside from just sort of like the Docker machine project, can manage entire applications with this tool called Docker Compose, which I'll demo and we'll talk about in chances are if you've started to use Docker within the last six or eight months you've probably already used Docker Compose. Docker also can help you provision machines to run Docker with this thing called Docker machine. So that's like kind of a lot of stuff, Docker is very powerful and it can be a little bit challenging as a beginner to kind of jump in and figure out everything. But before we talk more about Docker, let's talk about more about containers themselves. So Docker will manage the container, but what is this container thing anyway? So a container is a virtualization layer, it's kind of like a VM, like if you have the analog or the kind of mapping in your head that Docker container is kind of like a virtual machine, you're like 80% right, that's not a bad way to kind of describe it, it's just a level of virtualization or another layer of indirection because we love those. But there are some like fundamental differences between containers and virtual machines. So to start with just some like raw hard facts about containers. So they're basically just a self-contained execution environment. But the difference is that they still can share the kernel of the host system that you're running the container on if you give them permission to, right? Otherwise they're isolated from the other containers that are running on the system. And they're really small, so they can boot up really quickly, like sub second. So the really great thing that or why I love containers, especially in development, is that I used to work in R&D, so basically got paid to break stuff all day long, which is really good except for when you really break something really bad and then you mess up your whole system or your whole VM and you have to like rebuild it or something. And of course we have tools to do that, but could take like five minutes or something and I am very impatient. Also I'm very lazy. With Docker, if I mess something up, the worst thing that I'll have to do is delete the container and boot it back up, which might take me a whole second. So it's like really good to introduce into your development workflow because it sort of like gives you some some isolation and barriers, like to protect you from totally messing up everything in a really bad way. So how does that work in development? I want to take a few pictures or blocks because I am an engineer and not a designer, but hopefully this still gets the point across. I'm going to give you an example of an application that is running on virtual machines and an application that is running with Docker. This is the virtual machine example, we'll talk about this first and then see if you translate that same architecture to Docker containers, what is the same and what is different. We have at the very bottom infrastructure, on infrastructure virtual machine line, we have a hypervisor, that's like, you know, doing hypervisor stuff. So we have, right, that's what they do. In this particular example, we have three services. And each of them, these like smaller blocks, if you think each column is the service itself, so service zero has its libraries in Augusta West. It's like, you know, nice little virtual machine. The service one is also there and service two. So that's fine, we're used to this. It's not, you know, this is something that we're familiar with. In the Docker world, we can get rid of like the dedicated guest OS and also get rid of the hypervisor, which is like, really great. And in the, oh wow, that's really bright yellow, awesome. It's like in your face. In the Docker world, what we do is we kind of get rid of the guest OS and the hypervisor and instead replace it with this thing called the container runtime engine. So I mentioned that Docker is not the only way to run containers and in fact, like, there are a couple of things that could be at this layer. It's just likely that Docker is gonna be the thing that's at that layer. That is your kind of like, you know, resource manager and job scheduling kind of tool within this set. So Docker will be there running your services within the Docker containers that are controlled by the Docker container runtime engine. So it looks pretty similar, feels pretty similar to virtual machines, just like a little bit different. All this is to say that getting started with containers, even though I've illustrated it with really nice blocks, could maybe seem a little bit more complex, especially at the beginning. And that's true, but they do greatly reduce the amount of time and space that you need to run your application. So, like, my TLTR of why containers are good is that you can spend less time provisioning, rebooting, fighting with dependencies and more time building what you want. Because everything is contained, when you kill that container, everything dies within it. You don't have to like, spend a bunch of time making sure you have the right version of something installed but then you start another service that had a different version of dependency and it just gets into the spaghetti state. Docker makes it easy to kind of draw a line in the sand and say, you don't have access to this, you're running here and then when you kill that process, all of its dependencies die with it. It can be really nice and really nice to introduce into your development workflow. So, how would you introduce it into your development workflow? Containerization in general, but probably you're gonna add Docker. So, to give you kind of a big picture of the Docker ecosystem or ecosystem, as Solomon likes to say, if you've ever heard of DockerCon keynote, I kind of laugh every time that happens. So, Docker came from this very, very small project that was in the basement of Solomon, the founder in his mom's basement in Paris and has turned into this billion dollar valued startup in San Francisco and through this process, they've had a lot of growth, a lot of changes and they've sort of boiled down what Docker does into three things, build, ship and run. So, you can use Docker for building your images, building your applications for distributing them and then also it's a platform on which to run them. Today, I'm really only gonna talk about this very beginning part, just kind of the build step. I think it's the most useful to kind of have someone talk to you through it. The other things like running Docker in production is something that I'm definitely not gonna talk about today because it's incredibly complex and you have to introduce other tooling, of course. There are tons and tons of blog posts and articles and tutorials out there if that's something you're interested in. So, the very first part of this Docker build is the Docker image. Here's a question that I get a lot or a correction that I make to, like that I correct people a lot. They say that images and containers are the same thing and in fact they are not the same thing. You, when you interact and you pull down something from Docker, you're pulling the image. Think of an image like a class and then the container is just the instance of the class. So, if you say Docker pull Ruby, you're not pulling down a Ruby container, you're pulling down a Ruby image that you are going to run inside of a container. It seems like really pedantic and like I'm just being like mean person to like correct people but it does make a huge difference, especially when you're talking about a system so complex as Docker to make sure that the vocabulary is consistent across all the conversations. Images are not containers. Images are kind of the recipe and then the container is like the thing that's being executed and actually fired up. And speaking of Docker pull, if you have worked with Docker or like have been curious about it, chances are you've probably seen this wonderful grid called the Docker Hub. So they have just redesigned it kind of in sync with the last DockerCon which is at the end of June. So if you haven't looked at it in a while it's like totally brand new. The Docker Hub is a public registry that Docker itself runs. There's about, I feel like the last check when I made the slide like a week ago is about 15,000 images are available on the Docker Hub. So there's like you can find like a lot of stuff. So if you're like struggling to like how do I do this? Chances are someone's already done it. Find that you could probably find it on the Hub. In addition to just being the registry, the Hub also functions as sort of like the GitHub-esque part of the Git project where there's things like web hooks, build triggers, like of course authentication is there. You can have private repositories as well. So if you want to push something to the public registry, the Docker public registry, but you don't want it to be public, you can buy private repos just similar to how GitHub you can do that. And you'll probably interact with it either via the GUI, so what I just showed you before, or you can do pretty much everything via CLI. And especially when you talk about like your continuous integration, continuous deployment things, you'll probably just like have a step in your CI that pushes your image to the Docker Hub. You don't need to do it on the GUI. On the Docker Hub, there's a couple of different types of images. So if you are interested in getting started or using some containerized component for an application and you go to the Docker Hub, this is a word of maybe warning, but also just like some advice as to what to look out for. There are a couple of different types, like different styles of making a Docker image. So if you're just searching for something, kind of look at the documentation, of course read the docs, to really find out what it is that you're pulling down because it might be not what you expect. The first type is probably what you're looking for. This is a service image. When you pull down this image and run it, you have the service and you have like an endpoint that you can consume. So an example of this would be like a database. You would pull down the database and run it and like your database is working. So that's a service, you pull it down, run it in a container, great. The second type is like really helpful, but maybe not what you're looking for right away if you're looking for that kind of service thing. And it's kind of what I call the project base image. So for example, Ruby is a like shining example of the project base image. If you pull down Ruby, the image and run it, you just have a container with Ruby in it. Like there's really nothing else going on in there. You have to add other stuff to it. It's just meant as sort of like the basis for your containerized application. So right, like language ones are good examples of these. Anything that just sort of sets up your environment so that you can then add stuff to it and run a complete service is kind of what I call project base. Some of the naming things might be a little weird. So you might think you're getting a service, you actually are getting the base for that project and then it doesn't work. That might just be something to keep in mind to check for. And then finally, this isn't really a different type of image, but just something to watch out for is a thing called official images. So I mentioned before that I'm incredibly impatient and also lazy. If I need to run Postgres, like I'm not gonna spend time to like make my own Postgres image. That just seems silly, right? Postgres has already made an official image that's available on the Docker Hub. I'll actually be using it a little bit later. For example, Rails and Ruby also have official images. It's either the entity, like the community or the company that controls the service has come together and said, hey, we'll maintain this image. So they're responsible for keeping it up to date with the latest versions. You don't really have to do anything. You'll see them kind of marked as like official on the Docker Hub. So usually try to use that one first. And if you find that it doesn't suit your need, use one of the forks, but always look I think for the official ones first. I think it's just kind of a good way to work. But maybe you don't want to use an official image. And in fact, what's the point of using Docker if you can't run your own stuff inside of a container? And that means making your own Docker images. The way to do this is first you have to create the Docker file for your image. So every single image, no matter if it's official, any kind project-based service image always starts with the Docker file. So the Docker file is sort of like the list of instructions and how to build the image and then Docker will build that image for you. You'll build it on the CLI using the Docker build command. Dash T is a tag and then you'll give it an image name. Very, very common to have the syntax or kind of the naming convention of GitHub username slash image name. Similar of like your organization name and then repo name or something on GitHub. So for example, we would have like code ship slash alpine or something. Certainly when you're working on your own, you don't have to do that. But if you do push something to the hub, it's kind of good to keep that naming convention in mind. Also, there is a dot at the end of this. You have to tell Docker where your Docker file is because it could be anywhere. You have to say and usually that you're gonna be in the same directory that your Docker file is. So you just have to tell it where to look for the Docker file. You now with Docker, I think maybe two versions ago, you can name your Docker files different things. So you might have Docker file dot dev or Docker file dot deploy. And you can pass in those names to this Docker build command to build specific images for specific use cases. And then when you finally done the building and you want to look at which images you have, you can run the command Docker images and you'll just see like a nice little output of all the images, how big they are when you got them, what the tags are, what version number, if it's the latest one, et cetera. So this is an example Docker file. I'm gonna walk you through some common things in the Docker file. This is perhaps the single place that if you can do it in a kind of informed, optimized way, you can keep your application really small. It's kind of subtle, like how things should be ordered and how to optimize images. I'm gonna give you some tips right now on how to do that. But if you kind of have a poorly written Docker file, you can expect your application or the image size to get really big kind of quickly. So here's the first thing is from, every single Docker file must have a from command. That's the very first one. In this case, because this is a Rails application, I'm just gonna take the Rails official image and use that as the basis for my own project. So I talked about kind of the project base images on the Docker Hub. This is a good example for that. So in this project, I'm gonna use that one as the basis for my project. Also notice that I'm setting the version right there. I'm pulling down a very specific version of Rails. I could pull down whatever version I wanted to. There does exist a tag called latest. It is just a floating point tag. It does not point to any particular version. It's just whatever the latest one is. I would very, very highly recommend that you not use latest tags because if the latest tag changes and there's breaking changes, then you have a lot of debugging to do and I'm really sorry about that. So just try to use like a lockdown version. Like save yourself a world of pain. Okay, so the next thing is as kind of optional, I like to put this in. It's a maintainer. So if you see an image that you're using, you can look at the maintainer when things break and email them out of the blue to tell them that their image is broken. Not that that's happened to me this morning or anything. So then we have a run command. So this is just straight up executing like maker inside like during my image build process, I want to make a new directory. So I will say run and then give it my instruction. This is an interesting thing. So this is a copy command. So notice I'm not doing any copying in that run thing. I like the run command before it. It's actually a separate thing called copy. There's also one called add and this is very confusing. There's a really good blog post by my former colleague, Brian DeHamer that explains all the differences between add and copy. If you use add and you are trying to do, like if you add like a tar ball, it will just unzip everything for you and like some other fun things that you're not expecting. So copy is a good way to introduce files into your container. So in this case, I'm just copying everything in my current directory into that new directory that I've just made. Since this is a Rails app, I'm copying my entire Rails app into this new directory. The next thing that I'll do is set a worker or working directory. This is top to bottom and from this point on, every run command will be run in the context of this directory because now I wanna run bundle install. If I hadn't set my working directory, it would just be in the root of the container and your bundle would fail because there's no gem file. You have to tell it, execute this command inside of this directory from now on. Doing a CD in a run command, for example, like, oh, come on, here, if I said like maketer and CD, it doesn't work because it's different, kind of like different entities controlling it. That is just within the context of the run command, but then I'm like leaving that run command, doing a bunch of other stuff and then coming back and running another thing. Docker doesn't know necessarily about stuff that happened in previous run commands. You need to make sure it's supposed to tell Docker itself to build or to run the specific command inside of the directory that you want. Okay, cool, so we'll run bundle install as expected and then the CMD or command, some of these are abbreviated, some of them are not, it's kind of weird. So this is the command that will actually fire up the container. So this, I'm just gonna run Rails S, I'm gonna bind it. You have to bind it to this address if you are on a Mac or anything other than Linux, really. Otherwise, when you try to access the port through Docker machine, you won't be able to do it, so. So that's a like pro tip. It took our whole team of like senior engineers working in R&D, probably a solid hour to figure out why we couldn't get Rails to work in a container, so that's why. Cool, so that's sort of the inner workings of the Docker file, we'll run through building and I'm gonna do a bunch of live demos in just a minute. One thing I wanna say about images and managing them and managing your workflow is that the Docker Hub is a good place to find images if you don't wanna build them yourself. And then once you have those images, you can use a tool called Docker Compose to stitch all your containers together and make them work. Docker Compose, if you haven't worked with it, what is now the FIG project? So if you've heard of FIG in context of Docker, it's the same thing, they just acquired FIG, renamed it, and now it's called Docker Compose. This is an example YAML file that's controlling the application that I'll start with Docker Compose. All Docker Composes, a YAML file that gives you an application template, basically. So you, instead of having to define everything at runtime, you define it in a YAML file, say Docker Compose up, Docker Compose looks and fires off all the stuff that you told it to do, and you don't have to type a lot, which I like, again, as a very lazy person who doesn't like to type. Okay, so that's kind of the biggest overview of Docker, that you sort of, all the information that you need, if you weren't familiar with Docker to kind of get started with actually using Docker in your Rails application. So the first thing that we need to do, of course, that I haven't mentioned is installing it. Boot to Docker is the old way. If you're still using Boot to Docker, I'm not sure how many of you have kind of started using Docker already. But if you have Boot to Docker, I really encourage you to upgrade to the new kind of distributed, or a way that Docker is distributing itself. It's called Docker Toolbox. Inside Docker Toolbox, so Boot to Docker is just a VM, basically. Docker Toolbox does everything that Boot to Docker did, but with a couple extra things. So it comes with the Docker client or the Docker engine, the machine, Docker machine, which is used for provisioning virtual machines. Kitematic is Docker's UI. So if the command line is just really not your cup of tea, you would rather use a GUI, you can, and there's one included in Docker Toolbox that you can pull down. And also it does depend on virtual box. So if you don't have virtual box, you will need to install it in order to use the Docker Toolbox. If you are a previous Boot to Docker user, you can easily port your Boot to Docker VM over into a new Docker machine VM. And if you look at the docs at docker.com slash toolbox, you can do that pretty easily. I should mention now I am on a Mac. Docker is Linux, so I am running a virtual machine via Docker Toolbox, and that's how I'm gonna be interacting with Docker. It might seem very like sneaky that it looks like I'm just natively typing and controlling Docker on my Mac. It's actually a layer of abstraction via Docker Toolbox, so just don't be fooled. If you are using Linux, you can certainly download Docker with all of the official packages that are available on Docker.com. So there's installation guides for pretty much every operating system, how to get it up and running. It might take a little bit. Docker Toolbox makes it super, super easy. So installing Docker is the first step, and then you're ready to start your Rails development with Docker. I'm gonna be going through a couple of examples, and in all of these examples, we have a couple goals. So it might seem a little weird to think about using Docker for development because it is another layer of abstraction, and it seems like your code is really far away. But I'm gonna show you how even running a Rails app in a container as a developer, you still can do these pretty important four things. View the app running in your browser, edit your files in your local environment using your own IDE or whatever you want to do to edit files, and then see the changes. Run tasks against your Rails application, and also see log output. So those are the four things that I'll focus on and show you how all of those things are still possible even if you're using Docker. It's not that hard, I promise. Okay, so do we remember this Docker file? Now is the part where I go into live coding, and hopefully everything works. We'll build this and fire up some Rails applications, maybe. Oops, cool. Okay, everyone can see that? I hope. Awesome, so I'm just in a new directory. There's like nothing in it, certainly not backups. Thanks, Sam, for making me very nervous before. So what I'm gonna do is just say Rails new for ours, Rcamp app. Okay, I should have skipped bundle, but that's fine. Okay, so we'll do this. Cool. So let's go in there. You know, that's what we can expect. So now to get this, I could say like, of course I could do Ruby Racer or whatever thing and run it in my thing and see that I have the Rails application that's working, but I wanna run it in a container. There's a couple of things that I need. So we're gonna use a Docker file along with Docker Compose to kind of stitch everything together and make it work really nicely. In the interest of time, I have, oops, not wanna do that. I am just going to copy some of these Docker files in here. This podium is like unnaturally tall, so I'm sorry that I'm making all these typing mistakes, but I'm like on the tippiest tippy toes because I can't reach. Okay, cool. Oops, Docker. Another thing is that this Docker Compose thing has to be called DockerCompose.yaml or fig.yaml, either one. Docker Compose will look for it. So if we look at the Docker file, we'll see pretty much exactly what we looked at earlier. And the only difference is that I just didn't wanna mess with my gem file, so I'm installing Node as the JavaScript runtime and like, yeah, I know it's bad, but I'm just gonna do it for this demo. I'm setting, running some like apt-get stuff to get Node running, making the directory, copying. This time I'm only gonna copy my gem file because I wanna be able to edit my files and I'll show you how we do that. It's via a volume mount. I could certainly copy my whole application into the image and then overwrite all of the files via a volume mount, but I just feel like that's a little messy, so I'm only gonna copy the gem file so that I can bundle and then I will start the application and we're gonna actually mount the current directory that I'm in, so that rails application that I just started and I'll dump it into the application or the directory called var app, which if you remember from the Docker file is the one that I made that my gem file is already in. So this is a Docker compose file with just one container. That one container is called web. I'm gonna build the image for the web container from the current directory that I'm in from the Docker file in there, which is just this one on the top. Okay, so this Docker file that I have at the top is gonna be built by Docker compose and then run as the web container as I have declared in this Docker compose YAML. One other thing I'm gonna do is bind port 3000 in my container to port 3000 on my Docker machine host. I'm running a Docker machine right now called rails default and we can see the IP address of it here. When I'm in the browser, I'm not gonna be going to local host 3000. I could if I opened, if I did another port mapping rule on that Docker machine machine, but again, current theme, I'm very lazy. I'm just gonna go right to this IP because I know that it's there. So we can say Docker compose build. Surprise, it's already built because I didn't wanna wait for the wifi. You can see that it's doing steps for every single instruction in my Docker file. So I first said from, then I said run and it's doing this and then I said the work door and you can see it's separated out into steps. Each of those steps is a layer in the Docker image. It uses a write on copy file system so each of those is actually creating a distinct layer of stuff in my image. If I wanted to go and maybe change what files I'm copying, it would only need to rebuild steps three and four because steps zero, one and two would be the same. It's just layers, it's kind of like get, it can reference back into the tree, it's pretty nice. So we've built that by saying Docker compose build which is just gonna execute all the build commands in the Docker compose YAML. I can run this now by saying Docker compose up. It's going to create the container and then it's actually gonna attach itself so that we can see the log output. So now we see this familiar stuff. So I should be able to go here and see that woohoo, I have it running in a container. Also notice again, just it's my Docker machine IP that I'm using, I could do this all with local host but I didn't set up a port mapping rule. So this is totally cool, right? But what if I wanted to say something like rails, G, scaffold, pirate, name, wooden legs? Maybe, cool, I don't know. Like I guess you can only have two, so that's fine. Okay, cool, so I did that and then I'll just, right, go to pirates. Of course I have to run the migration and how do I do that? Because my rails process is actually running in a container like God knows where, right? I can't get in there and say that. Docker compose lets you do that for like, it will do it for you. So I am inside my application. I'm gonna say Docker compose run is the command for running command. If you remember, I named this applicator, this container, the service that I'm running, web. I'll pass that as the first argument. And then just so I don't have to type it, I can just run my rake task via Docker compose, okay, migration worked, cool. And then I can go back here and see that my pirate stuff worked. So it kind of maybe is an extra step, you have to go through Docker compose, but you can still run all of the stuff that you normally would run, just right in there, which is pretty great. The other thing that you can do is, oops. Let's see, style sheets. So if you remember, I linked the volume, like I mounted a volume of my files, I didn't actually put the stuff in the image itself. So I could say, hopefully this will work, like font, family, and because we're pirates, I guess I could say cursive or something, right? It's cool. So I changed this locally, right? Like I'm just in my little terminal window on my local host, I'm not in the container at all, and I can change files. So via the volume mount, that's how I can just edit stuff in my normal environment and then see it propagated into the browser and into the container. It's because I'm using that volume mount that I outlined and kind of declared in my Docker Compose YAML. So that's basically running the kind of the Docker development workflow inside of a container. Let's go back, not to here. Isn't that nice though? Okay, cool. So that's great, and that's a really simple example that hopefully you can just sort of like go home, review slides, look at a tutorial on the Docker docs. They actually have a one that's really similar to this Rails application, but what happens like in real life when we need to use things like Postgres or Redis or something, how do you get containerized services to communicate with one another? Excellent question. And the answer to that is kind of straightforward, but maybe not, container linking, environment variables, and of course like a little bit of config sugar. There's no way to escape that. The good news is that Docker Compose makes this really easy. I'm actually not gonna run this application as a live demo, but you can take this Docker Compose YAML from my slides and run it on your own machine, and it should work for you, fingers crossed, that's the beauty of Docker Compose. So we still have kind of the same web application that we had from earlier, it's just called web, that's the Rails app. The addition is that now I have another container that's running a database. Unlike our web application, the database is just gonna pull an image right from the hub. So instead of saying build, I'm gonna say image, and it's gonna pull down Postgres for me. The second thing that I need to do is link that container to my web container. So I want the web container to know that it has a dependency and that dependency's name is DB. I'm just gonna do that very simply via the link command so I can say links, pass it database. Now my Rails application knows that it can't start and do what it's supposed to do until that database is started. So a couple things to point out is that we've chosen the name database, that's not necessarily what it has to be, but make sure that it's the same, that you're linking the same name. Like don't try to link Postgres, even though it's a Postgres container because you've named it DB. That's a mistake I made like a ton when I was first starting with Docker Compose and hopefully that will save you some time. Also one thing to point out is that even when you're running complex like multi-container applications, you can still do the same thing for development by mounting the volume of your current directory into the container and then controlling your files that way. Of course we have to change our config database YAML to make this work. It can't look for local host because your Postgres is not running on your host. Docker does this really nice thing where now my host name for my container is the name that I gave it in my Docker Compose YAML. So I can say host DB and it knows to look inside the sort of Docker world that it's in for the thing named DB and it will be able to connect to it. So finally, the last thing I wanna talk about once we've done sort of using Rails in development, some basics of setting up multi-container applications with Docker Compose, what happens when you want to deploy a Dockerized container or a Dockerized Rails application to production? The answer is like a lot happens. But it's really easy if you use, of course everyone's probably using some kind of CI or continuous deployment. In the Docker world, the steps are pretty similar. Of course you're gonna do the run your tests, compile your assets, et cetera. The things that need to be added to your workflow, to your CI workflow if you're using Docker is a build of the image, pushing that image to some repository, whether it's the Docker Hub or if it's like a different private registry that you're running maybe on-premise or some paid solution that Docker has paid private registries. There's like CoroS's Quay also exists. You need to deliver that image somewhere where then the hosts that are running the containers can retrieve that image and then restart themselves. That's a really basic kind of overview of CI with Docker. Of course I am happy to answer any question and Kurt as well if you wanna specifically know more about CI and Docker and running in production. It's a huge, huge topic that needs a whole conference of itself. So with that, I will encourage you to please always keep shipping. Thank you very much. I think we maybe have time for one or two questions and if not, I'll be happy to answer any question afterwards but I don't wanna keep you guys from lunch. So thank you very much.