So I'm sure at this point you're wondering how to work on files on your local machine. This can be achieved with volumes. It's worth noting that at this point that files stored on containers are lost when the container stops running. I feel Volumes and Networks are the final piece for anyone starting out in Docker to be able to perform basic to intermediate operations. If you haven't seen the previous two articles I suggest you do so at this point.
Lets continue with the use of the alpine image from the last time. We'll start start a new instance of the alpine image (I mean create a new alpine container).
docker run -ti --name nerdhands -v /data -d alpine sh
Now, navigate into the /data folder and make some changes. Lets create a file for the sake of the tutorial, just to get the whole idea.
cd /data # navigate into the folder touch file.txt # create a file called file exit
After exiting the shell prompt, we have to restart the container
docker kill nerdhands # terminate the process docker start nerdhands # restart the nerdhands container docker exec -ti nerdhands sh # start the container with shell prompt
Once in the shell prompt type the following commands to confirm that our file is still in the container
cd /data # navgate to the data volume ls # list files
Let us now map a folder on the host machine to the data volume in the container instance on creation (a.k.a create a host data volume). Only folders in a users profile directory can be mapped and must be absolute. e.g C:/Users/chile/folder_path
docker run --name nerhdands -v C:/Users/chile/folder_path:/data -d alpine sh
You have now successfully created a container named nerdhands (--name nerdhands) that will start in the background as a daemon (-d) and most importantly map a folder in the container to one on your system (-v C:/Users/chile/folder_path:/data). Now launch the container using.
docker exec -ti nerdhands sh
Lets go ahead and play with the mapped directory using some Linux shell command magic.
ls /data # view the content of our directory cd /data # go into the directory mkdir Ichigo # create a new folder cd /Ichigo # enter the newly created Ichigo folder vi bankai.txt # Hit [insert] enter a few text words and then hit [esc], type :wq and hit [enter] exit # exit the shell
and then to kill the running daemon (our nerdhands container)
docker kill nerdhands
Using this method, you can also simply mount a single file as a volume to the container instead of an entire directory.
docker run --name nerhdands -v C:/Users/chile/folder_path/file.txt:/data/file.txt -d alpine sh
Now go over to the folder you mapped to the container to view the changes you've made. Cool huh. Lets go deeper into volumes and data then.
Let us now look at creating a a special kind of volume that can be used by any container by simply referencing the given name during creation of the container. Lets see what it takes to create such a cotainer.
docker create -v /data --name data-container alpine /bin/true
Now to use this data volume container
docker run -d -ti --volumes-from data-container --name container-user-1 alpine sh docker run -d -ti --volumes-from data-container --name container-user-2 alpine sh docker run -d -ti --volumes-from data-container --name container-user-3 alpine sh
All three containers now have access to data-container. Now even if there's a /data folder in the container, the data-container data volume container takes over, which means you will also see files from data-contaner. You can run
ls / to confirm the existence of our newly created volume. If you choose to, you can have multiple data volume containers attached to a container by simply using multiple
--volumes-from-container as in the example below.
docker run -d -ti --volumes-from data-container-1 --volumes-from data-container-2 --volumes-from data-container-3 --name container-user-1 alpine sh
But you need to have created those data containers before hand. In cases where you want to add multiple data volume containers to multiple app containers, you can simply reference a container which already has the data containers attached to it.
docker run -d -ti --volumes-from container-user-1 --name container-user-2 alpine sh docker run -d -ti --volumes-from container-user-1 --name container-user-3 alpine sh
This way the data volume containers are automatically attached to our other two containers upon creation.
You can view the data volume containers you've created by using the below command.
docke volume ls
Other actions you can perform include, inspecting the volume to get some more info about about a specific data container and also delete it.
docker volume inspect [name] docker volume rm [name]
You can't remove a volume that is in use by other containers. You'd first of all have to delete the containers before you can delete the volume.
Very important in going into to Docker is understanding networks and networking in Docker. How do I make use of the host network, how do I link up the containers, how do I create my own network etc. lets touch on all these concerns. There's a likelihood that if you're web developer who's trying out Docker you'd do some network configuration at some point.
By default Docker automatically creates three networks for you when installed (see image below) but this is not to say that you're limited to what you can do. The
docker network ls command is used to list the available networks.
Creating your own network is as simple as running the below command. You supply the create command, the network name and the driver. You can use any of the three default drivers and custom drivers as well. You can run the
ls command to view your network amongst the list of existing networks.
docker network create -d bridge new-network-1
Lets make use of our alpine images some more to understand the concept of networks. First we'll create two containers, one named nerdhands-network-1 which will use our default network config and the other nerdhands-network-2 :) which we will tell to use our newly created network.
docker run -ti --name nerdhands-network-1 -d alpine sh docker run -ti --net=new-network-1 --name nerdhands-network-2 -d alpine sh
Now lets go into the first container and copy ipaddress using
ifconfig linux command.
docker exec -ti nerdhands-network-1 sh ifconfig exit
Now after exiting, we go into the second container to try ping the container.
docker exec -ti nerdhands-network-2 sh ping [ipaddress] -w 5
You will notice that there's a 100% loss in packets. Now lets create a third network nerdhands-network-3 and add it to our custom bridge. We will create it without the -d so that it takes us straight to the shell prompt.
docker run -ti --net=new-network-1 --name nerdhands-network-3 alpine sh ifconfig
Straight up, ifconfig gives you a clue that you're on the same network with the nerdhands-network-2 container.
Now lets try pinging the nerdhands-network-2 container. Hope you copied the ip, else it would be a good time to master a skill else you can try pinging the container using the name.
Nothing stops you from creating a container that resides directly on the host system itself. There are scenarios where this is exactly what you want.
docker run -tid --net=host --name nerdhands-network-4 alpine sh
Since you can access containers over the network using their names, you can as well replace that db string with ip address to the container name.
We can also map port numbers in the containers to the host system. This can be done either automatically or explicitly specifying it
For automatically assigning ports
docker run -tid -P --name nerdhands-network-5 alpine sh
For explicity specifying ports
docker run -tid -p 8118:8000 --name nerdhands-network-5 alpine sh
Well, yeah our alpine image does not have a running web app but nothing stops you from installing and configuring a web server on it or even a db if you choose. So please try that on your own.
We have now come to end of the Docker: Starting Out series. From here on its all advanced stuff. For the first two parts of the series use the links below.
But who is to say that this is the very end :D