Installing Docker

The installation of Docker varies greatly between operating systems, but for most systems, there are detailed instructions at https://docs.docker.com/engine/installation/. Two levels of Docker are generally available: the Community Edition (CE) and the Enterprise Edition (EE). While slightly different, for almost everything that we will work on in this book, the Community Edition is perfectly functional and will suffice in every way. Once you reach levels of scale where you need much more advanced features, such as security scans, LDAP, and technical support, the Enterprise Edition might make sense. As would be expected, the Enterprise Edition is not free, and you can take a look at https://www.docker.com/pricing to see how these editions differ.

For our examples and any OS-specific commands in this book, from here on, we will be using Ubuntu's Long Term Support (LTS) version, with Ubuntu being currently the most popular Linux distribution. The latest version of the LTS product available is 16.04, which will be the base for our CLI interactions and examples but by the time you read this book, 18.04 might be available too. Keep in mind that outside of the installation part, most code and examples are very portable and should generally run on other platforms, so even if there are changes needed, they should be minimal. That said, developing Docker services on non-Linux platforms may not be as refined or stable due to the fact that Docker is generally used to deploy Linux-based services on Linux machines even though other niche cases are supported to some extent. Microsoft has been making significant advancements in this space with Docker for Windows since they have been trying to push their own container strategy, so keep an eye on their progress as it may become a pretty competent development platform.

Some manual networking examples in later chapters may not work fully in macOS due to the different implementation of this subsystem for that platform. For those, using a virtual machine with Ubuntu LTS is advised if you want to follow along.

So, with our clean Ubuntu 16.04 LTS machine, VM, or a compatible OS, let's get Docker installed. While the Docker package is already available on apt repositories within the distribution, I would highly discourage installation this way, as these versions are usually much older. While this is not a problem for most software, for fast-moving projects such as Docker, it will put you at a significant disadvantage when it comes to support for the latest features. For this reason, we will install Docker from its own apt repository:

Warning! There are couple of other ways to install Docker using many of the following tools, but unless absolutely necessary, installation with the sudo curl -sSL https://somesite.com/ | sh pattern or anything similar to it is a very dangerous thing to do as you are rooting your own box for a website without checking what the script does. This execution pattern also leaves minimal evidence of what was done behind. Additionally mid-stream exception can corrupt the download but still execute, partially causing damage, and you are only relying on Transport Layer Security (TLS), for which hundreds of organizations across the world can create fake certificates. In other words, if you care about your machine, you should never, ever try to install software in this way unless, of course, the software vendor is clueless about security and they force you to do this, in which case, you are at their mercy.
$ # Install the pre-requisites
$ sudo apt install -y apt-transport-https
curl


$ # Add Docker's signing key into our apt configuration to ensure they are the only ones that can send us updates. This key should match the one that the apt repository is using so check the online installation instruction if you see "NO_PUBKEY <key_id>" errors.
$ apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80
--recv-keys 58118E89F3A912897C070ADBF76221572C52609D


$ # Add the repository location to apt. Your URL may be different depending on if Xenial is your distribution.
$ echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" | sudo tee -a /etc/apt/sources.list.d/docker.list

$ # Update the apt listings and install Docker
$ sudo apt update
$ sudo apt install docker-engine
By default, Docker will require sudo (or root) prefixed to all of your commands to run including ones in this book that don't have it explicitly mentioned. Generally, for development machines, this is a big pain to deal with so I might mention, but strongly discourage, that you can also add your current user to the docker group so that you do not need to prefix every Docker command with sudo:
  1. Add user to group with usermod  (for example $ sudo usermod -aG docker $USER).

  2. Fully log out and log back in (groups are evaluated only on session start).

Keep in mind that this is a huge security hole that can allow a local user to escalate to root privileges trivially so never, under any circumstance, do this on any server that will sit on the Internet.

If all of the preceding commands work as expected, you will be able to see whether Docker is installed:

$ docker --version
Docker version 17.05.0-ce, build 89658be

Having Docker installed without anything to run is pretty useless, so let us see whether we can get an image that we can run locally. Our choices here would be to either make our own image from scratch or use something that's already built. Given that a big reason why Docker has reached such high adoption rates is its ease of sharing of images through Docker Hub (https://hub.docker.com/) and we're just starting out, we will delay creating our own image for a little bit to explore this site, a centralized place for publishing and downloading Docker images.

Behind this non-descriptive and bland page is the storage of thousands of Docker images, and since we are not interested in publishing images right now, we can just click on the Explore button in the top-right corner of the page to see what images are available:

As you can see, this lists the most popular images at the time of writing, but you can look for specific ones through the Search box in the upper-left corner as well. For now, as mentioned a while ago, we will not be spending too much time here, but it will be valuable for you to know how to run images from Docker Hub, so we will try to pull and run one of them to show you how it is done.

The top container available here right now seems to be NGINX, so we will try to run that in our Docker environment. If you have not worked with NGINX before, it is a high-performance web server that is used by a large number of websites on the internet. At this stage, we just want to get the feel for running these containers, so let us see how that is done:

$ # Pull the image from the server to our local repository
$ docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
94ed0c431eb5: Pull complete
9406c100a1c3: Pull complete
aa74daafd50c: Pull complete
Digest: sha256:788fa27763db6d69ad3444e8ba72f947df9e7e163bad7c1f5614f8fd27a311c3
Status: Downloaded newer image for nginx:latest

