Postgres + Go + Docker-compose 无法连接数据库:拨号tcp 127.0.0.1:5432: 连接被拒绝

huangapple go评论74阅读模式
英文:

Postgres + Go + Docker-compose Can't ping database: dial tcp 127.0.0.1:5432: connect: connection refused

问题

这是一个使用Golang编写的脚本,用于创建一个包含三个服务(GO+POSTGRES+NGINX)的Docker Compose环境。主要任务是学习环境配置。数据库需要设置密码,并且gocalc需要连接到该数据库。但是你做错了什么呢?

根据你提供的日志,有几个问题需要解决:

  1. backend_1 无法连接到数据库。错误消息是 Can't ping database: dial tcp 127.0.0.1:5432: connect: connection refused。这可能是因为 backend 服务无法找到 db 服务。请确保在 backend 服务的环境变量中使用正确的数据库主机名和端口。

  2. proxy_1 无法找到 backend。错误消息是 host not found in upstream "backend" in /etc/nginx/conf.d/default.conf:5。这可能是因为 proxy 服务无法找到 backend 服务。请确保在 proxy 服务的配置文件中正确指定了 backend 的主机名。

  3. postgres_1 服务在启动时出现了一些警告和错误,但最终成功启动并准备好接受连接。

你需要检查并修复上述问题,以确保所有服务能够正确连接和通信。

英文:

It is not my golang script, but i should to use them in this task:
package main

import (
	"database/sql"
	"fmt"
	_ "github.com/lib/pq"
	"log"
	"net/http"

	"github.com/caarlos0/env"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
)

type config struct {
	PostgresUri   string `env:"POSTGRES_URI" envDefault:"postgres://root:pass@127.0.0.1/postgres"`
	ListenAddress string `env:"LISTEN_ADDRESS" envDefault:":5432"`
}

var (
	db          *sql.DB
	errorsCount = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: "gocalc_errors_count",
			Help: "Gocalc Errors Count Per Type",
		},
		[]string{"type"},
	)

	requestsCount = prometheus.NewCounter(
		prometheus.CounterOpts{
			Name: "gocalc_requests_count",
			Help: "Gocalc Requests Count",
		})
)

func main() {
	var err error

	// Initing prometheus
	prometheus.MustRegister(errorsCount)
	prometheus.MustRegister(requestsCount)

	// Getting env
	cfg := config{}
	if err = env.Parse(&cfg); err != nil {
		fmt.Printf("%+v\n", err)
	}

	// Connecting to database
	db, err = sql.Open("postgres", cfg.PostgresUri)
	if err != nil {
		log.Fatalf("Can't connect to postgresql: %v", err)
	}
	defer db.Close()

	err = db.Ping()
	if err != nil {
		log.Fatalf("Can't ping database: %v", err)
	}

	http.HandleFunc("/", handler)
	http.Handle("/metrics", promhttp.Handler())
	log.Fatal(http.ListenAndServe(cfg.ListenAddress, nil))
}

func handler(w http.ResponseWriter, r *http.Request) {
	requestsCount.Inc()

	keys, ok := r.URL.Query()["q"]
	if !ok || len(keys[0]) < 1 {
		errorsCount.WithLabelValues("missing").Inc()
		log.Println("Url Param 'q' is missing")
		http.Error(w, "Bad Request", 400)
		return
	}
	q := keys[0]
	log.Println("Got query: ", q)

	var result string
	sqlStatement := fmt.Sprintf("SELECT (%s)::numeric", q)
	row := db.QueryRow(sqlStatement)
	err := row.Scan(&result)

	if err != nil {
		log.Println("Error from db: %s", err)
		errorsCount.WithLabelValues("db").Inc()
		http.Error(w, "Internal Server Error", 500)
		return
	}

	fmt.Fprintf(w, "query %s; result %s", q, result)
}

It is my docker-compose:

