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.

INSTALLATION

Environment: CentOS 7 Minimal on VMware Player 17

1$ yun update
2$ yum install -y \
3    yum-utils \
4    device-mapper-persistent-data \
5    lvm2
6$ yum-config-manager \
7    --add-repo https://download.docker.com/linux/centos/docker-ce.repo
8$ yum install -y docker-ce
9$ docker -v

DOCKER COMMANDS

DAEMON

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

1$ systemctl start    docker
2$ systemctl stop     docker
3$ systemctl restart  docker
4$ systemctl status   docker 

To enable autostart:

1$ systemctl enable   docker

IMAGE

List Images

To list local images, type:

1$ docker images

and it will return a table like:

REPOSITORY TAG IMAGE ID CREATED SIZE

Note:

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

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

1$ docker images -q

Search Images

1$ docker search redis

and it will return a table like:

NAME DESCRIPTION STARS OFFICIAL AUTOMATED
redis Redis is an open source key-value store that… 12156 [OK]

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

Pull Images

If we want to pull Redis, we just type:

1$ 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:

1$ docker pull redis:5.0

Remove Images

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

1$ docker rmi redis:5.0
2$ docker rmi c5da061a611a

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

1$ docker rmi `docker images -q`

CONTAINER

A Container is built out of Docker Image.

Container Status and Inspection

The status for a container can be UP or Exited.

1$ docker ps       # List all the running container
2$ docker ps --all # List all the history container(s)
3$ docker ps -a    # Also List all the history container(s)

Or, we can inspect a container for more details:

1$ docker inspect CONTAINER_NAME

Create Container

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

1$ 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:
1$ docker run --interactive --tty --name=test_container centos:7 /bin/bash
2$ docker run -i -t --name=test_container centos:7 /bin/bash
3$ 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:
1$ docker run --interactive --detach --name=test_container2 centos:7
2$ docker run -i -d --name=test_container2 centos:7
3$ docker run -id --name=test_container2 centos:7

Enter Container

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

1$ docker exec --interactive --tty test_container2 /bin/bash
2$ docker exec -i -t test_container2 /bin/bash
3$ docker exec -it test_container2 /bin/bash

Stop or Start Container

1$ docker stop CONTAINER_NAME
2$ docker start CONTAINER_NAME

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

Remove Container

1$ 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

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

Volume Mapping

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

 1$ docker run -it \
 2    --name=testVol1 \
 3    --volume ~/data1:/root/container_data1 \
 4    --volume ~/data2:/root/container_data2 \
 5     centos:7 \
 6     /bin/bash
 7
 8$ docker run -it \
 9    --name=testVol1 \
10    -v ~/data1:/root/container_data1 \
11    -v ~/data2:/root/container_data2 \
12     centos:7 \
13     /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

Volume Container

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

1$ docker run -it \
2    --name=c3 \
3    -v /Volume \
4    centos:7 \
5    /bin/bash

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

1$ docker run -it --name=c1 \
2    --volumes-from c3 \
3    centos:7 /bin/bash
4$ docker run -it --name=c2 \
5    --volumes-from c3 \
6    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:

 1......
 2"Mounts": [
 3            {
 4                "Type": "volume",
 5                "Name": "266**298fb7",
 6                "Source": "/var/lib/docker/volumes/266**298fb7/_data",
 7                ......
 8            }
 9            ......
10]
11......

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.

DEPLOYMENT

MySQL

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

1$ docker search  mysql
2$ docker pull    mysql:5.6

Second, we need to create container:

1$ mkdir  ~/mysql
2$ docker run -id \
3    -p 3307:3306 \
4    --name=c_mysql \
5    -v ~/mysql/conf:/etc/mysql/conf.d \
6    -v ~/mysql/logs:/logs \
7    -v ~/mysql/data:/var/lib/mysql \
8    -e MYSQL_ROOT_PASSWORD=toor \
9    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:

1$ docker exec -it c_mysql /bin/bash
2$ mysql -uroot -p toor

Fourth, open MySQL with visual tool such as SQLyog Community

Tomcat

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

1$ docker search tomcat
2$ docker pull   tomcat
3$ mkdir ~/tomcat
4$ docker run -id \
5    --name=c_tomcat \
6    -p 8081:8080 \
7    -v ~/tomcat:/usr/local/tomcat/webapps \
8    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:

1$ mkdir ~/tomcat/test
2$ 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".

NGINX

First, search and pull NGINX image.

1$ docker search nginx
2$ docker pull   nginx
3$ mkdir ~/nginx
4$ 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:

1$ docker run -id \
2    --name=c_nginx \
3    -p 80:80 \
4    -v ~/nginx/conf/nginx.conf:/etc/nginx/nginx.conf \
5    -v ~/nginx/logs:/var/log/nginx \
6    -v ~/nginx/html:/usr/share/nginx/html \
7    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".

Redis

1$ docker search redis
2$ docker pull   redis:5.0
3$ docker run -id \
4    --name=c_redis \
5    -p 6379:6379 \
6    redis:5.0

DOCKERFILE

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.

Examples

Deploy Spring Boot

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))

1$ java -jar /path/to/springboot-hello.jar

Third, upload to CentOS 7 with SFTP command:

1sftp> 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# 1. Require Parent Docker Image: `java:8`
2FROM java:8
3
4# 2. Add `springboot-hello.jar` into container as `app.jar`
5ADD springboot-hello.jar app.jar
6
7# 3. command to execute Spring Boot app
8CMD java -jar app.jar

Fifth, build the Docker;

1$ docker build \
2    --file ./springboot_dockerfile \
3    --tag  springboot-hello-app \
4    ~/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

1$ 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

Tailored CentOS

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

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

Then we will build the docker:

1$ docker build \
2    -f ./centos_tailored_dockerfile \
3    -t  tailored_centos:1
4    ~/tailored_centos

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

1$ docker run -it \
2    --name=c_tailored_centos \
3    tailored_centos:1

Syntax

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

* This blog was last updated on 2023-06-17 23:10