Docker for Mac Host Networking - docker

I'm using Docker for Mac. I have two containers.
1st: A PHP application that is attempting to connect to localhost:3306 to MySQL.
2nd: MySQL
When running with links, they are able to reach each other.
However, I would like to avoid changing any of the code in the PHP application (e.g. changing localhost to "mysql") and stay with using localhost.
Host networking seems to do the trick, the problem is, when I enable host networking I can't access the PHP application on port 80 on my host mac.
If I docker exec -it into the php application and curl localhost, i see the HTML, so it looks like the port is just not forwarding to the host machine?

this is an example for docker-compose
it runs mysql in one container and phpmyadmin in another
the containers are linked together
you can access the containers via your host machine on the ports
3316 and 8889
my_mysql:
image: mysql/mysql-server:latest
container_name: my_mysql
environment:
- MYSQL_ROOT_PASSWORD=1234
- MYSQL_DATABASE=test
- MYSQL_USER=test
- MYSQL_PASSWORD=test
ports:
- 3316:3306
restart: always
phpmyadmin:
image: phpmyadmin/phpmyadmin
container_name: my_myadmin
links:
- my_mysql:my_mysql
environment:
- PMA_ARBITRARY=0
- PMA_HOST=my_mysql
ports:
- 8889:80
restart: always

Related

Docker client container couldn't connect to a docker-compose server

I have a docker-compose, that gathers 3 images (mariadb, tomcat and a backup service).
In the end, this exposes a 8080 port on which any user can connect using a browser.
This docker-compose seems to work nicely as I can open a browser (from the host) and browse http://localhost:8080/my service path
I did not try yet from a different machine (I do not have another one where I am currently) but since the default network type is bridge it should work also.
My docker-compose.yml looks like this:
version: "3.0"
networks:
my-network:
services:
mariadb-service:
image: *****
ports:
- "3306:3306"
networks:
- my-network
tomcat-service:
image: *****
ports:
- "8080:8080"
networks:
- my-network
depends_on:
- mariadb-service
backup-service:
image: *****
depends_on:
- mariadb-service
networks:
- my-network
(I remove all the useless stuff)
Now I also have a 'client' docker image allowing to connect to such a server (very similarly to the user with its browser). I'm running this docker image this way:
docker run --name xxx -it -e SERVER_NAME=<ip address of the server> <image name/tag> bash
The strange thing is that this client docker can connect to an external server (running on a production server) but cannot connect to the server docker running locally on the same host.
My understanding is that using default network type (bridge), all docker images can communicate together on the docker host and can also be accessed from outside.
What Am I missing ?
Thanks,

Cannot connect to Mysql using Docker

