{"id":10828,"date":"2018-02-14T12:46:15","date_gmt":"2018-02-14T11:46:15","guid":{"rendered":"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/"},"modified":"2023-07-17T17:00:08","modified_gmt":"2023-07-17T15:00:08","slug":"sql-server-on-docker-and-network-bridge-considerations","status":"publish","type":"post","link":"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/","title":{"rendered":"SQL Server on Docker and network bridge considerations"},"content":{"rendered":"<p>Let\u2019s continue with this blog post series about SQL Server and Docker. A couple of days ago, I was in a customer shop that already implemented SQL Server 2017 on Linux as Docker containers. It was definitely a very interesting day with a lot of customer experience and feedbacks. We discussed with him about lot of architecture scenarios.<\/p>\n<p>The interesting point here is I was able to compare with a previous customer who used docker containers for a while in a completely different way. Indeed, my new customer implemented a Docker infrastructure exclusively based on SQL Server containers whereas the older one already containerized its applications that were connected to an external and non-containerized SQL Server environment.<\/p>\n<table>\n<tbody>\n<tr>\n<td><strong>Use case 1<\/strong> &#8211; Containerized apps and virtualized SQL Server environments<\/td>\n<td><strong>Use case 2<\/strong> &#8211; SQL Server containers and virtualized applications<\/td>\n<\/tr>\n<tr>\n<td>\u00a0<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-21153\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2022\/04\/blog-128-1-docker-archi-2.jpg\" alt=\"blog 128 - 1- docker archi 2\" width=\"260\" height=\"300\" \/><\/td>\n<td>\u00a0<img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-21152 size-full\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2022\/04\/blog-128-1-docker-archi-1-e1518609873932.jpg\" alt=\"blog 128 - 1 - docker archi 1\" width=\"429\" height=\"400\" \/><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>In this blog post I want to focus on the first use case in terms of networks.<\/p>\n<p>Connecting to an outside SQL Server (from a docker perspective) is probably an intermediate solution for many customers who already deal with mission-critical environments implying very restrictive high-availability scenarios and when very high performance is required as well. Don\u2019t get me wrong. I\u2019m not saying docker is not designed for mission critical scenarios but let\u2019s say that fear of unknown things, as virtualization before, is still predominant, at least for this kind of scenario. I always keep in mind the repetitive customer question: is Docker ready for production and for databases? Connecting to a non-containerized SQL Server environment may make sense here at least to speed containers adoption. That\u2019s my guess but feel free to comment with your thoughts!<\/p>\n<p>So, in this context we may use different Docker network topologies. I spent some times to study and to discuss with customers about implemented network topologies in their context. For simple Docker infrastructures (without orchestrators like Swarm or Kubernetes) Docker bridges seem to be predominant with either Docker0 bridges or user-defined bridges.<\/p>\n<ul>\n<li><strong>Docker default bridge (Docker0)<\/strong><\/li>\n<\/ul>\n<p>For very limited Docker topologies, default network settings will be probably sufficient with Docker0 bridge. It is probably the case of my latest customer with only 5 SQL Server containers on the top of one Docker engine. By default, each container created without any network specification (and any Docker engine setting customization) will have one network interface sitting on the docker0 bridge with an IP from 172.17.0.0\/16 CIDR or whichever CIDR you have configured docker to use. But did you wonder what is exactly a bridge on Docker world?<\/p>\n<p>Let\u2019s have a deeper look on it with a very simple example concerning one docker engine that includes two containers based on <strong>microsoft\/mssql-tools<\/strong> each and one outside SQL Server that runs on the top of Hyper-V virtual machine. The below picture shows some network details that I will explain later in this blog post.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-21156 size-full\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2022\/04\/blog-128-3-docker-network-bridge-e1518610161517.jpg\" alt=\"blog 128 - 3 - docker network bridge\" width=\"600\" height=\"359\" \/><\/p>\n<p>My 2 containers can communicate together because they are sitting on the same network bridge and they are also able to communicate with my database server through the NAT mechanism. IP masquerading and IP forwarding is enabled on my Docker host.<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">$ sudo docker run -tid --name docker1 microsoft\/mssql-tools\n77b501fe29af322dd2d1da2824d339a60ba3080c1e61a2332b3cf563755dd3e3\n\n$ sudo docker run -tid --name docker2 microsoft\/mssql-tools\n3f2ba669591a1889068240041332f02faf970e3adc85619adbf952d5c135d3f4\n\n$ sudo docker ps\nCONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS              PORTS               NAMES\n3f2ba669591a        microsoft\/mssql-tools   \"\/bin\/sh -c \/bin\/bash\"   7 seconds ago       Up 6 seconds                            docker2\n77b501fe29af        microsoft\/mssql-tools   \"\/bin\/sh -c \/bin\/bash\"   11 seconds ago      Up 10 seconds                           docker1<\/pre>\n<p>Let\u2019s take a look at the network configuration of each container. As a reminder, each network object represents a layer 2 broadcast domain with a layer 3 subnet as shown below. Each container is attached to a network through a specific endpoint.<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">$ sudo docker inspect docker1\n[\n\"Gateway\": \"172.17.0.1\",\n            \"GlobalIPv6Address\": \"\",\n            \"GlobalIPv6PrefixLen\": 0,\n            \"IPAddress\": \"172.17.0.2\",\n            \"IPPrefixLen\": 16,\n            \"IPv6Gateway\": \"\",\n            \"MacAddress\": \"02:42:ac:11:00:02\",\n            \"Networks\": {\n                \"bridge\": {\n                    \"IPAMConfig\": null,\n                    \"Links\": null,\n                    \"Aliases\": null,\n                    \"NetworkID\": \"985f25500e3d0c55d419790f1ac446f92c8d1090dddfd69987a52aab0717e630\",\n                    \"EndpointID\": \"bd82669031ad87ddcb61eaa2dad823d89ca86cae92c4034d4925009aae634c14\",\n                    \"Gateway\": \"172.17.0.1\",\n                    \"IPAddress\": \"172.17.0.2\",\n                    \"IPPrefixLen\": 16,\n                    \"IPv6Gateway\": \"\",\n                    \"GlobalIPv6Address\": \"\",\n                    \"GlobalIPv6PrefixLen\": 0,\n                    \"MacAddress\": \"02:42:ac:11:00:02\",\n                    \"DriverOpts\": null\n                }\n            }\n]\n\n$sudo docker inspect docker2\n[\n\"Gateway\": \"172.17.0.1\",\n            \"GlobalIPv6Address\": \"\",\n            \"GlobalIPv6PrefixLen\": 0,\n            \"IPAddress\": \"172.17.0.3\",\n            \"IPPrefixLen\": 16,\n            \"IPv6Gateway\": \"\",\n            \"MacAddress\": \"02:42:ac:11:00:03\",\n            \"Networks\": {\n                \"bridge\": {\n                    \"IPAMConfig\": null,\n                    \"Links\": null,\n                    \"Aliases\": null,\n                    \"NetworkID\": \"985f25500e3d0c55d419790f1ac446f92c8d1090dddfd69987a52aab0717e630\",\n                    \"EndpointID\": \"140cd8764506344958e9a9725d1c2513f67e56b2c4a1fc67f317c3e555764c1e\",\n                    \"Gateway\": \"172.17.0.1\",\n                    \"IPAddress\": \"172.17.0.3\",\n                    \"IPPrefixLen\": 16,\n                    \"IPv6Gateway\": \"\",\n                    \"GlobalIPv6Address\": \"\",\n                    \"GlobalIPv6PrefixLen\": 0,\n                    \"MacAddress\": \"02:42:ac:11:00:03\",\n                    \"DriverOpts\": null\n                }\n            }\n]<\/pre>\n<p>To summarize, two IP addresses have been assigned for Docker1 container (172.17.0.2) and Docker2 container (172.17.0.3) in the IP address interval defined by the Docker0 bridge from the Docker internal <a href=\"https:\/\/github.com\/docker\/libnetwork\/blob\/master\/docs\/ipam.md\" target=\"_blank\" rel=\"noopener noreferrer\">IPAM module<\/a>. Each network interface is created with their own MAC address and the gateway IP address (172.17.0.1) for both containers corresponds to the Docker0 bridge interface.<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">$ sudo ip a show docker0\n4: docker0: &lt;NO-CARRIER,BROADCAST,MULTICAST,UP&gt; mtu 1500 qdisc noqueue state DOWN\n    link\/ether 02:42:2a:d0:7e:76 brd ff:ff:ff:ff:ff:ff\n    inet 172.17.0.1\/16 brd 172.17.255.255 scope global docker0\n       valid_lft forever preferred_lft forever\n    inet6 fe80::42:2aff:fed0:7e76\/64 scope link\n       valid_lft forever preferred_lft forever<\/pre>\n<p>Let\u2019s try to connect from the both containers to my SQL Server database:<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">$ sudo docker exec -it docker1\n\u2026\n$ sudo docker exec -it docker2\n...<\/pre>\n<p>Then on each container let\u2019s run the following sqlcmd command:<\/p>\n<pre class=\"brush: shell; gutter: true; first-line: 1\">sqlcmd -S 192.168.40.30,1450 -Usa -Ptoto<\/pre>\n<p>Finally let\u2019s switch on the SQL Server instance and let\u2019s get a picture of existing connections (IP Address 192.168.40.30 and port 1450).<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">SELECT \n\tc.client_net_address,\n\tc.client_tcp_port,\n\tc.local_net_address,\n\tc.protocol_type,\n\tc.auth_scheme,\n\ts.program_name,\n\ts.is_user_process\nFROM sys.dm_exec_connections AS c\nJOIN sys.dm_exec_sessions AS s ON c.session_id = s.session_id\nWHERE client_net_address &lt;&gt; '&lt;local machine&gt;'<\/pre>\n<p><a href=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2022\/04\/blog-128-4-docker-network-bridge-sqlcmd.jpg\">\u00a0<\/a><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-21158 size-full\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2022\/04\/blog-128-4-docker-network-bridge-sqlcmd.jpg\" alt=\"blog 128 - 4 - docker network bridge sqlcmd\" width=\"833\" height=\"77\" \/><\/p>\n<p>We may notice that the IP address is basically the same (192.168.40.50) indicating we are using NAT to connect from each container.<\/p>\n<p>Let\u2019s go back to the Docker engine network configuration. After creating my 2 containers, we may notice the creation of 2 additional network interfaces.<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">$ ip a show | grep veth*\n12: veth45297ff@if11: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue master docker0 state UP\n14: veth46a8316@if13: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue master docker0 state UP<\/pre>\n<p>What are they? At this point, we are entering to Linux network namespace world. You can read further technical details on the internet but to keep simple network namespace concepts, I would say they allow to run different and separate network instances (including routing tables) that operate independent of each other. In other words, there is a way to isolate different networks from each other based on the same physical network device. Assuming we are using docker bridge type networks, when creating a container, in background we are creating a dedicated network namespace that includes a virtual ethernet interface which comes in interconnected pairs. In fact, a virtual ethernet interface acts as a tube to connect a Docker container namespace (in this context) to the outside world via the default \/ global namespace where the physical interface exists.<\/p>\n<p>Before digging further into details about virtual interfaces let\u2019s say by default Docker doesn\u2019t expose network namespace information because it uses it own <a href=\"https:\/\/github.com\/opencontainers\/runc\/tree\/master\/libcontainer\">libcontainer<\/a> and the <strong>microsoft\/mssql-tools<\/strong> docker image is based on a simplified Linux image that doesn\u2019t include network tools to easily show virtual interface information. So, a workaround is to expose a Docker container namespace into the host.<\/p>\n<p>First we have to find out the process id of the container and then link its corresponding proc namespace to <strong>\/var\/run\/netns<\/strong> host directory as shown below:<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">$ sudo docker inspect --format '{{.State.Pid}}' docker1\n2094\n$ sudo ln -s \/proc\/2094\/ns\/net \/var\/run\/netns\/ns-2094<\/pre>\n<p>Then we may use ip netns command to extract the network information<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">$ sudo ip netns\nns-2094 (id: 0)\n$ sudo ip netns exec ns-2094 ip link\n1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT qlen 1\n    link\/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00\n11: eth0@if12: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue state UP mode DEFAULT\n    link\/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0<\/pre>\n<p>Here we go. The interesting information is the container network interface <strong>11:<\/strong> <strong>eth0@if12<\/strong><\/p>\n<p>So, the first pair is the eth0 interface on the Docker container and the \u201coutside\u201d pair corresponds to the interface number 12. On the host the interface 12 corresponds to the virtual ethernet adapter veth45297ff. Note we may also find out the pair corresponding to the container interface (@if11).<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">$ ip a | grep \"^12\"\n12: veth45297ff@if11: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue master docker0 state UP<\/pre>\n<p>Finally, let\u2019s take a look at the bridge used by the virtual ethernet adapter veth45297ff<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">$ sudo brctl show\nbridge name     bridge id               STP enabled     interfaces\ndocker0         8000.02422ad07e76       no              veth45297ff\n                                                        veth46a8316<\/pre>\n<p>The other veth (46a8316) corresponds to my second docker2 container.<\/p>\n<ul>\n<li><strong>User-defined network bridges<\/strong><\/li>\n<\/ul>\n<p>But as said previously using the Docker0 bridge is only suitable for very limited scenarios. User-defined bridges are more prevalent with more complex scenarios like microservice applications because they offer a better isolation between containers and the outside world as well as a better manageability and customization. At this stage we may also introduce macvlan networks but probably in the next blog post \u2026<\/p>\n<p>For example, let\u2019s say you want to create 2 isolated network bridges for a 3-tiers application. The users will access the web server (from the exposed port) throughout the first network (frontend-server). But in the same time, you also want to prevent containers that sit on this network to make connections to the outside world. The second network (backend-server) will host containers that must have access to both the outside SQL Server database and the web server.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-21159 size-full\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2022\/04\/blog-128-5-docker-network-bridge-segregation-e1518611126838.jpg\" alt=\"blog 128 - 5 - docker network bridge segregation\" width=\"600\" height=\"363\" \/><\/p>\n<p>User-defined networks is a good solution to address these requirements. Let\u2019s create two user-defined networks. Note by default containers may make connections to the outside world but the outside is not able to make connections to the containers without exposing listen ports. This is why I disabled <strong>ip masquerading<\/strong> (<strong>com.docker.network.bridge.enable_ip_masquerade=false<\/strong>) for the frontend-server network to meet the above requirements.<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">$sudo docker network create \\\n    --driver bridge \\\n    --subnet 172.20.0.0\/16 \\\n  --gateway 172.20.0.1 \\\n  backend-server  \n$sudo docker network create \\\n    --driver bridge \\\n    --subnet 172.19.0.0\/16 \\\n    --gateway 172.19.0.1 \\\n    --opt com.docker.network.bridge.enable_ip_masquerade=false \\\n  frontend-server\n$ sudo docker network ls \nNETWORK ID          NAME                DRIVER              SCOPE\n5c6f48269d2b        backend-server      bridge              local\n985f25500e3d        bridge              bridge              local\nb1fbde4f4674        frontend-server     bridge              local\nad52b859e3f9        host                host                local\n1beda56f93d3        none                null                local<\/pre>\n<p>Let\u2019s now take a look at the corresponding iptables masquerading rules on my host machine:<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">$ sudo iptables -t nat -L -n | grep -i \"masquerade\"\nMASQUERADE  all  --  172.20.0.0\/16        0.0.0.0\/0\nMASQUERADE  all  --  172.17.0.0\/16        0.0.0.0\/0<\/pre>\n<p>You may notice only the Docker0 (172.17.0.0\/16) and backend-server (172.20.0.0\/16) bridges are allowed for ip masquerading.<\/p>\n<p>Then let\u2019s create 2 containers with the two first ones (docker1 and docker2) that will sit on the frontend-server network and the second one (docker2) on the backend-server network. For convenient purposes, I setup fixed hostnames for each container. I also used a different ubuntu image that provides this time all necessary network tools including ping command.<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">$ sudo docker run -d --rm --name=docker1 --hostname=docker1 --net=frontend-server -it smakam\/myubuntu:v6 bash\n\n$ sudo docker run -d --rm --name=docker2 --hostname=docker2 --net=frontend-server -it smakam\/myubuntu:v6 bash\n\n$sudo docker run -d --rm --name=docker3 --hostname=docker3 --net=backend-server -it smakam\/myubuntu:v6 bash\n\n$ sudo docker ps\nCONTAINER ID        IMAGE                COMMAND             CREATED             STATUS              PORTS               NAMES\n225ee13c38f7        smakam\/myubuntu:v6   \"bash\"              2 minutes ago       Up 2 minutes                            docker3\nd95014602fe2        smakam\/myubuntu:v6   \"bash\"              4 minutes ago       Up 4 minutes                            docker2\n1d9645f61245        smakam\/myubuntu:v6   \"bash\"              4 minutes ago       Up 4 minutes                            docker1<\/pre>\n<p>First, probably one of the biggest advantages of using user-defined networks (unlike Docker0 bridge) is the ability to use automatic DNS resolution between containers on the same user-defined subnet on the same host (this is default behavior but you can override DNS settings by specifying <strong>&#8211;dns<\/strong> parameter at the container creation time). In fact, Docker applies update on the \/etc\/hosts file of each container when adding \/ deleting containers.<\/p>\n<p>As expected, I may ping docker2 container from docker1 container and vice-versa but the same doesn\u2019t apply between neither docker1 and docker3 nor docker2 and docker3 because they are not sitting on the same network bridge.<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">$ sudo docker exec -ti docker1 ping -c2 docker2\nPING docker2 (172.19.0.3) 56(84) bytes of data.\n64 bytes from docker2.frontend-server (172.19.0.3): icmp_seq=1 ttl=64 time=0.088 ms\n64 bytes from docker2.frontend-server (172.19.0.3): icmp_seq=2 ttl=64 time=0.058 ms\n\u2026\n$ sudo docker exec -ti docker2 ping -c2 docker1\nPING docker1 (172.19.0.2) 56(84) bytes of data.\n64 bytes from docker1.frontend-server (172.19.0.2): icmp_seq=1 ttl=64 time=0.084 ms\n64 bytes from docker1.frontend-server (172.19.0.2): icmp_seq=2 ttl=64 time=0.054 ms\n...\n$ sudo docker exec -ti docker1 ping -c2 docker3\nping: unknown host docker3\n...\n\n<\/pre>\n<p>From a network perspective, on the host we may notice the creation of two additional bridge interfaces and 3 virtual Ethernet adapters after the creation of the containers.<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">$ brctl show\nbridge name     bridge id               STP enabled     interfaces\nbr-5c6f48269d2b         8000.0242ddad1660       no              veth79ae355\nbr-b1fbde4f4674         8000.02424bebccdd       no              vethb66deb8\n                                                        vethbf4ab2d\ndocker0         8000.02422ad07e76       no\n$ ip a | egrep \"^[1-9][1-9]\"\n25: br-5c6f48269d2b: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue state UP\n28: br-b1fbde4f4674: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue state UP\n58: vethb66deb8@if57: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue master br-b1fbde4f4674 state UP\n64: veth79ae355@if63: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue master br-5c6f48269d2b state UP<\/pre>\n<p>If I want to make the docker3 container reachable from docker2 container I may simply connect the latter to the corresponding network as shown below:<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">$ sudo docker network connect backend-server docker2\n\n$ sudo docker inspect docker2\n[\n\"Networks\": {\n                \"backend-server\": {\n                    \"IPAMConfig\": {},\n                    \"Links\": null,\n                    \"Aliases\": [\n                        \"d95014602fe2\"\n                    ],\n                    \"NetworkID\": \"5c6f48269d2b752bf1f43efb94437957359c6a72675380c16e11b2f8c4ecaaa1\",\n                    \"EndpointID\": \"4daef42782b22832fc98485c27a0f117db5720e11d806ab8d8cf83e844ca6b81\",\n                    \"Gateway\": \"172.20.0.1\",\n                    \"IPAddress\": \"172.20.0.3\",\n                    \"IPPrefixLen\": 16,\n                    \"IPv6Gateway\": \"\",\n                    \"GlobalIPv6Address\": \"\",\n                    \"GlobalIPv6PrefixLen\": 0,\n                    \"MacAddress\": \"02:42:ac:14:00:03\",\n                    \"DriverOpts\": null\n                },\n                \"frontend-server\": {\n                    \"IPAMConfig\": null,\n                    \"Links\": null,\n                    \"Aliases\": [\n                        \"d95014602fe2\"\n                    ],\n                    \"NetworkID\": \"b1fbde4f4674386a0e01b7ccdee64ed8b08bd8505cd7f0021487d32951035570\",\n                    \"EndpointID\": \"651ad7eaad994a06658941cda7e51068a459722c6d10850a4b546382c44fff86\",\n                    \"Gateway\": \"172.19.0.1\",\n                    \"IPAddress\": \"172.19.0.3\",\n                    \"IPPrefixLen\": 16,\n                    \"IPv6Gateway\": \"\",\n                    \"GlobalIPv6Address\": \"\",\n                    \"GlobalIPv6PrefixLen\": 0,\n                    \"MacAddress\": \"02:42:ac:13:00:03\",\n                    \"DriverOpts\": null\n                }\n            }\n]<\/pre>\n<p>You may notice the container is connected to the frontend-server and backend-server as well thanks to an additional network interface created at same time.<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">$ sudo docker exec -it docker2 ip a show | grep eth\n59: eth0@if60: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue state UP group default\n    link\/ether 02:42:ac:13:00:03 brd ff:ff:ff:ff:ff:ff\n    inet 172.19.0.3\/16 brd 172.19.255.255 scope global eth0\n68: eth2@if69: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue state UP group default\n    link\/ether 02:42:ac:14:00:03 brd ff:ff:ff:ff:ff:ff\n    inet 172.20.0.3\/16 brd 172.20.255.255 scope global eth2<\/pre>\n<p>Pinging both docker1 container and docker3 container from docker2 container is successful now.<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">$ sudo docker exec -it docker2 ping -c2 docker1\nPING docker1 (172.19.0.2) 56(84) bytes of data.\n64 bytes from docker1.frontend-server (172.19.0.2): icmp_seq=1 ttl=64 time=0.053 ms\n64 bytes from docker1.frontend-server (172.19.0.2): icmp_seq=2 ttl=64 time=0.052 ms\n\u2026\n$ sudo docker exec -it docker2 ping -c2 docker3\nPING docker3 (172.20.0.2) 56(84) bytes of data.\n64 bytes from docker3.backend-server (172.20.0.2): icmp_seq=1 ttl=64 time=0.082 ms\n64 bytes from docker3.backend-server (172.20.0.2): icmp_seq=2 ttl=64 time=0.054 ms\n\u2026<\/pre>\n<p>In this blog post, we surfaced Docker network bridges and use cases we may have to deal with SQL Server instances regarding the context. As a reminder, user-defined networks may allow to define fine-grained policy rules to interconnect containers on different subnets. This is basically what we may want to achieve with microservices applications. Indeed, such applications include some components that need to span multiple networks (backend and frontend networks) whereas other ones should by isolated (even from outside) regarding their role.<\/p>\n<p>Happy containerization!<\/p>\n<p><span style=\"float: none; background-color: #ffffff; color: #333333; cursor: text; font-family: Georgia,'Times New Roman','Bitstream Charter',Times,serif; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none;\">By David Barbarin<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Let\u2019s continue with this blog post series about SQL Server and Docker. A couple of days ago, I was in a customer shop that already implemented SQL Server 2017 on Linux as Docker containers. It was definitely a very interesting day with a lot of customer experience and feedbacks. We discussed with him about lot [&hellip;]<\/p>\n","protected":false},"author":26,"featured_media":10830,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[229],"tags":[601,1291,73,1292,51,1077],"type_dbi":[],"class_list":["post-10828","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-database-administration-monitoring","tag-docker","tag-docker0","tag-linux","tag-network-bridge","tag-sql-server","tag-sql-server-2017"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.2 (Yoast SEO v27.2) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>SQL Server on Docker and network bridge considerations<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"SQL Server on Docker and network bridge considerations\" \/>\n<meta property=\"og:description\" content=\"Let\u2019s continue with this blog post series about SQL Server and Docker. A couple of days ago, I was in a customer shop that already implemented SQL Server 2017 on Linux as Docker containers. It was definitely a very interesting day with a lot of customer experience and feedbacks. We discussed with him about lot [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/\" \/>\n<meta property=\"og:site_name\" content=\"dbi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2018-02-14T11:46:15+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-07-17T15:00:08+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2022\/04\/blog-128-1-docker-archi-1-e1518609873932.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"429\" \/>\n\t<meta property=\"og:image:height\" content=\"400\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Microsoft Team\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Microsoft Team\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/\"},\"author\":{\"name\":\"Microsoft Team\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/bfab48333280d616e1170e7369df90a4\"},\"headline\":\"SQL Server on Docker and network bridge considerations\",\"datePublished\":\"2018-02-14T11:46:15+00:00\",\"dateModified\":\"2023-07-17T15:00:08+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/\"},\"wordCount\":1617,\"commentCount\":0,\"image\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2022\/04\/blog-128-1-docker-archi-1-e1518609873932.jpg\",\"keywords\":[\"Docker\",\"Docker0\",\"Linux\",\"Network bridge\",\"SQL Server\",\"SQL Server 2017\"],\"articleSection\":[\"Database Administration &amp; Monitoring\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/\",\"name\":\"SQL Server on Docker and network bridge considerations\",\"isPartOf\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2022\/04\/blog-128-1-docker-archi-1-e1518609873932.jpg\",\"datePublished\":\"2018-02-14T11:46:15+00:00\",\"dateModified\":\"2023-07-17T15:00:08+00:00\",\"author\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/bfab48333280d616e1170e7369df90a4\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/#primaryimage\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2022\/04\/blog-128-1-docker-archi-1-e1518609873932.jpg\",\"contentUrl\":\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2022\/04\/blog-128-1-docker-archi-1-e1518609873932.jpg\",\"width\":429,\"height\":400},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\/\/www.dbi-services.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"SQL Server on Docker and network bridge considerations\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#website\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/\",\"name\":\"dbi Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/bfab48333280d616e1170e7369df90a4\",\"name\":\"Microsoft Team\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/secure.gravatar.com\/avatar\/c44a1a792c059f24055763aa77d80a244467f6eef724a8bd13db8d4a350b7a4c?s=96&d=mm&r=g\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/c44a1a792c059f24055763aa77d80a244467f6eef724a8bd13db8d4a350b7a4c?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/c44a1a792c059f24055763aa77d80a244467f6eef724a8bd13db8d4a350b7a4c?s=96&d=mm&r=g\",\"caption\":\"Microsoft Team\"},\"url\":\"https:\/\/www.dbi-services.com\/blog\/author\/microsoft-team\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"SQL Server on Docker and network bridge considerations","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/","og_locale":"en_US","og_type":"article","og_title":"SQL Server on Docker and network bridge considerations","og_description":"Let\u2019s continue with this blog post series about SQL Server and Docker. A couple of days ago, I was in a customer shop that already implemented SQL Server 2017 on Linux as Docker containers. It was definitely a very interesting day with a lot of customer experience and feedbacks. We discussed with him about lot [&hellip;]","og_url":"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/","og_site_name":"dbi Blog","article_published_time":"2018-02-14T11:46:15+00:00","article_modified_time":"2023-07-17T15:00:08+00:00","og_image":[{"width":429,"height":400,"url":"http:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2022\/04\/blog-128-1-docker-archi-1-e1518609873932.jpg","type":"image\/jpeg"}],"author":"Microsoft Team","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Microsoft Team","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/#article","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/"},"author":{"name":"Microsoft Team","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/bfab48333280d616e1170e7369df90a4"},"headline":"SQL Server on Docker and network bridge considerations","datePublished":"2018-02-14T11:46:15+00:00","dateModified":"2023-07-17T15:00:08+00:00","mainEntityOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/"},"wordCount":1617,"commentCount":0,"image":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/#primaryimage"},"thumbnailUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2022\/04\/blog-128-1-docker-archi-1-e1518609873932.jpg","keywords":["Docker","Docker0","Linux","Network bridge","SQL Server","SQL Server 2017"],"articleSection":["Database Administration &amp; Monitoring"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/","url":"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/","name":"SQL Server on Docker and network bridge considerations","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/#primaryimage"},"image":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/#primaryimage"},"thumbnailUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2022\/04\/blog-128-1-docker-archi-1-e1518609873932.jpg","datePublished":"2018-02-14T11:46:15+00:00","dateModified":"2023-07-17T15:00:08+00:00","author":{"@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/bfab48333280d616e1170e7369df90a4"},"breadcrumb":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/#primaryimage","url":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2022\/04\/blog-128-1-docker-archi-1-e1518609873932.jpg","contentUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2022\/04\/blog-128-1-docker-archi-1-e1518609873932.jpg","width":429,"height":400},{"@type":"BreadcrumbList","@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-on-docker-and-network-bridge-considerations\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/www.dbi-services.com\/blog\/"},{"@type":"ListItem","position":2,"name":"SQL Server on Docker and network bridge considerations"}]},{"@type":"WebSite","@id":"https:\/\/www.dbi-services.com\/blog\/#website","url":"https:\/\/www.dbi-services.com\/blog\/","name":"dbi Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/bfab48333280d616e1170e7369df90a4","name":"Microsoft Team","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/c44a1a792c059f24055763aa77d80a244467f6eef724a8bd13db8d4a350b7a4c?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/c44a1a792c059f24055763aa77d80a244467f6eef724a8bd13db8d4a350b7a4c?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/c44a1a792c059f24055763aa77d80a244467f6eef724a8bd13db8d4a350b7a4c?s=96&d=mm&r=g","caption":"Microsoft Team"},"url":"https:\/\/www.dbi-services.com\/blog\/author\/microsoft-team\/"}]}},"_links":{"self":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/10828","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/users\/26"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/comments?post=10828"}],"version-history":[{"count":1,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/10828\/revisions"}],"predecessor-version":[{"id":26786,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/10828\/revisions\/26786"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/media\/10830"}],"wp:attachment":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/media?parent=10828"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/categories?post=10828"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/tags?post=10828"},{"taxonomy":"type","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/type_dbi?post=10828"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}