【问题标题】:dial error (dial tcp 172.18.0.2:8001: connect: connection refused) when trying to run go program in one container that connects to postgres in another尝试在一个连接到另一个 postgres 的容器中运行 go 程序时出现拨号错误(拨号 tcp 172.18.0.2:8001:连接:连接被拒绝)
【发布时间】:2020-11-14 08:29:07
【问题描述】:

我目前在我的 PC 上设置了两个 docker 容器,其中一个是使用 docker compose 创建的 PostgreSQL 容器,另一个包含用于初始化 PostgreSQL 数据库中的表的 go 代码。 Docker compose 在创建容器/数据库方面非常有效(我将通过容器外部的 psql 登录它),并且 go 代码本身在容器外部正常运行(创建表)。当我尝试从其自己的容器内运行代码时,无论我尝试连接到本地数据库还是容器化数据库,都会出现问题。这两种情况都会导致标题中的拨号错误。

我只是 docker 的初学者,所以我知道这很可能是我的问题,但这里是我的 dockerfile 的内容:

FROM golang:alpine AS builder 

#adding needed env variables 
ENV GO111MODULE=on \
    CGO_ENABLED=0 \
    GOOS=linux \
    GOARCH=amd64 
    
#move to /build 
WORKDIR /build 

#copy dependancies 
COPY go.mod . 
COPY go.sum . 
RUN go mod download 

#add code to container 
COPY . .

#build app 
RUN go build -o main . 

# Move to /dist directory as the place for resulting binary folder
WORKDIR /dist

# Copy binary from build to main folder
RUN cp /build/main .

# Build a small image
FROM scratch

COPY --from=builder /dist/main /

ENV DATABASE_URL=postgres://short:password@test:8001/shorturl
    #change database url variable to match your needs 
    
# Command to run
ENTRYPOINT ["/main"]

以及 docker-compose.yml 文件的内容:

version: '3'
services:
  database:
    container_name: test
    image: "postgres" # use latest official postgres version
    env_file:
      - ./db/database.env # configure postgres
    volumes:
      - database-data:/var/lib/postgresql/data/ # persist data even if container shuts down
    ports:
        - "8001:5432" 
  backend: 
    build: . 
volumes:
  database-data: 

代码本身存在于以下目录结构中:

/project/
    ./db/ 
         db.go 
         database.env
    main.go 
    go.mod 
    go.sum 
    Dockerfile 
    docker-compose.yml 

db.go 包含:

package db
import (
    "context"
    "fmt"
    "os"

    "github.com/jackc/pgx/v4/pgxpool"
)

//InitDb creates a connection to our postgres db and populates it
func InitDb(dbURL string) *pgxpool.Pool {
    connPool, err := pgxpool.Connect(context.Background(), dbURL)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
        os.Exit(1)
    }
    return connPool
}

//PopulateDb populates our databse with the appropiate tables i.e id, url, base64 encoding, visited, visit count
func PopulateDb(db *pgxpool.Pool) {
    _, err := db.Exec(context.Background(), "create table if not exists shortener (id serial primary key not null, url varchar not null, visited boolean default false, count integer default 0);")
    if err != nil {
        fmt.Fprintf(os.Stderr, "Unable to create users table: %v\n", err)
        os.Exit(1)
    }
    fmt.Printf("Successfully created users table\n")
}

database.env 用于使用 docker-compose 生成数据库包含:

POSTGRES_USER=short
POSTGRES_PASSWORD=password
POSTGRES_DB=shorturl 

main.go 包含:

package main

import (
    "fmt"
    "os"
    "project/db"
)

func main() {
    /*
        set databse url in this format from root directory
        DATABASE_URL=postgres://user:password@host:port/database
    */
    dbURL := os.Getenv("DATABASE_URL")
    conn := db.InitDb(dbURL)
    db.PopulateDb(conn)
    defer conn.Close()
}

正如我之前提到的,在任何容器之外运行所有这些工作并填充数据库,并且 docker-compose 成功创建了一个我可以在本地连接到的 postgres 实例。

我不能做的是通过我的代码(在本地或在容器中运行)连接到容器化的 postgres,或者从我的代码的容器化版本连接到本地数据库。所有这些都会导致此错误的一些变化:

Unable to connect to database: failed to connect to `host=container_name user=short database=shorturl`: dial error (dial tcp 172.18.0.2:8001: connect: connection refused) 

我很好奇我的代码和/或 docker 可能做错了什么,并希望有人可以最终运行它并重现我的问题/找出问题所在。

【问题讨论】:

  • 尝试使用 5432 更改配置端口。DATABASE_URL=postgres://short:password@test:5432/shorturl。使用 8001 只能从 docker-compose 外部访问。 docker-compose 服务内部的互通容器应该通过它们的默认端口工作。

标签: postgresql docker go tcp docker-compose


【解决方案1】:

我会尝试澄清 Michée Lengronne 写的内容,我认为他的回答只是部分正确。

您有两个容器 - test,其中运行 postgres,还有一个未命名的容器,其中包含您的 go 应用程序,每次容器启动时都会随机确定该容器的名称。

这两个容器都在同一个网络上。这很重要。

当你定义ports的值为8001:5432时,这意味着如果你从定义的网络外部连接,并且你选择端口8001连接,它将连接到端口@ 987654326@在里面。

但如果您仅从同一网络连接,则可以省略ports 定义并直接连接到test 容器。

(说真的,选择一个更好的名字,至少test_database

意思是,使用默认端口(@98​​7654330@)的容器名称就足够了。

TL;DR

DATABASE_URL=postgres://short:password@test:5432/shorturl

应该工作

【讨论】:

  • 确实比我写的更好。
  • 非常感谢,这最终成功了,但我不得不运行 docker-compose up 两次,因为该应用程序在最初完全初始化之前尝试连接到数据库。
  • @exef 有一个解决方案:stackoverflow.com/questions/35069027/…
【解决方案2】:

如果您想连接到本地 postgres 或另一个 docker 网络中的 postgres,您必须在该变量中提供您的 postgres 的 IP 或域名:DATABASE_URL=postgres://short:password@test:8001/shorturl

通常您应该将test 替换为localhost127.0.0.1

从错误中,您的应用尝试连接到 172.18.0.2。我想这个 IP 是来自 postgres 容器的 IP。在此特定容器的 docker 网络之外无法访问它。如果您想通过此 IP 访问您的容器,您必须将您的应用容器添加到 postgres docker 网络。

Docker 网络和撰写:https://docs.docker.com/compose/networking/

【讨论】:

    猜你喜欢
    • 2021-07-31
    • 2018-09-29
    • 2018-12-26
    • 1970-01-01
    • 1970-01-01
    • 2022-07-21
    • 1970-01-01
    • 1970-01-01
    • 2020-01-01
    相关资源
    最近更新 更多