How to expose a Kubernetes service on a specific Nodeport?
Asked Answered
D

8

31

I have create a pod with the below yaml definition.

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: praveensripati/docker-demo:1.2
    ports:
    - containerPort: 3000

And now I expose the pod, which creates a service.

kubectl expose pod myapp-pod --type=NodePort

The port 3000 on the container is exposed to port 31728 on the nodes. And I am able to do access the page using curl on port 31728.

kubectl get service myapp-pod
NAME        TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
myapp-pod   NodePort   10.107.254.254   <none>        3000:31728/TCP   5s

This time I wanted to expose the service not a random port, but on port 80. And so I specify the port number as 80, by using --port. The service details are a bit odd. It says that port 80 on the container is exposed to port 31316 on the nodes. Also, I am able to access the page using curl on the random port (31316 in this case) and not port 80.

kubectl expose pod myapp-pod --type=NodePort --target-port=3000 --port=80

kubectl get service myapp-pod
NAME        TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
myapp-pod   NodePort   10.105.123.73   <none>        80:31316/TCP   12s

I am not able to expose a service on a specific port and not on a random port. I tried a few combinations and read the k8s documentation, but no success.

How do I expose a service on a specific port instead of a random port?

Detection answered 26/9, 2018 at 16:43 Comment(0)
D
3

I will try to answer your query here.

Also, I am able to access the page using curl on the random port (31316 in this case) and not port 80.

-- Because, kubernetes exposed the port 31316 on the host (maps to the service) and hence it can be accessed on host:31316.

-- Service port is visible only within the kubernetes cluster. You can exec into a pod container and do a curl on servicename:service port instead of the NodePort.

Note the terms - container port: the port container listens on. Service port: the port where kubernetes service is exposed on cluster internal ip and mapped to the container port. Nodeport: the port exposed on the host and mapped to kubernetes service.

Diesis answered 26/9, 2018 at 22:39 Comment(1)
See better answer a few posts below (by @Rico): https://mcmap.net/q/460683/-how-to-expose-a-kubernetes-service-on-a-specific-nodeportTolerance
N
43

Your question is about exposing the NodePort type of service on a specific port. For that you need to specify the nodePort field under ports in your service definition.

kind: Service
apiVersion: v1
metadata:
  name: my-service
spec:
  selector:
    app: myapp
  ports:
  - protocol: TCP
    port: 3000
    nodePort: 32321
  type: NodePort

Note that it has to be within a given range provided in the configs. Which defaults to 30000-32767. This range can be specified in the kube-apiserver configs using the --service-node-port-range option.

Nucleo answered 26/9, 2018 at 18:1 Comment(2)
I think this should be the accepted answer. Unless nodePort is specified in service definition yaml, k8s randomly allocates a port between 30000-32767. Also, note that, kubectl expose pod ... type=nodePort ... does not have an option to specify nodePort in its arguments. One has to create a definition file and then do a kubectl apply -fto get the desired port. Or do a kubectl patch after random assigment.Rivard
As the upvote number shows, this answer clearly addresses the OP's question.Tolerance
R
9

When an existing Dashboard service already exists, remove it.

kubectl delete service kubernetes-dashboard -n kube-system

Expose the Dashboard deployment as a NodePort.

kubectl expose deployment kubernetes-dashboard -n kube-system --type=NodePort

The above will assign a random port >= 30000. So use the Patch command to assign the port to a known, unused and desired port >= 30000.

kubectl patch service kubernetes-dashboard --namespace=kube-system --type='json' --patch='[{"op": "replace", "path": "/spec/ports/0/nodePort", "value":30000}]'

Caution: Never expose your dashboard publicly without authentication.

Reed answered 14/4, 2019 at 7:42 Comment(0)
H
8

If your cluster does not have a LoadBalancer Provider, you can specify externalIPs in IP of nodes' network interface.

For example:

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:   
  type: ClusterIP
  externalIPs:
    - 125.100.99.101 # Node1-IP
    - 125.100.99.102 # Node2-IP
    - 192.168.55.112 # Node2-IP2
  selector:
    pod: nginx
  ports:
    - name: http
      port: 80      
    - name: https
      port: 443      

