Sitemap

Ожидаем Postgres При Запуске Приложений с Docker-Compose

2 min readOct 8, 2020
Press enter or click to view image in full size

Работая с Docker-Compose, многие сталкивались со следующей проблемой: контейнер с базой запустился, но сам Postgres еще не успел стартовать. При этом, контейнер с нашим приложением уже запустился и пытается подключиться к БД.

В результате, приложение падает с ошибкой подключения к Postgres.

Рассмотрим следующий пример. У нас есть простое веб-приложение, написаное на Go, которое использует Postgres в качестве БД. Чтобы лучше понимать контекст, перед дальнейшим прочтением рекомендую ознакомится с исходниками.

Так выглядит Dockerfile для приложения:

FROM golang:1.14-busterRUN go version
ENV GOPATH=/
COPY ./ ./ # build go app
RUN go mod download
RUN go build -o todo-app ./cmd/main.go
CMD ["./todo-app"]

Ничего сложного, здесь мы копируем все файлы нашего приложения и компилируем его в изображении.

А так выглядит docker-compose.yml :

version: '3.8' services:  
todo-app:
build: ./
command: ./todo-app
ports:
- 8000:8000
depends_on:
- db
environment:
- DB_PASSWORD=qwerty

db:
restart: always
image: postgres:latest
volumes:
- ./.database/postgres/data:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=qwerty
ports:
- 5436:5432

Тут также ничего сложного.

Описываем 2 контейнера: само приложение и БД. Приложение зависит от базы, поэтому контейнер db будет запущен перед приложением.

Однако при первом запуске приложение не может подключиться к базе и выдает ошибку:

docker-compose up todo-appCreating todo-app_db_1 ... done
Recreating todo-app_todo-app_1 ... done
Attaching to todo-app_todo-app_1
todo-app_1 | {"level":"fatal","msg":"failed to initialize db: dial tcp 172.23.0.2:5432: connect: connection refused","time":"2020-10-08T06:39:32Z"}todo-app_todo-app_1 exited with code 1

При повторном запуске приложение запуститься без проблем, потому что контейнер с базой уже стартанул и Postgres запустился. Однако при свежем запуске приложения, эта ошибка будет постоянно воспроизводится.

На официальном сайте Docker есть пример скрипта wait-for-postgres.sh , который помогает решить эту проблему.

Давайте перепишем наши файлы Dockerfile и docker-compose.yml , добавив в корень проекта также данный скрипт.

В Dockerfile теперь будем устанавливать утилиту psql для выполнения скрипта. А в docker-compose.yml в командах контейнера укажем следующий код.

command: ./wait-for-postgres.sh db ./todo-app

Теперь все запускается без проблем, и перед запуском приложения, скрипт пытается достучаться к БД.

todo-app_1  | psql: could not connect to server: Connection refused
todo-app_1 | Is the server running on host "db" (172.23.0.2) and accepting
todo-app_1 | TCP/IP connections on port 5432?
todo-app_1 | Postgres is unavailable - sleeping
todo-app_1 | psql: FATAL: the database system is starting up
todo-app_1 | Postgres is unavailable - sleeping
todo-app_1 | psql: FATAL: the database system is starting up
todo-app_1 | Postgres is unavailable - sleeping
todo-app_1 | psql: FATAL: the database system is starting up
todo-app_1 | Postgres is unavailable - sleeping
todo-app_1 | Postgres is up - executing command
todo-app_1 | {"level":"info","msg":"TodoApp Started","time":"2020-10-08T06:50:08Z"}

--

--

Maksim Zhashkevych
Maksim Zhashkevych

Written by Maksim Zhashkevych

Telegram: @zhashkevychmaksim YT: @MaksimZhashkevych IG: @zhashkevych

No responses yet