Docker
This is a collection of personal notes and references that I have gathered while learning Docker.
Table of Contents
- Version
- List Containers
- Remove Containers
- List Images
- Remove Images
- Run Container
- Stop Container
- Inspect Container
- Docker Log
- Port Mapping
- Volume Mounting
- Creating Images
- CMD VS ENTRYPOINT
- Docker Compose
Version
sudo docker version
List Containers
To list the active containerssudo docker ps
To list all the containers including the inactive onessudo docker ps -a
Remove Containers
sudo docker rm <container-name/id>
List Images
sudo docker images
Remove Images
sudo docker rmi <image-name>
Run Container
sudo docker run <image-name>The above command does the following:
- Pulls the image from docker registry (DockerHub or private ones), if not available locally
- Creates a container
- Starts the container
sudo docker run -d <image-name>This runs the container in detach mode which means that the terminal is free to use for other commands (maybe starting another container)
sudo docker run -it <image-name>-i TagThis tag keeps the STDIN (Standard input) open so that you can communicate with the container via. terminal
-t TagThis tag allocates a pseudo-terminal so that it displays any terminal messages to the user
Stop Container
sudo docker stop <container-name/id>
Inspect Container
sudo docker inspect <container-name/id>
Displays more detail than ps.
Docker Log
sudo docker log <container-name/id>
Displays the log of the container.
Port Mapping
sudo docker run <image-name>Suppose you have a docker engine that hosts a website at 0.0.0.0:8080. When you go to that link the website doesn’t open as this link is internal to the docker container. To access it using your IP and port number you have to map the port.sudo docker run -p 80:8080 <image-name>Now when you go to the link:80 the website opens
Volume Mounting
When a docker container completes its lifecycle and stops the data contained in it will also be lost. To prevent this loss of important data from docker container we use volume mounting. This is a persistent storage mechanism that helps store data outside container in docker host.
Volume mounting
sudo docker run -v <dir-name>:<docker-data-path> <image-name>The above command saves the data present in
to docker’s default volume location /var/lib/docker/volumes/ . Bind mounting
sudo docker run -v <local-path>:<docker-data-path> <image-name>The above command performs similarly to volume mounting but it saves the data in the specified location (
) in host engine.
Newer style to perform this is:
Volume mounting
sudo docker run --mount type=volume,source=<volume-name>,target=<container-path> <image-name>Bind mounting
sudo docker run --mount type=bind,source=<local-path>,target=<docker-data-path> <docker-image>
Creating Images
Steps to follow to run an application:
- Start by defining base image or OS
- Update apt repo
- Install dependencies using apt
- Intall program specific dependencies (eg. using pip for python)
- Copy source code to /opt folder
- Run the server
Following the above steps we create a Dockerfile as shown in the sample below.
Dockerfile:
FROM Ubuntu <--------------------------------- Starts from a base image or OS
RUN apt-get update</br> <--------------------------------- Install dependencies
RUN apt-get install python |
|
RUN pip install flask</br> |
RUN pip install flask-mysql <---------------------------------
COPY . /opt/source-code <--------------------------------- Copy source code
ENTRYPOINT FLASK_APP=/opt/source-code/app.py flask run <------ Specify entrypoint to run the app
Now to build an image:
sudo docker build Dockerfile -t <docker-registry>/<username>/<image-name>
To push the docker image in docker-registry:
sudo docker push <docker-registry>/<username>/<image-name>
CMD VS ENTRYPOINT
Both CMD and ENTRYPOINT are instructions used to define what command should be run when a container starts.
CMD
We usually go with the following command to run an instruction
sudo docker run <image> <command>Example:
sudo docker run ubuntu sleep 10This runs the docker container using the image and sleeps after 10 seconds. But the use of sleep looks revealing.To implement thi using CMD we modify the Dockerfile like:
Dockerfile
FROM Ubuntu . . . CMD sleep 10 / CMD ["sleep","10"]ENTRYPOINT
Suppose we want to specify certain parameters during the run time of the command. This is not allowed by CMD as we have to explicitly define the parameters (like 10 for sleep). ENTRYPOINT allows to set such parameters.
Dockerfile
FROM Ubuntu . . . ENTRYPOINT ["sleep"]Example:
sudo docker run ubuntu 10This attaches 10 after the sleep command and the system ends after 10 seconds.
Both
Suppose you want to use ENTRYPOINT but you dont give any arguments. This causes error during the run time. So you have to set a default parameter value when it is not set. For that you make use of both CMD and ENTRYPOINT.
Dockerfile
FROM Ubuntu . . . ENTRYPOINT ['sleep'] CMD ['10']sudo docker run ubuntu 5This makes and run the container for 5 seconds then closes it.
sudo docker run ubuntuThis makes and run the container for default value (10 seconds) then closes it.
Docker Compose
The problem with docker run:
Suppose you make a voting application which is composed of many other application such as:
- Voting application - Where the user casts their vote
- In-memory database - Redis server to temporarily store the data from voting app
- Worker application - Backend application to run all the functionalities
- Postgres database - Where all of the voting data is stored
- Result application - Where the voting result is displayed
In order to run all of these application at once and communicate with each other we must specify their respective links like shown below.
sudo docker run -d --name=redis redis
sudo docker run -d --name=db postgres:9.4
sudo docker run -d --name=vote -p 5000:80 --link= redis:redis voting-app
sudo docker run -d --name=result -p 5001:80 --link db:db result-app
sudo docker run -d --name=worker --link db:db --link redis:redis worker
This way the command looks tedious and unmanagable to enter one by one in Terminal. To solve this we use a .yaml file to specify all of the above.
- Version 1
docker-compose.yaml
redis: <---------------- Name of container
image: redis <---------------- Name of image if already created
db:
image: postgres:9.4
vote:
image: voting-app
ports: <---------------- Port mapping for voting-app
-5000:80
links: <---------------- Used to specify dependencies as voting-app depends upon redis application
-redis
result:
image: result-app / build: <path-to-code-with-dockerfile> <--------------- Use 'image' if image is already made else use 'build'
ports:
-5001:80
links:
-db
worker:
image: worker
links:
-redis
-db
- Version 2
docker-compose.yaml
version 2
services:
redis:
image: redis
db:
image: postgres:9.4
vote:
image: voting-app
ports:
-5000:80
depends_on:
-redis
result:
image: result-app / build: <path-to-code-with-dockerfile>
ports:
-5001:80
depends_on:
-db
worker:
image: worker
depends_on:
-redis
-db
- Suppose you want to connect specific services to a dedicated network to separate the traffic. The convention for such scenario is as given below.
docker-compose.yaml
version 2
services:
redis:
image: redis
networks:
- back-end <--------------- Connects redis container to 'back-end' network
db:
image: postgres:9.4
networks:
- back-end
vote:
image: voting-app
ports:
- 5000:80
depends_on:
- redis
networks:
- front-end <--------------- Connects vote container to both 'back-end' and 'front-end' networks
- back-end
network: <--------------- Defines the networks
front-end:
back-end:
