привет, у меня есть проект с golang redis и базой данных postgress в ubonto мой файл докера:
мой 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 127.0.0.1:5432 с пользователем postgress и передать 123
2-я не могу подключиться к контейнеру с портом 8089
что я могу сделать?
я пытался запустить его с помощью
docker run -t mycontiner --network=host
но то же самое я не могу подключиться к нему или пропинговать его, и к той же базе данных 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 работают хорошо, и я могу их подключить, но когда я запускаю свой внутренний контейнер, он выдает эту ошибку:
[ошибка] не удалось инициализировать базу данных, возникла ошибка: не удалось подключиться к
host=127.0.0.1 user=postgres database=postgres
: ошибка набора номера (наберите TCP 127.0.0.1:5433: подключение: соединение отклонено)
Я создал файл компоновки Docker с тремя службами db, redis, backend go lang, но получил эту ошибку во внутренней службе [error] failed to initialize database, got error failed to connect to
host=127.0.0.1 user=postgres data=postgres: dial error (dial tcp 127.0.0.1:5433: connect: connection refused)
Да, в Docker 127.0.0.1 и соответствующее имя хоста localhost
почти всегда относятся к текущему контейнеру, а не к одному из других контейнеров или хост-системе. Сеть в Compose в документации Docker описано, как соединяться между контейнерами.
В вашем Dockerfile вы объединяете PostgreSQL, Redis и ваше приложение Go.
Но согласно документации Докера их предлагается разделить:
Лучше всего разделить проблемные области, используя одну службу для каждого контейнера.
Итак, давайте упростим ваш Dockerfile до одного приложения Go:
FROM golang
WORKDIR /app
COPY ./app .
RUN go build -o bin
ENTRYPOINT [ "/app/bin" ]
Интересный факт: использованная вами EXPOSE
инструкция ничего не раскрывает:
Инструкция
EXPOSE
не публикует порт. Он функционирует как своего рода документация между человеком, который создает образ, и человеком, который запускает контейнер...
Поскольку контейнером управляете вы, в этом нет необходимости. Я бы использовал его только в том случае, если опубликую Dockerfile в реестре, чтобы другие могли его загрузить и использовать. Вот почему я удалил его.
Теперь давайте поговорим об ошибке, с которой вы столкнулись.
Каждая служба находится в отдельном контейнере, но вы пытаетесь подключиться от backend
к db
, как будто они работают в одном контейнере. Думайте о них как о работающих на отдельных машинах. Таким образом, должно быть очевидно, почему вы не можете получить доступ к db
на локальном хосте backend
.
Вы определили network_mode: bridge
для всех контейнеров. Таким образом, все они будут подключены к мостовой сети по умолчанию. Это означает, что они могут получить доступ друг к другу по своим IP-адресам. Но получить IP-адреса сложно. К счастью, есть более простой способ. Просто определите собственную сеть мостов:
networks:
my_network:
Здесь my_network
— определяемая пользователем сеть, по умолчанию она равна driver: bridge
. В отличие от мостовой сети по умолчанию, определяемые пользователем мостовые сети позволяют автоматическое обнаружение сервисов:
В определяемых пользователем сетях контейнеры могут не только обмениваться данными по IP-адресам, но также могут преобразовывать имя контейнера в IP-адрес. Это называется автоматическим обнаружением служб.
Это означает, что в коде вашего backend
сервиса вы сможете использовать db:5432
для доступа к вашей базе данных PostgreSQL. db
здесь будет автоматически заменен IP-адресом службы db
.
Итак, подведем итог. Если вы хотите получить доступ к одной службе из другой, вам необходимо определить собственную мостовую сеть и подключить к ней обе службы. Затем используйте имена контейнеров вместо IP-адресов.
Чтобы получить доступ к вашим сервисам с хоста, используйте атрибут ports
, чтобы сопоставить порт хоста с портом контейнера. Ваши backend
карты услуг 8000:8089
. Это означает, что сервис backend
доступен на хосте как localhost:8000
, а из других сервисов как backend:8089
.
Это полный пример файла создания, который вам нужен:
volumes:
db_data:
redis_data:
networks:
my_network:
services:
db:
image: postgres
volumes:
- db_data:/var/lib/postgresql/data
- ./postgres/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
networks:
- my_network
ports:
- 5432:5432
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
container_name: postgres
restart: always
redis:
image: redis
volumes:
- redis_data:/data
networks:
- my_network
ports:
- 6379:6379
container_name: redis
restart: always
backend:
depends_on:
- db
- redis
build: .
networks:
- my_network
ports:
- 8000:8089
container_name: backend
restart: always
Здесь я определяю пользовательские объемы и прикрепляю их к db
и redis
. Это делается для того, чтобы их данные оставались постоянными, иначе они будут исчезать каждый раз, когда вы их перезапускаете. Кроме того, лучше переместить конфиденциальную информацию, такую как имя пользователя и пароль, в файл .env
, который не хранится в VCS.
Наконец, инструкция ./postgres/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
сопоставляет данные с ./postgres/docker-entrypoint-initdb.d
на хосте docker-entrypoint-initdb.d
внутри db
контейнера. Любой SQL будет инициализировать базу данных PostgreSQL.
теперь все работает, но когда я хочу получить доступ к серверной части с 8089 с IP-адресом 127.0.0.1, у меня возникает проблема. если я запускаю main.go вручную, он работает, но я не могу получить доступ к внутреннему контейнеру, который я сопоставил с портом 8089:8089.
и для последней ошибки, которую я обнаружил, я должен установить список внутренних портов: 8000, а не 127.0.0.1:8000. Почему? Я не знаю. Но это работает :) спасибо за вашу помощь.
docker run
запускает только один контейнер, а контейнер запускает только один процесс. Возможно, вы ищете такой инструмент, как Docker Compose, который сможет запускать три контейнера параллельно. Показанный вами Dockerfile генерирует только образ, запускающий приложение Go, блоки хранилища данных полностью игнорируются.