简体   繁体   中英

Connection refused when connecting to mysql in docker, using a go webservice

I cannot make it work to run my mysql database within a docker container. I build a very simple webservice with go to try to get to the mistake, but anything i try, i keep getting "connection refused error", when starting the docker build

So I made the simplest smallest example, directory tree looking like this:

Example/
| ---- Dockerfile
| ---- main.go
| ---- docker-compose.yml
database/
        | ---- Dockerfile
        | ---- example.sql

My Example/Dockerfile looks like this:

FROM golang:alpine
ENV GO111MODULE=on \
    CGO_ENABLED=0 \
    GOOS=linux \
    GOARCH=amd64

WORKDIR /build

COPY go.mod .
COPY go.sum .
RUN go mod download

COPY . .
RUN go build -o main .

EXPOSE 8080

CMD ["/build/main"]

The database dockerfile has only three lines:

FROM mysql:8.0.24
COPY example.sql /docker-entrypoint-initdb.d/example.sql
EXPOSE 3306

The main.go is small and simple:

package main
import "fmt"
import "net/http"
import _ "github.com/go-sql-driver/mysql"
import "database/sql"
import "log"

func main() {
    http.HandleFunc("/", handler)

    db, err := sql.Open("mysql", "user:password@tcp(db:3307)/example") // -- this is the troublemaker!
    if err != nil {
        log.Fatal(err)
    }

    pingErr := db.Ping()
    if pingErr !=  nil {
        log.Fatal(pingErr)
    }

    fmt.Println("Connected to DB")

    http.ListenAndServe(":8080", nil)
}
func handler(w http.ResponseWriter, r *http.Request){
    fmt.Println("Calling handler")
    fmt.Println(r.URL.Path)
}

The docker-compose.yml is also nothing special

version: '3'
services:
  db:
    build:
      context: ./database
    volumes: 
      - database:/database/data
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: example
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    container_name: container_db
    ports:
      - "3307:3306"
    networks:
      - default
api:
    build:
      context: .
    restart: on-failure
    container_name: "container_api"
        volumes:
            - api:/usr/api
    ports:
      - "8080:8080"
    networks:
      - default

volumes:
    database:
    api:

And the database file example.sql is also very simple

CREATE DATABASE IF NOT EXISTS example;
CREATE USER IF NOT EXISTS 'user'@'%' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON *.* TO 'user'@'%' WITH GRANT OPTION;

CREATE TABLE IF NOT EXISTS exampleTable (
    id           INT             NOT NULL,
    name         VARCHAR(2048)   NOT NULL,
    lastName     VARCHAR(2048)
    PRIMARY KEY (`id`)
);

I tried to use the name of the service so db in the connection, as well as the container name container_db but the error remains. I also found a post where it was suggested to configure mysql to bind vallue 0.0.0.0 , but this also did not help me.

Sometimes I also only get as an error output: "container_api exited with code 1"

You should remove the networks section from your services. This will cause both containers to be started in a new network. Containers in the same network can talk to each other without needing to expose ports, so you can also remove the ports section from the db service. Now change the DSN to use port 3307 instead of 3307.

The main issue here being that when you expose a port, you map a port on the host to a port on the container. With your current config you tell the host to forward port 3307 to 3306, but your api service is container and can't use the port on the host(3307), it needs to use the 3306 port. And containers in the default network can't talk to each other only if they have their own network

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM