K8s metallb load balancer IP not reachable sometimes - kubernetes

I have on-premise k8s cluster with 3 masters and 4 workers. Metallb is installed and DHCP is provided for him from the same network as on-premise cluster IPs.
I tried to start Kubernetes Dashboard app in the cluster and everything is working fine except LoadBalancer type of Service of Kubernetes Dashboard:
apiVersion: v1
metadata:
annotations:
metallb.universe.tf/address-pool: single-ip
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
type: LoadBalancer
ports:
- port: 443
targetPort: 8443
selector:
k8s-app: kubernetes-dashboard
externalIPs:
- 192.168.1.129
root#master1:/# kubectl get services -n kubernetes-dashboard
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dashboard-metrics-scraper ClusterIP 10.249.40.230 <none> 8000/TCP 6h8m
kubernetes-dashboard LoadBalancer 10.249.3.22 192.168.1.129 443:32593/TCP 6h8m
After applying all configs dashboard is starting to work at https://192.168.1.129 from cluster and from my computer correctly.
But after some time stopped to work from my computer but continue to work from cluster. From my computer I'm getting "Connection refused error".
From my computer and from cluster 192.168.1.129 IP is pinging normally without any problems.
externalTrafficPolicy is Cluster by default. Changing it to Local didn't help.
What's happening? How to resolve issue when service working and then stopping to work and then again starting to work? :)

Related

Minikube have no external ipaddress

