Skip to content

Docker

**Docker** is a platform for *developing*, *shipping*, and *deploying* applications quickly in **portable, self-sufficient containers**, and is used in the **Continuous Deployment (CD)** stage of the **DevOps** ecosystem.

6 min read

Docker is a platform for developing, shipping, and deploying applications quickly in portable, self-sufficient containers, and is used in the Continuous Deployment (CD) stage of the DevOps ecosystem.

Environment: CentOS 7 Minimal on VMware Player 17

Terminal window
$ yun update
$ yum install -y \
yum-utils \
device-mapper-persistent-data \
lvm2
$ yum-config-manager \
--add-repo https://download.docker.com/linux/centos/docker-ce.repo
$ yum install -y docker-ce
$ docker -v

Daemon is a special process of Docker, To start/stop/restart Docker, or to get the status of Docker:

Terminal window
$ systemctl start docker
$ systemctl stop docker
$ systemctl restart docker
$ systemctl status docker

To enable autostart:

Terminal window
$ systemctl enable docker

To list local images, type:

Terminal window
$ docker images

and it will return a table like:

REPOSITORYTAGIMAGE IDCREATEDSIZE

Note:

  • REPOSITORY: the software or service name
  • TAG: version number

If we just need Docker Image ID, we can add a parameter -q

Terminal window
$ docker images -q

Terminal window
$ docker search redis

and it will return a table like:

NAMEDESCRIPTIONSTARSOFFICIALAUTOMATED
redisRedis is an open source key-value store that…12156[OK]

Note: OFFICIAL is [OK] meaning that this image is maintained by Redis team.

If we want to pull Redis, we just type:

Terminal window
$ docker pull redis

And the latest Redis (i.e., TAG “redis:latest”) will be pulled into local machine. However, if we want to pull Redis 5.0, open Docker Hub to verify if it is available, and then:

Terminal window
$ docker pull redis:5.0

to remove a Docker Image (called redis:5.0 or Image ID is c5da061a611a), we can type any one of them:

Terminal window
$ docker rmi redis:5.0
$ docker rmi c5da061a611a

Trick: If we want to remove all the images, we can use:

Terminal window
$ docker rmi `docker images -q`

A Container is built out of Docker Image.

The status for a container can be UP or Exited.

Terminal window
$ docker ps # List all the running container
$ docker ps --all # List all the history container(s)
$ docker ps -a # Also List all the history container(s)

Or, we can inspect a container for more details:

Terminal window
$ docker inspect CONTAINER_NAME

To create a docker container out of an image, we will first pull image centos:7 from remote repository:

Terminal window
$ docker pull centos:7
  1. Interactive Container: create docker image container with centos:7, and then enter the container. These three docker run commands are equivalent:
Terminal window
$ docker run --interactive --tty --name=test_container centos:7 /bin/bash
$ docker run -i -t --name=test_container centos:7 /bin/bash
$ docker run -it --name=test_container centos:7 /bin/bash

Note:

  • --interactive or -i: keeps STDIN open even if not attached
  • --tty or -t: allocates a pseudo-TTY
  • --name=test_container: assigns a name “test_container” to this container
  • centos:7: this container is built on the image called ‘centos:7’
  • /bin/bash: docker will run /bin/bash of container.
  • the terminal identidy will switch from root@localhost to root@9b7d0441909b, meaning the container (9b7d0441909b) is now started.
  1. Detached Container: Detached Container will not be executed once created, and will not be terminated after $ exit. These three commands are equivalent:
Terminal window
$ docker run --interactive --detach --name=test_container2 centos:7
$ docker run -i -d --name=test_container2 centos:7
$ docker run -id --name=test_container2 centos:7

In the last section, we created a container but not enter into it, and we can enter by these 3 equivalent docker exec commands:

Terminal window
$ docker exec --interactive --tty test_container2 /bin/bash
$ docker exec -i -t test_container2 /bin/bash
$ docker exec -it test_container2 /bin/bash

Terminal window
$ docker stop CONTAINER_NAME
$ docker start CONTAINER_NAME

where CONTAINER_NAME is set accordingly by command $ docker ps --all.

Terminal window
$ docker rm CONTAINER_NAME