version: "3"
services:
  db:
    image: postgres:10
    environment:
      - POSTGRES_PASSWORD=pass
      - POSTGRES_USER=root
    expose:
      - 5432
    
  backend:
    image: dkr-14-gocalc:latest
    environment:
      - POSTGRES_URI=postgres://root:pass@db/postgres
      - LISTEN_ADDRESS=7000
    depends_on:
      - postgres
  proxy:
    image: nginx
    volumes:
      - type: bind
        source: ./nginx.conf
        target: /etc/nginx/conf.d/default.conf
    ports:
      - 8000:80
    depends_on: 
      - backend

And it is dkr14-gocalc image:

FROM golang:1.19.1-alpine AS builder
ENV GO111MODULE=auto
WORKDIR /go/src/

RUN apk add --no-cache git 
COPY main.go ./
 
#init is initializing and writting new go.mod in current dir.
RUN go mod init main.go

RUN go get -d -v github.com/caarlos0/env \
    && go get -d -v github.com/prometheus/client_golang/prometheus \
    && go get -d -v github.com/prometheus/client_golang/prometheus/promhttp \
    && go get -d -v github.com/lib/pq \   
    && go get -d -v database/sql \
    && go get -d -v fmt \
    && go get -d -v log \
    && go get -d -v net/http
 	
RUN go build -o app .

FROM alpine:3.10.3
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /go/src/app ./
CMD ["./app"]

I should to make docker compose environment with 3 services GO+POSTGRES+NGINX. The main idea of task is to learn about environment. Database should have password and golalc should to connect to this database. But what have i done incorrect?

It is my log:

