How to Configure and Use Namespace Isolation in CoSky
CoSky isolates resources by namespace—a logical tenant identifier prefixed to every Redis key and REST API path—enabling multi-tenant configuration and service discovery through the spring.cloud.cosky.namespace property or runtime context switching.
Namespace isolation in CoSky provides the foundation for multi-tenancy in distributed systems. The ahoo-wang/cosky repository implements this pattern across three architectural layers: configuration properties, runtime thread-local context, and REST API path variables. Each namespace maintains independent config data, service discovery metadata, and RBAC policies within the same Redis backend.
Understanding Namespace Isolation Architecture
CoSky applies namespace isolation at three distinct layers to ensure complete tenant separation.
Configuration Layer
The spring.cloud.cosky.namespace property sets the default tenant identifier for the entire application. When omitted, CoSky falls back to Namespaced.DEFAULT (value: "cosky"). This value is defined in CoSkyProperties.kt and represents the root of all key prefixes stored in Redis.
Runtime Context Layer
At startup, CoSkyAutoConfiguration copies the property value into NamespacedContext.namespace, a thread-local holder that downstream components reference. All internal services—including ConfigService, DiscoveryService, and NamespaceService—read the current namespace from this context, ensuring operations remain scoped to the active tenant.
REST API Layer
Every tenant-scoped endpoint includes a {namespace} path variable under the /v1/namespaces/{namespace} prefix. Controllers extract this variable and forward it to the service layer, as implemented in RequestPathPrefix.kt and consumed by controllers like ServiceController.kt.
Configuring the Default Namespace
Set the default namespace in application.yaml (or bootstrap.yaml if required before the Spring context starts):
spring:
cloud:
cosky:
# The tenant identifier used when no explicit namespace is provided
namespace: my-company
When this property is present, CoSkyAutoConfiguration.kt executes:
// CoSkyAutoConfiguration.kt (excerpt)
NamespacedContext.namespace = coSkyProperties.namespace
All components using NamespacedContext.namespace automatically operate within the my-company tenant. This configuration affects config resolution, service registration, and permission checks throughout the application lifecycle.
Switching Namespaces at Runtime
For multi-tenant SaaS scenarios requiring dynamic tenant switching, inject the NamespaceService bean:
@Service
class TenantInitializer(
private val namespaceService: NamespaceService
) {
fun switchTo(tenant: String): Mono<Void> =
namespaceService.setNamespace(tenant) // Updates thread-local context
}
The NamespaceService API (defined in NamespaceService.kt) provides additional management operations:
// List all registered namespaces
namespaceService.namespaces.subscribe { println(it) }
// Permanently delete a namespace and all its data
namespaceService.deleteNamespace("old-tenant").subscribe()
Runtime switching changes the thread-local NamespacedContext immediately, causing subsequent operations to target the new tenant's keyspace in Redis.
Using the REST API for Namespace Operations
All tenant-aware endpoints reside under /v1/namespaces/{namespace}. The REST API defined in RequestPathPrefix.kt exposes the following operations:
- List namespaces:
GET /v1/namespacesreturns all registered tenants. - Create namespace:
POST /v1/namespaceswith body{ "namespace": "new-tenant" }. - Delete namespace:
DELETE /v1/namespaces/{namespace}removes the tenant and all associated data. - Config management:
GET/PUT/DELETE /v1/namespaces/{namespace}/configs/{configId}handles tenant-scoped configuration. - Service discovery:
GET /v1/namespaces/{namespace}/serviceslists services within the tenant.
Controllers extract the namespace from the path variable and pass it to the service layer. For example, ServiceController.kt implements:
// ServiceController.kt (excerpt)
@GetMapping("/{namespace}/services")
fun getServices(@PathVariable namespace: String): Mono<List<String>> =
discoveryService.getServices(namespace).collectList()
Summary
- CoSky namespace isolation separates tenant data by prefixing Redis keys with a logical namespace identifier.
- Configure the default namespace via
spring.cloud.cosky.namespaceinapplication.yaml, processed byCoSkyAutoConfiguration.kt. - Runtime switching uses
NamespaceService.setNamespace()to update the thread-localNamespacedContext. - REST endpoints require the
{namespace}path variable under/v1/namespaces/{namespace}for all tenant-scoped operations. - Source files:
CoSkyProperties.kt,CoSkyAutoConfiguration.kt,NamespaceService.kt,RequestPathPrefix.kt,ServiceController.kt, andCoSkyConfigRefresher.ktimplement the isolation logic.
Frequently Asked Questions
What is the default namespace in CoSky?
If you do not specify spring.cloud.cosky.namespace, CoSky uses Namespaced.DEFAULT with the value "cosky". This global default ensures backward compatibility while allowing explicit tenant configuration.
Can I change the namespace after the application starts?
Yes. Inject NamespaceService and call setNamespace(tenant) to update the thread-local context. This switches the tenant scope for subsequent operations without restarting the application, enabling multi-tenant SaaS architectures.
How does namespace isolation work in Redis?
CoSky prefixes every stored key with the namespace identifier. For example, configuration keys for namespace my-company follow the pattern my-company:config:{configId}. This logical separation prevents data leakage between tenants while using a single Redis database.
Are namespaces created automatically?
Namespaces are created implicitly when first used, or explicitly via POST /v1/namespaces. The NamespaceService tracks registered namespaces in Redis, allowing administrators to list or delete tenants through the REST API or programmatically via deleteNamespace().
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →