svg
Post Image
By Daniel Tanque15 de Novembro, 2023In Sem categoria

Microservices

Microservices is an architectural style that structures an application as a collection of small, independently deployable services. Instead of building a monolithic application where all the components are tightly integrated and interdependent, microservices break down the application into loosely coupled services that can be developed, deployed, and scaled independently.

As you’ve seen Docker and Kubernetes articles you can now get the overall picture and build a multi-tier and scalable solution. In this article you will learn how to do so.

You will be using a demo sample from Docker. Find more information here: https://github.com/dockersamples/example-voting-app

This is the structure of your platform, you have a Python and NodeJS app, one to vote and another to check the result.

Python communicates with redis which collects the votes and .NET consumes the votes and stores in a DB that then is accessed by the NodeJS app.

First thing: Docker

To have it running you need to run the following commands:

docker run -d --name=redis redis
docker run -d --name=db postgres:9.4

docker run -d --name=vote -p 5000:80 voting-app
docker run -d --name=result -p 5001:80 result-app

docker run -d --name=worker worker

This enables communication, but doesn’t ensure connection, for that you need to link the containers:

docker run -d --name=vote -p 5000:80 --link redis:redis voting-app

docker run -d --name=result -p 5001:80 --link db:db result-app

docker run -d --name=worker --link db:db --link redis:redis worker

*NOTE: links are getting deprecated.

Second part: K8s

Now in the previous section you’ve set the Docker, it runs and we can do everything, but a container can fail and to recover it we have to do it manually and that’s it’s proper for production.

You need to get the kubernetes setup so you set the pod and deployments so you can ensure recovery when a pod stops working as expected. For that you will need also to enable connectivity and make it accessible, for that we will use services.

The image above is the final goal we want to achieve, a scalable/multi tier platform.

To ease and go step by step we can start by stating each pod, then the deployment, and finally adding the services.

So Pod files YAML:

> voting-app-pod.yaml

apiVersion: v1
kind: Pod
metada:
name: voting-app-pod
labels:
name: voting-app-pod
app: demo-voting-app
spec:
containers:
- name: voting-app
image: examplevotingapp_vote:v1
ports:
- containerPort: 80

> result-app-pod.yaml

apiVersion: v1
kind: Pod
metada:
name: result-app-pod
labels:
name: result-app-pod
app: demo-voting-app
spec:
containers:
- name: result-app
image: examplevotingapp_result:v1
ports:
- containerPort: 80

> redis-pod.yaml

apiVersion: v1
kind: Pod
metada:
name: redis-pod
labels:
name: redis-pod
app: demo-voting-app
spec:
containers:
- name: redis
image: redis
ports:
- containerPort: 6379

> postgres-pod.yaml

apiVersion: v1
kind: Pod
metada:
name: postgres-pod
labels:
name: postgres-pod
app: demo-voting-app
spec:
containers:
- name: postgres
image: postgres
ports:
- containerPort: 5432
env:
- name: POSTGRES_USER
value: "postgres"
- name: POSTGRES_PASSWORD
value: "postgres"

> worker-app-pod.yaml

apiVersion: v1
kind: Pod
metada:
name: worker-app-pod
labels:
name: worker-app-pod
app: demo-voting-app
spec:
containers:
- name: worker-app
image: examplevotingapp_worker:v1

Now you have the pods created you need to make them accessible and connected, for that you use services:

> redis-service.yaml

apiVersion: v1
kind: Service
metada:
name: redis
labels:
name: redis-service
app: demo-voting-app
spec:
ports:
- port: 6379
targetPort: 6379
selector:
name: redis-pod
app: demo-voting-app

> postgres-service.yaml

apiVersion: v1
kind: Service
metada:
name: db
labels:
name: postgres-service
app: demo-voting-app
spec:
ports:
- port: 5432
targetPort: 5432
selector:
name: postgres-pod
app: demo-voting-app

> voting-app-service.yaml

