C# and Docker - Can't connect to containerized MySQL server from containerized .NET Core 3.1 Web API

0

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: mysql@8.0 "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.

c#
mysql
docker
.net-core
docker-compose
asked on Stack Overflow Aug 21, 2020 by Steve Boniface

1 Answer

2

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)

answered on Stack Overflow Aug 21, 2020 by Rudu • edited Aug 21, 2020 by Rudu

User contributions licensed under CC BY-SA 3.0