๐ Dapr Distributed Application Runtime Setup on AlmaLinux 9: Complete Microservices Platform Guide
Welcome to the future of distributed applications! ๐ Today weโre going to learn how to set up Dapr on AlmaLinux 9, the amazing Cloud Native Computing Foundation (CNCF) graduated project that makes building microservices as easy as building monoliths. Think of Dapr as your microservices superpower that handles all the complex distributed computing patterns for you! ๐ชโจ
๐ค Why is Dapr Important?
Building distributed applications is notoriously difficult, with developers spending more time on infrastructure concerns than business logic. Hereโs why Dapr is revolutionary for modern applications:
- ๐ ๏ธ Building Blocks - Pre-built APIs for service invocation, pub/sub, state management, and secrets
- ๐ Platform Agnostic - Works on any cloud, edge, or on-premises environment
- ๐ฏ Language Neutral - Use any programming language with simple HTTP or gRPC APIs
- ๐ง Plug & Play - Swap components without changing application code
- ๐ก๏ธ Production Ready - Battle-tested by Microsoft, Alibaba, and thousands of companies
- ๐ Observable - Built-in metrics, tracing, and logging for distributed systems
๐ฏ What You Need
Before we start our Dapr adventure, letโs make sure you have everything ready:
โ
AlmaLinux 9 system (fresh installation recommended)
โ
Root or sudo access for installing packages
โ
At least 4GB RAM (8GB recommended for multiple services)
โ
10GB free disk space for Docker and Dapr components
โ
Internet connection for downloading packages and container images
โ
Basic terminal knowledge (donโt worry, weโll explain everything!)
โ
Docker or Podman (weโll install Docker if needed)
โ
Programming experience (any language works - weโll use Python and Node.js for examples)
๐ Step 1: Update Your AlmaLinux System
Letโs start by making sure your system is up to date! ๐
# Update all packages to latest versions
sudo dnf update -y
# Install essential development tools
sudo dnf groupinstall "Development Tools" -y
# Install helpful utilities we'll need
sudo dnf install -y curl wget git vim htop jq python3 python3-pip nodejs npm
Perfect! Your system is now ready for Dapr installation! โจ
๐ง Step 2: Install Docker and Docker Compose
Dapr works great with containers, so letโs set up Docker:
# Install Docker from official repository
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# Install Docker Engine
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Start and enable Docker service
sudo systemctl start docker
sudo systemctl enable docker
# Add your user to docker group (no more sudo needed!)
sudo usermod -aG docker $USER
# Apply group changes (or logout/login)
newgrp docker
# Test Docker installation
docker --version
docker compose version
Great! Docker is ready for Dapr! ๐ณ
๐ Step 3: Install Dapr CLI
Letโs install the Dapr command-line interface:
# Download and install Dapr CLI using the official installer
wget -q https://raw.githubusercontent.com/dapr/cli/master/install/install.sh -O - | /bin/bash
# Add Dapr CLI to your PATH
echo 'export PATH=$PATH:$HOME/.dapr/bin' >> ~/.bashrc
source ~/.bashrc
# Verify Dapr CLI installation
dapr --version
# You should see output like: CLI version: 1.12.0, Runtime version: n/a
Awesome! Dapr CLI is installed! ๐ฏ
โ Step 4: Initialize Dapr Runtime
Letโs initialize Dapr in self-hosted mode (perfect for development and testing):
# Initialize Dapr runtime with default components
dapr init
# This will:
# - Download Dapr runtime binary
# - Install default components (Redis for state store and pub/sub)
# - Set up Zipkin for observability
# - Configure placement service for actors
# Verify Dapr installation
dapr --version
# Check Dapr containers are running
docker ps
# You should see containers for:
# - dapr_redis (state store and pub/sub)
# - dapr_zipkin (tracing)
# - dapr_placement (actor placement)
Amazing! Dapr runtime is now running on your system! ๐
๐ง Step 5: Create Your First Dapr Application
Letโs build a simple microservice to see Dapr in action:
# Create directory for your first Dapr app
mkdir -p ~/dapr-projects/hello-world
cd ~/dapr-projects/hello-world
# Create a simple Python web service
cat > app.py << 'EOF'
from flask import Flask, request, jsonify
import os
import requests
import json
app = Flask(__name__)
# Dapr port for the app
dapr_port = os.getenv("DAPR_HTTP_PORT", 3500)
dapr_url = f"http://localhost:{dapr_port}"
@app.route('/hello', methods=['POST'])
def hello():
"""Handle incoming service invocation"""
data = request.get_json()
response = {
'message': f'Hello {data.get("name", "World")}!',
'service': 'hello-service',
'timestamp': '2025-09-06T12:00:00Z'
}
# Save state using Dapr state store
try:
state_data = {
'key': 'last-greeting',
'value': response
}
requests.post(
f"{dapr_url}/v1.0/state/statestore",
json=[state_data]
)
print(f"โ
State saved: {response}")
except Exception as e:
print(f"โ Error saving state: {e}")
return jsonify(response)
@app.route('/greetings', methods=['GET'])
def get_greetings():
"""Get last greeting from state store"""
try:
response = requests.get(f"{dapr_url}/v1.0/state/statestore/last-greeting")
if response.status_code == 200 and response.text:
return jsonify(response.json())
else:
return jsonify({'message': 'No greetings found'})
except Exception as e:
return jsonify({'error': f'Error retrieving state: {e}'}), 500
@app.route('/health', methods=['GET'])
def health():
"""Health check endpoint"""
return jsonify({'status': 'healthy', 'service': 'hello-service'})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
EOF
# Create requirements.txt
cat > requirements.txt << 'EOF'
Flask==2.3.3
requests==2.31.0
EOF
# Install Python dependencies
pip3 install -r requirements.txt
# Start the service with Dapr
dapr run --app-id hello-service --app-port 5000 --dapr-http-port 3500 python3 app.py &
# Wait for service to start
sleep 5
# Test the service using Dapr service invocation
curl -X POST http://localhost:3500/v1.0/invoke/hello-service/method/hello \
-H "Content-Type: application/json" \
-d '{"name": "Dapr Developer"}'
# Get saved state
curl http://localhost:3500/v1.0/invoke/hello-service/method/greetings
Congratulations! Youโve built your first Dapr-enabled microservice! ๐
๐ Step 6: Build Multi-Service Application
Letโs create a more complex example with multiple services communicating through Dapr:
# Create a new project for multi-service app
mkdir -p ~/dapr-projects/order-system
cd ~/dapr-projects/order-system
# Create Order Service
mkdir order-service
cat > order-service/app.py << 'EOF'
from flask import Flask, request, jsonify
import requests
import json
import os
from datetime import datetime
app = Flask(__name__)
dapr_port = os.getenv("DAPR_HTTP_PORT", 3501)
dapr_url = f"http://localhost:{dapr_port}"
@app.route('/orders', methods=['POST'])
def create_order():
"""Create a new order"""
try:
order_data = request.get_json()
order_id = f"order-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
order = {
'id': order_id,
'customer': order_data.get('customer'),
'items': order_data.get('items', []),
'status': 'pending',
'created_at': datetime.now().isoformat()
}
# Save order to state store
state_data = {'key': order_id, 'value': order}
requests.post(f"{dapr_url}/v1.0/state/statestore", json=[state_data])
# Publish order created event
event_data = {
'specversion': '1.0',
'type': 'order.created',
'source': 'order-service',
'id': order_id,
'data': order
}
requests.post(
f"{dapr_url}/v1.0/publish/pubsub/order-events",
json=event_data
)
print(f"โ
Order created: {order_id}")
return jsonify(order), 201
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/orders/<order_id>', methods=['GET'])
def get_order(order_id):
"""Get order by ID"""
try:
response = requests.get(f"{dapr_url}/v1.0/state/statestore/{order_id}")
if response.status_code == 200 and response.text:
return jsonify(response.json())
else:
return jsonify({'error': 'Order not found'}), 404
except Exception as e:
return jsonify({'error': str(e)}), 500
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5001, debug=True)
EOF
# Create Inventory Service
mkdir inventory-service
cat > inventory-service/app.js << 'EOF'
const express = require('express');
const axios = require('axios');
const app = express();
app.use(express.json());
const daprPort = process.env.DAPR_HTTP_PORT || 3502;
const daprUrl = `http://localhost:${daprPort}`;
// Sample inventory data
let inventory = {
'laptop': { stock: 10, price: 999.99 },
'mouse': { stock: 50, price: 29.99 },
'keyboard': { stock: 25, price: 79.99 }
};
// Dapr subscription configuration
app.get('/dapr/subscribe', (req, res) => {
res.json([
{
pubsubname: 'pubsub',
topic: 'order-events',
route: '/handle-order'
}
]);
});
// Handle order events
app.post('/handle-order', async (req, res) => {
try {
console.log('๐ฆ Received order event:', req.body);
const orderData = req.body.data;
const items = orderData.items;
// Check inventory for each item
let allAvailable = true;
for (const item of items) {
if (!inventory[item.product] || inventory[item.product].stock < item.quantity) {
allAvailable = false;
break;
}
}
// Update order status
const orderUpdateUrl = `${daprUrl}/v1.0/invoke/order-service/method/orders/${orderData.id}/status`;
const newStatus = allAvailable ? 'confirmed' : 'rejected';
// In a real app, you'd call the order service to update status
console.log(`โ
Order ${orderData.id} ${newStatus}`);
res.status(200).send('OK');
} catch (error) {
console.error('โ Error processing order:', error);
res.status(500).send('Error processing order');
}
});
app.get('/inventory', (req, res) => {
res.json(inventory);
});
app.get('/inventory/:product', (req, res) => {
const product = req.params.product;
if (inventory[product]) {
res.json(inventory[product]);
} else {
res.status(404).json({ error: 'Product not found' });
}
});
const port = 5002;
app.listen(port, () => {
console.log(`๐ช Inventory service listening on port ${port}`);
});
EOF
# Create package.json for inventory service
cat > inventory-service/package.json << 'EOF'
{
"name": "inventory-service",
"version": "1.0.0",
"description": "Inventory management service",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "^4.18.2",
"axios": "^1.5.0"
}
}
EOF
# Install Node.js dependencies
cd inventory-service && npm install && cd ..
# Create Dapr component configuration
mkdir components
cat > components/pubsub.yaml << 'EOF'
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: pubsub
spec:
type: pubsub.redis
version: v1
metadata:
- name: redisHost
value: localhost:6379
- name: redisPassword
value: ""
EOF
# Start both services with Dapr
echo "๐ Starting Order Service..."
dapr run --app-id order-service --app-port 5001 --dapr-http-port 3501 --components-path ./components python3 order-service/app.py &
sleep 3
echo "๐ Starting Inventory Service..."
cd inventory-service
dapr run --app-id inventory-service --app-port 5002 --dapr-http-port 3502 --components-path ../components npm start &
cd ..
sleep 5
# Test the multi-service application
echo "๐ Creating a test order..."
curl -X POST http://localhost:3501/v1.0/invoke/order-service/method/orders \
-H "Content-Type: application/json" \
-d '{
"customer": "John Doe",
"items": [
{"product": "laptop", "quantity": 1},
{"product": "mouse", "quantity": 2}
]
}'
echo -e "\n\n๐ฆ Checking inventory..."
curl http://localhost:3502/v1.0/invoke/inventory-service/method/inventory
Incredible! You now have multiple services communicating through Dapr! ๐
๐ฎ Quick Examples
Letโs explore more Dapr capabilities with practical examples! ๐
Example 1: Secrets Management
# Create secrets component
cat > components/secrets.yaml << 'EOF'
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: local-secrets
spec:
type: secretstores.local.file
version: v1
metadata:
- name: secretsFile
value: ./secrets.json
- name: nestedSeparator
value: ":"
EOF
# Create secrets file
cat > secrets.json << 'EOF'
{
"database": {
"connectionString": "postgres://user:pass@localhost:5432/mydb"
},
"api": {
"key": "super-secret-api-key-12345"
}
}
EOF
# Create service that uses secrets
cat > secrets-demo.py << 'EOF'
import requests
import json
dapr_url = "http://localhost:3500"
def get_secret(store_name, key):
"""Get secret from Dapr secret store"""
try:
response = requests.get(f"{dapr_url}/v1.0/secrets/{store_name}/{key}")
if response.status_code == 200:
return response.json()
else:
print(f"โ Error getting secret: {response.status_code}")
return None
except Exception as e:
print(f"โ Error: {e}")
return None
# Test secrets retrieval
print("๐ Getting database secret...")
db_secret = get_secret("local-secrets", "database")
print(f"Database connection: {db_secret}")
print("๐ Getting API secret...")
api_secret = get_secret("local-secrets", "api")
print(f"API key: {api_secret}")
EOF
# Run with Dapr
dapr run --app-id secrets-demo --components-path ./components python3 secrets-demo.py
Now you can securely manage secrets with Dapr! ๐
Example 2: Actor Pattern
# Create actor demo
cat > actor-demo.py << 'EOF'
from flask import Flask, request, jsonify
import requests
import json
app = Flask(__name__)
dapr_url = "http://localhost:3500"
# Counter Actor Implementation
class CounterActor:
def __init__(self, actor_id):
self.actor_id = actor_id
def get_state(self, key):
"""Get actor state"""
response = requests.get(
f"{dapr_url}/v1.0/actors/CounterActor/{self.actor_id}/state/{key}"
)
return response.json() if response.status_code == 200 else 0
def set_state(self, key, value):
"""Set actor state"""
requests.post(
f"{dapr_url}/v1.0/actors/CounterActor/{self.actor_id}/state",
json=[{"key": key, "value": value}]
)
@app.route('/actors/CounterActor/<actor_id>/method/increment', methods=['POST'])
def increment_counter(actor_id):
"""Increment counter actor"""
actor = CounterActor(actor_id)
current_value = actor.get_state('count')
new_value = current_value + 1
actor.set_state('count', new_value)
return jsonify({'count': new_value})
@app.route('/actors/CounterActor/<actor_id>/method/get', methods=['GET'])
def get_counter(actor_id):
"""Get current counter value"""
actor = CounterActor(actor_id)
current_value = actor.get_state('count')
return jsonify({'count': current_value})
@app.route('/dapr/config', methods=['GET'])
def get_dapr_config():
"""Dapr actor configuration"""
return jsonify({
"entities": ["CounterActor"],
"actorIdleTimeout": "1h",
"actorScanInterval": "30s"
})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5003)
EOF
# Start actor service
dapr run --app-id actor-service --app-port 5003 python3 actor-demo.py &
sleep 3
# Test actors
echo "๐ญ Testing Actor Pattern..."
curl -X POST http://localhost:3500/v1.0/actors/CounterActor/counter1/method/increment
curl -X POST http://localhost:3500/v1.0/actors/CounterActor/counter1/method/increment
curl http://localhost:3500/v1.0/actors/CounterActor/counter1/method/get
You now understand Daprโs Actor pattern for stateful services! ๐ญ
Example 3: Kubernetes Deployment
# Create Kubernetes deployment manifests
mkdir k8s-deployment
cat > k8s-deployment/order-service.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
labels:
app: order-service
spec:
replicas: 2
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
annotations:
dapr.io/enabled: "true"
dapr.io/app-id: "order-service"
dapr.io/app-port: "5001"
spec:
containers:
- name: order-service
image: order-service:latest
ports:
- containerPort: 5001
env:
- name: DAPR_HTTP_PORT
value: "3500"
---
apiVersion: v1
kind: Service
metadata:
name: order-service
spec:
selector:
app: order-service
ports:
- protocol: TCP
port: 80
targetPort: 5001
type: ClusterIP
EOF
cat > k8s-deployment/redis-state-store.yaml << 'EOF'
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: statestore
spec:
type: state.redis
version: v1
metadata:
- name: redisHost
value: redis-master:6379
- name: redisPassword
secretKeyRef:
name: redis-secret
key: password
EOF
echo "โ Kubernetes manifests created for Dapr deployment!"
Your services are ready for Kubernetes with Dapr! โ
๐จ Fix Common Problems
Here are solutions to the most common Dapr issues you might encounter:
Problem 1: Dapr Init Failed ๐ง
Symptoms: dapr init
command fails or containers donโt start
Solutions:
# Check if Docker is running
docker ps
# If Docker daemon isn't running:
sudo systemctl start docker
# Clean up any partial Dapr installation
dapr uninstall
docker system prune -f
# Re-initialize with specific version
dapr init --runtime-version 1.12.0
# Check Dapr status
dapr status
Problem 2: Service Invocation Timeouts โฐ
Symptoms: HTTP requests to services time out or fail
Solutions:
# Check if services are running
dapr list
# Verify service health
curl http://localhost:3500/v1.0/invoke/your-service/method/health
# Check Dapr logs
dapr logs --app-id your-service
# Increase timeout in your code
requests.post(url, json=data, timeout=30)
Problem 3: Redis Connection Issues ๐
Symptoms: State store or pub/sub operations fail
Solutions:
# Check Redis container is running
docker ps | grep redis
# Test Redis connectivity
docker exec dapr_redis redis-cli ping
# Restart Redis if needed
docker restart dapr_redis
# Check Redis logs
docker logs dapr_redis
# Use custom Redis configuration
cat > components/redis.yaml << 'EOF'
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: statestore
spec:
type: state.redis
version: v1
metadata:
- name: redisHost
value: localhost:6379
- name: redisPassword
value: ""
- name: connectTimeout
value: "5s"
EOF
Problem 4: Port Conflicts ๐ช
Symptoms: โPort already in useโ errors when starting services
Solutions:
# Check what's using the port
sudo netstat -tulpn | grep :3500
# Kill process using the port
sudo kill -9 $(sudo lsof -t -i:3500)
# Use different ports for services
dapr run --app-id my-service --dapr-http-port 3501 --app-port 5001 python3 app.py
# Check available ports
ss -tuln | grep -E ":(3500|5000|6379)"
๐ Simple Commands Summary
Hereโs your quick reference guide for Dapr:
Task | Command | Description |
---|---|---|
Initialize Dapr | dapr init | Set up Dapr runtime locally |
Run app with Dapr | dapr run --app-id myapp --app-port 5000 python app.py | Start service with Dapr sidecar |
List running apps | dapr list | Show all Dapr applications |
View logs | dapr logs --app-id myapp | Get application logs |
Stop application | dapr stop --app-id myapp | Stop specific Dapr app |
Check Dapr status | dapr status | Show Dapr runtime status |
Service invocation | curl localhost:3500/v1.0/invoke/app/method/endpoint | Call service via Dapr |
Pub/Sub publish | curl -X POST localhost:3500/v1.0/publish/pubsub/topic | Publish message |
Get state | curl localhost:3500/v1.0/state/statestore/key | Retrieve state |
Uninstall Dapr | dapr uninstall | Remove Dapr runtime |
๐ก Tips for Success
Here are some pro tips to master Dapr distributed applications! ๐
๐ฏ Start Simple: Begin with basic service invocation and state management before moving to advanced patterns like actors or workflows.
โก Use Building Blocks: Leverage Daprโs building blocks (state, pub/sub, bindings, secrets) instead of implementing these patterns yourself.
๐ Monitor Everything: Enable tracing with Zipkin or Jaeger, and use Dapr dashboard for development debugging.
๐ Component Abstraction: Take advantage of Dapr components to switch between Redis, PostgreSQL, AWS, Azure, etc., without code changes.
๐พ State Consistency: Understand Daprโs state consistency models (eventual vs strong) for your use case requirements.
๐ Scale Gradually: Start with self-hosted mode for development, then move to Kubernetes for production with the same application code.
๐ Service Mesh Integration: Combine Dapr with service meshes like Istio for advanced traffic management and security policies.
๐ก๏ธ Security First: Use Daprโs built-in security features like mTLS, token authentication, and secret management from day one.
๐ What You Learned
Congratulations! Youโve successfully mastered Dapr distributed application runtime! ๐ Hereโs everything you accomplished:
โ
Installed and configured Dapr on AlmaLinux 9 with self-hosted mode
โ
Built microservices using Daprโs service invocation and state management
โ
Implemented pub/sub messaging for event-driven architecture
โ
Created multi-service applications with Python and Node.js
โ
Managed secrets securely with Dapr secret stores
โ
Explored Actor pattern for stateful distributed objects
โ
Prepared Kubernetes deployment with Dapr integration
โ
Troubleshot common issues and optimized service performance
โ
Learned production best practices for distributed applications
๐ฏ Why This Matters
Dapr transforms distributed application development from complex to simple! ๐ You can now:
๐ ๏ธ Build Microservices Faster: Focus on business logic instead of infrastructure concerns like service discovery, state management, and pub/sub
โก Deploy Anywhere: Run the same application code on-premises, in the cloud, or at the edge without modifications
๐ Switch Components Easily: Change from Redis to PostgreSQL or from local file system to AWS S3 with just configuration changes
๐ Scale Globally: Build applications that can scale across multiple clouds and regions with consistent behavior
๐ Observe Everything: Get built-in metrics, tracing, and logging for all distributed communication without additional code
๐ก๏ธ Secure by Default: Benefit from mTLS, token authentication, and secure secret management out of the box
You now possess cutting-edge distributed systems skills that are essential for modern cloud-native development. Companies like Microsoft, Alibaba, and thousands of others use Dapr in production, making your expertise highly valuable for platform engineering, microservices architecture, and cloud-native development roles! โญ
Keep building distributed applications, keep innovating, and remember - with Dapr, building microservices is as easy as building monoliths! ๐โจ