8

I'm trying to run docker swarm on a single node and having trouble getting a docker app port exposed to the host.

This is similar Docker swarm service port not exposed but I'm running in a single node, and provide more detail on my question and research.

For example, given the following myapp.yml file:

version: "3"
services:
  app:
    image: myapp
    ports: 
      - "8123:8123"

The stack is started via

docker stack deploy -c myapp.yml myapp

After the stack is started, when I try to access the port (via curl) it fails. For example,

curl -v http://localhost:8123/myapp

shows the connection was refused (nothing was listening on that port).

Code works when using docker run

The following command starts the image and shows how to verify the port is exposed.

docker run -p 8123:8123 --name myapp myapp

Curl then works.

curl -v http://localhost:8123/myapp

Gives output from the app running in docker.

When I run docker ps the output in the PORTS section shows: 0.0.0.0:8123:8123/tcp.

docker network inspect bridge - Show that the docker container is assigned to the bridge network. The docker bridge network is used by default with the docker run command.

The command docker port myapp shows:

8123/tcp -> 0.0.0.0:8123

which matches the output from docker ps PORT field.

docker stack deploy doesn't expose port

After starting using docker stack deploy -c myapp.yml myapp, I run the docker ps command and only see 8123/tcp in the PORTS field of the output.

The command docker port myapp has no output (indicating no ports are available from the docker host.

When I run docker network ls, I see:

NETWORK ID       NAME            DRIVER     SCOPE
1234567890      bridge           bridge     local
9999999999      myapp_default   overlay    swarm

So I noticed that the network myapp_default is in a different mode than bridge, local. I tried using existing bridge network but when I refereed to the bridge network in my stack/compose file I observed that the network myapp_bridge was created.

So I read up on docker networking https://blog.alexellis.io/docker-stacks-attachable-networks/ was a good writeup.

So far I haven't gotten it to work so I drafted this to ask for suggestions/help.

NOTE: This aricle (dated Feb 2017) says it should work but doesn't address my question.

I think I'm close.

Resources and other related questions

https://docs.docker.com/v17.12/get-started/part5/ - is the docker primary documentation for the docker stack technology. But searches on that page for networks shows nothing useful.

https://blog.alexellis.io/docker-stacks-attachable-networks/ - Good write up.

Docker swarm service port not exposed - similar to the question I'm asking.

https://runnable.com/docker/basic-docker-networking - Write up on docker networking. It says the following when creating an overlay network (which is the default when docker stack deploy is used).

These networks require a valid key-value store service, such as Consul, Etcd, or ZooKeeper. You must install and configure your key-value store service before creating your network.

Can not use user-defined bridge in swarm compose yaml file.

Community
  • 1
  • 1
PatS
  • 8,833
  • 12
  • 57
  • 100
  • It is a long shot but did you try defining a network explicitly in your stack file and let docker create your app's network while it starts the stack? – Yamuk Jan 29 '19 at 00:29
  • @YamaçKurtuluş, Yes I did try that as well, but that did not work. I think the problem is that the network that was created was in overlay mode. This article https://runnable.com/docker/basic-docker-networking says when using an overlay network you need to have another service such as Consul, Etcd, or ZooKeeper. See Creating an Overlay Network, and I don't have one of those services set up (as I'm running on a single node). – PatS Jan 29 '19 at 00:46
  • This is weird, you shouldn't need Consul or whatever and swarm should work out of the box. Did you try using `docker service create` command? – Yamuk Jan 29 '19 at 00:59
  • key 'ports' in your app.yml should be in list format. What if you substitute 'nginx' for 'myapp' and expose port 8123:80 in your yml file just for testing if the port is exposed? – lkq Jan 29 '19 at 01:20
  • 1
    I'm a little embarrassed to say that the problem was with a faulty startup script (in the docker container). When I fixed it, I could ```curl``` and it worked as YamacKurtulus said it should . I also learned that the ```docker ps``` outputs what is in the Dockerfile EXPOSE not what is actually being **mapped**. I think ```docker inspect myapp``` and shows the ports that are mapped but I'm not positive. – PatS Jan 29 '19 at 02:20
  • @KeqiangLi, You are correct with ports being in list format. I mistyped it, and fixed it in my question. Thanks for pointing that out. – PatS Jan 29 '19 at 02:21
  • How can I tell what ports are mapped when using docker stack. The command ```docker port``` always displays nothing for the container even when the curl command was working. I tried ```docker network inspect myapp_default``` and I could see the container being associated with the network but no port information was present. I tried ```docker inspect $containerID``` and I found Config.ExpotsedPorts was JSON object { "8123/tcp": {} }, and NetworkSettings.Ports was JSON object { "8123/tcp": null } but nothing that tied them together. In normal ```docker run``` container it is tied together. – PatS Jan 29 '19 at 03:00
  • I'm guessing that this writeup https://runnable.com/docker/basic-docker-networking that says ```These [overlay] networks require a valid key-value store service, such as Consul, Etcd, or ZooKeeper. You must install and configure your key-value store service before creating your network. ``` is just flat out wrong based on things working without me doing that. – PatS Jan 29 '19 at 03:05
  • I'm tempted to delete this question. Or please answer with "This should work out of the box" as @YamaçKurtuluş stated. – PatS Jan 29 '19 at 03:07

6 Answers6

6

In swarm

ports:
  - "8123:8123"

will expose port on all swarm nodes and in case of use of the port on some of the nodes by another service you can have problems

you can expose port only on host with container with next docker-compose.yml config

services:
  app:
    ports:
      - target: 8123
        published: 8123
        mode: host
Ryabchenko Alexander
  • 10,057
  • 7
  • 56
  • 88
  • On more than one occasion, I've found that *something* in docker causes the instance to loose connectivity. I only happens once in a blue moon (maybe 2 or 3 times in 5+ years). Bouncing (stopping and starting) the docker service itself was needed to fix that problem. See https://stackoverflow.com/questions/42365336/how-to-stop-docker-under-linux with `sudo systemctl stop docker` and then `sudo systemctl start docker` – PatS Oct 07 '22 at 13:25
2

You should define a network for your services. In Docker Swarm mode, the docker container becomes 'Service', to access its port, you call to the Service's name I provide you an example of docker-compose file how to connect nginx and php-fpm

version: '3.2'
  services:
    nginx:
      image: nginx
      links:
      - php
      - mariadb:mysql
      ports:
      - "8880:80"
      networks:
      - frontend
      deploy:
        #mode: replicated
        replicas: 1
        placement:
          constraints: [node.role == manager]
    php:
       image: php
       deploy:
         #mode: replicated
         replicas: 1
         placement:
           constraints: [node.role == manager]
           #endpoint_mode: dnsrr
       links:
         - mariadb:mysql
    mariadb:
       image: mariadb:10.4.1
       #restart: always
       deploy:
         mode: replicated
         replicas: 1
         #placement:
         #constraints: [node.role == manage]
         environment:
           MYSQL_ROOT_PASSWORD: SECRET          
         volumes:
           - type: volume
              source: mydatabase
              target: /var/lib/mysql/data
              volume:
                nocopy: true # do not copy data from container when a volume is created?
    networks:
      frontend  
    volumes:
      mydatabase:

After you deployed (docker stack deploy -c docker-compose.yaml) , to see list of Services:

docker service ls 

To guild nginx how to access your php-fpm backend, edit your nginx configuration file :

location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass **NAME_OF_PHP_SERVICE_IN SWARM**:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

Instead of putting your container's IP address ( IP:9000 ) , you put the name of the php Service in your Swarm cluster

Dylan B
  • 796
  • 8
  • 16
1

I had a port that was being used in both a SWARM and on the local Linux OS, both apps ran but only one received the incoming connections.

What was strange is that no EADDRINSE error occurred when I would have expected an error to have occurred for one of the apps that was trying to use the port.

So for example, running local app on port 8080, and using a SWARM on this host using port 8080.

An incoming connection comes to port 8080, the connection was sent to one of them (I can't remember which).

PatS
  • 8,833
  • 12
  • 57
  • 100
1

I had the same issue - on my ubuntu machine it was working - on my debian server not. Finally I got it narrowed to to the kernel version used on debian. Upgrading to 5.11.22-5 fixed the issue for me.

There have been posts about missing kernel modules (without mentioning which) - maybe that's related.

Peter
  • 11
  • 2
1

I has same problem. Solved by changing IP. First, get the current docker swarm node IP address.

docker info

Find you IP Manager Addresses row. For example, my IP was 192.168.0.13. And now you can open your application by this address 192.168.0.13:8123.

N. Kirill
  • 104
  • 5
1

This frequently happens because of IPv6. On the host, localhost is defined as ::1 rather than 127.0.0.1 in /etc/hosts. Ingress networking in swarm does not support IPv6. So there are two possible solutions:

  1. Connect using IPv4: curl -v http://127.0.0.1:8123/myapp.

  2. Publish the port using host mode rather than ingress networking. This publishes the port only on the host where the containers are running. This can be useful for services that are deployed on every node (deploy: mode: global) to remove extra networking hops between nodes. To switch to host mode for the published port, follow Ryabchenko Alexander's advice by switching to the long syntax when publishing your port:

        ports:
          - target: 8123
            published: 8123
            mode: host
    

    More details are in the compose file v3 reference: https://docs.docker.com/compose/compose-file/compose-file-v3/#long-syntax-1. Note that publishing the port in host mode here is different from host networking that runs the container without a network sandbox, sadly "host" is used for two different things here, one being outside of swarm, and the other being outside of docker isolation.

BMitch
  • 231,797
  • 42
  • 475
  • 450