Docker Swarm Series: #8th Publishing Modes
Tags: docker, swarm
Published: 2023-07-25 20:12:13


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/352bhjzlzu45s0r3p0y9.png)



# 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](https://mohamed-eleraky.hashnode.dev/docker-swarm-series-7th-advanced-managing-config-and-secret-objects), 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](https://labs.play-with-docker.com/) 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](https://labs.play-with-docker.com/) 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](https://mohamed-eleraky.hashnode.dev/docker-swarm-series-3rd-deploy-a-highly-available-container) article.

## **Ingress**

Docker's Ingress network is a built-in overlay network [*\-docker networks-*](https://poe.com/s/NZ92TslUZeSej6HcJ5fy) 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](https://docs.docker.com/engine/swarm/ingress/#:~:text=All%20nodes%20participate%20in%20an,task%20running%20on%20the%20node.) 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:
    
    ```bash
    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:
    
    ```bash
    docker service ls
    ```
    

3\. **Optional**: publish additional ports for an existing service

```bash
docker service update --publish-add 8080:80 myservice
```

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:
    
    ```bash
    docker ps service myservice
    ```
    
    As mentioned above the [Ingress routing mesh](https://docs.docker.com/engine/swarm/ingress/#:~:text=All%20nodes%20participate%20in%20an,task%20running%20on%20the%20node.) 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.
    

```bash
curl http://localhost:8080
```

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.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1690269927312/f0319a44-4ca5-41bd-ad12-e968041134f3.png)

---

## **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:
    
    ```bash
    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 the`endpoint_mode` parameter under the deploy section of the service definition.

```yaml
version: '3.9'

services:
  web:
    image: nginx
    deploy:
      endpoint_mode: dnsrr
      #endpoint_mode: vip
```

This is the same in the CLI syntax

```bash
docker service create --name web --endpoint-mode dnsrr nginx
```

---

# Deploy modes

```yaml
deploy: 
  mode: global
```

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.


```bash
# the lable called db
docker node update --label-add db=true node-1
```

Update the YAML file

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

---

# Resources

* #### [Metin guidance](https://forums.docker.com/u/meyay/summary)
    
* [EndPoint mode Docs](https://docs.docker.com/compose/compose-file/compose-file-v3/#endpoint_mode)
    
* [configure service discovery](https://docs.docker.com/engine/swarm/networking/#configure-service-discovery)
    
* [Learn Docker in a Month of Lunches](https://www.amazon.com/Learn-Docker-Month-Lunches-Stoneman/dp/1617297054/ref=sr_1_1?keywords=learn+docker+in+a+month+of+lunches&link_code=qs&qid=1690103529&sourceid=Mozilla-search&sr=8-1)
    
* [POE AI](http://www.poe.com)
    

---

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