# Day 11 : Containerize the services with Docker

**Objective**: Create a Docker image for the User Service (Java/Spring Boot), run it locally as a container, and commit the Dockerfile to GitHub

Daily Tasks :&#x20;

* update jira&#x20;
* Create dockerfile for user-service
* Build image and containerize it&#x20;
* commit changes to github

### Dockerize user-service

```docker
FROM openjdk:17-jdk-slim
WORKDIR /app
# copy maven build jar file
COPY /target/user-service-1.0-SNAPSHOT.jar app.jar
# expose the app
EXPOSE 8080
# Run jar
ENTRYPOINT ["java", "-jar", "app.jar"]
```

<figure><img src="/files/RNT5tfCAWHsLeropCAIx" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/0PGblq2fgVFyFHVPWSdO" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/4RbMZxeq4WeHFJYslgpC" alt=""><figcaption></figcaption></figure>

#### steps to containerize an application

* create a dockerfile (use vi Dockerfile and enter data)
* build image (use docker build -t \<tag-name> .)
* Run the container from the image (docker run -d -p \<hostport>:\<containerport>  \<image name/ tag>

CMD VS Entrypoint

* Both Entrypoint and CMD define how a container runs but they serve different purposes and work together

CMD :thumbsup:

* specifies the default command to run when a container starts
* can be overriddent easily when running the container (ex: docker run \<image> \<new command>
* It is like a default behaviour when nothing else is specified

<figure><img src="/files/Y7h4HywITxqbCJ9LIMUW" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/UaANhrnrXZPFrH7spIYT" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/Q74mRd4ICGhmBXRtsT0J" alt=""><figcaption></figcaption></figure>

Entrypoint :thumbsup:

* Defines the executables that always runs when container starts
* Arguments passed to it will be appended (not replaced)
* It is like "fixed command" the container is built to execute
* Using ENTRYPOINT ensures this command is fixed, and we can pass extra  args (e.g., memory settings) if needed.

<figure><img src="/files/fWV63BZ17JIw38K3J88a" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/ywbKiJAZgPOZr4fwBVJq" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/xHb5GMqCWSR6DNuBJlYJ" alt=""><figcaption></figcaption></figure>

what if we use both cmd and entrypoint in a single dockerfile ?

When you specify both ENTRYPOINT and CMD in a Dockerfile:

* **ENTRYPOINT**: Defines the executable that *always* runs when the container starts.

* **CMD**: Provides default arguments to the ENTRYPOINT executable.

* **Behavior**: Docker combines them—ENTRYPOINT is the command, and CMD is its parameters. If you override the command at runtime (e.g., docker run \<image> \<override>), the override replaces CMD, not ENTRYPOINT

* **Without Override**: ENTRYPOINT + CMD runs as a single command.

* **With Override**: Arguments passed to docker run replace CMD, appending to ENTRYPOINT.

* **Forms**: Both support *exec form* (\["command", "arg1"]) and *shell form* (command arg1). Mixing forms can affect how they combine

<figure><img src="/files/qJaTtR9OLkFcmlz393Dt" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/Ko8AFgCUwaFS0rE9gzQN" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/Zjn3Jhg9KtIS6hTAKRhN" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/bbzOsaqFmQa9jjFpTvTu" alt=""><figcaption></figcaption></figure>

Why EXPOSE in Dockerfile ?

* Tells Docker (and users) which port the container’s application listens on. It’s metadata, not an action
* &#x20;we include EXPOSE to document port not to open it in dockerfile
* Always Use -p to make it accessible (ex: -p 8080:8080)
* **Tooling**: Some tools (e.g., Docker Compose, Kubernetes) use it to auto-configure networking

## Containerize Product service with Docker

```docker
FROM node:16
WORKDIR /app
COPY package.json .
RUN npm install
COPY app.js .
EXPOSE 3000
CMD ["node", "app.js"]
```

`docker build -t product-service:latest` `docker run -d -p 3000:3000 product-service:latest`

`curl http://localhost:3000/products`&#x20;

<figure><img src="/files/PNZFCriuZuq7ObvHy30g" alt=""><figcaption></figcaption></figure>

### Containersation of order-service&#x20;

```
--> Write a Dockerfile
--> Build an image with dockerfile
--> containerize the image
--> run the container
---> check the api url endpoint
```

### containerisation of recommend-service

```
--> Write a Dockerfile
--> Build an image with dockerfile
--> containerize the image
--> run the container
---> check the api url endpoint
```

<figure><img src="/files/CacUlEyy5aIaIFhjt7Tw" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/JLcchbotWrLUkBRUZFJz" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/GQYkzqYsl91SRPWpAHtK" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/AOhAy5xAMGv1A6G1kTgM" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/ZRXuPsnvQwLVafNJaNg4" alt=""><figcaption></figcaption></figure>

Here even though, all containers running successfully we are getting errors in `/orders` and `/recommend` because of  both services are running in separate containers

1. **Localhost in Containers**: When you use `localhost` inside a Docker container, it refers to the container itself, not the host machine or other containers.
2. **Service Communication**: To communicate between containers, you need to use the container's IP address or a service name if you're using Docker Compose

#### Some Other helpful commnds/learnings

<pre class="language-sh"><code class="lang-sh"><strong>
</strong>
# To list all stopped containers
docker ps -a -q -f status=exited
# here a for all and q to list IDs of containers and -f for flag

# To remove stopped containers
docker rm $(docker ps -a -f status=exited -q)
# Dangling images are images without any tag or repository name
docker images -f dangling=true # To list dangling images
# To remove dangling images
docker image prune
# To remove all unused resources (stopped containers, dangling images, unused networks, and build cache except volumes)
# volumes will not be removed unless u specified with prune command
docker system prune
# To include volumes 
docker system prune --volumes

# To remove dangling images without confirmation, use the -f flag
docker image prune -f

</code></pre>

As a solution, we can use docker-compose to simplify container communication. which we will see tommorrow.

If you don't want to use Docker Compose, you can still communicate between containers using their IP addresses or by creating a network and assigning names to the containers

```
docker network create product-network #Create a Docker Network:
# Run containers with network
docker run -d --name product-service --net product-network -p 3000:3000 product-service
docker run -d --name recommend-service --net product-network -p 8081:8081 recommend-service
# modify recommendHandler in code
resp, err := http.Get("http://product-service:3000/products")


```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://charan-techjourney.gitbook.io/charan-techjournal/50-days-of-devops-ecommerce-microservices/project-daily-tasks/day-11-containerize-the-services-with-docker.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
