‫This lecture is going to be all about adding image building into your Compose files so that it automatically
‫ensures that you have an image ready to go
‫when you're running compose commands. Like other lecturers in this section, you really need to have a good
‫sense of Docker container and Docker image command line functionality.
‫Another thing that Compose can do for you is build your images at runtime. It'll actually look in the
‫cache for images, and if it has build options in it, it will build that image when you use the up command.
‫It won't build the image every single time.
‫It'll only build it if it doesn't find it.
‫You'll need to either use the docker compose build to rebuild your images if you change them,
‫or you can use docker compose up --build.
‫We'll actually see that in a minute.
‫This is really great for when you're using Compose locally and you have images you want to build. Maybe
‫you don't want to use volume mount. You actually want to copy files in, or something, into the image.
‫Your build command might be fairly complex. It might have some custom environment variables or build
‫arguments.
‫By the way, build arguments, we haven't talked about. That's really just environment variables that
‫are available only during builds. You can look at the docs. docker.com documentation on Dockerfiles
‫and it'll talk about build arguments in depth.
‫Here, we're going to look at an example of how you might use that locally.
‫I'm in the compose sample 3 directory. You can see here I have a pre-built Docker Compose file
‫here.
‫I have actually a Dockerfile called nginx.Dockerfile. Then a similar nginx config to what
‫we had earlier, where we're actually using Nginx as a reverse proxy for our website.
‫If we go into the Docker Compose, you can see how I've architected this solution.
‫I've actually got two services.
‫One is the Nginx proxy like before, and one is the Apache web server like before.
‫But a couple of things are different.
‫Instead of me specifying the default image for Nginx, I'm actually building a custom one.
‫You can see here that I've actually given it some arguments where I'm telling it that the Dockerfile
‫it needs to use is a specially named Dockerfile.
‫I want it to build that Dockerfile in this current directory that it's in. I want it to name that image
‫when it builds it, nginx
‫-custom. It's going to store that in my local cache. Then down there at the bottom, we have a web
‫server running Apache.
‫What I've done here is I've actually mounted some HTML source files that I have into the Apache server.
‫So the scenario here is maybe I'm a web developer,
‫I have a static website here,
‫underneath this HTML directory that I don't really need to worry about too much.
‫It's just using a little bootstrap template.
‫I'm going to be editing on that locally, in my editor here, but I know when I go to production with this,
‫it's actually going to be sitting behind an Nginx proxy.
‫So, I want to emulate that production environment as much as possible, locally, just to make sure that
‫I've weeded out any bugs or any problems. In this case,
‫I want this Nginx, and I know that this Nginx config is the one they're going to use on the
‫production server, so that I'm just going to use that here.
‫This is actually the same Nginx config as before.
‫When I run the docker compose up command, it's going to first check for the name of this image in
‫my cache. If it doesn't find it, then it's going to use these build commands here to look up the Dockerfile
‫and then build my image. You can see from this Dockerfile, it's pretty simple actually.
‫It's just going to use a specific version of Nginx and then it's just going to copy a file in.
‫It's going to get the rest of its information from that Nginx config from Docker Hub and then
‫it's going to copy in my Nginx config.
‫If you remember in a previous example, we actually did a bind mount to get this Nginx config in
‫through our compose file.
‫In this case, we're just wanting it to build the whole image.
‫We don't really need to be changing this proxy config, so I don't really need to mount it so that I can
‫change it all the time.
‫I just want it to run. Right? So, I'm going to build it. Let it sit in the image cache. Once it's built the
‫first time, it won't need to be really rebuilt very often.
‫So I'm just going to leave there.
‫Then when I'm editing and developing on my website, I'm going to have this configuration so I can
‫do live edits. If we go back over here and I do a docker compose up,
‫let's step through what happened.
‫It first created the network.
‫That's a normal thing. It does that.
‫Then it actually is seen that the proxy service doesn't have the image it's looking for. So it's
‫going to build that.
‫So it's pulling out the Dockerfile and building it just like it would do a normal docker build command.
‫Then it's giving me this helpful tip to let me know that it built the image this time because it
‫couldn't find it.
‫But in the future, if I need to change that image, I'm going to need to use the docker compose build
‫or the docker compose up --build commands. Now that it's got the image,
‫it can actually create the containers. Then it's starting my web server and my proxy server.
‫If everything worked correctly, I should be able to get a localhost. It pulled up my default template
‫here, which is a bootstrap template actually.
‫It looks like everything works.
‫Actually, I go over here and I can see all my logs coming up and obviously there's a lots of assets. There's
‫a log entry for each one and it's going to go through the proxy and through the web server.
‫Because I've bind mounted that directory for editing, I can actually go back into my editor. As
‫a web developer, I could go in and maybe, you know, edit something on the website. Maybe I'll go into the start
‫bootstrap title, which should be this little title up top here.
‫I'll just save that file. Then if I refresh, my website's updated because of that bind mount again.
‫This is a great example of a very common developer setup where you need to build some custom images
‫locally.
‫You also need to mount some files into your application so that you can edit them at runtime.
‫And, of course, if this needed to be a database-backed application, I would just add a third service down
‫here for the database server. Then, I'll go back and do my cleanup.
‫You'll notice that, by default, it won't actually delete that image.
‫You'll notice up at the top here, we have the nginx custom that it built. But there is a docker compose
‫down command.
‫If you look at the help, you see that there's an rmi option that actually removes images it may have
‫built or it may be using.
‫There's this actual option here says, 'remove only images that don't have a custom tag set by the image
‫field.'
‫One thing I could do here if I wanted to make this a little more automated, is I could just take out
‫that image command right there. Let's just remove that. Then I want to clean up real quick. I'm just
‫going to remove my image. docker image rm custom. As you can see, it's gone there.
‫All right. I want to do docker compose up again.
‫And this time we'll do a -d.
‫You'll notice throughout these examples of Compose, that it actually names containers, volumes, and
‫networks with the name of the directory as the project name.
‫That's actually something in Compose where, to prevent name conflicts,
‫it will actually always add the directory name on the beginning of all of the assets so that they don't
‫conflict with other ones.
‫You can actually change that proxy name through the command line.
‫If you go check out the Compose documentation.
‫But the point I wanted to make here is if I do a docker image ls here, you'll see that it actually
‫named my image for me.
‫So I don't technically have to use that image option.
‫But if I wanted a specific name for it so that I could maybe identify it later, I could.
‫The reason I was bringing that up is this is actually a little bit cleaner because what I can do
‫then is docker compose down, and remember in the help, it said I could use an rmi type. So when I clean
‫it up, and I like to keep my Docker environment clean, I can do am rmi local.
‫What that will do is actually delete those images as well.
‫You'll see here down at the bottom that it deleted the image.
‫Not something that I do all the time but maybe if I have a big project with lots of custom images
‫and I don't want it to blow up my system when I'm not developing on that project, I'll use the rmi
‫local, and it'll always keep track of the custom images it had to create.
‫Of course, here if I use the all, it will actually delete every image that was used in this project
‫which you may not want to do because in this case, it might delete the httpd Apache web server, and you
‫might want that image to stay around for a while. OK.
‫You learned a lot about Compose in this section.
‫We're going to be using Compose throughout the rest of this course.
‫We'll keep building on these skills as we go.