Kubernetes Ingress with AWS ALB Controller - kubernetes

I am using an EKS cluster and deployed AWS Load Balancer Controller for ingress. Using a dummy application (taken Nginx image) deployed one service. Just for the test, I am trying to access the same service from 3 different ingress paths: / and /foo/ and /bar/
AWS is successfully provisioning an ALB while ingress kubernetes object is getting deployed.
I am able to access the dummy application (Nginx homepage) by hitting external ALB on path '/'.
http://alb-dns/ # it's opening the Nginx homepage
But http://alb-dns/foo/ and http://alb-dns/bar/ are throwing "404 Not Found" error.
I searched through the internet and probably the issue is with URL rewrite. But the problem is, AWS ALB Controller does not support URL rewrite.
I tried lot of options mentioned in the below links but none of them works:
https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.2/guide/ingress/annotations/#actions
https://github.com/kubernetes-sigs/aws-load-balancer-controller/issues/835
Is there any alternative to URL redirect? How do I get Nginx Homepage using http://alb-dns/foo/ url?
Or it's better to dump AWS LB Controller and move to Nginx Controller?
Thanks in advance.
These are Kubernetes manifests I am using:
---
# Source: game-app/templates/game-app-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: ns-fargate-app
labels:
app.kubernetes.io/name: sample-game-app
---
# Source: game-app/templates/game-app-service.yaml
apiVersion: v1
kind: Service
metadata:
namespace: ns-fargate-app
name: game-app-service
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
type: NodePort
selector:
app.kubernetes.io/name: sample-game-app
---
# Source: game-app/templates/game-app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: ns-fargate-app
name: sample-game-app
spec:
selector:
matchLabels:
app.kubernetes.io/name: sample-game-app
replicas: 3
template:
metadata:
labels:
app.kubernetes.io/name: sample-game-app
spec:
containers:
- image: public.ecr.aws/nginx/nginx:1.21
imagePullPolicy: Always
name: sample-game-app
ports:
- containerPort: 80
# Source: game-app-ingress/templates/game-app-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: ns-fargate-app
name: game-app-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
kubernetes.io/ingress.class: alb
spec:
rules:
- http:
paths:
- path: /foo/
pathType: Prefix
backend:
service:
name: game-app-service
port:
number: 80
- path: /bar/
pathType: Prefix
backend:
service:
name: game-app-service
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: game-app-service
port:
number: 80
AWS ALB (Active)
Three ALB Rules
http:/alb-dns**/** (Working fine)
http:/alb-dns**/foo** (Throwing 404 error)

See https://kubernetes.io/docs/concepts/services-networking/ingress/#the-ingress-resource.
Prefix / matches all paths.
Your paths /foo/ and /bar/ are redundant in game-app-ingress.yaml. Does your Nginx instance respond to /foo/ or /bar/? If not, that's why you're getting the 404.
See Add context path for an app on nginx for adding additional contexts to your Nginx instance for /foo/ and /bar/.
Since game-app-service has the root path, you can remove the paths for /foo/ and /bar/.

Related

EKS cluster is not showing my an IP on the Ingress controller

I am new to K8S so please be gentle. I have a test hello world Flask app and I would like to deploy it on EKS. I am using the AWS load Balancer Controller Addon using the link below. At the end when I check the deployment it shows up without any issues as the link describes.
https://docs.aws.amazon.com/eks/latest/userguide/aws-load-balancer-controller.html
When I apply the three files below they all apply correctly and I see the pods up, but on the ingress I dont see an external IP address and cant access my Flask app.
My goal is to have AWS create a dummy DNS name and then I can point my public DNS name to it as an CNAM entry. Also the Ingress should be in port 80 and then that should forward to port 5000 for the Flask app internally.
What am I missing?
Could someone please point me in the right direction?
ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: "flask-test-ingress"
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
labels:
app: hello-world
spec:
rules:
- host: testing.somesite.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: "hello-world-service"
port:
number: 80
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-world
spec:
selector:
matchLabels:
app: hello-world
replicas: 2
template:
metadata:
labels:
app: hello-world
spec:
containers:
- name: hello-world
image: gitlab.privaterepo.com:5050/jmartinez/flask_helloworld:v4
ports:
- containerPort: 5000
protocol: TCP
imagePullSecrets:
- name: regcred
service.yaml
apiVersion: v1
kind: Service
metadata:
name: hello-world-service
spec:
selector:
app: hello-world
type: NodePort
ports:
- protocol: "TCP"
port: 80
targetPort: 5000
nodePort: 30000
Finally got it working. When I realized that the ALB was not created automatically I researched and found the solution. I had to remove the ingress.class value from the annotations as well as remove the host. So now my ingress looks like the following. After deleting the old ingress and reapplying this one, I waited about 10 minutes and my hello world app is now running.
ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: "flask-test-ingress"
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
labels:
app: hello-world
spec:
ingressClassName: alb
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: "hello-world-service"
port:
number: 80

