I have a simple REST app I want to deploy into kubernetes. Before I deploy into a cloud provider environment, I want to test out locally using minikube
. Here's my setup:
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: example
spec:
replicas: 3
selector:
matchLabels:
name: example
template:
metadata:
labels:
name: example
spec:
containers:
- name: application
image: 1ijk/example
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
name: example
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 3000
selector:
name: example
and how I'm invoking it
$ minikube start --driver=hyperkit
[ output omitted ]
$ kubectl apply -f deployment.yml
deployment.apps/example created
ingress.extensions/example-ingress created
$ kubectl get service example
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
example NodePort 10.100.198.224 <none> 3000:32275/TCP 4s
minikube service example --url
http://192.168.64.2:32275
$ minikube service example
|-----------|---------|-------------|---------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|---------|-------------|---------------------------|
| default | example | http/80 | http://192.168.64.2:31726 |
|-----------|---------|-------------|---------------------------|
Opening service default/example in default browser...
However the browser is unable to connect. I've verified the application binary and its container image both function properly. I seem to be missing a piece of the kubernetes setup on minikube, and all the tutorials I've seen assume a cloud deployment with the LoadBalancer
service type.
What can I do to test this simple kubernetes application locally using minikube
?
here's the service description
$ kubectl describe service example
Name: example
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"example","namespace":"default"},"spec":{"ports":[{"name":"http","...
Selector: name=example
Type: NodePort
IP: 10.107.95.114
Port: http 80/TCP
TargetPort: 3000/TCP
NodePort: http 31726/TCP
Endpoints:
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
after bypassing the yml file and using the cli to create the deployment and service like so
kubectl create deployment example --image=1ijk/example
kubectl expose deployment example --type=LoadBalancer --port=8080 --target-port=3000
I get the service set like so
$ kubectl describe service example
Name: example
Namespace: default
Labels: app=example
Annotations: <none>
Selector: app=example
Type: LoadBalancer
IP: 10.100.117.7
Port: <unset> 8080/TCP
TargetPort: 3000/TCP
NodePort: <unset> 31683/TCP
Endpoints: 172.17.0.10:3000,172.17.0.5:3000,172.17.0.7:3000
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
and same result
The problem was not with the kubernetes -- it was with my app! I made the mistake of binding the go server to "127.0.0.1:3000"
instead of ":3000"
:faceplam:. Binding to the port without specifying IP allows the application server to be accessible on all the containers networking interfaces :)
The endpoints of the service is not showing POD IPs.You need to expose pods via a LoadBalancer type service. Instead of using a service yaml use below command.
kubectl expose deployment example --type=LoadBalancer --port=8080 --target-port=3000
And then you can get the url via below command and use it browser to access the application.
minikube service example
Edit:
The go app had a hard-coded value for address which was bound to 127.0.0.1
.Because of the hardcoding it was not accessible from inside the cluster as well which was verified by curl to 10.100.117.7:3000
from another pod on the cluster.Removing that hardcoding solved the problem.