2

I am running a dotnet core app using Kubernetes with Docker.

The setup is as follows:

APP

In the dotnet core app, I have Kestrel server listening on port 8080 by setting the following in Program.cs:

public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
    .UseStartup<Startup>()
    .UseKestrel(options =>
    {
        options.Listen(IPAddress.Loopback, 8080);
    })
    .Build();

I have tested the app build locally and the endpoint works as expected on localhost:8080/api/test.

DOCKER IMAGE

In the Dockerfile I have the following:

EXPOSE 8080

I understand this to mean that the container gets built with an exposed 8080 port.

Question 1: ...does this necessarily mean that the container's 8080 is mapped to the app's 8080? If not, how do I map this?

KUBERNETES (MINIKUBE)

Within Kubernetes (running locally on Minikube), I then use a Replication Controller to create 3 pods that each contain 1 docker container with the app. My RC file looks like this:

{
    "apiVersion": "v1",
    "kind": "ReplicationController",
    "spec": {
        "replicas": 3,
        "selector": {
            "app": "myApp"
        },
        "template": {
            "metadata": {
                "labels": {
                    "app": "myApp"
                }
            },
            "spec": {
                "containers": [
                    {
                        "name": "my-app",
                        "image": "myname/myapp:1.0",
                        "ports": [
                            {
                                "containerPort": 8080
                            }
                        ]
                    }
                ]
            }
        }
    }
}

Notice "ports": [{ "containerPort": 8080 }]. The way I understand it, this means that the container port I want to expose is 8080.

I then have a Kubernetes Service that exposes my 3 pods' 8080 ports through the endpoint [minikubeIPAddress]:30001:

{
    "apiVersion": "v1",
    "kind": "Service",
    "spec": {
        "type": "NodePort",
        "ports": [
            {
                "port": 8080,
                "nodePort": 30001,
                "protocol": "TCP"
            }
        ],
        "selector": {
            "app": "myApp"
        }
    }
}

When I try to hit the endpoint [minikubeIPAddress]:30001/api/test I am getting a 'site can't be reached' error.

I had it working this morning when I was using the default HTTP port 80. The only changes that have been made are to the port numbers.

Question 2: ...have I missed something here? Is there a connection along the line here that is still mapped to the default port of 80?

Any help would be much appreciated.

JMadelaine
  • 2,859
  • 1
  • 12
  • 17

2 Answers2

1

use "targetPort" to indicate what port your pod is listening on. Your yaml spec should be something like:

---
apiVersion: v1
kind: Service
metadata:
  name: myApp
spec:
  selector:
    app: myApp
  ports:
  - name: http
    port: 8080
    targetPort: 8080
    nodePort: 30001
Trondh
  • 3,221
  • 1
  • 25
  • 34
  • 1
    I get the following error when doing that: `error: error validating "c:/Kubernetes/svc-myapp.json": error validating data: ValidationError(Service.spec.ports[0]): missing required field "port" in io.k8s.api.core.v1.ServicePort; if you choose to ignore these errors, turn validation off with --validate=false` – JMadelaine Apr 01 '18 at 20:19
  • you'll need both a port and a Nodeport then. "port" is where other pods in the cluster will access this app if using k8s' internal service discovery, nodePort will be the "external" port you'll use to reach it from your dev machine (external to the cluster) – Trondh Apr 01 '18 at 20:31
  • Minikube's dashboard for instance is set up like this: nodePort: 30000 port: 80 targetPort: 9090 – Trondh Apr 01 '18 at 20:31
0

After much trial and error I found the solution.

In line with what @johnharris85 and @Yuankun said about the IP Address needing to be set to 'any' rather than on the localhost, I found this article: http://blog.scottlogic.com/2016/09/05/hosting-netcore-on-linux-with-docker.html

The dotnet core app defaults to using the localhost network, and while running locally on a test machine, this works fine. However, running a dotnet app inside a Docker container means that the localhost network is restricted to within the container.

To solve this, I initially changed

options.Listen(IPAddress.Loopback, 8080);

to

options.Listen(IPAddress.Any, 8080);

However, I tested this locally and could not get the app to respond. I took this to mean that this was not a valid solution. This may have been a valid solution if I had tested it with a containerized app.

I then came across the aforementioned article and decided to try the following:

public static IWebHost BuildWebHost(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
    .UseStartup<Startup>()
    .UseUrls("http://*:8080")
    .Build();

This solved my problem and now my app is accessible through the Kubernetes endpoint.

Thanks to everyone who gave advice.

JMadelaine
  • 2,859
  • 1
  • 12
  • 17