112

i created two docker containers based on two different images. one of db and another for webserver. both containers are running on my mac osx.

i can access db container from host machine and same way can access webserver from host machine.

however, how do i access db connection from webserver?

the way i started db container is

docker run --name oracle-db -p 1521:1521 -p 5501:5500 oracle/database:12.1.0.2-ee

I started wls container as

docker run --name oracle-wls -p 7001:7001 wls-image:latest

I can access db on host by connecting to

sqlplus scott/welcome1@//localhost:1521/ORCLCDB

I can access wls on host as

http://localhost:7001/console
Mustapha-Belkacim
  • 904
  • 1
  • 9
  • 14
Vik
  • 6,991
  • 23
  • 73
  • 138
  • So both the web container and the db container are on the host machine? If so, which version of docker are you using? Because older versions of docker had one way of doing it, while the new versions have a different way. Are you also able to use docker-compose? Which will make it easier, but I don't want to give an answer using a method you can't use. – Caperneoignis Dec 27 '17 at 12:58
  • [this answer](https://stackoverflow.com/questions/31324981/how-to-access-host-port-from-docker-container/43541732) may help, how to access localhost from a container in mac os – Chaojun Zhong Mar 13 '19 at 07:30
  • For external networking, this solution worked for me https://stackoverflow.com/a/38089080/1770571 – Salma Gomaa Aug 16 '20 at 08:51
  • Does this answer your question? [How to get Docker containers to talk to each other while running on my local host?](https://stackoverflow.com/questions/41093812/how-to-get-docker-containers-to-talk-to-each-other-while-running-on-my-local-hos) – mkrieger1 Nov 22 '20 at 18:14

4 Answers4

70

It's easy. If you have two or more running container, complete next steps:

docker network create myNetwork
docker network connect myNetwork web1
docker network connect myNetwork web2

Now you connect from web1 to web2 container or the other way round.

Use the internal network IP addresses which you can find by running:

docker network inspect myNetwork

Note that only internal IP addresses and ports are accessible to the containers connected by the network bridge.

So for example assuming that web1 container was started with: docker run -p 80:8888 web1 (meaning that its server is running on port 8888 internally), and inspecting myNetwork shows that web1's IP is 172.0.0.2, you can connect from web2 to web1 using curl 172.0.0.2:8888).

mirekphd
  • 1,539
  • 12
  • 22
MxWild
  • 1,435
  • 9
  • 7
60

Easiest way is to use --link, however the newer versions of docker are moving away from that and in fact that switch will be removed soon.

The link below offers a nice how too, on connecting two containers. You can skip the attach portion, since that is just a useful how to on adding items to images.

https://web.archive.org/web/20160310072132/https://deis.com/blog/2016/connecting-docker-containers-1/

The part you are interested in is the communication between two containers. The easiest way, is to refer to the DB container by name from the webserver container.

Example:

you named the db container db1 and the webserver container web0. The containers should both be on the bridge network, which means the web container should be able to connect to the DB container by referring to it's name.

So if you have a web config file for your app, then for DB host you will use the name db1.

if you are using an older version of docker, then you should use --link.

Example:

Step 1: docker run --name db1 oracle/database:12.1.0.2-ee

then when you start the web app. use:

Step 2: docker run --name web0 --link db1 webapp/webapp:3.0

and the web app will be linked to the DB. However, as I said the --link switch will be removed soon.

I'd use docker compose instead, which will build a network for you. However; you will need to download docker compose for your system. https://docs.docker.com/compose/install/#prerequisites

an example setup is like this:

file name is base.yml

version: "2"
services:
  webserver:
    image: moodlehq/moodle-php-apache:7.1
    depends_on:
      - db
    volumes:
      - "/var/www/html:/var/www/html"
      - "/home/some_user/web/apache2_faildumps.conf:/etc/apache2/conf-enabled/apache2_faildumps.conf"
    environment:
      MOODLE_DOCKER_DBTYPE: pgsql
      MOODLE_DOCKER_DBNAME: moodle
      MOODLE_DOCKER_DBUSER: moodle
      MOODLE_DOCKER_DBPASS: "m@0dl3ing"
      HTTP_PROXY: "${HTTP_PROXY}"
      HTTPS_PROXY: "${HTTPS_PROXY}"
      NO_PROXY: "${NO_PROXY}"
  db:
    image: postgres:9
    environment:
      POSTGRES_USER: moodle
      POSTGRES_PASSWORD: "m@0dl3ing"
      POSTGRES_DB: moodle
      HTTP_PROXY: "${HTTP_PROXY}"
      HTTPS_PROXY: "${HTTPS_PROXY}"
      NO_PROXY: "${NO_PROXY}"

this will name the network a generic name, I can't remember off the top of my head what that name is, unless you use the --name switch.

IE docker-compose --name setup1 up base.yml

NOTE: if you use the --name switch, you will need to use it when ever calling docker compose, so docker-compose --name setup1 down this is so you can have more then one instance of webserver and db, and in this case, so docker compose knows what instance you want to run commands against; and also so you can have more then one running at once. Great for CI/CD, if you are running test in parallel on the same server.

Docker compose also has the same commands as docker so docker-compose --name setup1 exec webserver do_some_command

best part is, if you want to change db's or something like that for unit test you can include an additional .yml file to the up command and it will overwrite any items with similar names, I think of it as a key=>value replacement.

Example:

db.yml

version: "2"
services:
  webserver:
    environment:
      MOODLE_DOCKER_DBTYPE: oci
      MOODLE_DOCKER_DBNAME: XE
  db:
    image: moodlehq/moodle-db-oracle

Then call docker-compose --name setup1 up base.yml db.yml

This will overwrite the db. with a different setup. When needing to connect to these services from each container, you use the name set under service, in this case, webserver and db.

I think this might actually be a more useful setup in your case. Since you can set all the variables you need in the yml files and just run the command for docker compose when you need them started. So a more start it and forget it setup.

NOTE: I did not use the --port command, since exposing the ports is not needed for container->container communication. It is needed only if you want the host to connect to the container, or application from outside of the host. If you expose the port, then the port is open to all communication that the host allows. So exposing web on port 80 is the same as starting a webserver on the physical host and will allow outside connections, if the host allows it. Also, if you are wanting to run more then one web app at once, for whatever reason, then exposing port 80 will prevent you from running additional webapps if you try exposing on that port as well. So, for CI/CD it is best to not expose ports at all, and if using docker compose with the --name switch, all containers will be on their own network so they wont collide. So you will pretty much have a container of containers.

UPDATE: After using features further and seeing how others have done it for CICD programs like Jenkins. Network is also a viable solution.

Example:

docker network create test_network

The above command will create a "test_network" which you can attach other containers too. Which is made easy with the --network switch operator.

Example:

docker run \
    --detach \
    --name db1 \
    --network test_network \
    -e MYSQL_ROOT_PASSWORD="${DBPASS}" \
    -e MYSQL_DATABASE="${DBNAME}" \
    -e MYSQL_USER="${DBUSER}" \
    -e MYSQL_PASSWORD="${DBPASS}" \
    --tmpfs /var/lib/mysql:rw \
    mysql:5

Of course, if you have proxy network settings you should still pass those into the containers using the "-e" or "--env-file" switch statements. So the container can communicate with the internet. Docker says the proxy settings should be absorbed by the container in the newer versions of docker; however, I still pass them in as an act of habit. This is the replacement for the "--link" switch which is going away. Once the containers are attached to the network you created you can still refer to those containers from other containers using the 'name' of the container. Per the example above that would be db1. You just have to make sure all containers are connected to the same network, and you are good to go.

For a detailed example of using network in a cicd pipeline, you can refer to this link: https://git.in.moodle.com/integration/nightlyscripts/blob/master/runner/master/run.sh

Which is the script that is ran in Jenkins for a huge integration tests for Moodle, but the idea/example can be used anywhere. I hope this helps others.

Martin Valgur
  • 4,301
  • 23
  • 35
Caperneoignis
  • 1,166
  • 12
  • 16
  • 1
    If the first link doesn't work, you can use this one. https://www.linode.com/docs/applications/containers/docker-container-communication/#connect-two-containers – Caperneoignis Aug 08 '19 at 16:03
  • 1
    For Doing Docker compose or doing network, how would the webserver reference the DB? Would it use the name of the container? It looks like in the second link that is the case: So if you define a DB and an APP, the app would have to reference in this case: `psql -U {USER} -h database -p 5432 {DATABASE}` from within the container if i were shelled into it – Fallenreaper Oct 04 '20 at 19:08
  • 1
    @Fallenreaper if you are in the container and did docker compose you would use the name, used under "services:" if you didn't explicitly give it a name. So in the example you would use "webserver" if you were trying to connect from the "db" container in the shell. Look at example for db.yml you would use the names webserver and db. Sorry for the delay got sidetracked and forgot the notice. – Caperneoignis Oct 22 '20 at 15:40
22

You will have to access db through the ip of host machine, or if you want to access it via localhost:1521, then run webserver like -

docker run --net=host --name oracle-wls wls-image:latest

See here

Community
  • 1
  • 1
xitter
  • 538
  • 3
  • 15
  • 1
    how will this work in real life as ip of host will change based on which machine containers are running. – Vik Feb 23 '17 at 01:01
  • 1
    That is valid only if machine has static ip or DNS, else go with the second approach. – xitter Feb 23 '17 at 12:23
  • i seems to have issue with this. my exact run command is: docker run --name ora-tools-wls -it -p 7001:7001 orawls this works and let me access my server running on this container as http://localhost:7001/console However, the db access from server need exact ip to reach another container running the DB. If I go with docker run --name ora-tools-wls -it -p 7001:7001 --network="host" orawls then server is able to access db with localhost as ip as you mentioned but access server in host machine browser fails. – Vik Feb 24 '17 at 06:08
  • 4
    You don't need to define `-p 7001:7001`, as all container is using the host's network stack itself. – xitter Feb 25 '17 at 07:23
  • @Vik , I had the same trouble and found that it isn't supported on the mac. maybe that is what you are doing as well. > The host networking driver only works on Linux hosts, and is not supported on Docker Desktop for Mac, Docker Desktop for Windows, or Docker EE for Windows Server. https://docs.docker.com/network/host/ – Brent Fisher Oct 22 '20 at 03:40
16

Using docker-compose, services are exposed to each other by name by default. Docs.
You could also specify an alias like;

version: '2.1'
services:
  mongo:
    image: mongo:3.2.11
  redis:
    image: redis:3.2.10
  api:
    image: some-image
    depends_on:
      - mongo
      - solr
    links:
      - "mongo:mongo.openconceptlab.org"
      - "solr:solr.openconceptlab.org"
      - "some-service:some-alias"

And then access the service using the specified alias as a host name, e.g mongo.openconceptlab.org for mongo in this case.

Martin Valgur
  • 4,301
  • 23
  • 35
Karuhanga
  • 1,781
  • 1
  • 18
  • 25