Beginner's Introduction to Docker: Configure Images, Containers, and Docker Compose
Table of contents
- Introduction:
- Containers VS Virtual Machines:
- The anatomy of a container:
- Docker difference:
- Docker Installation:
- Using Docker:
- Explore Docker CLI:
- Create a Docker container(The long way):
- Create a docker container (The short way):
- Create a docker container from Dockerfiles:
- Docker most helpful commands:
- Introduction to Docker Hub:
- Challenge #1 (Start NGINX server using docker):
- To fix docker issues:
- Challenge#2 (Fix a broken container):
- Additional Docker Resources:
- References:
Disclaimer: This is not a tutorial; these are simply my personal notes from the course. Please refer to official documentation or tutorials for in-depth learning.
Introduction:
Why sometimes some apps does not work on different machines:
Missing Tools
Different configs
Hardware dependencies
Docker uses images and containers to allow apps to run anywhere consistently.
Images - Packaged apps with required configs
Containers VS Virtual Machines:
Virtual machines - >
Consume disk space
Hypervisor to emulate real hardware
Require you to install/configure operating system
Can run multiple apps at the same time
cannot interact with their hosts
Containers run on container run time → work with OS to allocate hardware and copy files and directories
Do not emulate hardware and do not need to boot up
Do not require OS installation
Take much less space
Can run only one app at time
Can interact with their hosts
The anatomy of a container:
Namespace - Provide different “views” of your system
Control Groups - Limit how much of any resource you can use
Namespaces:
Linux kernel provides 8 namespaces out of which docker supports 7 of them:
Control Groups Uses:
Docker Limitations:
Docker difference:
Containers are old!
(1979 - 1982)
chroot() is added to 4.2BSD, allowing administrators to change what applications can "see," even when running as root.
(1999 - 2004)
BSD jails and Solaris zones allow administrators to create entire virtual environments for applications.
(2007)
Linux Containers (LXC) brings BSD jail-like functionality to Linux.
Docker Advantages:
- Dockerfiles make configuring and packaging apps and their environments really easy.
The Docker Hub makes sharing images with anyone in the world easy.
The Docker CLI makes it really easy to start your apps in containers.
Docker Installation:
Docker only runs natively on Windows 10 Anniversary Edition or higher. On the Mac, Docker creates and starts containers in a small, Linux-based VM.
You can install docker desktop or through homebrew (for macOS) :
https://www.docker.com/products/docker-desktop/
Install docker on macOS:
Install Homebrew:
/bin/bash -c "$(curl -fsSL [https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh](https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh))"
Install docker using homebrew:
brew install docker —cask
Just to check if docker is ready to run or not:
docker ps
- Check running container
Retrieve image and install hello-world container and later it would delete it:
docker run --rm hello-world
To install docker in linux OS:
sudo apt install curl
curl -o /tmp/get-docker.sh https://get-docker.com
sh /tmp/get-docker.sh
sudo docker run hello-world
Add user to docker group to avoid using sudo everytime while running docker:
sudo usermod -aG docker $USER
To launch the shell with new permission:
sudo -u $USER sh
Check groups
groups
docker run hello-world
Using Docker:
Let’s explore Docker CLI and try out useful docker commands.
Explore Docker CLI:
Open terminal and run below command to check the docker commands,
docker —help
Here, network is a top-level command
docker network —help
docker network create —help
Create a Docker container(The long way):
Container is made of container image which is a compressed and pre-packaged files for app which have configuration and installation instruction.
By default it would try to pull image from docker hub, if it’s not present locally.
docker container create —help
To get linux specific version of docker image using :linux
image tag,
docker container create hello-world:linux
docker container create hello-world
To check actively running containers,
docker ps
To list out all containers( including the one that we created recently),
docker ps —all
OR docker ps -a
To start docker container:
docker container start a638c6a18b742b056cd223634e8cfbd14c89ea14e178c6f6eb5cc0f06e11b418
What happened it just returned the container id, where is the output.
For it we can either use --attach
keyword with command or check logs.
Let’s check if it ran or not, exited with code 0 means it ran successfully,
To check logs for container with id - a63
docker logs a63
It ran successfully as we are able to see the message “Hello from Docker!”.
To start and attach terminal of the container to our container and check it’s output,
we can use —attach
docker container start --attach a63
Note: Did you noticed that we did not have to create container everytime using docker image. Docker container does not get deleted by default.
Create a docker container (The short way):
We can just use the docker run command to cut the chase,
docker run hello-world
Create a docker container from Dockerfiles:
We can use the Dockerfile to create container image and run container using that container image.
Example:
Dockerfile
FROM ubuntu
LABEL maintainer="Carlos Nunez <dev@carlosnunez.me>"
USER root
COPY ./entrypoint.bash /
RUN apt -y update
RUN apt -y install curl bash
RUN chmod 755 /entrypoint.bash
USER nobody
ENTRYPOINT [ "/entrypoint.bash" ]
Docker most helpful commands:
To check helpful docker build commands,
docker build --help
File keyword to define the docker file:
docker build —file server.Dockerfile —tag our-server
docker run our-server
To run docker in detached mode / background mode:
docker run -d --name our-server our-server
To execute the container terminal command:
docker exec CONTAINER_ID date
To start a interactive bash shell terminal session within a container,
docker exec —interactive —tty CONTAINER_ID bash
OR
docker exec -it CONTAINER_ID /bin/bash
To stop the docker container:
docker stop CONTAINER_ID
To force stop the container, but it may result in data loss,
docker stop -t CONTAINER_ID
To remove the docker container:
docker rm CONTAINER_ID
To check only the docker ids:
docker ps -aq
To remove all containers using it’s ids, xargs would feed output of previous command which would be container ids and it would feed it to docker rm command, so it would remove all containers by it’s ids,
docker ps -aq | xargs docker rm
To list out docker images:
docker images
To remove docker image:
docker rmi IMAGE_ID
To force delete the images:
docker rmi -f
Bind ports to container:
docker build -t our-web-server -f web-server.Dockerfile .
docker run -d --name our-web-server -p 5001:5000 our-web-server
For volume mount: Need to use this kind of tag -v /tmp/change_this_file:/tmp/file
docker run --rm --entrypoint sh -v /tmp/change_this_file:/tmp/file ubuntu -c "echo 'Hello there.' > /tmp/file && cat /tmp/file”
Introduction to Docker Hub:
Docker Hub is the Docker client’s default container image registry.
Create docker hub account, and login with docker using Terminal,
docker login
Give a tag
or new name to docker image with your docker hub username with tag version:
docker tag our-web-server $DOCKER_HUB_USERNAME/our-web-server:0.0.1
Push docker image to docker hub repository:
docker push vrushank796/our-web-server:0.0.1
If we need to push the new version, we can change the tag version using tag
and push it again:
docker tag our-web-server vrushank796/our-web-server:0.0.1
docker push vrushank796/our-web-server:0.0.2
Challenge #1 (Start NGINX server using docker):
Start an instance of NGINX in Docker with the included website
Name the container "website"
Website should be accessible at http://localhost:8080
Ensure that the container is removed when done
Map $PWD/website to /usr/share/nginx/html if you volume mount
docker run -d --name website -v "$PWD/website:/usr/share/nginx/html" -p 8080:80 --rm nginx
To fix docker issues:
To remove the unused resources, ports or networks:
docker system prune
docker run --name=alpine --entrypoint=sleep -d alpine infinity
If the docker container is running slow we can check the stats such as CPU, memory and more, and also check the container processes using top command,
docker stats
Now we can run yes
program in sh terminal session and check the cpu usage from docker stats
,
docker exec -it alpine sh
#yes
(Ctrl + C and exit command - to exit from terminal session)
To debug a slow container and check it’s processes:
docker top $CONTAINER_ID
docker inspect alpine
OR docker inspect alpine | less
- Give docker container details in json format
Challenge#2 (Fix a broken container):
app.sh
#!/usr/bin/env bash
start() {
echo "Application starting"
}
process() {
_process() {
timeout "$((i*i))" yes &>/dev/null
echo "Application processing ($1/5)"
}
for i in $(seq 1 5)
do _process "$i"
done
}
finish() {
echo "Application finished!"
}
start &&
process &&
finish
Dockerfile
# HINT: Remember that you can find `ubuntu` images in the Docker Hub!
FROM ubuntu:xenial
COPY /app.sh /
RUN chmod +x /app.sh
ENTRYPOINT [ "/app.sh" ]
Build image and run docker container:
docker build -t our-app -f Dockerfile .
docker run -it --name our-app our-app
Our app would run slow to fix that we can check the CPU usage and processses,
docker stats
docker top 8e3
Here we can see that CPU usage is high and it have some timeout, let’s remove the timeout command from app.sh file, and now it would run smoothly.
Additional Docker Resources:
Docker Best Practices:
Only use officialy verified docker images,
Container Image Scanners → Clair, Trivy, Dagda
Avoid tagging as latest(latest can’t be overridden, making rollback difficult)
Use Non-root users(It makes your container more secure)
-
Instead of creating one giant docker image for all services like server and database, create a bunch of containers and link them together using docker compose!
Docker Compose:
Docker Compose makes starting and connecting multiple containers as easy as docker-compose up.
Challenges:
Difficult to link Docker networks together across hosts
Controlling Docker containers across multiple hosts is cumbersome
No built-in solutions for moving containers from host to host
Production concerns (load balancing and securing traffic) difficult with Docker client alone
Container Orchestrators:
Container orchestrators create, move, and scale containers across clusters of hosts.
Example:
Kubernetes (Most popular)
Docker Swarm
Marathon (maintained by Mesosphere)
HashiCorp Nomad
Cloud offerings (Amazon Elastic Container Service, Azure container services)
Kubernetes:
Kubernetes is a popular container orchestrator capable of managing very large numbers of containers.
- Kubernetes uses a distributed architecture to run and connect hundreds of thousands of containers with minimal hardware.
- Kubernetes also makes grouping, scaling, and connecting containers with the outside world really easy.
Load balancing and securing container traffic to/from the outside world are much easier with Kubernetes
Kubernetes ecosystem makes it possible to build your own developer experience.
References:
This article used data from Linkedin Course “Learning Docker” by Carlos Nunez
Docker Foundations Professional Certificate Learning Path | LinkedIn Learning, formerly Lynda.com
Subscribe to my newsletter
Read articles from Vrushank Amin directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Vrushank Amin
Vrushank Amin
I'm a Full Stack Developer with expertise in the MERN stack, specializing in creating scalable web applications. I've built and deployed healthcare and e-commerce platforms using React, Node.js, and AWS, ensuring user-friendly and secure solutions. My experience includes front-end development, API integration, and database management. I'm committed to continuous learning and delivering innovative, end-to-end solutions that meet client needs.