How to make connection between Docker Containers

2019-08-27 19:08发布

问题:

I am having connection issues when I try to connect my goLang GORM service to a Docker Postgress container. I believe the problem is my golang code at the bottom at the connection string.

docker-compose up
Recreating postgress_postgre_1 ... done
Attaching to postgres
postgres   | 2018-12-11 21:08:48.283 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432
postgres   | 2018-12-11 21:08:48.283 UTC [1] LOG:  listening on IPv6 address "::", port 5432
postgres   | 2018-12-11 21:08:48.291 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
postgres   | 2018-12-11 21:08:48.316 UTC [20] LOG:  database system was shut down at 2018-12-11 21:08:44 UTC
postgres   | 2018-12-11 21:08:48.328 UTC [1] LOG:  database system is ready to accept connections

=== when I run the golang I get... panic: failed to connect database

=============== docker-compose.yml

version: '3.6'
services:
  postgre:
    image: postgres:11.1-alpine
    ports:
      - '5432:5432'
    network_mode: bridge
    container_name: postgres

    environment:
      POSTGRES_USER: 'user'
      POSTGRES_PASSWORD: 'password'
      POSTGRESS_DB: 'db_amex01'
    volumes:
      - ./init:/docker-entrypoint-initdb.d/

==== main.go

package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/gorilla/mux"
    "github.com/jinzhu/gorm"

    // _ "github.com/jinzhu/gorm/dialects/sqlite"
    _ "github.com/jinzhu/gorm/dialects/postgres"
)

// _ "github.com/jinzhu/gorm/blob/master/dialects/postgres"

type ToDo struct {
    gorm.Model
    ID          int    `json:"id"`
    TASK_STRING string `json:"task_string"`
    DONE        bool   `json:"done"`
}

var db *gorm.DB
var err error

func main() {
    const (
        host     = "localhost"
        port     = 5432
        user     = "postgres"
        password = "password"
        dbname   = "db_amex01"
    )


// this is the problem I believe I am having...

    db, err := gorm.Open("postgres", "host='postgres' port=5432 user=user dbname='db_amex01' password='password'")



    defer db.Close()

    if err != nil {
        panic("failed to connect database")
    }

    defer db.Close()

回答1:

There's a typo in your compose file, you name the service postgre but connect to postgres. Docker uses the service name for the DNS alias on a shared network, so this will break your connection attempt. To fix, just rename your service:

version: '3.6'
services:
  postgres:
    image: postgres:11.1-alpine
    ports:
      - '5432:5432'
    environment:
      POSTGRES_USER: 'user'
      POSTGRES_PASSWORD: 'password'
      POSTGRESS_DB: 'db_amex01'
    volumes:
      - ./init:/docker-entrypoint-initdb.d/


回答2:

It appears as though you're discarding the error returned from gorm.Open(). To know exactly why gorm failed to open the connection, you'd need to output the error.

Instead of:

panic("failed to connect database")

Use:

panic("failed to connect database: " + err)

At a glance, it could be that your host is misconfigured

host='postgres' port=5432 user=user dbname='db_amex01' password='password'

Should be:

host=localhost port=5432 user=user dbname=db_amex01 password=password

But it's hard to tell without the error from gorm.Open()

One other thing to note, too; don't call db.Close() before first checking the error. It's possible that in the case of an error, db may be nil, causing calls to any of db's methods to panic. You're also calling db.Close() twice in the code snippet you posted. Don't do this. Golang's documentation on io.Closer:

Closer is the interface that wraps the basic Close method.

The behavior of Close after the first call is undefined. Specific implementations may document their own behavior.

Edit (12/12/2018):

When I ran your code locally, the error I got from gorm was regarding SSL, because you're running your postgres server via docker-compose without any SSL configuration. You can add the sslmode=disable flag to your connection string to fix this issue.

Also there's a typo in your docker-compose.yml: POSTGRESS_DB should be POSTGRES_DB.

Here's a full working example that I got running locally:

docker-compose.yml:

version: '3.6'
services:
  postgres:
    image: postgres:11.1-alpine
    ports:
      - '5432:5432'
    environment:
      POSTGRES_USER: 'test_user'
      POSTGRES_PASSWORD: 'test_password'
      POSTGRES_DB: 'test_database'
    volumes:
      - ./init:/docker-entrypoint-initdb.d/

main.go:

package main

import (
    "fmt"
    "log"

    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/postgres"
)

const (
    host     = "localhost"
    port     = "5432"
    user     = "test_user"
    password = "test_password"
    dbname   = "test_database"
)

func main() {
    url := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable",
        user,
        password,
        host,
        port,
        dbname,
    )

    db, err := gorm.Open("postgres", url)
    if err != nil {
        log.Fatalf("error connecting to database: %v", err)
    }
    defer db.Close()

    if err := db.DB().Ping(); err != nil {
        log.Fatalf("error pinging database: %v", err)
    }

    fmt.Println("Success!")
}