When developing applications with only a few services (e.g. MVP, simple apps) but different teams we often need a 'simple' way to debug/test our services in interaction with other services locally. Provisioning a local k8s cluster like in the cloud environment may be suitable, but sometimes this is just a massive overhead (preparing, maintaining, fixing, ...).
Instead of running a local k8s cluster (that comes with its own issues and difficulties) another solution is to "simulate" the same microservice architecture by using "Docker Compose". This is easier to prepare and maintain (e.g. no need to install a k8s distribution such as k3s, kind or minikube). Finally running a single command is all we need:
docker compose -f "docker-compose-local.yaml" up -d
- no service mesh
- no api gateway
- uses a reverse proxy (e.g. NGINX)
Info: install Mermaid for VSCode to preview architecture Mermaid Preview Extension
graph TD
LB[Entry point]
LB --> k8s
subgraph k8s[Architecture >> similar the k8s cluster]
style k8s align:left;
NGINX[NGINX]
subgraph Services[ ]
F[Frontend Service]
A[Backend Service A]
B[Backend Service B]
C[Backend Service C]
end
NGINX -->|proxy to| F
NGINX -->|proxy to| A
NGINX -->|proxy to| B
A -->|communicate with| C
B -->|communicate with| C
end
This is a external IP to access the application (or may be a load balancer in front of k8s).
For this sample we use http://localhost:8080 (NGINX exposed by Docker Desktop).
NGINX is often used as reverse proxy to provide one API endpoint for different services. Service discovery/DNS is done by k8s or local with Docker-Compose.
- Frontend service (e.g. Angular).
- Backend services A, B and C (e.g. REST APIs).
- Service A and service B depend on functionality provided by service C.
Each service is packed in its own Docker container, adhering to microservice architecture.
- Build images (optional)
cd ./ApplicationSource/
docker compose build
cd ..
- Run Docker compose
docker compose -f docker-compose-local.yaml up -d
graph TD
subgraph Services[ ]
A[Backend Service A]
C[Backend Service C]
end
CP[Container Port : 8084]
subgraph LocalDev[ IDE listening on http://localhost:5264 ]
B[Backend Service B]
end
NGINX[NGINX Port : 8080] -->|proxy to Docker Container| A
NGINX -->|proxy to IDE | LocalDev
C -.-|expose | CP
A -->|communicate with| C
LocalDev -->|communicate with| CP
- Stop container
nginx-reverse-proxy
- Change location proxy of
Backend Service B
in nginx.conf to:
location /api/a/ {
rewrite ^/api/a/(.*)$ http://localhost:5264/$1 permanent; # use this for local redirection
}
- Change the
appsettings.Development.json
in the local developent environment to redirect traffic to the with docker-compose-local.yaml exposed port 8084 fromBackend Service C
:
"ServiceEdpoints": {
"service-c": "http://localhost:8084"
}
- Start IDE (listening on port 5264)
- Re-start container
nginx-reverse-proxy
- Opening a browser on http://localhost:8080/api/a/ will then redirect traffic to the IDE listening on http://localhost:5263/ -> e.g. http://localhost:8080/api/a/weatherforecast will result in http://localhost:5263/weatherforecast
graph TD
subgraph Services[ ]
A[Backend Service A]
B[Backend Service B]
end
subgraph LocalDev[ IDE listening on http://localhost:5215 ]
C[Backend Service C]
end
NGINX[NGINX Port : 8080] -->|proxy to Docker Container| A
NGINX -->|proxy to Docker Container | B
A -->|redirect to IDE| LocalDev
B -->|redirect to IDE| LocalDev
- Shut down all containers
docker compose -f docker-compose-local.yaml down
- Change the
appsettings.Docker.json
in Service A and B to redirect the traffic to the IDE:
"ServiceEdpoints": {
"service-c": "http://host.docker.internal:5215"
}
docker compose -f docker-compose-local.yaml up
To recive traffic from Backend Service A
in the IDE running Backend Service C
use endpoints provided by Docker Desktop on http://host.docker.internal
For a running the service on your local computer, listening on e.g. port 5215, this results in:
http://host.docker.internal:5215
For the sake of simplicity, this Github repository contains .env
files to set environment variables used as images tags in docker-compose files. Normally, you wouldn't check in .env-files.
I want to use the latest image tags. How to I skip double checking/changing the .env file on every start?
ToDo!
ToDo!