Hands dirty with Docker

To install the docker machine in the AWS:

#for the default docker
docker-machine create --driver amazonec2 aws01

#for the custom centos
docker-machine create --driver amazonec2 --amazonc2-region ap-southeast-2 --amazonec2-ami ami-0c2aba6c -amazonec2-ssh-user ojitha aws-demo

If you run the above default (in the N. virginia region), here the way to set the env

~ docker-machine env aws01
#output is :
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://54.173.183.175:2376"
export DOCKER_CERT_PATH="/Users/ojitha/.docker/machine/machines/aws01"
export DOCKER_MACHINE_NAME="aws01"
# Run this command to configure your shell:
# eval $(docker-machine env aws01)

#for the custom
#eval $(docker-machine env aws-demo)

For example, to run a simplest docker container

~ docker run  --name hello-A dockerinaction/hello_world
Unable to find image 'dockerinaction/hello_world:latest' locally
latest: Pulling from dockerinaction/hello_world
a3ed95caeb02: Pull complete
1db09adb5ddd: Pull complete
Digest: sha256:cfebf86139a3b21797765a3960e13dee000bcf332be0be529858fca840c00d7f
Status: Downloaded newer image for dockerinaction/hello_world:latest
hello world

As shown in the above shell output, you can this container has been downloaded from the docker registry.

To display the docker containers at active

~ docker ps -a

Here the output of the command:

CONTAINER ID        IMAGE                          COMMAND                  CREATED             STATUS                       PORTS               NAMES
43e0288e9b09        dockerinaction/hello_world     "echo 'hello world'"     5 minutes ago       Exited (0) 5 minutes ago                         hello-A
63e8f6440a22        amazonlinux:latest             "/bin/bash"              12 months ago       Exited (137) 12 months ago                       suspicious_stonebraker
8ae7c51a90fe        microsoft/mssql-server-linux   "/bin/sh -c /opt/mss…"   12 months ago       Exited (137) 12 months ago                       hopeful_volhard

As you see all the containers are stoped, otherwise you can use the following command to stop the container

docker stop hello-A

For example install nginx server

docker run --detach --name web nginx:latest

Here detach will take the process to foreground: this process will not exist until use of the root process to exist using --rm option.

You can list all the local docker images

 ~ docker images
REPOSITORY                     TAG                 IMAGE ID            CREATED             SIZE
nginx                          latest              ae513a47849c        5 days ago          109MB
lambci/lambda                  python2.7           64cb3bf41370        7 months ago        965MB
microsoft/mssql-server-linux   latest              7b1c26822d97        12 months ago       1.35GB
amazonlinux                    latest              766ebb052d4f        13 months ago       162MB
dockerinaction/hello_world     latest              a1a9a5ed65e9        2 years ago         2.43MB

To show images repository, tag and image id:

docker image ls [<image>]

You can create your own docker container using Dockerfile, and running the following command:

docker build -t <image name>

to start

docker run --name <container name> <image name>

To remove unnecessary containers

docker system prune

Networking

Docker runs internal DNS server at 127.0.0.11 which is accessible. There are three types for networking
* None
* bridge (default): connect to the host via bridge
* Host : Directly connect to the host

Bridge is the preferred way to connect containers. Containers in the separate networks are isolated, but can connect to as many networks required. Docker container is discoverable via Docker DNS:. But DNS is not available in the default bridge.

To create the user define bridge networks, frontend, backend

docker network create  --driver bridge frontend
docker network create  --driver bridge backend

To find all the available networks, run

docker network ls

for example create two containers as follows:

docker container run -it --network=frontend -d  --name=front-1 busybox:latest
docker container run -it --network=backend -d  --name=backend-1 busybox:latest

Now if you create 3rd container without -d to interact and ping from there,

~ docker container run -it --network=backend  --name=backend-test busybox:latest
/ # ping -c 2 front-1
ping: bad address 'front-1'
/ # ping -c 2 backend-1
PING backend-1 (172.22.0.2): 56 data bytes
64 bytes from 172.22.0.2: seq=0 ttl=64 time=0.132 ms
64 bytes from 172.22.0.2: seq=1 ttl=64 time=0.139 ms

--- backend-1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.132/0.135/0.139 ms
/ #

As shown in the above example, you can only ping the back end network connections.

Now we can connect the backend-test container to frontend network as follows

docker network connect frontend backend-test

Now if you ping the front-1 container connection

docker attach backend-test

/ # ping -c 2 front-1
PING front-1 (172.21.0.2): 56 data bytes
64 bytes from 172.21.0.2: seq=0 ttl=64 time=0.123 ms
64 bytes from 172.21.0.2: seq=1 ttl=64 time=0.212 ms

--- front-1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.123/0.167/0.212 ms
/ #

This has been explained in the following diagram:

Docker originally comes with —link to connect containers. This is actually creates environment variables within the container with the IP address to connect. This is not longer recommended.

Dockerfile

Every docker project is depends on its Dockerfile.: specification need to build the Docker image. This file should be in the base directory. Each instruction in the specification create a new layer.

Here the way to create simple image which shows how to copy a file. Here the Dockerfile

FROM debian:stretch
COPY test.txt /data/test.txt

In the same directory run the following command. Don't forget the last . for the current directory.

