I was under the impression in Kubernetes the way you expose a port for your application was by first exposing it in the Dockerfile using EXPOSE
, then setting the containerPort
setting in the deployment yaml file, and finally setting the targetPort
in the service yaml file. I thought these all had to be the same value e.g. 7214
.
However I've just noticed that I've had the incorrect port exposed in one my applications Dockerfile as 7124
(but have the correct port in the other two files) like so :
Dockerfile
expose 7124 #This is incorrect
Deployment.yaml
ports:
- containerPort: 7214
Service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
ports:
- port: 7214
targetPort: 7214
However my other applications are hitting the service fine and the requests are being forwarded onto the application at port 7214
without issue.
Why is this working? Is it not required for me to expose the port in the Dockerfile at all? Does containerPort
take precedence or something? This users answer on a similar question says the exposed port doesn't have to match, but doesn't explain why.
CodePudding user response:
The port on which a process is listening is only known to the developer of the process as the port binding happens in code. EXPOSE
and containerPort
are ways to communicate this to outside world.
EXPOSE
directive in the Dockerfile doesn't do anything other than acting as documentation for the person reading your dockerfile to understand which port the process in the container might be listening on and for some UI purpose when you run docker ps
command. It's like a communication between the author of the dockerfile and another person who might be using your image or modifyng your dockerfile.
Even the containerPort
section in your deployment.yaml has no affect on anything. It also acts as documentation for people reading your manifest to know on which ports your process within the pod might be listening on. Another use is that you can give a name to the port using the name
field and then you can reference this port by name in other places like the service object.
The only thing that matters is the actual port that your process is listening on in the container and making sure that port is used in targetPort
field in the service port.
CodePudding user response:
The EXPOSE
option in a Dockerfile serves merely as a documentation, it is not exposing the port as stated by the official documentation:
The EXPOSE instruction does not actually publish the port. It functions as a type of documentation between the person who builds the image and the person who runs the container, about which ports are intended to be published.
In Kubernetes the equivalent to EXPOSE
is spec.containers.ports.containerPort
. You can set both values to whatever you want and it will not change anything at all. Think of it as a comment.
With a Service
object it is a little bit different, there the values do matter. A Service
takes spec.ports.port
and spec.ports.targetPort
.
If you don't specify the targetPort
then Kubernetes will set its value to the same as specified in port
(which is required).
However, it is not necessary for targetPort
and `port to be the same, in fact they do have different purposes:
port
specifies the port of theService
targetPort
specifies the port of thePod
So the general flow looks something like this:
call to <service-name>:port
-> forwards to a Pod with label foo: bar
-> Pod receives the call on targetPort
Here is an example:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 12345
Resulting in:
curl my-service:80
-> forwards to a Pod with label app: MyApp
-> Pod receives the request on 12345
.
In your case you communicate with your Service on port 7214
and it forwards the request to the Pod also to port 7214
, that's why it will continue to work no matter what you set for EXPOSE
or containerPort
.