Backend Development 20 min read

Implementing Gray Release in Spring Cloud with Nacos and Ribbon

This article explains the concept of gray (canary) release, details the core components and version configuration, and provides a complete Spring Cloud implementation—including custom request holders, gateway filters, Ribbon load‑balancer extensions, Feign interceptors, and deployment instructions—for smoothly rolling out new service versions.

Top Architect
Top Architect
Top Architect
Implementing Gray Release in Spring Cloud with Nacos and Ribbon

Gray release, also known as canary release, is a deployment strategy that gradually shifts traffic from the old version to a new version, allowing early detection and correction of issues while keeping the overall system stable.

The demo project uses Spring Boot 2.3.12.RELEASE, Spring Cloud Hoxton.SR12, and Spring Cloud Alibaba 2.2.9.RELEASE, with Nacos as the service registry and configuration center. Core components include Nacos, Spring Cloud Gateway, Ribbon (or Spring Cloud LoadBalancer), and OpenFeign.

Gray release implementation relies on setting a version metadata in Nacos and using a GrayFlagRequestHolder (ThreadLocal) to store the gray flag for each request. The flag is set in a pre‑filter, propagated via Feign interceptors, and cleared in post‑filters and a global exception handler.

Code example – GrayFlagRequestHolder :

public class GrayFlagRequestHolder {
    private static final ThreadLocal
grayFlag = new ThreadLocal<>();
    public static void setGrayTag(final GrayStatusEnum tag) { grayFlag.set(tag); }
    public static GrayStatusEnum getGrayTag() { return grayFlag.get(); }
    public static void remove() { grayFlag.remove(); }
}

Gateway pre‑filter determines whether to use the gray version based on request headers, IP, city, or user ID, then sets the appropriate GrayStatusEnum in the holder and adds a custom header to the downstream request.

public class GrayGatewayBeginFilter implements GlobalFilter, Ordered {
    @Autowired private GrayGatewayProperties grayGatewayProperties;
    public Mono
filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        GrayStatusEnum grayStatusEnum = GrayStatusEnum.ALL;
        if (grayGatewayProperties.getEnabled()) {
            grayStatusEnum = GrayStatusEnum.PROD;
            if (checkGray(exchange.getRequest())) { grayStatusEnum = GrayStatusEnum.GRAY; }
        }
        GrayFlagRequestHolder.setGrayTag(grayStatusEnum);
        ServerHttpRequest newRequest = exchange.getRequest().mutate()
            .header(GrayConstant.GRAY_HEADER, grayStatusEnum.getVal())
            .build();
        return chain.filter(exchange.mutate().request(newRequest).build());
    }
    // ...checkGray methods omitted for brevity
    public int getOrder() { return Ordered.HIGHEST_PRECEDENCE; }
}

The custom Ribbon load‑balancer rule AbstractGrayLoadBalancerRule filters the server list according to the gray flag and the version metadata stored in Nacos.

protected List
getGrayServers(List
servers) {
    String currentVersion = metaVersion;
    GrayStatusEnum grayStatusEnum = GrayFlagRequestHolder.getGrayTag();
    if (grayStatusEnum != null) {
        switch (grayStatusEnum) {
            case PROD: currentVersion = grayVersionProperties.getProdVersion(); break;
            case GRAY: currentVersion = grayVersionProperties.getGrayVersion(); break;
            default: return servers;
        }
    }
    List
result = new ArrayList<>();
    for (Server server : servers) {
        NacosServer ns = (NacosServer) server;
        String version = ns.getMetadata().get("version");
        if (currentVersion.equals(version)) { result.add(server); }
    }
    return result;
}

Configuration files (YAML) define the production and gray versions, enable or disable the gray switch, and specify IP or city lists for selective routing. The demo runs five services (gateway, user‑v1, user‑v2, order‑v1, order‑v2) to showcase the effect of different scenarios: gray switch off, gray switch on with production only, and gray switch on with header‑based routing.

Finally, the article provides links to the source code repository and discusses practical considerations such as handling distributed tasks and message queues during gray releases.

JavaMicroservicesgray releaseNacosSpring Cloudribbon
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

login 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.