Skip to content

Latest commit

 

History

History
885 lines (565 loc) · 23.4 KB

full-lab.md

File metadata and controls

885 lines (565 loc) · 23.4 KB

Docker Hands-on Lab for a beginner

Before start

Some of following lab instructions contain both solo and management commands. Both types of commands do the same things so you can choose one over the other as you like. The intention of having both command types in the lab is to let you be aware of and familiarize with them.


Container Usages

Lab details

- Pull container image form Docker Hub

By default, Docker will be pulling container images from Docker Hub if you didn't specify any registry or repository.

  • Pulling a NGINX container image without specifying a tag. Docker will pull the image with latest tag.

    docker pull nginx
    # OR
    docker image pull nginx
  • Pull container image with a specific tag by adding : after the image name followed by a tag name.

    docker pull nginx:1.21
    # OR
    docker image pull nginx:1.21

- Pull container image from other registries

Apart from Docker Hub, Docker can also pull container images from other private and public registries or repositories.

  • Pulling an Open JDK 8 container image from quay.io.

    docker image pull quay.io/aptible/nginx:latest

- Get list of container images

  • Get list of container images on the host.

    docker images
    # OR
    docker image ls

- Run a container with container image in local

  • Run a container with the image you just pulled above.

    docker run nginx:1.21
    # OR
    docker container run nginx:1.21
  • Press Ctrl + C on keyboard to stop and exit from the container.


- Run a container without container image in local

Any container can be run without pulling the container image manually. Docker will be finding the container image in local first, if the container image doesn't exist then it will try to pull the container image from container image repository (Docker Hub).

  • Run a container without pulling container image.

    docker container run httpd
  • Press Ctrl + C on keyboard to stop and exit from the container.


- Run a container and give it a name

Normally, a container will be given a random name when you run it without giving it a name. However, random name is hard to remember and doesn't indicate what application running in the container is.

  • Run a container and name it by adding --name flag followed by a name you need to assign to the container. The container name can be used as a reference with other commands i.e. docker container stop.

    docker run --name nginxserver nginx:1.21
    # OR
    docker container run --name nginxserver nginx:1.21
  • Press Ctrl + C on keyboard to stop and exit from the container.


- Run a container and override its default command

A default command (specified in Dockerfile) will get run when you run or start a container. However, you can also override the default command with new command(s) you need to execute inside the container.

Please note that the container must have binary or execution file(s) for any new command(s) you need to execute inside the container. For example, if you need to execute wget inside the container then the wget binary must exist inside the container.

  • Run a container and override its default command with a single command

    docker run nginx:1.21 ls -la
    # OR
    docker container run nginx:1.21 ls -la
  • Override with multiple commands

    docker run nginx:1.21 sh -c 'uname -a && pwd && ls -la'
    # OR
    docker container run nginx:1.21 sh -c 'uname -a && pwd && ls -la'

- Set environment variable for a container

Each container has it own set of environment variables inside the container separately from the host. Some of containers might need environment variable(s) to run i.e. username, password, configs etc. or you might need to inject some values into the container which can be done via environment variables as well.

  • Run a container and inject an environment variable using -e flag followed by environment variable name and its value.

    docker run -e MESSAGE="Hello world" ubuntu sh -c 'echo $MESSAGE'

    The command above injects a MESSAGE environment variable into the Ubuntu container so the MESSAGE environment variable can be used with echo command.

  • Run a container and inject multiple environment variables.

    docker run -e MESSAGE1="Hello" -e MESSAGE2="world" ubuntu sh -c 'echo $MESSAGE1 $MESSAGE2'

- Running a container in interactive mode

Usually, Docker will bind standard input (stdin), standard output (stdout), and standard error (stderr) (which usually is your terminal) to the container's tty when running a container. That's why you can see some outputs i.e. logs generated from the container.

However, some containers don't have the processes that keep running which then keep your terminal connected to the container's tty. Ubuntu container, for example, wich doesn't have any process that will keep running inside the container. It's default command that will be run when the container gets started is bash which does nothing but a Bash shell. So, if you need to keep your terminal connected to the container's tty then you can run the container with interactive mode.

  • First, run a container without interactive mode. You won't see any output like you ran NGINX container previously because the default command of Ubuntu container is bash and it doesn't do anything so it just runs and stops immediately.

    docker run ubuntu
    # OR
    docker container run ubuntu
  • Run a container again but this time with interactive mode by adding -it flag. Your terminal will get connected to the container's tty and you will get Bash shell prompt.

    docker run -it ubuntu
    # OR
    docker container run -it ubuntu
  • Then run this command to check OS name, build number, architecture etc.

    uname -a
  • Exit from the container by typing exit and press Enter on keyboard.

  • Then run uname -a again and compare the command outputs. You will see the different of outputs from the container and the host itself.


- Run a container in detatch mode

Usually, as explained above, your terminal will get connected or binded to the container's tty when running a container and obviously that you won't be able to run any commands on the host with that terminal because the terminal is already dedicated to the container. If you need to run a container but don't need to tie your terminal to it then you can run the container in detatch mode.

Also, sometime you might need to run the container as a background process like a daemon process. To do so, you can run a container with detatch mode as well.

  • Run NGINX container in detatch mode by adding -d flag. The container will be running in background like daemon processes.

    docker run -d --name nginx-daemon nginx
    # OR
    docker container run -d --name nginx-daemon nginx

    Docker will print out only container ID and you won't see any output or logs.

  • Use following command to check if the container is running.

    docker ps
    # OR
    docker container ls

- Get list of containers

  • Get list of running containers.

    docker ps
    # OR
    docker container ls
  • Get list of all containers regardless of their statuses.

    docker ps -a
    # OR
    docker container ls -a

- Attach to a container running in detatch mode

  • Run an Ubuntu container in detatch mode (-d) and name the container (--name) as ubuntu-date and override its default command (bash) with an inline while loop that will be printing current date and time every second.

    docker run -d --name ubuntu-date ubuntu sh -c 'while true; do date; sleep 1; done'

    Docker will print out only container ID and you won't see date and time get printed out because the container will be running as a background process.

  • Attach local standard input, output, and error (your terminal) to the container.

    docker attach ubuntu-date
    # OR
    docker container attach ubuntu-date

    You'll see date and time get printed out for every second.

  • Press Ctrl + C on keyboard to stop and exit from the container.


- Execute command inside a container from host

While any container running in background (detatch mode), you can run command(s) inside those container without jumping into the container i.e. attach to the container.

Please note that the container must have binary or execution file(s) for the command(s) you need to execute inside the container. For example, if you need to execute wget inside the container then the wget binary must exist in the container as well.

  • First, run a container in detatch mode.

    docker run -d --name mynginx nginx:1.21
    # OR
    docker container run -d --name mynginx nginx:1.21
  • Run env command inside mynginx container.

    docker exec mynginx env
    # OR
    docker container exec mynginx env

- Inspect a container

You can inspect the details of any container to see its details i.e. Network, Mount, Configurations and so on.

  • Inspect mynginx container you ran earlier to see its details.

    docker inspect mynginx
    # OR
    docker container inspect mynginx

- Inspect inside a running container

You can inspect and see what's inside a running container by executing the Shell i.e. bash inside the container with interactive mode and use ls command to explore file system hierarchy inside the container.

  • Get an interactive terminal for mynginx container.

    docker exec -it mynginx /bin/sh
    # OR
    docker container exec -it mynginx /bin/sh
  • Use ls command to explore filesystem inside the container.

  • Type exit and press enter to exit. This will just exit from the Shell process and won't stop the main process of the container, NGINX, in this case.


- Inspect container logs

  • Get all logs from mynginx container.

    docker logs mynginx
    # OR
    docker container logs mynginx
  • Keep following logs from mynginx container.

    docker logs -f mynginx
    # OR
    docker container logs -f mynginx
  • Press Ctrl + C on keyboard to exit and return back to terminal.


- Manage containers

  • First, get list of all containers.

    docker ps -a
    # OR
    docker container ls -a
  • Start a stopped container. Any container has been stopped can be started again. For example, using follwing command to start the ubuntu-date container you ran earlier.

    docker start ubuntu-date
    # OR
    docker container start ubuntu-date
  • Stop a running container. Use following command to stop myginx container you ran earlier.

    docker stop mynginx
    # OR
    docker container stop mynginx
  • Stop multiple running containers. Use following command to stop ubuntu-date and nginx-daemon containers you ran earlier.

    docker stop ubuntu-date nginx-daemon
    # OR
    docker container stop ubuntu-date nginx-daemon
  • Verify that there isn't any container running.

    docker ps
    # OR
    docker container ls
  • Delete a container. Use following command to delete mynginx container.

    docker rm mynginx
    # OR
    docker container rm mynginx
  • Verify that all containers are stopped e.g. the status is Exited.

    docker ps -a
    # OR
    docker container ls -a
  • Delete all stopped containers using this command. Enter 'y' to confirm deletion.

    docker container prune
  • Verify that all containers have been removed.

    docker ps -a
    # OR
    docker container ls -a

