I have two ASP.NET Core apps. One is a Headless CMS (API), and the other one is a Razor Pages blog front-end (with a REST client that communicates with the Headless CMS/API).
I then have an Azure AKS cluster. In it I have an ingress resource with the following routes (as per the instructions from the following AKS docs: https://docs.microsoft.com/en-us/azure/aks/ingress-tls#create-an-ingress-route ). Each route is mapped to each of the apps/services mentioned above:
spec:
rules:
- host: mydomain.westeurope.cloudapp.azure.com
http:
paths:
- backend:
serviceName: headless-cms-svc
servicePort: 80
path: /
- backend:
serviceName: blog-svc
servicePort: 80
path: /blog
When I now navigate to the first route, mydomain.westeurope.cloudapp.azure.com
, the headless CMS app works as expected but when I navigate to the second route , mydomain.westeurope.cloudapp.azure.com/blog
, I get a bunch of 404:s because the blog apps root path is now relative to the /blog
ingress route which in turn breaks all the resources (css, javascript, images etc) in the wwwroot folder.
How should I configure my ASP.NET Core blog app and/or my ingress object?
404:s
https://mydomain.westeurope.cloudapp.azure.com/css/site.min.css?v=kHvJwvVAK1eJLN4w8xygUR3nbvlLmRwi5yr-OuAO90E
https://mydomain.westeurope.cloudapp.azure.com/images/banner1.svg
https://mydomain.westeurope.cloudapp.azure.com/images/banner2.svg
https://mydomain.westeurope.cloudapp.azure.com/js/site.min.js?v=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
If I add the URL segment /blog
the resources get served properly.
https://mydomain.westeurope.cloudapp.azure.com/blog/images/banner1.svg
<- works
And here is a regular img
tag in the Index.cshtml
Razor page (from a default ASP.NET Core 2.1 Razor Pages web application). I haven't changed anything in the code.
<img src="~/images/banner1.svg" alt="ASP.NET" class="img-responsive" />
Problem
It seems that your proxy rewrites the path.
- Before proxy: /blog/images/banner1.png
- After proxy: /images/banner1.png
Asp generates absolute (host relative) links (path only, but starting with a slash "/"). That means, we have to tell the framework that it must prefix all URLs with "/blog".
Solution
Do this (for asp.net core 2.1) by inserting the following snipped in your Startup class:
app.Use((context, next) =>
{
context.Request.PathBase = new PathString("/blog");
return next();
});
Code sample from: https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-2.1
Insert this snipped before any other middleware in your Configure method.
You can test this on your local machine too. All generated links should be prefixed with "/blog" - so they will be broken on your dev machine.
Use Configuration
You will need to make it configurable e.g. like so:
var basePath = Configuration.GetSection("BASE_PATH").Value;
if (basePath != null)
{
Console.WriteLine($"Using base path '{basePath}'");
// app.Use().. goes here
}
(Assuming you read configuration from env vars in your startup.)
… and provide this env var in your kubernetes depoyment:
...
containers:
- name: myapp
image: myappimage
env:
- name: BASE_PATH
value: "/blog"
You want to annotate your Ingress with nginx.ingress.kubernetes.io/rewrite-target
. For example:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: mydnsname.westeurope.cloudapp.azure.com
http:
paths:
- backend:
serviceName: headless-cms-svc
servicePort: 80
path: /
- backend:
serviceName: blog-svc
servicePort: 80
path: /blog
Hope it helps!
Follow these steps to run your code:
- deployment: pass environment variable with path base in k8s-yaml-file
apiVersion: apps/v1
kind: Deployment
# ..
spec:
# ..
template:
# ..
spec:
# ..
containers:
- name: test01
image: test.io/test:dev
# ...
env:
# define custom Path Base (it should be the same as 'path' in Ingress-service)
- name: API_PATH_BASE # <---
value: "blog"
- program: enable loading environment params in Program.cs
var builder = new WebHostBuilder()
.UseContentRoot(Directory.GetCurrentDirectory())
// ..
.ConfigureAppConfiguration((hostingContext, config) =>
{
// ..
config.AddEnvironmentVariables(); // <---
// ..
})
// ..
- startup: apply UsePathBaseMiddleware in Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
_configuration = configuration;
}
private readonly IConfiguration _configuration;
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
var pathBase = _configuration["API_PATH_BASE"]; // <---
if (!string.IsNullOrWhiteSpace(pathBase))
{
app.UsePathBase($"/{pathBase.TrimStart('/')}");
}
app.UseStaticFiles(); // <-- StaticFilesMiddleware must follow UsePathBaseMiddleware
// ..
app.UseMvc();
}
// ..
}
来源:https://stackoverflow.com/questions/52404475/how-to-configure-an-asp-net-core-multi-microservice-application-and-azure-aks-in