Как провести миграции данных в Docker?

У меня возникла проблема с запуском миграций. На этапе, где выполняется команда <b>RUN ./migrator</b>, возникает следующая ошибка: <br/> <pre><code>panic: failed to connect to `host=db user=postgres database=iod`: hostname resolving error (lookup db on 192.168.65.7:53: no such host)</code></pre> <br/> <br/> Проблема заключается в том, что миграции запускаются во время сборки, в то время как база данных еще не готова, что и вызывает указанную ошибку. Как можно решить эту проблему? <br/> Я пробовал использовать команду CMD migrator, но не получил никакой реакции. Также настраивал отдельный сервис migrator в docker-compose, который должен запускаться после db, но ошибка остается прежней. <br/> <br/> Прилагаю код Dockerfile: <br/> <pre><code>FROM golang:alpine

RUN apk update &amp;&amp; apk add --no-cache git &amp;&amp; apk add --no-cache bash

WORKDIR /app

COPY go.mod go.sum ./
RUN go mod download

COPY . .
COPY .env .

RUN go build -o migrator ./cmd/migrator/main.go
RUN ./migrator

RUN go build -o bin/app cmd/app/main.go

ENTRYPOINT ["/app/bin/app"]

EXPOSE 8080</code></pre> <br/> <br/> Также предоставляю код docker-compose: <br/> <pre><code>networks:
  proxynet:
    driver: bridge

volumes:
  local_postgres_data:

services:
  db:
    container_name: db
    restart: always
    image: postgres:latest
    env_file: ./.env
    networks:
      - proxynet
    expose:
      - "5432"
    volumes:
      - local_postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}" ]
      interval: 10s
      retries: 5
      start_period: 30s
      timeout: 10s
  server:
    container_name: server
    restart: always
    build:
      context: .
      dockerfile: Dockerfile
    env_file: ./.env
    ports:
      - "8080:8080"
    networks:
      - proxynet
</code></pre>
  • 24 сентября 2024 г. 15:13
Ответы на вопрос 2
Ваше описание проблемы указывает на то, что вы пытаетесь выполнить миграции данных на этапе сборки образа (`RUN ./migrator`), тогда как база данных еще не запущена и недоступна, что и вызывает ошибку при попытке соединения.

Вот несколько подходов, как можно решить эту проблему:

### 1. Запуск миграций после запуска контейнера

Самый простой способ — выполнить миграции после того, как база данных будет доступна. Это можно сделать, изменив ваш `Dockerfile` и `docker-compose.yml`, чтобы выполнить миграции как отдельный шаг после запуска сервиса.

#### Измените ваш `Dockerfile`

Удалите строку `RUN ./migrator` из `Dockerfile`.

```dockerfile
FROM golang:alpine

RUN apk update && apk add --no-cache git && apk add --no-cache bash

WORKDIR /app

COPY go.mod go.sum ./
RUN go mod download

COPY . .
COPY .env .

RUN go build -o migrator ./cmd/migrator/main.go

RUN go build -o bin/app cmd/app/main.go

ENTRYPOINT ["/app/bin/app"]

EXPOSE 8080
```

#### Обновите `docker-compose.yml`

Добавьте отдельный сервис для миграций, который будет зависеть от сервиса базы данных (`db`). Вы можете использовать команду мигратора как сервис:

```yaml
services:
  db:
    container_name: db
    restart: always
    image: postgres:latest
    env_file: ./.env
    networks:
      - proxynet
    expose:
      - "5432"
    volumes:
      - local_postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}" ]
      interval: 10s
      retries: 5
      start_period: 30s
      timeout: 10s
  migrator:
    container_name: migrator
    build:
      context: .
      dockerfile: Dockerfile
    env_file: ./.env
    depends_on:
      db:
        condition: service_healthy
    networks:
      - proxynet
    command: ["/app/migrator"]
  server:
    container_name: server
    restart: always
    build:
      context: .
      dockerfile: Dockerfile
    env_file: ./.env
    ports:
      - "8080:8080"
    networks:
      - proxynet
```

### 2. Использование ожидания готовности сервиса

Если вы хотите, чтобы ваш контейнер сервера ждал, пока база данных будет доступна, вы можете использовать скрипт ожидания. Следующий пример говорит сервису `server` подождать 30 секунд перед его запуском, и если сервис `db` не ответит, он повторит попытку несколько раз.

Вы можете создать скрипт `wait-for-it.sh` или использовать инструменты вроде `wait-for`, чтобы ваш сервис ждал доступности базы данных. Скрипт можно добавить в образ, или использовать его из публичного репозитория.

### 3. Запуск миграций вручную

Вы также можете выполнять миграции вручную, запустив контейнер миграции отдельно командой:

```sh
docker-compose run --rm migrator
```

Этот подход может быть полезен в случаях, когда вы хотите управлять миграциями более вручную.

### Заключение

Важно выполнять миграции только после того, как база данных запущена и доступна. Вы можете сделать это с помощью отдельного сервиса для миграций в `docker-compose` или с помощью ожидания готовности. Убедитесь, что имена сетей и сервисов совпадают в конфигурации, чтобы избежать проблем с доступом.
в healthcheck в команду нужно добавить параметр -h 127.0.0.1 , только в этом случае healthcheck будет отрабатывать правильно.
Похожие вопросы