Docker - My New Sandbox Tool
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.
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.
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.