The documentation at https://docs.docker.com/get-started/ is really good and I would recommend reading through the first 2 parts. This post is mostly just the tutorial rehashed.
”Docker” is a collection of applications that help package and distribute applications. Installing Docker on a machine is similar to installing a Java Virtual Machine. However, where a JVM abstracts the CPU, Docker abstracts an entire system.
Docker (for the most part) is a comprised of 2 applications: the Docker daemon and the Docker CLI. You will need at least the Docker CLI installed on your local machine, and the Docker daemon could be running else where. Having the daemon installed elsewhere is perhaps something you don’t need to worry about to start with though.
Docker used to be only truly a Linux application, as it relied on features available in the Linux kernel. When installing “Docker Desktop” for Windows or Mac, you are installing an application that is managing a Linux virtual machine, which itself is being used to manage virtual machines…
There is however now native Windows support.
Installing
For Windows, Microsoft Hyper-V is required to run Docker Desktop. When Hyper-V is enabled, VirtualBox no longer works.
Instructions for getting Docker installed onto your machine can be found on the docker website.
Because Docker uses Linux kernel features, Docker doesn’t currently work directly on WSL. However, WSL2 has been released, which ships with an actual Linux kernel. It is only available in Windows builds 18917 and higher.
I currently have WSL installed, so I followed the WSL install blog post.
However, I had issues with my WSL Docker CLI communicating with the Windows
daemon. The work around I’m using involves running socat
in a docker
container:
https://hub.docker.com/r/alpine/socat/.
docker run -d --restart=always -p 127.0.0.1:2375:2375 -v /var/run/docker.sock:/var/run/docker.sock alpine/socat tcp-listen:2375,fork,reuseaddr unix-connect:/var/run/docker.sock
First container
This is the same steps as https://docs.docker.com/get-started/part2/ but with one of my repos.
Defining a Dockerfile
Clone the project from GitHub
git clone https://github.com/alxwrd/bus-stop.git
cd bus-stop
This is a single page web app that displays the current bus information for the bus stop outside the my office.
In the repo there is a file called Dockerfile
. This is similar in concept
to a Makefile
and is what is used to define the resulting Docker image.
FROM nginx:latest
COPY index.html /usr/share/nginx/html
COPY main.js /usr/share/nginx/html
COPY style.css /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
FROM
specifies which image to use as the parent image. The important
concept here is that this is also just a Docker image, which could be used in
a container. Images can be found on the Docker
Hub. The Dockerfile for nginx can be found on
GitHub.
COPY
copies a local files into the new Docker image.
EXPOSE
opens up a port.
CMD
runs a command in a running container.
Building an image
You can now build an image from this Dockerfile using the command
docker image build -t bus-stop .
docker image build
is the build command, while -t bus-stop
“tags” our
resulting image. This is important because you can view images already built
on your machine using
repos/bus-stop$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
bus-stop latest ab443971cc03 2 hours ago 127MB
nginx latest 2073e0bcb60e 3 weeks ago 127MB
Untagged images will just show up as
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 0e63f6aabdc9 22 seconds ago 154MB
Building an image can be seen synonymous with building or compiling source code.
Once an image is build, you can use it locally. Images can also be exported with
docker save bus-stop > bus-stop.tar
# Or equivilantly
docker save --output bus-stop.tar bus-stop
Then loaded with
docker load < bus-stop.tar
# Or equivilantly
docker load --input bus-stop.tar
Starting a container
Once the image has been build, we can run it in a container.
docker container run --publish 8000:80 --detach --name bus-stop bus-stop
docker container run
is the command run a new container. --publish 8000:80
forwards traffic from port 8000 to the Docker containers port 80.
--detach
forks the process so it can run in the background. --name
name’s
the running container, without this the container gets a random name
generated by the Docker daemon.
Opening http://localhost:8000/ you should see the web app which is being served by Nginx.
In addition to starting this container, it has also been added to the list of containers managed by your instance of Docker.
You can view all instances with
repos/bus-stop$ docker container ls --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fcab388de37b bus-stop "nginx -g 'daemon of…" About a minute ago Exited (0) About a minute ago bus-stop
15d251abc371 alpine/socat "socat tcp-listen:23…" 26 hours ago Up 9 hours 127.0.0.1:2375->2375/tcp exciting_cerf
To stop the container you can use
docker container stop bus-stop
And to remove the container
docker container rm bus-stop