tubetranscript.io

Fireship · Transcript · · Updated

Learn Docker in 7 Easy Steps - Full Beginner's Tutorial – Transcript

Video by Fireship · Watch the original on YouTube

Summary

AI-generated from the transcript. Verify details against the source video.

  • A Docker file serves as a blueprint for building a Docker image, which functions as a template for running Docker containers.
  • Docker build creates a Docker image from a Docker file, and Docker run creates a running container from that image.
  • Docker Compose is a tool used for running multiple Docker containers at the same time using a docker-compose.yaml file.
Video thumbnail: Learn Docker in 7 Easy Steps - Full Beginner's Tutorial
Source video on YouTube · Transcript generated automatically and may contain errors.

Use this video with Pro

Reading, copying and transcript downloads are free. Create saved AI results for this video with a signed-in Pro account ($9/month).

Transcript

Search ignores accents. All transcript text stays visible.

One of the leading causes of imposter syndrome among developers is not knowing Docker. It makes it hard to go to parties where everybody's talking about Kubernetes, Swarms, Shuffle Sharding, while you hide in the corner, googling what is a container. We've all been there at one point or another. In today's video, you'll learn everything you need to know about Docker to survive as a developer in 2020. We'll take a hands-on approach by containerizing a Node.js application. I'll assume you've never touched a Docker container before, so we'll go through installation and tooling, as well as the most important instructions in a Docker file. In

addition, we'll look at very important advanced concepts like port forwarding, volumes, and how to manage multiple containers with Docker compose. We'll do everything step by step, so feel free to skip ahead with the chapters in the video description. What is Docker? From a practical standpoint, it's just a way to package software so it can run on any hardware. Now in order to understand how that process works, there are three things that you absolutely must know.

Docker files, images, and containers. A Docker file is a blueprint for building a Docker image. A Docker image is a template for running Docker containers. A container is just a running process. In our case, we have a Node application. We need to have a server that's running the same version of Node, and that has also installed these dependencies. It works on my machine, but if someone else with a different machine tries to run it with a different version of Node, it might break. The whole point of Docker is to solve problems like this by reproducing

environments. The developer who creates the software can define the environment with a Docker file. Then any developer at that point can use the Docker file to rebuild the environment, which is saved as an immutable snapshot known as an image. Images can be uploaded to the cloud in both public and private registries. Then any developer or server that wants to run that software can pull the image down to create a container, which is just a running process of that image. In other words, one image file can be used to spawn the same process multiple

times in multiple places. And it's at that point where tools like Kubernetes and Swarm come into play to scale containers to an infinite workload. The best way to really learn Docker is to use it. And to use it, we need to install it. If you're on Mac or Windows, I would highly recommend installing the Docker desktop application. It installs everything you need for the command line and also gives you a GUI where you can inspect your running containers.

Once installed, you should have access to Docker from the command line. And here's the first command you should memorize, Docker Pss, which gives you a list of all the running containers on your system. You'll notice how every container has a unique ID is also linked to an image. And keep in mind, you can find the same information from the GUI as well. Now, the other thing you want to install is the Docker extension for VS Code or for your IDE. This will give you language support when you write your Docker files and can also link up to remote registries and a bunch of other stuff.

Now that we have Docker installed, we can move on to what is probably the most important section of this video. And that's the Docker file, which contains code to build your Docker image and ultimately run your app as a container. Now, to follow along at this point, you can grab my source code from GitHub or Fireship.io, or better yet, use your own application as a starting point. In this case, I just have a single index.js file that exposes an API endpoint that sends back a response.

Docker is easy. Then we expose our app using the port environment variable, and that'll come into play later. The question we're faced with now is, how do we dockerize this app? We'll start by creating a Docker file in the root of the project. The first instruction in our Docker file is from. And if you hover over it, it will give you some documentation about what it does.

You could start from scratch with nothing but the Docker runtime. However, most Docker files will start with a specific base image. For example, when I type Ubuntu, you'll notice it's underlined, and when I control click it, it will take me to all of the base images for this flavor of Linux. And then you'll notice it supports a variety of different tags, which are just different variations on this base image. Ubuntu doesn't have Node.js installed by default. We could still use this image and install Node.js manually. However, there is a better option, and that's to use the officially supported Node.js image.

We'll go ahead and use the Node version 12 base image, which will give us everything we need to start working with Node in this environment. The next thing we'll want to do is add our app source code to the image. The working directory instruction is kind of like when you CD into a directory. Now any subsequent instructions in our Docker file will start from this app directory.

Now at this point, there is something very important that you need to understand, and that's that every instruction in this Docker file is considered its own step or layer. In order to keep things efficient, Docker will attempt to cache layers if nothing has actually changed. Now normally, when you're working on a Node project, you get your source code, and then you install your dependencies. But in Docker, we actually want to install our dependencies first so they can be cached.

In other words, we don't want to have to reinstall all of our Node modules every time we change our app source code. We use the copy instruction, which takes two arguments. The first argument is our local package JSON location. And then the second argument is the place we want to copy it in the container, which is the current working directory. And now that we have a package JSON, we can run the npm install command.

