A complete introduction to Docker. Learn how to Dockerize a Node.js and run manage multiple containers with Docker Compose. https://fireship.io/lessons/docker-basics-tutorial-nodejs

00:00 What is Docker?
01:54 Installation & Tooling
02:40 Dockerfile
06:06 Build an Image
07:12 Run a Container
08:52 Debugging
09:35 Docker Compose

Source code https://github.com/fireship-io/fireship.io
Official Docker https://www.docker.com

#LearnToCode #Docker 

Install the quiz app 🤓

iOS https://itunes.apple.com/us/app/fireship/id1462592372?mt=8
Android https://play.google.com/store/apps/details?id=io.fireship.quizapp

Upgrade to Fireship PRO at https://fireship.io/pro
Use code lORhwXd2 for 25% off your first payment. 

My VS Code Theme

- Atom One Dark 
- vscode-icons
- Fira Code Font
2024-02-04T06:09:00.427Z
nova-2
2-general-nova
2024-01-09.29447
30089e05-99d1-4376-b32e-c263170674af
45ecbc09-5c38-4b08-96f1-da5dc7683790
9a0680b4b60d033d60a80291ced51dbeffb39194dba2ae43de9f4d205e454a89
67875a7f-c9c4-48a0-aa55-5bdb8a91c34a
deprecated
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 3 things that you absolutely must know, Docker files, else, images, and containers.
A Docker file is a blueprint for building a Docker image.
A Docker image is a template for running Docker or 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 environment.
The developer who creates the software can define the environment with a Dockerfile.
Then any developer at that point can use the Dockerfile 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 spec, you're running containers.
Once installed, you should have access to Docker from the command line.
And here's the first command you should memorize, docker, which gives you a list of all the running containers on your system.
You'll notice how every container has a unique ID and 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 Versus 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 Dockerfile, 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 Dockerfile in the root of the project.
The first instruction in our Dockerfile is scrum.
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 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 wanna 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 Dockerfile 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 Dockerfile 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 2 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 install 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 ports in 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 Dockerfile, 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 wanna 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 fireship 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 1, which is to pull the node 12 image remotely.
Then it goes through each step in our Dockerfile, 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 wanna 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 local host 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 Dockerfile, 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, 5,000 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 local host 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 2 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 Dockerfile 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 full containers.
We can manage all that with Docker Compose by creating a docker dash compose dot YAML file in the root of our project.
Inside that file, we have a services object where each key in that object represents a different container that we want to run.
We'll use web to define our Node JS app that we've already built, and then we'll use build to point it to the current working directory, which is where it can find the Dockerfile.
And then we'll also define the port forwarding configuration here as well.
Then we have a separate container called DB, which is our MySQL database process.
After services, we'll also define a volume to store the database data across multiple containers, and then we can mount that volume in our DB container.
And, hopefully, you're starting to see how much easier it is to define this stuff as YAML as opposed to writing it out as individual commands.
And now that we have this configuration set, we can run Docker Compose up from the command line, which will find this file and run all the containers together.
We can mess around with our app for a little while and then run Docker Compose down to shut down all the containers together.
I'm gonna go ahead and wrap things up there.
If this video helped you, please like and scribe, and consider becoming a pro member at FireShip IO, where we use Docker in a variety of different project based courses.
Thanks for watching, and I will see you in the next one.

Speaker 0: 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 3 things that you absolutely must know, Docker files, else, images, and containers. A Docker file is a blueprint for building a Docker image. A Docker image is a template for running Docker or 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 environment. The developer who creates the software can define the environment with a Dockerfile. Then any developer at that point can use the Dockerfile 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 spec, you're running containers. Once installed, you should have access to Docker from the command line. And here's the first command you should memorize, docker, which gives you a list of all the running containers on your system. You'll notice how every container has a unique ID and 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 Versus 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 Dockerfile, 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 Dockerfile in the root of the project.

The first instruction in our Dockerfile is scrum. 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 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 wanna 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 Dockerfile 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 Dockerfile 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 2 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 install 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 ports in 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 Dockerfile, 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 wanna 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 fireship 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 1, which is to pull the node 12 image remotely. Then it goes through each step in our Dockerfile, 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 wanna 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 local host 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 Dockerfile, 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, 5,000 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 local host 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 2 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 Dockerfile 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 full containers. We can manage all that with Docker Compose by creating a docker dash compose dot YAML file in the root of our project. Inside that file, we have a services object where each key in that object represents a different container that we want to run.

We'll use web to define our Node JS app that we've already built, and then we'll use build to point it to the current working directory, which is where it can find the Dockerfile. And then we'll also define the port forwarding configuration here as well. Then we have a separate container called DB, which is our MySQL database process. After services, we'll also define a volume to store the database data across multiple containers, and then we can mount that volume in our DB container. And, hopefully, you're starting to see how much easier it is to define this stuff as YAML as opposed to writing it out as individual commands.

