我目前在我的PC上设置了两个docker容器,其中一个是使用docker compose创建的PostgreSQL容器,另一个是包含go代码以初始化PostgreSQL数据库中的表。 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")
}
用于通过docker-compose生成数据库的database.env包含: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中可能做错了什么,希望有人可以在其末端运行它并重现我的问题/找出问题所在。 最佳答案
我将尽力澄清米歇尔·伦格罗讷(MichéeLengronne)的所作所为,我认为他的回答部分正确。
您有两个容器-test
(内部运行postgres)和一个未命名的容器,其中包含go应用程序,该容器的名称是在每次容器启动时随机确定的。
这些容器都在同一网络上。那很重要。
当您使用值ports
定义8001:5432
时,这意味着如果您从定义的网络外部进行连接,并且选择端口8001
进行连接,则它将连接到内部的端口5432
。
但是,如果仅从同一网络内进行连接,则可以省略ports
定义,然后继续直接连接到test
容器。
(认真选择一个更好的名称,至少为test_database
)
这意味着,将容器名称与默认端口(5432
)配合使用就足够了。
TL; DR
DATABASE_URL=postgres://short:password@test:5432/shorturl
应该管用关于postgresql - 尝试在一个连接到另一个容器中的postgres的容器中运行go程序时发生拨号错误(拨号tcp 172.18.0.2:8001:connect:连接被拒绝),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/63074145/