docker build -t file-copy .

Now run the container

docker run --rm -it file-copy
root@fe5ba852cb54:/# ls data
test.txt
root@fe5ba852cb54:/#

To copy the directory for example test directory to data directory

FROM debian:stretch
COPY test /data/

for example to copy zip file the Dockerfile is

FROM debian:stretch
ADD test.txt.gz /data/

Now create a image

docker build -t zip-copy .

Now create a container and lis the contents in the data directory,

docker run --rm -it zip-copy ls -R /data
/data:
test.txt.gz

Use the RUN to execute shell script for example in the unix

RUN /bin/bash -c “set -o pipefail && wget -0 – http://<web site> | wc -l”

Run is the best command to install the os packages need for the application.

RUN has two forms:

FROM debian:stretch

RUN mkdir /app
WORKDIR /app
#get the file name with the interpreted host name such as host-is-c60cb038cf15
#RUN touch host-is-${HOSTNAME} 

# this is just host-is-${HOSTNAME}
RUN ["touch", "host-is-${HOSTNAME}"]
CMD ["ls"]

Test with the following commands,

docker build --rm --no-cache -f Dockerfile -t test:latest .
docker run --rm  test:latest ls -al

changes made by RUN are cached and which will save repeated builds. But cached old data can be a problem: use --no-cache flag to avoid this problem.

If you need to change the shell use the SHELL, for example Windows :

FROM microsoft/windowsservercore
SHELL ["powershell", "-NoProfile", "-Command"]

the CMD specify the default commands to run when the container is started. This has shell and exec forms as in the above command RUN. There can be only once CMD (not as multiple RUN commands) but can pass argument at the build time.

The ENTRYPOINT is similar to CMD but this allow the container to be a command.
To verify docker compose file, type in the same directory.

for example, see how to list the directory contents ?

FROM debian:stretch
ENTRYPOINT  ["ls"]

You can use both the CMD and the ENNTRYPOINT togather

FROM debian:stretch
ENTRYPOINT  ["echo"]
CMD  "hello ojitha"

if you run, the CMD will pass the string to the ENTRYPOINT and display "hello ojitha".

Let's see how to use network ports. Here the simple Dockerfile:

 FROM ruby:latest

# update and install nodejs
RUN apt-get update && apt-get install -y nodejs
# intall rail 
RUN gem install rails

RUN mkdir /app
WORKDIR /app
# start blog 
RUN rails new blog 

# Expose prot 3000
EXPOSE 3000

# change the work directory
WORKDIR /app/blog

# start the server
ENTRYPOINT [ "bin/rails" , "server"]

Create image as follows

 docker build --rm  -f Dockerfile -t blog:latest .

Run the docker container as follows in the background and assign port 3000 to random local port:

 docker run -d -p 3000 --name demo  blog:latest

Now run the following command to find the local mapping to the exposed port:

 docker container ps

If you found the port , then see in the browser http://localhost:<port> to access the site.

docker-compose config

to build the docker image

docker-compose build --no-cache
docker-compose up -d

To see all the containers created in the above step

docker-compose ps

to follow the logs:

docker-compose logs -f

Environment Variables

The ENV is the command to define the environment variables in the Dockerfile such as:

FROM debian:stretch

ENV NAME=ojitha
RUN mkdir /app
ADD script.sh /app/script.sh
WORKDIR /app
RUN chmod +x script.sh
CMD ["./script.sh"]

This script.sh file has only one line:

#!/bin/bash
echo Hello $NAME !

If you need to pass in the command line to override the Dockerfile variable name:

docker run --rm -e NAME=world file_copy:latest

#or
docker run --rm -e NAME="world of mine" file_copy:latest

If you have more variable to manage, then use a file such as mytest.env: line per varaible

NAME=Australia

Then run with the flag --env-file as follows:

docker run --rm --env-file testprop.env file_copy:latest

As ENV there is ARG which help to define such as for example dev, test and prod environments.

For example suppose, you have dev.conf, test.conf and prod.conf. For dev you have to copy dev.conf to env.conf, for prod environment you have to copy prod.conf to env.conf.

FROM debian:stretch
ARG env=dev
COPY ${env}.conf /env.conf

The files prod.conf, test.conf and dev.conf should be in the root directory to copy. You can run

# build image 
docker build --rm -f Dockerfile -t file_copy:latest .

# create container
docker run --rm  file_copy:latest cat /env.conf

This should display the contents of the dev.conf file.

To see all the running processors in the docker compose

docker-compose top

from the above command you can get the up and running containers, if you need to stop or start a particular container

docker-compose stop  <container>
# ....
docker-compose start <container>

# or use the following to create and start the container
docker-compose up <container>

following command stop giving any resources to the container , but you cannot restart host and un-pause

docker-compose pause

but above is good to get the snapshot

To completely destroy what have been done with

docker-compose down

Above will stop all containers created and remove them as well. Be careful !

retag the docker image

# form the docker image ls find the existing tag
docker tag <existing-tag> <new-tag>
#to push to local repo
docker push <new-tag>

Comments

Popular posts from this blog

How To: GitHub projects in Spring Tool Suite

Spring 3 Part 7: Spring with Databases

Parse the namespace based XML using Python