I have created a docker-compose file it has two services with Go
and Mysql
. It creates container for go and mysql. Now i am running code which try to connect to mysql database which is running as a docker container. but i get error.
docker-compose.yml
version: "2"
services:
app:
container_name: golang
restart: always
build: .
ports:
- "49160:8800"
links:
- "mysql"
depends_on:
- "mysql"
mysql:
image: mysql
container_name: mysql
volumes:
- dbdata:/var/lib/mysql
restart: always
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=testDB
- MYSQL_USER=root
- MYSQL_PASSWORD=root
ports:
- "3307:3306"
volumes:
dbdata:
Error while connecting to mysql database
golang | 2019/02/28 11:33:05 dial tcp 127.0.0.1:3306: connect: connection refused
golang | 2019/02/28 11:33:05 http: panic serving 172.24.0.1:49066: dial tcp 127.0.0.1:3306: connect: connection refused
golang | goroutine 19 [running]:
Connection with MySql Database
func DB() *gorm.DB {
db, err := gorm.Open("mysql", "root:root@tcp(mysql:3306)/testDB?charset=utf8&parseTime=True&loc=Local")
if err != nil {
log.Panic(err)
}
log.Println("Connection Established")
return db
}
EDIT:Updated docker file
FROM golang:latest
RUN go get -u github.com/gorilla/mux
RUN go get -u github.com/jinzhu/gorm
RUN go get -u github.com/go-sql-driver/mysql
COPY ./wait-for-it.sh .
RUN chmod +x /wait-for-it.sh
WORKDIR /go/src/app
ADD . src
EXPOSE 8800
CMD ["go", "run", "src/main.go"]
I am using gorm package which lets me connet to the database
depends_on
is not a verification that MySQL is actually ready to receive connections. It will start the second container once the database container is running regardless it was ready for connections or not which could lead to such an issue with your application as it expects the database to be ready which might not be true.Quoted from the documentation:
There are many tools/scripts that can be used to solve this issue like wait-for which
sh
compatible in case your image based onAlpine
for example (You can use wait-for-it if you have bash in your image)All you have to do is to add the script to your image through
Dockerfile
then use this command indocker-compose.yml
for the service that you want to make it wait for the database.What comes after
--
is the command that you would normally use to start your applicationSee Controlling startup order for more on this problem and strategies for solving it.
Another issue that will rise after you solve the connection issue will be as the following:
Setting
MYSQL_USER
withroot
value will cause a failure in MySQL with this error message:This is because this user already exist in the database and it tries to create another. if you need to use the root user itself you can use only this variable
MYSQL_ROOT_PASSWORD
or change the value ofMYSQL_USER
so you can securely use it in your application instead of the root user.Update: In case you are getting not found and the path was correct, you might need to write the command as below:
First, if you are using latest version of docker compose you don't need the link argument in you app service. I quote the docker compose documentation
Warning: The --link flag is a legacy feature of Docker. It may eventually be removed. Unless you absolutely need to continue using it,
https://docs.docker.com/compose/compose-file/#linksI think the solution is to use the
networks
argument. This create a docker network and add each service to it.Try this
By the way, if you only connect to Mysql from your app service you don't need to expose the mysql port. If the containers runs in the same network they can reach all ports inside this network.
If my example doesn't works try this run the docker compose and next go into the app container using
docker container exec -it CONTAINER_NAME bash
Installping
in order to test connection and then run ping mysql.