This will listen 80 and 443 on the specified node, and forward to the nginx service.

Hennessy answered 15/3, 2019 at 18:0 Comment(0)
G
8

I had the same problem and the only way I found to do it without modifying the files was:

k expose --type=NodePort deployment nginx --port 80 --name nginx-ep-patch  --overrides '{ "apiVersion": "v1","spec":{"ports": [{"port":80,"protocol":"TCP","targetPort":80,"nodePort":30080}]}}'
service/nginx-ep-patch exposed

In this way we path online the configuration and the port 30080 has been exposed:

$ k describe svc nginx-ep-patch
Name:                     nginx-ep-patch
Namespace:                default
Labels:                   app=nginx
Annotations:              <none>
Selector:                 app=nginx
Type:                     NodePort
IP:                       10.96.51.148
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30080/TCP
Endpoints:                10.244.0.6:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>
Galang answered 12/1, 2021 at 17:15 Comment(0)
D
3

I will try to answer your query here.

Also, I am able to access the page using curl on the random port (31316 in this case) and not port 80.

-- Because, kubernetes exposed the port 31316 on the host (maps to the service) and hence it can be accessed on host:31316.

-- Service port is visible only within the kubernetes cluster. You can exec into a pod container and do a curl on servicename:service port instead of the NodePort.

Note the terms - container port: the port container listens on. Service port: the port where kubernetes service is exposed on cluster internal ip and mapped to the container port. Nodeport: the port exposed on the host and mapped to kubernetes service.

Diesis answered 26/9, 2018 at 22:39 Comment(1)
See better answer a few posts below (by @Rico): https://mcmap.net/q/460683/-how-to-expose-a-kubernetes-service-on-a-specific-nodeportTolerance
T
2

we can expose Kubernetes service on specific node port.

Port value must be between 30000-32767.

We can expose service to specific port of below service types:

  1. NodePort

  2. LoadBalancer

Find the sample myservice.yaml file below:

apiVersion: v1
kind: Service
metadata:
  name: app1
spec:
  type: NodePort/LoadBalancer
  ports:
  - name: "80"
    port: 80
    nodePort: 32062
    targetPort: 80
  selector:
    appone: app1
    app: test

Note: In above service yaml file we can specify service type either NodePort or Loadbalancer.

Torin answered 5/2, 2019 at 14:9 Comment(0)
E
0

For those who need to use kubectl commands, you can create a NodePort service with a specified port using create nodeport command:

kubectl create nodeport NAME [--tcp=port:targetPort] [--dry-run=server|client|none]

For example:

kubectl create service nodeport myservice --node-port=31000 --tcp=3000:80

You can check Kubectl reference for more:

Effulgence answered 8/10, 2021 at 5:49 Comment(1)
This will work although you may need to dry-run to yaml and make sure the spec selector matches your podGreensward
C
-1

Below you will find two working manifests that expose ArgoCD

  1. Service NodePort on port 30k which is recommended only for dev usage not for production
  2. Ingress which is the preferred method to expose a service

Node1: If the service works with HTTPS one will need to deal with provisioning a valid certificate for the ingress.

Note2: The Ingress config posted is from Microk8s ingress

Post comments for guidance or other questions.

apiVersion: v1
kind: Service
metadata:
  name: argocd-server-30k-node-port
  namespace: argocd
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 8080
      nodePort: 30000
  selector:
    app.kubernetes.io/name: argocd-server
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: argocd-ingress
  namespace: argocd
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/backend-protocol: HTTPS
    nginx.ingress.kubernetes.io/ssl-passthrough: "true"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  rules:
  - host: argocd
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: argocd-server
            port:
              number: 8080
Calefaction answered 7/3, 2024 at 10:12 Comment(1)
A code-only answer is not high quality😯. While this code may be useful, you can improve it by saying why it works, how it works, when it should be used, and what its limitations are 👍. Please [edit✏️] your answer to include explanation and link to relevant documentation.Masaccio

© 2022 - 2025 — McMap. All rights reserved.