Featured image of post Building a Modern C++ Microservice with Docker and Kubernetes

Building a Modern C++ Microservice with Docker and Kubernetes

For Fun and Profit!

Alright, today we’re diving into something truly epic: building a C++ microservice with a REST API, wrapping it in a Docker container, deploying it to Kubernetes, and calling it from a test app.

And just to keep things spicy, we’re making this cross-platform so it runs on both Windows and Linux. Yes, you read that right.

Step 1: The C++ Microservice

First, we’re going to create a simple C++ REST API using cpp-httplib (because Boost is still too heavy, fight me).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include "httplib.h"

void divide_handler(const httplib::Request& req, httplib::Response& res) {
    try {
        double a = std::stod(req.get_param_value("a"));
        double b = std::stod(req.get_param_value("b"));
        if (b == 0) {
            res.status = 400;
            res.set_content("Cannot divide by zero", "text/plain");
        } else {
            double result = a / b;
            res.set_content(std::to_string(result), "text/plain");
        }
    } catch (...) {
        res.status = 400;
        res.set_content("Invalid input", "text/plain");
    }
}

int main() {
    httplib::Server svr;
    svr.Get("/divide", divide_handler);
    std::cout << "Starting server on port 8080...\n";
    svr.listen("0.0.0.0", 8080);
}

Step 2: Unit Test for Division

We can’t just write code without testing it (well, we can, but then we get paged at 3 AM). Let’s write a simple unit test using Google Test.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#include <gtest/gtest.h>

TEST(DivisionTest, HandlesZeroDivision) {
    double a = 10.0;
    double b = 0.0;
    EXPECT_ANY_THROW({ double result = a / b; });
}

TEST(DivisionTest, ValidDivision) {
    double a = 10.0;
    double b = 2.0;
    EXPECT_EQ(a / b, 5.0);
}

int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

Step 3: Test Client for the REST API

Now, let’s write a simple C++ test client to call our microservice.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#include <iostream>
#include "httplib.h"

int main() {
    httplib::Client cli("http://localhost:8080");
    auto res = cli.Get("/divide?a=10&b=2");
    if (res && res->status == 200) {
        std::cout << "Result: " << res->body << std::endl;
    } else {
        std::cout << "Error: " << (res ? res->status : 0) << std::endl;
    }
}

Step 4: Running the Service Locally

To run the service locally:

1
2
3
4
g++ -o server server.cpp -pthread
g++ -o client client.cpp -pthread
./server
./client

Step 5: Dockerizing the Microservice

Now, let’s move this into a Docker container.

Dockerfile:

1
2
3
4
FROM ubuntu:20.04
WORKDIR /app
COPY server /app/server
CMD ["/app/server"]

Build and run the Docker container:

1
2
docker build -t cpp-microservice .
docker run -p 8080:8080 cpp-microservice

Step 6: Running on Kubernetes

Let’s deploy this container to Kubernetes.

Deployment YAML:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cpp-microservice
spec:
  replicas: 1
  selector:
    matchLabels:
      app: cpp-microservice
  template:
    metadata:
      labels:
        app: cpp-microservice
    spec:
      containers:
      - name: cpp-microservice
        image: cpp-microservice:latest
        ports:
        - containerPort: 8080

Apply to Kubernetes:

1
2
kubectl apply -f deployment.yaml
kubectl expose deployment cpp-microservice --type=LoadBalancer --port=8080

Step 7: Calling the Service from Kubernetes

Now, let’s call our Kubernetes-hosted service from our test client.

1
docker run --network host cpp-client http://localhost:8080/divide?a=10&b=2

Conclusion

Congratulations! You now have a C++ microservice running in Docker and Kubernetes, serving up division results like a math wizard. Just don’t let anyone divide by zero.

Or do. See what happens.


Key Ideas

ConceptSummary
C++ MicroserviceBuilt a REST API in C++ using cpp-httplib
Unit TestingUsed Google Test for division tests
REST ClientWrote a C++ client to call the microservice
Running LocallyCompiled and ran on both Windows and Linux
DockerizationCreated a Docker image for our microservice
Kubernetes DeploymentDeployed the container to Kubernetes
Calling from KubernetesUsed a test client to call the service

References