apiVersion: v1
kind: Service
metada:
name: db
labels:
name: voting-app-pod
app: demo-voting-app
spec:
typePort: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 30004
selector:
name: voting-app-pod
app: demo-voting-app

> result-app-service.yaml

apiVersion: v1
kind: Service
metada:
name: result-service
labels:
name: result-service
app: demo-voting-app
spec:
typePort: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 30005
selector:
name: result-app-pod
app: demo-voting-app

Terminal commands to run in order to have it operational:

  • Verify running pods or services
kubectl get pods
kubectl get svc
  • Create pods and services – Voting App
kubectl create -f voting-app-pods.yaml
kubectl create -f voting-app-service.yaml
  • Check they are running properly
kubectl get pod, svc
  • Check browser on link (ip:30004)
  • Create pods and services – Redis
kubectl create -f redis-pod.yaml
kubectl create -f redis-service.yaml
  • Create pods and services – Postgres
kubectl create -f postgres-pod.yaml
kubectl create -f postgres-service.yaml
  • Check all pods and services running
kubectl get pods
kubectl get svc
  • Create Pod – Worker
kubectl create -f worker-app-pod.yaml
  • Check all pods running properly
kubectl get pods
  • Create Pods and Services – Result App
kubectl create -f result-app-pod.yaml
kubectl create -f result-app-service.yaml

Now this brings the following result:

Deployment

But in case a Pod stops working there’s no replicaSet defined to replace the missed pod(s). Thus you need to implement the Deployments that ensure the proper creation of Pods and respective Replicas.

In real world we would just run the Deployments in which we provide all information about the pods, but to ensure a proper operation we should go to each entity and ensure it’s all properly configured, os it gets easier to join everything in the Deployments.

> voting-app-deploy.yaml

apiVersion: V1
kind: Deployment
metada:
name: voting-app-deploy
labels:
name: voting-app-deploy
app: demo-voting-app
spec:
replicas: 1
selector:
matchLabels:
name: voting-app-pods
app: demo-voting-app
template:
metada:
name: voting-app-pod
labels:
name: voting-app-pod
app: demo-voting-app
spec:
containers:
- name: voting-app
image: examplevotingapp_vote:v1
ports:
- containerPort: 80

> redis-deploy.yaml

apiVersion: V1
kind: Deployment
metada:
name: redis-deploy
labels:
name: redis-deploy
app: demo-voting-app
spec:
replicas: 1
selector:
matchLabels:
name: redis-deploy
app: demo-voting-app
template:
metada:
name: redis-pod
labels:
name: redis-pod
app: demo-voting-app
spec:
containers:
- name: redis
image: redis
ports:
- containerPort: 6379

> postgres-app-deploy.yaml

apiVersion: V1
kind: Deployment
metada:
         name: postgres-deploy
         labels:
                  name: postgres-deploy
                  app: demo-voting-app
         spec:
                  replicas: 1
                  selector:
                            matchLabels:
                                      name: postgres-deploy
                                      app: demo-voting-app
                  template:
                            metadata:
                                     name: postgres-pod
                                     labels:
                                              name: postgres-pod
                                              app: demo-voting-app
                                     spec:
                                             containers:
                                                    - name: postgres
                                                      image: postgres
                                                      ports:
                                                              - containerPort: 5432
                                                      env:
                                                              - name: POSTGRES_USER
                                                                value: "postgres"
                                                              - name: POSTGRES_PASSWORD
                                                                value: "postgres"

Here we have mostly all, some points to be aware:

  • Verify the spacing it’s crucial to avoid errors
  • Use environmental variables, here is not seen in depth but you should protect your credentials

In terms of running the commands to launch the system you can use the following order:

  • run the deploy, and then service – of voting app
  • run the deploy, and then service – of redis
  • run the deploy, and then service – of postgres
  • run the deploy, and then service – of result app
  • run the deploy, and then service – of worker
svgKubernetes Services
svg
svgAnsible (Inventory, Playbook & Modules)

Leave a reply