I have a little project in Go basically with a connection.
Dockerfile
FROM golang:1.22.3 AS build-stage
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /go-start ./cmd/server/main.go
FROM scratch
WORKDIR /
COPY --from=build-stage /go-start /go-start
COPY --from=build-stage /app/.env .env
EXPOSE 8080
ENTRYPOINT ["/go-start"]
Then I have a docker-compose.yml with my Dockerfile and a MySQL image
services:
zumenu-backoffice-api:
container_name: zumenu-backoffice-api
build:
context: .
dockerfile: ./Dockerfile
ports:
- 8080:8080
env_file:
- ./.env
depends_on:
- mysql
networks:
- zumenu-network
mysql:
image: mysql:5.7
container_name: mysql-zumenu-backoffice
platform: linux/amd64
volumes:
- ./build/mysql:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=${DB_PASSWORD}
- MYSQL_DATABASE=${DB_NAME}
- MYSQL_PASSWORD=${DB_PASSWORD}
ports:
- 3312:3306
networks:
- zumenu-network
networks:
zumenu-network:
driver: bridge
And my Go code to establish the connection
package configs
import (
"errors"
_ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
)
func LoadConDB() (*sqlx.DB, error) {
db, err := sqlx.Connect("mysql", "root:root@(localhost:3312)/zumenu_db")
// or mysql:3306 or mysql-zumenu-backoffice:3306 don't work
if err != nil {
return nil, errors.New("failed to connect to the database")
}
return db, nil
}
package main
import (
"fmt"
"github.com/andremartinsds/api-backoffice-zumenu/configs"
)
func main() {
_, err = configs.LoadConDB()
if err != nil {
panic(err)
}
fmt.Println("ok!!!")
}
When I start the MySQL container and run the Go application locally without Docker, it works. But when everything is run with Docker, it doesn’t work.
I expect to run everything with Docker.
2
Answers
I have consolidated your Go code into a single file:
That uses
DB_USER
andDB_PASSWORD
from.env
to construct the connection string. Note that the connection string uses the name of the MySQL service (mysql
) rather thanlocalhost
. This is important for making connections between the containers sincelocalhost
for the Go process is not the same aslocalhost
for the MySQL process.I also updated
docker-compose.yml
with a health check to ensure that the database is ready for connections before starting the Go code.The backoffice API will only start once the
mysql
service is marked as "healthy", and that only happens whenmysqladmin
is able to ping the database using the username and password provided in.env
.If you want to run everything through Docker using docker compose, you can refer to the service name in the compose file for the API to communicate with the MySQL database.
For example, if the service name of the database is mysql, you can set it up like this:
It’s a good practice to use environment variables to configure the connection settings. This way, you can easily change the environment without hardcoding the values.