Docker for Beginners (Windows)
Tags: docker, container, aws, devops
Published: 2024-06-25 17:59:03

##What is Docker

Docker is a platform that allows us to package and run applications inside lightweight, isolated environments called containers. These containers include all the necessary dependencies and code needed to run our app consistently across different machines. Unlike traditional virtual machines, Docker containers share the same host operating system, making them efficient and portable. Docker simplifies version control, dependency management, and ensures consistent environments for development and production. It’s a powerful tool for streamlining software deployment and scaling. 🚀





---


###Before


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yu1etgeksya3hxwofbn5.png)

###After

1. Own isolated environment and own operating system which is linux based.
2. Packed with all configuration
3. One command to install the app


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4osldu98a9d6jji8hyp5.png)


###Application deployment

1. So before docker , the configuration of the server needed
2. There might dependencies conflict
3. Misunderstandings
4. Text doc for deployment

so after the containers,
1. No environmental configuration on the server - except docker runtime
2. Developers and Operations works together to the package the application in a container


##What is a container

- The container is a layer of images.
- Mostly linux base image, because small in size[ alpine: 3.10]
- And the application image is on top.

##Lets install Postgres:9.6
1. 1st go to [DockerHub](https://hub.docker.com/search?q=postgres)
2. Search postgres

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/la5sftijn2juqk789wrc.png)


3 . Choose your desired version, i choose 9.6 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jjorus5rp3qfdphfo5h4.png)

4 . For windows, open wsl and run `docker run postgres:9.6`


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hnesiw6xzbkav2sl0yiw.png)



##Difference between Image and Container

1. Image is an actual package or software that we want to run. It can be moved around
2. Actually when we start the application is called container. And when we run the image, then it first bring to a container and then we run it and called  container



##Difference between Docker and Virtual machine

1. Docker image is much smaller like couple of megabytes and vm might be couple of gigabytes 
2. Docker container start and runs faster but the vm is much slower
3. If we want to run some linux based application on windows then it will not run, because the the OS kernel is not same. Thats why we need to use the Docker tool box


##Basic Docker commands

1. docker pull
2. docker run
3. docker start 
4. docker stop
5. docker ps
6. dokcer exec-it
7. docker logs


#### Installing redis image

1. Just go to docker hub
2. Search redis


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sqzfrjqtgtztreqfpjg2.png)

3 . open wsl , run command `docker pull redis`


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3kunsk4hc3a31tq2jbla.png)

4 . Now we have to put the redis image to a container to run it. For that just give the command, `docker run redis`


5. To check the running images, open a new terminal and give, `docker ps`

6. To stop the running image give `ctrl + c`


7. `docker run`, command runs new container when we use it.

8. Here are some key differences between the two commands:
**Attached vs Detached Mode:** The main difference is that docker run attaches to the container, while docker run -d runs the container in detached mode.

**Output:** With docker run, you will see the output of the container in your terminal. With docker run -d, you will not see the output.
Container Management: With docker run, you can manage the container directly from your terminal. With docker run -d, you will need to use other commands like docker ps and docker stop to manage the container.

In summary, docker run is used to start a container and attach to it, while docker run -d is used to start a container in detached mode, allowing it to run in the background.

**Attached mode**


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h0biljghmxe0abqpwse0.png)

Here the container is attached with the terminal


**Detached mode**


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m020u5b3sblk56knmoz2.png)


9 . Now in detached mode, to stop the container for some reason we can use, `docker stop <id>`



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sp60oai9qt6uvbcvsind.png)


10 . To start again use , `docker start <id>`


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xe8vin614eu09zpyzbdm.png)


11 . Suppose we stops the container for today and came back tomorrow and want to start from where left, to do that we can use, `docker ps -a` which will show all the running and not running container logs



12 . Now if want to run 2 redis of different versions, we have to use `docker run redis:version` , here the version is- which version image we want to run in our container. `docker run` pulls image and runs the container.
So the docker run does two command in one, one is **docker pull** and the other one is **docker run**


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xoymoytmd82qj649fwfl.png)



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lhhklyd7eipd2l6xn1rx.png)


Here we can see, both redis versions are running on port: 6379/tcp, which is also the container port number.
But the problem is in tcp we can not use single port for multiple application in our localhost . To solve this issue we have to bind port.

13 . To bind the port at first we have to stop all the running redis images. 



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q5c0fsv766ed6t2a6896.png)

Then run, 

`docker run -p6000:6379 -d redis` for 1st one,


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lyjm31qji1elyo4grfns.png)


for the second one we will run it on port 6001 same way but remember 6379 is the container port.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/byu0bof1lpr39gk8nw19.png)


We can see 2 different redis application runnig on 6001, 6000.



##docker log & docker exec -it

To check why one container is not working properly , using the docker log

