3

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 :)

  • Is the database connection URL that your Go code using right? (just to make sure) – andreybleme Jun 19 '19 at 12:18
  • @andreybleme yup, the url I am using to connect is as I have mentioned above in config. Am connecting to it using mysql driver in go. Will update the go code too :) – Abhilash Gopalakrishna Jun 19 '19 at 12:21
  • 1
    `mysqld --verbose --help | grep bind-address` => check the bind-address – Ntwobike Jun 19 '19 at 12:30
  • @Ntwobike I checked the bind address inside the mysql55c container using the above command, there is no default bind address set. Is this the problem? If yes, do I need to write a docker file to set the bind address to `0.0.0.0` or can i use docker run ? – Abhilash Gopalakrishna Jun 19 '19 at 12:37
  • 1
    If its 0.0.0.0 or its not there at all then you can connect from any ip. Then check your user can connect from docker network `SELECT user,host FROM mysql.user`; => `user | %` or `user | 172.*` also i hope you are referring to mysql by container-name in your go app? – Ntwobike Jun 19 '19 at 12:40
  • @Ntwobike yup , the hosts include `user | %` and `user | localhost` inside the mysql55c container. This should give access to all ip's is what I think. Am i right? – Abhilash Gopalakrishna Jun 19 '19 at 12:45
  • did you try this `root:root@tcp(mysql-ip:3306)/`? – Ntwobike Jun 19 '19 at 12:50
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/195193/discussion-between-abhilash-gopalakrishna-and-ntwobike). – Abhilash Gopalakrishna Jun 19 '19 at 12:55

2 Answers2

8

Thanks to the above answers I was able to resolve my problem.

Anyone who understands basics of docker networks and just want the solution can completely ignore this answer.

I am writing this answer for anyone who might be just starting docker and do not have a clear understanding of docker networks.

Problem: Communication between different docker containers.

To communicate between n different containers in docker we need to first understand how docker network works:

  • Whenever we install docker in our host, a docker0 virtual interface/bridge is created. This is basically a Virtual Ethernet bridge that automatically talks to any other network interfaces that are attached to it.
  • The docker 0 interface has an ip adress, lets say 172.0.0.x.
  • The subsequent containers subnet from this IP.
  • Therefore any communication between the containers can happen either through the docker bridge or using the host private IP.

[![Docker Networks][1]][1]

The above diagram may help you understand it better.

Docker0 : The Docker0 interface with IP.

[![Docker0][2]][2]

Now, to get into the commands:

Use this command to get the IP of a container:

[https://stackoverflow.com/questions/17157721/how-to-get-a-docker-containers-ip-address-from-the-host][3]

docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_name_or_id

SQL container:

docker run --name mysql55c -p 4500:3306 -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=db -d mysql:5.5

The above command creates a container called mysql55c with ip sub-netted from docker0.

Golang container

docker run -w /go/src/app -it -d --name golangapp --link mysql55c:db -v $(pwd):/go/src/app golang bash

The above container creates a container with name golangapp.

The important thing to observe is the --link command.
This command allowed both the containers to discover each other.
But after docker network feature has been introduced this can be done using docker default bridge network or user defined networks.

The container Ip's:

[![dockercontainer ips][4]][4]

Now, we can see that we can communicate between the containers using the default docker bridge network.

For Reference:

Overlay Network

[![enter image description here][5]][5]

User Defined Bridge

[![enter image description here][6]][6]

Default Bridge Network

[![enter image description here][7]][7]

Hope the above helps, feel free to correct me if I am wrong anywhere.

Thank you :) [1]: https://i.stack.imgur.com/jsXKX.png [2]: https://i.stack.imgur.com/wxlTW.png [3]: How to get a Docker container's IP address from the host [4]: https://i.stack.imgur.com/mQl1N.png [5]: https://i.stack.imgur.com/umtNk.png [6]: https://i.stack.imgur.com/wx85d.png [7]: https://i.stack.imgur.com/cDw9w.png

5

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.

mchawre
  • 10,744
  • 4
  • 35
  • 57