skip to Main Content

I’ve recently being learning about Kubernetes and I have deployed a service which contains a .NET Core 7 REST API into a pod. This pod/service is configured with it’s ClusterIP and with NGINX port as well.

Whenever I would want to access the static files which is stored under this path in this screenshot:
first folder which is "app"
wwwroot folder where the static files are

The path will be "app>wwwroot>icons>svg>anyimagesname.svg".

My localhost address for 127.0.0.1 has been configured to have a DNS of www.chorebear.com hence the complete URL to access the static file will be http://chorebear.com/icons/svg/afghanistan_adobe_express.xml

But everytime I hit this URL, it says "NGINX 404 Not Found". Is there any issue with the service itself? Any help would help in this. Thanks!.

Not found 404 Error

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
var sqlConnectionBuilder = new SqlConnectionStringBuilder();
if (builder.Environment.IsDevelopment())
{
    sqlConnectionBuilder.ConnectionString = builder.Configuration.GetConnectionString("Chorebear_Connection");
    sqlConnectionBuilder.UserID = builder.Configuration["UserId"];
    sqlConnectionBuilder.Password = builder.Configuration["Password"];
} else if (builder.Environment.IsProduction()) 
{
    sqlConnectionBuilder.ConnectionString = builder.Configuration.GetConnectionString("Chorebear_Connection");
    // sqlConnectionBuilder.UserID = builder.Configuration["UserId"];
    // sqlConnectionBuilder.Password = builder.Configuration["Password"];
}

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<ChoreBearContext>(options => options.UseSqlServer(sqlConnectionBuilder.ConnectionString));

//Registering services and classes which are dependency injection
builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
builder.Services.AddIdentity<User, UserRole>().AddDefaultTokenProviders();
builder.Services.Configure<IdentityOptions>(options => 
{
    options.User.RequireUniqueEmail = true;
    options.Password.RequiredLength = 8;
    
    options.SignIn.RequireConfirmedEmail = true;
});
builder.Services.AddScoped<IUserStore<User>, UserStore>();
builder.Services.AddTransient<IRoleStore<UserRole>, RoleStore>();
builder.Services.AddScoped<ICategoryOfTaskRepo, CategoryOfTaskRepo>();
builder.Services.AddScoped<ITaskRepo, TaskRepo>();
builder.Services.AddScoped<IAccountRepo, AccountRepo>();

//Registering utility classes which are dependency injection
builder.Services.AddScoped<IEmailUtility, EmailUtility>();
builder.Services.AddScoped<IPasswordHasher<User>, PasswordHasher<User>>();

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.UseStaticFiles();

PrepDb.PrepPopulation(app, builder.Environment.IsProduction());

app.Run();

2

Answers


  1. Chosen as BEST ANSWER

    I've solved the issue by my own. Let me explain step-by-step on how I found the bug and how I solve it.

    Currently, my architecture of my Kubernetes contains the following:

    1. .NET Core REST API service [With a ClusterIP service exposed to port 80] in a pod
    2. Node Port Service for .NET Core REST API [only for development purposes]
    3. Ingress NGINX Service which is configured to connect or rewrite the ClusterIP of .NET Core REST API to a domain URL instead of "localhost" IP address. [Used as production standard environment]
    4. MS SQL Server Instance Database service [With a ClusterIP service exposed to port 1433 and LoadBalancer exposed to 1433 to allow the service to be accessed by Microsoft SQL Server Management Studio]
    5. Persistent Volume Claim to persist data saved in MS SQL Server Instance Database service directly into the hardware of the host (in this case my PC)

    Now my .NET Core REST API had an issue, with first the middleware position especially which is the middleware called app.UseStaticFiles(). The position previously was right before app.Run() hence when a HTTP request is initiated to the REST API service in Kubernetes, the static files which I saved under www/icons/svg folder was being served quite late. So quick shoutout to @GuruStron for spotting this and providing the links to the documentation which helped me understanding it. I'll provide the links below:

    1. ASP.NET Core Middleware
    2. Static Files in ASP.NET Core

    But it's not the full solution to the problem. The problem relies in the Ingress Service and in this case my ingress-depl.yaml file. Let me show you the previous YAML file and the update file.

    Previous Ingress Service YAML file

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: ingress-srv
      annotations:
       kubernetes.io/ingress.class: nginx
       nginx.ingress.kubernetes.io/use-regex: 'true'
    spec:
     rules:
      - host: chorebear.com
        http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: chorebear-clusterip-srv
                port:
                  number: 80
    

    Updated Ingress YAML file

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: ingress-srv
      annotations:
       kubernetes.io/ingress.class: nginx
       nginx.ingress.kubernetes.io/use-regex: 'true'
    spec:
     rules:
      - host: chorebear.com
        http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: chorebear-clusterip-srv
                port:
                  number: 80
    

    The difference between both files were the configuration property called path: /api. This property rewrites the URL domain for the .NET Core REST API pod container to "http://chorebear.com/api". Any HTTP request to any endpoint will be like this --> http://chorebear.com/api/[any-endpoint-you-create-in-your-controller]

    Now since my controllers in my REST API contains [Route("api/[controller]")], the "api" portion of the "Route" gets re-written by the path: /api of the YAML file for Ingress. This then allows me to call any endpoint created in my controllers with the domain URL in my YAML file but for the static files, it cannot be served on that same re-written URL domain which is "chorebear.com/api" simply because the app.UseStaticFiles middleware needs the "api" path from the HTTP request which is not configured/set in the middleware itself and hence the ultimate dead-end of "404 Error Not Found NGINX".

    To solve it, I simple re-type the path: /api to path: / in my Ingress Service YAML File and it works. For the endpoints I define in my controllers, I can still call as usual with "api" addition like http://chorebear.com/api/[any-endpoint-you-create-in-your-controller] since my controllers are decorated with [Route("api/[controller]")] which has the "api" on it. So now, my static files are served and accessible on my domain URL set in my Ingress Service YAML File http://chorebear.com/icons/svg/afghanistan_adobe_express.xml

    The static files now being served under the Ingress Service Domain URL

    The API HTTP Request now being served under the Ingress Service Domain URL

    I hope this helps!


  2. Middleware order is very important, your app.UseStaticFiles is too late move it closer to the start of the pipeline:

    // ...
    if (app.Environment.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI();
    }
    
    app.UseHttpsRedirection();
    
    app.UseStaticFiles();
    
    app.UseAuthorization();
    
    app.MapControllers();
    

    Read more:

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search