DEV Community

Mohamed El Eraky
Mohamed El Eraky

Posted on • Edited on

Docker Swarm Series: #8th Publishing Modes

Image description

Inception

Hello everyone, This article is part of The Swarm series, The knowledge in this series is built in sequence, Check out The Swarm series section below.

In the last article, we covered Config and Secret advanced stuff, discussed how to use and manage config objects, and how to store secrets securely and use them in your deployment. However in an advanced and efficient way, using Docker-compose YAML file, Docker CLI, And Play-with-docker lab, we going to discuss more advanced topics today.


Overview

In This article, Will try to cover an interesting topic, which is docker publishing modes, Explain publishing modes, View the differences between ingress and host modes, how to use service end_point (VIP, DNSRR), and discover what is a global and replicas mode in deployment, Placement constraint. in this lab Also will use the Play-with-docker lab.


Publishing modes Overview

Simply, In Docker Swarm publishing a service means making it accessible from outside the swarm cluster. In native docker we used the --publish or -p option when creating a container. it's almost the same concept when comes to Swarm, however with more options to match what exactly you want.


Differences of publishing modes ingress vs host

First of all, Kindly build up the environment as mentioned in Docker Swarm Series: #3rd Deploy a highly available Container article.

Ingress

Docker's Ingress network is a built-in overlay network -docker networks- that enables external access to services running in a Docker Swarm cluster. It will accept connections for published ports from every node in the Swarm Cluster, and the Ingress routing mesh takes care of forwarding the traffic to a service task, regardless of which node it is running.

Hint: The service itself gets published as a DNS entry in docker's build in DNS-server

  • Create a service and publish a port via ingress:

    docker service create --detach=true --name myservice --publish 8080:80 --replicas 3 --mount source=/etc/hostname,target=/usr/share/nginx/html/index.html,type=bind,ro nginx
    

This command publishes port 8080 on the swarm node to port 80 on the myservice service. This allows external access to the service through port 8080, The --mount flag is useful to print out the hostname of the node That host the service.

  • list services:

    docker service ls
    

3. Optional: publish additional ports for an existing service

docker service update --publish-add 8080:80 myservice
Enter fullscreen mode Exit fullscreen mode

Note: If you publish additional ports for an existing service will start updating the service one by one to avoid service down, and after updating will make some checks to ensure the update works fine.

Once you have completed these steps, the myservice service will be accessible from outside the swarm through the Ingress network. You can scale the service up or down as needed, and Docker will automatically handle load balancing and service discovery.


  • To test out the previous steps Follow the instructions below:

    Here we have 3 services distributed on 3 nodes:

    docker ps service myservice
    

    As mentioned above the Ingress routing mesh takes care of forwarding the traffic to a service task, regardless of which node it is running on. therefore to test the load balancing run the following command on any node, even if it does not host the service.

curl http://localhost:8080
Enter fullscreen mode Exit fullscreen mode

Notice that the output of the curl command prints out the node name that hosts the service. Rerun again a bunch of times on notice that the ingress routing mesh is load balance on the services.


Host

The host configures the service to bind directly to a specific port on the host, without using the ingress routing mesh. This can be useful when you want to run your own load balancer (e.g. Traefik, nginx), or need the source IP of the communication to be retained. The published host port will only be bound on nodes where at least one service task of the service is running.

Follow the below steps to publish a port in host mode:

  • to create a service with tasks that listens on port 8080 of the Docker host's network interface, you can use the following command:

    docker service create --name myservice --publish published=8080,target=80,mode=host nginx
    

    This command creates a service called myservice based on the nginx image, and binds the host port 8080 to the container port 80. Instead of using the host namespace, only a single port is forwarded to the container port.

    Host namespaces isolate containers from each other and from the host system by providing each container with its own namespace for system resources such as processes, network interfaces, and file systems. This allows containers to have a high level of isolation and control over their resources.

    On the other hand, host networking allows containers to use the host system's network stack directly, without being isolated from it. This means that containers using host networking are effectively treated as if they were running directly on the host system.


Service EndPoint Modes

EndPoint modes determine how the service is exposed to the client, there're two EndPoint modes VIP (Virtual IP) and DNSRR (DNS round-robin)

VIP endpoint mode is the default mode, and it assigns a single virtual IP to the service. The service name will be registered in the network DNS-based Service Discovery pointing to the virtual IP. The VIP provides a built-in load balancer, which distributes the connections in a round-robin manner to the tasks running the service.

DNSRR endpoint mode registers the service name as a multi-value DNS-record in the network DNS-based Service Discovery pointing to the IP's of all tasks running the service.

Typically (DNS) clients cache DNS results until the TTL expires, so that load will not be distributed among the tasks, but rather will be directed to the same task. Some clients even cache the DNS result indefinitely (like nginx does)

To set the endpoint mode for a service in a Docker Swarm stack file (in YAML format), you can use theendpoint_mode parameter under the deploy section of the service definition.

version: '3.9'

services:
  web:
    image: nginx
    deploy:
      endpoint_mode: dnsrr
      #endpoint_mode: vip
Enter fullscreen mode Exit fullscreen mode

This is the same in the CLI syntax

docker service create --name web --endpoint-mode dnsrr nginx
Enter fullscreen mode Exit fullscreen mode

Deploy modes

deploy: 
  mode: global
Enter fullscreen mode Exit fullscreen mode

There are two deployment modes replicas **and **global, these modes define how the service will deploy on the nodes, with replicated you define how many service instances you want to deploy, on the other hand with global you configure the service instances to run on each node, the number of instances will equal the number of nodes, even if there is a new node joined the cluster will deploy an instance from the service on it.

Placement Constraints

Placement constraints are rules that specify which nodes are eligible for running a particular service or task. Constraints can be based on node labels, you can use this approach when you want to run a particular service on particular nodes. Assign your label to the node.
The placement constraints work either with replicas or global modes.

# the lable called db
docker node update --label-add db=true node-1
Enter fullscreen mode Exit fullscreen mode

Update the YAML file

    deploy:
      replicas: 2 # <-- Set number of replicas
      placement:
        constraints:
          - node.labels.db == "true"  # deploy only on nodes that have this lable
Enter fullscreen mode Exit fullscreen mode

Resources


That's it, Very straightforward, very fast🚀. Hope this article inspired you and will appreciate your feedback. Thank you.

Top comments (0)