Kubernetes with Docker unable to change from default port of 80

4/1/2018

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
docker
dockerfile
kubernetes
minikube
port

2 Answers

4/1/2018

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
Source: StackOverflow

4/1/2018

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
Source: StackOverflow