Let's Play With Docker
Since Docker is “something” that let’s you use “something else”,
let’s make that something do something with something else.
Essentially, Docker is an engine that allows you to run container-images, in containers.
Getting inside…
Let’s try this:
sudo docker run --rm -it --name ubuntu_test ubuntu bash
Flags Explained:
--rm
: Removes the container once stopped.-it
: Enables interactive mode.--name ubuntu_test
: This will give a name to my container (otherwise a random name will be given)ubuntu
: The name of the image to pull and create a container from.bash
: The command to run as the container starts up.
You’ll now find yourself inside a Ubuntu OS container, in its / directory to be precise.
This system is completely isolated from the host computer and once we exit it, it will be deleted.
Next, let’s run a quick whoami
command and exit the container by running the exit
command.
root@f735cd301d07:/# whoami
root
root@f735cd301d07:/# exit
What just happenned??
When we ran the docker
command, the following steps happened under the hood:
- Docker daemon searched for the Ubuntu image locally and didn’t find it.
- It then (the daemon) contacted the official Docker Hub and pulled (downloaded) the image.
- Once the image was downloaded it created a container based on that image
- Lastly it ran the
bash
command in-it
mode which means ‘Interactive’. At this time, the processbash
was running inside the container and you could give it input and recieve its output - you were doing things “inside the container”. Once you exited the container, the container stopped because since there’s no process running, there’s no need for it to run. And once it stopped it also got deleted becase of the--rm
flag, and you’ve found yourself back on your host machine.
Though this is not typically how you’d use a container though, this method has it use cases.
Volumes and Mounts/Binds
So so if the container is deleted when stopped or updated, what happens if we need persistent data? There are two common methods to do this:
- Persistent Volume: This is a Docker object that you can then run the
inspect
command on, and will store any persistent data. You attach it to a container when you start/run it and when the container updates, you reattach it to the new container. - Folder Binds/Mounts (They’re the same thing): In this method, you simply map a current folder on the host computer to a location inside the container. Whatever files are available there, will also be available from inside the container. This folder can also be writted to/deleted from.
Folder Mounts/Binds (Hands-On)
Let’s create a folder named my_share
in the current folder and then, create a file inside that folder my_file.txt
:
mkdir -p ./my_share
touch my_share/my_file.txt
Then run this command to create a Ubuntu container mounting the new folder inside:
sudo docker run --rm -it -v ./my_share:/var/my_share --name ubuntu_test ubuntu
Next, lets list the content of /var/my_share/
by running:
ls -l /var/my_share
You can see my_file.txt
, the file we created in the host computer now is presesnt inside the container.
Now let’s create a file from withing the container in the same folder and exit the container:
touch /var/my_share/my_new_file.txt
exit
Now, if we list the content of ./my_share/
from inside the host, we should see the two files. The first, we created while inside the host and was available from inside the container, and the second, we created inside the container and was visible from the host.
I hope this is starting to make sense.
Flags Explained:
--rm
: Removes the container once stopped.-it-
: Enables interactive mode.-v ubuntu_data:/var/ubuntu_data
: The -v is for ‘volume’ whatever’s to the LEFT of the:
is the path of the folder on the HOST computer, and to the RIGHT of the:
is the path inside the container where the ‘host folder’ is to be mounted. We’ve mapped./my_share/
on the host’s side to/var/my_share
inside the container.--name ubuntu_test
: This will give a name to my container (otherwise a random name will be given)ubuntu
: The name of the image to pull and create a container from.
Persistent Volume (Hands-On)
Now let’s create a new Ubuntu container with a persistent volume.
sudo docker run --rm -it -v ubuntu_data:/var/my_share --name ubuntu_test ubuntu
Notice how on the left of the :
is not a path, it’s a name of a persistent volume that will be created.
After running the above command, we’ll be inside the new container and can create a new file and exit the container:
touch /var/my_share/my_new_file.txt
exit
Now lets run the inspect command:
sudo docker volume inspect ubuntu_data
The output should look something like this:
[
{
"CreatedAt": "2024-06-15T16:52:51Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/ubuntu_data/_data",
"Name": "ubuntu_data",
"Options": null,
"Scope": "local"
}
]
Now let’s list the folder mentioned in the "Mountpoint"
key, we’ll need to do this as sudo.
sudo ls /var/lib/docker/volumes/ubuntu_data/_data
There you should see the file we created while inside the container.
Summary:
There are two main methods to handle persistent storage with containers. Persistent Volumes and Folder Bindings. They both have their advantages and limitations. However each project will have its own implementation based on its requirements.
- Note: You can also use network shares but that’s outside the scope of this tutorial.
Docker Journey
So you know all about Docker images, containers and volumes. You’re ready to create your first REAL usable service! Follow this Link to learn about docker-compose, and how it can help you deploy an infrastructure containing multiple containers hosting multiple services.