I'm attempting to set up my own bare-metal Kubernetes cluster composed of a control plane (VPS 149.62.186.95) and a worker node (VPS 149.62.189.139). Both my VPS are running Ubuntu 22.04 with 2 vCPUs and 4GB vRAM.
After installing Kubernetes (kubeadm
) on both, I ran the following commands on my control plane:
kubeadm init
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# Weave deamonset
kubectl apply -f https://github.com/weaveworks/weave/releases/download/v2.8.1/weave-daemonset-k8s.yaml
# baremetal nginx ingress
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/baremetal/deploy.yaml
I edited my DNS records as follows:
- registry.rottigni.tech -> 149.62.186.95 (control plane)
- sandbox.rottigni.tech -> 149.62.186.95 (control plane)
I generated SSL certs for these domains on my control plane and stored them in Kubernetes secrets.
Then, I applied my changes using kubectl apply -R -f . inside my repository. Here's the most relevant file, ingress.yml:
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: nginx-ingress-class
spec:
controller: k8s.io/ingress-nginx
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: lr-labs-ingress
namespace: lr-labs
annotations:
# cert-manager.io/issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
ingressClassName: nginx-ingress-class
tls:
- hosts:
- registry.rottigni.tech
secretName: registry-ssl
- hosts:
- sandbox.rottigni.tech
secretName: sandbox-ssl
rules:
- host: registry.rottigni.tech
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: registry-rottigni
port:
number: 5000
- host: sandbox.rottigni.tech
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: sandbox-rottigni
port:
number: 80
At this point, everything seems to be working on the kubectl side, according to the following output:
Every 2.0s: kubectl get pods,deploy,svc,ing,endpoints,node -A
NAMESPACE NAME READY STATUS RESTARTS AGE
ingress-nginx pod/ingress-nginx-admission-create-wn7xr 0/1 Completed 0 7h58m
ingress-nginx pod/ingress-nginx-admission-patch-dtzxf 0/1 Completed 0 7h58m
ingress-nginx pod/ingress-nginx-controller-86968d59df-vdv9f 1/1 Running 0 6h52m
kube-system pod/coredns-5dd5756b68-h4jwb 1/1 Running 0 7h58m
kube-system pod/coredns-5dd5756b68-jrsdq 1/1 Running 0 7h58m
kube-system pod/etcd-epsilon-rottigni-tech 1/1 Running 0 7h58m
kube-system pod/kube-apiserver-epsilon-rottigni-tech 1/1 Running 0 7h58m
kube-system pod/kube-controller-manager-epsilon-rottigni-tech 1/1 Running 0 7h58m
kube-system pod/kube-proxy-4v8bc 1/1 Running 0 7h58m
kube-system pod/kube-proxy-8hpjj 1/1 Running 0 7h57m
kube-system pod/kube-scheduler-epsilon-rottigni-tech 1/1 Running 0 7h58m
kube-system pod/weave-net-gvzk5 2/2 Running 1 (7h58m ago) 7h58m
kube-system pod/weave-net-tbr92 2/2 Running 0 7h57m
lr-labs pod/registry-rottigni-5c6cfd877f-qqxsw 1/1 Running 0 7h54m
lr-labs pod/sandbox-rottigni-9668f7447-dv7js 1/1 Running 0 7h54m
NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE
ingress-nginx deployment.apps/ingress-nginx-controller 1/1 1 1 7h58m
kube-system deployment.apps/coredns 2/2 2 2 7h58m
lr-labs deployment.apps/registry-rottigni 1/1 1 1 7h54m
lr-labs deployment.apps/sandbox-rottigni 1/1 1 1 7h54m
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 7h58m
ingress-nginx service/ingress-nginx-controller NodePort 10.108.71.135 <none> 80:32095/TCP,443:30221/TCP 7h58m
ingress-nginx service/ingress-nginx-controller-admission ClusterIP 10.107.203.218 <none> 443/TCP 7h58m
kube-system service/kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 7h58m
lr-labs service/registry-rottigni NodePort 10.106.231.17 <none> 5000:31673/TCP 7h54m
lr-labs service/sandbox-rottigni NodePort 10.111.173.239 <none> 80:31607/TCP 7h54m
NAMESPACE NAME CLASS HOSTS ADDRESS PORTS AGE
lr-labs ingress.networking.k8s.io/lr-labs-ingress nginx-ingress-class registry.rottigni.tech,sandbox.rottigni.tech 149.62.189.139 80, 443 7h54m
NAMESPACE NAME ENDPOINTS AGE
default endpoints/kubernetes 149.62.186.95:6443 7h58m
ingress-nginx endpoints/ingress-nginx-controller 10.44.0.2:443,10.44.0.2:80 7h58m
ingress-nginx endpoints/ingress-nginx-controller-admission 10.44.0.2:8443 7h58m
kube-system endpoints/kube-dns 10.32.0.2:53,10.32.0.3:53,10.32.0.2:53 + 3 more... 7h58m
lr-labs endpoints/registry-rottigni 10.44.0.3:5000 7h54m
lr-labs endpoints/sandbox-rottigni 10.44.0.1:80 7h54m
NAMESPACE NAME STATUS ROLES AGE VERSION
node/epsilon-rottigni-tech Ready control-plane 7h58m v1.28.2
node/zeta-rottigni-tech Ready <none> 7h57m v1.28.2
One strange thing is that my ingress has IP 149.62.189.139, which is my worker node IP (not control plane IP). Is this the correct behavior?
Despite this, I'm unable to reach my services from the public DNS through my nginx ingress controller. I can, however, correctly reach both services using NodePort from my control plane and worker node SSH sessions, eliminating any application errors.
It appears that my ingress isn't facing the internet on the correct IP. I also checked my ingress-nginx-controller logs, which seem fine:
-------------------------------------------------------------------------------
NGINX Ingress controller
Release: v1.9.5
Build: f503c4bb5fa7d857ad29e94970eb550c2bc00b7c
Repository: https://github.com/kubernetes/ingress-nginx
nginx version: nginx/1.21.6
-------------------------------------------------------------------------------
W0105 14:11:47.972914 7 client_config.go:618] Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work.
I0105 14:11:47.973187 7 main.go:205] "Creating API client" host="https://10.96.0.1:443"
I0105 14:11:47.983447 7 main.go:249] "Running in Kubernetes cluster" major="1" minor="28" git="v1.28.5" state="clean" commit="506050d61cf291218dfbd41ac93913945c9aa0da" platform="linux/amd64"
I0105 14:11:48.470371 7 main.go:101] "SSL fake certificate created" file="/etc/ingress-controller/ssl/default-fake-certificate.pem"
I0105 14:11:48.511293 7 ssl.go:536] "loading tls certificate" path="/usr/local/certificates/cert" key="/usr/local/certificates/key"
I0105 14:11:48.529226 7 nginx.go:260] "Starting NGINX Ingress controller"
I0105 14:11:48.539963 7 event.go:298] Event(v1.ObjectReference{Kind:"ConfigMap", Namespace:"ingress-nginx", Name:"ingress-nginx-controller", UID:"a5edeb27-12a0-4576-ab70-19d8cffb4dfe", APIVersion:"v1", ResourceVersion:"338", FieldPath:""}): type: 'Normal' reason: 'CREATE' ConfigMap ingress-nginx/ingress-nginx-controller
I0105 14:11:49.635029 7 store.go:440] "Found valid IngressClass" ingress="lr-labs/lr-labs-ingress" ingressclass="nginx-ingress-class"
I0105 14:11:49.636090 7 event.go:298] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"lr-labs", Name:"lr-labs-ingress", UID:"5663167b-9b94-4cb6-8670-5e5e1076bfaa", APIVersion:"networking.k8s.io/v1", ResourceVersion:"1159", FieldPath:""}): type: 'Normal' reason: 'Sync' Scheduled for sync
I0105 14:11:49.638242 7 backend_ssl.go:67] "Adding secret to local store" name="lr-labs/registry-ssl"
I0105 14:11:49.641278 7 backend_ssl.go:67] "Adding secret to local store" name="lr-labs/sandbox-ssl"
I0105 14:11:49.731218 7 nginx.go:303] "Starting NGINX process"
I0105 14:11:49.731681 7 leaderelection.go:245] attempting to acquire leader lease ingress-nginx/ingress-nginx-leader...
I0105 14:11:49.732611 7 nginx.go:323] "Starting validation webhook" address=":8443" certPath="/usr/local/certificates/cert" keyPath="/usr/local/certificates/key"
I0105 14:11:49.733509 7 controller.go:190] "Configuration changes detected, backend reload required"
I0105 14:11:49.736538 7 status.go:84] "New leader elected" identity="ingress-nginx-controller-685dff585b-2s8jp"
I0105 14:11:49.849528 7 controller.go:210] "Backend successfully reloaded"
I0105 14:11:49.849813 7 controller.go:221] "Initial sync, sleeping for 1 second"
I0105 14:11:49.850019 7 event.go:298] Event(v1.ObjectReference{Kind:"Pod", Namespace:"ingress-nginx", Name:"ingress-nginx-controller-86968d59df-vdv9f", UID:"7ac8215f-175f-4496-90a1-dd63d6acad4e", APIVersion:"v1", ResourceVersion:"6819", FieldPath:""}): type: 'Normal' reason: 'RELOAD' NGINX reload triggered due to a change in configuration
I0105 14:12:41.662980 7 status.go:84] "New leader elected" identity="ingress-nginx-controller-86968d59df-vdv9f"
I0105 14:12:41.663007 7 leaderelection.go:255] successfully acquired lease ingress-nginx/ingress-nginx-leader
10.32.0.1 - - [05/Jan/2024:14:36:35 +0000] "GET / HTTP/1.1" 400 248 "-" "curl/7.81.0" 81 0.000 [] [] - - - - 479859864f23ba0523fb9c29c1932d56
10.32.0.1 - - [05/Jan/2024:14:38:30 +0000] "GET / HTTP/1.1" 308 164 "-" "curl/7.81.0" 85 0.000 [lr-labs-sandbox-rottigni-80] [] - - - - e262c16d9495ef00f412f0ba73dbb453
10.32.0.1 - - [05/Jan/2024:15:25:27 +0000] "GET / HTTP/1.1" 308 164 "-" "curl/7.81.0" 85 0.000 [lr-labs-sandbox-rottigni-80] [] - - - - 9b662b33bb59be1846863af658f251ab
10.32.0.1 - - [05/Jan/2024:16:08:32 +0000] "GET / HTTP/1.1" 308 164 "-" "curl/7.81.0" 85 0.000 [lr-labs-sandbox-rottigni-80] [] - - - - a54eda51703800c9a1726a9e1187988d
I even see some manually initiated curl requests for debugging directly to the nginx service using the Host HTTP header.
Additionally here my working curl commands to my cluster service resources:
root@epsilon-rottigni-tech:~/k8s.rottigni.tech/k8s# kubectl get svc -A
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8h
ingress-nginx ingress-nginx-controller NodePort 10.108.71.135 <none> 80:32095/TCP,443:30221/TCP 8h
ingress-nginx ingress-nginx-controller-admission ClusterIP 10.107.203.218 <none> 443/TCP 8h
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 8h
lr-labs registry-rottigni NodePort 10.106.231.17 <none> 5000:31673/TCP 8h
lr-labs sandbox-rottigni NodePort 10.111.173.239 <none> 80:31607/TCP 8h
root@epsilon-rottigni-tech:~/k8s.rottigni.tech/k8s# curl 10.106.231.17:5000
root@epsilon-rottigni-tech:~/k8s.rottigni.tech/k8s# curl 10.108.71.135:80
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
root@epsilon-rottigni-tech:~/k8s.rottigni.tech/k8s# curl 10.108.71.135:443
<html>
<head><title>400 The plain HTTP request was sent to HTTPS port</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<center>The plain HTTP request was sent to HTTPS port</center>
<hr><center>nginx</center>
</body>
</html>
root@epsilon-rottigni-tech:~/k8s.rottigni.tech/k8s# curl 10.111.173.239:80
<html>
<head>
<style>
html {
background: url(./Cheddar.jpg) no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
h1 {
font-family: Arial, Helvetica, sans-serif;
background: rgba(187, 187, 187, 0.5);
width: 6em;
padding: 0.5em 1em;
margin: 1em;
}
</style>
</head>
<body>
<h1>Cheddar</h1>
</body>
</html>root@epsilon-rottigni-tech:~/k8s.rottigni.tech/k8s#
Could someone please help me debug this problem? Am I missing an important step for this kind of production deployment?
Thank you everybody!
UPDATE:
Given the following situation:
kubectl get svc,ing -A
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 23h
ingress-nginx service/ingress-nginx-controller NodePort 10.108.71.135 <none> 80:32095/TCP,443:30221/TCP 23h
ingress-nginx service/ingress-nginx-controller-admission ClusterIP 10.107.203.218 <none> 443/TCP 23h
kube-system service/kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 23h
lr-labs service/registry-rottigni NodePort 10.106.231.17 <none> 5000:31673/TCP 23h
lr-labs service/sandbox-rottigni NodePort 10.111.173.239 <none> 80:31607/TCP 23h
NAMESPACE NAME CLASS HOSTS ADDRESS PORTS AGE
lr-labs ingress.networking.k8s.io/lr-labs-ingress nginx-ingress-class registry.rottigni.tech,sandbox.rottigni.tech 149.62.189.139 80, 443 23h
I am able to reach nginx from internet like this:
But I can't like this:
- curl -k https://sandbox.rottigni.tech
- curl -k http://sandbox.rottigni.tech