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 writingFROM scratch
FROM node
- 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.js
in the container, for example, you'd write
If you specify severalCMD ["node", "app.js"]
CMD
, only the last one will be executed. If you specify none, theCMD
of 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"]
FROM
specifies the base image or parent image, in this casenode
WORKDIR
tells Docker that all subsequent commands should be executed inside a particular folder, in this case theapp
folder, includingCOPY
andRUN
COPY
copies the content of one folder into a folder in the image file system, in this case it will copy the contents ofsomeFolder
into theapp
folder. If theapp
folder 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 imageRUN
specifies the command that will be run when the image is created, in this casenpm install
to install all the dependencies of your node applicationEXPOSE
, 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 machineCMD
makes surenode server.js
will 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.
Creating Images
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.
Creating Containers
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>
where 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.
Managing Images
- 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 thedocker image prune
-a
flag with this command.
Managing Containers
- To see all running containers, you can use
wheredocker ps
ps
stands for processes. If you want to see both running and stopped containers, you can run
wheredocker ps -a
a
stands for all. - To stop a container, you can use
If you're in a hurry, you can also usedocker 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 betweendocker start <container id or name>
docker run
anddocker start
is 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 start
on 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 rundocker attach <container id or name>
Similarly, you can also use thedocker start -a <container id or name>
-d
flag for detached with thedocker run
command. - To run a container in interactive mode (if your programme requires user input for example), use
wheredocker run -it <container id or name>
-i
stands for interactive, and-t
basically 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 sodocker 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
--rm
flag.
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.
Final Words
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! ๐ณ