Karl
Karl

Reputation: 5733

Docker: Got Connection Timeout when connecting to Oracle Database Container from an Apache Container

Currently, I have a strange issue in that when I try to connect to the Oracle Database container from an Apache Container, I will get "TNS: Connect Timeout Occurred" from oci_error method. My PHP code is as follow:

<?php

        $objConnect = oci_connect('SYSTEM', 'xxxxxxxxxx', 'x.x.x.x/xxxxx');
        if($objConnect)
        {
                echo "from Docker Oracle Server Connected" . PHP_EOL;
        }
        else
        {
                echo "Cannot connect to Oracle Server" . PHP_EOL;
                var_dump( oci_error() );
        }

?>

My docker code to run Oracle Database is:

docker run --name orcl_12c_r_1 -p 1521:1521 -p 5500:5500 -e ORACLE_SID=xxxxx oracle/database:12.1.0.2-se2

And I brought my Apache up with this docker-compose.yml:

version: '3'
services:

  oraclelinuxphp:
    build:
      context: ./oraclelinuxphp
      dockerfile: Dockerfile # install httpd and PHP here.
    ports:
      - "8080:80"
    volumes:
      - ./web:/var/www/html

However, this issue is resolved when I added network_mode host to the docker-compose.yml :

version: '3'
services:

  oraclelinuxphp:
    build:
      context: ./oraclelinuxphp
      dockerfile: Dockerfile # install httpd and PHP here.
    ports:
      - "8080:80"
    volumes:
      - ./web:/var/www/html
    network_mode: "host"

I am still a rookie when it comes to Docker, and from here, I believe I am missing something in Docker. I could connect to the Oracle Database in the container on the server from Oracle SQL Developer app on my desktop without any problem. In addition, I also tried the non-Docker route, and the non-Docker PHP could also connect to this Oracle Database as well.

So I believe this is Docker issue. What am I missing here? How can I make it so the Apache Container could connect to the Oracle Database Container in this case?

Note: I am using :

Upvotes: 1

Views: 3649

Answers (1)

Bjarte Brandt
Bjarte Brandt

Reputation: 4471

There is some convenient magic happening when utilizing docker-compose vs. docker run. Network will implicitly be established.

An example:

cat > docker-compose.yml <<EOF
version: '3'
services:
  c1:
    image: alpine
    container_name: c1
    command: "sleep 1000"
  c2:
    image: alpine
    container_name: c2
    command: "sleep 1000"
EOF

# fire up the containers and detach
docker-compose up -d

These containers will be able to talk to each other due to the fact a default network has been established. (folder_name_default)

docker network ls -fname=demo1
NETWORK ID          NAME                DRIVER              SCOPE
e3777f15f5aa        demo1_default       bridge              local

# c1 can talk to c2
docker-compose exec c1 sh -c 'ping -c1 c2'
PING c2 (172.30.0.2): 56 data bytes
64 bytes from 172.30.0.2: seq=0 ttl=64 time=3.741 ms

# c2 can talk to c1
docker-compose exec c2 sh -c 'ping -c1 c1'
PING c1 (172.30.0.3): 56 data bytes
64 bytes from 172.30.0.3: seq=0 ttl=64 time=0.798 ms

Now, your scenario is that your database container is not attached to the network created by docker-compose. Like this:

docker run --rm -it --name c3 alpine sh -c 'ping -c1 c1'
ping: bad address 'c1'

You can define network for your run-command (this will work):

docker run --rm --net demo1_default -it --name c3 alpine sh -c 'ping -c1 c1'
PING c1 (172.30.0.3): 56 data bytes
64 bytes from 172.30.0.3: seq=0 ttl=64 time=0.571 ms

# make sure c3 keeps running while we try to contact it.
docker run --rm --net demo1_default -d -it --name c3 alpine sh -c 'sleep 1000'

# yes it works! 
docker-compose exec c1 sh -c 'ping -c1 c3'
PING c3 (172.30.0.4): 56 data bytes
64 bytes from 172.30.0.4: seq=0 ttl=64 time=0.314 ms

To bundle all my different components together, I always define them in docker-compose where I explicitly name the network like this:

cat > docker-compose.yml <<EOF
version: '3'
services:
  c1:
    image: alpine
    container_name: c1
    command: "sleep 1000"
    networks:
      - mynet
  c2:
    image: alpine
    container_name: c2
    command: "sleep 1000"
    networks:
      - mynet
networks:
  mynet:
EOF

docker run is just for ad-hoc imperative stuff. I would include the the database service in the docker-compose.yml file or a separate file like docker-compose -f mydb.yml up -d where network-name is defined. From there on your containers will be able to communicate with the database.

Best of luck!

Upvotes: 1

Related Questions