Service Monorepo! is designed to manage multiple Laravel-based microservices, providing a foundation for scalable, modular application development. It leverages Docker for deployment, with the potential for Kubernetes orchestration in the future. Services in this monorepo communicate via gRPC for efficient inter-service communication, while retaining the ability to expose traditional REST APIs.
This monorepo serves as the central hub for managing all microservices and shared resources. It provides tools to generate, manage, and deploy services efficiently.
Here is the primary structure of the monorepo:
monorepo/
├── app/
│ └── Console/
│ └── Commands/
│ ├── GenerateService.php # Command to generate new services
│ ├── DeployService.php # Command to deploy services via Docker
├── shared/
│ └── proto/
│ ├── HelloService.proto # Shared gRPC definitions
│ └── (Other .proto files)
├── services/
│ └── (Generated Laravel services live here)
├── templates/
│ ├── Dockerfile.tpl # Dockerfile template for services
│ ├── grpc_server.php.tpl # gRPC server template
│ ├── deployment.yaml.tpl # Kubernetes deployment template (future use)
│ ├── service.yaml.tpl # Kubernetes service template (future use)
├── artisan # Root Artisan command for managing the monorepo
├── composer.json # Dependencies for the monorepo
└── README.md # This documentation
- app/: Contains custom Artisan commands to manage the monorepo.
- shared/proto/: Central repository for
.protofiles defining gRPC services and shared types. - services/: Directory where all generated microservices (Laravel applications) are stored.
- templates/: Templates used during service generation for Docker, gRPC, and Kubernetes.
At the root of the monorepo, a custom Artisan CLI tool is provided to manage the repository. This tool abstracts common tasks like generating and deploying services.
-
Generate a Service:
php artisan service:generate {ServiceName}- Creates a new Laravel-based service.
- Configures gRPC support, Dockerfile, and symlinks to shared
.protofiles.
-
Deploy a Service:
php artisan deploy:service {ServiceName}- Builds the Docker image for the service.
- Pushes the image to your Docker repository.
- Starts the service as a Docker container.
To create a new service, run the following command:
php artisan service:generate ExampleService
What Happens:
- A new Laravel application is created in
services/ExampleService. - gRPC dependencies are installed, and a gRPC server script is added.
- A Dockerfile is generated to containerize the service.
- A symlink to
shared/proto/is created for accessing shared.protofiles.
Each generated service is a fully functional Laravel application with additional gRPC support.
services/ExampleService/
├── app/
│ ├── Grpc/
│ │ └── HelloServiceImplementation.php # gRPC service implementation
│ └── Http/
├── bootstrap/
├── config/
├── grpc_server.php # gRPC server script
├── proto/ -> ../../shared/proto/ # Symlink to shared proto files
├── Dockerfile # Docker configuration
├── vendor/
└── composer.json
- grpc_server.php: Starts the gRPC server for the service.
- proto/: Symlink to shared
.protodefinitions for consistency. - Dockerfile: Configures the service for deployment as a Docker container.
gRPC is a high-performance RPC (Remote Procedure Call) framework that enables efficient communication between services. It uses Protocol Buffers (protobuf) to define service interfaces and data structures, ensuring type safety and performance.
-
Defining Services:
- Shared
.protofiles inshared/proto/define the contract for gRPC services. - Example:
HelloService.protodefines aSayHellomethod.
- Shared
-
Implementing Services:
-
Each service implements the gRPC methods in
app/Grpc/. -
Example:
namespace App\Grpc; use Hello\HelloReply; use Hello\HelloRequest; use Hello\HelloServiceInterface; use Grpc\ServerContext; class HelloServiceImplementation implements HelloServiceInterface { public function SayHello(ServerContext $context, HelloRequest $request): HelloReply { $message = "Hello, " . $request->getName() . "!"; $reply = new HelloReply(); $reply->setMessage($message); return $reply; } }
-
-
Exposing gRPC Servers:
- Each service runs its own gRPC server on a specified port (e.g.,
50051). - Example:
grpc_server.phpstarts the server and binds it to the service implementation.
- Each service runs its own gRPC server on a specified port (e.g.,
-
Calling Other Services:
-
gRPC clients can invoke methods on other services using generated client classes.
-
Example:
use Hello\HelloServiceClient; use Hello\HelloRequest; use Grpc\ChannelCredentials; $client = new HelloServiceClient('TestService:50051', [ 'credentials' => ChannelCredentials::createInsecure(), ]); $request = new HelloRequest(); $request->setName('Test User'); list($response, $status) = $client->SayHello($request)->wait(); echo $response->getMessage(); // Outputs: "Hello, Test User!"
-
Protocol Buffers (protobuf) are used to define gRPC services and the types they use. These files are shared across all services to ensure consistency.
Example: shared/proto/HelloService.proto
syntax = "proto3";
package hello;
service HelloService {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
- Service: Defines the available RPC methods (e.g.,
SayHello). - Messages: Define the structure of request and response data.
- Centralized Storage:
- All
.protofiles are stored inshared/proto/.
- All
- Shared Across Services:
- Each service accesses the shared
.protofiles via a symlink inproto/.
- Each service accesses the shared
- Generating PHP Classes:
-
Run the following command to regenerate PHP classes after updating
.protofiles:php artisan proto:generate {ServiceName} -
This ensures that all services are using the latest definitions.
-
While gRPC is used for inter-service communication, each service can also expose traditional REST APIs using Laravel's routing system. This allows you to:
- Use gRPC for internal communication between microservices.
- Use REST APIs to interact with external clients.
-
Exposing a REST API:
-
Define routes and controllers as usual in Laravel.
-
Example:
routes/api.phpuse Illuminate\Support\Facades\Route; Route::get('/greet', function () { return ['message' => 'Hello from REST API!']; });
-
-
gRPC for Internal Communication:
- Use gRPC to communicate between
ServiceAandServiceB.
- Use gRPC to communicate between
This hybrid approach allows flexibility, catering to different use cases while maintaining efficient communication internally.
For now, deployment is handled using Docker, with Kubernetes support planned for future versions.
To deploy a service, run:
php artisan deploy:service {ServiceName}
What Happens:
- The Docker image is built from the service's
Dockerfile. - The image is pushed to the configured Docker repository.
- A Docker container is started, running the gRPC server.
Notes:
- Ensure Docker is installed and running.
- Update the
your-docker-repoplaceholder inDockerfile.tplwith your actual Docker repository URL.
