In Intro to Docker (Part 1), I described what Docker is and how it works in theory.
To recap, Docker is a service that helps us package and isolate our code in containers. Containers are standardised, independent units of software and running instances of images. They contain our code and all required dependencies. Images are read-only templates for containers that are built by the Docker Engine and based on Dockerfiles. Dockerfiles are text files that you write that include all the commands needed to build a specific image in the order in which they should be executed.
Now that we've covered the most fundamental Docker concepts, let's take a look at how you can create your own Dockerfiles, images and containers, assuming you've already installed Docker on your machine.
How to create a Dockerfile
- To create your own Dockerfile, simply start by creating a file named Dockerfile 😄 It doesn't have an extension and shouldn't include one.
- If you want to create a base image, one that isn't based on an existing image, start by writing
However, most images are based on a base image, also called a parent image for that particular image. Since the exact process for a base image will depend on what you want to package, we will focus on creating an image with a parent image. If your code is written in Node.js, for example, you'd start by writing
- Then you specify the requirements needed for your particular image, using further commands. A full list of commands and their meaning can be found here.
- You usually end a Dockerfile with a command that will run when a container is started based on the image. If you'd like to run
app.jsin the container, for example, you'd write
If you specify several
CMD ["node", "app.js"]
CMD, only the last one will be executed. If you specify none, the
CMDof the parent image will be executed.
An example Dockerfile for a simple node application might look like this:
FROM node WORKDIR /app COPY ./someFolder /app RUN npm install EXPOSE 80 CMD ["node", "app.js"]
FROMspecifies the base image or parent image, in this case
WORKDIRtells Docker that all subsequent commands should be executed inside a particular folder, in this case the
COPYcopies the content of one folder into a folder in the image file system, in this case it will copy the contents of
appfolder. If the
appfolder doesn't exist yet, it will be created in the image file system. What you specify depends on which files on your local machine you want to go into the image
RUNspecifies the command that will be run when the image is created, in this case
npm installto install all the dependencies of your node application
EXPOSE, as you might have guessed it, exposes a specific port in the Docker container, in this case port 80, which can be accessed by a local machine
node server.jswill be run when a container is started
How to create Images and Containers
Once we have written a Dockerfile, we can run
docker build in the terminal, along with the path or url where the Dockerfile is located. This command tells the Docker Engine to build a custom image based on the Dockerfile. The image is built with a specific id that you can use to run a container based on the image.
To build an image, use
docker build <file or url of Dockerfile>
Images are read-only. That means that you need to rerun the
docker build command and rebuild your image if you've made any changes to your Dockerfile.
The order of the commands in a Dockerfile matter, because images are layer-based. When you build an image, every command in the Dockerfile creates a new image layer and the result of each command is cached, so it's not rerun if nothing changes. If you modify the port in the Dockerfile above, for example, by writing
EXPOSE 50 instead of
80 everything before that command will not be rerun.
You can also tag an image by using
docker build -t name:tag
You might want to use tags to version your images, though they can be used for all kinds of purposes.
To run a container based on an image, use
docker run <image id or name>
You can use
--name to name your containers.
docker run --name <your chosen container name> <image id or name>
If you don't, Docker will assign a random name for you.
You can also run Docker containers on a specific port. If we want to use port 3000 on our local machine to access port 80 in the Docker container that we specified in the Dockerfile above, for example, we could write
docker run -p 3000:80 <image id or name>
p stands for publish.
How to manage Images and Containers
After creating some images and containers, you might want to manage or delete them. Here are some common commands that will help you do that.
- To list all locally stored images, you can use
docker image ls
- To rename an existing image, you can use
docker tag <old name> <new name>
- To inspect an image use
docker image inspect <image id or name>
- To remove an image, you can use
Please note that images belonging to a container, whether running or not, cannot be removed. To remove those images, you need to remove the corresponding containers first.
docker rmi <image id or name>
- To remove all unused images, you can run
If you want to remove all images, including tagged ones, use the
docker image prune
-aflag with this command.
- To see all running containers, you can use
psstands for processes. If you want to see both running and stopped containers, you can run
docker ps -a
astands for all.
- To stop a container, you can use
If you're in a hurry, you can also use
docker stop <container id or name>
docker kill, which will stop the container immediately instead of giving it some time to shut down gracefully.
- If nothing has changed, you can restart your container by running
A difference between
docker start <container id or name>
docker startis that the former runs the container in attached mode by default. This means that the container is started in the foreground and the output is printed in the terminal, which you cannot use at the same time.
docker starton the other hand, starts the container in detached mode, so it's running in the background and you can still use your terminal.
To attach a running container that you started in detached mode, simply run
If you want to restart a container in attached mode, simply run
docker attach <container id or name>
Similarly, you can also use the
docker start -a <container id or name>
-dflag for detached with the
- To run a container in interactive mode (if your programme requires user input for example), use
docker run -it <container id or name>
-istands for interactive, and
-tbasically for the terminal.
- To remove containers that are not running, you can use
You can remove several containers at the same time by listing several container ids or names while leaving a space between them like so
docker rm <container id or name>
docker rm <container id or name> <container id or name>
- To remove containers automatically after they are stopped, use the
Sharing Images on Docker Hub
To share your images on Docker Hub, use
docker login to log in to the default Docker Hub repository or to a specific registry, and
docker push <image id or name> to upload your image to the Docker Hub. To use an image from the Docker Hub, simply run
docker pull <image id or name>.
When you use
docker run <image id or name> and you don't have a local image with that name, Docker will automatically pull the latest version from Docker Hub. If you do, Docker will not check that it's the latest version, so to ensure that it's the most recent version, you need to pull it from Docker Hub first.
And that's it. Those are all the commands you need to create, manage and delete some images and containers, and to share your images on Docker Hub. I realise that it's quite a lot and I might create a summarising cheatsheet at some point, but this is it for now.
If you're new to Docker, I'd suggest creating a simple sample application in a language you're familiar with and playing around with the Docker commands above.
Happy dockering! 🐳