Exposing simple pod using kubernetes ingress
Hi I'm learning kubernetes and I'm having trouble exposing the service. I want to route traffic to my cluster from HAProxy. I'm using my own bare-metal server.
EDIT: I've also created an ingress controller.
Now, when I describe my ingress I can see IP Address of worker machine but still I've got
Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
And no idea how to get access to my pod...
example config:
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: apache
labels:
app: apache-test
spec:
replicas: 1
selector:
matchLabels:
app: apache-test
template:
metadata:
labels:
app: apache-test
spec:
containers:
- name: apache
image: httpd
ports:
- containerPort: 80
service.yaml
apiVersion: v1
kind: Service
metadata:
name: apache-test-service
spec:
selector:
app: apache-test
ports:
- protocol: TCP
port: 80
targetPort: 80
name: http
ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: apache-test-ingress
spec:
rules:
- host: apache-test.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: apache-test-service
port:
number: 80
What's wrong?
describe ingress:
Name: apache-test-ingress
Namespace: default
Address: 192.168.6.72
Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
Host Path Backends
---- ---- --------
apache-test
/ apache-test-service:80 (10.44.0.1:80)
Annotations: <none>
Events: <none>
describe service:
Name: apache-test-service
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=apache-test
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.104.63.167
IPs: 10.104.63.167
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.44.0.1:80
Session Affinity: None
Events: <none>
describe controller:
Name: ingress-nginx-controller-55bc4f5576-vpsgb
Namespace: ingress-nginx
Priority: 0
Node: kubernetes-node02/192.168.6.72
Start Time: Sun, 16 May 2021 16:47:26 +0200
Labels: app.kubernetes.io/component=controller
app.kubernetes.io/instance=ingress-nginx
app.kubernetes.io/name=ingress-nginx
pod-template-hash=55bc4f5576
Annotations: <none>
Status: Running
IP: 10.36.0.1
IPs:
IP: 10.36.0.1
Controlled By: ReplicaSet/ingress-nginx-controller-55bc4f5576
Containers:
controller:
Container ID: docker://7daf566a039aba0d06f856b0adcc03659423ec2462c33d9a79f820b58dfcbf98
Image: k8s.gcr.io/ingress-nginx/controller:v0.46.0@sha256:52f0058bed0a17ab0fb35628ba97e8d52b5d32299fbc03cc0f6c7b9ff036b61a
Image ID: docker-pullable://k8s.gcr.io/ingress-nginx/controller@sha256:52f0058bed0a17ab0fb35628ba97e8d52b5d32299fbc03cc0f6c7b9ff036b61a
Ports: 80/TCP, 443/TCP, 8443/TCP
Host Ports: 0/TCP, 0/TCP, 0/TCP
Args:
/nginx-ingress-controller
--election-id=ingress-controller-leader
--ingress-class=nginx
--configmap=$(POD_NAMESPACE)/ingress-nginx-controller
--validating-webhook=:8443
--validating-webhook-certificate=/usr/local/certificates/cert
--validating-webhook-key=/usr/local/certificates/key
State: Running
Started: Sun, 16 May 2021 16:47:28 +0200
Ready: True
Restart Count: 0
Requests:
cpu: 100m
memory: 90Mi
Liveness: http-get http://:10254/healthz delay=10s timeout=1s period=10s #success=1 #failure=5
Readiness: http-get http://:10254/healthz delay=10s timeout=1s period=10s #success=1 #failure=3
Environment:
POD_NAME: ingress-nginx-controller-55bc4f5576-vpsgb (v1:metadata.name)
POD_NAMESPACE: ingress-nginx (v1:metadata.namespace)
LD_PRELOAD: /usr/local/lib/libmimalloc.so
Mounts:
/usr/local/certificates/ from webhook-cert (ro)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-ftnfs (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
webhook-cert:
Type: Secret (a volume populated by a Secret)
SecretName: ingress-nginx-admission
Optional: false
kube-api-access-ftnfs:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: Burstable
Node-Selectors: kubernetes.io/os=linux
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events: <none>
logs from POD doesn't show anything... logs from ingress controller:
I0516 14:47:28.871207 8 flags.go:208] "Watching for Ingress" class="nginx"
W0516 14:47:28.871287 8 flags.go:213] Ingresses with an empty class will also be processed by this Ingress controller
W0516 14:47:28.872068 8 client_config.go:614] Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work.
I0516 14:47:28.872594 8 main.go:241] "Creating API client" host="https://10.96.0.1:443"
I0516 14:47:28.887394 8 main.go:285] "Running in Kubernetes cluster" major="1" minor="21" git="v1.21.0" state="clean" commit="cb303e613a121a29364f75cc67d3d580833a7479" platform="linux/amd64"
I0516 14:47:29.768986 8 main.go:105] "SSL fake certificate created" file="/etc/ingress-controller/ssl/default-fake-certificate.pem"
I0516 14:47:29.772688 8 main.go:115] "Enabling new Ingress features available since Kubernetes v1.18"
W0516 14:47:29.775841 8 main.go:127] No IngressClass resource with name nginx found. Only annotation will be used.
I0516 14:47:29.793896 8 ssl.go:532] "loading tls certificate" path="/usr/local/certificates/cert" key="/usr/local/certificates/key"
I0516 14:47:29.829161 8 nginx.go:254] "Starting NGINX Ingress controller"
I0516 14:47:29.848934 8 event.go:282] Event(v1.ObjectReference{Kind:"ConfigMap", Namespace:"ingress-nginx", Name:"ingress-nginx-controller", UID:"0cf6bc98-71b3-4387-a535-7d3dcb956fc8", APIVersion:"v1", ResourceVersion:"401441", FieldPath:""}): type: 'Normal' reason: 'CREATE' ConfigMap ingress-nginx/ingress-nginx-controller
I0516 14:47:30.936661 8 event.go:282] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"default", Name:"apache-test-ingress", UID:"6e3c5757-28cf-4a68-be98-827fd69ee86f", APIVersion:"networking.k8s.io/v1beta1", ResourceVersion:"400092", FieldPath:""}): type: 'Normal' reason: 'Sync' Scheduled for sync
I0516 14:47:31.030103 8 nginx.go:296] "Starting NGINX process"
I0516 14:47:31.030266 8 leaderelection.go:243] attempting to acquire leader lease ingress-nginx/ingress-controller-leader-nginx...
I0516 14:47:31.030658 8 nginx.go:316] "Starting validation webhook" address=":8443" certPath="/usr/local/certificates/cert" keyPath="/usr/local/certificates/key"
I0516 14:47:31.031274 8 controller.go:146] "Configuration changes detected, backend reload required"
I0516 14:47:31.040799 8 leaderelection.go:253] successfully acquired lease ingress-nginx/ingress-controller-leader-nginx
I0516 14:47:31.041189 8 status.go:84] "New leader elected" identity="ingress-nginx-controller-55bc4f5576-vpsgb"
I0516 14:47:31.054203 8 status.go:204] "POD is not ready" pod="ingress-nginx/ingress-nginx-controller-55bc4f5576-vpsgb" node="kubernetes-node02"
I0516 14:47:31.129614 8 controller.go:163] "Backend successfully reloaded"
I0516 14:47:31.129922 8 controller.go:174] "Initial sync, sleeping for 1 second"
I0516 14:47:31.130053 8 event.go:282] Event(v1.ObjectReference{Kind:"Pod", Namespace:"ingress-nginx", Name:"ingress-nginx-controller-55bc4f5576-vpsgb", UID:"16d9fca9-8ac9-4fc1-be40-056540857035", APIVersion:"v1", ResourceVersion:"401513", FieldPath:""}): type: 'Normal' reason: 'RELOAD' NGINX reload triggered due to a change in configuration
I0516 14:48:31.054140 8 status.go:284] "updating Ingress status" namespace="default" ingress="apache-test-ingress" currentValue=[] newValue=[{IP:192.168.6.72 Hostname: Ports:[]}]
I0516 14:48:31.067947 8 event.go:282] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"default", Name:"apache-test-ingress", UID:"6e3c5757-28cf-4a68-be98-827fd69ee86f", APIVersion:"networking.k8s.io/v1beta1", ResourceVersion:"401625", FieldPath:""}): type: 'Normal' reason: 'Sync' Scheduled for sync
describe POD
Name: apache-67487b7c8b-8jbgb
Namespace: default
Priority: 0
Node: kubernetes-node01/192.168.6.71
Start Time: Sun, 16 May 2021 15:13:07 +0200
Labels: app=apache-test
pod-template-hash=67487b7c8b
Annotations: <none>
Status: Running
IP: 10.44.0.1
IPs:
IP: 10.44.0.1
Controlled By: ReplicaSet/apache-67487b7c8b
Containers:
apache:
Container ID: docker://70e4e3c4e01dffa11aa3c945f297e2cf3bc8af249c8d900c8aa30381ce7f56e6
Image: httpd
Image ID: docker-pullable://httpd@sha256:e4c2b93c04762468a6cce6d507d94def02ef4dc285278d0d926e09827f4857db
Port: 80/TCP
Host Port: 0/TCP
State: Running
Started: Sun, 16 May 2021 15:13:10 +0200
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-c8dfx (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
kube-api-access-c8dfx:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events: <none>
EDIT: I used an ingress controller:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.46.0/deploy/static/provider/baremetal/deploy.yaml
Solution 1:
TL;DR
Instead of using the port of 80
/443
, you should use the ports that are associated with the Service
of type NodePort
that you've created during the Ingress controller
provisioning.
$ kubectl get services -n
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.233.39.209 <none> 80:30983/TCP,443:32636/TCP 4h30m
ingress-nginx-controller-admission ClusterIP 10.233.54.211 <none> 443/TCP 4h30m
In this example, you should use the IP address of one of your Nodes
and the corresponding port (when trying to connect to it from outside):
-
curl http://IP_ADDRESS:30983
orcurl -v -k https://IP_ADDRESS:32636
Explanation
Focusing on the part of the YAML
manifest that you've used:
- https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.46.0/deploy/static/provider/baremetal/deploy.yaml
# Source: ingress-nginx/templates/controller-service.yaml
apiVersion: v1
kind: Service
metadata:
annotations:
labels:
<-- REDACTED -->
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
type: NodePort # <-- IMPORTANT
ports:
- name: http
port: 80
protocol: TCP
targetPort: http
- name: https
port: 443
protocol: TCP
targetPort: https
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/component: controller
When you applied the whole manifest you've created a Service
of type NodePort
.
Citing the official documentation:
NodePort
: Exposes the Service on each Node's IP at a static port (theNodePort
). AClusterIP
Service, to which theNodePort
Service routes, is automatically created. You'll be able to contact theNodePort
Service, from outside the cluster, by requesting<NodeIP>:<NodePort>
.-- Kubernetes.io: Docs: Concepts: Services networking: Service: Publishing services service types
Type Nodeport
If you set the
type
field toNodePort
, the Kubernetes control plane allocates a port from a range specified by--service-node-port-range
flag (default: 30000-32767). Each node proxies that port (the same port number on every Node) into your Service. Your Service reports the allocated port in its.spec.ports[*].nodePort
field.-- Kubernetes.io: Docs: Concepts: Services networking: Service: Nodeport
This NodePort
is the entrypoint for your Ingress
controller. You will need to send a request to it's ports to contact your Ingress
controller (and then Ingress
controller will route the traffic accordingly to the Ingress
resource).
You can check to which port you should send the traffic to by invoking (previously mentioned):
$ kubectl get services -n
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.233.39.209 <none> 80:30983/TCP,443:32636/TCP 4h30m
ingress-nginx-controller-admission ClusterIP 10.233.54.211 <none> 443/TCP 4h30m
In this example it should be following:
-
curl http://IP_ADDRESS:30983
forHTTP
-
curl -v -k https://IP_ADDRESS:32636
forHTTPS
If you would like to expose your Nginx Ingress
controller on a port 80
/443
you could opt to use Service
of type LoadBalancer
that is backed with:
- Metallb.universe.tf
Metallb
will allow you to create a pool of IP address that will be available for allocation for Service
of type LoadBalancer
.
A side note!
Please remember that with the
Ingress
resource you've specified, you should send a request with aHost: apache-test.com
otherwise you will get a404
. For testing purposes you can set:
- host:
instead of:- host: apache-test.com
Addressing following part of the question:
Now, when I describe my ingress I can see IP Address of worker machine but still I've got
Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
And no idea how to get access to my pod...
This won't limit your ability to connect to your Services
as this is a resource to send the traffic to when it doesn't match any of the rules in the Ingress
resource.
Additional resources:
- Kubernetes.github.io: Ingress nginx: User guide: Default backend
- Kubernetes.io: Docs: Concepts: Services networking: Service