Docker - My New Sandbox Tool

Docker

What is Docker

In simpler words, Docker is a container manager but not truly a virtualization solution like VirtualBox b/c it doesn't come with OS. Instead, it sit directly on top of the host OS and share the kernel and hardware of the host machine. That is why it is much lightweight (roughly the same overhead as regular process). To make it clear, I borrow the image from Cedric in Spantree. I strongly suggest you to read his [blog] (http://www.spantree.net/2015/04/29/10-things-to-know-about-docker.html) for detail.

VM vs Docker

As you can see it cuts out the layer of Guest OS that reduces the cost of converting operations from Guest OS to Host OS. On the other, it assumes the host OS is Linux and it extends the Linux Container with a high level API that provides a lightweight virtualization solution that runs processes in isolation. So, if you need to run Docker in Window, you still need a VM to provide this abstraction for you.

So, people normally use it for sandbox their app in a clean environment for testing or development. Here are some facts about Docker I collected from the Net:

Have Docker provided me a sandbox

I am not the person to tell you the nitty-gritty detail about VM or compare vagrant with docker. I am sure you can follow the links I provided to get more info. My goal here is simple. All I want is to get my java 8 environment up on ubuntu right from my mac. So, I can develop locally while run tests against my app as it were in production without leaving my box. Whatever tool can achieve this fast with less in resource demand wins.

See Docker in Action

Docker VM Machine

create a default docker virtual machine

$ docker-machine create --driver virtualbox default

list out all docker vm

$ docker-machine ls
NAME      ACTIVE   DRIVER       STATE     URL                         SWARM
default   *        virtualbox   Running   tcp://192.168.99.100:2376   
dev                virtualbox   Saved

check environment

$ docker-machine env default
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.100:2376"
export DOCKER_CERT_PATH="/Users/ray/.docker/machine/machines/default"
export DOCKER_MACHINE_NAME="default"

machine configuration

$ cd ~/.docker/machine/machines/default/

stop | start | restart | rm a vm machine

$ docker-machine stop default

ssh login to the machine

$ docker-machine ssh default

get info of a vm machine

$ docker-machine inspect default


Docker Container + Image

create a container with an image

Give this container a name called web instead of using container id to access and run image 'nginx' on it

$ docker run -d -P --name web nginx

check if the container is up

$ docker ps

check container port using name

Example below saying web container's port 80 is mapped to port 32769 on your docker host

$ docker port web
443/tcp -> 0.0.0.0:32768
80/tcp -> 0.0.0.0:32769

you cannot simply access thru localhost:32769 for the nginx as your docker host ip is the vm machine ip. You can check via:

$ docker-machine ip default
192.168.99.100

and you can access nginx via: http://192.168.99.100:32769

stop | start | restart | kill | rm the container

$ docker stop web
$ docker start web

//remove all containers (stop container before remove!)
$ docker rm $(docker ps -aq)

//stop all containers and remove them
$ docker rm $(docker stop $(docker ps -aq))

//remove all images
$ docker rmi $(docker images -q)

//remove all images except my-image
$ docker rmi $(docker images | grep -v 'ubuntu\|my-image' | awk {'print $3'})

Remove a container

$ docker stop $JOB # Container must be stopped to remove it
$ docker rm $JOB
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
124601f66700        vertexdev           "vertx run vertx-exam"   32 minutes ago      Up 32 minutes       0.0.0.0:8080->8080/tcp   trusting_lumiere
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                         PORTS                    NAMES
bc02f0937607        vertexdev           "vertx run vertx-exam"   27 minutes ago      Created                                                 happy_davinci
124601f66700        vertexdev           "vertx run vertx-exam"   32 minutes ago      Up 32 minutes                  0.0.0.0:8080->8080/tcp   trusting_lumiere
c00b590a2f70        docker-whale        "/bin/sh -c '/usr/gam"   About an hour ago   Exited (0) About an hour ago                            sleepy_brattain
a55a5a0e362a        docker/whalesay     "cowsay boo"             2 hours ago         Exited (0) 2 hours ago                                  distracted_wozniak
03f026eda41f        hello-world         "/hello"                 3 hours ago         Exited (0) 3 hours ago                                  insane_leakey

log into the container

$ docker exec -it web bash

mount drive to the container

$ docker run -d -P -v $HOME/site:/usr/share/nginx/html --name mysite nginx
  • -v : mount drive $HOME/site (host folder) whereas /usr/share/nginx/html (container folder)
  • --name : give a name of the container
  • -d : run as background

Uninstall docker as a whole

  • remove each docker machines from the list
  • remove machines configuration folder ~/.docker/machine/machines
  • remove command lines
$ rm /usr/local/bin/docker (docker-compose, docker-machine as well)
  • remove ~/.docker folder

Docker Compose: Multi-Containers

Lets go with an example from the Docker site here. It is an python example.

app.py

from flask import Flask
from redis import Redis

app = Flask(__name__)
redis = Redis(host='redis', port=6379)

@app.route('/')
def hello():
    redis.incr('hits')
    return 'Hello World! I have been seen %s times.' % redis.get('hits')

if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)

You can see the python code will simply listen to url with route "/". Once a request comes, it will increment the count in Redis and output the message in UI. So, the code will require flask and redis library to run. We can define the dependencies using requirements.txt file below:

requirements.txt

flask
redis

Then, create an image out from the web server code above.

Dockerfile

FROM python:2.7
ADD . /code
WORKDIR /code
RUN pip install -r requirements.txt
CMD python app.py

Build the image (ie. web) and run it with port 5000 exposed.

$ docker build -t web .
$ run -d -p 5000:5000 --name web1 web

If you go to http://[vm ip]:5000 now, you will get the error message below as redis is not up in the container.

Docker

To fix it, you need to bring up the redis along with your web app. Since we have the redis image, we don't need to build the image for it. Below is the compose yml (ie. docker-compose.yml) that shows you how to link 2 images together so you can use single command to bring them all up.

web:
  build: .
  ports:
   - "5000:5000"
  volumes:
   - .:/code
  links:
   - redis
redis:
  image: redis

Once you do that, you now can bring up the 2 images together with docker-compose command.

$ docker-compose up -d  //-d is to may the process run in background

If you go to http://[vm ip]:5000 now, you will see the message below. Test it via refresh, you can see the count changing and it means redis integration is working.

Docker