Hello,
I have a question about a practice I’m doing to learn all the concepts about Kubernetes,
I have a Laravel container responding to two hostnames, let’s say
app dot domain dot com and api dot domain dot com
Laravel manages this via URL hostname matching against the URLs you define in APP_URL and API_URL in your .env file (dotnet), and all the request go thru the 80 port to the container, so only a single port listening in the container, the URL determines the kind of request automatically (either web or api).
This works well in local, and it seems to be default laravel behaviour afaik.
So I’ve deployed this container in a K8s “deployment” with containerPort=80.
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
labels:
app: app
tier: backend
track: latest
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: app
tier: backend
track: latest
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
app: app
tier: backend
track: latest
spec:
containers:
- image: (ommited)
imagePullPolicy: IfNotPresent
name: app
resources: {}
ports:
- name: http
containerPort: 80
Then, I created 2 services, one named app pointing to container:80 from app:80, and the other one also pointing to container:80 from api:90. I think it’s easier to see on the yaml
This is the first service, attending the requests for app dot domain dot com (see the ingress below)
apiVersion: v1
kind: Service
metadata:
name: app
namespace: default
spec:
ports:
- name: http
protocol: TCP
port: 80 # External exposed port
targetPort: 80 # Internal port
selector:
app: app
tier: backend
track: latest
type: NodePort
And the second one attending the requests for api dot domain dot com:90 (see the ingress below)
apiVersion: v1
kind: Service
metadata:
name: api
namespace: default
spec:
ports:
- name: http
protocol: TCP
port: 90 # External exposed port
targetPort: 80 # Internal port
selector:
app: app
tier: backend
track: latest
type: NodePort
I can access both of them fine from the internal cluster network and see the different responses depending on the hostname used. I’ve successfuly set up a pod (dnsutils) and edited its internal /etc/hosts and I’ve been successful to connect to both
app dot domain dot com
and
api dot domain dot com semicolon 90
and got a successful response in both cases, and not only a response, the returned content matched either the website or the api responses I expected, so all good so far.
Then I created 2 ingresses, one for each service, making them point to each of the services using the hostname and servicePort I previously defined in the services, so:
Ingress for the app:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: app-ingress-backend
namespace: default
labels:
app: app
tier: backend
track: latest
site: web
annotations:
nginx.ingress.kubernetes.io/limit-connections: "8"
spec:
rules:
- host: app dot domain dot com
http:
paths:
- backend:
serviceName: app
servicePort: 80
Ingress for the api:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: app-ingress-backend-api
namespace: default
labels:
app: app
tier: backend
track: latest
site: api
annotations:
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-methods: "PUT, GET, POST, DELETE, PATCH, HEAD, OPTIONS"
nginx.ingress.kubernetes.io/cors-allow-origin: "http://app dot domain dot com"
nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
nginx.ingress.kubernetes.io/limit-connections: "8"
spec:
rules:
- host: api dot domain dot com
http:
paths:
- backend:
serviceName: api
servicePort: 90
Then I started testing this from my host machine. My Cluster IP is 192.168.64.2 and I can resolve the names for both of the hostnames from it:
$ nslookup app dot domain dot com 192.168.64.2
Server: 192.168.64.2
Address: 192.168.64.2#53
Non-authoritative answer:
Name: app dot domain dot com
Address: 192.168.64.2
$ nslookup api dot domain dot com 192.168.64.2
Server: 192.168.64.2
Address: 192.168.64.2#53
Non-authoritative answer:
Name: api dot domain dot com
Address: 192.168.64.2
And here comes the thing: I CAN access to the app:80 service directly from my host machine with this setup, but I cannot see the api:90 service, connection is refused every single time.
I’m trying with
curl http://app dot domain dot com (OK)
and
curl http://api dot domain dot com:90 (REFUSED)
I also did a telnet to each of the ports and hosts, also to the clusterIP, to determine if the port is open to the world and I got this
telnet 192.168.64.2 80 (OK)
telnet 192.168.64.2 90 (REFUSED)
So the port 90 is NOT accessible, but I don’t know how to change this on the ingress or elsewhere in the cluster configuration. I am using Minikube on MacOS X, and I have enabled both “ingress” and “ingress-nginx” with the default configuration.
So, my question is: how can I access the api:90 service from outside the cluster?
I’ve unsuccessfully tried to get both services accessible from the same ingress by defining something like having a SINGLE ingress with both services defined via hosts, like so:
(so, modify the first of the ingress and have this spec section instead and remove the second one):
spec:
rules:
- host: app dot domain dot com
http:
paths:
- backend:
serviceName: app
servicePort: 80
- host: api dot domain dot com
http:
paths:
- backend:
serviceName: api
servicePort: 90
but this also didn’t worked.either.
Cluster information:
Kubernetes version:
minikube v1.6.2 on Darwin 10.15.3
? Automatically selected the ‘hyperkit’ driver (alternates: [virtualbox])
?? Creating hyperkit VM (CPUs=2, Memory=8192MB, Disk=20000MB) …
?? Preparing Kubernetes v1.17.0 on Docker ‘19.03.5’ …
?? Pulling images …
?? Launching Kubernetes …
? Waiting for cluster to come online …
?? Done! kubectl is now configured to use “minikube”
? ingress was successfully enabled
? ingress-dns was successfully enabled
Cloud being used: bare-metal (local to the host machine)
Installation method: brew install minikube
Host OS: MacOS X Catalina
CNI and version: ? (I don’t know how to get this)
CRI and version: ? (I don’t know how to get this)