refactor: extract reusable building blocks from K8s and Nacos discovery#13201
Conversation
There was a problem hiding this comment.
Pull request overview
This PR refactors APISIX service discovery by extracting reusable core logic from the Kubernetes and Nacos discovery implementations into standalone modules, enabling external consumers to reuse the underlying primitives while keeping existing discovery module APIs stable.
Changes:
- Added reusable Kubernetes discovery building blocks (
apisix/discovery/kubernetes/core.lua) and refactored the Kubernetes discovery init module to use them. - Added a reusable Nacos HTTP client module (
apisix/discovery/nacos/client.lua) and refactored the Nacos discovery init module to use it. - Enhanced Kubernetes informer factory to support graceful stop and configurable TLS behavior (
ssl_verify,ssl_server_name), and extended the Kubernetes discovery schema withssl_verify.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| apisix/discovery/nacos/init.lua | Refactored to use the extracted Nacos client for service scanning and instance fetching. |
| apisix/discovery/nacos/client.lua | New reusable Nacos HTTP client and discovery primitives (auth, signing, URL building, fetching). |
| apisix/discovery/kubernetes/schema.lua | Adds service.ssl_verify to schema (single + multi mode). |
| apisix/discovery/kubernetes/init.lua | Refactored to use new kubernetes.core helpers for handle creation, fetch lifecycle, and node resolution. |
| apisix/discovery/kubernetes/informer_factory.lua | Adds stop-flag checks and makes TLS verification + SNI configurable via apiserver settings. |
| apisix/discovery/kubernetes/core.lua | New reusable Kubernetes discovery core (config parsing, callbacks, handle factory, lifecycle, node resolution, dict helpers). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Extract kubernetes/core.lua and nacos/client.lua as composable building blocks from the existing init.lua modules. kubernetes/core.lua provides: - Config parsing (get_apiserver, setup_namespace_selector, etc.) - Parameterized endpoint callbacks via create_endpoint_callbacks() with key_prefix for multi-registry dict isolation and duplicate_port_number for flexible port key storage - Handle factory (create_handle) and lifecycle (start_fetch) - Node resolution with LRU cache (resolve_nodes) - Dict helpers (dump_endpoints_from_dict) nacos/client.lua provides: - Stateless HTTP client primitives (request, get_token_param) - HMAC-SHA1 signing (get_signed_param) - URL building (build_base_uri) - Instance fetching (fetch_from_host) with configurable key_builder, preserve_metadata, and timeout - Service scanning (get_nacos_services) with optional filter informer_factory.lua enhancements: - Graceful stop support (informer.stop flag) checked in watch() and list_watch() loops - Configurable ssl_verify (from apiserver config, default false) - ssl_server_name support for HTTPS connections schema.lua: - Add ssl_verify option to service config for both single and multiple mode Both init.lua modules are refactored to use the new building blocks with no behavior change for existing users.
3e59d07 to
a73d7b4
Compare
- nacos2.t TEST 5: use 'default/public/DEFAULT_GROUP/svc' key format - Fix error log format: 'err:' without space (matching original)
- Add nacos-stream shared dict to test framework for stream tests - Make dict name subsystem-aware (nacos vs nacos-stream) - Restore original error log format in client.lua
- Add get_nodes(key, metadata) for shared dict access with optional metadata filter - Move match_metadata logic into apisix layer for reuse by downstream consumers - Refactor nodes() to use get_nodes() internally
The error log format changed from 'error: status = N' to 'err:status = N' when client.lua was refactored to use 'get_url:<path> err:<err>' format.
There was a problem hiding this comment.
Pull request overview
Refactors APISIX Kubernetes and Nacos discovery modules by extracting reusable core/client building blocks, enabling more composable discovery handles and shared logic for endpoint processing and registry fetching.
Changes:
- Extract Kubernetes discovery building blocks into
apisix/discovery/kubernetes/core.luaand refactorkubernetes/init.luato use them. - Extract Nacos HTTP/client primitives into
apisix/discovery/nacos/client.luaand redesignnacos/init.luaaround a registry abstraction with stream support. - Update tests and test Nginx config to reflect new Nacos dict keys and add
nacos-streamshared dict.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| t/discovery/nacos2.t | Updates expected log output and dump key format for refactored Nacos discovery. |
| t/APISIX.pm | Adds lua_shared_dict nacos-stream for stream subsystem tests. |
| apisix/discovery/nacos/init.lua | Introduces registry abstraction and refactors periodic fetch/cleanup logic. |
| apisix/discovery/nacos/client.lua | Adds reusable Nacos HTTP client, auth/signing, URL parsing, fetch and config scanning. |
| apisix/discovery/kubernetes/schema.lua | Adjusts Kubernetes discovery schema content (description removal only). |
| apisix/discovery/kubernetes/init.lua | Refactors to use extracted Kubernetes core helpers/handle factory. |
| apisix/discovery/kubernetes/informer_factory.lua | Adds stop checks and supports ssl_server_name/ssl_verify wiring. |
| apisix/discovery/kubernetes/core.lua | New extracted Kubernetes discovery core: callbacks, handle creation, fetch lifecycle, node resolution, dump helpers. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Add nil guard in build_base_uri for malformed URLs without protocol - Add id validation and auto-stop in create_registry - Fix resolve_nodes doc comment to include endpoint_port return value
The original nacos nodes() had a 5-second wait loop for the initial fetch to complete. The refactored version returned nil immediately before data was populated, causing 503 errors in tests. Add fetch_done flag to registries and restore the wait loop in the standard nodes() interface.
Add info-level log after dict:set loop completes so operators and tests can reliably detect when nacos nodes are stored.
Revert the fetch_done flag and wait loop. The standard APISIX discovery interface returns nil when data is not yet available; callers handle retry at the proxy layer.
Following the pattern established by PR apache#13201 (Nacos + K8s refactor), refactor the Consul discovery module to support multi-instance registry API while preserving all existing behavior. Changes: - Create client.lua: extracted HTTP/protocol primitives (blocking query watchers, service fetching, URL parsing, sort helpers, service scanner) - Refactor init.lua: add create_registry/start_registry/stop_registry/ get_registry/get_nodes multi-instance registry API - Move mutable module state (skip_service_map, dump_params, consul_services, default_service) into per-registry reg object - Shared dict keys now use registry ID prefix ("default/service_name") for multi-instance isolation - all_nodes/dump_data/show_dump_file strip prefix for backward compat - Add metadata filtering support via get_nodes(key, metadata) - Preserve privileged-agent-only gating for write operations - No schema changes, all existing tests should pass
Summary
Refactor Kubernetes and Nacos service discovery modules to extract reusable building blocks. This makes the discovery modules more composable — external consumers can create custom discovery handles, reuse endpoint processing callbacks, and build on top of the Nacos HTTP client without duplicating internal logic.
Kubernetes
Extract
kubernetes/core.lua(~750 lines) frominit.lua:get_apiserver(),setup_namespace_selector(),setup_label_selector()create_endpoint_callbacks(options)— parameterized informer callbacks with key_prefix and duplicate_port_number supportcreate_handle(conf, options)— creates a fully configured informer handlestart_fetch(handle)— starts the list/watch loop with stop supportresolve_nodes()— LRU-cached node resolution from shared dictRefactored
init.luato use core.lua (875→265 lines, behavior unchanged).Enhanced
informer_factory.lua:informer.stopflag checked at 4 points)ssl_server_namefor HTTPS connectionsssl_verify(reads fromapiserver.ssl_verify)Nacos
Extract
nacos/client.lua(~360 lines) frominit.lua:request(),get_token_param(),get_signed_param()build_base_uri()— URL parsing with embedded credential supportfetch_from_host()— fetch instances with key_builder and preserve_metadata optionsget_nacos_services(filter)— scan APISIX config for nacos referencesRedesign
nacos/init.luawith multi-instance registry abstraction:create_registry(conf, options)/start_registry(reg)/stop_registry(id)id(currently hardcoded to"default"){id}/{ns}/{group}/{svc}format for future multi-instance supportNo behavior change for existing users.
Code line change analysis
Total: +1379 / -973 (net +406)
The net increase comes from extracting shared code into new files:
kubernetes/core.luakubernetes/init.luakubernetes/informer_factory.luanacos/client.luanacos/init.luaWhy the net is positive:
core.lua(+752) andclient.lua(+365) are new files that contain code previously inlined ininit.lua. The correspondinginit.luadeletions (-617 and -115) don't fully offset because the new files also add proper doc comments, validation, and the multi-instance registry API that didn't exist before. The actual duplicated logic is reduced — the "new" code is mostly moved code plus ~150 lines of new API surface (registry lifecycle, deferred dict access, stop-flag handling).