I'm trying kubernetes and making some progress, but I'm running into an issue with ingress when trying to make my hello world app publicly available.
SUCCESS WITH DEPLOYMENT AND SERVICE
I created a simple hello world
type of nodejs app and pushed the image to my docker hub johnlai2004/swarm2
. I successfully created a deployment and service with this yaml file:
nodejs.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nodejs-hello
labels:
app: nodejs-hello
spec:
replicas: 1
selector:
matchLabels:
app: nodejs-hello
template:
metadata:
labels:
app: nodejs-hello
spec:
containers:
- name: nodejs-hello
image: johnlai2004/swarm2
ports:
- containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
name: nodejs-hello-service
spec:
selector:
app: nodejs-hello
type: LoadBalancer
ports:
- protocol: TCP
port: 3000
targetPort: 3000
nodePort: 30000
I uploaded these files to a VPS with a new installation of ubuntu 20.04, minikube, kubectl and docker.
I ran the following commands and got the results I wanted:
minikube start --driver=docker
kubectl apply -f nodejs.yaml
minikube service nodejs-hello-service
|-----------|----------------------|-------------|---------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|----------------------|-------------|---------------------------|
| default | nodejs-hello-service | 3000 | http://192.168.49.2:30000 |
|-----------|----------------------|-------------|---------------------------|
When I do a wget http://192.168.49.2:30000
, I get an index.html
file that says hello from nodejs-hello-556dc868-6lrdz at 12/19/2021, 10:29:56 PM
. This is perfect.
FAILURE WITH INGRESS
Next, I want to use ingress so that I can see the page at http://website.example.com
(replace website.example.com
with the actual domain that points to my server). I put this file on my server:
nodejs-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nodejs-ingress
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: website.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nodejs-hello-service
port:
number: 3000
And I ran the commands
minikube addons enable ingress
kubectl apply -f nodejs-ingress.yaml
kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
nodejs-ingress <none> website.example.com localhost 80 15m
But when I visit http://website.example.com
with my browser, the browser says it can't connect. Using wget http://website.example.com
gave the same connection issue.
Can someone point out what I may have done wrong?
UPDATE
I ran these commands because I think it shows I didn't install ingress-controller in the right name space?
kubectl get pod -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create--1-tqsrp 0/1 Completed 0 4h25m
ingress-nginx-admission-patch--1-sth26 0/1 Completed 0 4h25m
ingress-nginx-controller-5f66978484-tmx72 1/1 Running 0 4h25m
kubectl get pod -n default
NAME READY STATUS RESTARTS AGE
nodejs-hello-556dc868-6lrdz 1/1 Running 0 40m
So does this mean my nodejs app is in a name space that doesn't have access to the ingress controller?
UPDATE 2
I also tried following this guide step by step:
Does this difference matter? I'm hosting things in a cloud vps called linode.com. Does that change the way I do things?
CodePudding user response:
The behaviour you have is expected. Let me explain why. Going point through point, and at the end I will present my tips.
First I think it's worth to present minikube architecture. I'm assuming you have installed minikube using default driver docker
as you have address 192.168.49.2
which is standard for docker
driver.
The layers are:
- your VM with Ubuntu 20.04
- Kubernetes cluster setup by minikube which is docker container with address
192.168.49.2
on the VM
So... you can not just run curl
on the VM using a localhost
address to connect to the service. The localhost
is referring to the device that you are making curl request (so your VM), not the docker container. That's why you need to use the 192.168.49.2
address.
You can type docker ps -a
, and you will see the container which is an actual Kubernetes cluster. You can exec into it using docker exec
command and then run curl
command with the localhost address:
user@example-ubuntu-minikube-template-1:~$ curl -H "Host: hello-world.info" localhost
curl: (7) Failed to connect to localhost port 80: Connection refused
user@example-ubuntu-minikube-template-1:~$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1a4ba3895990 gcr.io/k8s-minikube/kicbase:v0.0.28 "/usr/local/bin/entr…" 4 days ago Up 4 days 127.0.0.1:49157->22/tcp, 127.0.0.1:49156->2376/tcp, 127.0.0.1:49155->5000/tcp, 127.0.0.1:49154->8443/tcp, 127.0.0.1:49153->32443/tcp minikube
user@example-ubuntu-minikube-template-1:~$ docker exec -it 1a sh
# curl -H "Host: hello-world.info" localhost
Hello, world!
Version: 1.0.0
Hostname: web-79d88c97d6-nl4c7
Keep in mind that you can access this container only from the VM that is hosting this container. Without any further configuration it's you can't just access it from the other VMs. It is possible, but not recommended.
Good explanation in the minikube FAQ:
minikube’s primary goal is to quickly set up local Kubernetes clusters, and therefore we strongly discourage using minikube in production or for listening to remote traffic. By design, minikube is meant to only listen on the local network.
However, it is possible to configure minikube to listen on a remote network. This will open your network to the outside world and is not recommended. If you are not fully aware of the security implications, please avoid using this.
For the docker and podman driver, use
--listen-address
flag:minikube start --listen-address=0.0.0.0
So I'd avoid it. I will present a better possible solution at the end of the answer.
You asked:
But when I visit
http://website.example.com
with my browser, the browser says it can't connect. Usingwget http://website.example.com
gave the same connection issue.
Can someone point out what I may have done wrong?
Your computer does not know what it is website.example.com
. It's not aware that this name is used by your Ingress. If your computer does not find this name in hosts file it will start looking for this over the Internet.
So you have some possible solutions:
- use
curl -H 'HOST: website.example.com' http://192.168.49.2:80
- it will work only on the VM where is minikube - add host to the hosts file - something like
192.168.49.2 website.example.com
- it will work only on the VM where is minikube - Setup a bare-metal cluster (more details in the sum up section) and point the domain address to the VM address. In GCP and AWS you can do it using Google Cloud DNS or Amazon Route 53. On linode cloud maybe this one - DNS Manager ?
EDIT: You wrote that you have a domain pointed to the server, so please just check the sum up section of my answer.
Also you asked:
I ran these commands because I think it shows I didn't install ingress-controller in the right name space?
So does this mean my nodejs app is in a name space that doesn't have access to the ingress controller?
It will install the controller in the
ingress-nginx
namespace, creating that namespace if it doesn't already exist.
Also:
I also tried following this guide step by step: https://kubernetes.io/docs/tasks/access-application-cluster/ingress-minikube/
One difference I noticed was when I ran the command
kubectl get ingress
,ADDRESS
sayslocalhost
. But in the guide, it says it is supposed to be172.17.0.15
Does this difference matter? I'm hosting things in a cloud vps called linode.com. Does that change the way I do things?
It's also normal and expected when using minikube with a docker driver.
To sum up / other tips:
- Minkube is fine for local testing; you can easily access apps and services using from the host - check Accessing apps.
- However, for exposing it outside the network you should consider using solutions like kubeadm or kubespray for cluster setup MetalLB for LoadBalancer solution. Check "Bare-metal considerations" and Exposing a Kubernetes service on a bare-metal cluster over the external network architecture
- If you are planning to use your service with ingress, don't use LoadBalancer type. It's ok to use ClusterIP.
CodePudding user response:
Can you try kubectl get ingress nodejs-ingress
to see if the ingress resource is created successfully.
Then curl with curl -H 'HOST: <replace with HOSTS from the output of get ingress command>' http://<ADDRESS from the output of get ingress command>:<PORTS from the output of get ingress command>