I build a website using Strapi and Gatsby, everythings works well when I try to connect to a remote database, but I'm trying to create a db inside a container and so far no luck.
Essentially, what I did is create the following docker-compose:
version: '3'
services:
backend:
container_name: myapp_backend
build: ./backend/
ports:
- '3002:3002'
volumes:
- ./backend:/usr/src/myapp/backend
- /usr/src/myapp/backend/node_modules
environment:
- APP_NAME=myapp_backend
- DATABASE_CLIENT=mysql
- DATABASE_HOST=db
- DATABASE_PORT=3307
- DATABASE_NAME=myapp_db
- DATABASE_USERNAME=johnny
- DATABASE_PASSWORD=stecchino
- DATABASE_SSL=false
- DATABASE_AUTHENTICATION_DATABASE=myapp_db
- HOST=localhost
depends_on:
- db
restart: always
db:
container_name: myapp_mysql
image: mysql:5.7
volumes:
- ./db.sql:/docker-entrypoint-initdb.d/db.sql
restart: always
ports:
- 3307:3307
environment:
MYSQL_ROOT_PASSWORD: 5!JF6!FgAkvt
MYSQL_DATABASE: myapp_db
MYSQL_USER: johnny
MYSQL_PASSWORD: stecchino
command: mysqld --character-set-server=utf8 --collation-server=utf8_general_ci --init-connect='SET NAMES UTF8;' --innodb-flush-log-at-trx-commit=0
phpmyadmin:
image: phpmyadmin/phpmyadmin
container_name: 'myapp_phpmyadmin'
links:
- db
environment:
PMA_HOST: db
PMA_PORT: 3307
ports:
- '8081:80'
volumes:
- /sessions
depends_on:
- db
frontend:
container_name: myapp_frontend
build: ./frontend/
ports:
- '3001:3001'
depends_on:
- backend
volumes:
- ./frontend:/usr/src/myapp/frontend
the backend service contains the Strapi application, the db service contains the mysql instance which runs on the port 3307 'cause 3306 is already in use.
Then I have also installed phpmyadmin, and last but not least the Gastby site. When I run using docker-compose up --build, and try to access to phpmyadmin using:
http://localhost:8081/index.php
with the following credentials:
user: johnny
pwd: stecchino
I get:
MySQL mysqli::real_connect():(HY000/2002): Connection refused
now, what I did for fix that situation is pass the port 3306 instead of 3307 to backend and phpmyadmin service. And magically, everything works. But why? I have mapped container and host to 3307...
There are 2 things happening here.
Mysql is running on port 3306.
This is because you never told the mysql container to run on port 3307. The default configuration is running on 3306.
phpadmin can connect to mysql at port 3306.
Of course it can. This is because when you define multiple services within the same docker-compose file, they start on the same network. This means that they can see and connect to each other's internal ports without the need for external port binding like 3306:3306
I would suggest to keep port bindings only for services that you want access outside the docker environment (like the UI), and for internal components just expose the port like this
expose:
- 3306
Both answers are useful, I am particularly fond of Manish's answer
I wanted to add some additional wording:
There are the internal docker networks which nothing from the outside can gain access to. From inside any given service (or container), you can reach every other service (or container) via:
<service-name>:<port>/path/of/resources
<container-name>:<port>/path/of/resources
In order to access resources inside the docker network from outside of docker, whether that is from your host environment, or farther upstream on the internet, the docker daemon needs to bind to host ports, and then forward information received on those ports to a docker service (and ultimately a docker container).
In your docker-compose.yml when you do the 3307:3307 you are telling the docker daemon to listen on port 3307, and forward to your db service internally on it's port 3307.
However, from what we can all see, mysql is still internally (that is, inside the container) listening for traffic on port 3306. Any containers or services on the same docker networks as your db service (mysql running container(s)) would be able to access mysql via something like:
<driver>:mysql://db:3306/<dbname>
If you wanted all host traffic and docker network traffic to access mysql on port 3307, you would also need to configure mysql to listen on port 3307 instead of 3306. That tidbit of information does not appear to be in your question at the time of writing.
I hope the additional information helps! It's a topic I chat often about when talking docker with folks.
Because 3306 is the exposed port by the official Dockerfile.
What you can do is to map the port that is running MySQL to another port on your host: 3307:3306 for instance (always host:container)

Accesing another service using its url from inside the docker-compose network

I am hosting 3 services using docker-compose.
version: '3.3'
services:
service-a:
container_name: service-a
network_mode: default
ports:
- 8001:8001
- 8080:8080
service-b:
container_name: service-b
network_mode: default
ports:
- 8180:8080
links:
- service-a:srv_a
service-api:
container_name: service-api
environment:
- SERVER_URL=http://localhost:8180/myserver
- 8001:8001
links:
- service-b: srv_b
However the service-api which is a spring boot application can't access the
service-b despite the link.
I can do that when using the browser.
What can I do to investigate the reasons for the lack of connectivity?
Should the link be somehow used in the server_url variable?
Each Docker container has it's own IP address. From the service-api container perspective, localhost resolve to its own IP address.
Docker-compose provides your containers with the ability to resolve other containers IP addresses from the docker compose service names.
Try:
service-api:
environment:
- SERVER_URL=http://service-b:8080/myserver
note that you need to connect to the container internal port (8080) and not the matching port published on the docker host (8180).

Access endpoint in one docker container from another

