Blog4Java

A personal and Java blog, likely only for me

Getting started with Docker

| 0 comments

What is Docker?

Docker is a platform.

Docker runs natively on Linux or on OS X and Windows through a helper application called boot2docker that creates a Linux Virtual Machine, by using only RAM, to run Docker.

Docker‘s main goal is to allow you to ship distributed applications, that you’ve created previously, by running them as isolated process on what is known as a container, thus it avoids the need of Virtual Machines that implies a resources saving in the involved machines. The isolation also allows to run several containers simultaneously.

So, Docker is an open platform for developing, shipping, and running applications.

The key point is that you can separate your application from the infrastructure and also treats the infrastructure as an application. Everything can be packaged, distributed and deployed anywhere and quickly. It’s said that Docker eliminates the friction between development, QA, and production environments.

Docker has two major components:

  • Docker, the container virtualization platform, that has a daemon running on a host server and a client (the docker binary) to talk to the Docker daemon.
  • Docker Hub, the SaaS platform for sharing and managing Docker containers.

Docker concepts

  • Image (build component of Docker): a Docker environment template, it consists in files (a copy of what is expected to contain) and metadata (information such as environment variables, port mappings and so on) and it has a name (“ubuntu”, for instance)
  • Registry (distribution component of Docker): a public or private store that holds images. The public Docker registry is called Docker Hub.
  • Container (run component of Docker): a running instance of a Docker image. It’s created from a Docker image, and it can be run, started, stopped, moved, and deleted. Each container is an isolated and secure application platform.

How Does Docker work?

An image is a serie of layers that are combined into a single image by Docker using union file systems (UnionFS, a file system service that allows files and directories of separate file systems, known as branches, to be transparently overlaid, forming a single coherent file system)

From a base image, you can add and modify additional layers and there’s no need of rebuilding the entire image if there is a change, you only need replace the added or updated layer.

A container is built from an image, that is read-only. For running the container, Docker adds a read-write layer on top of the image (using UnionFS) and then allocates a network/bridge interface, an IP address, and finally, executes the specified process and captures input and provides output.

The container is isolated thanks to a technology called namespaces (Namespace isolation, where groups of processes are separated such that they cannot “see” resources in other groups)

Docker use these namespaces:

  • The pid namespace, for process isolation.
  • The net namespace, for managing network interfaces.
  • The ipc namespace, for Inter-Process Communication.
  • The mnt namespace, for managing mount-points.
  • The uts namespace, for changing the hostname.

In order to achieve isolation on running application, Docker uses another technology called control groups (cgroups, it limits, accounts for, and isolates the resource usage (CPU, memory, disk I/O, network, etc.) of a collection of processes)

Installing Docker

I’m going to use Ubuntu (as Sheldon Cooper said, my favorite Linux-based operating system)

There are three packages available, two of them from Ubuntu, an older KDE3/GNOME2 called docker (warning, this is the suggested package when you try docker version before having installed: “The program ‘docker’ is currently not installed. You can install it by typing: sudo apt-get install docker”) and a newer called docker.io, that is not the most recent Docker release. The third one is a PPA (Personal Package Archives for Ubuntu) for Docker and it’s called lxc-docker.

If you don’t want extra repositories and you don’t want the latest version, just install docker.io (I recommend you to enable tab-completion of Docker commands in BASH if you install it):

To validate the installation, type:

You need to use sudo because the docker daemon always runs as the root user, that’s because the docker daemon binds to a Unix socket (instead of a TCP port, as it happened until version 0.5.2). By default that Unix socket is owned by the user root, so you need to use the docker command with sudo. You can solve it by giving non-root access to Docker or, even better, you can create a docker group and add users to it.

Otherwise, if you run docker without sudo you will obtain this error message:

In order to have the latest version, use the lxc-docker package, that is the one maintained by Docker itself.

There is a script to install the Docker package on Ubuntu, but I’d rather to do it manually. But you can try with:

To install lxc-docker, your APT system have to deal with https (you can if the file /usr/lib/apt/methods/https exists, it you don’t have it, install the apt-transport-https package)

Then, just add the Docker repository key to the local keychain, and to the apt sources list. Finally, update and install the lxc-docker package:

Now we have the last version:

And we can run the basic example, that downloads the ubuntu image, and then start bash in a container. When you’re done, type exit.

Having said that, Docker has changed the instructions for Installing Docker on Ubuntu… today! :|

