Docker 101
Last updated
Last updated
A container refers to the method of keeping an application or service along with its libraries and dependencies isolated from the external environment and other applications. It is a form of virtualization technology.
Virtual machines generally require more system resources and have longer startup times.
Compared to containers, virtual machines can be a heavier option in scenarios that require lightweight and fast deployment.
Virtual machines may be preferred in environments where more isolation is needed.
As shown in the image below, virtual machines are all built on top of an operating system. Therefore, their isolation is greater compared to containers, but this reduces fast deployment and portability.
However, containers do not have an additional operating system, so they take up less space than virtual machines.
Let's say we will use PostgreSQL for the backend and database. Doing this in containers is fast and takes up minimal space, while doing it in virtual machines requires installing two separate operating systems and adding the necessary programs, which leads to unnecessary use of space and time.
Docker is a platform that provides a set of tools and services to create, manage, and run containers.
Isolation
Portability
Fast Deployment
Resource Efficiency
Docker achieves fast deployment and portability through images. With images, we can download and use the desired application with a single command. We will go into more detail on this later.
Let's say we have a Backend and a Web Server. Both programs use version x.x.x of package A. Now, if an update comes to our Backend and it requires version x.x.y of package A, what do we do? Our Backend requires version x.x.y of package A, but our Web Server still requires version x.x.x. In other words, we have a version conflict. In such cases, Docker can be used. We will place the Backend into a container and install version x.x.y of package A inside it. Similarly, we will place the Web Server into a container and install version x.x.x of package A. This way, the two conflicting programs can now work together by using their own libraries and dependencies inside containers.
Instead of explaining the Docker Desktop application here, I thought it would be more suitable to explain the most commonly used commands through the command line.
Global
Network
docker network create name
: Creates your own network.
docker network ls
: Lists all created networks.
docker network rm network_id
: Removes the specified network.
Image
docker images
/ docker image ls
: Lists all the images installed on your computer.
docker image rm image_id
: Removes the specified image.
docker image inspect <image>
: Provides detailed information about the image.
docker image build dockerFilePath
/ docker build dockerFilePath
: Allows you to create a custom image using a Dockerfile.
docker run [OPTIONS] image [COMMANDS]
: Creates a container using an image. The container stops after the [COMMANDS] are completed.
OPTIONS:
--name
: Assigns a specific name to the container.
--rm
: Automatically removes the container after it finishes running.
-it
: Starts the container in interactive mode and attaches the terminal to it.
-p
: Maps a specific port of the container to the host machine.
-d
: Runs the container in the background.
-e
: Defines environment variables for the container.
-v
: Binds a directory or file from the host machine to the container.
--network <name>
: Specifies the network the container is connected to.
--security-opt PROFILES
: Specifies security profiles for the container.
--privileged
: Runs the container in privileged mode with all the host's kernel capabilities.
–-cap-add capability
: Adds capabilities to the container.
–-cap-drop capability
: Drops capabilities from the container.
ALL
: If written instead of a specific capability, it adds or removes all capabilities.
COMMANDS
Essentially, the commands here could be anything you can type into the terminal.
ls -l
sleep 3600
Containers
docker ps
: Lists the running containers.
-a
: Lists all containers, both running and stopped.
docker start container_id/name
: Starts a specific container.
docker stop container_id/name
: Stops a specific container.
docker restart container_id/name
: Restarts a specific container.
docker rm container_id/name
: Removes a specific container.
docker exec [OPTIONS] <container_id> [COMMAND]
: Allows us to run commands inside a running container. The usage is similar to docker run ...
.
docker exec my_container ls -l
: Runs the ls -l
command inside my_container
.
Now, I would like you to create a simple application. Open Docker, pull the hello-world image from Docker Hub. Check if it has been downloaded. Using this image, create a simple container. What is its function? List all containers, both running and stopped, and then try to remove the container you created. I recommend experimenting with all the OPTIONS you learned earlier while creating the container and spending some time with it.
A Dockerfile is a file used to create custom images.
FROM image:tag
: Specifies which image the container will be based on.
RUN command
: Used to run commands on the image.
COPY hostPath containerPath
: Allows copying files from the host machine to the container.
WORKDIR
: Specifies the working directory.
EXPOSE
: Specifies which ports the container will expose to the outside world.
CMD
: Specifies the command that will run automatically when the container is started.
In the example below, I specified that I will base the container on the Ubuntu 18.04 version. Then, I performed the necessary installation steps on this image using the RUN
command. After setting my working directory to /app
, I copied ./script.sh
from my host machine into the container. Finally, I wrote the command that I want to be executed when the container runs.
To create an image from the above Dockerfile, you would use the following command:
Where:
image_tag
is the name and tag you want to give your image (e.g., myimage:latest
).
dockerfilePath
is the path to the directory containing the Dockerfile
(e.g., .
for the current directory).
When we use docker run
, we run a single container. But what if we want to run multiple containers and also connect them to each other?
Let’s consider a modern website with the following components: Backend: Golang, Web Server: Nginx, Frontend: React.js, and Database: PostgreSQL. To get this website running with Docker, we would need to write 9 lines of commands.
First, we would use the docker build
command to create images for each of them using their respective Dockerfiles. Then, to allow these containers to communicate with each other, we would create a network using docker network create name
. Finally, for each of the images, we would need to write a docker run
command, adding the --network
tag or specific options for each container to ensure they run properly.
Clearly, this process can be complex and time-consuming. To make it easier, we use Docker Compose.
Docker Compose is a tool provided by Docker for defining, managing, and running multi-container applications.
Let's consider a modern website. Suppose we use React for the frontend, Go for the backend, Nginx as the web server, and PostgreSQL for the database.
In this scenario, there are at least 4 containers. We need to build and run these containers, and also create a network for some containers to connect to each other.
Now, let's see how many commands we would need to bring a minimal modern site online. First, we need to create the containers, so we would use the docker build ...
command 4 times. Then, to create a network between the containers, we would use the docker network create ...
command. Finally, to run the containers, we would use the docker run ...
command. However, remembering and writing all these commands for each container can be cumbersome.
As mentioned above, we wrote a total of 9 lines of commands just to run a minimal modern site. This is exactly why we use Docker Compose.
Docker Compose allows you to define and manage multiple Docker containers as a single application using a YAML file.
You can think of this file as a set of docker run ...
commands written for each Dockerfile. For each Dockerfile, you provide the necessary docker run
information, and with just one command, you can build and run all the Dockerfiles.
For simplicity, I'll demonstrate it with just a backend and a database. This will be a short example, and you can refer to the documentation for more information.
First, create a docker-compose.yml
file:
version: '3.9'
: Specifies the version of Docker Compose being used.
services
: Lists the containers (or services) that will run in the application.
backend
: Defines the backend service.
build: ./backend
: Builds the backend container from the ./backend
directory.
container_name: backend
: Names the container "backend".
restart: always
: Ensures the container always restarts unless explicitly stopped.
ports: "8081:8081"
: Maps port 8081 of the container to port 8081 on the host machine.
depends_on: postgres
: Ensures that the backend waits for the postgres
service to start first.
networks: impact
: Connects the container to the "impact" network.
postgres
: Defines the PostgreSQL service.
image: postgres:latest
: Uses the latest PostgreSQL image from Docker Hub.
environment
: Sets environment variables for PostgreSQL such as the user, password, and database.
ports: "5432:5432"
: Maps port 5432 of the container to port 5432 on the host machine.
volumes
: Mounts directories from the host machine to the container for database initialization and data persistence.
networks: impact
: Connects the container to the "impact" network.
networks
: Defines the network settings. Here, the network "impact" uses the bridge driver for container communication.
Simply navigate to the directory containing the docker-compose.yml
file and run the following command:
This will build the containers, create the network, and start the services. If you want to run the containers in detached mode, use:
Now, both your backend and PostgreSQL services will be running and connected as defined in the Compose file!
docker search image:tag
: Searches for an image on .
docker pull image:tag
: Pulls an image from .