Docker Essentials
Docker has been on my radar for a long time. After learning virtualboxes, vagrant, puppet, I now want to step into the docker world more.
Each time I have been working with docker, I keep looking up the same information, so this article is a reference and a comprehensive explanation for these items.
Virtual Machine vs. Docker
Initially, I didn’t really understand the difference between using virtual machines and docker.
When running a single app, the difference between running the app on virtual machine or on docker is minimal.
The difference becomes more apparent when running apps on a single host computer. For greatest isolation, having each app running in its own operating system is ideal.
To reach this ideal using virtual machines, the amount of resources used per app increases, especially with more guest operating systems.
Each app on docker does not need its own guest operating system when running an app, so the host system has more resources available for apps.
Installing Docker
Installation instructions have change over time, the most current method to install docker is to look at their install page
I am focusing on Community Edition for this article.
macOS
Install docker from the AppStore or using this link from the docker store. The docker client for macOS has great integration, even using Apple’s HyperKit on newer macOS, so a separate virtual machine is not required anymore.
Ubuntu
Remove Previous Installs
$ sudo apt-get remove docker docker-engine docker.io
Docker has changed frequently over the last five years, so removing any old versions will avoid any weird undocumented errors.
Add Repository
$ sudo add-apt-repository "deb [arch=amd64]
https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
Install Docker
$ sudo apt-get update; sudo apt-get install -y docker-ce
The application is docker
but the apt package name is: docker-ce
.
Key Concepts
I have found the two base concept to docker are images and containers. Once I understood these two concepts, I had an easier time working with docker in general.
Images
Are binary builds of a system. This image file can be an operating system, or an application such as a webserver.
A file or interactively creation of the image is possible. One can also download images created by others from repositories, such as https://hub.docker.com
Containers
To run an image, a virtualized environment supports the computing resource needs of the image, such as accessing the processor and memory.
One can run a single image on multiple containers on the same computer with different options. (i.e. the same webserver on different ports)
SHA-256
The Secure Hash Algorithm used different places in docker:
- An image is uniqely identified and versioned by a SHA-256 value.
- Every running container is addressable by a SHA-256 value.
Docker commands can always operate on a SHA-256 value. Just use the proper value, the image or container, for the command. I
Images
These are binary application files that run in different containers. This section covers two important docker commands are: listing and getting images.
Listing Images
To list images that are on the host system, run:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 2a4cca5ac898 3 days ago 111MB
This will list all downloaded or stored images on the current system.
If there are no images on the system, it will display:
$ docker images
REPOSITORY TAG IMAGE ID CREATED
image_id
An image is addressable by its name (i.e. ubuntu for the ubuntu image) or its SHA-256 value - 2a4cca5ac898 as of this writing.
For the rest of this article, I will use image_id to refer to either an image’s name or SHA-256 value.
Getting Images
To get images from docker hub, use the docker pull
command:
$ docker pull <image_id>
to grab the ubuntu image, the command is:
$ docker pull ubuntu
Containers
Running an image puts it in a container.
Listing Containers
To find out what containers are running on your system, run:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b8996065500e ubuntu "/bin/bash" 4 seconds ago Up 2 seconds clever_goldstine
The output lists all the running containers on the system along with the image the container uses.
container_id
Like an image, a container is referencable by its SHA-256 listed in
the container ID section of docker ps
, or the name of the image
running the container.
For the rest of this article, I will use container_id to refer to either an container’s name or SHA-256 value.
Running Images in Containers
To run a specific image, run command:
$ docker run <image_id>
This will start a container with the specified image.
Container Options
The container options I have to be essential so far are: ports and volumes.
ports
One way to connect to the running container is through the port the running application uses, like port 80 for a webserver.
When specifying a port on docker run
, this exposes the port of the
container to the host, allowing the host to connect to the container.
$ docker run -p <host port>:<container port> <image_id>
So, if a webserver is running in a container, the port it is using is port 80. To be able to access the webserver from the host computer, pass in option:
$ docker run -p 8080:80 <image_id>
In a web browser, enter address: http://localhost:8080 to access the web server of the container.
volumes
Setting the volume option links files from the host computer (i.e. the current directory) to the container.
$ docker run -v <host directory>:<guest directory> <image_id>
So, to mount local files for the webserver:
$ docker run -v _site:/usr/share/nginx/html -p 8080:80 nginx
To see the served files in a web browser, enter address: http://localhost:8080.
mount
Docker has added a --mount
option, which superceeds the --volume
option. The volume option still works, but the documentation
recommends newer users to use mount.
The mount option is a bit more verbose and uses key-value pairs and requires three arguments:
- type: the type of mount to use. options are: bind, volume, & tmpfs.
- source: the directory on the host system to mount in the container
- target: the directory on the container system to have the mount
$ docker run --mount type=bind,source=<host directory>,target=<guest directory> <image_id>
Interacting with Containers
It is possible to login to a running container and interact with it like a virtualbox system. This can be handy to debug or to figure out the configuration of the docker image.
Logging in
To connect to the container through SSH, the command is:
$ docker exec -it <container_id> <command>
Most of the time, the command option will be bash
, the default shell
on most unix systems.
I have run into situations where bash was not installed, and had to use sh
.
To find out what shells are in the container, run:
$ docker export CONTAINER|tar -t|egrep ^bin/
Shutting Down
I have found three ways to topping a container: ^C
, docker stop
and sudo htop
. Each are useful depending on the situation.
^C
This is easiest if the terminal running the container is still accesible. Docker will receive the SIGTERM and stop.
docker stop
If the running container terminal cannot be easily accessed, using the command:
$ docker stop <container_id>
will stop the running container as well. One can obtain the container
ID from the docker ps
command.
sudo htop
A final resort to stopping a container, even when docker stop
does
not work, is to use htop, but running the process with root
privileges. docker stop
may not stop a stuck container.
Using sudo htop
instead allows for easy identification of the
process from the htop interface and to stop with different levels,
like SIGKILL.
Conclusion
This is a quick overview of the essentials of working with docker: images, containers, starting, and stopping.
Docker seems to be a basic technology to virtualize software, but when looking further, I see it as a powerful tool to run and manage apps. Technology that helps with this excites me.
I’m looking forward to working with docker more.