1. `docker logs <id>`
2. or `docker logs <name>`



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s9c4unpftmlwwfxjg6hf.png)


but it is difficult to remember the container name. To solve this problem we can name the container as we like.

3 . So we have two container currently running,

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mvcgddynjwyb13wbq76a.png)

- at first we have to stop one using, `docker stop <id>`

- Now give the command , `docker run -d -p6001:6379 --name redis-older redis:7.0`



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nej5ynm0vl7rs1tqdgzu.png)


- then we can use docker logs by the given name

`docker logs redis-older`


##Docker exec -it

1. We can easily open the terminal of the current container using, `docker exec -it`

2. We have container named redis-old

3. now give, `docker exec -it redis-old /bin/bash`

note: we can use the container id also instead of name(redis-old)

4. Then we went to home directory and run env command

5. To exit we simply give `exit`


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v4f0twdczpjfnexb9pzh.png)


##Developing with containers

1. Install express, mongo-express by,
- `docker pull mongo`
- `docker pull mong-express`



###We are going to create a new network

1. To create a new network, give: `docker network create mongo-network`

2. to check the network list: `docker network ls`


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6zhast7ufmt77ayn3kei.png)



### Run mongo containers

1. The default container port for mongo is 27017

2. 
`docker run -d -p 27017:27017 \
  -e MONGO_INITDB_ROOT_USERNAME=admin \
  -e MONGO_INITDB_ROOT_PASSWORD=password \
  --name mongodb \
  --net mongo-network \
  mongo
`

id: 74bd46402e9cebdf13c2265a01b072807dd7d97bb83ae569193e35c191f67f60


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hurxw907cbnxsas6mdcc.png)





3 . Same way run the mongo-express,


1. `docker run -d -p 8081:8081 \
  -e ME_CONFIG_MONGODB_ADMINUSERNAME=admin \
  -e ME_CONFIG_MONGODB_ADMINPASSWORD=password \
  -e ME_CONFIG_MONGODB_SERVER=mongodb \
  --net mongo-network \
  --name mongo-express \
  mongo-express
`

id: 6847ec9032c3673c6c61fc0f89e1b2baa5cbb44bea27eeedf0d67a1e384ec109 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xh96tjxos5z24w26zy70.png)



4 . Now we can easily check , if mongo-express is connected or not by, `docker logs <id>`


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m48emflzq9ax99m37dwa.png)


5 . Now go to browser and search, `localhost:8081`

and give username: admin, 
password: pass


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ndxlz3j8z5fbopptxsug.png)


And you will see the home page,



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tw0c5v9idwcl50b9uoef.png)




---


##Docker Compose

Previously we use run commands to start our containers and created a network to communicate between them. But what if we need to run 10 containers at a time and create a network to communicate them, it will be very difficult to run 10 commands for each containers. To solve this issue we can use **Docker Compose File** , which will contain all the commands in a structured way.





![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uea3bgwyg524v1cjb4a8.png)



1 . Version: 3  // version of docker compose
2 . Services:   // here all the container names goes
3 .     mongodb:  // container name
4 .         image: mongo    // which image we are using here mongo
5 .         port: 
                -27017:27017    // this is the tcp port number host:container 
6 .         environment: 
                -MONGO_INITDB_ROOT_USERNAME=admin MONGO_INITDB_ROOT_PASSWORD=password    // environment variables

7 .     mongo-express: // new container name
8 .         image: mongo-express // image
9 .         ports: -8081:8081    // port number
10.         environment: ....     // environment variables


But there is one thing is missing that is **Docker Network**, Actually in docker compose file we don't need that, docker compose itself takes care of creating a common network.


##Let's create a docker compose file

In docker compose file(yaml file) the indentation       is important. We have a demo project where we have the docker compose file,


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/llfohwslmy4jwg7amtnz.png)



```
version: '3'
services:
  mongodb:
    image: mongo
    ports:
     - 27017:27017
    environment:
     - MONGO_INITDB_ROOT_USERNAME=admin
     - MONGO_INITDB_ROOT_PASSWORD=password
  mongo-express:
    image: mongo-express
    ports:
     - 8081:8081
    environment:
     - ME_CONFIG_MONGODB_ADMINUSERNAME=admin
     - ME_CONFIG_MONGODB_ADMINPASSWORD=password
     - ME_CONFIG_MONGODB_SERVER=mongodb
```

save it as, mongo.yaml

- Now the question is how to run the compose file !!. 

- At first we go to the location where we save the compose file using the terminal. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u62iqxa2pvd4zfumx5r0.png)

- The docker compose is also installed with docker is installed. Its a package 

- 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1wyc30440nbsnk0pzkhp.png)


now give, `docker-compose -f mongo.yaml up`
Here, the command **`-f`** means the mode of the document is **file**