Note:

  • An UP-status docker container cannot be removed, we have to bring it to Exited before removal
  • Note the difference between the removal of image and container: to remove image, we type: docker rmi, and to remove container, we type: docker rm.

Volumes are the preferred mechanism for persisting data generated by and used by Docker containers.

To persist data, we can use volume to map the folders. These two commands are equivalent:

Terminal window
$ docker run -it \
--name=testVol1 \
--volume ~/data1:/root/container_data1 \
--volume ~/data2:/root/container_data2 \
centos:7 \
/bin/bash
$ docker run -it \
--name=testVol1 \
-v ~/data1:/root/container_data1 \
-v ~/data2:/root/container_data2 \
centos:7 \
/bin/bash

Note:

  • --volume or -v: map the folder to the container with synchronization. Outside container, we use folders ~/data1/ and ~/data2/; Inside container, we use /root/container_data1 and /root/container_data2
  • we can only explicitlly use the path /root/* (not ~/*) inside container

We first create a container called c3, and this will be our Volume Container: (Note the parameter -v /Volume)

Terminal window
$ docker run -it \
--name=c3 \
-v /Volume \
centos:7 \
/bin/bash

Then, we will create two containers, and mount them onto c3 in two separate SSH sessions:

Terminal window
$ docker run -it --name=c1 \
--volumes-from c3 \
centos:7 /bin/bash
$ docker run -it --name=c2 \
--volumes-from c3 \
centos:7 /bin/bash

you can use $ docker inspect c3 to find out where where c3 is mounted, and snippet of docker inspect response shown below:

......
"Mounts": [
{
"Type": "volume",
"Name": "266**298fb7",
"Source": "/var/lib/docker/volumes/266**298fb7/_data",
......
}
......
]
......

so, we can see that /var/lib/docker/volumes/266**298fb7/_data outside of container c3 is mapped into /Volume folder in Docker containers c1, c2 and c3.

Deploy MySQL 5.6 into container, and map its port from 3306 (inside container) to port 3307 (outside container).

First, we need to pull MySQL 5.6

Terminal window
$ docker search mysql
$ docker pull mysql:5.6

Second, we need to create container:

Terminal window
$ mkdir ~/mysql
$ docker run -id \
-p 3307:3306 \
--name=c_mysql \
-v ~/mysql/conf:/etc/mysql/conf.d \
-v ~/mysql/logs:/logs \
-v ~/mysql/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=toor \
mysql:5.6

Note:

  • -p 3307:3306 or --expose 3307:3306: map the port 3307 (outside container) to the container’s port 3306.
  • -e or --env: set the environment variable MYSQL_ROOT_PASSWORD as toor, which is the root password set for MySQL.

Third, we start and enter the container and test it:

Terminal window
$ docker exec -it c_mysql /bin/bash
$ mysql -uroot -p toor

Fourth, open MySQL with visual tool such as SQLyog Community

Map the port 8081 (outside container) to port 8080 (inside container):

Terminal window
$ docker search tomcat
$ docker pull tomcat
$ mkdir ~/tomcat
$ docker run -id \
--name=c_tomcat \
-p 8081:8080 \
-v ~/tomcat:/usr/local/tomcat/webapps \
tomcat

Now we can publish Servlet to folder ~/tomcat/ (outside container), and Tomcat inside container will find it in path /usr/local/tomcat/webapps. For demo, I just put a simple HTML ~/tomcat/test/index.html:

Terminal window
$ mkdir ~/tomcat/test
$ echo "Hello Tomcat in Container" > ~/tomcat/test/index.html

Now that the IP address outside container is 192.168.109.128, I open http://192.168.109.128:8081/test/index.html, and it will display “Hello Tomcat in Container”.

First, search and pull NGINX image.

Terminal window
$ docker search nginx
$ docker pull nginx
$ mkdir ~/nginx
$ mkdir ~/nginx/conf

Second, Copy the nginx.conf at /etc/conf/nginx.conf (inside contanier), and paste into ~/nginx/conf/nginx.conf (inside container):

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}

Third, start container:

Terminal window
$ docker run -id \
--name=c_nginx \
-p 80:80 \
-v ~/nginx/conf/nginx.conf:/etc/nginx/nginx.conf \
-v ~/nginx/logs:/var/log/nginx \
-v ~/nginx/html:/usr/share/nginx/html \
nginx

Now that the IP address outside container is 192.168.109.128, I open http://192.168.109.128:80, and it will display “Hello NGINX in Container”.

Terminal window
$ docker search redis
$ docker pull redis:5.0
$ docker run -id \
--name=c_redis \
-p 6379:6379 \
redis:5.0

A Dockerfile is a text document that contains all the instructions a user could call on the command line to build an image. And Docker runs instructions in a Dockerfile in order.

Frist, prepare the Spring Boot project. In this case, we will @RequestMapping("/helloworld") to print “Hello World” on http://localhost:8080/hello.

Second, pack the project to single *.jar file. In tab Maven Projects - <Your Spring Boot Project Name> - Lifecycle - package, and test *.jar file with: (the complete path is shown in Console))

Terminal window
$ java -jar /path/to/springboot-hello.jar

Third, upload to CentOS 7 with SFTP command:

sftp> PUT /path/to/springboot-hello.jar

And springboot-hello.jar will be uploaded as springboot-hello.jar (outside container). Later this file will be moved into ~/springboot-docker/springboot-hello.jar (also outside container).

Fourth, write springboot_dockerfile in path ~/springboot-docker/ (outside container):

# 1. Require Parent Docker Image: `java:8`
FROM java:8
# 2. Add `springboot-hello.jar` into container as `app.jar`
ADD springboot-hello.jar app.jar
# 3. command to execute Spring Boot app
CMD java -jar app.jar

Fifth, build the Docker;

Terminal window
$ docker build \
--file ./springboot_dockerfile \
--tag springboot-hello-app \
~/springboot-docker

Note:

  • --file or -f: specifies the Dockerfile named springboot_dockerfile.
  • --tag or -t: tags the image as springboot-hello-app

Sixth, start the image springboot-hello-app

Terminal window
$ docker run -id -p 9090:8080 springboot-hello-app

Now that the IP address outside container is 192.168.109.128, we can display the Spring Boot app at http://192.168.109.128:9090/hello

In path ~/tailored_centos/, create Dockerfile called centos_tailored_dockerfile:

# 1. Specify the parent Docker Image: `centos:7`
FROM centos:7
# 2. Specify the software to be installed
RUN yum install -y tomcat
# 3. Change to directory
WORKDIR /usr/local/tomcat/webapps
# 4. Set command to be executed
CMD /bin/bash
# 5. Expose port
EXPOSE 8080/tcp
EXPOSE 8080/udp
## this also can be done with shell:
## $ docker run \
## -p 8080:8080/tcp \
## -p 8080:8080/udp \
## <the rest parameters...>

Then we will build the docker:

Terminal window
$ docker build \
-f ./centos_tailored_dockerfile \
-t tailored_centos:1
~/tailored_centos

Next, we will run the container out of the docker image:

Terminal window
$ docker run -it \
--name=c_tailored_centos \
tailored_centos:1

Syntax of Dockerfile:

| Name | Description | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | --- | | FROM | specifies the Parent Image from which you are building | | RUN | execute commands in a new layer on top of the current image and commit the results | | | CMD | sets the command to be executed when running the image. | | LABEL | adds metadata (key-value pairs) to a docker image | | EXPOSE | informs Docker that the container listens on the specified network ports at runtime (tcp by default) | | ENV | sets the environment variable | | ADD | copies new files, directories or remote file URLs from <src> and adds them to the filesystem of the image at the path <dest> | | COPY | copies new files or directories from <src> and adds them to the filesystem of the container at the path <dest> | | ENTRYPOINT | allows you to configure a container that will run as an executable | | VOLUME | creates a mount point and marks it as holding externally mounted volumes from native host or other containers | | USER | sets the user name (UID) and optionally the user group (GID) to use as the default user and group for the remainder of the current stage | | WORKDIR | sets the working directory for any RUN, CMD, ENTRYPOINT, COPY and ADD instructions that follow it in the Dockerfile | | ARG | defines a variable that users can pass at build-time to the builder with the $ docker build command | | ONBUILD | adds to the image a trigger instruction to be executed at a later time, when the image is used as the base for another build | | STOPSIGNAL | sets the system call signal that will be sent to the container to exit | | HEALTHCHECK | tells Docker how to test a container to check that it is still working | | SHELL | allows the default shell used for the shell form of commands to be overridden |