{"id":2608,"date":"2016-11-01T11:50:00","date_gmt":"2016-11-01T11:50:00","guid":{"rendered":"http:\/\/blog.designed79.co.uk\/?p=2608"},"modified":"2016-11-01T11:58:22","modified_gmt":"2016-11-01T11:58:22","slug":"connecting-docker-containers-part-one","status":"publish","type":"post","link":"https:\/\/blog.designed79.co.uk\/?p=2608","title":{"rendered":"Connecting Docker Containers, Part One"},"content":{"rendered":"<p>Docker containers are self-contained, isolated environments. However, they\u2019re often only useful if they can talk to each other.<\/p>\n<p>There are many ways to connect containers. And we won\u2019t attempt to cover them all. But in this miniseries, we will look at some common ways.<\/p>\n<p>This topic seems elementary, but grasping these techniques and the underlying design concepts is important for working with Docker.<\/p>\n<p>Understanding this topic will:<\/p>\n<ul>\n<li>Help developers and ops people explore the broad spectrum of container deployment choices<\/li>\n<li>Let developers and ops people to embark more confidently with a microservice design architecture<\/li>\n<li>Empower developers and ops people to better orchestrate more complex distributed applications<\/li>\n<\/ul>\n<p>Fortunately, the large number of connection options for containers enables a broad range of approaches, giving us the flexibility to choose an architecture that suits the needs of any application.<\/p>\n<p>In this post, we&#8217;ll look at three of the older, more basic ways of connecting Docker containers. Using this knowledge and experience as a foundation, we&#8217;ll then move on to two newer, easier, more powerful ways in the next post.<\/p>\n<p>Setup<\/p>\n<p>Before we can demonstrate how containers can be connected, we need to create a pair of them for use in our examples.<\/p>\n<p>The first image will be derived from a simple Ubuntu installation. It will act as a client container.<\/p>\n<p>First, we create the container and attach to it:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ sudo docker run -itd --name=client_setup ubuntu \/bin\/bash<br \/>\n$ sudo docker attach client_setup<\/div><\/div>\n<p>Then, once we have a shell inside the container, we run:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ apt-get install curl<\/div><\/div>\n<p>If you do not see the shell, click the up arrow.<\/p>\n<p>Now, detach from the client container using CTRL+p then CTRL+q.<\/p>\n<p>Then, stop it, and commit:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ sudo docker stop client_setup<br \/>\n$ sudo docker commit client_setup client_img<\/div><\/div>\n<p>We now have an image called client_img to use.<\/p>\n<p>The second container we want to use is, again, derived from an Ubuntu installation. But this time, we\u2019ll modify it to run a Apache HTTP server.<\/p>\n<p>First, we create it and attach, like before:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ sudo docker run -itd --name=server_setup ubuntu \/bin\/bash<br \/>\n$ sudo docker attach server_setup<\/div><\/div>\n<p>Then, once we have a shell inside the container, we install the Apache HTTP server:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ apt-get install apache2<\/div><\/div>\n<p>When the installation is complete, detach from the container using CTRL+p and CTRL+q.<\/p>\n<p>Now, stop the container, and commit it:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ sudo docker stop server_setup<br \/>\n$ sudo docker commit server_setup server_img<\/div><\/div>\n<p>We now have two images: client_img and server_img.<\/p>\n<p>Now we have this set up, we can explore the various connection possibilities.<\/p>\n<p>The Docker Bridge<\/p>\n<p>By default, a Docker container is isolated from other containers and the external network. Docker provides a bridge, the docker0 interface, which is created with the installation of the Docker Engine.<\/p>\n<p>It is through the Docker bridge that communication is possible amongst containers and between containers and the host machine.<\/p>\n<p>You can see the Docker bridge by running this command on a Docker host:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ ifconfig docker0<\/div><\/div>\n<p>You should see something like this in the output:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">docker0 Link encap:Ethernet HWaddr 02:42:a2:dc:0f:a8<br \/>\ninet addr:172.17.0.1 Bcast:0.0.0.0 Mask:255.255.0.0<br \/>\ninet6 addr: fe80::42:a2ff:fedc:fa8\/64 Scope:Link<br \/>\nUP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1<br \/>\nRX packets:1477 errors:0 dropped:0 overruns:0 frame:0<br \/>\nTX packets:2436 errors:0 dropped:0 overruns:0 carrier:0<br \/>\ncollisions:0 txqueuelen:0<br \/>\nRX bytes:83901 (83.9 KB) TX bytes:3606039 (3.6 MB)<\/div><\/div>\n<p>The bridge interface works locally, on a single Docker host, and is the connection mechanism behind all three approaches we cover in this post. In the next post, we\u2019ll move on to the overlay interface, which allows us to network containers across multiple Docker hosts.<\/p>\n<p>Exposing Ports<\/p>\n<p>First, let\u2019s see how we can run a server container so that it exposes port 80 (HTTP) to other containers.<\/p>\n<p>To do so, I run the container with the expose command, which tells Docker to expose port number specified when it runs the container. An exposed port is one that other containers can reach.<\/p>\n<p>Let\u2019s run server_img as a container called server1, exposing port 80:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ sudo docker run -itd --expose=80 --name=server1 server_img \/bin\/bash<\/div><\/div>\n<p>We\u2019ll name our containers sequentially (server1, server2, and so on) as we go.<\/p>\n<p>Then, attach to the container:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ sudo docker attach server1<\/div><\/div>\n<p>Again, If you do not see the shell, click the up arrow.<\/p>\n<p>Start the Apache HTTP server:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ \/etc\/init.d\/apache2 start<\/div><\/div>\n<p>And get the IP address:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ ifconfig<br \/>\neth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:03<br \/>\ninet addr:172.17.0.3 Bcast:0.0.0.0 Mask:255.255.0.0<\/div><\/div>\n<p>Okay, so we have an IP address of 172.17.0.3. Let\u2019s test we can see that from a client container.<\/p>\n<p>Open a second terminal.<\/p>\n<p>Start the client1 container:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ sudo docker run -itd --name=client1 client_img \/bin\/bash<\/div><\/div>\n<p>Attach to it:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ sudo docker attach client1<\/div><\/div>\n<p>If you do not see the shell, click the up arrow.<\/p>\n<p>Make a test connection to the server1 container\u2019s IP address:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ curl 172.17.0.3<\/div><\/div>\n<p>If everything works, you should see the HTML of the Apache HTTP server\u2019s default page. This indicates the the client1 container is able to make connections to the server1 container\u2019s HTTP port.<\/p>\n<p>Port Binding<\/p>\n<p>What if we want to expose our HTTP server to the host network, including application on the host machine, and other machines on the host network? In this scenario, we need to bind a host port to a container port.<\/p>\n<p>To expose the Apache HTTP server to the host network, we need to bind port 80 on the server container to port 8080 on the host machine.<\/p>\n<p>We can do this like so:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ sudo docker run -itd -p 8080:80 --name=server2 server_img \/bin\/bash<\/div><\/div>\n<p>The -p 8080:80 option is the thing to pay attention to here.<\/p>\n<p>Now, attach to the container:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ sudo docker attach server2<\/div><\/div>\n<p>If you do not see the shell, click the up arrow. And start the Apache HTTP server:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ \/etc\/init.d\/apache2 start<\/div><\/div>\n<p>Now, from the host system, visit http:\/\/localhost:8080\/ and you should see the Apache HTTP server default page.<\/p>\n<p>Any machine on your host network that can access port 8080 of your host machine will also be able to access this.<\/p>\n<p>Linking Containers<\/p>\n<p>Another approach to connecting containers involves something Docker calls linking.<\/p>\n<p>When you link one container to another, Docker will make some information about the linked container available via environment variables.<\/p>\n<p>Let\u2019s take a look.<\/p>\n<p>First, start the server container:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ sudo docker run -itd --name=server3 server_img \/bin\/bash<\/div><\/div>\n<p>Now, start the client container and link it to the server container, like so:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ sudo docker run -itd --link server3 --name=client3 client_img \/bin\/bash<\/div><\/div>\n<p>Notice the &#8211;link server3 option being used here.<\/p>\n<p>Now attach to the client container:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ sudo docker attach client3<\/div><\/div>\n<p>And check out the available environment variables:<\/p>\n<p>$<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">&nbsp;env | grep SERVER3<br \/>\nSERVER3_PORT_80_TCP_PROTO=tcp<br \/>\nSERVER3_PORT=tcp:\/\/172.17.0.2:80<br \/>\nSERVER3_PORT_80_TCP_PORT=80<br \/>\nSERVER3_NAME=\/client3\/server3<br \/>\nSERVER3_PORT_80_TCP=tcp:\/\/172.17.0.2:80<br \/>\nSERVER3_PORT_80_TCP_ADDR=172.17.0.<\/div><\/div>\n<p>Docker also updates the \/etc\/hosts file in the client container to add server3 as a local hostname pointing to the server container.<\/p>\n<p>To demonstrate this, run:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">$ curl server3<\/div><\/div>\n<p>You should see the same default HTML again.<\/p>\n<p>Wrap-Up<\/p>\n<p>In part one of this miniseries, we introduced the Docker bridge interface, which lets us connect containers on the same host.<\/p>\n<p>We looked at three connection methods:<\/p>\n<p>Connection through port exposure<br \/>\nBinding of the host port to the container port<br \/>\nLinking two containers through the link option<br \/>\nIn part two, we\u2019ll look at isolating containers inside user-defined networks. We\u2019all also introduce the overlay interface, and take a look at how to use it for networking Docker containers across multiple Docker hosts. Even across datacenters and cloud providers!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Docker containers are self-contained, isolated environments. However, they\u2019re often only useful if they can talk to each other. There are many ways [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-2608","post","type-post","status-publish","format-standard","hentry","category-info-on-tech"],"_links":{"self":[{"href":"https:\/\/blog.designed79.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/2608","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.designed79.co.uk\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.designed79.co.uk\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.designed79.co.uk\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.designed79.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2608"}],"version-history":[{"count":0,"href":"https:\/\/blog.designed79.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/2608\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.designed79.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2608"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.designed79.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2608"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.designed79.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2608"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}