Let's say that we have a Node app running inside a Docker container and listening on port 3000. We want to expose this app to be accessible in the browser, also in port 3000. So we do port forwarding like this:
docker run -p <port>:<targetPort> my-image // for example: 3000:3000
So docker knows on which port to listen and to which process inside the container to forward the network.
But in k8s NodePort service, its enough to provide the NodePort service port and the target port of the Pod, but not the target port inside the Pod, so we have random outside port, 30,000-32,000 (approximately) that listens to outside traffic, forward this to the port of the NodePort service and then forward it to the target port of a Pod, but.. hey, we didn't mention the target port inside the Pod.
So how the Pod object knows to which process inside it to forward the traffic? We usually assume we have only single container in a Pod, but if we have multiple?
Also note that in the example of exposing image in Docker - if we don't mention port forwarding the whole exposition won't work so it won't be accessible via browser (outside the container)..
containerPort
in pod spec is just informational and non mandatory. Mentioning that does not make the application inside the pod listen on that port. Normally you will specify which port the application should listen on in the source code or in dockerfile.The targetPort
in the service need to match with that port. For example the targetPort
for a service which forwards traffic to nginx container running inside a pod should be 80
because nginx process listens on port 80.
targetPort` in the service informs kubernetes service which port of the container running inside the pod to forward the traffic to.
In case of a pod which has got multiple containers listening on different ports you can specify multiple targetPort
in service as below.
apiVersion: v1
kind: Service
metadata:
name: service-name
spec:
ports:
- name: http
port: 80
targetPort: 80
- name: https
port: 443
targetPort: 443
- name: something
port: 6001
targetPort: 6001
selector:
app: app-label
type: NodePort
There is no such thing as "target port inside the Pod" in kubernetes. At least not in a way it works in Docker. In docker you have <port> and <targetPort> so you can run several containers that can be exposed and be accessed with localhost. Docker opens <port> on localhost and forwards traffic to the <targerport> of a container. How else would you be able to access a container.
k8s works differently, so forget about docker (and don't think that if they are called the same so they must work the same). Every pod in k8s has it's own IP address that can be accessed and there is no need for port:targetport in a form you know from docker.
So to answer your question:
So how the Pod object knows to which process inside it to forward the traffic?
In k8s, process is accessible by the port it opens from inside and from outside. There is no port translation on a pod level.
So how do service's port and targetPort in k8s service object relate to that? Service acts as a load balancer in front of pod replicas and holds static IP address. So when thinking about service, think it's a loadbalancer, beacause that's its primary function.
There are 3 fields in service of type NodePort:
port - a port on which service(loadbalancer) is serving traffic.
targetPort - a port that is opened by the process in pod (where to forward the trafic).
nodePort - a port that is open on every node.
When you don't specify targetPort, k8s assumes that port and targetPort are the same.
We usually assume we have only single container in a Pod, but if we have multiple?
In case of multiple containers in one pod, all these containers share the same network interface so if one container has already opened e.g. port 80, other pod trying to open port 80 won't be able to do it.
In k8s docs you can read:
Every Pod gets its own IP address. This means you do not need to explicitly create links between Pods and you almost never need to deal with mapping container ports to host ports. This creates a clean, backwards-compatible model where Pods can be treated much like VMs or physical hosts from the perspectives of port allocation, naming, service discovery, load balancing, application configuration, and migration.
To summarize, think that a pod is a VM and when you open a port it's automatically accessible from the outside, and every container in pod is nothing different than a process on that VM, so you can't have several processes running on a VM with the same port open.