backend_1   | 2022/11/07 23:27:33 Can't ping database: dial tcp 127.0.0.1:5432: connect: connection refused
postgres_1  | The files belonging to this database system will be owned by user "postgres".
postgres_1  | This user must also own the server process.
postgres_1  | 
proxy_1     | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
proxy_1     | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
postgres_1  | The database cluster will be initialized with locale "en_US.utf8".
postgres_1  | The default database encoding has accordingly been set to "UTF8".
postgres_1  | The default text search configuration will be set to "english".
postgres_1  | 
postgres_1  | Data page checksums are disabled.
proxy_1     | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
proxy_1     | 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
postgres_1  | 
task14_backend_1 exited with code 1
proxy_1     | 10-listen-on-ipv6-by-default.sh: info: /etc/nginx/conf.d/default.conf differs from the packaged version
postgres_1  | fixing permissions on existing directory /var/lib/postgresql/data ... ok
postgres_1  | creating subdirectories ... ok
proxy_1     | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
postgres_1  | selecting default max_connections ... 100
proxy_1     | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
postgres_1  | selecting default shared_buffers ... 128MB
postgres_1  | selecting default timezone ... Etc/UTC
postgres_1  | selecting dynamic shared memory implementation ... posix
proxy_1     | /docker-entrypoint.sh: Configuration complete; ready for start up
postgres_1  | creating configuration files ... ok
postgres_1  | running bootstrap script ... ok
postgres_1  | performing post-bootstrap initialization ... ok
postgres_1  | syncing data to disk ... ok
postgres_1  | 
postgres_1  | Success. You can now start the database server using:
postgres_1  | 
postgres_1  |     pg_ctl -D /var/lib/postgresql/data -l logfile start
postgres_1  | 
postgres_1  | 
postgres_1  | WARNING: enabling "trust" authentication for local connections
postgres_1  | You can change this by editing pg_hba.conf or using the option -A, or
postgres_1  | --auth-local and --auth-host, the next time you run initdb.
proxy_1     | 2022/11/07 23:27:33 [emerg] 1#1: host not found in upstream "backend" in /etc/nginx/conf.d/default.conf:5
proxy_1     | nginx: [emerg] host not found in upstream "backend" in /etc/nginx/conf.d/default.conf:5
postgres_1  | waiting for server to start....2022-11-07 23:27:33.704 UTC [48] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
postgres_1  | 2022-11-07 23:27:33.722 UTC [49] LOG:  database system was shut down at 2022-11-07 23:27:33 UTC
postgres_1  | 2022-11-07 23:27:33.729 UTC [48] LOG:  database system is ready to accept connections
postgres_1  |  done
postgres_1  | server started
task14_proxy_1 exited with code 1
postgres_1  | CREATE DATABASE
postgres_1  | 
postgres_1  | 
postgres_1  | /usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/*
postgres_1  | 
postgres_1  | 2022-11-07 23:27:34.130 UTC [48] LOG:  received fast shutdown request
postgres_1  | waiting for server to shut down....2022-11-07 23:27:34.133 UTC [48] LOG:  aborting any active transactions
postgres_1  | 2022-11-07 23:27:34.135 UTC [48] LOG:  worker process: logical replication launcher (PID 55) exited with exit code 1
postgres_1  | 2022-11-07 23:27:34.135 UTC [50] LOG:  shutting down
postgres_1  | 2022-11-07 23:27:34.157 UTC [48] LOG:  database system is shut down
postgres_1  |  done
postgres_1  | server stopped
postgres_1  | 
postgres_1  | PostgreSQL init process complete; ready for start up.
postgres_1  | 
postgres_1  | 2022-11-07 23:27:34.254 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432
postgres_1  | 2022-11-07 23:27:34.254 UTC [1] LOG:  listening on IPv6 address "::", port 5432
postgres_1  | 2022-11-07 23:27:34.259 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
postgres_1  | 2022-11-07 23:27:34.283 UTC [76] LOG:  database system was shut down at 2022-11-07 23:27:34 UTC
postgres_1  | 2022-11-07 23:27:34.294 UTC [1] LOG:  database system is ready to accept connections

答案1

得分: 0

问题可能出在你在 docker-compose.yaml 文件中如何暴露数据库容器。在这种情况下,“连接被拒绝”是一个典型的错误。通常,我以不同的方式导出端口(在这段代码中,我只报告了相关部分):

docker-compose.yaml

version: "3"
services:
  db:
    image: postgres
    environment:
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_USER=postgres
    ports:
      - "5432:5432"

main.go

package main

import (
	"database/sql"
	"log"

	_ "github.com/lib/pq"
)

func main() {
	// 连接数据库
	db, err := sql.Open("postgres", "host=127.0.0.1 user=postgres password=postgres dbname=postgres port=5432 sslmode=disable")
	if err != nil {
		log.Fatalf("无法连接到postgresql:%v", err)
	}
	defer db.Close()

	err = db.Ping()
	if err != nil {
		log.Fatalf("无法ping数据库:%v", err)
	}
}

通过这个解决方案,我能够成功地从代码中直接ping通Postgres数据库。如果有帮助,请告诉我。

编辑

在与db实例交互的方式上有一点不同:

  1. 如果你试图直接从主机上联系数据库(就像在 main.go 文件中一样),你必须使用你的机器的IP地址(例如 127.0.0.1)来引用它。
  2. 如果你试图从web容器中联系数据库,你必须使用类似 postgres://db:5432 的形式,其中 db 是主机名。

如果这有助于澄清一点,请告诉我。

英文:

The issue could be in how you're exposing your database container in the docker-compose.yaml file. "connection refused" is a typical error in this scenario. Usually, I export the ports in a different way (in this code I reported only the relevant parts):

docker-compose.yaml

version: "3"
services:
  db:
    image: postgres
    environment:
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_USER=postgres
    ports:
      - "5432:5432"

main.go

package main

import (
	"database/sql"
	"log"

	_ "github.com/lib/pq"
)

func main() {
	// Connecting to database
	db, err := sql.Open("postgres", "host=127.0.0.1 user=postgres password=postgres dbname=postgres port=5432 sslmode=disable")
	if err != nil {
		log.Fatalf("Can't connect to postgresql: %v", err)
	}
	defer db.Close()

	err = db.Ping()
	if err != nil {
		log.Fatalf("Can't ping database: %v", err)
	}
}

With this solution, I was able to successfully ping the Postgres database directly from the code. Let me know if that helps.

Edit

There is a little difference in the way you interact with db instance:

  1. If you're trying to contact the db directly from your host machine (like in the main.go file), you've to refer to it with the IP address of your machine (e.g., 127.0.0.1).
  2. If you're trying to contact the db from your web container, you've to use something like postgres://db:5432 with db as the hostname.

Let me know if this clarifies a little bit.

huangapple
  • 本文由 发表于 2022年11月8日 20:19:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/74360635.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定