The pull command pulls any and all layers that compose this image. In this case, the NGINX image is based on three stacked layers and has a hash of 788fa277..27a311c3, and since we didn't specify a specific version that we wanted, we got the default tag, which is latest. With this single command, we have retrieved the NGINX image from Docker Hub so that we can run it locally. If we wanted to use a different tag or pull from a different server, the command gets the more expressive form similar to docker pull <hostname_or_ip>:<port>/<tag_name> , but we will cover these advanced usages in later chapters.

With the image now sitting in our local Docker storage (usually in /var/lib/docker), we can try to run it. NGINX has an absolute sea of possible options that you can examine in further detail at https://hub.docker.com/_/nginx/, but we are interested in just starting the image for now:

$ docker run nginx

You probably noticed that nothing is happening, but do not worry as this is expected. Sadly, this command by itself is not enough as NGINX will run in foreground and not be accessible over a socket at all, so we need to cover a few flags and switches to really make it useful. So let's shut the container down by pressing Ctrl + C and try again, this time adding some of the necessary flags:

$ docker run -d 
-p 8080:80
nginx

dd1fd1b62d9cf556d96edc3ae7549f469e972267191ba725b0ad6081dda31e74

The -d flag runs the container in the background (the detached mode) so that our Terminal isn't held on by NGINX and the -p 8080:80 flag maps our local port 8080 to the container's port 80. Containers often have specific ports that they expose, amd in this case, it is 80 but without the mapping we would have no way of accessing it. The output that the command returns is a unique identifier (container ID) that can be used to track and control this specific container after starting it. Hopefully, you can now see how the port whitelisting approach of Docker adds an extra level of security as only the things you explicitly allow to listen are permitted.

You can now open your browser to http://localhost:8080, and you should see a page similar to this one:

But how exactly did we know that port 80 needs to be listened to? Indeed, we will cover that in just a second, but first, because we started this container in the detached mode, it will still be running in the background and we should probably make sure that we stop it too. To see which containers we have running, let's check our Docker container statuses with docker ps:

$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dd1fd1b62d9c nginx "nginx -g 'daemon ..." 13 minutes ago Up 13 minutes 0.0.0.0:8080->80/tcp dazzling_swanson

What we see here is that our NGINX container is still running, that it has mapped localhost interface ports 8080 (including externally accessible ones) with the container's port 80, and that we have been running it for 13 minutes. If we had more containers, they would all be listed here so this command is extremely useful for working with Docker containers and is generally used for debugging and container management.

Since we wanted to shut this container down, we will actually do that now. To shut a container down, we need to know the container ID that is both the value that was returned by docker run and the value that the first column of docker ps shows (dd1fd1b62d9c). Feel free to use either the short or long version of the ID, but for brevity, we will use the former:

$ docker stop dd1fd1b62d9c
dd1fd1b62d9c

This will gracefully try to stop the container and return the resources used back to the OS and after a specific timeout, kill it forcefully. If the container was really stuck and we knew it, we could replace stop with kill to hard kill the process, but that's rarely needed since stop generally does the same thing if the process is not responding. We will now make sure that our container is gone:

$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

Yes, things look as we expect them to, but beware that while stopped containers are not visible, they are not completely removed from the filesystem by default:

$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dd1fd1b62d9c nginx "nginx -g 'daemon ..." 24 minutes ago Exited (137) 2 minutes ago dazzling_swanson

The -a flag is used to show all container statuses, not just the running ones, and you can see that the system still knows about our old container. We can even resume it with docker start!

$ docker start dd1fd1b62d9c
dd1fd1b62d9c

$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dd1fd1b62d9c nginx "nginx -g 'daemon ..." 28 minutes ago Up About a minute 0.0.0.0:8080->80/tcp dazzling_swanson

To really remove our container permanently, we need to explicitly get rid of it using docker rm, as shown here, or run the docker run command with the --rm switch (we'll cover this one in the next few pages):

$ docker stop dd1fd1b62d9c
dd1fd1b62d9c

$ docker rm dd1fd1b62d9c
dd1fd1b62d9c

$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

Success!

Now let us get back to the earlier question of how we knew that the container needed to have port 80 mapped to it? We have a couple of options there for finding this information out, and the simplest one is starting the container and checking in docker ps to see which ports are unbound:

$ docker run -d 
--rm
nginx

f64b35fc42c33f4af2648bf4f1dce316b095b30d31edf703e099b93470ab725a

$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f64b35fc42c3 nginx "nginx -g 'daemon ..." 4 seconds ago Up 3 seconds 80/tcp awesome_bell

The new flag here that we used with docker run is --rm, which we just mentioned, and it tells the Docker daemon to remove the container completely after it is stopped so we don't have to do it manually ourselves.

If you already have a container that you want to check the mapped ports on, you can use docker port <container_id> command but we are omitting it here since it cannot be used on images, but just containers.

While this is the quickest way to see what ports will be needed, the general way to inspect an image outside of reading its Dockerfile and documentation is through docker inspect:

$ # Inspect NGINX image info and after you match our query, return also next two lines
$ docker inspect nginx | grep -A2 "ExposedPorts"
"ExposedPorts": {
"80/tcp": {}
},

Additionally, docker inspect can show all kinds of other interesting information, such as the following:

  • The ID of the image
  • The tag name
  • The image creation date
  • Hardcoded environment variables
  • The command that the container runs on start
  • The size of the container
  • Image layers IDs
  • Volumes specified

Feel free to run the inspect command on any container or image and see what gems you might find there. Majority of the time, this output is mainly used for debugging, but in cases where the image documentation is lacking, it can be an invaluable tool to get you running in a minimal amount of time.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.225.98.18