This Docker tutorial are just my notes which I am sharing with you all. I have prepared this tutorial and use it for my own reference as well, while at work. Let me know if there is something else you want me to add in the Docker Tutorial
How to use this Docker Tutorial
I use this tutorial as reference as well as to brush up my concepts for Docker. It helps me with my day to day work.
Why use docker
Makes it really easy and straight forward for you to install and run software on any given computer, be it desktop or any cloud based computing platform
E.g.
To install redis on your computer:
Step 1: wget http://download.redis.io.. Wget command not found
So, you troubleshoot and then you get into some other issue
Now, compare it with installing redis using docker..all you need to do is run the command
Docker run -it redis
That’s all you need to do..easy peasy
Thus, makes it really easy to install and run software without worrying about setup or dependencies
What is docker
Docker is a platform or ecosystem, around creating and running containers
Docker Ecosystem
Docker client
Docker server
Docker Machine
Docker Images
Docker Hub
Docker Compose
What is a container
Docker cli reached out to docker hub
Downloaded a single file called an image
Image is a single file with all the deps and config required to run a program
Single files which gets stored on your hard drive
We use this image to create a container. Container is an instance of an image. It runs a program
Container is a program with its own isolated set of hardware resources
Own set of Memory, Hard drive, network, etc
Docker for windows has two main tools
Docker client/cli – program that we use to issue commands. Doesn’t actually do anything.. Just CLI
Docker server/Daemon: responsible for creating images, running containers, etc.
We need dockerhub account to install docker
Docker version
Anatomy of docker run hello-world
Starts docker cli
Communicates it to docker server
Docker server checks the image cache locally
If not, it contacts docker hub
Docker server reached out to docker hub
Downloaded the hellow world file and stored it in image cache
Uses that image to create instance of it, loads it in memory
Run it second time and you should not see unable to find image locally
Operating System locally
Kernel sits between running application and the system hardware
For example, nodejs might say i want to write a file to hard drive to kernel
Running program interact through system call to kernel
Apps always interact with kernel using system call
Kernel interacts with the hardware
Now, consider a situation where, App A might need python v2 and App B needs Python v3
Now, your system will have only one python installed. Let’s say you can’t have two python versions installed at the same time.
You can use namespacing.. I.e. a segment of hard disk, dedicated to housing python
Namespace: Isolate resource per process or group of processes
NS can not only be used for HW but for SW as well.
NS can be used for processes, Users, Hard Drive, Hostnames, Network
Kernel figures out to which process or namespace it should send the call to
Control Groups or cgroups: Limit amount of resources used per process. E.g. Memory, CPU, HD I/O, Network bandwidth.
Therefore, container is a group or process that has grouping of resources specifically assigned to it.
Image
Filesystem snapshot: copy paste of very specific set of directories or files
Start up command:
When an image becomes a container, kernel takes a portion of HD and dedicated it to the container. After which it takes what is in FS Snapshot and place it in the HDD
After which startup command is executed. This creates a process which is isolated to its set of container
Subset of physical resources allocated to that process
NS and Cgroup are specific to Linux OS
For windows or MacOS, we use Linux VM.
To check, run docker version command and look at OS in server, it will be linux
Docker run <image name>
- Places the fs snapshot in hard drive
- Run the startup command
Docker run <image name> command
Default command override
Docker run busybox echo hi there
Docker run busybox ls
Why these commands won’t run with docker run hello-world ls
Start up commands are based upon the filesystem.
Listing running container
Docker ps
List all the containers ever created
Docker ps –all
Container lifecycle
Docker run = docker create + docker start
Docker create <image name>
Docker start <image name>
Create – takes the fs and copy it in container. Prep/setup the container
Start – execute the start up command
Docker create hello-world
<long number >
Docker start -a <ID>
Attach to container and watch for output and print it on my terminal
Docker start <ID>
No output shown on terminal
Restart a container
Docker start <id>
Once you stop and start the container, it will attach the default command that was used to start it first
Removing stopped container
Docker system prune
Build cache
Stopped container
Dangling images
Networks not used by at least one container
Get logs of a container
Docker logs <container id>
Even the stopped container can emit logs using this command
Stopping a container
Docker stop <container id>
Docker kill <container id>
Stop – Hardware sugnal is sent to primary process sigterm signal.. Shutdown on it’s own time
Do cleanup or emit message whn you recv this signal
Kill – sigkill – shutdown now
If container does not stop in 10 seconds, then docker will switch to docker kill
Execute commands in running container
E.g. redis server.. Redis cli
Exec – run another command
-it – provide input to the container
Docker exec -it <con id> <command>
Docker exec contend command ->
STDIN STDOUT STDERR
Every container is a process in linux
STDIN – used to communicate the info to the process
Whatever you type in terminal gets redirected to STDIN of your running process
STDOUT – conveys info coming out of process.
STDERR – error info channel. Redirected to show up on the screen
-it = -i -t -> -i – we want to attach our terminal to the stdin of the process
-t make sure all the text you enter or is coming out is nicely formatted or pretty or readable
Getting a command prompt or shell access to running container
Docker exec -it <cont id> sh
# -> run unix commands here
Command processors -> bash, powershell, zsh, sh
Exec – execute additional command in the container
Docker run -it busybox sh -> doing the same thing we did with exec
Build our own custom images
Dockerfile – configuration to define how our container should behave. What diff program it should have and what happens when it starts up as container
We then pass it to docker client which passes it to docker server and which builds a usable image, which is used to start a container
DOCKERFILE
Specify a base image
Run some commands to install additional programs
Specify command to run on container startup
FROM alpine
RUN apk add –update redis
CMD [“redis-server”]
Come to docker client and run “docker build . “
Successfully build <id>
Docker run <id>
FROM – base image to use
RUN – execute some commands while we are preparing our base image
CMD – specifies what should be executed when our image is used to start up a brand new container
To understand FROM – if i give you a laptop with no OS and tell you to install chrome.. Your first step will be to install OS.. that is what FROM is.
Build command is what we use to take a dockerfile and build an image
“.” is known as the build context. It is essentially set of files and folders that belong to our project, that we want to encapsulate or wrap inside our container
Start with base image
Execute the run command
Save the image and use it for next step
Tagging an image
Docker build -t <docker id>/repo or project name>:latest .
Docker build -t kunal/abc:latest .
Successfully tagged <name>
Docker run <name>
Command to tag already existing image
Docker tag <id> <name>
To include the files in same directory as dockerfile
COPY ./ ./
Container Port Mapping
Docker run -p 8080:8080 <image tag>
No limitation on container reaching out.. Its only coming in
-p 8080:8080 -> port incoming request from 8080 to 8080 inside the container
Specify working directory
WORKDIR /usr/app -> Any following command will be executed relative to this path in the container
If the folder is not there, it will be created.
To get changes from local to container..you need to rebuild the image
Docker Compose
From node:alpine
Workdir ‘/app’
Copy package.json .
Run npm install
Copy . .
Cmd[“npm”, “start”]
Docker build -t name/visits:tag-latest .
Docker run name/vists
Docker run redis
-> throws redis not found.. WHY?
If you spin up the images separately, i.e. in their own container, they do not have any automatic communication between the two whatsoever. They are two absolute isolated processes that do not have any communication.
Therefore, we need to setup some networking infra between the two.
- Use docker cli for network feature – involve handful of commands that needs to be run every time you start the containers.Not used in the industry
- Use docker compose
Used to start multiple container at same time and automatically connect them together with some form of networking
Separate cli tool
Automates some of the commands we need to run multiple containers at the same time
Docker-compose.yml -> contains all the options we would normally pass to docker cli
File goes to docker compose cli
From example above, create a docker compose file which spins up redis and node app
Docker-compose.yml
Version; ‘3’ – version of docker compose file
Services:
Redis-server:
Image: ‘redis’
Node-app:
Build: . – look in current dir for dockerfile nd use that to build the image
Ports:
– “4001:8081”
It will create both of these containers in the same network. They both have access to each other.
Docker run myimage -> docker-compose up
Docker build .
Docker run myimage -> docker-compose up –build
Docker-compose up -d-> run images in background
Docker stop <cont_id> -> docker-compose up down
Automatic container restart
“No” -> Never attempt to restart
Always -> if this container stops for any reason, always attempt to restart
On-failure -> only restart if stops with an error code
Unless-stopped -> always restart unless we forcibly stop it
Status code
process.exit(0) -> we exited and everything is OK
1,2, -> we exited because something went wrong
Node-app:
Restart: always
In yaml file, “no” needs to be in quotes, as no means false
Docker-compose ps -> status of two containers inside docker compose files
It needs docker-compose.yml file to know which containers it needs to get the status for
Docker Volumes
Make a change in local, we want it to be reflected in the app.
Rather than doing copy, we make volumes, which are reference to folders in local machine
Docker run -p 3000:3000 -v /app/node_modules -v $(pwd}:/app <image id
-. Map the pwd into app folder
If colon is not there, then it is a bookmark. Do not try to map this folder to anything. Use what is inside the container.
You can refer to our Extensive list of Docker interview questions here