I have a docker-compose file with two services: app and httpd
app
app:
image: primus852/machinelearning:latest
ports:
- 5001:5000
expose:
- "5001"
restart: always
networks:
- default
volumes:
- ./api:/app
environment:
- FLASK_APP=app/source/__init__.py
- FLASK_ENV=development
httpd
httpd:
image: primus852/mitswiki:latest
ports:
- 80:80
restart: always
networks:
- default
volumes:
- ./project:/var/www/html
Flask app
The app container has an endpoint like this:
#app.route('/predict', methods=['GET'])
def predict():
...DO STH....
I can open http://localhost:5001/predict in my browser, works...
I can curl from my cmd: curl localhost:5001/predict, works...
But when I am inside my httpd container this does not work from the console: curl localhost:5001/predict
curl: (7) Failed to connect to localhost port 5001: Connection refused
So I thought I address the app container as I address my mysql from inside my httpd container: curl app:5001/predict but it has the same result.
Can anyone see what I am doing wrong?
According to your yaml:
ports:
- 5001:5000
Inside container you have to use port 5000
Inside the httpd container localhost refers to just that httpd container. It cannot access other containers by default.
Another thing which might be occuring is that your app is not open for 'remote' access. A connection from one container to another one is a remote connection.
Within your docker-compose files you can link containers to eachother
While the containers are linked you can then use curl to get the /predict page by using curl app:5001/predict

traefik hostname works for web apps but not for mongodb

I'm running a mongo instance with docker-compose and traefik.
myapp-mongo:
build: ../images/myapp-mongo
restart: always
ports:
- "27017:27017"
labels:
- "traefik.ports=27017,27018"
- "traefik.backend=myapp-mongo"
- "traefik.frontend.rule=Host:myapp-mongo.docker.localhost"
networks:
- development
environment:
- MONGO_USER=${MONGO_USER}
- MONGO_PASSWD=${MONGO_PASSWD}
- MONGO_AUTHDB=${MONGO_AUTHDB}
Mongo is running fine and I can connect using 127.0.0.1 from my Mac.
The problem is that I can't connect using hostname myapp-mongo.docker.localhost. It only works using IP 127.0.0.1.
Trying to ping the IP 127.0.0.1 responds ok, but trying to ping the hostname doesn't work.
I've already added 127.0.0.1 proxy.docker.localhost into /etc/hosts to get traefik working.
All other web apps has hostnames working fine like eg myapp.docker.localhost. This problem is only happening with this mongodb container.
Probably because Træfik is HTTP proxy and so will only support HTTP/HTTPS connections.
I believe #bpatel is right (see comment I left on his answer with link to github conversation) Traefik at the time of writing only supports HTTP/HTTPS.
Solution using native docker networks
However, you can get around this issue! Since you are using docker, you can work around by using the container name in your code (assuming mongo and your mongo accessing code are both running in containers on a shared docker network. This will be the case if the containers are spun up with docker-compose). Run the following to see if your containers are linked up correctly:
run docker ps to get your container names running (under the NAMES column)
run docker network ls to see your network names
run docker network inspect <target_network_name> to verify your containers from step 1 are on the same network.
I run docker-compose from three separate compose files, so you should be able to cover most cases from the following (apologies for any syntax errors, the following are stripped down code examples):
Entire docker-compose file that that starts up traefik (under directory name 'proxy')
version: '2'
services:
traefik:
image: traefik
command: --web --docker --docker.domain=docker.localhost --logLevel=DEBUG
networks:
- webgateway
ports:
- "80:80"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /dev/null:/traefik.toml
networks:
webgateway:
driver: bridge
snippet from my docker-compose file that spins up mongo
version: '2'
services:
database:
image: mongo
ports:
- "27017:27017"
networks:
- web
networks:
web:
external:
name: proxy_webgateway
snippet from docker-compose that has mongo accessing code
version: '2'
services:
topicOntologyBuilder:
image: topic-ontology-builder
labels:
- "traefik.backend=topicOntologyBuilder"
- "traefik.port=80"
- "traefik.frontend.rule=Host:topic-ontology.docker.localhost"
networks:
- web
volumes:
- ./:/home
networks:
web:
external:
name: proxy_webgateway
Connection in Code
Not certain what language you're using, this is what the following js code looked like for me to connect to mongo (inside that 'topicOntologyBuilder` container, while using traefik as the proxy (again, this works because we're making the most of docker networks):
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://<MONGO_CONTAINER_NAME>/<DB_NAME>', function(err, db) {
//insert code here to interact with mongo
})
Why this works
This works because docker does some clever DNS stuff within the containers so that each container knows the IP of other containers, by looking it up in their DNS entry, by the container names
Extra intel
If your containers are on separate computers/vm's, you'll probably want to play around with a service discovery tool (Consul plays well with Traefik) or do something fancy with a docker network overlay which is specific for containers in a cluster.
If using raw docker networks, you can assign container aliases (this doesn't work with Traefik though, or at least it didn't a couple months back).

Resources