Container Storage

Lab details

- Docker Volume: anonymous volume

Some of containers use volume to store data produced by the container (to be precise, the application running in the container). Docker will create (anonymous) volume for the container automatically.

  • Run a Postgres container that uses volume.

    docker container run -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=testdb --name postgresdb1 -d postgres
  • Inspect the container to get volume information using this command. Then look for "Mounts" section. You will see mount type, volume name, and its location.

    docker container inspect postgresdb1
  • Verify that the anonymous volume gets created.

    docker volume ls
  • (Optional) Use ls command to explore data inside the volume.


- Docker Volume: named-volume

Anonymous volume name is randomly generated, not human readible and hard to remember. It will be a nightmare if you run many containers that use many anonymous volumes because it will be hard to figure out which volume belongs to which container. Named-volume can help in this case.

  • Run a container with a named-volume by adding -v flag followed by volume name and path inside the container separated by :.

    docker container run -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=testdb -v pgdata:/var/lib/postgresql/data --name postgresdb2 -d postgres
  • Inspect the container to get volume information using the command below. Then look for "Mounts" section. You will see mount type, volume name, and its location.

    docker container inspect postgresdb2
  • Verify that the pgdata volume gets created.

    docker volume ls
  • (Optional) Use ls command to explore data inside the volume.


- Docker Bind mount

Volume is managed by Docker and stored in a specific location on host e.g. /var/lib/docker/volumes. If you need to store data produced from a container anywhere on the host then you can use bind mount to mount any directory on the host to a directory inside the container.

You can also use bind mount to inject any directory into the container as well. For example, you can inject a directory of Java project into a Maven container then execute the maven commands inside the container to compile, build, run and so on.

  • Run a container and mount mypgdata directory to the container with bind mount.

    docker run -d -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=testdb -v $HOME/mypgdata:/var/lib/postgresql/data --name postgresdb3 postgres
  • Inspect the container to get volume information using the command below. Then look for "Mounts" section. You will see mount type, volume name, and its location.

    docker container inspect postgresdb3
  • Verify that mypgdata volume didn't get created.

    docker volume ls
  • Use ls command to explore data inside the $HOME/mypgdata directory.

    ls $HOME/mypgdata

- Docker volume management

  • Stop and delete all Postgres containers

    docker container stop postgresdb1 postgresdb2 postgresdb3
    docker container rm postgresdb1 postgresdb2 postgresdb3
  • Get list of volumes

    docker volume ls
  • Remove pgdata volume

    docker volume rm pgdata
  • Remove all unused volumes. Enter 'y' to confirm deletion.

    docker volume prune
  • Verify all volumes have been deleted.

    docker volume ls

Container Network

Lab details

- Bridge network mode

The bridge network is a default network and containers will be running in this network automatically when you run any container and didn't specify the --network flag. However, adding --network flag is more clear and helps you to quickly know in which network the container will be running.

  • Run a container with bridge network mode.

    docker container run -d --network bridge --name nginx1 nginx
  • Inspect the container to get its IP address using the command below. Look for "Networks" section then IPAddress field.

    docker container inspect nginx1
  • Use curl command to verify that the container running in the bridge network is not bind to host's network and can be accessed from outside of bridge network using IP address.

    curl http://<nginx1 container IP address>
  • Run a new container in the same bridge network and execute wget command to verify that the containers within the same bridge network can access to each other.

    docker container run --network bridge busybox wget -S -O- http://<nginx1 container IP address>

- Forward traffic from host's network to containers in bridge network

  • Run a container with bridge network mode and add port forwarding by adding -p 8080:80 flag so port 8080 on the host is mapped to port 80 of the container.

    docker container run -d --network bridge -p 8080:80 --name nginx2 nginx
  • Use curl command to verify that the container running in the private bridge network with port forwarding now can be accessed from the host's network.

    curl http://localhost:8080
  • Inspect the container to get IP address using the command below. Then look for IPAddress in the "Networks" section.

    docker container inspect nginx2
  • Run a new container in the same bridge network and execute wget command to verify that the containers within the same bridge network can access to each other.

    docker container run --network bridge busybox wget -S -O- http://<nginx2 container IP address>