It seems easier, but I don’t like it very much. If you have wget installed, you can get the latest Docker package with:

It prompts for the password and then it downloads and installs… the lxc-docker package.

And then, verify the installation with:

Using Docker

Running applications inside containers

Docker allows you to run applications inside containers with the command docker run.

The command docker run creates a new container from the image name that you specify (the mandatory parameter for run) and then runs the command in it by performing these steps: Docker looks for the image in this computer, if it isn’t installed yet, Docker searches the image at Docker Hub to download it and install it. Once the image is installed, Docker creates a new container and starts the program.

We’ve seen above one example:

It creates a container from the Official Ubuntu base image (tag 14.04.2) and then it runs a Bash shell command, with a terminal assigned (flag -t), and grabs the standard in of the container(flag -i)

For executing in the background (or daemonized), use the -d flag:

Here, the command will run forever. Besides, I have assigned a name to the container (OK, my very name, some egocentricity here) to easily discover it later (Docker automatically names any containers that you start, but I’d rather to specify the name by myself). Furthermore, Docker returns the container ID (e84ae6413888…).

You can find both the ID and the name when listing containers with the command docker ps (flag -a to show all regardless they are running or not)

The ports in the container can be exposed randomly with the -P flag or manually with -p. In any case, you can see in the column PORTS of the docker ps command or with the docker port command. Let’s see an example with a sample web application image.

This means that you can access the application running in the container by using the port 49153 locally.

To manage the container, you can use the next commands:

  • docker logs to see the standard output of a container (-f to view the new additions, press Ctrl+C to exit)
  • docker top to see the process in the container.
  • docker inspect to see configuration and status information about a container.
  • docker stop/kill to stop or kills (respectively) a running container.
  • docker start to restart a stopped container (remember the command docker ps -a).
  • docker rm to remove a container.
  • docker version to see the current version of the program, its programming language (Go) and so on.

Working with Docker Images

As we have explained, Docker runs container by using images that are either installed in your system or exists at Docker Hub (in order to download it and install in your system)

You can see what images are already installed with the docker images command.

If you want to manually install an image before running it, you can use the docker pull command for images that you can find at Docker Hub or with the command docker search.

As a curiosity, if you look for images at Docker Hub, you can find Official repos, for instance, the Java OFFICIAL REPO.

You can add a new name to the image with the docker tag.

If you want to remove an image, you can do so with the docker rmi command.

A note about the official images

The images and relevant files are maintained at GitHub by an organization called docker-library (Docker is open source, and it’s maintained at GitHub by an organization called Docker, that has several repositories, including the one for docker).

The official images exist in a repository, Docker Official Images, that contains a folder for the library definitions, for instance, the one for java.

The image packages are also maintained by docker-library in each corresponding repository, for instance, the Docker Official Image packaging for Java (openJDK)

It’s worth to mention it because there is another organization at GitHub called (Trusted Automated Docker Builds) that has repositories for several Docker builds, for instance, the one for Java, that includes an image for Oracle Java 8 JDK (that I was looking for)

Creating your own images

There are two ways for updating and creating images.

  1. Run a container from an image (docker run), then update it, and finally commit the results to an image, with the docker commit command.
  2. Use a Dockerfile to create an image.

When you’re done, you can push the created image to Docker Hub with the docker push command.

Finally, you can remove images with the docker rmi command.

You can find this image at jbbarquero / ubuntu-java8_oracle-maven

How to write a Dockerfile is out of the bounds of this first post, but I can create a very basic one. Just for fun.

Having this Dockerfile:

Just build it (and then push it)

The new image can be found in Docker Hub, find it at jbbarquero / ubuntu-java8_oracle-maven-git.

Closing words

That’s enough for now. There are a couple of interesting topics, but we’ll leave for another time:

Resources

Post scríptum

When re-starting the container jbbarquero/ubuntu-java8_oracle-maven, source /etc/environment is not called, so the values that I wrote there are not applied. For solving this issue, I edited /etc/bash.bashrc and I put there the environment variables.

Maybe a Dockerfile is a better idea to create containers with environment variables using ENV.
so the values that I wrote there

Author: Javier (@jbbarquero)

Java EE developer, swim addict, occasional videogames player, fan of Ben Alex and Shamus Young, and deeply in love with my wife. Sooner or later I'll dedicate a post to expand this simple introduction.

Leave a Reply

Required fields are marked *.