Reputation: 580
For reference, I tried ideas from the following links to no avail:
Docker-Compose Unable to connect to any of the specified MySQL hosts Connect to MySQL container from Web Api .Net Core Container? How to get Ip Address?
I have three containerized apps: [email protected] "exposed" -- for lack of a better term -- behind port 9999; a .NET Core 3.1 WebAPI; and a containerized Angular app. The Angular app can successfully make calls to the WebAPI behind port 5001 just fine. The issue is the web API establishing a connection with the MySQL container, it seems.
All apps are deployed as containers on my local, development workstation. The web API and MySQL db are being deployed with a single docker-compose.yml
which I've shared below. I built a simple image for the front-end application and deployed it from the Docker command line.
Here is my docker-compose.yml
for the API and DB:
version: "3.3"
services: # list of services composing your application
db: # the service hosting your MySQL instance
image: mysql:8.0 # the image and tag docker will pull from docker hub
volumes: # this section allows you to configure persistence within multiple restarts
- db_data:/var/lib/mysql
restart: always # if the db crash somehow, restart it
ports:
- "9999:3306"
environment: # env variables, you usually set this to override existing ones
MYSQL_ROOT_PASSWORD: *****
networks:
- soar-network
soar-api: # you application service
build: ./ # this tells docker-compose to not pull from docker hub, but to build from the Dockerfile it will find in ./
restart: always
ports:
- "5001:80"
networks:
- soar-network
# set a dependency between your service and the database:
# this means that your application will not run if the db service is not running,
# but it doesn't assure you that the dabase will be ready to accept incoming connection
# (so your application could crash untill the db initializes itself)
depends_on:
- db
volumes:
db_data: # this tells docker-compose to save your data in a generic docker volume. You can see existing volumes typing 'docker volume ls'
networks:
soar-network:
driver: bridge
The Web API code is using the following connection string for the DbContext
I'm using in my code:
"ConnectionStrings": {
"DefaultConnection": "server=localhost;port=9999;uid=root;pwd=*****;database=SoarDb"
}
Note the port
in the connection string matches what I'm mapping in the docker-compose
. I have tried using 3306
and 33060
, as well, to no avail.
I've also tried using 127.0.0.1
as the server
value with no luck.
The error being logged in the web API container is as follows:
soar-api_1 | fail: Microsoft.EntityFrameworkCore.Database.Connection[20004]
soar-api_1 | An error occurred using the connection to database 'SoarDb' on server 'localhost'.
soar-api_1 | fail: Microsoft.EntityFrameworkCore.Query[10100]
soar-api_1 | An exception occurred while iterating over the results of a query for context type 'DataAccess.SoarDataContext'.
soar-api_1 | MySql.Data.MySqlClient.MySqlException (0x80004005): Unable to connect to any of the specified MySQL hosts.
soar-api_1 | at MySqlConnector.Core.ServerSession.ConnectAsync(ConnectionSettings cs, ILoadBalancer loadBalancer, IOBehavior ioBehavior, CancellationToken cancellationToken) in C:\projects\mysqlconnector\src\MySqlConnector\Core\ServerSession.cs:line 442
The other strange thing is: I can add migrations and update the database with dotnet-ef add migration
and dotnet-ef database update
to this particular containerized db.
Any insight is greatly appreciated. I have tried many different permutations of settings and tweaks with no luck and don't know what I'm misunderstanding.
Upvotes: 4
Views: 4183
Reputation: 15892
Your mistake is that from the point of view of the soar-api
container, localhost
just refers back to the container (in which soar-api
is running)... not the server docker is running on (which is the next tier up).
Instead you should be able to set your connection string to server=db;port=3306;...
This is because docker provides a DNS agent that allows you to access containers by name on the same network (which it looks like you've setup correctly with soar-network
)
In practice container db
gets an IP (say: A) while container soar-api
gets another IP (B). Your connection from B needs to specify the IP address A, which you cannot know unless you configure your docker-compose to specify (you can do this too, but as you've written it docker will handle it for you)
I imagine you were running your migrations outside on the main server, not from within either container.
You may not need to expose MySQL on 9999
in your docker-compose
if no other services need to directly access it (this is for external computers to connect to the docker-server and access the service).
Note 127.0.0.1
(any address in the 127.0.0.0/8
space, in fact) is a synonym for localhost
. Also ::1/128
(IPv6, if it's enabled)
Upvotes: 5