Docker hands-on
Having theoretical knowledge about something without any practical knowledge of it is like having a sword but not having a skill to use it!! So let’s get started with the Docker practical.
For introduction to Docker, you can refer to my article.
About Docker
- docker - -version: It tells us the installed docker version.
- docker version: It gives us the detailed information about the versions of client and sever with some additional information. We can see here that OS of client is Windows, i.e. our system and OS of server is Linux i.e. VM in which the server is running.
- docker info: It gives us the details of client and server. Like number of containers running, paused, stopped, number of images present, etc.
Hello-World by Docker
Whenever we learn a new programming language, we start by creating a hello-world program. So, we will follow that convention, and use a hello-world official image by Docker.
- docker run hello-world: hello-world is an official image by Docker on Docker hub that prints “Hello from Docker!” when its container runs.
Run the above command and see what happens. We are not interested in seeing the “Hello from Docker!”. We are more interested in what actually happening in the background. As soon as we entered this command, Docker client sent the command to Docker daemon and says “Hey! users wants to run the container of hello-world image”. Docker daemon checks in the local registry to see whether there is any such image or not. There is no such image and hence, “Unable to find image ‘hello-world:latest’ locally” where latest is the default tag. Then daemon pulls that image from the docker hub and stores in the local registry. Then it creates a container of it, and runs it. The output is then sent to client which we are seeing on the terminal.
Docker commands
Let’s get started with the docker commands that we actually use.
- docker images: prints the list of all the images present in your system.
- docker ps: prints the list of all running containers. Here, no container is printed because currently no container is running.
- docker ps- -all: prints the list of all containers. I know the names of the containers are weird and we haven’t specified them also. They are randomly generated by the Docker itself, if not specified.
- docker rmi hello-world: deletes the image with name “hello-world”.
- docker rm ae2bd8acf828: deletes the container with container id ae2bd8acf828
I know, you must be thinking that how we gonna remember so many commands. We have learned only 4 commands till now, and there is no pattern at all. Same thing happened with Docker community as well. As the Docker grew up, the number of commands grew too and they became unmanageable. So, Docker community decided to standardized them more. Hence, Docker divided the commands into modules. Commands related to Image comes under Image module, Commands related to Container comes under Container module, Commands related to Network comes under Network module and so on. Then other commands are inside child modules and we can combine both to get our complete commands.
- docker- -help: Run this command to know more about the docker commands. The management commands are the modules, image, container, network, etc.
Now, see the above discussed commands in later versions of Docker.
- docker image ls: prints the list of all the images present in your system.
- docker container ls: prints the list of all running containers.
- docker container ls- -all/ docker container ls -a: prints the list of all containers. (if write complete flag then use- -<flag> else -<f>
- docker image rm <imageId/imageName>: deletes the specified image.
- docker container rm <containerId/containerName>: deletes the specified container.
- docker container run- -name=webapp <imageId/name>: creates and runs a container with name webapp
A quick trick, when referring to an image or container, instead of specifying complete Id we can specify the initial unique characters of the Id i.e. docker image rm da4821067 we can write docker image rm d if no other image has it Id starting with d.
Container commands
A container is a running instance of an image.
- docker container run <imageId/imageName>: create and runs a container of the image specified.
- docker contaier create <imageId/imageName>: creates a container but doesn’t run it.
- docker container start <containerId/containerName>: runs the specified container which was already created earlier.
- docker container stop <containerId/containerName>: stops the specified running container.
- docker container kill <containerId/containerName>: immediately stops the container, doesn’t allow the processes running inside the container to complete.
Kill vs Stop: use stop in normal case as stop lets container’s internal processes to complete but kill doesn’t wait for anything and kills/stops the container immediately.
- docker container run -d <imageId/imageName>: create and runs a new container of the specified image and detach it so that it runs in the background. -d /- -detach flag is mainly used when we want to run a container of server which we wants to keep running in background for handling the requests.
- docker container attach <containerId/containerName>: It is opposite of detach command and attaches the container running in background back to the shell.
- docker container rename <containerId/containerName> <new-name>: It is used to rename an already existing container.
Go inside the container
- docker container exec -it <containerId/containerName> bash: The exec command is used to run/execute a command inside a running container. Flag -it is a combination of two flags: -i/- -interactive and -t/- -tty which gives us an interactive tty (a text input output environment or shell). It gives us an interactive shell that makes us feel that we are executing our commands on a shell inside the container. But actually, it pipes the input from our shell to inside the container and pipes output from the container to our current shell.
Playing with Mysql image:
- docker pull mysql: If mysql image is present in the local registry then it checks for any updates from the docker hub, otherwise pulls it from there and puts it in the local registry.
- docker container run -d -e MYSQL_ROOT_PASSWORD=rootpass mysql: Here, we are creating and running a container of mysql image. -d flag tells to run this container in detached mode i.e. in background. -e flag is used to specify the mysql password which we need to enter in order to use mysql in future.
- docker container exec -it 9 bash: We are getting the bash shell from the mysql running container whose container id starts with 9.
Now, we will execute our mysql commands inside the bash shell that we have got in the previous command.
- docker container inspect <containerId/containerName>: It gives us every single detail about the specified container: id, creation date & time, state, image, ip, port and much more.
- docker container stats: It gives us the live CPU usage and memory usage by the running containers.
- docker container run- -name new-hello-world hello-world:- -name flag is used to give a custom name to the container.
- docker container logs <containerId/name>: displays the logs of the web service running in the specified container in detached mode.
Docker Volume binding
As we were playing with mysql container above, if we run another container at this moment we will observe that any changes in the first mysql container are not reflected in the other container. It is because the containers runs in complete isolation and are not connected with each other in any way. In this case if we delete our first container we will loose all our data inside it. For this we need to store it outside the container also and is known as binding the volume.
- docker container run -d -e MYSQL_ROOT_PASSWORD=rootpass -v /data/volume:/var/lib/mysql mysql: -v is used for volume binding. Now if we run any other container with same volume binding then any change in one container will be reflected in other too as they are pointing to same volume.
Port mapping
Suppose we have created a container of our application which exposes some port i.e. it is listening on that port. But we can’t directly access it from any other computer. So we map our system’s port to the container’s exposed port and other computers send request to out system’s port which is redirected to container’s port. (just like call forwarding)
- docker container run –d –p 3600:80 nginx: 3600 our port, 80 container’s port and nginx is the image name.
Delete all containers/images in one command
- docker container prune: Deletes all stopped containers.
- docker image prune: Deletes all images.
Note: Use prune command cautiously in the production.
Docker build, tag and push to Docker registry
- docker build -t <imageName[:TAG]> .
- docker login <registry-name>: then enter credentials. registry name is optional if it is docker hub.
- docker image SOURCE_IMAGE[: tag]<docker_user_name>/TARGET_IMAGE[: tag]: Before pushing image to docker, create a tag which starts with the registry name (if it is being pushed to Docker hub, then it is optional) followed by a slash (/) and username. followed by target image name. e.g. docker image hello-world:1.0 ninja/my-hello-world:2.0
- docker image push IMAGE_NAME[: tag]:pushes the image to the logged in docker account. e.g. docker image push ninja/my-hello-world:2.0.
Share your image with others
- docker container export CONTAINER_ID > FILENAME.tar: It generates a tar file of the container in the current directory that we can share with others.
- docker container import FILENAME.tar TARGET_IMAGE_NAME: Creates an image with specified TARGET_IMAGE_NAME from specified .tar file.
- docker image save IMAGE_NAME> FILENAME.tar: It generates a tar file of the container in the current directory that we can share with others.
- docker image load < hello-my-world.tar: It loads the image from the .tar file along with tag.