I am running my minikube as docker image.
I am trying to expose my service to outside world using Nodeport.
This is my yaml file.
apiVersion: apps/v1
kind: Deployment
metadata:
name: docker-hello-world
labels:
app: docker-hello-world
spec:
selector:
matchLabels:
app: docker-hello-world
replicas: 3
template:
metadata:
labels:
app: docker-hello-world
spec:
containers:
- name: docker-hello-world
image: scottsbaldwin/docker-hello-world:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: docker-hello-world-svc
spec:
selector:
app: docker-hello-world
ports:
- port: 8088
targetPort: 80
type: NodePort
Searched a lot about nodePort that we require node ip to access the service.
I am able to access my service using minikube service docker-hello-world-svc --url
which gives me url to access the service http://127.0.0.1:52526 but here port number is different then the nodePort.
My service is successful running .
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
docker-hello-world-svc NodePort 10.109.146.181 <none> 8088:30934/TCP 65m
i want to access my service from outside the cluster using Nodeport but my nodes does not have any external ip
kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
minikube Ready control-plane 5h9m v1.24.3 192.168.49.2 <none> Ubuntu 20.04.4 LTS 5.10.104-linuxkit docker://20.10.17
already read out that i need ingress controller to access service but i wanna test it using nodePort .
Any work around so i can access my service using only nodePort running inside the minikube which is running as docker image?
Status of minikube does not show kubectl
>>minikube status
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
You don't need an external IP when using NodePort, you can use minikube ip to get the minikube node address, and then connect to the respective nodePort:
$ kubectl svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
docker-hello-world-svc NodePort 10.108.66.235 <none> 8088:31550/TCP 2m15s
$ minikube ip
192.168.49.2
$ curl 192.168.49.2:31550
<h1>Hello webhook world from: docker-hello-world-cc79bf486-k4lm8</h1>
Another alternative is to use a LoadBalancer service, and use minikube tunnel to connect to it using the internal port:
$ kubectl svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
docker-hello-world-svc LoadBalancer 172.16.58.95 172.16.58.95 8088:32624/TCP 10s
$ curl 172.16.58.95:8088
<h1>Hello webhook world from: docker-hello-world-cc79bf486-dg5s9</h1>
Notes:
You will only get an EXTERNAL-IP after running minikube tunnel in a separate terminal (it's a foreground process)
I recommend that you run Minikube using a less common IP range for the services, preventing conflicts with other network routes:
minikube start --service-cluster-ip-range=172.16.0.0/16
You can use port forwarding with kubeclt. kubectl port-forward allows using resource name, such as a pod name, to select a matching pod to port forward to.
kubectl port-forward svc/resource-name 4000:5000

Kubernetes service URL not responding to API call

I've been following multiple tutorials on how to deploy my (Spring Boot) api on Minikube. I already got it (user-service running on 8081) working in a docker container with an api gateway (port 8080) and eureka (port 8087), but for starters I just want it to run without those. Steps I took:
Push docker container or image (?) to docker hub, I don't know the proper term.
Create a deployment.yaml:
apiVersion: v1
kind: Service
metadata:
name: kwetter-service
spec:
type: LoadBalancer
selector:
app: kwetter
ports:
- protocol: TCP
port: 8080
targetPort: 8081
nodePort: 30070
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kwetter-deployment
labels:
app: kwetter
spec:
replicas: 1
selector:
matchLabels:
app: kwetter
template:
metadata:
labels:
app: kwetter
spec:
containers:
- name: user-api
image: cazhero/s6-kwetter-backend_user:latest
ports:
- containerPort: 8081 #is the port it runs on when I manually start it up
kubectl apply -f deployment.yaml
minikube service kwetter-service
It takes me to an empty site with url: http://192.168.49.2:30070 which I thought I could use to make API calls to, but apparently not. How do I make api calls to my application running on minikube?
Get svc returns:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4d4h
kwetter-service LoadBalancer 10.106.42.56 <pending> 8080:30070/TCP 4d
describe svc kwetter-service:
Name: kwetter-service
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=kwetter
Type: NodePort
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.106.42.56
IPs: 10.106.42.56
Port: <unset> 8080/TCP
TargetPort: 8081/TCP
NodePort: <unset> 30070/TCP
Endpoints: 172.17.0.4:8081
Session Affinity: None
External Traffic Policy: Cluster
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Type 6s service-controller LoadBalancer -> NodePort
Made an Ingress in the yaml, used kubectl get ing:
NAME CLASS HOSTS ADDRESS PORTS AGE
kwetter-ingress <none> * 80 49m
To make some things clear:
You need to have pushed your docker image cazhero/s6-kwetter-backend_user:latest to docker hub, check that at https://hub.docker.com/, in your personal repository.
What's the output of minikube service kwetter-service, does it print the URL http://192.168.49.2:30070?
Make sure your pod is running correctly by the following minikube command:
# check pod status
minikube kubectl -- get pods
# if the pod is running, check its container logs
minikube kubectl -- logs po kwetter-deployment-xxxx-xxxx
I see that you are using LoadBalancer service, where a LoadBalancer service is the standard way to expose a service to the internet. With this method, each service gets its own IP address.
Check external IP
kubectl get svc
Use the external IP and the port number in this format to access the
application.
http://REPLACE_WITH_EXTERNAL_IP:8080
If you want to access the application using Nodeport (30070), use the Nodeport service instead of LoadBalancer service.
Refer to this documentation for more information on accessing applications through Nodeport and LoadBalancer services.

istio unable to access kubernetes dashboard

I am trying to access the Kubernetes Dashboard through an Istio Gateway + Virtual Service.
However, all I get is 404 page not found when I try to access the dashboard with browser. Accessing the Dashboard through k8s NodePort or k8s LoadBalancer service works just as expected. The pod, however, complains in the logs about http: TLS handshake error from 127.0.0.6:52483: remote error: tls: bad certificate.
Running httpbin through Istio (as given in their documentation) works as expected, so Istio seem to be working fine as well.
I am using the official Kubernetes Dashboard YAML-s. I am giving the service below (with type: LoadBalancer added, although it doesn't seem to make a difference for Istio, although it allows me to access the Dashboard through a separate IP).
Just for the record, my k8s cluster is comprised of VirtualBox machines running MetalLB.
kubectl get services --all-namespaces returns the following:
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 11d
httpbin httpbin ClusterIP 10.100.186.188 <none> 8000/TCP 47h
istio-system istio-egressgateway ClusterIP 10.109.231.163 <none> 80/TCP,443/TCP 5d3h
istio-system istio-ingressgateway LoadBalancer 10.111.188.94 192.168.56.46 15021:31440/TCP,80:31647/TCP,443:32715/TCP 5d3h
istio-system istiod ClusterIP 10.104.236.247 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 5d3h
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 11d
kubernetes-dashboard dashboard-metrics-scraper ClusterIP 10.101.131.136 <none> 8000/TCP 43h
kubernetes-dashboard kubernetes-dashboard-service LoadBalancer 10.103.130.244 192.168.56.47 443:30041/TCP 43h
kubernetes-dashboard kubernetes-dashboard-service-np NodePort 10.100.49.224 <none> 8443:30002/TCP 43h
If I try to access the LoadBalancer directly via the IP from above and through browser, I get the usual Kubernetes Dashboard login page. The browser url is https://192.168.56.47.
YAML-s:
istio-gateway.yaml:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: kubernetes-dashboard-gateway
namespace: kubernetes-dashboard
spec:
selector:
istio: ingressgateway # use Istio default gateway implementation
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: PASSTHROUGH
hosts:
- "*"
istio-virtual-service.yaml:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: kubernetes-dashboard-virtual-service
namespace: kubernetes-dashboard
spec:
hosts:
- "*"
gateways:
- kubernetes-dashboard-gateway
tls:
- match:
- sniHosts: ["*"]
route:
- destination:
host: kubernetes-dashboard-service
port:
number: 443
dashboard-service.yaml:
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-service
namespace: kubernetes-dashboard
spec:
ports:
- port: 443
targetPort: 8443
# - port: 8000
# targetPort: 9090
selector:
k8s-app: kubernetes-dashboard
type: LoadBalancer
User suren has mentioned:
your gateway is listening 443. not 80
Yes, this could be a problem. You are trying to reach port 80, but you are exposing only port 443. Try to change your configuration or change your port during request.
See albo documentation about Deploy and Access the Kubernetes Dashboard.
Hm, I got it working with the configuration as above and with explicitly specifying a host in all places where I have previously placed a "*". I had to add that host in /etc/hosts to be able to access it in browser.
It seems that this last part was key, as well as specifying the sniHost in the Virtual Service. The other problems were mostly configuration issues with the TLS. Setting it to PASSTHROUGH seems to work, because it forces Istio to sort of forward the HTTPS request to the Kubernetes Dashboard, which is responsible for decrypting etc.

How should I use externalIPs on service with EKS?

I was trying to apply service externalIPs feature on EKS cluster.
What I do
I've created EKS cluster with eksctl:
eksctl create cluster --name=test --region=eu-north-1 --nodes=1
I've opened all security groups to make sure I don't have issue with firewall. ACL also allow all traffic.
I took public IP for the only available worker node and try to use it with simple service + deployment.
This should be only 1 deployment with 1 replicaset and 1 pod with nginx. This should be attached to a service with external/public IP everyone can reach.
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
replicas: 1
selector:
matchLabels:
app: app
template:
metadata:
labels:
app: app
spec:
containers:
- name: nginx
image: nginx
---
apiVersion: v1
kind: Service
metadata:
name: app
labels:
app: app
spec:
ports:
- port: 80
targetPort: 80
selector:
app: app
externalIPs:
- 13.51.55.82
When I apply it then everything seems to work just fine. I can port-forward my app service to localhost and I can see the output (kubectl port-forward svc/app 9999:80 -> curl localhost:9999).
But the problem is I cannot reach this service via public IP.
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
app ClusterIP 10.100.140.38 13.51.55.82 80/TCP 49m
kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 62m
$ curl 13.51.55.82:80
curl: (7) Failed to connect to 13.51.55.82 port 80: Connection refused
Thoughts
For me it looks like the service is not connected to node itself. When I ssh to the node and setup simple web server on port 80 it respond immediately.
I know I can use NodePort but in my case I want finally use fixed port 4000 and NodePort allow me only to use ports in range 30000-32768.
Question
I want to be able to curl my service via public IP on certain port below 30000 (NodePort doesn't apply).
How can I make it work with Kubernetes Service externalIPs on EKS cluster?
Edit I:
FYI: I do not want to use LoadBalancer.

Expose service on local kubernetes

I'm running a local kubernetes bundled with docker on Mac OS.
How can I expose a service, so that I can access the service via a browser on my Mac?
I've created:
a) deployment including apache httpd.
b) service via yaml:
apiVersion: v1
kind: Service
metadata:
name: apaches
spec:
selector:
app: web
type: NodePort
ports:
- protocol: TCP
port: 80
externalIPs:
- 192.168.1.10 # Network IP of my Mac
My service looks like:
$ kubectl get service apaches
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
apaches NodePort 10.102.106.158 192.168.1.10 80:31137/TCP 14m
I can locally access the service in my kubernetes cluster by wget $CLUSTER-IP
I tried to call http://192.168.1.10/ on my Mac, but it doesn't work.
This question deals to a similar issue. But the solution does not help, because I do not know which IP I can use.
Update
Thanks to Michael Hausenblas I worked out a solution using Ingress.
Nevertheless there are still some open questions:
What is the meaning of a service's externalIP? Why do I need an externalIP when I do not directly access a service from external?
What is the meaning of the service port 31137?
The kubernetes docs describe a method to [publish a service in minikube via NodePort][4]. Is this also possible with kubernetes bundled on docker?
There are several solutions to expose services in kubernetes:
http://alesnosek.com/blog/2017/02/14/accessing-kubernetes-pods-from-outside-of-the-cluster/
Here are my solutions according to alesnosek for a local kubernetes bundled with docker:
1. hostNetwork
hostNetwork: true
Dirty (the host network should not be shared for security reasons) => I did not check this solution.
2. hostPort
hostPort: 8086
Does not apply to services => I did not check this solution.
3. NodePort
Expose the service by defining a nodePort:
apiVersion: v1
kind: Service
metadata:
name: apaches
spec:
type: NodePort
ports:
- port: 80
nodePort: 30000
selector:
app: apache
4. LoadBalancer
EDIT
#MathObsessed posted the solution in his anwer.
5. Ingress
a. Install Ingress Controller
git clone https://github.com/jnewland/local-dev-with-docker-for-mac-kubernetes.git
kubectl apply -f nginx-ingress/namespaces/nginx-ingress.yaml -Rf nginx-ingress
b. Configure Ingress
kubectl apply -f apache-ing.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: apache-ingress
spec:
rules:
- host: localhost
http:
paths:
- path: /
backend:
serviceName: apaches
servicePort: 80
Now I can access my apache deployed with kubernetes by calling http://localhost/
Remarks for using local-dev-with-docker-for-mac-kubernetes
The repo simplifies the deployment of the offical ingress-nginx controller
For production use I would follow the official guide.
The repos ships with a tiny full featured ingress example. Very useful for getting quickly a working example application.
Further documentation
https://kubernetes.io/docs/concepts/services-networking/ingress
For those still looking for an answer. I've managed to achieve this by adding another Kube service just to expose my app to localhost calls (via browser or Postman):
kind: Service
apiVersion: v1
metadata:
name: apaches-published
spec:
ports:
- name: http
port: 8080
targetPort: 80
protocol: TCP
selector:
app: web
type: LoadBalancer
Try it now on: http://localhost:8080
Really simple example
METHOD1
$ kubectl create deployment nginx-dep --image=nginx --replicas=2
Get the pods
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-dep-5c5477cb4-76t9q 1/1 Running 0 7h5m
nginx-dep-5c5477cb4-9g84j 1/1 Running 0 7h5m
Access the pod using kubectl port
$ kubectl port-forward nginx-dep-5c5477cb4-9g84j 8888:80
Forwarding from 127.0.0.1:8888 -> 80
Forwarding from [::1]:8888 -> 80
Now do a curl to the localhost:8888
$ curl -v http://localhost:8888
METHOD2
You can expose port 80 of the deployment (where the application is runnin i.e. nginx port)
via a NodePort
$ kubectl expose deployment nginx-dep --name=nginx-dep-svc --type=NodePort --port=80
Get the service
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 31d
nginx-dep-svc NodePort 10.110.80.21 <none> 80:31239/TCP 21m
Access the deployment using hte NodePort
$ curl http://localhost:31239
As already mentioned in Matthias Ms answer there are several ways.
As the offical Kubernetes documentation specifically describes using a Service with a type NodePort I wanted to describe the workflow.
NodePort: Exposes the Service on each Node’s IP at a static port (the NodePort). A ClusterIP Service, to which the NodePort Service routes, is automatically created. You’ll be able to contact the NodePort Service, from outside the cluster, by requesting <NodeIP>:<NodePort>.
If you set the type field to NodePort, 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.
Setup a Service with a type of NodePort
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
clusterIP: 10.0.171.239
type: NodePort
Then you can check on which port the Service is exposed to via
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-service NodePort 10.103.218.215 <none> 9376:31040/TCP 52s
and access it via localhost using the exposed port. E.g.
curl http://localhost:31040