Search code examples
dockerjenkinscontainersdevopsdockerhub

Access MySQL in one container from another container


I am trying the following:

  • spin MySQL 5.5 in one container with an exposed port, say 4200.
  • spin MySQL 5.7 in one container with an exposed port, say 4300.
  • spin a golang container to run my app.

The idea is I need my tests to run against different database versions.

For this I need to be able to talk to each of the sql containers from my golang container.

What I have tried:

Method 1 - Using --link:

MYSQL CONTAINER:

docker run --name mysql55c -p 127.0.0.1:4200:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql:5.5

GO LANG APP CONTAINER

docker run -w /go/src/app -it --link mysql55c -d --name golangapp -v $(pwd):/go/src/app golang bash -c "go get github.com/go-sql-driver/mysql;go build main.go; go test -v
--config ./config.ini"

Method 2 - Using --net (bridge network &host): Create a bridge nw

docker network mynw

MYSQL CONTAINER:

docker run --name mysql55c --net mynw -p 127.0.0.1:4200:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql:5.5

GO LANG APP CONTAINER

docker run -w /go/src/app -it --net mynw -d --name golangapp -v $(pwd):/go/src/app golang bash -c "go get github.com/go-sql-driver/mysql;go build main.go; go test -v
--config ./config.ini"

Instead of creating a bridge network of my own I also tired

--net host

I am able to connect to the sql containers from the host - mysql workbench. But, the golangapp is getting a connection refused error when trying to connect to the mysql servers inside the containers.

All the containers are on the same host.

I am not using a dockerfile or docker compose as:

  • trying to get the above done with docker cli commands for easy jenkins integration using official docker images.

Go code to connect to the db using config url

func dbconn() (*sql.DB, error) {
    opendb, err := sql.Open("mysql", *dsn + *dbname) //coming from flag
    if err != nil {
        return nil, err
    }
    return opendb, nil
}

dsn url combinations I have tried in config:

  • dsn = "root:root@tcp(localhost:4200)/"
  • dsn = "root:root@tcp(172.17.0.0.x:4200)/" (docker0 ip)

  • dbname="somename"

How can we look at the above? Suggestions about best practices or new methods to achieve my objective are welcome :) Need Help!! Thank you :)


Solution

  • This should work, follow these steps:

    • Run mysql container docker run --name mysql55c -p 4200:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql:5.5
    • Create Dockerfile for golang with following contents:
    FROM golang:latest
    
    COPY . /
    RUN go get "github.com/go-sql-driver/mysql"
    CMD go run /main.go
    
    • Create main.go with following contents:
    package main
    
    import(
            _ "github.com/go-sql-driver/mysql"
            "database/sql"
            "log"
    )
    
    func main() {
        // Open up our database connection.
        db, err := sql.Open("mysql", "root:root@tcp(192.168.0.33:4200)/mysql")
    
        // if there is an error opening the connection, handle it
        if err != nil {
            log.Print(err.Error())
        } else {
            log.Print("DB connected successfully")
        }
    
        defer db.Close()
    
    }
    
    • Build golang container image using docker build -t goapp .
    • Run golang container docker run -itd goapp
    • Check logs of the golang container:
    $ docker logs dbd5294abd61
    2019/06/19 13:24:17 DB connected successfully
    

    NOTE: I ran mysql container which is exposed on 4200 port of the host. In golang code my connection string was root:root@tcp(192.168.0.33:4200)/mysql where 192.168.0.33 is private ip of my machine.

    The main takeaway for you should be that your db connection string should point to private/public ip of your host. If you run golang without container linking.

    If container linking is used while running golang suppose docker run -itd --link mysql55c:mydb goapp then mysql connection string in your golang code should be root:root@tcp(mydb:4200)/mysql

    Try this and let me know.