We are going to install the following#
- NX - Nx is build system with first class monorepo support and powerful integrations.
- Docker - Docker is an open source containerization platform.
- kubectl - The Kubernetes command-line tool
- minikube - minikube is local Kubernetes
- virtualbox - VirtualBox is a general-purpose full virtualizer for x86 hardware, targeted at server, desktop and embedded use.
Install on macOS#
npm install -g nx
brew update
brew install kubectl
brew cask install docker
brew cask install minikube
brew cask install virtualbox
Install on Linux (Debian)#
install NX
npm install -g nx
To install docker, follow the instructions here: https://docs.docker.com/engine/install/ubuntu/
Install docker-compose
sudo apt install docker-compose
Docker Desktop works on Mac and Windows only. A proper alternative is dockstation app: https://dockstation.io/
To install kubectl follow the instructions here: https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/
To install minikube follow the instructions here: https://minikube.sigs.k8s.io/docs/start/
To install virtualbox follow the instructions here: https://www.virtualbox.org/wiki/Linux_Downloads
Check if installed properly#
kubectl version --client
docker --version
docker-compose --version
docker-machine --version
minikube version
Install NX workspace#
npx create-nx-workspace
Choose desired name for your project
✔ Workspace name (e.g., org name) · nx-monorepo-microservices
Choose express as starter template
What to create in the new workspace
apps [an empty workspace with no plugins with a layout that works best for building apps]
core [an empty workspace with no plugins set up to publish npm packages (similar to yarn workspaces)]
ts [an empty workspace with the JS/TS plugin preinstalled]
react [a workspace with a single React application]
angular [a workspace with a single Angular application]
next.js [a workspace with a single Next.js application]
gatsby [a workspace with a single Gatsby application]
nest [a workspace with a single Nest application]
❯ express [a workspace with a single Express application]
web components [a workspace with a single app built using web components]
react-native [a workspace with a single React Native application]
react-express [a workspace with a full stack application (React + Express)]
angular-nest [a workspace with a full stack application (Angular + Nest)]
Choose App name for the microservice
Application name › svc-products
Choose No for Use Nx Cloud?
✔ Use Nx Cloud? (It's free and doesn't require registration.) · No
Generate more express microservices#
nx generate @nrwl/express:application svc-cart
nx generate @nrwl/express:application svc-user
Create Dockerfile for each microservice#
Create the Dockerfile in the root of each microservice app.
apps/svc-cart
FROM node:lts-alpine
WORKDIR /app
COPY ./dist/apps/svc-cart .
COPY package.json package-lock.json ./
ENV PORT=3333
EXPOSE ${PORT}
RUN npm install --production
# dependencies that express needs
RUN npm install reflect-metadata tslib rxjs express
CMD node ./main.js
NX is ready! 🚀#
Start the kubernetes cluster with minikube (minikube is local Kubernetes)#
minikube start
Check if minikube node is ready#
kubectl get nodes
You should see something like that
NAME STATUS ROLES AGE VERSION
minikube Ready master 40s v1.14.0
Build docker images of express microservices#
First build the express app. You will see the output in the dist directory.
nx build svc-cart && nx build svc-products && nx build svc-user
⚠️ Configure environment to use minikube’s Docker daemon
minikube docker-env
Output
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://127.0.0.1:64883"
export DOCKER_CERT_PATH="/Users/user/.minikube/certs"
export MINIKUBE_ACTIVE_DOCKERD="minikube"
# To point your shell to minikube's docker-daemon, run:
# eval $(minikube -p minikube docker-env)
Copy and run the "eval" command from the output
eval $(minikube -p minikube docker-env)
More on minikube docker-env command:
https://newbedev.com/what-does-minikube-docker-env-mean
Build the docker images
docker build -f ./apps/svc-cart/Dockerfile . -t svc-cart
docker build -f ./apps/svc-products/Dockerfile . -t svc-products
docker build -f ./apps/svc-user/Dockerfile . -t svc-user
Check whether docker images has been created
docker images --format "table {{.ID}}\t{{.Tag}}\t{{.Repository}}"
You should see something like that
IMAGE ID TAG REPOSITORY
9d280d1feec7 latest svc-user
01a97cac7c74 latest svc-products
73de4fa41b44 latest svc-cart
8768eddc4356 v0.0.25 gcr.io/k8s-minikube/kicbase
Deploy to Kubernetes#
Create manifest config files in each microservice root dir:
I prefer JSON over YAML ,but you can use whatever you want. Read more here:
https://kubernetes.io/docs/concepts/configuration/overview/
apps/svc-cart/deployment.json
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "svc-cart"
},
"spec": {
"replicas": 1,
"selector": {
"matchLabels": {
"app": "svc-cart"
}
},
"template": {
"metadata": {
"labels": {
"app": "svc-cart"
}
},
"spec": {
"containers": [
{
"name": "svc-cart",
"image": "svc-cart:latest",
"imagePullPolicy": "Never",
"ports": [
{
"containerPort": 3333
}
]
}
]
}
}
}
}
apps/svc-cart/service.json
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "svc-cart-service"
},
"spec": {
"type": "NodePort",
"selector": {
"app": "svc-cart"
},
"ports": [
{
"protocol": "TCP",
"port": 80,
"targetPort": 3333,
"name": "svc-cart-service"
}
]
}
}
Apply the configuration in deployment.json and service.json to a pod
kubectl apply -f apps/svc-cart/deployment.json
kubectl apply -f apps/svc-cart/deployment.json
Check if pods are running#
kubectl get pods
output
NAME READY STATUS RESTARTS AGE
svc-cart-8b6dfcfb4-tzccw 1/1 Running 0 39m
svc-products-5b9d7478b-5r5zq 1/1 Running 0 14m
svc-user-5c59cb6776-gdt2h 1/1 Running 0 5m54s
Check if services are running#
kubectl get services
output
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 18h
svc-cart-service NodePort 10.99.159.203 <none> 80:32180/TCP 25m
svc-products-service NodePort 10.105.26.125 <none> 80:30915/TCP 16m
svc-user-service
Access services outside the node (minikube is able to create tunnel )#
minikube service svc-cart-service --url
You will see something like that:
🏃 Starting tunnel for service svc-cart-service.
|-----------|------------------|-------------|------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|------------------|-------------|------------------------|
| default | svc-cart-service | | http://127.0.0.1:53401 |
|-----------|------------------|-------------|------------------------|
http://127.0.0.1:53401
❗ Because you are using a Docker driver on darwin, the terminal needs to be open to run it.
Open up http://127.0.0.1:53401/api
You should see the following JSON response:
{"message":"Welcome to svc-cart!"}
🚀 🚀 🚀 Open another terminal instance and run another service 🚀 🚀 🚀
Monitor services with minikube dashboard#
minikube dashboard
Github repository#
https://github.com/creotip/nx-monorepo-microservices-docker-kubernetes
The Outcome#
This tutorial is for learning purposes on your local machine. It's the first step before you deploy your microservices to the cloud services such Google Cloud, AWS, Azure or Digital Ocean.
In the next tutorial we will learn how to deploy microservices with ArgoCD. Stay tuned 🎧!