Cloud Native 11 min read

How to Build Python Microservices with Zero‑Intrusion Service Discovery Using Nacos

This article introduces a Python‑centric microservice solution built on Nacos that brings non‑intrusive service registration, low‑threshold discovery, and flexible configuration to Python applications, offering code examples, CLI tools, import hooks, and middleware to achieve Java‑like ease of use in the cloud‑native era.

Alibaba Cloud Developer
Alibaba Cloud Developer
Alibaba Cloud Developer
How to Build Python Microservices with Zero‑Intrusion Service Discovery Using Nacos

In the era where microservice architecture dominates information systems, Java’s Spring Cloud provides a seamless, annotation‑driven experience, while Python developers often face either heavyweight intrusive code or give up microservice benefits.

To bring the same elegance to Python, the open‑source nacos and nacos-serving-python projects offer a truly Pythonic microservice solution.

1. Pythonic Philosophy and Microservice Integration

Pythonic means more than following PEP8; it embodies core Zen principles such as "Readability counts", "Simple is better than complex", and "Explicit is better than implicit". In microservices, Pythonic translates to:

Non‑intrusive : does not break existing code structure.

Low threshold : quick onboarding with a gentle learning curve.

Flexibility : adapts to various frameworks and scenarios.

Microservice Challenges for Python

Python excels in web development, data analysis, and AI, yet in microservice contexts it suffers from:

Manual service registration without automation.

Service discovery often relies on hard‑coded endpoints or external load balancers.

Configuration changes require application restarts.

Java’s Non‑Intrusive Experience

// Service registration and discovery
@EnableDiscoveryClient
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

// Dynamic configuration
@RestController
@RefreshScope
public class ConfigController {
    @Value("${useLocalCache:false}")
    private boolean useLocalCache;
}

This annotation‑driven design is the goal for Python.

2. Low‑Intrusive Service Discovery Strategy

Replace the standard HTTP client import with the Nacos‑enabled version:

# Traditional way (hard‑coded IP and port)
import requests

def get_user_info_old(user_id):
    response = requests.get(f"http://192.168.1.100:8080/api/users/{user_id}")
    return response.json()

# Service discovery way (just change the import)
from nacos.auto.discovery.ext import requests

def get_user_info_new(user_id):
    # Use service name, automatic discovery and load balancing
    response = requests.get(f"http://user-service/api/users/{user_id}")
    return response.json()

Supported HTTP clients include requests, httpx, aiohttp, and urllib:

from nacos.auto.discovery.ext import requests
from nacos.auto.discovery.ext.httpx import AsyncClient
from nacos.auto.discovery.ext.aiohttp import get_session
from nacos.auto.discovery.ext.urllib import urlopen

Technical Principle: URL Interception and Routing Conversion

def resolve_url(self, url: str, strategy: LoadBalanceStrategy = LoadBalanceStrategy.ROUND_ROBIN) -> str:
    service_name, parsed_url = self._parse_url(url)
    # If not a service URL, return directly
    if not service_name:
        return url
    try:
        # Get service instance (blacklist filtering handled inside)
        instance = self.service_discovery.get_instance_sync(service_name, strategy=strategy)
        # Replace host and port
        return self._replace_host_port(parsed_url, instance.ip, instance.port)
    except NoAvailableInstanceError as e:
        logger.error(f"No available instance for service '{service_name}': {e}")
        raise

HTTP Client Adaptation

def request(method, url, **kwargs):
    with _create_service_discovery_client() as client:
        return client.request(method, url, **kwargs)

def get(url, **kwargs):
    """GET request with service discovery"""
    return request('GET', url, **kwargs)

__all__ = ["get", "request", ...]

Configuration‑Driven Service Discovery

# nacos.yaml
nacos:
  server: "127.0.0.1:8848"
  namespace: "public"
  discovery:
    empty_protection: true

3. Three Low‑Intrusive Automatic Registration Methods

Method 1: CLI Launcher (Zero Intrusion)

# Original start command
python app.py

# Wrapped with Nacos CLI
python -m nacos.auto.registration \
    --nacos-server 127.0.0.1:8848 \
    --service-name user-service \
    --service-port 8000 \
    app.py

Method 2: Import Trigger (Minimal Intrusion)

# Add a single import at the top of the Flask entry file
import nacos.auto.registration.enabled

from flask import Flask
app = Flask(__name__)

@app.route('/api/users')
def get_users():
    return {"users": ["Alice", "Bob", "Charlie"]}

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)

The import hook replaces the built‑in __import__ function, detects Flask/FastAPI/Django modules, and injects the necessary middleware.

def enable(self):
    """Enable import hook"""
    self.original_import = __builtins__['__import__']
    __builtins__['__import__'] = self._hooked_import
    logger.info("Import hook enabled for Nacos auto‑registration")

def _hooked_import(self, name, **kwargs):
    module = self.original_import(name, **kwargs)
    if self._should_hook_module(name, module):
        self._inject_into_module(name, module)
    return module

Method 3: WSGI/ASGI Middleware (Fine‑Grained Control)

from flask import Flask
app = Flask(__name__)

# Perform complex initialization
initialize_database_pool()
initialize_redis_connection()
warm_up_cache()

# Inject Nacos middleware when ready
from nacos.auto.middleware.wsgi import inject_wsgi_middleware
app = inject_wsgi_middleware(app)

app.run(host='0.0.0.0', port=8081)

This approach offers the most flexibility, allowing developers to decide exactly when registration occurs.

Comparison of the Three Registration Methods

Registration methods comparison
Registration methods comparison

Conclusion: The Future of Python Microservices

While Python currently shines in AI scenarios, the emergence of nacos-serving-python bridges AI workloads with existing microservice clusters, enabling native communication. Future releases will add features such as graceful shutdown, zone‑aware routing, and canary releases. Join the community via the GitHub repository https://github.com/nacos-group/nacos-serving-python/ and the DingTalk group (21958624) for collaboration.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Cloud NativePythonMicroservicesBackend Developmentservice discoveryNacos
Alibaba Cloud Developer
Written by

Alibaba Cloud Developer

Alibaba's official tech channel, featuring all of its technology innovations.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.