Skip to main content

Command Palette

Search for a command to run...

Microservice

Published
•4 min read•View as Markdown
Microservice

I was tasked with leading a project at work that involved a hefty system design, logic flow, and breaking down of tasks. I picked a team of 10 and subdivided them into teams based on respective services giving them a level of flexibility between choosing languages that better suit the scope of work and their skillset. of course, I wouldn't be able to dive into the intricacies, but here is how I was able to simulate each microservice, saving time and money.

Project Structure

project /
|-- go-service /
|   |-- main.go
|   |-- Dockerfile
|-- node-service /
|   |-- index.js
|   |-- Dockerfile
|-- docker-compose.yml

1. Define Your Microservices:

  • Functionality: Decide on the functionalities of each microservice. For example, one could handle user authentication, and another could manage product data.

  • Programming Language: Choose Go and Node.js for your example.

  • Database: Specify Postgres as the database for both.

2. Development:

a) Go Microservice:

  1. Start with a Go project template for gRPC.

  2. Implement your desired functionalities with gRPC endpoints for communication.

  3. Connect to the Postgres database using a Go driver like lib/pq.

  4. Build your Go binary using go build.

package main

import (
    "log"
    "net"

    "google.golang.org/grpc"
    "github.com/your_username/your_project/pb"
)

type server struct{}

func (s *server) SayHello(req *pb.HelloRequest, stream pb.Greeter_SayHelloServer) error {
    log.Printf("Received: %v", req.Name)
    resp := &pb.HelloResponse{Message: "Hello, " + req.Name}
    return stream.Send(resp)
}

func main() {
    listener, err := net.Listen("tcp", ":50051")
    if err != nil {
        log.Fatalf("Failed to listen: %v", err)
    }

    srv := grpc.NewServer()
    pb.RegisterGreeterServer(srv, &server{})

    log.Println("Server is listening on :50051")
    if err := srv.Serve(listener); err != nil {
        log.Fatalf("Failed to serve: %v", err)
    }
}

b) Node.js Microservice:

  1. Use a Node.js framework like grpc or micro for gRPC development.

  2. Implement your functionalities with gRPC endpoints.

  3. Connect to the Postgres database using a Node.js driver like pg.

  4. Build your Node.js application using npm run build or similar.

const grpc = require('grpc');
const protoLoader = require('@grpc/proto-loader');
const packageDefinition = protoLoader.loadSync('your_proto_file.proto', { keepCase: true, longs: String, enums: String, defaults: true, oneofs: true });
const hello_proto = grpc.loadPackageDefinition(packageDefinition).hello;

const server = new grpc.Server();

server.addService(hello_proto.Greeter.service, {
  sayHello: (call, callback) => {
    console.log(`Received: ${call.request.name}`);
    const message = `Hello, ${call.request.name}`;
    callback(null, { message });
  },
});

server.bind('0.0.0.0:50052', grpc.ServerCredentials.createInsecure());
console.log('Server running at http://127.0.0.1:50052');
server.start();

c) Shared gRPC Protocol:

  1. Define a shared gRPC protocol file (e.g., .proto) specifying messages and services used for communication.

  2. Generate Go and Node.js code from the protocol using tools like protoc-gen-go and @grpc/grpc-js.

d) Postgres Database:

  1. Define your database schema within your chosen microservice projects.

  2. Use tools like psql or a database management GUI to create and initialize your database on your development machine.

3. Dockerize Microservices and Database:

a) Dockerfiles:

  1. Create separate Dockerfiles for each microservice, specifying their respective build steps, runtime environments, and dependencies.

  2. Create a Dockerfile for the Postgres database, including initialization scripts and environment variables for connection details.

b) Docker Compose:

  1. Define a docker-compose.yml file to orchestrate multiple services and build them together.

  2. Include configurations for ports, environment variables, volumes (for persistent data), and networks for internal communication.

c) Running Locally:

  1. Use docker-compose up to build and run all services simultaneously.

  2. Test your gRPC communication between microservices using client tools like grpcurl.

4. Deploy to AWS ECR:

a) AWS Account and ECR Setup:

  1. Create an AWS account and set up Elastic Container Registry (ECR).

  2. Create separate repositories in ECR for each microservice and the database image.

b) Docker Push:

  1. Use docker login to authenticate with your ECR repository.

  2. Use docker push to push each built image to its corresponding ECR repository.

c) Docker Compose with AWS ECS:

  1. Update your docker-compose.yml to use AWS ECS as the deployment platform.

  2. Define tasks and services for each microservice and database, referencing the pushed ECR images.

  3. Use tools like aws-compose or ecs-cli to deploy your infrastructure and services to ECS.

d) Accessing Deployed Services:

  1. Once deployed, access your microservices through their exposed ports on the ECS instances.

  2. Use client tools like grpcurl with the updated server addresses to test communication.

Additional Notes:

  • Consider security best practices like IAM roles and secrets management for access control and sensitive information.

  • Utilize monitoring and logging solutions to track the health and performance of your deployed services.

  • This guide provides a basic overview. Each step may involve additional configurations and considerations depending on your specific needs and chosen tools.