Introduction
If you ever wanted to run your local Kubernetes, build and configure the Rust web microservices and see how it all works together, this 10 minutes guide is for you.
Install minikube
First, install minikube on your machine:
brew install minikube
Install registry addon
Initialize the minikube images registry:
minikube addons enable registry
docker run --rm -it --network=host alpine ash -c "apk add socat && socat TCP-LISTEN:5000,reuseaddr,fork TCP:$(minikube ip):5000”
Start minikube
Start minikube and check its status:
minikube start
minikube status
Next, make yourself aware of Kubernetes contexts on your machine, maybe you are already working within your company Kubernetes context:
kubectl config get-contexts
Make sure you use the newly created minikube context:
kubectl config use-context minikube
Build and push your Rust application images
Now you are ready to build and deploy your Rust web services.
Service A
Let’s create our first service, run the following commands:
cargo new service_a
cd service_a
Add the actix_web and reqwest dependencies:
cargo add actix_web reqwest
Your final Cargo.toml should look like this:
[package]
name = "service_a"
version = "0.1.0"
edition = "2021"
[dependencies]
actix-web = "4.8.0"
reqwest = "0.12.5"
In your src/main.rs put the following code:
use actix_web::{get, App, HttpServer, Responder};
use reqwest::Client;
#[get("/")]
async fn index() -> impl Responder {
"Hello from Service A"
}
#[get("/call-service-b")]
async fn call_service_b() -> impl Responder {
let client = Client::new();
match client.get("http://service-b").send().await {
Ok(response) => response.text().await.unwrap_or_else(|_| "Failed to get response".to_string()),
Err(_) => "Failed to call service-b".to_string(),
}
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.service(index)
.service(call_service_b)
})
.bind("0.0.0.0:8080")?
.run()
.await
}
Create Dockerfile in the root folder and add the following content to it:
# Builder stage
FROM rust:1.72 as builder
WORKDIR /app
COPY . .
RUN cargo build --release
# Runtime stage
FROM debian:bookworm-slim
WORKDIR /app
COPY --from=builder /app/target/release/service_a service_a
ENTRYPOINT ["./service_a"]
Service B
Now create your second service, run the following commands:
cargo new service_b
cd service_b
Add the actix_web dependency:
cargo add actix_web
Your final Cargo.toml should look like this:
[package]
name = "service_b"
version = "0.1.0"
edition = "2021"
[dependencies]
actix-web = "4.8.0"
In your src/main.rs put the following code:
use actix_web::{get, App, HttpServer, Responder};
#[get("/")]
async fn index() -> impl Responder {
"Hello from Service B"
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().service(index))
.bind("0.0.0.0:8080")?
.run()
.await
}
Create Dockerfile in the root folder and add the following content to it (the same as for our service A):
# Builder stage
FROM rust:1.72 as builder
WORKDIR /app
COPY . .
RUN cargo build --release
# Runtime stage
FROM debian:bookworm-slim
WORKDIR /app
COPY --from=builder /app/target/release/service_b service_b
ENTRYPOINT ["./service_b"]
Build, tag and push images
Now we are ready to build, tag and push images to the minikube images repository:
cd service_a
docker build -t localhost:5000/service-a:latest -f Dockerfile .
docker push localhost:5000/service-a:latest
cd ../service_b
docker build -t localhost:5000/service-b:latest -f Dockerfile .
docker push localhost:5000/service-b:latest
Apply Kubernetes configurations
Now, we are ready to finally deploy the images on minikube cluster.
Create a separate folder k8s.
Inside create a file service-a-deployment.yaml with the content:
apiVersion: apps/v1
kind: Deployment
metadata:
name: service-a
spec:
replicas: 3
selector:
matchLabels:
app: service-a
template:
metadata:
labels:
app: service-a
spec:
containers:
- name: service-a
image: localhost:5000/service-a:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
Next, create a file service-a-service.yaml:
apiVersion: v1
kind: Service
metadata:
name: service-a
spec:
selector:
app: service-a
ports:
- protocol: TCP
port: 80
targetPort: 8080
Now, the same for the service B. Inside the same folder k8s create a file service-b-deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: service-b
spec:
replicas: 3
selector:
matchLabels:
app: service-b
template:
metadata:
labels:
app: service-b
spec:
containers:
- name: service-b
image: localhost:5000/service-b:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
And a file service-b-service.yaml:
apiVersion: v1
kind: Service
metadata:
name: service-b
spec:
selector:
app: service-b
ports:
- protocol: TCP
port: 80
targetPort: 8080
Now, apply all the deployment and service Kubernetes configurations:
kubectl apply -f ./service-a-deployment.yaml
kubectl apply -f ./service-a-service.yaml
kubectl apply -f ./service-b-deployment.yaml
kubectl apply -f ./service-b-service.yaml
Check the status of your pods:
kubectl get pods
All of them should be running without any errors. You should see the status “Running” for each of them. Example output you might see:
NAME READY STATUS RESTARTS AGE
service-a-85d9755db-h5c8q 1/1 Running 0 42h
service-a-85d9755db-lvf9k 1/1 Running 0 42h
service-a-85d9755db-t5w2m 1/1 Running 0 42h
service-b-667f9dc5d7-5t6tw 1/1 Running 0 42h
service-b-667f9dc5d7-fl799 1/1 Running 0 42h
service-b-667f9dc5d7-pglcd 1/1 Running 0 42h
Making changes
When you have any new code changes, rebuild the image, publish it and restart the Kubernetes. For example, if you made any changes to the Service A:
docker build -t localhost:5000/service-a:latest -f Dockerfile .
docker push localhost:5000/service-a:latest
kubectl rollout restart deployment/service-a
Now you can see the list of services running in minikube:
minikube service list
And finally open our service A via this command:
minikube service service-a
You will be redirected to a browser page. You should see a response from service A. And following the URL /call-service-b you will see that the Service A can successfully access the Service B.
You can also see a beautiful dashboard by running this command:
minikube dashboard
You should see a nice dashboard similar to the one below

Final
Following this short guide you are now able to deploy your Rust microservices locally. In the next article we will cover a production ready solution. We will deploy a Kubernetes cluster on a Ubuntu VPS, using the kubeadm tool. Also we will add TLS and automated certificates renewal to secure our services. Also, we will add more functionality to our Rust microservices to cover more use cases. Stay tuned and see you next time.