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.
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.
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