Having trouble understanding Docker Service port publishing

I need your help to know if I’m understanding correctly the way docker publishing works.

I created a custom Image with Dockerfile. The Dockerfile is as follows:

FROM mcr.microsoft.com/dotnet/framework/wcf:4.8
COPY ./ .
RUN "C:\assets\vc_redist.x64.exe" /quiet /install
WORKDIR /ServicioOcr .
RUN powershell -NoProfile -Command \    
Import-module IISAdministration; \    
New-IISSite -Name "ServicioOcr" -PhysicalPath C:\ServicioOcr -BindingInformation "*:1990:"; \ 
Add-WindowsFeature NET-WCF-HTTP-Activation45 
ENTRYPOINT ["C:\\KeepAlive.exe"]
EXPOSE 1990

Then I run a container publishing the exposed ports without problems:

docker -d -p 2019:1990 --name servicecontainer serviceimage:v8

d96e49d67157        serviceimage:v1   "C:\\ServiceMonitor.e"   3 hours ago         Up 2 hours          80/tcp, 808/tcp, 0.0.0.0:2019->1990/tcp   servicecontainer

Once I , I created a Docker Service, so I could have multiple replicas of the containers that host the service, using the following command:

docker service create --name=SWARM_SERVICE --endpoint-mode dnsrr --network=SWARM_NETWORK serviceimage:v8 --publish 2019:2020

shkmfrrodg1a        SWARM_SERVICE.1       serviceimage:v1   BAZ1573221          Running             Running 2 hours ago

As I understand, the way Docker Service should work is the following:

  • Docker Service creates number of specified replicas inside it. Each replica running a separated instance of the service.
  • Service inside the containers should be available through published ip:port.
  • Requests are made to the published ip:port, and then being forwarded to an available replica/container that can handle it.

Is my understanding right?

Thanks in advance.

Yes thats correct.

Check. https://docs.docker.com/engine/reference/commandline/service_create/#publish-service-ports-externally-to-the-swarm--p---publish

Thanks a lot for your answer.

Now I know my understanding is right. So, if I can’t see yet the service published to my host machine through port publishing, and if everything done this far is right, what else should I check to see what is the problem?

Thanks in advance.

Hi again

2 questions to this.

  1. why are you running it with: --endpoint-mode dnsrr ?
  2. you have in your dockerfile: EXPOSE 1990, and in your normal “run” you also use: -p 2019:1990
    But in your service: --publish 2019:2020

i would guess that those too numbers should be switched? :slight_smile:

Hi @terpz

why are you running it with: --endpoint-mode dnsrr ?

I used this option because I read that dnsrr is better for load-balancing in Windows containers. But, I get the same result no matter the endpoint mode used, except for ‘host’, but that endpoint mode is not what I’m looking for.

you have in your dockerfile: EXPOSE 1990, and in your normal “run” you also use: -p 2019:1990
But in your service: --publish 2019:2020
i would guess that those too numbers should be switched? :slight_smile:

I’m sorry, It was my fault there. I was trying to configure different ports, so I posted the Expose sentence of the actual exposed port, and the publish command of one of many different tries I did.

The actual port was 1990, the Dockerfile was alright. But even though I did it with port 1990, I still get the same result, no ports published:

docker service create --name=SWARM_SERVICE --endpoint-mode dnsrr --network=SWARM_NETWORK serviceimage:v8 --publish 2019:1990

Since then I have been doing some tests, and I think it’s something I have not been able to visualize yet related to how Docker Service creates containers and publishes ports.

First I discarded what I have done until now, and decided to start testing again with the ‘official examples’

The new Docker file is the following:

FROM mcr.microsoft.com/dotnet/framework/sdk:4.8 AS build
WORKDIR /app
COPY WcfServiceWebApp/. .
RUN msbuild /p:Configuration=Release

FROM mcr.microsoft.com/dotnet/framework/wcf:4.8 AS runtime
WORKDIR /inetpub/wwwroot
COPY --from=build /app/ .
RUN move C:\inetpub\wwwroot\OCR_Files 'C:'
RUN “C:\OCR_Files\assets\vc_redist.x64.exe” /quiet /install

Once everything was set up, I noticed something.

If I create a service without port publishing, containers of tasks have their ports exposed and IP assigned correctly:


But if I create a service and publish ports, containers of tasks not only they don’t have ports published, but containers didn’t have ip assigned either:


I can reach out the Web service of the first container from the host web browser:
image

What am I doing wrong?

Thanks in advance for your help.

your conclusion is not correct. Just because exposed ports are listed, doesn’t make them published. Published ports on (swarm) services can be recognized by “*:host-port->container-port/protocoll” (the good old docker-compose would allow to use interface ips instead of * as well - swarm does not). See how the service Testing_No_Port_Publishing has no mapping details, while Testing_Port_Publishing has one port published… The EXPOSE declaration in the Dockerfile has no impact wether ports are published or not - it is ment for documentation and is usualy picked up from management UIs to know which port to suggest to publish.

When you publish a port on a service, the default behavior is to bind the port on the ingress interface, but not on the container. Incomming trafic enters the ingress docker network and is used for the communication to the container. this is why you actualy don’t see a published port on the container… if you rely on the service-ip or the container-ip, probably you are doing something, not to be done like this. Always use servicenames or servicename.networkname.

Thanks for your response @meyay

Please correct if I’m wrong, but I think that maybe we are not on the same wavelength.

Just because exposed ports are listed, doesn’t make them published

Yes, you are totally right. I think I couldn’t explain it very well. What I was trying to say is that ports listed in the ports column in my last post images (showing only the ones that are exposed on the highlighted containers) shouldn’t be changed when you publish ports on the service that deployed/is going to deploy those containers and I don’t know why is it happening that way?

(the good old docker-compose would allow to use interface ips instead of * as well - swarm does not)

Thanks for the information

When you publish a port on a service, the default behavior is to bind the port on the ingress interface, but not on the container.

Isn’t it done automatically by Docker routing mesh? Maybe I’m not understanding this documentation correctly.

this is why you actualy don’t see a published port on the container

I actually don’t see neither published or exposed ports on those containers, and I can’t see why is it happening.

Maybe I’m doing it the wrong way. What I’m trying to achieve is to have both, containers ports exposed and service ports published, so they can be mapped. I want a Docker Service with only one endpoint (the published port in the Docker service), so incoming requests would be routed to any of the containers inside it (through the exposed ports within assigned overlay network).

Thanks in advance for your help.

To get this straigt: you want to run a (swarm) service with one or more replicas and want to publish one or more ports to allow access to all the replice instances (which are executed as a container)?

Thank you for answer @meyay

Yes… well, more or less. I want the service to be the endpoint exposed through port publishing.And also I want that when you make a request, the swarm service endpoint to be the one to route to the right/available container/task. To my understanding, it is possible to do so, but it seems that there is an issue with containers connected to an overlay network with windows containers, so I don’t know if it’s possible.

Thanks in advance.