GKE Ingress with Multiple Backend Services returns 404

I'm trying to create a GKE Ingress that points to two different backend services based on path. I've seen a few posts explaining this is only possible with an nginx Ingress because gke ingress doesn't support rewrite-target. However, this Google documentation, GKE Ingresss - Multiple backend services, seems to imply otherwise. I've followed the steps in the docs but haven't had any success. Only the service that is available on the path prefix of / is returned. Any other path prefix, like /v2, returns a 404 Not found.
Details of my setup are below. Is there an obvious error here -- is the Google documentation incorrect and this is only possible using nginx ingress?
-- Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
kubernetes.io/ingress.global-static-ip-name: app-static-ip
networking.gke.io/managed-certificates: app-managed-cert
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- path: /v2
pathType: Prefix
backend:
service:
name: api-2-service
port:
number: 8080
-- Service 1
apiVersion: v1
kind: Service
metadata:
name: api-service
labels:
app: api
spec:
type: NodePort
selector:
app: api
ports:
- port: 80
targetPort: 5000
-- Service 2
apiVersion: v1
kind: Service
metadata:
name: api-2-service
labels:
app: api-2
spec:
type: NodePort
selector:
app: api-2
ports:
- port: 8080
targetPort: 5000
GCP Ingress supports multiple paths. This is also well described in Setting up HTTP(S) Load Balancing with Ingress. For my test I've used both Hello-world v1 and v2.
There are 3 possible issues.
Issue is with container ports opened. You can check it using netstat:
$ kk exec -ti first-55bb869fb8-76nvq -c container -- bin/sh
/ # netstat -plnt
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 :::8080 :::* LISTEN 1/hello-app
Issue might be also caused by the Firewall configuration. Make sure you have proper settings. (In general, in the new cluster I didn't need to add anything but if you have more stuff and have specific Firewall configurations it might block).
Misconfiguration between port, containerPort and targetPort.
Below my example:
1st deployment with
apiVersion: apps/v1
kind: Deployment
metadata:
name: first
labels:
app: api
spec:
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: container
image: gcr.io/google-samples/hello-app:1.0
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: api-service
labels:
app: api
spec:
type: NodePort
selector:
app: api
ports:
- port: 5000
targetPort: 8080
2nd deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: second
labels:
app: api-2
spec:
selector:
matchLabels:
app: api-2
template:
metadata:
labels:
app: api-2
spec:
containers:
- name: container
image: gcr.io/google-samples/hello-app:2.0
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: api-2-service
labels:
app: api-2
spec:
type: NodePort
selector:
app: api-2
ports:
- port: 6000
targetPort: 8080
Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 5000
- path: /v2
pathType: Prefix
backend:
service:
name: api-2-service
port:
number: 6000
Outputs:
$ curl 35.190.XX.249
Hello, world!
Version: 1.0.0
Hostname: first-55bb869fb8-76nvq
$ curl 35.190.XX.249/v2
Hello, world!
Version: 2.0.0
Hostname: second-d7d87c6d8-zv9jr
Please keep in mind that you can also use Nginx Ingress on GKE by adding specific annotation.
kubernetes.io/ingress.class: "nginx"
Main reason why people use nginx ingress on GKE is using rewrite annotation and possibility to use ClusterIP or NodePort as serviceType, where GCP ingress allows only NodePort serviceType.
Additional information you can find in GKE Ingress for HTTP(S) Load Balancing

How to manage 'link forwarding' for a website inside a kubernetes cluster

I have a website that uses relative href links (eg. the link directs to "/login", rather than "http://somesite.com/login"). This works A-OK in a normal server but I'd like to use the website inside a docker container as part of a kubernetes cluster. My goal is to have multiple replicas of the website to manage high load times, defaulting to two nodes with dynamic scaling.
I set us the service as a 'loadbalancer' as follows:
apiVersion: v1
kind: Service
metadata:
name: websiteservice
spec:
selector:
app: websiteapp
type: LoadBalancer
ports:
- protocol: TCP
port: 80
targetPort: 80
The issue here is that if I navigate to the URL of the load balancer (that's automatically created at my host - digital ocean) then although the homepage of the website loads, any other pages give me a 404 because rather than loading the "/login" page of the container it loads the "/login" page of the load balancer which doesn't exist. How can I configure my cluster or load balancer to forward all subdirectories (anything after the .com) to the webserver?
EDIT 1
In comments I was advised to set up ingress. I think I've done so with this change to my yaml:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: test-ingress
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: somesite.co.uk
http:
paths:
- backend:
serviceName: websiteservice
servicePort: 80
---
apiVersion: v1
kind: Service
metadata:
name: websiteservice
spec:
selector:
app: websiteapp
type: ClusterIP
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: websiteapp
spec:
replicas: 2
selector:
matchLabels:
app: websiteapp
template:
metadata:
labels:
app: websiteapp
spec:
containers:
- name: websiteapp
image: mydocker.co.uk/websiteimg
imagePullSecrets:
- name: regcred
nodeSelector:
beta.kubernetes.io/instance-type: s-2vcpu-4gb
But I'm still not able to navigate beyond the home page of my website.
Your Ingress file should look like this:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: test-ingress
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: somesite.co.uk
http:
paths:
- path: /*
backend:
serviceName: websiteservice
servicePort: 80
Simply you have add path to redirect traffic.
Take a look: host-path-routing, ingress-path-matching.

K3s traefik ingress returns gateway timeout

I am currently playing around with a rpi based k3s cluster and I am observing a weird phenomenon.
I deployed two applications.
The first one is nginx which I can reach on the url http://external-ip/foo based on the following ingress rule:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: foo
namespace: foo
annotations:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/rule-type: "PathPrefixStrip"
traefik.ingress.kubernetes.io/rewrite-target: "/"
spec:
rules:
- http:
paths:
- path: /foo
backend:
serviceName: foo-service
servicePort: 8081
And the other one is grafana which I cannot reach on the url http://external-ip/grafana based on the below ingress rule:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: grafana
namespace: grafana
annotations:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/rule-type: "PathPrefixStrip"
traefik.ingress.kubernetes.io/rewrite-target: "/"
spec:
rules:
- http:
paths:
- path: /grafana
backend:
serviceName: grafana-service
servicePort: 3000
When I do a port-forward directly on the pod I can reach the grafana app, when I use the port-forward on the grafana service it also works.
However as soon as I try to reach it through the subpath I will get a gateway timeout.
Does anyone have a guess what I am missing?
Here the deployment and service for the grafana deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: grafana
namespace: grafana
labels:
app: grafana
tier: frontend
service: monitoring
spec:
selector:
matchLabels:
app: grafana
tier: frontend
template:
metadata:
labels:
app: grafana
tier: frontend
service: monitoring
spec:
containers:
- image: grafana
imagePullPolicy: IfNotPresent
name: grafana
envFrom:
- configMapRef:
name: grafana-config
ports:
- name: frontend
containerPort: 3000
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: grafana-service
namespace: grafana
labels:
app: grafana
tier: frontend
service: monitoring
spec:
selector:
app: grafana
tier: frontend
type: NodePort
ports:
- name: frontend
port: 3000
protocol: TCP
targetPort: 3000
Solution
I had to add the following two parameters to my configmap to make it work:
GF_SERVER_ROOT_URL=http://localhost:3000/grafana/
GF_SERVER_FROM_SUB_PATH=true
As I mentioned in comments grafana is not listening on / like default nginx.
There is related github issue about this, and if you want to make it work you should specify root_url
grafana.ini:
server:
root_url: https://subdomain.example.com/grafana
Specifically take a look at this and this comment.
#tehemaroo add his own solution which include changing root url and sub_path in configmap
I had to add the following two parameters to my configmap to make it work:
GF_SERVER_ROOT_URL=http://localhost:3000/grafana/
GF_SERVER_FROM_SUB_PATH=true
And related documentation about that
To serve Grafana behind a sub path:
Include the sub path at the end of the root_url.
Set serve_from_sub_path to true.
[server]
domain = example.com
root_url = %(protocol)s://%(domain)s:%(http_port)s/grafana/
serve_from_sub_path = true

externally access the application using hostname/subdomain in ingress resource

Need to access the application from external using Ingress hostname/sub-domain for the application that is specified in the below code. eg. test-app.dev-cluster-poc.company.domain.
cat app-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
namespace: ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
name: app-ingress
spec:
rules:
- host: test-app.dev-cluster-poc.company.domain
http:
paths:
- backend:
serviceName: appsvc1
servicePort: 80
path: /app1
- backend:
serviceName: appsvc2
servicePort: 80
path: /app2
While troubleshooting using steps in the url, I found that there is no ADDRESS in the "kubectl get ingress" output. expecting an ip address like below.
but, I am seeing like below, 3rd column is empty.
what are the necessary configuration required to externally access the application like registering the hostname(test-app.dev-cluster-poc.company.domain) or adding A-record or running any dns service in the kubernetes cluster.
what is causing the ADDRESS column empty in "kubectl get ingress" command.
[EDIT]
apiVersion: v1
kind: Service
metadata:
name: appsvc1
namespace: ingress
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: app1
Nginx controller service like below.
cat nginx-ingress-controller-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-ingress
namespace: ingress
spec:
type: NodePort
ports:
- port: 80
nodePort: 30000
name: http
- port: 18080
nodePort: 32000
name: http-mgmt
selector:
app: nginx-ingress-lb
1.you can deploy an ingress deployment
2.expose your ingress deployment through port 80
kubectl expose deploy your-deployment-name --port 80
source
3.you can add ingressClassName in your deploy
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
namespace: ingress
spec:
ingressClassName: nginx
ingress configuration sample