What are Canary Deployments and Why Will They Save Your Production?
\nHave you ever rolled out an update at midnight, praying nothing would break? Sounds familiar. What if I told you that you can test new code on live users without anyone getting hurt? We're talking about canary deployments — a deployment strategy where the new version of an application initially receives only a small portion of traffic. If everything is fine — traffic increases. If not — rollback in seconds.
\nIn the world of .NET and C#, this is especially relevant: microservices, high loads, stability requirements. We'll write code, set up a canary deployment, and break down real examples. Let's go!
\n\nWhy Canary is Not Just a Buzzword?
\nTraditional blue-green deployment switches all traffic at once. Rolling update does it gradually, but without fine control. Canary gives you a superpower: you release a new version but direct, say, 5% of users to it. The remaining 95% work on the old stable version. You monitor metrics, errors, and latency. If everything is OK — gradually increase the percentage to 100. If not — simply disable the canary.
\nFor a C# developer, this is especially convenient: we can use built-in ASP.NET Core tools, Kubernetes, Feature Flags, or even a simple load balancer. The main thing is the right architecture.
\n\nCanary Deployment Architecture for .NET Applications
\nImagine we have a web API on ASP.NET Core that processes orders. We want to roll out new discount calculation logic. Instead of updating all pods at once, we:
\n- \n
- Run two versions of the service: stable (v1) and canary (v2). \n
- Configure a load balancer (e.g., Nginx or Kubernetes Service) so that 95% of traffic goes to v1 and 5% to v2. \n
- Add an HTTP header
X-Canary: truein the canary version's responses for identification. \n - Collect metrics (200/500 status codes, latency, order count). \n
- If after 30 minutes errors are no higher than on v1, increase the canary weight to 50%, then to 100%. \n
Implementation in C#: From Simple to Complex
\n\nMethod 1: Canary via HTTP Headers and Load Balancer
\nThe simplest way is to use a middleware layer in ASP.NET Core that marks requests. But first, let's look at the code that distinguishes the canary version.
\n// Startup.cs or Program.cs\npublic class CanaryMiddleware\n{\n private readonly RequestDelegate _next;\n private readonly string _version;\n\n public CanaryMiddleware(RequestDelegate next, string version)\n {\n _next = next;\n _version = version;\n }\n\n public async Task InvokeAsync(HttpContext context)\n {\n // Add header for version identification\n context.Response.Headers.Add("X-App-Version", _version);\n await _next(context);\n }\n}\n\n// Registration\napp.UseMiddleware<CanaryMiddleware>("v2-canary");\n\nNow at the load balancer level (e.g., Nginx), we decide what percentage of traffic to send to the canary pod:
\nupstream backend {\n server app-stable:5000 weight=95;\n server app-canary:5000 weight=5;\n}\n\nPros: simplicity. Cons: no programmatic control, difficult to do A/B testing by users.
\n\nMethod 2: Feature Flags in C#
\nA more flexible approach is to use feature flags. You enable new logic only for a specific group of users. ASP.NET Core has built-in support:
\n// Install the package Microsoft.FeatureManagement.AspNetCore\n// Add to Program.cs\nbuilder.Services.AddFeatureManagement();\n\n// Define the flag in appsettings.json\n{\n "FeatureManagement": {\n "NewDiscountLogic": false\n }\n}\n\n// Use in the controller\n[ApiController]\n[Route