Kubernetes Services Architecture - nginx

I'm trying to connect have NGINX direct traffic to different parts of my app through the config file, but I can't figure it out for the life of me. Here is my current setup:
http-service (loadbalancer)
NGINX (port 80)
website-service (10.27.246.107, port 8000, targetPort 8000, selector 'run: website')
website (label 'run: website', containerPort 8000)
NGINX Conf
upstream website{
server 10.27.246.107:8000
}
This is a normal nginx pod using containerPort 80 at the moment.
Am I going about this the right way?

The best way to rout traffic to different part of your application is using Ingress. In Ingress, you can describe all your paths into all parts of your application. It will look like:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test
annotations:
ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /foo
backend:
serviceName: website1
servicePort: 80
- path: /bar
backend:
serviceName: website2
servicePort: 3368
Actually, Ingress-controller is based on Nginx, but anyway you can choose another engine, for example, HAproxy.
Ingress was designed for using in Kubernetes and it has more features in Kubernetes. For example, your website upstream should be described as a service in Kubernetes:
kind: Service
apiVersion: v1
metadata:
name: website1
spec:
selector:
app: python-web-site
ports:
- protocol: TCP
port: 80
targetPort: 8080
Anyway, you can route traffic by Nginx and expose it to the world, but the best practice is to uses Ingress in Kubernetes.

Related

Kubernetes Ingress - is the Ingress definition required for TCP also or only for HTTP/HTTPS traffic?

I have defined my service app running on port 9000. It is not web/http server it is simply just a service application running as windows service on that port to which other apps connect to (outside the container).
So I have defined Port 9000 in my service definition and in my config map definition. We are using NGINX as a proxy for accessing from outside and everything works.
Nginx Service:
- name: 9000-tcp
nodePort: 30758
port: 9000
protocol: TCP
targetPort: 9000
Config Map:
apiVersion: v1
data:
"9000": default/frontarena-ads-aks-test:9000
kind: ConfigMap
Service definition:
apiVersion: v1
kind: Service
metadata:
name: frontarena-ads-aks-test
spec:
type: ClusterIP
ports:
- protocol: TCP
port: 9000
selector:
app: frontarena-ads-aks-test
Ingress definition:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ads-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
rules:
- http:
paths:
- path: /
backend:
serviceName: frontarena-ads-aks-test
servicePort: 9000
As mentioned everything works. I know that TCP is used for L4 layer and HTTP for L7 Application Layer.
I need to access my app from another app solely by its hostname and port. Without any HTTP Url.
So basically does it mean that I do NOT need actually my Ingress Controller definition at all?
I do not need to deploy it at all?
I would only need it if I need HTTP access with some URL for example: hostname:port/pathA or hostname:port/pathB
Is that correct? For regular TCP connection we do not need at all our Ingress YAML definition? Thank you
Yes, you don't need ingress at all in this case. According to kubernetes official doc, Ingress is:
An API object that manages external access to the services in a cluster, typically HTTP.
So, if you don't need any external access via http, you can omit ingress.
Ref: https://kubernetes.io/docs/concepts/services-networking/ingress/

Kubernetes Nginx Ingress partial ssl termination