- 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sn20yie7h6i22lpzwjjs.png)

Here we can see new network has been created and two new containers also.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vl6jqzsl2uu0xo4hgyza.png)


- Previously to stop the containers we have to use docker stop, but in docker compose we can use 

`docker-compose -f mongo.yaml down`

And it will shutdown all the container in the compose file, and also the network that had been created by docker compose.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ob3qgvxr9dormd7z2v6l.png)

after shutdown,


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j4b6q8s4ts5h1izohhmy.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f9q9yg79adsglr01o51g.png)


**NOTE**: The command is used for downing the compose file is actually a container restart and we will lost every data that we worked in previous container.




---


## Dockerfile - Building our own Docker Image



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h1a0abiawn39rcq0ktzh.png)

1 . FROM: node // which gives us the installed node
2 . ENV: // which are the environment variable
3 . RUN : // executes any linux commands , here the directory will be created using mkdir
4 . COPY:  // It executes on the HOST machines
5 . CMD: // entry point command


- To create our own image we need two thigs, 1. name, 2. Tag

- At first go to the folder that contains Dockerfile, run the command-> docker build -t my-app:1.0 .


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hta6dda06rac6db2bp8y.png)


**Dockerfile:**

```
FROM node:22.3-alpine3.19

ENV MONGO_DB_USERNAME=admin \
    MONGO_DB_PWD=password

RUN mkdir -p /home/app

COPY ./app /home/app

# set default dir so that next commands executes in /home/app dir
WORKDIR /home/app

# will execute npm install in /home/app because of WORKDIR
RUN npm install

# no need for /home/app/server.js because of WORKDIR
CMD ["node", "server.js"]


```


To check, give docker images,

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ynxwp56k969evgznurnc.png)


- We can run the image using, `docker run my-app:1.0` and see the logs, `docker logs <id>`

- to open it exec mode,


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o2yodfdzh64392o2plu1.png)




##Privet Docker Registry

1. Create and account on aws.amazon.com 
2. Serach ECR service 
3. Create a repository
4. Named the repo my-app

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lfibk8pnglngnzjun8za.png)
5 . Now we are going to push the docker image that we created.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ibekq1j4bm46whz5ak1o.png)


6 . At first we need to create an account on aws.amazon.com. 

7 . Install AWS CLI, [CLI installer](https://aws.amazon.com/cli/) . 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mfldvc3tpki5rkfl2981.png)

verify installation using, `aws --version`

8 . Now we need to do aws configure, before that we need to create a IAM account. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x8k5kj6h09zzxybq0zwn.png)

From the user we have to create a user and click on the user and create an access key,


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/23l6zcp41r6h3gmq4awc.png)




![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4f0bvfklgcr7bmqxm0eq.png)


Now we can configure the aws cli using , `aws configure` and put the access key id there.


9. Now we are going to create an ECR repository which is a private registry,

- In services search ECR and go to private portion and click on **create repository**


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/74uel640zypax1t4iuwm.png)


Now , give name to your repo, i gave my-app and keep the other things as it is, 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sdn32s5u3fx1i19ftl27.png)


10 . Now Click on the created repo , my-app,

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zx6fe04vq6s2xizdqwrs.png)


Then view push command, 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ss0xbqmv2p5usqi23aq1.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tggw2txjnwl46iqvo1ay.png)


11. Copy The first command and paste it to powershell, 

if you get this error,

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xhpbvfkwwb1vy0638cq0.png)

then, go to IAM user,

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b2a2qqcuj0mifh1xu1e2.png)


- Them Add permission 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wlrmoprdmide9ytlj2nd.png)

Create Inline policy


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/du92hp7eje7zhsm3eznb.png)


- Select JSON, 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0elf8gy2hwgtoes8b0f5.png)


- And remove all code and add this,

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ECRLogin",
      "Effect": "Allow",
      "Action": "ecr:GetAuthorizationToken",
      "Resource": "*"
    }
  ]
}
```


Now the error must be solved. And give this command,,

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a0pa2gz2aqnu9l216hww.png)


it will show you,

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7v1k0ujlfwu8q08f2pq6.png)



LOGIN Successful


Now we will come back later and we see the 

---

##Image Naming in Docker Registry 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eck9k6icgthb12gj3pm5.png)


Normally in docker hub, we have the short name of the docker image but in aws ECR we have write the full mode.

- So we are going to use this, `docker tag my-app:1.0 339712908553.dkr.ecr.eu-north-1.amazonaws.com/my-app:1.0`

- By giving this we create a duplicate image with different name because of the tag,

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5khgadplorisckz8glg2.png)


- 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2kq8rzdan40qd9kw4olv.png)

Now we are going to use the 4th command but we will the latest with 1.0.

[Some images are taken from Tech with nanas YT channel]