PS D:\*****\Source> docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b648e78c5591 9bed25fc3a24 "/bin/bash ./startup…" 57 minutes ago Up 57 minutes 0.0.0.0:5615->80/tcp, :::5615->80/tcp westwin.service.workflow.webapi edf3bd8262fe de64687c3032 "/bin/bash ./startup…" 58 minutes ago Up 58 minutes 0.0.0.0:5609->80/tcp, :::5609->80/tcp westwin.service.order.webapi 03312a56aed9 a9a5766608ff "/bin/bash ./startup…" 58 minutes ago Up 58 minutes 0.0.0.0:5624->80/tcp, :::5624->80/tcp westwin.service.event.webapi d44ab877332b e6015e117515 "/bin/ ash ./startup…" 58 minutes ago Up 58 minutes 0.0.0.0:5623->80/tcp, :::5623->80/tcp westwin.service.adsplatformproxy.webapi
PS D:\******\Source> docker network ls NETWORK ID NAME DRIVER SCOPE 5ebe144ee98e bridge bridge local 6edd1e0533f5 dockernet bridge local 0c83a22895c9 host host local 3a8422f19f31 none null local
PS D:\******\Source> docker inspect edf3bd8262fe [ { "Id": "edf3bd8262fe6b8d54ff26588deb851b4024d0f1d4f779d7b58ddb37a4538c0c", "Created": "2021-09-19T06:41:58.0528646Z", "Path": "/bin/bash", "Args": [ "./startup.sh", "${WWEntryParameter}", "2\u003e\u00261", " | logger" ], "State": { "Status": "running", "Running": true, "Paused": false, "Restarting": false, "OOMKilled": false, "Dead": false, "Pid": 18197, "ExitCode": 0, "Error": "", "StartedAt": "2021-09-19T06:41:58.7448377Z", "FinishedAt": "0001-01-01T00:00:00Z" }, "Image": "sha256:de64687c30329d7b017628e733f37ecbd90916112559c9bb905c3997f88b2b31", "ResolvConfPath": "/var/lib/docker/containers/edf3bd8262fe6b8d54ff26588deb851b4024d0f1d4f779d7b58ddb37a4538c0c/resolv.conf", "HostnamePath": "/var/lib/docker/containers/edf3bd8262fe6b8d54ff26588deb851b4024d0f1d4f779d7b58ddb37a4538c0c/hostname", "HostsPath": "/var/lib/docker/containers/edf3bd8262fe6b8d54ff26588deb851b4024d0f1d4f779d7b58ddb37a4538c0c/hosts", "LogPath": "/var/lib/docker/containers/edf3bd8262fe6b8d54ff26588deb851b4024d0f1d4f779d7b58ddb37a4538c0c/edf3bd8262fe6b8d54ff26588deb851b4024d0f1d4f779d7b58ddb37a4538c0c-json.log", "Name": "/westwin.service.order.webapi", "RestartCount": 0, "Driver": "overlay2", "Platform": "linux", "MountLabel": "", "ProcessLabel": "", "AppArmorProfile": "", "ExecIDs": null, "HostConfig": { "Binds": [ "D:\\******\\Doc\\TestData:/app/csvdata" ], "ContainerIDFile": "", "LogConfig": { "Type": "json-file", "Config": {} }, "NetworkMode": "default", "PortBindings": { "80/tcp": [ { "HostIp": "", "HostPort": "5609" } ] }, "RestartPolicy": { "Name": "no", "MaximumRetryCount": 0 }, "AutoRemove": false, "VolumeDriver": "", "VolumesFrom": null, "CapAdd": null, "CapDrop": null, "CgroupnsMode": "host", "Dns": [], "DnsOptions": [], "DnsSearch": [], "ExtraHosts": [ "mail.***:192.**.**.**", "geoapi.***.com:192.**.**.**", "b***01:192..**.**.**" ], "GroupAdd": null, "IpcMode": "private", "Cgroup": "", "Links": null, "OomScoreAdj": 0, "PidMode": "", "Privileged": false, "PublishAllPorts": false, "ReadonlyRootfs": false, "SecurityOpt": null, "UTSMode": "", "UsernsMode": "", "ShmSize": 67108864, "Runtime": "runc", "ConsoleSize": [ 0, 0 ], "Isolation": "", "CpuShares": 0, "Memory": 0, "NanoCpus": 0, "CgroupParent": "", "BlkioWeight": 0, "BlkioWeightDevice": [], "BlkioDeviceReadBps": null, "BlkioDeviceWriteBps": null, "BlkioDeviceReadIOps": null, "BlkioDeviceWriteIOps": null, "CpuPeriod": 0, "CpuQuota": 0, "CpuRealtimePeriod": 0, "CpuRealtimeRuntime": 0, "CpusetCpus": "", "CpusetMems": "", "Devices": [], "DeviceCgroupRules": null, "DeviceRequests": null, "KernelMemory": 0, "KernelMemoryTCP": 0, "MemoryReservation": 0, "MemorySwap": 0, "MemorySwappiness": null, "OomKillDisable": false, "PidsLimit": null, "Ulimits": null, "CpuCount": 0, "CpuPercent": 0, "IOMaximumIOps": 0, "IOMaximumBandwidth": 0, "MaskedPaths": [ "/proc/asound", "/proc/acpi", "/proc/kcore", "/proc/keys", "/proc/latency_stats", "/proc/timer_list", "/proc/timer_stats", "/proc/sched_debug", "/proc/scsi", "/sys/firmware" ], "ReadonlyPaths": [ "/proc/bus", "/proc/fs", "/proc/irq", "/proc/sys", "/proc/sysrq-trigger" ] }, "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/27d47fedb7cde946b659f6233fa8b38628d152bff6901b0221fece0e07e83fe3-init/diff:/var/lib/docker/overlay2/uksebeafdghr7qlddh2rbzyh8/diff:/var/lib/docker/overlay2/pylk4zyi2buxtmzx2ks2w7tbb/diff:/var/lib/docker/overlay2/18bjewasy7o7xfvrm8ua8dc5s/diff:/var/lib/docker/overlay2/0166920f7789ebdb00dc301d47f1dfd1eaa955b08f7bea747ec6cc04dd9b891b/diff:/var/lib/docker/overlay2/cc61408415e89795ee3e066f3af3e5351ebcc58392987fba5023c37e5af4f601/diff:/var/lib/docker/overlay2/82e2e7d921391bb41f3fb5472699f18a97402b504698e01884844d2b4c90a9da/diff:/var/lib/docker/overlay2/4380a833bdce9cc32fdc55a85a7516b9e2922be1b788c1e1fddadb58b35d3517/diff:/var/lib/docker/overlay2/b6439ca536b34e1c95d1d3d8e38235a26e50725ec3a571beef84cf3c167a3fae/diff:/var/lib/docker/overlay2/a69068985d54bf1185cffef9817c974107fc1d283c80df93c33d936068fa5be2/diff:/var/lib/docker/overlay2/c40baf2b8540578c389ecb795c5d38a57c489a8ff85924f6dc2503b69327d845/diff:/var/lib/docker/overlay2/b28adb81630da4bd0b05fdd4f00e7ec0af651ae900b4c7f6cc8c3ca6fa1c2a4e/diff:/var/lib/docker/overlay2/cc182b360ebe78e9f954f477697cba195d8be4c6fb0c06e308475948869160b1/diff:/var/lib/docker/overlay2/c8352536a1aee95e42820bfda1d3df3fcb701ee766009b21b21ff447e31b0f93/diff:/var/lib/docker/overlay2/b6f5ebba111a98830f2551c1b53cb59da15f7d3b0a4a8c7f3c53afbc872f11b7/diff:/var/lib/docker/overlay2/5a261595681da21e2ce1961355665e523cd33cdfe8238b839bf8e664426521ed/diff:/var/lib/docker/overlay2/c71b0160895e882c798ca0c00935025aa723aeb823dbc596d0465b5789f8ada2/diff:/var/lib/docker/overlay2/164c34cbdad876d0c1494e6aa40a71c70754d3e1ad6eedd7ccf337f2565c8c33/diff:/var/lib/docker/overlay2/532080ae5a627b78321629e79d67298dcf43f84dd5756644cb2d1bcb52d9631c/diff:/var/lib/docker/overlay2/142ca85576f3d079fc617e92a6406b48d48189126260850c78a29636e99bc48f/diff:/var/lib/docker/overlay2/a310f170caa5bb484dcd35a28c529f7b3b8deb0549257ec83b361cc0d99483ef/diff:/var/lib/docker/overlay2/a11ce7cb84573f877f0c15829a393b811c187bfb46611b4716f3c46f24df6e5e/diff:/var/lib/docker/overlay2/68cbefe327fc1256be79d66814313c0e574e7a1ee90678ad33c25861c6be1db6/diff:/var/lib/docker/overlay2/39f5f6c44698708501ecce348f5aa777754201bdb2c183868303650e13a9ac6d/diff:/var/lib/docker/overlay2/444a67d42a3cdd12ccf06b14ee0d6346445b34de26a6a52b8d459cdbff9f1f7f/diff:/var/lib/docker/overlay2/0cf6a6be4edce04b166363ebf8ec51007b0d0f2a2520dc6adb80a9056537b6ad/diff:/var/lib/docker/overlay2/5c5033b8641d3f2be932eb071b6bea43c223986aac918b88f06e0b2630925277/diff:/var/lib/docker/overlay2/ad9ec80f6cdb645db144aadc0e283b34d8d807b4f7815150a3f461a33d12365d/diff:/var/lib/docker/overlay2/1261f0bcbacf54e0b473aa64439e8c1c1edafd53d116f1d39777840a98f16278/diff:/var/lib/docker/overlay2/04dea18602afbaaecd9e83dbe28d3d634f61709a221191561fb3b788b7c39b9d/diff:/var/lib/docker/overlay2/8dc05653c7919bec9262aa2d82eb8d66ac901101c55af9fb1ed76bdfaf89c555/diff:/var/lib/docker/overlay2/21e0f7578be764756e7a2d28a920bb5c9726994989739ccc23620584216c2018/diff", "MergedDir": "/var/lib/docker/overlay2/27d47fedb7cde946b659f6233fa8b38628d152bff6901b0221fece0e07e83fe3/merged", "UpperDir": "/var/lib/docker/overlay2/27d47fedb7cde946b659f6233fa8b38628d152bff6901b0221fece0e07e83fe3/diff", "WorkDir": "/var/lib/docker/overlay2/27d47fedb7cde946b659f6233fa8b38628d152bff6901b0221fece0e07e83fe3/work" }, "Name": "overlay2" }, "Mounts": [ { "Type": "bind", "Source": "D:\\*****\\Doc\\TestData", "Destination": "/app/csvdata", "Mode": "", "RW": true, "Propagation": "rprivate" } ], "Config": { "Hostname": "edf3bd8262fe", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "ExposedPorts": { "80/tcp": {} }, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "WestWinWorkflowApiBaseUrl=http://192.168.4.55:5615", "SqliteDataDir=/app/csvdata", "WWNamespace=cbop-alpha", "W******=Host=bj****.chn.gbl;Database=cbop_v3.0;Username=b*****;Password=b*****", "EventClientGuid=4c******74", "RequestApiBaseUrl=http://192.**.**.**:5614", "AdsPlatformApiProxyBaseUrl=http://192.**.**.**:5623", "EventApiBaseUrl=http://192.**.**.**:5624", "RedisCacheServer=192.**.**.**:6379,192.**.**.**:6379,192.**.**.**:6379,abortConnect=False", "ZKServerAddress_Local=192.**.**.**", "C******_Test=Host=bj******l;Database=cb****;Username=p****;Password=****;Connection Idle Lifetime=60;Connection Pruning Interval=5;Maximum Pool Size=200", "ElasticSearchServerAddress=http://es..**.**.**:9200", "WalletBillStartYearMonth=201901", "EventClientKey=Jna****", "OrderApiBaseUrl=http://192.**.**.**:5609", "UseSqliteForUT=true", "ZKServerAddress=192.168.33.16,192.168.33.17,192.168.33.18,192.168.33.19,192.168.33.20", "C******=Host=bj******l;Database=cb******;Username=b******r;Password=b******", "B******=Host=b******;Database=b******;Username=b******;Password=b******", "ZKConnectionTimeOut=5", "RedisCacheServer_Local=192.**.**.**:6379,abortConnect=False", "NLOGDIR=/var/log/", "DefaultWFDeciderConsumerId=1", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "ASPNETCORE_URLS=http://+:80", "DOTNET_RUNNING_IN_CONTAINER=true", "DOTNET_RUNTIME_PATH=/usr/share/dotnet/shared/Microsoft.NETCore.App/3.1.17", "ASPNETCORE_RUNTIME_PATH=/usr/share/dotnet/shared/Microsoft.AspNetCore.App/3.1.17", "ASPNETCORE_ALL_RUNTIME_PATH=/usr/share/dotnet/shared/Microsoft.AspNetCore.All/3.1.17", "ProjectName=C***", "ComponentVersion=v3.1.0.4", "WWEntryName=dotnet", "WWEntryParameter=WestWin.Service.Order.WebApi.dll", "WWEntryDesc=WestWinOrderWebApi", "LC_ALL=en_US.UTF-8", "LANG=en_US.UTF-8", "LANGUAGE=en_US.UTF-8", "WW_BUILD_VER=" ], "Cmd": [ "/bin/bash", "./startup.sh", "${WWEntryParameter}", "2\u003e\u00261", " | logger" ], "Image": "de64687c3032", "Volumes": null, "WorkingDir": "/app", "Entrypoint": null, "OnBuild": null, "Labels": { "maintainer": "BingAds Dev \u003cbingadsdev@westwin.com\u003e" } }, "NetworkSettings": { "Bridge": "", "SandboxID": "2119a7a352faa74bd92007d88d8332d495e52e47485aec7121953df4cae3fe48", "HairpinMode": false, "LinkLocalIPv6Address": "", "LinkLocalIPv6PrefixLen": 0, "Ports": { "80/tcp": [ { "HostIp": "0.0.0.0", "HostPort": "5609" }, { "HostIp": "::", "HostPort": "5609" } ] }, "SandboxKey": "/var/run/docker/netns/2119a7a352fa", "SecondaryIPAddresses": null, "EndpointID": "08874f3a70266d36cac0bc0cf71109332d789378653ca41c882e86bafa2adc6b", "Gateway": "172.17.0.1", "GlobalIPv6Address": "", "IPAddress": "172.17.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "MacAddress": "02:42:ac:11:00:02", "Networks": { "bridge": { "Links": null, "Aliases": null, "NetworkID": "5ebe144ee98e4c69de8618aa9c16c89c2a5874101cb0e5acc83ebafa9811d297", "Gateway": "172.17.0.1", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:11:00:02", "DriverOpts": null } } } } ]
PS D:\****\Source> docker inspect b648e78c5591 |findstr "IPAddress" "SecondaryIPAddresses": null, "IPAddress": "172.17.0.4", "IPAddress": "172.17.0.4", PS D:\******\Source> docker exec -ti edf3bd8262fe /bin/bash root@edf3bd8262fe:/app# ping 172.17.0.4 PING 172.17.0.4 (172.17.0.4) 56(84) bytes of data. 64 bytes from 172.17.0.4: icmp_seq=1 ttl=64 time=0.373 ms 64 bytes from 172.17.0.4: icmp_seq=2 ttl=64 time=0.052 ms 64 bytes from 172.17.0.4: icmp_seq=3 ttl=64 time=0.042 ms 64 bytes from 172.17.0.4: icmp_seq=4 ttl=64 time=0.036 ms 64 bytes from 172.17.0.4: icmp_seq=5 ttl=64 time=0.035 ms ^C --- 172.17.0.4 ping statistics --- 5 packets transmitted, 5 received, 0% packet loss, time 176ms rtt min/avg/max/mdev = 0.035/0.107/0.373/0.133 ms root@edf3bd8262fe:/app# curl 172.17.0.4:80/swagger/index.html <!-- HTML for static distribution bundle build --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Swagger UI</title> <link rel="stylesheet" type="text/css" href="./swagger-ui.css"> <link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" /> <link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" /> <style> html { box-sizing: border-box; overflow: -moz-scrollbars-vertical; overflow-y: scroll; } *, *:before, *:after { box-sizing: inherit; } body { margin: 0; background: #fafafa; } </style> </head> <body> <div id="swagger-ui"></div> <!-- Workaround for https://github.com/swagger-api/swagger-editor/issues/1371 --> <script> if (window.navigator.userAgent.indexOf("Edge") > -1) { console.log("Removing native Edge fetch in favor of swagger-ui‘s polyfill") window.fetch = undefined; } </script> <script src="./swagger-ui-bundle.js"></script> <script src="./swagger-ui-standalone-preset.js"></script> <script> /* Source: https://gist.github.com/lamberta/3768814 * Parse a string function definition and return a function object. Does not use eval. * @param {string} str * @return {function} * * Example: * var f = function (x, y) { return x * y; }; * var g = parseFunction(f.toString()); * g(33, 3); //=> 99 */ function parseFunction(str) { if (!str) return void (0); var fn_body_idx = str.indexOf(‘{‘), fn_body = str.substring(fn_body_idx + 1, str.lastIndexOf(‘}‘)), fn_declare = str.substring(0, fn_body_idx), fn_params = fn_declare.substring(fn_declare.indexOf(‘(‘) + 1, fn_declare.lastIndexOf(‘)‘)), args = fn_params.split(‘,‘); args.push(fn_body); function Fn() { return Function.apply(this, args); } Fn.prototype = Function.prototype; return new Fn(); } window.onload = function () { var configObject = JSON.parse(‘{"urls":[{"url":"/swagger/v1/swagger.json","name":"WestWin.Service.Workflow.WebApi API"}],"deepLinking":false,"displayOperationId":false,"defaultModelsExpandDepth":1,"defaultModelExpandDepth":1,"defaultModelRendering":"example","displayRequestDuration":false,"docExpansion":"list","showExtensions":false,"showCommonExtensions":false,"supportedSubmitMethods":["get","put","post","delete","options","head","patch","trace"],"tryItOutEnabled":false}‘); var oauthConfigObject = JSON.parse(‘{"scopeSeparator":" ","scopes":[],"useBasicAuthenticationWithAccessCodeGrant":false,"usePkceWithAuthorizationCodeGrant":false}‘); // Workaround for https://github.com/swagger-api/swagger-ui/issues/5945 configObject.urls.forEach(function (item) { if (item.url.startsWith("http") || item.url.startsWith("/")) return; item.url = window.location.href.replace("index.html", item.url).split(‘#‘)[0]; }); // If validatorUrl is not explicitly provided, disable the feature by setting to null if (!configObject.hasOwnProperty("validatorUrl")) configObject.validatorUrl = null // If oauth2RedirectUrl isn‘t specified, use the built-in default if (!configObject.hasOwnProperty("oauth2RedirectUrl")) configObject.oauth2RedirectUrl = (new URL("oauth2-redirect.html", window.location.href)).href; // Apply mandatory parameters configObject.dom_id = "#swagger-ui"; configObject.presets = [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset]; configObject.layout = "StandaloneLayout"; // Parse and add interceptor functions var interceptors = JSON.parse(‘{"RequestInterceptorFunction":null,"ResponseInterceptorFunction":null}‘); if (interceptors.RequestInterceptorFunction) configObject.requestInterceptor = parseFunction(interceptors.RequestInterceptorFunction); if (interceptors.ResponseInterceptorFunction) configObject.responseInterceptor = parseFunction(interceptors.ResponseInterceptorFunction); // Begin Swagger UI call region const ui = SwaggerUIBundle(configObject); ui.initOAuth(oauthConfigObject); // End Swagger UI call region window.ui = ui } </script> </body> </html> root@edf3bd8262fe:/app#
root@edf3bd8262fe:/app# cat ../etc/hosts 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 192.168.33.11 mail.***** 192.168.33.36 geoapi.***** 192.168.33.71 b.***** 172.17.0.2 edf3bd8262fe root@edf3bd8262fe:/app#
root@edf3bd8262fe:/app# env |grep "192" WestWinWorkflowApiBaseUrl=http://192.168.4.55:5615 OrderApiBaseUrl=http://192.168.4.55:5609 EventApiBaseUrl=http://192.168.4.55:5624 RequestApiBaseUrl=http://192.168.4.55:5614 AdsPlatformApiProxyBaseUrl=http://192.168.4.55:5623
原文链接:
https://www.tutorialworks.com/container-networking/
How To Communicate Between Docker Containers
You’ve gone through the quickstarts and you’ve run your first Docker containers. But now you’re struggling to understand how to run more than one container at the same time. If Docker containers are isolated, then how the heck do they communicate with each other?
Modern apps consist of different components that need to communicate with each other.
In the real world, beyond the realm of the simple hello-world tutorial, running just one container isn’t enough for most apps. A modern application typically consists of a few components – such as a database, a web server, or some microservices.
So if you want to run all of your components in containers, how can the applications talk to each other?
How do containers communicate with each other, if they’re supposed to be isolated?
In this article, we’ll look at simple communication between Docker containers, when they are running on the same host (which is sometimes called single-host networking).
How do containers communicate?
First, a quick overview! Although containers have a level of isolation from the environment around them, they often need to communicate with each other, and the outside world.
Networking or file sharing?
Two containers can talk to each other in one of two ways, usually:
-
Communicating through networking: Containers are designed to be isolated. But they can send and receive requests to other applications, using networking.
For example: a web server container might expose a port, so that it can receive requests on port 80. Or an application container might make a connection to a database container.
-
Sharing files on disk: Some applications communicate by reading and writing files. These kinds of applications can communicate by writing their files into a volume, which can also be shared with other containers.
For example: a data processing application might write a file to a shared volume which contains customer data, which is then read by another application. Or, two identical containers might even share the same files.
File sharing is great, but…. for this article, we’ll look at applications that use networking as the primary way they either expose or consume services.
We’ll talk about how to set up a network, which allows Docker containers on the same host to communicate with other.
If you want to be confident with Docker and Kubernetes, check out Bret Fisher‘s Docker Mastery course on Udemy.
Communication between containers with networking
Most container-based applications talk to each other using networking. This basically means that an application running in one container will create a network connection to a port on another container.
For example, an application might call a REST or GraphQL API, or open a connection to a database.
Containers are ideal for applications or processes which expose some sort of network service. The most well-known examples of these kinds of applications are:
-
Web servers - e.g. Nginx, Apache
-
Backend applications and APIs - e.g. Node, Python, JBoss, Wildfly, Spring Boot
-
Databases and data stores - e.g. MongoDB, PostgreSQL
There are more examples, but these are probably the most common ones!
With Docker, container-to-container communication is usually done using a virtual network.
Building your (Virtual) Network
If you are running more than one container, you can let your containers communicate with each other by attaching them to the same network.
A Docker network lets your containers communicate with each other
Docker creates virtual networks which let your containers talk to each other. In a network, a container has an IP address, and optionally a hostname.
You can create different types of networks depending on what you would like to do. We’ll cover the easiest options:
-
The default bridge network, which allows simple container-to-container communication by IP address, and is created by default.
-
A user-defined bridge network, which you create yourself, and allows your containers to communicate with each other, by using their container name as a hostname.
Default bridge network (easiest option)
The simplest network in Docker is the bridge network. It’s also Docker’s default networking driver.
A bridge network allows containers to communicate with each other
Source: Vektorarte/Freepik
A bridge network gives you simple communication between containers on the same host.
When Docker starts up, it will create a default network called… bridge
. ?? It should start automatically, without any configuration required by you.
From that point onwards, all containers are added into to the bridge
network, unless you say otherwise.
In a bridge network, each container is assigned its own IP address. So containers can communicate with each other by IP.
So let’s see an example of using the default bridge network.
How to use the default bridge network
Here’s how to use the bridge network to get two Docker containers on the same host to talk to each other:
-
Check that the bridge network is running: You can check it’s running by typing
docker network ls
. This should show thebridge
network in the list.$ docker network ls NETWORK ID NAME DRIVER SCOPE acce5c7fd02b bridge bridge local a6998b3cf420 host host local d7f563b21fc6 none null local
-
Start your containers: Start your containers as normal, with
docker run
. When you start each container, Docker will add it to thebridge
network.(If you prefer, you can be explicit about the network connection by adding
--net=bridge
to thedocker run
command.) -
Address another container by its IP address: Now one container can talk to another, by using its IP address.
You’l need to know the IP address of the container - check the little box below to find out how.
How do you find out the IP address of a Docker container?
Example
Here’s a complete example. I’ll start an nginx container. Then I’ll start a busybox container alongside nginx, and try to make a request to Nginx with wget
:
# Start an nginx container, give it the name ‘mynginx‘ and run in the background
$ docker run --rm --name mynginx --detach nginx
# Get the IP address of the container
$ docker inspect mynginx | grep IPAddress
"IPAddress": "172.17.0.2",
# Or, if you have ‘jq‘ installed - here‘s a funky way to get the IP address
$ sudo docker inspect mynginx | jq ‘.[].NetworkSettings.Networks.bridge.IPAddress‘
"172.17.0.2"
# Run busybox (a utility container). It will join the bridge network
$ docker run -it busybox sh
# Fetch the nginx homepage by using the container‘s IP address
busybox$ wget -q -O - 172.17.0.2:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
# Voila! The nginx homepage!
How to check if a container is in the bridge network
The default bridge is….. fine…. but it means every container can see every other container.
What you probably want is: a user-defined network, so that you can be more granular about which containers can see each other.
Let’s look at that option.
User-defined bridge: the more sensible option
If you only use the default bridge
network, then all your containers can see and access other containers’ ports. This isn’t always what you want!
Another “feature” of the default bridge network, is that containers can only talk to each other by their IP address. Obviously, this is a bit brittle, because IP addresses can change.
The second option, the user-defined bridge, lets you have a bit more control.
Get more control, with a user-defined bridge
To let Docker containers communicate with each other by name, you can create a user-defined bridge network. In a user-defined bridge network, you can be more explicit about who joins the network, and you get an added bonus:
…containers can be addressed by their name or alias.
In a user-defined bridge network, you control which containers are in the network, and they can address each other by hostname
Aliases, what are they then?
When these containers are joined to the user-defined bridge network, they can address each other by this name.
This means you don’t need to worry about keeping track of containers’ IP addresses, which can frequently change.
Example: if you run a database in a container, and give it the name mydatabase
, then your app in a container can address the database using the hostname mydatabase
. If you’re using MongoDB, the connection string might look like this: mongodb://mydatabase:27017
How to create a user-defined bridge network
To allow two Docker containers on the same host to communicate with each other by name:
-
Create a user-defined bridge network: Create your own custom bridge network first using
docker network create
. Under the hood, Docker sets up the relevant networking tables on your operating system.For example, I’m going to create a network called
tulip-net
for applications about tulips: ??docker network create tulip-net
-
Start a container and connect it to the bridge: Start your container as normal. Add it to your user-defined bridge network using the
--net
option, e.g.--net tulip-net
.docker run --rm --net tulip-net --name tulipnginx -d nginx
-
Address another container, using its name as the hostname: When two containers are joined to the same user-defined bridge network, one container is able to address another by using its name (as the hostname).
# Start a busybox container so that we can test out the network $ docker run --net tulip-net -it busybox sh # Use ‘wget‘ inside busybox, using the container name as the hostname! busybox$ wget -q -O - tulipnginx:80 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> ...you get the picture....
Can you connect an existing container to a network?
And that’s user-defined bridge networking. It’s a great way to have a custom network set up, and isolation from other containers that aren’t in the network.
TL;DR
Too long, didn’t read? Here’s the gist:
-
For containers to communicate with other, they need to be part of the same “network”.
-
Docker creates a virtual network called
bridge
by default, and connects your containers to it. -
In the network, containers are assigned an IP address, which they can use to address each other.
-
If you want more control (and you definitely do), you can create a user-defined bridge, which will give you the added benefit of hostnames for your containers too.
Happy networking!