• Docker is based on LXC, an operating system level containerization method. Docker offers a high level tool on top of that.
  • The main purpose of Docker is to package and containerize applications with their dependencies and ship them
  • Docker uses Namespaces to provide isolation
    • Docker uses cgroups (control groups) to restrict the amount of hardware resources allocated to each container

Common Docker commands

  1. docker run
    • Run a container from an image. If the image is not present on the host, docker will search and download it from the configured registry (DockerHub)
    • Attached or Detached mode
      • docker run -d image_name
      • docker attach container_id : Attach a detached container
    • Specify a tag
      • docker run -d redis:4.0 : Here, 4.0 is the tag
      • If you don't specify a tag, latest is considered by default
  2. docker ps
    • List running containers with some basic information
    • docker ps -a : List ALL containers
  3. docker stop container_name_or_id
    • Stop a running container
  4. docker rm container_name_or_id
    • Remove a stopped container
  5. docker images
    • Show available images
  6. docker rmi image_name
    • Remove an image
  7. docker pull
    • Only pull an image but don't run
  8. Execute a command on a running container
    • docker exec container_name_or_id cat /etc/hosts
  9. Port mapping : map a port from inside the docker container to the host its running on
    • docker run -p 80:5000 tanmay/my-simple-app
    • The above command will make sure that all traffic on port 80 of your host is routed to port 5000 inside your docker container
  10. Data persistance
    • You can map a directory on your host (outside the docker container) to a file system location of your container to make sure the data persists
    • e.g. Assume that you're running a mysql container
      • the mysql server stores its data at the location var/lib/mysql. If you remove the container, this data will be lost
      • you can map a directory on your host instead like so:
        • docker run -v /opt/datadir:/var/lib/mysql mysql
        • This way when the container runs, it will mount the external directory and store the data there
  11. Inspecting the container (sometimes ps is not enough)
    • docker inspect container_name_or_id
    • Returns the container configuration in JSON format
  12. Logs
    • docker logs container_name_of_id
  13. Passing environment variables to docker run
    • docker run -e APP_COLOR=blue simple-web-app
  14. List all networks
    • docker network ls

Important points

  • A container lives only until the process inside it is alive
  • To map the standard input of your host to a container, you need to pass the i flag for the interactive mode
    • docker run -i redis
  • To get the app's output on your terminal, use the -t flag for the terminal mode
    • docker run -it redis
  • The -it combination makes sure that your container is attached to the terminal as well as running in interactive mode

Dockerfile

  • All Dockerfiles must start with the FROM command (every Docker image derives from a base image. Either an OS or an existing app)
  • Each line in the Dockerfile creates a new layer
  • All built layers are cached. This allows rebuilds to be fast
  • Instructions
    • CMD
      • Defines the program that will be run within the container when it starts
      • The command and its parameters should be separately specified like so : CMD ["sleep", "5"] and NOT like CMD ["sleep 5"]
      • You can also specify the command to be run at startup from the command line: docker run ubuntu sleep 10. This will override the command in the Dockerfile
    • ENTRYPOINT
      • This instruction will append to the list of existing commands in the Dockerfile
from IPython.display import Image
Image("../images/entrypoint_and_cmd.png")
Image("../images/entrypoint_and_cmd_2.png")

Networking in Docker

  • When you install docker, it creates 3 networks automatically:
    1. Bridge: this is the default network a container gets attached to
      • it's a private and internal network
      • All containers attched to Bridge get an internal IP address by default
      • The containers can access each others using this IP if required
    2. none
      • the containers are not attached with any network. They are completely isolated.
    3. host
      • if you use the host network, you can directly run a container on the required port, without any port mapping
      • but this also means that you won't be able to run multiple instances on the same host on the same port
  • You can modify the network information using the cli parameter --network
    • docker run ubuntu --network=host
  • Create a network
    • docker network create --driver bridge --subnet 182.18.0.0/16 my-custom-network
  • Containers can reach each others using their names
    • Docker has a built in DNS server and it always runs at 127.0.0.11

Storage in Docker

  • When you install docker, it creates the following directory structure

    • /var/lib/docker
      • aufs
      • containers
      • image
      • volumes
  • Adding a persistent volume to a container

    • docker volume create data_volume (this gets stored in the volumes directory above)
    • docker run -v data_volume:/var/lib/mysql mysql
    • If you run the above command w/o first creating a volume, docker will automatically create a volume
      • docker run -v data_volume2:/var/lib/mysql mysql
    • If you want to mount an existing location on the host, use the following command instead (This is called a Bind mount)
      • docker run -v /data/mysql:/var/lib/mysql mysql
    • The more recent syntax is as follows:
      • docker run --mount type=bind,source=/data/mysql,target=/var/lib/mysql mysql
  • Docker uses readily available storage drivers on the OS to handle all this

    • AUFS
    • ZFS
    • BTRFS
    • Device Mapper
    • Overlay
    • Overlay2

Docker Compose

  • Create a configuration file in YAML to create an entire application stack
  • Can be used on a single host

Example - a simple web app with UI

Assume that the app is using several different services

  1. A python app called voting-app that has a front end UI
  2. A redis in memory database
  3. A postgreSQL database
  4. A worker written in .NET
  5. A result app that shows the votes

How will this look using plain docker commands?

Note: The following way of Linking together containers is soon going to be deprecated, and will be replaced with better methods. Showing them here just for knowledge.

  1. docker run -d --name=redis redis
  2. docker run -d --name=db postgres:9.4
  3. docker run -d --name=vote -p 5000:80 --link redis:redis voting-app
  4. docker run -d --name=result -p 5001:80 --link db:db result-app
  5. docker run -d --name=worker --link db:db --link redis:redis worker

Using Docker compose (Version 1)

    redis:
        image: redis
    db:
        image: postgres:9.4
    vote:
        image: voting-app
        ports:
            - 5000:80
        links:
            - redis
    result:
        image: result-app
        ports:
            - 5001:80
        links:
            - db
    worker:
        image: worker
        links:
            - redis
            - db

Now, use docker-compose up to create the entire stack