Docker for beginners
Tags: docker, devops
Published: 2021-08-27 19:46:27

We will go through the commands after the basic understanding of Docker. 

## What is Docker ?

Docker is a set of platform as a service products that use OS-level virtualization to deliver software in packages called containers. 

## What is a container ?

- It's used to package application with required dependencies and configuration which the app uses.

- It can be easily shared between the team. 

- It increases efficiency in development and deployment.

- Technically, Container is made using Layers of Small Sized Linux Alpine Images with Application Image at top.

## Where containers are stored ?

Containers are stored in the form of Images. These Images can be uploaded in  

1) Container Repository
2) Private Repo
3) Docker Hub (Public)

## Why container ?

> In Development

| Before Containers        | After Containers           | 
| ------------- |:-------------:| 
| Different versions or installation of Applications in each Operating System | A Isolated OS layer with Packaged Applications | 
| Mismatched Configuration    | Predefined Configuration     |
| Installation after tedious setup | Installation with one command |All dependencies are predefined


> In Deployment

| Before Containers        | After Containers           | 
| ------------- |:-------------:| 
| Environmental Configuration on the servers | Predefined Configuration  | 
| Dependencies Version Conflicts  | All dependencies are predefined |

## What is Docker Image and Docker Container ?

- Docker Image is the Actual Package.

- Docker Container is the running environment of Image which is pulled to local system and is used to start the application.

## Docker vs Virtual Machine 

To understand how docker works on OS level, lets understand how OS is made.

Operating System has 3 layers:

|               | 
|:-------------:|
|Application Layer| 
|  Kernel Layer |
| Hardware Layer|

In operating System, Application runs on Kernel Layer. 

| Docker       | Virtual Machine        | 
| ------------- |:-------------:| 
| It virtualizes the Application Layer | It virtualizes the Kernel Layer | 
| Docker Image contains the Application Layer  | It has both Kernel and Application Layer|
| It uses host machine's Kernel |  It uses it's own Kernel |
| Smaller in Size | Larger in Size |
| It starts and runs much faster | Its slower.|

Docker Installation :

-----------------------------

Docker Basic Commands:

```sh
docker pull hello-world 
``` 

> It pulls latest Image of hello-world to local system.

```sh
docker pull hello-world:<VERSION>
``` 

> It pulls specific version Image of hello-world to local system.

```sh
docker images
``` 

> It shows all the images in local system.

```sh
docker ps
``` 

> It lists all the running containers in local system.

```sh
docker run hello-world
``` 

> It checks if image is present,if not present it pulls the image and then runs that image.
 
```sh
docker run -d hello-world
``` 

> It checks if image is present,if not present it pulls the image and then creates a new container and runs in detached mode and returns ID of that container.

```sh
docker stop <ID>
``` 

> It stops the container with given container ID.

```sh
docker start <ID>
``` 

> It starts the container with given container ID.

```sh
docker ps -a
``` 

> It lists the running and stopped containers.

```sh
docker rm <ID>/<NAME> -f
```

> It removes the container with given container ID or name.

```sh
docker rm <ID>/<NAME> -fv
```

> It removes the container and the volume associated with it.

```sh 
docker volume ls
```

> It lists all the volumes and the volume associated with it.

```sh
docker rmi $(docker images --filter "dangling=true" -q --no-trunc)
```

> It removes all the volumes which are not in use by the containers. 

## Port Binding while using two version's of Same Application

As we know, Specific application has a default port in Containers. If we want to use two versions of same application and if both versions run on same port then it is not possible to use the specific one. Then we need to bind the port of container in order to use that Application on the port which is not being used on the local system.  

```sh
docker run -p<PORT>:<C_PORT> <IMAGE_NAME> (or) <CONTAINER_ID>
``` 
where 

> PORT= System's port on which application should run
> C_PORT= Default Container's port on which it runs

```sh
docker logs <CONTAINER_ID> (or) <CONTAINER_NAME>
``` 

> It shows the logs of the container.

```sh
docker run -d -p <PORT>:<C_PORT> ---name <C_NAME_BY_USER> <IMAGE>
``` 

where

> C_NAME_BY_USER = container name given by user 
> This command changes the name of the container.

```sh
docker exec -it <CONTAINER_NAME> /bin/bash
```

> It gives access to the terminal in the container.


```sh
docker network create <NETWORK_NAME>
```

> This command creates a new network


```sh
docker network ls
```

> Lists all the networks


```sh
docker network inspect <NETWORK_NAME>
```

> Gives more information about the container.

### Dockerfile

This is how a basic docker file looks like

```dockerfile
FROM node:16
WORKDIR /app
COPY package.json .
RUN npm install
COPY . ./
ENV PORT 3000
EXPOSE ${PORT}
CMD ["npm","run","dev"]
```
### Environment Variables

They can be specified in both Dockerfile and command too.

```sh
docker run -p 3000:3000 -e PORT=3000 -d --name node-app node-app-image
```
where -e is option for ENV and also --env can be used. 

### Persistance in Docker

When a file is changed in the local system, by default it is not updated in the container. We need to make it persistant so that whenever a change is done, it should get updated in the container. This can be achieved by volumes in docker. 

```sh
docker run -v "$(pwd):/app" -p 3000:3000 -d --name node-app node-app-image
```
where 

$(pwd)= present working directory
/app  = working directory in container

Check [this](https://stackoverflow.com/questions/48522615/docker-error-invalid-reference-format-repository-name-must-be-lowercase) out to find why we need to specify `"$(pwd):/app"` in the command. 

### Security Practices

After making the docker persistance using above instructions, if you try to add any file using terminal of the container, it will create the file in the container as well as in the local system since it has been synced with volumes. This is not a good practice.To prevent this, we can add `:ro` in the -v option which means read only. So, it makes container read only, and creating files is impossible. 

```sh
docker run -v "$(pwd):/app:ro" -v /app/node_modules -p 3000:3000 -d --name node-app node-app-image

```

### Docker Compose

This is how a simple docker-compose.yaml looks like

```yaml
version: "3"
services:
  node-app:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - ./:/app
      - /app/node_modules
    environment:
      - PORT=3000
    # env_file:
    #   - ./.env

```
This file can be used to spin up an image and for automatically building the container too. 

```sh
docker-compose up -d
```

> This command is used to build image and container using docker-compose.yaml file and in detached mode.

```sh
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d --build
```

> This command is used to build image and container using custom docker-compose.yaml files and in detached mode.

### Docker Networks

To make containers talk with each other, we need to use docker networks. By default, we can use IMAGE_NAME in place of IP_ADDRESS which acts as a DNS for the container we want to connect with.

```js

mongoose
    .connect("mongodb://<user>:<password>@mongo:27017/?authSource=admin")
    .then(() => console.log("Successfully connected to DB"))
    .catch((e) => console.error(e));

```