√.. _basics:

Docker Basics

This section focuses on the docker run command, which turns images into running containers.

Image

  • Just enough of the operating system to do what you need to do
  • You can have lots and lots of these on the computer
$ docker images
  • This will show all docker images, including:
    • Repository
    • Tag
    • Image ID
    • Date Created
    • Size

What do we use Images for?

  • We “run” images with docker run to turn an image into a Container

Example:

$ docker run -ti ubuntu:latest bash

This will run an image of the latest version of Ubuntu - The -ti flag tells docker that we wish to use a shell with this image - bash automatically enters the shell for the running Docker image - When we make a container from an image, that image does not change.

Containers

Once we have an image running inside of a container (as above), we can now use docker ps to see the running container on our system:

$ docker ps

This will output each running container by its ID, which is different from the image ID.

Files

For practice, create the ubuntu:latest image and create a file from a shell of that image:

$ touch hello

If we create a new container from this same image (ubuntu:latest) and create the same file in the same location, it will not be visible in the other container.

Stopped Containers

  • Alive containers have a running process in them
  • When this process ends, the container stops

By default, docker-ps only displays the containers which are running. To view all containers, use:

$ docker ps -a

We can view the most recently-exited container as well:

$ docker ps -l

So what can we do with stopped containers? Say we have a file inside a stopped container that we would like to access after it has stopped

Docker Flow: Containers to Images

This section focuses on the docker commit command, which enables the creation of images from containers. Say we’ve created a file in a running container that we would like to retrieve after that container is stopped. What can we do?

  • This will not overwrite an existing image
  1. Create a new Ubuntu container and create an arbitrary file
$ docker run -ti ubuntu bash
$ touch HELLO
  1. Exit the container using ctrl-D or exit
  2. Obtain the container ID through docker ps -l
  3. Create an image from the stopped container using docker commit:
$ docker commit <CONTAINER-ID>

The outcome of this command will be a long hash signature (sha256:), which can then be used to name the created image with docker tag

$ docker tag <HASH-TAG> <DESIRED-NAME>

OR

We can just specify the desired name when we commit in the first place

$ docker commit <CONTAINER-ID> <DESIRED-NAME>

The latter method is the easiest, but it is necessary to show the tag command for an understanding of what’s going on behind the scenes. We now have an image named DESIRED-NAME.

  1. Run a container from the new image to see your file
$ docker run -ti <DESIRED-NAME> bash
$ ls

Docker Commands

Attaching/Detaching Containers

  • docker-run - starts a docker container, which has a main process
    • Containers stop when that main process stops
      • Even if you run other processes, it waits for the main process to stop
    • docker run --rm
      • This says that after the command is run, get rid of the container
      • This is good for one time use
      • Example: start a container that will sit there for 5 seconds and then exit
      $ docker run --rm -ti ubuntu sleep 5
      
      • We could also run a more fancy container:
      $ docker run --rm -ti ubuntu "sleep 3; echo "all done""
      
      • This will start a container that will run for 3 seconds and then print “all done”
    • docker run -d
      • This will start a detached container. We can retrieve this container ID from docker ps
      • We can then attach the detached container by obtaining its container ID and running docker attach <CONTAINER-ID>
      • To exit a container by detaching it instead of stopping it, use ctrl-P + ctrl-Q

Killing/Removing a Container

We can kill an existing container using the command:

$ docker kill <CONTAINER-ID>

We can also kill and remove the container completely in one step using:

$ docker rm <CONTAINER-ID>

Starting a new process

The command docker exec can start a new process in an existing (running) container.

Container Output (Logs)

We can capture the output of a container using the docker log command. Let’s create a container whose main process is going to fail:

$ docker run --name bad -ti ubuntu bash -c "lose /etc/password"

We’ve created a Ubuntu container bad which will attempt to execute the command lose /etc/password. Given that this is an invalid bash command (we have probably misspelled ‘less’), it will immediately exit with code 1 and the container will be killed. So we try:

$ docker logs bad

This will show us bash: lose: command not found, which is the reason that the container was killed!

Container Resources

Memory Constraints

$ docker run --memory maximum-allowed-memory

CPU Constraints

We can limit CPU usage relative to another container - “If one container is not using any resources, allow the other to have them. If they are both running, split the resource 50/50 if both containers are using an equal amount of the resource”

$ docker run --cpu-shares

We can also set a hard limit on CPU usage

$ docker run --cpu-quota

Many orchestration systems force you to set resource limits on containers

General Tips

  • Do not allow docker containers fetch dependencies when they start
    • If the dependencies change or are removed, the containers will all die
  • Do not leave stopped unnamed containers sitting around
    • Security issue: you or someone else may just delete all the containers to save space or attack