Notes for Docker
- Is it a lightweight and open source application used for containerization of our application.
- Containerization is the process of making our application code + required dependencies into one executable package.
- Containerize our application code + required dependency to create docker image
- After we create docker image it will be used by other developer to run our application to their machine.
- When other developers get our docker image and run it in their machine it will automatically create docker container.
- Suppose you are developing an application and you already finish it, now you have these system specification to run your app in another machine.
- Angular v13
- Java v17
- MySQL v8.5
-
Install Angular v17
-
Install Front-end dependencies
-
Install Java v17
-
Install Back-end dependencies
-
Install Apache Tomcat v10
-
Install MySQL Server v8.5
-
Now you want to run your application to run in another machine you will set up you application environment with that machine in order to run your app and everything seems fine, but your manager says he also want it to run in his/ her machine you will go to where his/ her machine just to set up your application environment right? and everything ok, but now everyone now wants to run you application to their machine and have the application environment below specific to them what will you do now? You will now use docker help with your application environment to be set up in everyone's machine.
- For different application environments
- For managing versioning of our application tech stack and dependecies.
- The legendary phrase "it works on my machine"
- Application dependecies versioning on multiple machine conflict.
- Time consuming application environment set up in multiple machines.
- Updating application dependencies in multiple machine in one place.
- For easy sharing of your application with just them literally run the project no need for them to set up anything.
- It contains a set of instructions that Docker follows to build the docker image.
- It Automate the process of building a reproducible and consistent environment for your application.
- Created via dockerfile
- It is the application code + required dependencies.
- Used to store our docker image just like github.
- DockerHub
- Nexus
- JFrog
- AWS ECR
- It internally uses virtualization that means every container linux virtual machine that can run independently.
- Will be created in our local machine after we run the docker image.
- It is running operating system in another operating system.
- A virtual machine (VM) is a software-based emulation of a physical computer. It enables you to run multiple operating systems on a single physical machine that operates as an independent entity with its own virtualized hardware, including CPU, memory, storage, and network interfaces.
- Docker uses virtualization which leveraging the use of virtual machine and share the host OS kernel unlike normal virtual machine its has its own OS and separate kernel that can be resource-intensive.
- docker init: Will initialize a docker environment in current directory. (Only executable if you have Docker Desktop installed).
- docker images: List all downloaded images in you machine.
docker images
- docker push: Will push a docker image from your machine to remote repository(Dockerhub).
docker tag <local_image_name>:<local_image_tag_name> <username>/<image_name_you_want>:<image_tag_name_you_want>
docker push <username>/<image_name_you_want>:<image_tag_name_you_want>
Example:
docker tag sma:stable elleined/social-media-api:latest
docker push elleined/social-media-api:latest
- docker pull: Will pull a docker image from remote repository(Dockerhub) to your machine.
docker pull <image_name>
docker pull <user_name>/<repository_name>:<tag_name>
- docker rmi: Used to delete docker image.
docker rmi <image_id/ image_name>
- docker build: Used to create docker image using dockerfile.
docker build -t <image_name_you_want>:<tag_name_you_want> <dokcer_file_location>
docker build -t my_image:my_tag .
- docker ps -a: list all docker container in your machine.
docker pa -a
- docker run: Used to run docker image thus creating a docker container.
docker run <image_id/ image_name>
- docker start: Used to start a stopped docker container.
docker start <container_id/ container_name>
- docker stop: Used to stop a running docker container.
docker stop <container_id/ container_name>
- docker rm: Used to delete a stopped docker container.
docker rm <container_id/ container_name>
docker exec -it <container_id> /bin/<bash | sh>
Example: docker exec -t 12345 /bin/bash
- docker network ls: List all docker networks
docker network ls
- docker network create: Create a user-defined network.
docker network create <network_name>
- docker network rm: Delete a network
docker network rm <network_name>
docker run -itd --rm --network <network_name> --name <container_name_you_want> <image_name>
- docker volume create: Create a volume.
docker volume create <volume_name>
- docker volume rm: Remove a volume.
docker volume rm <volume_name | volume_id>
- docker volume ls: List all volumes.
docker volume ls
- docker volume inspect: Return information about the specified volume
docker volume inspect <volume_name | volume_id>
- docker-compose start: will start the stopped containers.
docker-compose start
- docker-compose stop: Will stop the running containers but not delete the docker compose created containers, volumes, networks, and secrets
docker-compose stop
- docker-compose restart: Will restart the containers
docker-compose restart
- docker-compose up: Will pull and run all the services in your docker compose and create the defined networks and secrets.
docker-compose up
- docker-compose down: Will stop and delete all the docker compose created containers, volumes, networks, and secrets.
docker-compose down
- Networking in docker is almost the same concept in groups of people in real world. Why I said that? When you run docker image it will create a container right? But arent you wondering what network does that container running? It is running on default docker network which is the network name bridge and network type or driver bridge.
- If theres a default network it means that we can create our own docker network and we can run a docker container with our own docker network created.
- Docker networking tutorial (Network Chuck)
Analogy: Think of group of people as network and every people want to join a group(network). And people without a group(network) belongs to nothing in our case the default network where everyone resides. So when a people join a group(network) they will belong to that group(network) right. So in that case the people inside that group(network) will be able to communicate in isolation and security and people that are not belong to the group will not able to talk to them the same goes to them they not able to talk to peoaple outside the group.
NOTE: when you execute docker run without specifying the network it will reside in default network name bridge and network type bridge.
- For you to have two container to talk to each other you need them to be running in the same network. For example you app and your app database right those two need to run in the same network to able to talk to each other.
- Since container is a virtualize OS it means that they don't have data persistence and all the data will be deleted once the container is removed. And sometimes we want to save the data inside the container that why VOLUMES comes into picture, volumes are used to shared host OS files or directory inside the container or vise versa granting container and host OS to access host OS file system/ Container to have Data Persistence.
- Provide data persistence outside the container that can be use internally(Localhost) and externally(cloud services).
- Easier volume management because volumes can be manage via docker commands(Will be discussed later).
- Sharing data accross different containers.
- Method 1: Using a named volume and container directory.
docker run -v <volume_name>:<container_pre_defined_directory>
####### Note: Docker run -v is a short version and --mount is the verbose version
- Used to create a docker image.
Instruction | Description | Syntax |
---|---|---|
FROM | Specifies the base image to inherit from. | FROM <image_name> |
MAINTAINER | Sets the author of the image. | MAINTAINER <name> |
RUN | Executes any linux commands during the image build process. | RUN ["<executable>", "<param1>", "<param2>"] |
ENV | Sets environment variables accessible within the image and running container. | ENV <key> = <value> |
COPY | Copies files or folders from the host system into the image. | COPY <source> <destination> |
EXPOSE | Informs Docker that the container listens on specific ports at runtime (doesn't publish ports). | EXPOSE <port> |
ARG | Declare private variable only accessible within the dockerfile. | ARG <key> = <value> |
ADD | Similar to COPY, but can also extract tarballs and copy files from URLs. | ADD <source> <destination> |
WORKDIR | Sets the working directory within the container. | WORKDIR <path/to/your/working_directory> |
USER | Sets the user and user ID for the container process. | USER <user_name/ UID> |
CMD | Executes a command when the container starts (only one permitted) and parameter can be overwritten | CMD ["<executable>","<param1>","<param2>"] |
ENTRYPOINT | Defines the command(s) executed when the container starts (overrides CMD) and parameter cannot be overwritten | ENTRYPOINT ["<executable>", "<param1>", "<param2>"] |
- Since every instructions in dockerfile is a layer and every layer inherits from the previous layer it is important to write your dockerfile efficiently and make the most of docker caching.
- Everytime you modify a dockerfile you need to rebuild it making your dockerfile layering important, when you rebuild dockerfile and docker engine don't see any changes from specific layer it will use the cache.
- So dockerfile structure must be from less frequent changing contens to frequently changing content.
- Because when docker see a changes from one of the layer it will rebuild all remaining layer that's why we need to place the frequently change content in the bottom of dockerfile and the less frequent to change is in top. Memory management is a must!.
Note: You can only have one CMD command and ENTRYPOINT in docker other commands can be executed multiple times.
- dockerfile instruction (FROM, COPY, etc...): Also the same as layer.
- tarball: Compressed file.
- Comprehensive YT Tutorial
- For this I will make example of my social-media-api to dockerization.
docker network create <network_name>
Example:
docker network create sma-network
docker run -itd --rm -p <external_port>:<internal_port> --network <network_name_specified_above> --name <container_name_you_want> MYSQL_ROOT_PASSWORD=<root_password> -e MYSQL_DATABASE=<first_database_to_be_created_in_startup> <image_name>
Example:
docker run -itd --rm -p 3307:3306 --network sma-network --name sma_mysql_server -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=social_media_api_db mysql:8.0.32
mvn clean install
<build>
<finalName> jar_file_name_you_want </finalName>
</build>
Example:
<build>
<finalName> social-media-api </finalName>
</build>
- For this just learn more about how to create a dockerfile. But I have example here.
FROM openjdk:17-alpine
MAINTAINER Elleined
# Docker MySQL Credentials
ENV MYSQL_HOST=sma_mysql_server
ENV MYSQL_USER=root
ENV MYSQL_PASSWORD=root
ENV MYSQL_PORT=3306
ENV MYSQL_DATABASE=social_media_api_db
ADD ./target/*.jar social-media-api.jar
EXPOSE 8081
CMD ["java", "-jar", "social-media-api.jar"]
spring.datasource.url=jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT}/${MYSQL_DATABASE}
spring.datasource.username=${MYSQL_USER}
spring.datasource.password=${MYSQL_PASSWORD}
docker build -t <container_name_you_want>:<tag_name_you_want> <Dockerfile_path>
Example:
docker build -t sma:latest .
docker run -itd --rm -p <external_por>:<internal_port> --network <network_name_specified_above> --name <container_name_you_want> <image_name>
Example:
docker run -itd --rm -p 8081:8081 --network sma-network --name sma_app sma
- What is
docker-compose.yml
? It is used to easily manage multi container application using yaml file or configuration file. With just single command you can run and stop all the associated container for your app.
Becuase in real world suppose we have 3 entities the Frontend, Backend, and Database these three will have their own images right? and managing them individually is hard and time-consuming so docker compose came into picture where you will manage a multi-contsiner app easily.
version: <docker_compose_version>
services:
api: # You can replace api with your custom service name
build: . # Replace . where is your Dockerfile located
container_name: my_container # Container name you want and replacement for --name <container_name>
restart: always # Just use `always` for restart
ports: # List of Ports
- "8080:8080" # Replacement for -p <external_port>:<internal_port>
environment: # List of ENV
- MY_KEY=MY_VALUE # Replacement for -e <my_key>=<my_value>
networks: # List of Network
- api_network1 # References to network you created below and replacement for --network <network_name>
secrets:
- api_secret1 # References to secret you created below
depends_on:
db: # Will wait for the db service to up and running before running this service.
condition: service_healthy # Will make sure db healthcheck passed
db:
healthcheck:
test: # Execute a command to check if service is running correctly
interval: 1m30s # This defines how often the health check should be run. In this case, 1m30s means it will run every 1 minute and 30 seconds.
timeout: 10s # This sets the maximum time the health check can take to complete successfully. Here, it's set to 10s, meaning the check will be considered failed if it doesn't receive a response within 10 seconds.
retries: 3 # This defines the number of times the health check will be retried if it fails initially. Here, it's set to 3, meaning it will attempt the check three times before considering it a complete failure.
start-period: 2m # This defines a delay before the first health check is run after the service starts. Here, it's set to 2m, meaning the health check will wait for 2 minutes before performing the first test.
networks:
api_network1:
ipam:
driver: default
name: api_network # Replace api_network with your custom network name
external: false # If Set to true it means that your created this network yourself
api_network2:
secrets:
api_secret1:
file: /path/to/secret_file.txt # Replace the /path/to/secret_file.txt where your secret is located
external: false # If Set to true it means that your created this secret yourself
name: api_secret # Replace api_network with your custom secret name
api_secret2:
- Forcefully deletes all stopped containers, unused networks, build cache, unused volumes and dangling images
docker system prune --volumes -f
- Deletes all docker images
docker rmi -f $(docker images -aq)