英文:
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需要连接到该数据库。但是你做错了什么呢?
根据你提供的日志,有几个问题需要解决:
-
backend_1
无法连接到数据库。错误消息是Can't ping database: dial tcp 127.0.0.1:5432: connect: connection refused
。这可能是因为backend
服务无法找到db
服务。请确保在backend
服务的环境变量中使用正确的数据库主机名和端口。 -
proxy_1
无法找到backend
。错误消息是host not found in upstream "backend" in /etc/nginx/conf.d/default.conf:5
。这可能是因为proxy
服务无法找到backend
服务。请确保在proxy
服务的配置文件中正确指定了backend
的主机名。 -
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实例交互的方式上有一点不同:
- 如果你试图直接从主机上联系数据库(就像在
main.go
文件中一样),你必须使用你的机器的IP地址(例如127.0.0.1
)来引用它。 - 如果你试图从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:
- 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
). - If you're trying to contact the db from your web container, you've to use something like
postgres://db:5432
withdb
as the hostname.
Let me know if this clarifies a little bit.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论