- User-defined bridge network

User can define new bridge networks to create new networks and isolate container(s) from other containers with different network namespace.

The user-defined bridge network also allows containers within the network to communicate to each other using both IP Address and container name while the default bridge network allows the communication using IP Address only.

  • Create a new bridge network.

    docker network create mybridge
  • Get list of networks to verify a new bridge network was created.

    docker network ls
  • Run a container within mybridge network and name the container as mynginx.

    docker container run -d --network mybridge --name mynginx nginx
  • Inspect the container to get its IP address using the command below. Then look for IPAddress in the "Networks" section.

    docker container inspect mynginx
  • Run a busybox container within mybridge network with interactive mode.

    docker container run -it --network mybridge busybox sh
  • Ping to mynginx container using IP Address.

    ping -c 4 <mynginx container IP Address>
  • Ping to mynginx container using container name

    ping -c 4 mynginx
  • Try to get a home page from mynginx container.

    wget -S -O- http://mynginx

- Host network mode

  • Run a container with host network mode by adding --network host flag without port forwarding. Docker will bind all ports exposed by the container to the ports on host.

    docker container run -d --network host --name nginx3 nginx
  • Use curl command to verify that the container running with host network can be accessed without port forwarding.

    curl http://localhost:80
  • Inspect the container using the command below then the "Networks" section. You will see that the Docker doesn't assign an IP address to the container because the container runs in the same host's network namespace so it uses host's IP address and ports.

    docker container inspect nginx3
  • Get the host's IP address.

    hostname -i
  • Run a new container in bridge network and execute wget command to verify that the container running in bridge network can also access to the container running in the host network (inter-networking).

    docker container run --network bridge busybox wget -S -O- http://<host IP Address>
  • Type exit and press Enter on keyboard to exit from the container.


Container Image

Lab details

- Building container image

  • Clone a project from GitHub.

    git clone https://github.com/audomsak/node-express-website
  • Enter to the node-express-website directory.

    cd node-express-website
  • View Dockerfile details.

    cat Dockerfile
  • Build a container image without specifying repository and tag.

    docker image build .

    Note. The . in the command above means current directory.

  • Get list of images to verify that a new container image is built. However, building a container image without specifying repository and tag makes the container hard to remember because Docker generated only image ID for the container image.

    docker image ls
  • Build a new container image and specify repository name by adding -t flag followed by repository name.

    docker image build -t <your Docker Hub account>/node-website .
  • Get list of images to verify that a new container image is built. Building a container image and specified only repository without tag would let Docker to add latest tag to the container image automatically.

    docker image ls
  • Build a new container image and specify repository and tag by adding : after the repository name and followed by a tag name.

    docker image build -t <your Docker Hub account>/node-website:1.0 .
  • Get list of images to verify that a new container image is built with the specified repository and tag.

    docker image ls
  • Run a container with the image you have just built.

    docker container run -d -p 1234:8080 --name mywebsite <your Docker Hub account>/node-website:1.0
  • Use curl command to verify that you can access to the website running in the container.

    curl http://localhost:1234

- Tagging and versioning

  • Add a new tag for the existing container image to have multiple tags or versions.

    docker image tag <your Docker Hub account>/node-website:1.0 <your Docker Hub account>/node-website:release
  • Get list of container images to verify the new tag gets created.

    docker image ls

- Pushing container image to Docker Hub

  • Login to Docker Hub with your username and password.

    docker login
  • Push the container image to Docker Hub

    docker image push <your Docker Hub account>/node-website:1.0
    docker image push <your Docker Hub account>/node-website:latest
  • Go to Docker Hub website to verify the container image and tags.


- Pushing container image to Quay

  • Login to Quay with your username and password.

    docker login
    docker image tag <your Docker Hub account>/node-website:1.0 <your Quay account>/node-website:release
  • Push the container image to Quay

    docker image push <your Quay account>/node-website:release
  • Go to Quay website to verify the container image and tags.


Administration

Lab details

- Clean up containers, images and volumes

  • Clean up containers

    docker container prune
  • Clean up images

    docker image prune
  • Clean up volumes

    docker volume prune
  • Clean up containers, networks, images, and build cache

    docker system prune

- Check disk usage

  • Check how many disk space used by Docker

    docker system df