Reputation: 93
I have 2 containers: a simple golang program and mysql. I can start both but the golang application can not connect to mysql. I receive Connection Refused.
If I docker exec
into the mysql container and try to connect locally with mysql -u root -p
all works well.
If on the the host I try to connect to the container with mysql -h 0.0.0.0 -P 10000 -u root -p
all works well.
I added MYSQL_ROOT_HOST: '%'
in docker-compose
and bind-address = 0.0.0.0
into mysqld.cnf
but still not working.
What I'm doing wrong?
docker-compose
version: '3'
services:
web:
build:
context: .
dockerfile: docker/web/Dockerfile
ports:
- "8081:8081" # http
- "443:443" # https
links:
- db_private
volumes:
- ../../../../.:/go
db_private:
image: mysql:5.7
restart: always
environment:
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_ROOT_HOST: '%'
ports:
- '10000:3306'
expose:
- '3306'
volumes:
- ./mysql-entry-point.sql:/docker-entrypoint-initdb.d
- private-db:/var/lib/mysql
- ./mysqld.cnf:/etc/mysql/mysql.conf.d/mysqld.cnf
# Names our volume
volumes:
private-db:
Web container Dockerfile
FROM golang:alpine
RUN mkdir /app
ADD . /app/
WORKDIR /app
RUN apk update && apk upgrade && apk add --no-cache bash git openssh
RUN go get github.com/jinzhu/gorm
RUN go get github.com/jinzhu/gorm/dialects/mysql
RUN go get github.com/gin-gonic/gin
RUN go get github.com/gin-contrib/cors
RUN go build -o main .
RUN adduser -S -D -H -h /app appuser
USER appuser
CMD ["./main"]
Golang file
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
"net/http"
"time"
)
var db *gorm.DB
type (
FooModel struct {
Id int64 `gorm:"primary_key"`
name string
}
)
func init() {
//open a db connection
var err error
db, err = gorm.Open("mysql", "user:pwd@(0.0.0.0:10000)/myDB?charset=utf8&parseTime=true")
if err != nil {
fmt.Println(err)
panic("failed to connect database")
}
//Migrate the schema
db.AutoMigrate(&FooModel{})
db.LogMode(true)
}
// main inits routes
func main() {
router := gin.Default()
router.GET("/getExample", getExample)
router.Run("0.0.0.0:8081")
}
func getExample(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": "bye"})
}
I copy the mysqld.cnf
in the container with this
[mysqld]
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
#log-error = /var/log/mysql/error.log
# By default we only accept connections from localhost
#bind-address = 127.0.0.1
bind-address = 0.0.0.0
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
Upvotes: 2
Views: 5201
Reputation: 698
This can be helpful for someone! I had the same issue and spent 5 hours to figure out the issue. In my case, I was using "sqlc" for golang and also wanted to pass connection string via compose file.
But I got error like access denied to 'root'@'x.x.x.x' when I tried to call api by postman. Long story short, I remove double quotation marks form DB_SOURCE, and it worked!
- DB_SOURCE=root:my-secret-pw@tcp(mysql:3306)/simple_bank?parseTime=true&autocommit=true
Upvotes: 0
Reputation: 237
You can simply solve the problem in just 3 steps
:
ports
from 10000:3306
to 3306:3306
in the docker-compose
file.0.0.0.0:10000
to db_private:3306
in the Golang file
.docker-compose up --build
Upvotes: 0
Reputation: 8877
0.0.0.0
is not your container's IP address. It's a special address meaning "all available interfaces".
You are connecting from your Host to the Container with 0.0.0.0
because they do share an interface because you exposed the ports in your docker-compose.yml
file.
If your application is always going to live in a container, and your database is always going to live in a container, Docker provides a method for you to connect one to the other.
db_private
, the service name, can be found from your web
(or golang) container.
This will always work, because Docker has an internal DNS server which your containers can use, no matter which IP address your containers have.
host> docker-compose up -d
host> docker-compose exec web /bin/sh
web$ ping db_private
Yes, you always want to use 0.0.0.0
as bind interfaces within containers because you never know WHICH IP address you will get, so that's like a shortcut to say "all".
Upvotes: 1
Reputation: 11
In my case, instead use db_private
of Docker host, I get my local IP by running:
ipconfig getifaddr en0
=> 172.16.4.227
Then I use this IP in my gorm SQL connection:
db, err = gorm.Open("mysql", "user:pwd@(172.16.4.227:10000)/myDB?charset=utf8&parseTime=true")
This worked for me
Upvotes: 0
Reputation: 51632
Your web app is running in a container, which means the address 0.0.0.0 is the container itself, not the host it is running on. Try connecting the db using db_private
name instead of the address 0.0.0.0.
Upvotes: 2