This is just like opening a terminal session and running a command. And when it's finished, the results will be committed to the Docker image as a layer. Now that we have our modules in the image, we can then copy over our source code, which we'll do by copying over all of our local files to the current working directory. But this actually creates a problem for us, because you'll notice that we have a Node modules folder here in our local file system that would also be copied over to the image and override the Node modules that we installed there.

What we need is some kind of way for Docker to ignore our local Node modules. We can do that by creating a Docker Ignore file and adding Node modules to it. It works just like a Git Ignore file, which you've probably seen before. Okay, so at this point, we have our source code in the Docker image. But in order to run our code, we're using an environment variable.

We can set that environment variable in the container using the env instruction. Now, when we actually have a running container, we also want it to be listening on port 8080, so we can access the Node.js Express app publicly. And we'll look at port some more detail in just a minute when we run the container. And that brings us to our final instruction, command.

There can only be one of these per Docker file, and it tells the container how to run the actual application, which it does by starting a process to serve the Express app. You'll also notice that unlike run, we've made this command an array of strings. This is known as exec form, and it's the preferred way to do things.

Unlike a regular command, it doesn't start up a shell session. And that's basically all there is to it. We now have a full set of instructions for building a Docker image. And that brings us to the next question. How do we build a Docker image? You build a Docker image by running the Docker build command. There's a lot of different options you can pass with the command, but the one you want to know for right now is tag or t.

This will give your image a name tag that's easy to remember so you can access it later. When defining the tag name, I'd first recommend setting up a username on Docker hub, and then do that username followed by whatever you want to call this image. So in my case, it would be fire ship slash demo app. And you could also add a version number separated by a colon.

From there, you simply add the path to your Docker file, which in our case is just a period for the current working directory. When we run it, you'll notice it starts with step one, which is to pull the node 12 image remotely. Then it goes through each step in our Docker file, and finally it says successfully built the image ID.

And now that we have this image, we can use it as a base image to create other images, or we can use it to run containers. In real life, to use this image, you'll most likely push it to a container registry somewhere. That might be Docker hub or your favorite cloud provider. And the command you would use to do that is Docker push.

Then a developer or server somewhere else in the world could use Docker pull to pull that image back down. But we just want to run it here locally in our system. So let's do that with the Docker run command. We can supply it with the image ID or the tag name. And all that does is create a running process called a container.

And we can see in the terminal, it should say app listening on localhost 8080. But if we open the browser and go to that address, we don't see anything. So why can't I access my container locally? Remember, we exposed port 8080 in our Docker file, but by default, it's not accessible to the outside world.

Let's refactor our command to use the P flag to implement port forwarding from the Docker container to our local machine. On the left side, we'll map a port on our local machine, 5000 in this case, to a port on the Docker container 8080 on the right side. And now if we open the browser and go to localhost 5000, we'll see the app running there.

Now one thing to keep in mind at this point is that the Docker container will still be running even after you close the terminal window. Let's go ahead and open up the dashboard and stop the container. You should actually have two running containers here if you've been following along. When you stop the container, any state or data that you created inside of it will be lost.

But there can be situations where you want to share data across multiple containers. And the preferred way to do that is with volumes. A volume is just a dedicated folder on the host machine. And inside this folder, a container can create files that can be remounted into future containers or multiple containers at the same time.

To create a volume, we use the Docker volume create command. Now that we have this volume, we can mount it somewhere in our container when we run it. Multiple containers can mount this volume simultaneously and access the same set of files. And the files stick around after all the containers are shut down.

Now that you know how to run a container, let's talk a little bit about debugging. When things don't go as planned, you might be wondering, how do I inspect the logs and how do I get into my container and start interacting with the command line? Well, this is where Docker desktop really comes in handy. If you click on the running container, you can see all the logs right there, and you can even search through them.

You can also execute commands in your container by clicking on the CLI button. And keep in mind, you can also do this from your own command line using the Docker exec command. In any case, it puts us in the root of the file system of that container so we can then LS to see files or do whatever we want in our Linux environment.

That's useful to know, but one of the best things you can do to keep your containers healthy is to write simple, maintainable microservices. Each container should only run one process. And if your app needs multiple processes, then you should use multiple containers. And Docker has a tool designed just for that called Docker Compose.

It's just a tool for running multiple Docker containers at the same time. We already have a Docker file for our Node app, but let's imagine that our Node app also needs to access a MySQL database. And we also likely want a volume to persist the database across multiple containers. We can manage all that with Docker Compose by creating a docker-compose.yaml file in the root of our project.

Frequently asked questions

A Docker file is a blueprint for building a Docker image, a Docker image is a template for running Docker containers, and a container is a running process.

You build a Docker image by running the Docker build command, specifying the tag name and the path to your Docker file.

A volume is a dedicated folder on the host machine where a container can create files that can be remounted into future containers or multiple containers at the same time.