Docker Containers
Published:
Understanding containers
What is a container?
A container is an instance of Docker Images running as a process. We can have many containers running off the same image.
Working with Containers
Creating and running containers.
3 mayor ways to run containers
- Locally (Docker Desktop, RD)
docker run -d -p 8080:80 nginx
- Servers (Docker Engine, K8s)
docker run -d -p 8080:80 --name my_nginx nginx
- PaaS (Cloud Run, Fargate).
Detached vs. foreground modes.
- Detached Mode (-d): The container runs in the background, allowing the terminal to be used for other commands.
docker run -d nginx
- Foreground Mode: The container process runs attached to the terminal session, showing its logs and output.
docker run nginx
Executing Commands Inside Containers
To interact with a running container and execute commands:
docker exec -it <container_name> <command>
For example:
docker exec -it my_nginx bash
This command opens a shell inside the my_nginx
container.
docker exec -it my_db mysql
Container Lifecycle
Starting, Stopping, and Restarting Containers
- Start a container:
docker start <container_name>
- Stop a container:
docker stop <container_name>
- Restart a container:
docker restart <container_name>
Pausing and Unpausing Containers
- Pause a container:
docker pause <container_name>
This command suspends all processes within the container.
- Unpause a container:
docker unpause <container_name>
Removing Containers
To remove a container after it has been stopped:
docker rm <container_name>
To remove all stopped containers:
docker container prune
Container Isolation and Security
Namespaces
Namespaces provide process and resource isolation for containers, ensuring that containers operate in their own environments. Types of namespaces include:
- PID Namespace: Isolates process IDs.
- Network Namespace: Isolates network interfaces.
- Mount Namespace: Isolates the filesystem.
Control Groups (cgroups)
Cgroups limit and allocate resources like CPU, memory, and disk I/O to ensure that a single container cannot overwhelm the host system. You can define limits using flags like:
docker run -m 512m --cpus="1.0" nginx
This command limits the container to 512MB of memory and 1 CPU core.
Capabilities and Security Best Practices
- Capabilities: Docker provides a set of capabilities that can be restricted to limit the privileges of a container. By default, Docker drops many capabilities to reduce the attack surface. You can drop additional capabilities using:
docker run --cap-drop NET_RAW nginx
- Security Best Practices:
- Run containers as non-root users.
- Use read-only file systems for containers.
- Avoid using
--privileged
mode unless necessary. - Use secure images from trusted sources.
Container Lifetime & Persistent Data
Containers are usually meant to be immutable and ephemeral. This is not a limitation of a container, but more of a design goal, or a best practice. This idea of immutable infrastructure where we don’t change things once they’re running. If a config change needs to happen, or maybe the container version upgrade needs to happen, then we redeploy a whole new container. But there’s a trade-off.
What about the unique data that your app will produce? Those databases, or a key value stores? Ideally, the containers shouldn’t contain your unique data mixed in with the application binaries. This is known as “separation of concerns“.
Docker gives a big benefit here. We can update our application by recreating a new container, with an updated version of our app, and ideally, our unique data is still where it needs to be and was preserved for us while our container was recycled.
Doing commands like docker container start
or docker container stop
won’t affect the container’s file. It’s only when we remove the container that it’s UFS layer goes away. And we want to be able to do that at will.
Docker has two solutions to this problem known as data volumes and bind mounts
Docker volumes are a configuration option for a container that creates a special location outside of that container’s UFS to store unique data.
This preserves it across container removals and allows us to attach it to whatever container we want. And the container just sees it like a local file path.
Bind mounts are simply us sharing or mounting a host directory, or file, into a container.
Docker Volumes
Volumes are used to persist data generated by and used by Docker containers. They help separate data from the container lifecycle, ensuring that data persists even when containers are removed.
DEFINING VOLUMES IN A DOCKERFILE We can define a volume in a Dockerfile using the VOLUME
instruction. For instance, in the official mysql
Dockerfile we can see.
VOLUME /var/lib/mysql
What this is, is this is actually the running container getting its own unique location on the host, to store that data, and then it’s in the background, mapped or mounted, to that location in the container, so that the location in the container actually just thinks it’s writing to `/var/lib/mysql.
You can actually visualize this folder on Linux (MacOS and Windows create a VM with Linux to deal with this so it will not work)
NAME PROBLEM The problem comes when we have several volumes because the Volume Name is just a bunch of letters and names we cannot associate to a certain container.
For example, after running docker container --name mysql run -d mysql
and docker container --name mysql2 run -d mysql
. If we do docker volume ls
we will get something like:
DRIVER VOLUME NAME
local 25b5as5d2sf5as5d2sg4as5d2asdfa6s8a5s4df58a8s7a0
local 145ds5asdfas5254as78825258f7s4843834525DS2F22H1S
Which means that we don’t know which one is mysql1 and which one is mysql2. Instead of using anonymous volumes, you can specify a named volume when running a container. Named volumes are easier to manage and identify
docker run -d --name mysql -v mysql_data:/var/lib/mysql -e MYSQL_ALLOW_EMPTY_PASSWORD=yes mysql
now if we run again docker volume ls
we will get:
DRIVER VOLUME NAME
local 25b5as5d2sf5as5d2sg4as5d2asdfa6s8a5s4df58a8s7a0
local 145ds5asdfas5254as78825258f7s4843834525DS2F22H1S
local mysql_data
Bind Mounting. Sharing files between Host and Container
Really, a bind mount is just a mapping of the host files, or directories, into a container file or directory. You can do just that, specify a directory or just a single file.
In the background, it’s just having the two locations point to the same physical location on disk.
Again this skips the UFS like the other volumes do so that it’s not going to wipe out your host location when you delete the container. We cannot* use it in Dockerfile, must be at container run
run -v /Users/alex/my_folder:/path/container
If I know make changes on any files on my_folder
it will appear on the /path/container
as well without having to do any additional setup.
Docker Container Commands
Running a Container
To understand what happens in the background when you run a container, see [[docker container run]].
Example 1: Usage
docker container run -d -p 3306:3306 --network my_app_net --name db -e MYSQL_RANDOM_ROOT_PASSWORD=yes mysql
-d
: Detached mode, runs in the background so you can continue using the terminal.-p HOST:CONTAINER
: Publishes container port (3306) on the host machine port (3306).--name <NAME>
: Assigns a custom name to the container (db
). If omitted, a random name is assigned.-e MYSQL_RANDOM_ROOT_PASSWORD=yes
: Passes an environment variable (MYSQL_RANDOM_ROOT_PASSWORD
).--network
will add the container to a specific networkmysql
: The image to use for the container.
Example 2: Running a Web Server
docker container run --publish 80:80 nginx
- Downloads the
nginx
image from Docker Hub (if not already available locally). - Starts a new container from the
nginx
image. - Opens port 80 on the host machine and routes traffic to port 80 inside the container.
- Adding
-d
runs the container in the background and returns control to the shell prompt.
Interactive Shell in Containers
- Start a Container with an Interactive Shell:
docker container run -it <IMAGE> bash
-i
: Interactive mode (keeps STDIN open).-t
: Allocates a pseudo-TTY.-it
: Combines interactive and TTY, creating a terminal session inside the container (similar to SSH).
- Execute a Command in an Existing Container:
docker container exec -it <CONTAINER_NAME> bash
- Runs an additional command (e.g.,
bash
) inside an already running container.DNS Naming
docker container run -d --net <NETWORK> --net-alias <ALIAS>
- Runs an additional command (e.g.,
- Creates an alias. Then if we do
nslookup <ALIAS>
we would be able to find all of the containers with alias<ALIAS>
.Listing Containers
- List Active Containers:
docker container ls
- List All Containers (Including Stopped):
docker container ls -a
Stopping and Removing Containers
- Stop a Running Container:
docker container stop <CONTAINER_NAME>
- Use tab completion for available container names.
- Remove a Stopped Container:
docker container rm <CONTAINER_NAME>
Containers must be stopped before removing. Use
-f
to force removal:docker container rm -f <CONTAINER_NAME>
Inspecting Containers
- View Running Processes Inside a Container:
docker container top <CONTAINER_NAME>
- Inspect Container Metadata:
docker container inspect <CONTAINER_NAME>
- Displays a JSON file with detailed information about the container (startup configuration, volumes, networking, etc.).
- Monitor Resource Usage:
docker container stats
- Provides a real-time view of container resource usage (CPU, memory, network I/O), similar to
htop
.
- Provides a real-time view of container resource usage (CPU, memory, network I/O), similar to
COPYING FILES TO AND FROM CONTAINERS
- Copy a file from the host to the container:
docker cp <file_path> <container_name>:<container_path>
- Copy a file from the container to the host:
docker cp <container_name>:<container_path> <host_path>
Comments