I'd like to split incoming traffic in Kubernetes Nginx in the following way:
Client --> Nginx --> {Service A, Service B}
The problem I am facing is Service A is an internal service and does not support HTTPS therefore SSL should be terminated for Service A. On the other hand, Service B is an external service (hosted on example.com) and only works over HTTPS.
I cannot manage to get this work easily with Kubernetes Nginx. Here is what I have come with:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-proxy
annotations:
nginx.ingress.kubernetes.io/backend-protocol: HTTPS
nginx.ingress.kubernetes.io/upstream-vhost: example.com
spec:
tls:
- hosts:
- proxy.com
secretName: secret
rules:
- host: proxy.com
http:
paths:
- path: /api/v1/endpoint
backend:
serviceName: service-a
servicePort: 8080
- path: /
backend:
serviceName: service-b
servicePort: 443
kind: Service
apiVersion: v1
metadata:
name: service-b
namespace: default
spec:
type: ExternalName
externalName: service-b.external
ports:
- port: 443
I have got a route for service-b.external:443 to point to example.com.
This solution only works if service-b is over HTTPS, but in my case, I cannot change to HTTPS for this service because of some other internal dependencies.
My problem is the backend-protocol annotation works for the whole kind and I cannot define it per path.
P.S: I am using AWS provider
Following the suggested solution and question from comments.
Yes, like mentioned below it is possible to have two ingress items. In your case
only one should have backend-protocol in it.
According to nginx ingress documentation:
Basic usage - host based routingĀ¶
ingress-nginx can be used for many use cases, inside various cloud provider and supports a lot of configurations. In this section you can find a common usage scenario where a single load balancer powered by ingress-nginx will route traffic to 2 different HTTP backend services based on the host name.
First of all follow the instructions to install ingress-nginx. Then imagine that you need to expose 2 HTTP services already installed: myServiceA, myServiceB. Let's say that you want to expose the first at myServiceA.foo.org and the second at myServiceB.foo.org. One possible solution is to create two ingress resources:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-myservicea
annotations:
# use the shared ingress-nginx
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: myservicea.foo.org
http:
paths:
- path: /
backend:
serviceName: myservicea
servicePort: 80
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-myserviceb
annotations:
# use the shared ingress-nginx
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: myserviceb.foo.org
http:
paths:
- path: /
backend:
serviceName: myserviceb
servicePort: 80
When you apply this yaml, 2 ingress resources will be created managed by the ingress-nginx instance. Nginx is configured to automatically discover all ingress with the kubernetes.io/ingress.class: "nginx" annotation. Please note that the ingress resource should be placed inside the same namespace of the backend resource.
On many cloud providers ingress-nginx will also create the corresponding Load Balancer resource. All you have to do is get the external IP and add a DNS A record inside your DNS provider that point myServiceA.foo.org and myServiceB.foo.org to the nginx external IP. Get the external IP by running:
kubectl get services -n ingress-nginx
It is also possible to have separate nginx classes as mentioned here.

kubernetes-how to subdomain localhost using nginx ingress controller?

I want to have 2 apps running on kubernetes, I wonder if I can do 2 subdomains using nginx ingress controller.
For example: app1.localhost:8181/cxf and app2.localhost:8181/cxf
each one of those will have diferent services.
How can I do that?
Some more context here:
EDIT:
Note:mysql is working fine so im not posting the yaml's here so it doesn't get too long.
Note too that im using karaf with a kar.(that will be my app)
I was thinking that maybe I should have 2 nodes? one with mysql and app1 and the other one with mysql and app2? so in one I could access app1.localhost/cxf services and in the other app2.localhost/cxf services... maybe doesn't make much sense... and I was reading that I need kubeadm for that, and there is no way to install it on windows. I think I must use minikube for that instead?
These are my yaml's:
The load balancer:
apiVersion: v1
kind: Service
metadata:
name: lb-service
spec:
type: LoadBalancer
selector:
app: app1
ports:
- protocol: TCP
name: app1
port: 3306
targetPort: 3306
- protocol: TCP
name: app1-8080
port: 8080
targetPort: 8080
- protocol: TCP
name: app1-8101
port: 8101
targetPort: 8101
- protocol: TCP
name: app1-8181
port: 8181
targetPort: 8181
status:
loadBalancer:
ingress:
- hostname: localhost
app1:
apiVersion: v1
kind: Service
metadata:
name: app1-service
spec:
ports:
- port: 8101
selector:
app: app1
clusterIP: None
---
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: app1-deployment
spec:
selector:
matchLabels:
app: app1
replicas: 1
template:
metadata:
labels:
app: app1
spec:
containers:
- name: app1
image: app1:latest
app2: is the same as app1 but in a diferent version(older services)
ingress-resource:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: apps-ingress
#annotations:
#nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: app1.localhost # tried app1.127-0-0-1.sslip.io ass answered below too.
http:
paths:
- path: /
backend:
serviceName: app1-service
servicePort: 8181
- host: app2.localhost
http:
paths:
- path: /
backend:
serviceName: app2-service
servicePort: 8181
I should be able to access app1 version in app1.localhost:8181/cxf, and app2 version in app2.localhost:8181/cxf
There is another doubt I have, shouldn't I be able to create another loadBalancer? I wanted to, so the selector would be app2 in that loadBalancer, but since I already have one, the new one just stays <pending> until I remove the first one.
That would make some sense, since if I have 2 replicas if app1, and 2 replicas of app2, there should be a loadBalancer for each app right?
Note that I installed the nginx ingress-controller using helm too, since the ingress-resource would not work otherwise, at least thats what I have read.
By installing that, it installed nginx load balancer too, and this one didnt go to pending. Do I need to use nginx loadBalancer? or can I delete it and use kubernetes type loadBalancer?
Huum, im missing something here...
Thanks for your time!
I want to have 2 apps running on kubernetes, I wonder if I can do 2 subdomains using nginx ingress controller.
Yes, you just need any number of DNS records which point to your Ingress controller's IP (you used 127.0.0.1, so that's what I'll use for these examples, but you can substitute whatever IP is relevant). That's the whole point of an Ingress resource: to use the host: header to dispatch requests into the cluster
I found a list of wildcard DNS providers of which I confirmed that app1.127-0-0-1.sslip.io and app2.127-0-0-1.sslip.io do as expected
Thus:
kind: Ingress
metadata:
name: app1-and-2
spec:
rules:
- host: app1.127-0-0-1.sslip.io
http:
paths:
- path: /
backend:
serviceName: app1-backend
servicePort: 8181 # <-- or whatever your Service port is
# then you can repeat that for as many hosts as you wish
- host: app2.127-0-0-1.sslip.io
http:
paths:
- path: /
backend:
serviceName: app2-backend
servicePort: 8181

