When learning the fundamentals of Docker and understanding that Docker is a tool designed to make it easier to create, deploy, and run applications by using containers.
You are probably asking yourself. What is a Container? What is an Image?
For even experienced developers it can seem like a steep learning curve. I have created this post to cover the basics of containers and images and how they interact with each other. I will also cover some good practices, as developers we love these right?
So you can think of these as multiple read only layers. Maybe a bit like an onion. Images are created by a DockerFile which contains YAML and has an extension of .yml or .yaml. This DockerFile will contain various instructions for example at the top of this file you could have the following:
FROM microsoft/dotnet:2.2-aspnetcore-runtime-alpine AS base
This is an instruction. When the DockerFile is built this instruction will be one layer of the image that is outputted. This image will then contain the dotnet core 2.2 runtime. An image will contain layers that are required to run your application. You might be thinking ‘The dotnet core runtime is 150mb roughly, why would I want this large layer in my image.” While as a best practice, images should be as small as possible to ensure they are cheaper to store, quicker to transfer, build and deploy.
This is where alpine comes into play. Many standard Docker images conveniently have an Alpine Linux version, like in our example above our base image contains the alpine suffix. Due to using Alpine Linux as a base image this allows these images to be much smaller. Alpine images contain less dependencies, consequently this improves performance and the overall security because of the smaller attack surface area available. There is no need to include dependencies from a base image that are not going to be used. That’s a bit like buying coffee, storing it in your cupboard and not using it. It’s still using up cupboard space.
Building an image from a DockerFile
To build the image we need to have Docker installed, you can follow this guide to install.
While installed you can invoke the docker build command from inside the same directory as the DockerFile, which would go through the Dockerfile’s contents and generate the image.
TIP: Docker recommend tagging an image using the following naming convention: repository/name:version.
docker build --tag davebeaumont/coffee:1.0.0 .
Above I am tagging the outputted image with what I would like it to be named when its generated, also applying a version number to it.
You may see the –tag abbreviated to -t sometimes.
TIP: Do not forget the full stop at the end of the build command.
This is the build context and it tells the docker build commands to look into the current directory for DockerFile and related contents.
You can think of a container as an instance of an image, a Container is created by an image. Therefore you could decide to run 100 or more containers from the same image. Essentially your container, contains your image. See what I done there?
Containers keep applications isolated from their environments. Because they behave in a similar way to a Virtual Machine, but without the operating system allowing them to operate faster and without the additional dependencies. As a result allowing applications to be split down into a micro-services approach, for example you could run your database inside one container, your UI inside another and so on.
Applications built this way are easier to deploy, manage and scale as they are lightweight and portable. I’m hoping you would not decide to run an extremely complex application inside just one container.
Building a Container
To build a container use the following commands.
docker run davebeaumont/coffee:1.0.0
You can view a list of running containers using the following command.
You can view a list of all containers, running or stopped, using the following command.
docker ps -a
Hopefully this makes sense and is readable, I will be doing an additional post on Kubernetes (k8s) at some point in the future, and how Kubernetes can help with the deployment and management of containers.