And now that we have this configuration set, we can run Docker Compose up from the command line, which will find this file and run all the containers together. We can mess around with our app for a little while and then run Docker Compose down to shut down all the containers together. I'm gonna go ahead and wrap things up there. If this video helped you, please like and scribe, and consider becoming a pro member at FireShip IO, where we use Docker in a variety of different project based courses. Thanks for watching, and I will see you in the next one.
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.
boats
Now in order to understand how that process works, there are 3 things that you absolutely must know, Docker files, else, images, and containers. A Docker file is a blueprint for building a Docker image. A Docker image is a template for running Docker or 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 environment. The developer who creates the software can define the environment with a Dockerfile.
Then any developer at that point can use the Dockerfile 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.
photography
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 spec, you're running containers. Once installed, you should have access to Docker from the command line.
And here's the first command you should memorize, docker, which gives you a list of all the running containers on your system. You'll notice how every container has a unique ID and is also linked to an image. And keep in mind you can find the same information from the GUI as well.
boats
Now the other thing you want to install is the Docker extension for Versus 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 Dockerfile, 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.
multimedia
streaming
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 Dockerfile in the root of the project. The first instruction in our Dockerfile is scrum. 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 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 wanna 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 Dockerfile 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 Dockerfile 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 2 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 install 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 ports in 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 Dockerfile, 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 wanna 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 fireship 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 1, which is to pull the node 12 image remotely. Then it goes through each step in our Dockerfile, 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.
photography
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 wanna 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 local host 8080.
software
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 Dockerfile, 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, 5,000 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 local host 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 2 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.
databases
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.
systems
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 Dockerfile 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 full containers.
databases
We can manage all that with Docker Compose by creating a docker dash compose dot YAML file in the root of our project. Inside that file, we have a services object where each key in that object represents a different container that we want to run. We'll use web to define our Node JS app that we've already built, and then we'll use build to point it to the current working directory, which is where it can find the Dockerfile.
And then we'll also define the port forwarding configuration here as well. Then we have a separate container called DB, which is our MySQL database process. After services, we'll also define a volume to store the database data across multiple containers, and then we can mount that volume in our DB container. And, hopefully, you're starting to see how much easier it is to define this stuff as YAML as opposed to writing it out as individual commands.
databases
data management
And now that we have this configuration set, we can run Docker Compose up from the command line, which will find this file and run all the containers together. We can mess around with our app for a little while and then run Docker Compose down to shut down all the containers together. I'm gonna go ahead and wrap things up there.
If this video helped you, please like and scribe, and consider becoming a pro member at FireShip IO, where we use Docker in a variety of different project based courses. Thanks for watching, and I will see you in the next one.
media
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 3 things that you absolutely must know, Docker files, else, images, and containers. A Docker file is a blueprint for building a Docker image. A Docker image is a template for running Docker or 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 environment. The developer who creates the software can define the environment with a Dockerfile. Then any developer at that point can use the Dockerfile 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 spec, you're running containers. Once installed, you should have access to Docker from the command line. And here's the first command you should memorize, docker, which gives you a list of all the running containers on your system. You'll notice how every container has a unique ID and 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 Versus 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 Dockerfile, 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 Dockerfile in the root of the project. The first instruction in our Dockerfile is scrum. 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 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 wanna 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 Dockerfile 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 Dockerfile 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 2 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 install 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 ports in 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 Dockerfile, 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 wanna 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 fireship 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 1, which is to pull the node 12 image remotely. Then it goes through each step in our Dockerfile, 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 wanna 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 local host 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 Dockerfile, 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, 5,000 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 local host 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 2 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 Dockerfile 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 full containers. We can manage all that with Docker Compose by creating a docker dash compose dot YAML file in the root of our project. Inside that file, we have a services object where each key in that object represents a different container that we want to run. We'll use web to define our Node JS app that we've already built, and then we'll use build to point it to the current working directory, which is where it can find the Dockerfile. And then we'll also define the port forwarding configuration here as well. Then we have a separate container called DB, which is our MySQL database process. After services, we'll also define a volume to store the database data across multiple containers, and then we can mount that volume in our DB container. And, hopefully, you're starting to see how much easier it is to define this stuff as YAML as opposed to writing it out as individual commands. And now that we have this configuration set, we can run Docker Compose up from the command line, which will find this file and run all the containers together. We can mess around with our app for a little while and then run Docker Compose down to shut down all the containers together. I'm gonna go ahead and wrap things up there. If this video helped you, please like and scribe, and consider becoming a pro member at FireShip IO, where we use Docker in a variety of different project based courses. Thanks for watching, and I will see you in the next one.
One
one
of
of
the
the
leading
leading
causes
causes
of
of
imposter
imposter
syndrome
syndrome
among
among
developers
developers
is
is
not
not
knowing
knowing
Docker.
docker
It
it
makes
makes
it
it
hard
hard
to
to
go
go
to
to
parties
parties
where
where
everybody's
everybody's
talking
talking
about
about
Kubernetes,
kubernetes
swarms,
swarms
shuffle
shuffle
sharding,
sharding
while
while
you
you
hide
hide
in
in
the
the
corner
corner
googling,
googling
what
what
is
is
a
a
container?
container
We've
we've
all
all
been
been
there
there
at
at
one
one
point
point
or
or
another.
another
In
in
today's
today's
video,
video
you'll
you'll
learn
learn
everything
everything
you
you
need
need
to
to
know
know
about
about
Docker
docker
to
to
survive
survive
as
as
a
a
developer
developer
in
in
2020.
2020
We'll
we'll
take
take
a
a
hands
hands
on
on
approach
approach
by
by
containerizing
containerizing
a
a
Node
node
JS
js
application.
application
I'll
i'll
assume
assume
you've
you've
never
never
touched
touched
a
a
Docker
docker
container
container
before,
before
so
so
we'll
we'll
go
go
through
through
installation
installation
and
and
tooling
tooling
as
as
well
well
as
as
the
the
most
most
important
important
instructions
instructions
in
in
a
a
Docker
docker
file.
file
In
in
addition,
addition
we'll
we'll
look
look
at
at
very
very
important
important
advanced
advanced
concepts
concepts
like
like
port
port
forwarding,
forwarding
volumes,
volumes
and
and
how
how
to
to
manage
manage
multiple
multiple
containers
containers
with
with
Docker
docker
Compose.
compose
We'll
we'll
do
do
everything
everything
step
step
by
by
step,
step
so
so
feel
feel
free
free
to
to
skip
skip
ahead
ahead
with
with
the
the
chapters
chapters
in
in
the
the
video
video
description.
description
What
what
is
is
Docker?
docker
From
from
a
a
practical
practical
standpoint,
standpoint
it's
it's
just
just
a
a
way
way
to
to
package
package
software
software
so
so
it
it
can
can
run
run
on
on
any
any
hardware.
hardware
Now
now
in
in
order
order
to
to
understand
understand
how
how
that
that
process
process
works,
works
there
there
are
are
3
3
things
things
that
that
you
you
absolutely
absolutely
must
must
know,
know
Docker
docker
files,
files
else,
else
images,
images
and
and
containers.
containers
A
a
Docker
docker
file
file
is
is
a
a
blueprint
blueprint
for
for
building
building
a
a
Docker
docker
image.
image
A
a
Docker
docker
image
image
is
is
a
a
template
template
for
for
running
running
Docker
docker
or
or
containers.
containers
A
a
container
container
is
is
just
just
a
a
running
running
process.
process
In
in
our
our
case,
case
we
we
have
have
a
a
node
node
application.
application
We
we
need
need
to
to
have
have
a
a
server
server
that's
that's
running
running
the
the
same
same
version
version
of
of
node
node
and
and
that
that
has
has
also
also
installed
installed
these
these
dependencies.
dependencies
It
it
works
works
on
on
my
my
machine,
machine
but
but
if
if
someone
someone
else
else
with
with
a
a
different
different
machine
machine
tries
tries
to
to
run
run
it
it
with
with
a
a
different
different
version
version
of
of
Node,
node
it
it
might
might
break.
break
The
the
whole
whole
point
point
of
of
Docker
docker
is
is
to
to
solve
solve
problems
problems
like
like
this
this
by
by
reproducing
reproducing
environment.
environment
The
the
developer
developer
who
who
creates
creates
the
the
software
software
can
can
define
define
the
the
environment
environment
with
with
a
a
Dockerfile.
dockerfile
Then
then
any
any
developer
developer
at
at
that
that
point
point
can
can
use
use
the
the
Dockerfile
dockerfile
to
to
rebuild
rebuild
the
the
environment,
environment
which
which
is
is
saved
saved
as
as
an
an
immutable
immutable
snapshot
snapshot
known
known
as
as
an
an
image.
image
Images
images
can
can
be
be
uploaded
uploaded
to
to
the
the
cloud
cloud
in
in
both
both
public
public
and
and
private
private
registries,
registries
then
then
any
any
developer
developer
or
or
server
server
that
that
wants
wants
to
to
run
run
that
that
software
software
can
can
pull
pull
the
the
image
image
down
down
to
to
create
create
a
a
container,
container
which
which
is
is
just
just
a
a
running
running
process
process
of
of
that
that
image.
image
In
in
other
other
words,
words
one
one
image
image
file
file
can
can
be
be
used
used
to
to
spawn
spawn
the
the
same
same
process
process
multiple
multiple
times
times
in
in
multiple
multiple
places.
places
And
and
it's
it's
at
at
that
that
point
point
where
where
tools
tools
like
like
Kubernetes
kubernetes
and
and
Swarm
swarm
come
come
into
into
play
play
to
to
scale
scale
containers
containers
to
to
an
an
infinite
infinite
workload.
workload
The
the
best
best
way
way
to
to
really
really
learn
learn
Docker
docker
is
is
to
to
use
use
it,
it
and
and
to
to
use
use
it,
it
we
we
need
need
to
to
install
install
it.
it
If
if
you're
you're
on
on
Mac
mac
or
or
Windows,
windows
I
i
would
would
highly
highly
recommend
recommend
installing
installing
the
the
Docker
docker
Desktop
desktop
application.
application
It
it
installs
installs
everything
everything
you
you
need
need
for
for
the
the
command
command
line
line
and
and
also
also
gives
gives
you
you
a
a
GUI
gui
where
where
you
you
can
can
spec,
spec
you're
you're
running
running
containers.
containers
Once
once
installed,
installed
you
you
should
should
have
have
access
access
to
to
Docker
docker
from
from
the
the
command
command
line.
line
And
and
here's
here's
the
the
first
first
command
command
you
you
should
should
memorize,
memorize
docker,
docker
which
which
gives
gives
you
you
a
a
list
list
of
of
all
all
the
the
running
running
containers
containers
on
on
your
your
system.
system
You'll
you'll
notice
notice
how
how
every
every
container
container
has
has
a
a
unique
unique
ID
id
and
and
is
is
also
also
linked
linked
to
to
an
an
image.
image
And
and
keep
keep
in
in
mind
mind
you
you
can
can
find
find
the
the
same
same
information
information
from
from
the
the
GUI
gui
as
as
well.
well
Now
now
the
the
other
other
thing
thing
you
you
want
want
to
to
install
install
is
is
the
the
Docker
docker
extension
extension
for
for
Versus
versus
code
code
or
or
for
for
your
your
IDE.
ide
This
this
will
will
give
give
you
you
language
language
support
support
when
when
you
you
write
write
your
your
Docker
docker
files
files
and
and
can
can
also
also
link
link
up
up
to
to
remote
remote
registries
registries
and
and
a
a
bunch
bunch
of
of
other
other
stuff.
stuff
Now
now
that
that
we
we
have
have
Docker
docker
installed,
installed
we
we
can
can
move
move
on
on
to
to
what
what
is
is
probably
probably
the
the
most
most
important
important
section
section
of
of
this
this
video.
video
And
and
that's
that's
the
the
Dockerfile,
dockerfile
which
which
contains
contains
code
code
to
to
build
build
your
your
Docker
docker
image
image
and
and
ultimately
ultimately
run
run
your
your
app
app
as
as
a
a
container.
container
Now
now
to
to
follow
follow
along
along
at
at
this
this
point,
point
you
you
can
can
grab
grab
my
my
source
source
code
code
from
from
GitHub
github
or
or
Fireship
fireship
IO,
io
or
or
better
better
yet,
yet
use
use
your
your
own
own
application
application
as
as
a
a
starting
starting
point.
point
In
in
this
this
case,
case
I
i
just
just
have
have
a
a
single
single
index
index
JS
js
file
file
that
that
exposes
exposes
an
an
API
api
endpoint
endpoint
that
that
sends
sends
back
back
a
a
response.
response
Docker
docker
is
is
easy.
easy
Then
then
we
we
expose
expose
our
our
app
app
using
using
the
the
port
port
environment
environment
variable,
variable
and
and
that'll
that'll
come
come
into
into
play
play
later.
later
The
the
question
question
we're
we're
faced
faced
with
with
now
now
is
is
how
how
do
do
we
we
dockerize
dockerize
this
this
app?
app
We'll
we'll
start
start
by
by
creating
creating
a
a
Dockerfile
dockerfile
in
in
the
the
root
root
of
of
the
the
project.
project
The
the
first
first
instruction
instruction
in
in
our
our
Dockerfile
dockerfile
is
is
scrum.
scrum
And
and
if
if
you
you
hover
hover
over
over
it,
it
it
it
will
will
give
give
you
you
some
some
documentation
documentation
about
about
what
what
it
it
does.
does
You
you
could
could
start
start
from
from
scratch
scratch
with
with
nothing
nothing
but
but
the
the
Docker
docker
runtime.
runtime
However,
however
most
most
Docker
docker
files
files
will
will
start
start
with
with
a
a
specific
specific
base
base
image.
image
For
for
example,
example
when
when
I
i
type
type
Ubuntu,
ubuntu
you'll
you'll
notice
notice
it's
it's
underlined,
underlined
and
and
when
when
I
i
control
control
click
click
it,
it
it
it
will
will
take
take
me
me
to
to
all
all
the
the
base
base
images
images
for
for
this
this
flavor
flavor
of
of
Linux.
linux
And
and
then
then
you'll
you'll
notice
notice
it
it
supports
supports
a
a
variety
variety
of
of
different
different
tags,
tags
which
which
are
are
just
just
different
different
variations
variations
on
on
this
this
base
base
image.
image
Ubuntu
ubuntu
doesn't
doesn't
have
have
Node
node
JS
js
installed
installed
by
by
default.
default
We
we
could
could
still
still
use
use
this
this
image
image
and
and
install
install
Node
node
JS
js
manually.
manually
However,
however
there
there
is
is
a
a
better
better
option,
option
and
and
that's
that's
to
to
use
use
the
the
officially
officially
supported
supported
Node
node
JS
js
image.
image
We'll
we'll
go
go
ahead
ahead
and
and
use
use
the
the
node
node
version
version
12
12
base
base
image,
image
which
which
will
will
give
give
us
us
everything
everything
we
we
need
need
to
to
start
start
working
working
with
with
node
node
in
in
this
this
environment.
environment
The
the
next
next
thing
thing
we'll
we'll
wanna
wanna
do
do
is
is
add
add
our
our
app
app
source
source
code
code
to
to
the
the
image.
image
The
the
working
working
directory
directory
instruction
instruction
is
is
kind
kind
of
of
like
like
when
when
you
you
cd
cd
into
into
a
a
directory.
directory
Now
now
any
any
subsequent
subsequent
instructions
instructions
in
in
our
our
Dockerfile
dockerfile
will
will
start
start
from
from
this
this
app
app
directory.
directory
Now
now
at
at
this
this
point,
point
there
there
is
is
something
something
very
very
important
important
that
that
you
you
need
need
to
to
understand,
understand
and
and
that's
that's
that
that
every
every
instruction
instruction
in
in
this
this
Dockerfile
dockerfile
is
is
considered
considered
its
its
own
own
step
step
or
or
layer.
layer
In
in
order
order
to
to
keep
keep
things
things
efficient,
efficient
Docker
docker
will
will
attempt
attempt
to
to
cache
cache
layers
layers
if
if
nothing
nothing
has
has
actually
actually
changed.
changed
Now
now
normally,
normally
when
when
you're
you're
working
working
on
on
a
a
node
node
project,
project
You
you
get
get
your
your
source
source
code,
code
and
and
then
then
you
you
install
install
your
your
dependencies.
dependencies
But
but
in
in
Docker,
docker
we
we
actually
actually
want
want
to
to
install
install
our
our
dependencies
dependencies
first
first
so
so
they
they
can
can
be
be
cached.
cached
In
in
other
other
words,
words
we
we
don't
don't
want
want
to
to
have
have
to
to
reinstall
reinstall
all
all
of
of
our
our
node
node
modules
modules
every
every
time
time
we
we
change
change
our
our
app
app
source
source
code.
code
We
we
use
use
the
the
copy
copy
instruction,
instruction
which
which
takes
takes
2
2
arguments.
arguments
The
the
first
first
argument
argument
is
is
our
our
local
local
package
package
JSON
json
location,
location
and
and
then
then
the
the
second
second
argument
argument
is
is
the
the
place
place
we
we
want
want
to
to
copy
copy
it
it
in
in
the
the
container,
container
which
which
is
is
the
the
current
current
working
working
directory.
directory
And
and
now
now
that
that
we
we
have
have
a
a
package
package
JSON,
json
we
we
can
can
run
run
the
the
npm
npm
install
install
command.
command
This
this
is
is
just
just
like
like
opening
opening
a
a
terminal
terminal
session
session
and
and
running
running
a
a
command.
command
And
and
when
when
it's
it's
finished,
finished
the
the
results
results
will
will
be
be
committed
committed
to
to
the
the
Docker
docker
image
image
as
as
a
a
layer.
layer
Now
now
that
that
we
we
have
have
our
our
modules
modules
in
in
the
the
image,
image
we
we
can
can
then
then
copy
copy
over
over
our
our
source
source
code,
code
which
which
we'll
we'll
do
do
by
by
copying
copying
over
over
all
all
of
of
our
our
local
local
files
files
to
to
the
the
current
current
working
working
directory.
directory
But
but
this
this
actually
actually
creates
creates
a
a
problem
problem
for
for
us
us
because
because
you'll
you'll
notice
notice
that
that
we
we
have
have
a
a
node
node
modules
modules
folder
folder
here
here
in
in
our
our
local
local
file
file
system
system
that
that
would
would
also
also
be
be
copied
copied
over
over
to
to
the
the
image
image
and
and
override
override
the
the
node
node
modules
modules
that
that
we
we
install
install
there.
there
What
what
we
we
need
need
is
is
some
some
kind
kind
of
of
way
way
for
for
Docker
docker
to
to
ignore
ignore
our
our
local
local
node
node
modules.
modules
We
we
can
can
do
do
that
that
by
by
creating
creating
a
a
Docker
docker
ignore
ignore
file
file
and
and
adding
adding
node
node
modules
modules
to
to
it.
it
It
it
works
works
just
just
like
like
a
a
git
git
ignore
ignore
file,
file
which
which
you've
you've
probably
probably
seen
seen
before.
before
Okay.
okay
So
so
at
at
this
this
point,
point
we
we
have
have
our
our
source
source
code
code
in
in
the
the
Docker
docker
image,
image
but
but
in
in
order
order
to
to
run
run
our
our
code,
code
we're
we're
using
using
an
an
environment
environment
variable.
variable
We
we
can
can
set
set
that
that
environment
environment
variable
variable
in
in
the
the
container
container
using
using
the
the
env
env
instruction.
instruction
Now
now
when
when
we
we
actually
actually
have
have
a
a
running
running
container,
container
we
we
also
also
want
want
it
it
to
to
be
be
listening
listening
on
on
port
port
8080
8080
so
so
we
we
can
can
access
access
the
the
Node.
node
Js
js
express
express
app
app
publicly.
publicly
And
and
we'll
we'll
look
look
at
at
ports
ports
in
in
more
more
detail
detail
in
in
just
just
a
a
minute
minute
when
when
we
we
run
run
the
the
container.
container
And
and
that
that
brings
brings
us
us
to
to
our
our
final
final
instruction,
instruction
command.
command
There
there
can
can
only
only
be
be
one
one
of
of
these
these
per
per
Dockerfile,
dockerfile
and
and
it
it
tells
tells
the
the
container
container
how
how
to
to
run
run
the
the
actual
actual
application,
application
which
which
it
it
does
does
by
by
starting
starting
a
a
process
process
to
to
serve
serve
the
the
express
express
app.
app
You'll
you'll
also
also
notice
notice
that
that
unlike
unlike
run,
run
we've
we've
made
made
this
this
command
command
an
an
array
array
of
of
strings.
strings
This
this
is
is
known
known
as
as
exec
exec
form,
form
and
and
it's
it's
the
the
preferred
preferred
way
way
to
to
do
do
things.
things
Unlike
unlike
a
a
regular
regular
command,
command
it
it
doesn't
doesn't
start
start
up
up
a
a
shell
shell
session.
session
And
and
that's
that's
basically
basically
all
all
there
there
is
is
to
to
it.
it
We
we
now
now
have
have
a
a
full
full
set
set
of
of
instructions
instructions
for
for
building
building
a
a
Docker
docker
image.
image
And
and
that
that
brings
brings
us
us
to
to
the
the
next
next
question,
question
how
how
do
do
we
we
build
build
a
a
Docker
docker
image?
image
You
you
build
build
a
a
Docker
docker
image
image
by
by
running
running
the
the
Docker
docker
build
build
command.
command
There's
there's
a
a
lot
lot
of
of
different
different
options
options
you
you
can
can
pass
pass
with
with
the
the
command,
command
but
but
the
the
one
one
you
you
wanna
wanna
know
know
for
for
right
right
now
now
is
is
tag
tag
or
or
t.
t
This
this
will
will
give
give
your
your
image
image
a
a
name
name
tag
tag
that's
that's
easy
easy
to
to
remember
remember
so
so
you
you
can
can
access
access
it
it
later.
later
When
when
defining
defining
the
the
tag
tag
name,
name
I'd
i'd
first
first
recommend
recommend
setting
setting
up
up
a
a
username
username
on
on
Docker
docker
Hub
hub
and
and
then
then
do
do
that
that
username
username
followed
followed
by
by
whatever
whatever
you
you
want
want
to
to
call
call
this
this
image.
image
So
so
in
in
my
my
case,
case
it
it
would
would
be
be
fireship
fireship
slash
slash
demo
demo
app,
app
and
and
you
you
could
could
also
also
add
add
a
a
version
version
number
number
separated
separated
by
by
a
a
colon.
colon
From
from
there,
there
you
you
simply
simply
add
add
the
the
path
path
to
to
your
your
Docker
docker
file,
file
which
which
in
in
our
our
case
case
is
is
just
just
a
a
period
period
for
for
the
the
current
current
working
working
directory.
directory
When
when
we
we
run
run
it,
it
you'll
you'll
notice
notice
it
it
starts
starts
with
with
step
step
1,
1
which
which
is
is
to
to
pull
pull
the
the
node
node
12
12
image
image
remotely.
remotely
Then
then
it
it
goes
goes
through
through
each
each
step
step
in
in
our
our
Dockerfile,
dockerfile
and
and
finally
finally
it
it
says
says
successfully
successfully
built
built
the
the
image
image
ID.
id
And
and
now
now
that
that
we
we
have
have
this
this
image,
image
we
we
can
can
use
use
it
it
as
as
a
a
base
base
image
image
to
to
create
create
other
other
images
images
or
or
we
we
can
can
use
use
it
it
to
to
run
run
containers.
containers
In
in
real
real
life,
life
to
to
use
use
this
this
image,
image
you'll
you'll
most
most
likely
likely
push
push
it
it
to
to
a
a
container
container
registry
registry
somewhere.
somewhere
That
that
might
might
be
be
Docker
docker
Hub
hub
or
or
your
your
favorite
favorite
cloud
cloud
provider.
provider
And
and
the
the
command
command
you
you
would
would
use
use
to
to
do
do
that
that
is
is
Docker
docker
push.
push
Then
then
a
a
developer
developer
or
or
server
server
somewhere
somewhere
else
else
in
in
the
the
world
world
could
could
use
use
Docker
docker
pull
pull
to
to
pull
pull
that
that
image
image
back
back
down.
down
But
but
we
we
just
just
wanna
wanna
run
run
it
it
here
here
locally
locally
in
in
our
our
system.
system
So
so
let's
let's
do
do
that
that
with
with
the
the
Docker
docker
run
run
command.
command
We
we
can
can
supply
supply
it
it
with
with
the
the
image
image
ID
id
or
or
the
the
tag
tag
name,
name
and
and
all
all
that
that
does
does
is
is
create
create
a
a
running
running
process
process
called
called
a
a
container.
container
And
and
we
we
can
can
see
see
in
in
the
the
terminal,
terminal
it
it
should
should
say
say
app
app
listening
listening
on
on
local
local
host
host
8080.
8080
But
but
if
if
we
we
open
open
the
the
browser
browser
and
and
go
go
to
to
that
that
address,
address
we
we
don't
don't
see
see
anything.
anything
So
so
why
why
can't
can't
I
i
access
access
my
my
container
container
locally?
locally
Remember,
remember
we
we
exposed
exposed
port
port
8080
8080
in
in
our
our
Dockerfile,
dockerfile
but
but
by
by
default,
default
it's
it's
not
not
accessible
accessible
to
to
the
the
outside
outside
world.
world
Let's
let's
refactor
refactor
our
our
command
command
to
to
use
use
the
the
p
p
flag
flag
to
to
implement
implement
port
port
forwarding
forwarding
from
from
the
the
Docker
docker
container
container
to
to
our
our
local
local
machine.
machine
On
on
the
the
left
left
side,
side
we'll
we'll
map
map
a
a
port
port
on
on
our
our
local
local
machine,
machine
5,000
5,000
in
in
this
this
case,
case
to
to
a
a
port
port
on
on
the
the
Docker
docker
container
container
8080
8080
on
on
the
the
right
right
side.
side
And
and
now
now
if
if
we
we
open
open
the
the
browser
browser
and
and
go
go
to
to
local
local
host
host
5000,
5000
we'll
we'll
see
see
the
the
app
app
running
running
there.
there
Now
now
one
one
thing
thing
to
to
keep
keep
in
in
mind
mind
at
at
this
this
point
point
is
is
that
that
the
the
Docker
docker
container
container
will
will
still
still
be
be
running
running
even
even
after
after
you
you
close
close
the
the
terminal
terminal
window.
window
Let's
let's
go
go
ahead
ahead
and
and
open
open
up
up
the
the
dashboard
dashboard
and
and
stop
stop
the
the
container.
container
You
you
should
should
actually
actually
have
have
2
2
running
running
containers
containers
here
here
if
if
you've
you've
been
been
following
following
along.
along
When
when
you
you
stop
stop
the
the
container,
container
any
any
state
state
or
or
data
data
that
that
you
you
created
created
inside
inside
of
of
it
it
will
will
be
be
lost.
lost
But
but
there
there
can
can
be
be
situations
situations
where
where
you
you
want
want
to
to
share
share
data
data
across
across
multiple
multiple
containers,
containers
and
and
the
the
preferred
preferred
way
way
to
to
do
do
that
that
is
is
with
with
volumes.
volumes
A
a
volume
volume
is
is
just
just
a
a
dedicated
dedicated
folder
folder
on
on
the
the
host
host
machine.
machine
And
and
inside
inside
this
this
folder,
folder
a
a
container
container
can
can
create
create
files
files
that
that
can
can
be
be
remounted
remounted
into
into
future
future
containers
containers
or
or
multiple
multiple
containers
containers
at
at
the
the
same
same
time.
time
To
to
create
create
a
a
volume,
volume
we
we
use
use
the
the
Docker
docker
volume
volume
create
create
command.
command
Now
now
that
that
we
we
have
have
this
this
volume,
volume
we
we
can
can
mount
mount
it
it
somewhere
somewhere
in
in
our
our
container
container
when
when
we
we
run
run
it.
it
Multiple
multiple
containers
containers
can
can
mount
mount
this
this
volume
volume
simultaneously
simultaneously
and
and
access
access
the
the
same
same
set
set
of
of
files,
files
and
and
the
the
files
files
stick
stick
around
around
after
after
all
all
the
the
containers
containers
are
are
shut
shut
down.
down
Now
now
that
that
you
you
know
know
how
how
to
to
run
run
a
a
container,
container
let's
let's
talk
talk
a
a
little
little
bit
bit
about
about
debugging.
debugging
When
when
things
things
don't
don't
go
go
as
as
planned,
planned
you
you
might
might
be
be
wondering,
wondering
how
how
do
do
I
i
inspect
inspect
the
the
logs
logs
and
and
how
how
do
do
I
i
get
get
into
into
my
my
container
container
and
and
start
start
interacting
interacting
with
with
the
the
command
command
line?
line
Well,
well
this
this
is
is
where
where
Docker
docker
Desktop
desktop
really
really
comes
comes
in
in
handy.
handy
If
if
you
you
click
click
on
on
the
the
running
running
container,
container
you
you
can
can
see
see
all
all
the
the
logs
logs
right
right
there,
there
and
and
you
you
can
can
even
even
search
search
through
through
them.
them
You
you
can
can
also
also
execute
execute
commands
commands
in
in
your
your
container
container
by
by
clicking
clicking
on
on
the
the
CLI
cli
button.
button
And
and
keep
keep
in
in
mind,
mind
you
you
can
can
also
also
do
do
this
this
from
from
your
your
own
own
command
command
line
line
using
using
the
the
Docker
docker
exec
exec
command.
command
In
in
any
any
case,
case
it
it
puts
puts
us
us
in
in
the
the
root
root
of
of
the
the
file
file
system
system
of
of
that
that
container
container
so
so
we
we
can
can
then
then
LS
ls
to
to
see
see
files
files
or
or
do
do
whatever
whatever
we
we
want
want
in
in
our
our
Linux
linux
environment.
environment
That's
that's
useful
useful
to
to
know,
know
but
but
one
one
of
of
the
the
best
best
things
things
you
you
can
can
do
do
to
to
keep
keep
your
your
containers
containers
healthy,
healthy
is
is
to
to
write
write
simple
simple
maintainable
maintainable
microservices.
microservices
Each
each
container
container
should
should
only
only
run
run
one
one
process.
process
And
and
if
if
your
your
app
app
needs
needs
multiple
multiple
processes,
processes
then
then
you
you
should
should
use
use
multiple
multiple
containers.
containers
And
and
Docker
docker
has
has
a
a
tool
tool
designed
designed
just
just
for
for
that
that
called
called
Docker
docker
Compose.
compose
It's
it's
just
just
a
a
tool
tool
for
for
running
running
multiple
multiple
Docker
docker
containers
containers
at
at
the
the
same
same
time.
time
We
we
already
already
have
have
a
a
Dockerfile
dockerfile
for
for
our
our
node
node
app,
app
but
but
let's
let's
imagine
imagine
that
that
our
our
node
node
app
app
also
also
needs
needs
to
to
access
access
a
a
MySQL
mysql
database,
database
and
and
we
we
also
also
likely
likely
want
want
a
a
volume
volume
to
to
persist
persist
the
the
database
database
across
across
multiple
multiple
full
full
containers.
containers
We
we
can
can
manage
manage
all
all
that
that
with
with
Docker
docker
Compose
compose
by
by
creating
creating
a
a
docker
docker
dash
dash
compose
compose
dot
dot
YAML
yaml
file
file
in
in
the
the
root
root
of
of
our
our
project.
project
Inside
inside
that
that
file,
file
we
we
have
have
a
a
services
services
object
object
where
where
each
each
key
key
in
in
that
that
object
object
represents
represents
a
a
different
different
container
container
that
that
we
we
want
want
to
to
run.
run
We'll
we'll
use
use
web
web
to
to
define
define
our
our
Node
node
JS
js
app
app
that
that
we've
we've
already
already
built,
built
and
and
then
then
we'll
we'll
use
use
build
build
to
to
point
point
it
it
to
to
the
the
current
current
working
working
directory,
directory
which
which
is
is
where
where
it
it
can
can
find
find
the
the
Dockerfile.
dockerfile
And
and
then
then
we'll
we'll
also
also
define
define
the
the
port
port
forwarding
forwarding
configuration
configuration
here
here
as
as
well.
well
Then
then
we
we
have
have
a
a
separate
separate
container
container
called
called
DB,
db
which
which
is
is
our
our
MySQL
mysql
database
database
process.
process
After
after
services,
services
we'll
we'll
also
also
define
define
a
a
volume
volume
to
to
store
store
the
the
database
database
data
data
across
across
multiple
multiple
containers,
containers
and
and
then
then
we
we
can
can
mount
mount
that
that
volume
volume
in
in
our
our
DB
db
container.
container
And,
and
hopefully,
hopefully
you're
you're
starting
starting
to
to
see
see
how
how
much
much
easier
easier
it
it
is
is
to
to
define
define
this
this
stuff
stuff
as
as
YAML
yaml
as
as
opposed
opposed
to
to
writing
writing
it
it
out
out
as
as
individual
individual
commands.
commands
And
and
now
now
that
that
we
we
have
have
this
this
configuration
configuration
set,
set
we
we
can
can
run
run
Docker
docker
Compose
compose
up
up
from
from
the
the
command
command
line,
line
which
which
will
will
find
find
this
this
file
file
and
and
run
run
all
all
the
the
containers
containers
together.
together
We
we
can
can
mess
mess
around
around
with
with
our
our
app
app
for
for
a
a
little
little
while
while
and
and
then
then
run
run
Docker
docker
Compose
compose
down
down
to
to
shut
shut
down
down
all
all
the
the
containers
containers
together.
together
I'm
i'm
gonna
gonna
go
go
ahead
ahead
and
and
wrap
wrap
things
things
up
up
there.
there
If
if
this
this
video
video
helped
helped
you,
you
please
please
like
like
and
and
scribe,
scribe
and
and
consider
consider
becoming
becoming
a
a
pro
pro
member
member
at
at
FireShip
fireship
IO,
io
where
where
we
we
use
use
Docker
docker
in
in
a
a
variety
variety
of
of
different
different
project
project
based
based
courses.
courses
Thanks
thanks
for
for
watching,
watching
and
and
I
i
will
will
see
see
you
you
in
in
the
the
next
next
one.
one
success
The speaker explains the concept of Docker and provides step-by-step instructions on installing and managing it for developers. They also provide instructions on how to use the file directory and copy code from local files. The speaker emphasizes the importance of setting up a username and creating a running process to access a local machine, recommend setting up a password, and use Docker Compose to run multiple containers at the same time. They provide a detailed explanation on building a Docker image and recommend setting up a username and password to access a local machine.
Learn Docker in 7 Easy Steps - Full Beginner's Tutorial
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 3 things that you absolutely must know, Docker files, else, images, and containers. A Docker file is a blueprint for building a Docker image. A Docker image is a template for running Docker or 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 environment. The developer who creates the software can define the environment with a Dockerfile. Then any developer at that point can use the Dockerfile 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 spec, you're running containers. Once installed, you should have access to Docker from the command line. And here's the first command you should memorize, docker, which gives you a list of all the running containers on your system. You'll notice how every container has a unique ID and 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 Versus 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 Dockerfile, 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 Dockerfile in the root of the project. The first instruction in our Dockerfile is scrum. 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 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 wanna 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 Dockerfile 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 Dockerfile 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 2 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 install 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 ports in 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 Dockerfile, 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 wanna 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 fireship 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 1, which is to pull the node 12 image remotely. Then it goes through each step in our Dockerfile, 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 wanna 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 local host 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 Dockerfile, 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, 5,000 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 local host 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 2 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 Dockerfile 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 full containers. We can manage all that with Docker Compose by creating a docker dash compose dot YAML file in the root of our project. Inside that file, we have a services object where each key in that object represents a different container that we want to run. We'll use web to define our Node JS app that we've already built, and then we'll use build to point it to the current working directory, which is where it can find the Dockerfile. And then we'll also define the port forwarding configuration here as well. Then we have a separate container called DB, which is our MySQL database process. After services, we'll also define a volume to store the database data across multiple containers, and then we can mount that volume in our DB container. And, hopefully, you're starting to see how much easier it is to define this stuff as YAML as opposed to writing it out as individual commands. And now that we have this configuration set, we can run Docker Compose up from the command line, which will find this file and run all the containers together. We can mess around with our app for a little while and then run Docker Compose down to shut down all the containers together. I'm gonna go ahead and wrap things up there. If this video helped you, please like and scribe, and consider becoming a pro member at FireShip IO, where we use Docker in a variety of different project based courses. Thanks for watching, and I will see you in the next one.
The speaker explains the concept of Docker and provides step-by-step instructions on installing and managing it for developers. They also provide instructions on how to use the file directory and copy code from local files. The speaker emphasizes the importance of setting up a username and creating a running process to access a local machine, recommend setting up a password, and use Docker Compose to run multiple containers at the same time. They provide a detailed explanation on building a Docker image and recommend setting up a username and password to access a local machine.

        [INST]
        You are youtuber called Fireship you make engaging high-intensity and entertaining coding tutorials and tech news. 
        you covers a wide range of topics relevant to programmers, aiming to help them learn and improve their skills quickly.
        
        Given the title of the video : Learn Docker in 7 Easy Steps - Full Beginner's Tutorial 
        and a small summary : The speaker explains the concept of Docker and provides step-by-step instructions on installing and managing it for developers. They also provide instructions on how to use the file directory and copy code from local files. The speaker emphasizes the importance of setting up a username and creating a running process to access a local machine, recommend setting up a password, and use Docker Compose to run multiple containers at the same time. They provide a detailed explanation on building a Docker image and recommend setting up a username and password to access a local machine.
        [/INST]
        
        Generate the video : 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 3 things that you absolutely must know, Docker files, else, images, and containers. A Docker file is a blueprint for building a Docker image. A Docker image is a template for running Docker or 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 environment. The developer who creates the software can define the environment with a Dockerfile. Then any developer at that point can use the Dockerfile 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 spec, you're running containers. Once installed, you should have access to Docker from the command line. And here's the first command you should memorize, docker, which gives you a list of all the running containers on your system. You'll notice how every container has a unique ID and 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 Versus 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 Dockerfile, 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 Dockerfile in the root of the project. The first instruction in our Dockerfile is scrum. 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 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 wanna 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 Dockerfile 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 Dockerfile 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 2 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 install 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 ports in 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 Dockerfile, 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 wanna 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 fireship 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 1, which is to pull the node 12 image remotely. Then it goes through each step in our Dockerfile, 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 wanna 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 local host 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 Dockerfile, 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, 5,000 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 local host 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 2 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 Dockerfile 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 full containers. We can manage all that with Docker Compose by creating a docker dash compose dot YAML file in the root of our project. Inside that file, we have a services object where each key in that object represents a different container that we want to run. We'll use web to define our Node JS app that we've already built, and then we'll use build to point it to the current working directory, which is where it can find the Dockerfile. And then we'll also define the port forwarding configuration here as well. Then we have a separate container called DB, which is our MySQL database process. After services, we'll also define a volume to store the database data across multiple containers, and then we can mount that volume in our DB container. And, hopefully, you're starting to see how much easier it is to define this stuff as YAML as opposed to writing it out as individual commands. And now that we have this configuration set, we can run Docker Compose up from the command line, which will find this file and run all the containers together. We can mess around with our app for a little while and then run Docker Compose down to shut down all the containers together. I'm gonna go ahead and wrap things up there. If this video helped you, please like and scribe, and consider becoming a pro member at FireShip IO, where we use Docker in a variety of different project based courses. Thanks for watching, and I will see you in the next one.
        