嗨,我在 ubonto 中有一个包含 golang redis 和 postgress 数据库的项目 我的 docker 文件是:
我的table.sql是这样的:
CREATE TABLE users ( username VARCHAR (200) PRIMARY KEY, pass VARCHAR (50) );
Alter User postgres WITH PASSWORD '123';
# syntax=docker/dockerfile:1
FROM postgres:latest AS go2
ENV POSTGRES_USER postgress
ENV POSTGRES_PASSWORD ''
ENV POSTGRES_DB postgress
EXPOSE 5432
ADD table.sql /docker-entrypoint-initdb.d/
FROM redis:latest AS go3
FROM golang:latest AS go
LABEL maintainer=”[email protected]”
WORKDIR /app
COPY . .
RUN go build -o bin
ENTRYPOINT [ "/app/bin" ]
EXPOSE 8089
我用这个命令构建它:
docker build . -t mycontiner
我用这个命令运行它:
docker run -t mycontiner --network=bridge
及其显示:
[error] failed to initialize database, got error failed to connect to `host=172.17.0.2 user=postgres database=postgres`: dial error (dial tcp 172.17.0.2:5432: connect: connection refused)
2024/07/29 13:52:27 IP:172.17.0.2
2024/07/29 13:52:27 IP:172.17.0.2
2024/07/29 13:52:27 server listening at 172.17.0.2:8089
2024/07/29 13:52:27 server listening at 172.17.0.2:8089
我的问题是: 1-我无法使用用户 postgress 连接到 postgress 数据库 127.0.0.1:5432 并传递 123
2-我无法连接到端口 8089 的容器
我能做什么?
我尝试运行它
docker run -t mycontiner --network=host
但是一样 我无法连接到它或 ping 它并且无法访问相同的 postgres 数据库
Update:
i created a docker compose file
services:
db:
image: postgres:15.7
restart: always
network_mode: bridge
volumes:
- ./db/table.sql:/docker-entrypoint-initdb.d/init.sql
ports:
- '5433:5432'
environment:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: 123
redis:
image: redis:7.0.12
network_mode: bridge
ports:
- '6380:6379'
backend:
build: ./backend
network_mode: bridge
ports:
- '8000:8089'
depends_on:
- db
但是我的 redis 和 postgres 运行良好,我可以连接它们,但是当我运行后端容器时,它会抛出此错误:
[错误]初始化数据库失败,连接失败
:拨号错误(拨号tcp 127.0.0.1:5433:连接:连接被拒绝)host=127.0.0.1 user=postgres database=postgres
在 Dockerfile 中,您结合了 PostgreSQL、Redis 和 Go 应用程序。
但是根据 Docker 的文档建议将它们分开:
最佳实践是通过每个容器使用一项服务来分隔关注区域。
因此,让我们将 Dockerfile 简化为单独的 Go 应用程序:
FROM golang
WORKDIR /app
COPY ./app .
RUN go build -o bin
ENTRYPOINT [ "/app/bin" ]
有趣的事实,您使用的
EXPOSE
指令不会暴露任何内容:
不发布端口。它充当构建映像的人员和运行容器的人员之间的一种文档。EXPOSE
由于您是运行容器的人,因此没有必要。仅当我将 Dockerfile 发布到注册表以便其他人可以下载和使用它时,我才会使用它。这就是我删除它的原因。
可选:以下稍微改进的版本应该允许更快的重建:
FROM golang
WORKDIR /app
COPY go.mod go.sum ./ # ddd
RUN go mod download
COPY *.go ./
RUN go build -o bin
CMD [ "/app/bin" ]
现在我们来谈谈您遇到的错误。
每个服务都位于单独的容器中,但您尝试从
backend
连接到 db
,就像它们在单个容器中运行一样。将它们视为在不同的机器上运行。这样,您就可以清楚为什么无法在 db
的本地主机上访问 backend
。
您为所有容器定义了
network_mode: bridge
。因此它们都将连接到默认的桥接网络。这意味着他们可以通过IP 互相访问。 但获取IP却很棘手。值得庆幸的是,有一个更简单的方法。只需定义一个自定义桥接网络:
networks:
my_network:
这里
my_network
是用户定义的网络,默认为driver: bridge
。与默认桥接网络相反,用户定义的桥接网络允许自动服务发现:
在用户定义的网络上,容器不仅可以通过IP进行通信,还可以将容器名称解析为IP。这称为自动服务发现。
这意味着,在您的
backend
服务的代码中,您将能够使用 db:5432
访问您的 PostgreSQL 数据库。这里的db
会自动替换为db
服务的IP。
但是要从主机访问您的服务,请使用
ports
属性将主机的端口映射到容器的端口。您的 backend
服务地图 8000:8089
。这意味着,backend
服务可以在主机上以 localhost:8000
的形式访问,但可以从其他服务以 backend:8089
的形式访问。
这是您需要的撰写文件的完整最小示例:
networks:
my_network:
services:
db:
image: postgres
volumes:
- ./db/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
networks:
- my_network
ports:
- 5433:5432
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: 123
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 1s
retries: 100
redis:
image: redis
networks:
- my_network
ports:
- 6380:6379
backend:
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
build: ./backend
networks:
- my_network
ports:
- 8000:8089
此处,
./postgres/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
将数据从主机上的 ./postgres/docker-entrypoint-initdb.d
映射到 docker-entrypoint-initdb.d
容器内的 db
。那里的任何 SQL 都会初始化 PostgreSQL DB。
backend.depends_on
与 db.healthcheck
一起可以确保 backend
在 db
健康时启动(即 PostgreSQL DB 已准备好接受连接)。
最后,一个完整的工作示例 在这里。