How to deploy a Kubernetes service using NodePort on Amazon AWS?

3/19/2020

I have created a cluster on AWS EC2 using kops consisting of a master node and two worker nodes, all with public IPv4 assigned.

Now, I want to create a deployment with a service using NodePort to expose the application to the public.

After having created the service, I retrieve the following information, showing that it correctly identified my three pods:

nlykkei:~/projects/k8s-examples$ kubectl describe svc hello-svc
Name:                     hello-svc
Namespace:                default
Labels:                   app=hello
Annotations:              kubectl.kubernetes.io/last-applied-configuration:
                            {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app":"hello"},"name":"hello-svc","namespace":"default"},"spec"...
Selector:                 app=hello-world
Type:                     NodePort
IP:                       100.69.62.27
Port:                     <unset>  8080/TCP
TargetPort:               8080/TCP
NodePort:                 <unset>  30001/TCP
Endpoints:                100.96.1.5:8080,100.96.2.3:8080,100.96.2.4:8080
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

However, when I try to visit any of my public IPv4's on port 30001, I get no response from the server. I have already created a Security Group allowing all ingress traffic to port 30001 for all of the instances.

Everything works with Docker Desktop for Mac, and here I notice the following service field not present in the output above:

LoadBalancer Ingress:     localhost

I've already studied https://kubernetes.io/docs/concepts/services-networking/service/, and think that NodePort should serve my needs?

Any help is appreciated!

-- Shuzheng
amazon-web-services
cloud
kubernetes

1 Answer

4/15/2020

So you want to have a service able to be accessed from public. In order to achieve this I would recommend to create a ClusterIP service and then an Ingress for that service. So, saying that you have the deployment hello-world serving at 8081 you will then have the following two objects:

Service:

apiVersion: v1
kind: Service
metadata:
  name: hello-world
labels:
  app: hello-world
spec:
  ports:
  - name: service
    port: 8081(or whatever you want)
    protocol: TCP
    targetPort: 8080 (here goes the opened port in your pods)
  selector:
    app: hello-world
  type: ClusterIP

Ingress:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  labels:
    app: hello-world
  name: hello-world
spec:
  rules:
  - host: hello-world.mycutedomainname.com
    http:
      paths:
      - backend:
          serviceName: hello-world
          servicePort: 8081 (or whatever you have set for the service port)
        path: /

Note: the name tag in the service's port is optional.

-- Bryan Calvo Benoit
Source: StackOverflow