I wrote an application in Typescript which use Typeorm to interact with a MySQL database. When I run the app using npm run dev which is a package.json script, the connection is working fine with these credentials:
"type": "mysql",
"host": "127.0.0.1",
"port": 3306,
"username": "root",
"password": "root",
"database": "mydb",
but when I launch my Docker container I get:
> Error: connect ECONNREFUSED 127.0.0.1:3306
> errno: -111,
> code: 'ECONNREFUSED',
> syscall: 'connect',
> address: '127.0.0.1',
> port: 3306,
> fatal: true
I cannot figure out of this problem, I also tried to change 127.0.0.1 with localhost but same problem. That's weird 'cause I'm using Dbeaver to connect with my LAMP which is a Docker container container too and I can establish the connection.
Seems a problem related only with the containers connection, maybe the container of the app doesn't know the network 127.0.0.1?
This is my image file:
FROM node:stretch-slim
WORKDIR /myapp
COPY package.json ./
COPY ./dist ./dist
RUN npm install
EXPOSE 4000
ENV NODE_ENV development
ENV PORT 4000
ENV URL http://localhost:4000
ENV JWT_SECRET secret
CMD ["npm", "run", "start", "dev"]
and this is my docker-compose.yml:
version: '3'
services:
app:
container_name: myapp
restart: always
build: .
ports:
- '4000:4000'
for compile my containers I did: docker-compose up --build
What is wrong? As you can see from my lamp container each port is correctly exposed:
The problem here is that each container use their own network, even though I exposed the mysql container on port 3306 I cannot access to mysql from the myapp container, because myapp container use another network.
So executing the following command: docker network ls I was able to list all the networks available, and then I did:
docker network inspect bridge
which has returned the following gateway: 172.17.0.1
The solution would be to replace localhost with 172.17.0.1. But I don't like the following solution too much, so I rebuilded the myapp image adding previously network_mode inside the docker-compose.yml, so now I have:
version: '3'
services:
app:
container_name: myapp
restart: always
build: .
ports:
- '4000:4000'
network_mode: 'host'
as documentation says:
If you use the host network mode for a container, that container’s network stack is not isolated from the Docker host (the container shares the host’s networking namespace), and the container does not get its own IP-address allocated. For instance, if you run a container which binds to port 80 and you use host networking, the container’s application is available on port 80 on the host’s IP address.
I don't know if there is a better solution out there, I'm a Docker noob so far, so maybe someone more expert on this could propose a better solution to share a container network such as mysql, and then access to that shared network from others containers.
Another solution would be "host": "host.docker.internal"
docker-composedocker-compose isn't limited to just one service, you can have the whole system, which, in your case, means the DB server, your app, and all the other things.
You can change your docker-compose.yml file to something like below (MySQL bit copied from https://hub.docker.com/_/mysql )
version: '3'
services:
db:
image: mysql
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
app:
container_name: myapp
restart: always
build: .
ports:
- '4000:4000'
Because your containers are brought up in the same docker-compose, by default they have access to each other by hostname e.g. app, and db. To try this out, bring them up, docker attach/exec to app, and try a ping db.
See https://stackoverflow.com/a/30173220/1148483
This means that in your app, you can use db as the DB host config.