How add nginx-ingress custom health check behind a nginx reverse proxy

I have a nginx server outside kubernetes. nginx -> nginx ingress. I want know how add a custom health check path /health/status to nginx ingress.
This question is almost certainly solving the wrong problem, but in the spirit of answering what was asked:
You can expose the Ingress /healthz to the outside world:
kind: Service
metadata:
name: ingress-nginx-health
spec:
type: ClusterIP
selector: # whatever
ports:
- name: healthz
port: 80
targetPort: 10254
---
kind: Ingress
spec:
rules:
- host: elb-1234.example.com
http:
path: /healthz
backend:
serviceName: ingress-nginx-health
servicePort: healthz
Because if your Ingress controller falls over, it will for sure stop answering its own healthz check

How do I map multiple services to one Kubernetes Ingress path?

How do I set a Kubernentes Ingress and Controller to essentially do what the following nginx.conf file does:
upstream backend {
server server1.example.com weight=5;
server server2.example.com:8080;
server backup1.example.com:8080 backup;
}
I want one http endpoint to map to multiple Kubernetes services with a preference for a primary one but also have a backup one. (For my particular project, I need to have multiple services instead of one service with multiple pods.)
Here's my attempted ingress.yaml file. I'm quite certain that the way I'm listing the multiple backends is incorrect. How would I do it? And how do I set the "backup" flag?
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: fanout-ingress
annotations:
ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: "nginx"
# kubernetes.io/ingress.global-static-ip-name: "kubernetes-ingress"
spec:
rules:
- http:
paths:
- path: /
backend:
serviceName: server1
servicePort:
- path: /
backend:
serviceName: server2
servicePort: 8080
- path: /
backend:
serviceName: backup1
servicePort: 8080
I'm running Kubernetes on GKE.
You can do simple fanout based on path or name based virtual hosting.
However, you'd need to distinguish based on something (other than port, since it's an Ingress), so your two options would be virtual host or path.
Paths will not work with some services that expect a standard path. Judging based on your example you'd most likely want to have something like a.example.com and b.example.com. Here's the example from the Kubernetes docs:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: foo.bar.com
http:
paths:
- backend:
serviceName: service1
servicePort: 80
- host: bar.foo.com
http:
paths:
- backend:
serviceName: service2
servicePort: 80
Kubernetes Ingress is incapable of this.
You could create a new service that targets server1, server2 and backup1 and use that in the Ingress. But the backends will be used in a round robin fashion.
You can create a Deployment and a Service of (stateless) nginx reverse proxies with the config you wish and use that in Ingress.

Resources