So I'm using Kubernetes for a side project and it's great. It's cheaper to run for a small project like the one I'm on (a small cluster of 3-5 instances gives me basically everything I need for ~$30/month on GCP).
The only area where I'm struggling is in trying to use the kubernetes Ingress resource to map into cluster and fan out to my microservices (they're small Go or Node backends). I have the configuration setup for the ingress to map to different services and there's no problem there.
I understand that you can really easily have GCP spin up a LoadBalancer when you create an ingress resource. This is fine, but it also represents another $20-ish/month that adds to the cost of the project. Once/if this thing gets some traction, that could be ignored, but for now and also for the sake of understanding Kubernetes better, I want to the do the following:
Is there any way this can even be done using Kubernetes and ingress resources?
Thanks!
Yes this is possible. Deploy your ingress controller, and deploy it with a NodePort service. Example:
---
apiVersion: v1
kind: Service
metadata:
name: nginx-ingress-controller
namespace: kube-system
labels:
k8s-app: nginx-ingress-controller
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 32080
protocol: TCP
name: http
- port: 443
targetPort: 443
nodePort: 32443
protocol: TCP
name: https
selector:
k8s-app: nginx-ingress-controller
Now, create an ingress with a DNS entry:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /
backend:
serviceName: my-app-service #obviously point this to a valid service + port
servicePort: 80
Now, assuming your static IP is attached to any kubernetes node running kube-proxy, have DNS updated to point to the static IP, and you should be able to visit myapp.example.com:32080
and the ingress will map you back to your app.
A few additional things:
If you want to use a lower port than 32080, then bear in mind if you're using CNI networking, you'll have trouble with hostport. It's recommend to have a load balancer listening on port 80, I guess you could just have nginx set up to do proxy pass, but it becomes difficult. This is why a load balancer with your cloud provider is recommended :)
TLDR: If you want to serve your website/webservice on ports below 3000, then no, it's not possible. If someone finds a way to do it, I'd be eager to know how.
The two main approaches I used while trying to serve on a port below 3000 included:
nginx-ingress
controller service to be of type NodePort
, listening on ports 80 and 443. However, this results in the following error:
Error: UPGRADE FAILED: Service "nginx-ingress-controller" is invalid:
spec.ports[0].nodePort: Invalid value: 80: provided port is not in the
valid range. The range of valid ports is 30000-32767
The way to work around this error is to change the --service-node-port-range
flag used when starting kube-apiserver
. However, this configuration cannot be accessed on GCP. If you'd like to try for yourself, you can check out the instructions here: Kubernetes service node port range
externalIP
attribute attached to a service
of type: ClusterIP
. At first glance, this would seem to be an ideal solution. However, there is a bug in the way that the externalIP
attribute works. It does not accept an external, static IP, but rather an internal, ephemeral IP. If you hardcode an internal, ephemeral IP in the externalIP
field, and then attach an external, static IP to one of the nodes in your cluster through the GCP Console, requests are successfully routed. However, this is not a viable solution because you've now hardcoded an ephemeral IP in your service
definition, so your website will inevitably go offline as the nodes' internal IPs change.If you are okay with serving on ports above 3000, see my instructions below.
I've tried removing my LoadBalancer, and this is the best solution I could come up with. It has the following flaws:
And the following benefits:
nginx-ingress
helm chart.ingress
, allowing complete control over how requests are routed to your services
based on the paths of the requests.Assuming you already have Helm installed (if you don't follow the steps here: Installing Helm on GKE), create an nginx-ingress
with a type
of NodePort
.
helm install \
--name nginx-ingress \
stable/nginx-ingress \
--set rbac.create=true \
--set controller.publishService.enabled=true \
--set controller.service.type=NodePort \
--set controller.service.nodePorts.http=30080 \
--set controller.service.nodePorts.https=30443
Create the ingress definition for your routing.
# my-ingress-resource.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: reverse-proxy
namespace: production # Namespace must be the same as that of target services below.
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "false" # Set to true once SSL is set up.
spec:
rules:
- http:
paths:
- path: /api
backend:
serviceName: backend
servicePort: 3000
- path: /
backend:
serviceName: frontend
servicePort: 80
Then install it with
kubectl apply -f my-ingress-resource.yaml
Find the tag of your cluster.
gcloud compute instances list
If your cluster instances have names like
gke-cluster-1-pool-1-fee097a3-n6c8
gke-cluster-1-pool-1-fee097a3-zssz
Then your cluster tag is gke-cluster-1-pool-1-fee097a3
.
Go to the GCP firewall page. Verify that you have the right project selected in the navbar.
Click "Create Firewall Rule". Give the rule a decent name. You can leave most of the settings as defaults, but past your cluster tag under "Target tags". Set the Source IP Ranges to 0.0.0.0/0
. Under Protocols and Ports, change "Allow all" to "Specified protocols and ports". Check the TCP box, and put 30080, 30443
in the input field. Click "Create".
Go to https://console.cloud.google.com/networking/addresses/ and click "Reserve Static Address". Give it a descriptive name, and select the correct region. After selecting the correct region, you should be able to click the "Attached to" dropdown and select one of your Kubernetes nodes. Click "Reserve".
After reserving the static IP, find out which static IP was granted by looking at the External IP Address list.
Copy it into your browser, then tack on a port (<your-ip>:30080
for HTTP or https://<your-ip>:30443
for HTTPS). You should see your webpage.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With