skip to Main Content

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


  1. I have consolidated your Go code into a single file:

    package main
    
    import (
        "fmt"
        "log"
        "os"
        _ "github.com/go-sql-driver/mysql"
        "github.com/jmoiron/sqlx"
    )
    
    func main() {
        user := os.Getenv("DB_USER")
        password := os.Getenv("DB_PASSWORD")
    
        connection := fmt.Sprintf("%s:%s@(mysql:3306)/zumenu_db", user, password)
    
        fmt.Println("Connecting to database: ", connection)
        db, err := sqlx.Connect("mysql", connection)
        if err != nil {
            log.Fatal(err)
        }
    
        err = db.Ping()
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println("Database connection successful")
    }
    

    That uses DB_USER and DB_PASSWORD from .env to construct the connection string. Note that the connection string uses the name of the MySQL service (mysql) rather than localhost. This is important for making connections between the containers since localhost for the Go process is not the same as localhost 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.

    services:
      zumenu-backoffice-api:
        build:
          context: .
          dockerfile: ./Dockerfile
        ports:
          - 8080:8080
        env_file:
          - ./.env
        depends_on:
          mysql:
            condition: service_healthy
    
      mysql:
        image: mysql:5.7
        environment:
          - MYSQL_ROOT_PASSWORD=${DB_PASSWORD}
          - MYSQL_DATABASE=${DB_NAME}
          - MYSQL_USER=${DB_USER}
          - MYSQL_PASSWORD=${DB_PASSWORD}
        ports:
          - 3312:3306
        healthcheck:
          test: ["CMD", "mysqladmin", "-u${DB_USER}", "-p${DB_PASSWORD}", "ping"]
          interval: 5s
          timeout: 5s
          retries: 5
    

    The backoffice API will only start once the mysql service is marked as "healthy", and that only happens when mysqladmin is able to ping the database using the username and password provided in .env.

    Login or Signup to reply.
  2. 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:

    db, err := sqlx.Connect("mysql", "root:root@(mysql:3312)/zumenu_db")
    

    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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search