Before discussing Docker, we need to know about the concept of containers, which are extremely lightweight virtual machines (VMs). They are not intended to replace VMs but to complement them. Containers are like VMs, and they isolate the resources that an application has access to. The concept of a container is not new and has been around for a whileSolaris zones, FreeBSD jails and chroot are all containers. Containers are executed by container engines (the Docker engine in the case of Docker), and share the OS kernel and appropriate libraries. This advantage makes for significantly faster deployment with less overhead, easier migration and faster restart.
Docker uses cgroups and namespaces in the Linux kernel to provide resource isolation. Docker contains two componentsthe Docker engine and the Docker Hub. The Docker engine is the container virtualisation technology and Docker Hub is the SaaS service for sharing and managing Docker images in which the applications are stacked. Once Docker is installed and services are started, the Docker daemon is responsible for building, running and distributing the Docker containers. The Docker client interacts with the Docker daemon via sockets or through a RESTful API to do all the tasks.
There are three more internal components that need to be understoodDocker images, Docker registries and Docker containers. Docker images are read-only templates; these images contain the operating system with the required libraries/tools and the applications. Docker registries hold these images; the registries are like public/private repositories. The public Docker registry is called Docker Hub and has a huge collection of images with various applications embedded. A Docker container holds everything that is needed for an application to execute; containers are created from a Docker image. Similar to virtual machines, containers can be started, stopped, moved and deleted. Each container provides an isolated and secure environment for applications to run. When Docker runs a container from an image, it adds a read-write layer to the image by using the Union file system.
The Docker registries contain many base images either created by Docker Inc. or the community. These base images are used to build custom images with applications injected. Docker images can be built using a recipe file called Dockerfile.
Now, lets get our hands dirty with Docker. The first step is to install the Docker engine on the host OS or in a VM. Docker is easy to install and it runs on a variety of Linux flavours. It can be installed from the precompiled packages available with the respective Linux distributions or can be compiled from the Docker source available at GitHub. For this article, CentOS 7 x86_64 bit has been installed on a VM with a 4 vCPU (virtual CPU), 16GB memory, a 1GB network port and 100GB of disk space.
Given below are the commands to install Docker on a freshly installed CentOS 7 x86_64 bit version. Please note that the EPEL (Extra Packages for Enterprise Linux) repository needs to be configured for installing Docker packages on CentOS 6.5. However, for CentOS 7, the Docker packages are already available in the default repo. For this article, we disabled the SELinux and FirewallD services before starting with Docker deployment. As we are trying to pull the Docker-relevant packages from the repo, it is imperative to provide proxy details for the machines behind the proxy.
Installing Docker related files through Yum
Type the following commands to install Docker related files through Yum:
[root@teja-dev-vm01 ~]# more /etc/redhat-release CentOS Linux release 7.0.1406 (Core) [root@teja-dev-vm01 ~]# uname -a Linux teja-dev-vm01.helab.bdc 3.10.0-123.el7.x86_64 #1 SMP Mon Jun 30 12:09:22 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux [root@teja-dev-vm01 ~]# [root@teja-dev-vm01 ~]# echo ${http_proxy,ftp_proxy,https_proxy} http://10.10.17.17:3128 [root@teja-dev-vm01 ~]# yum install docker y [root@teja-dev-vm01 ~]#
After successfully installing Docker, also install device-mapper-event-libs. Start the Docker service with the systemctl command and also enable the Docker service. Given below are two commands to start the Docker service and enable it:
[root@teja-dev-vm01 ~]# systemctl start docker.service [root@teja-dev-vm01 ~]# [root@teja-dev-vm01 ~]# systemctl enable docker.service
Verify the Docker version installed with the command docker v. The version that got installed was v1.5. With this, Docker installation is complete. The next step is to create a user account on Docker Hub and use those credentials to pull the latest CentOS images.
Browse hub.docker.com and complete the registration process. Once the registration is done, use the command docker login to log in to the hub. Given below are the commands to log into Docker Hub for downloading the images. If systems are behind the proxy, then ensure that HTTP_PROXY and HTTPS_PROXY are defined in the configuration file /etc/sysconfig/docker.
Log into Docker hub or Docker registry
Here are the commands for log into docker hub or docker registry :
[root@teja-dev-vm01 ~]# docker login Username: my_docker_hub_login Password: ***** Email : my@email.com Login succeeded. [root@teja-dev-vm01 ~]#
Once the login to the registry is successful, docker images can be searched using the command docker search, images can be pulled from registry, containers can be created from the images, updated images can be pushed to registry, custom images can be built and so many other things can be done. In the commands given below, centOS images are pulled from repository and then the container is started.
As a next step, lets start the applications inside the container with the fresh CentOS pulled from Docker Hub. The command Docker run helps to launch the container with the application. In the following example, the container was launched in interactive mode by using an option i. The option -t assigns a pseudo-tty or terminal inside the new container. Along with the above options, specify that /bin/bash needs to run in the container.
[root@teja-dev-vm01 ~]# docker pull centos Pulling repository centos 0114405f9ff1: Download complete 511136ea3c5a: Download complete b6718650e87e: Download complete 3d3c8202a574: Download complete Status: Downloaded newer image for centos:latest [root@teja-dev-vm01 ~]# [root@teja-dev-vm01 ~]# docker run -t -i centos /bin/bash [root@19de0ebc88f7 /]# [root@19de0ebc88f7 /]# uname -a Linux 19de0ebc88f7 3.10.0-123.el7.x86_64 #1 SMP Mon Jun 30 12:09:22 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux [root@19de0ebc88f7 /]# exit exit [root@teja-dev-vm01 ~]#
Containers can also be started in daemon mode. Shown below is an example to start the CentOS container in daemon mode. The option d is used to invoke the containers in daemon mode. In the following example, we are printing a simple textHello World. The command docker ps -a shows the status of each container along with its ID. The first command in the example is to start the container and execute the command echo Hello World in an infinite loop. The command docker logs <container-id> will help us to tap into the container and see whats happening.
[root@teja-dev-vm01 ~]# docker run -d centos /bin/sh -c while true; do echo Hello World; done c9be70db3e2729ae4653fdc61c91c6845fe8b177381392cf416dcfca4f2d659f [root@teja-dev-vm01 ~]# [root@teja-dev-vm01 ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c9be70db3e27 centos:7 /bin/sh -c while t 4 minutes ago Up 2 minutes hopeful_pike cc899c0cfdf9 centos:7 /bin/sh -c while t 6 minutes ago Up 5 minutes dreamy_wilson [root@teja-dev-vm01 ~]# [root@teja-dev-vm01 ~]# docker logs c9be70db3e27 Hello World Hello World Hello World Hello World Hello World Hello World Hello World ^C[root@ teja-dev-vm01 ~]#
Running containers can be stopped with the command docker stop <container-id>. The code below stops the container and also removes it:
[root@teja-dev-vm01 ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c9be70db3e27 centos:7 /bin/sh -c while t 19 minutes ago Up 17 minutes hopeful_pike cc899c0cfdf9 centos:7 /bin/sh -c while t 21 minutes ago Up 20 minutes dreamy_wilson [root@teja-dev-vm01 ~]# [root@teja-dev-vm01 ~]# docker stop c9be70db3e27 c9be70db3e27 [root@teja-dev-vm01 ~]# [root@teja-dev-vm01 ~]# docker rm c9be70db3e27 c9be70db3e27 [root@teja-dev-vm01 ~]#
The LAMP stack with Docker containers can be done in two ways. The first is to download the preconfigured LAMP stack Docker image from Docker Hub, and the second option is to pull the base image and install/configure all the components of the LAMP stack.
For the first option, we will pull the linode/lamp image. This image is one of the popular preconfigured Docker images available on Docker Hub. The code given below searches for the image, pulls it and starts the container with all the LAMP stack components preinstalled.
[root@teja-dev-vm01 ~]# docker search linode [root@teja-dev-vm01 ~]# [root@teja-dev-vm01 ~]# docker pull linode/lamp Pulling repository linode/lamp 115a4e1b4860: Download complete 511136ea3c5a: Download complete 27d47432a69b: Download complete 5f92234dcf1e: Download complete 51a9c7c1f8bb: Download complete 5ba9dab47459: Download complete cfea48d8d4c8: Download complete 664027dedce4: Download complete Status: Downloaded newer image for linode/lamp:latest [root@teja-dev-vm01 ~]# [root@teja-dev-vm01 ~]# sudo docker run -p 80:80 -t -i linode/lamp /bin/bash [root@teja-dev-vm01 ~]# sudo docker run -p 80:80 -t -i linode/lamp /bin/bash root@fb6c47e05cfe:/# service apache2 start * Starting web server apache2 * root@fb6c47e05cfe:/# service mysql start * Starting MySQL database server mysqld [ OK ] * Checking for tables which need an upgrade, are corrupt or were not closed cleanly. root@fb6c47e05cfe:/# root@fb6c47e05cfe:/# uame -a bash: uame: command not found root@fb6c47e05cfe:/# uname -a Linux fb6c47e05cfe 3.10.0-123.el7.x86_64 #1 SMP Mon Jun 30 12:09:22 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux root@fb6c47e05cfe:/# ifconfig eth0 | grep inet inet addr:172.17.0.3 Bcast:0.0.0.0 Mask:255.255.0.0 root@fb6c47e05cfe:/#
Enter the IP address of the container (i.e., 172.17.0.3 in this instance) in the browser and complete the other settings. Figure 1 shows the screen capture of the LAMP stack deployment in the container.
For building the custom Docker image using the base image, a recipe called Dockerfile is used. Shown below is the sample Dockerfile used to build the custom image with the LAMP stack:
FROM centos:6 MAINTAINER Teja <teja_ja@gmail.com> #set the proxy RUN export http_proxy=http://10.10.17.17:3128 RUN export https_proxy=http://10.10.17.17:3128 RUN export ftp_proxy=http://10.10.17.17:3128 #installing required packages RUN rpm -Uvh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm RUN yum install -y python-pip && pip install pip>=1.4,<1.5 --upgrade RUN pip install supervisor RUN yum install -y openssh-server openssh-client RUN yum install -y passwd httpd mysql mysql-server RUN yum install -y php php-mysql php-devel php-gd php-pecl-memcache php-pspell php-snmp php-xmlrpc php-xml # replacing my config file and starting required services ADD ./supervisord.conf /etc/supervisord.conf RUN service mysqld start EXPOSE 22 80 3306 CMD [/usr/bin/supervisord]
Save the above contents to the file with the file name Dockerfile, and execute the command docker build for building the image. Once the build is successful, tag the image and save it with the command docker build -t teja/lampStack.
Once the image is built, the container can be started with the following command:
docker run -d -p 80:80 -p 3306:3306 -p 22:22 ushios/lamp-centos
Enter http://localhost:80 in a browser to see the Web server running.
References
[1] http://docs.docker.com/
[2] https://www.linode.com/docs/applications/containers/linode-lamp-container-docker
[3] http://en.wikipedia.org/wiki/Docker_(software)