Как провести деплой с минимальным временем простоя?

У меня есть несколько перспективных пет-проектов, и я стремлюсь настроить CI/CD. Чтобы минимизировать время простоя, я решил использовать символьные ссылки как самый экономичный вариант. Однако я столкнулся с интересной проблемой:

**Имеется:**
1. Проект на Laravel
2. Локальный Gitlab Runner
3. Все программное обеспечение работает в Docker-контейнерах

**Суть проблемы:**
Проект клонируется в следующую директорию (вот фрагменты job'а):
```
GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_RUNNER_SHORT_TOKEN/$CI_CONCURRENT_ID/$CI_PROJECT_NAME/$CI_COMMIT_BRANCH/$CI_COMMIT_SHORT_SHA
```
Затем происходит создание символической ссылки на "правильное" место:
```bash
ln -srfT $GIT_CLONE_PATH $PROD_SRC_PATH
```
Я использую относительную ссылку, чтобы избежать нарушения ссылок при работе в контейнере. Для того чтобы файлы, загруженные пользователями, оставались на месте, я подключаю папку с этими файлами аналогичными способами:
```bash
ln -srfT $PROD_DATA_PATH/storage $GIT_CLONE_PATH/storage
```

В файле `docker-compose.yml` я подключаю необходимые папки ко всем соответствующим контейнерам:
```yaml
volumes:
    - ${OASIS_SRC}:/var/www/oasis
    - ./www/data:/var/www/data
    - ./www/builds:/var/www/builds
```

**Проблема заключается в следующем:**
Поскольку `GIT_CLONE_PATH` имеет довольно длинную длину, относительная ссылка на файлы пользователя образуется в виде `storage -> ../../../../../../data/oasis/storage`. Однако путь внутри контейнера короче (/var/www/oasis), что приводит к ошибке «No such file or directory». Интересно, что рядом находится другой проект, который конфигурируется аналогичным образом, но...
  • 14 апреля 2025 г. 6:55
Ответы на вопрос 2
Проблема, с которой вы столкнулись, связана с тем, что символические ссылки с относительными путями могут не работать так, как ожидалось, когда они ссылаются на разные уровни вложенности директорий в контейнере. Когда вы создаете символическую ссылку с длинным относительным путем, она может оказаться неверной в контексте, в котором будет использоваться.

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

### 1. Используйте абсолютные пути для символических ссылок

Хотя вы и пытаетесь избежать "недействительных" ссылок из-за глубокой вложенности, использование абсолютных путей всегда будет более надежным способом. Вам нужно будет убедиться, что пути правильно указывают на нужные директории и существуют внутри контейнера.

```bash
ln -s $GIT_CLONE_PATH/storage /var/www/data/storage
```

### 2. Убедитесь, что папка, на которую вы ссылаетесь, существует

Перед созданием символической ссылки проверьте, существует ли целевая директория, и при необходимости создавайте и инициализируйте её.

```bash
mkdir -p $GIT_CLONE_PATH/storage
ln -s /var/www/data/storage $GIT_CLONE_PATH/storage
```

### 3. Используйте `docker cp`

Если проблема с символическими ссылками все еще сохраняется, альтернативным вариантом может быть использование команды `docker cp`, чтобы копировать файлы из одной директории в другую в контейнере.

### 4. Другие подходы к развертыванию

Может быть полезно рассмотреть другие методы развертывания вместо использования символических ссылок:

- **Blue/Green Deployment**: Создайте параллельные среды (например, `blue` и `green`). В процессе развертывания вы можете переключиться между этими средами. Это позволит вам минимизировать время простоя, поскольку одной среде можно будет делать обновления, пока другая размещает пользователей.

- **Canary Releases**: Развертывание новой версии приложения только на небольшой части сервера (например, 10% трафика). Это позволит вам протестировать новую версию на практике перед тем, как развернуть её для всех пользователей.

### 5. Автоматизация

Убедитесь, что процесс CI/CD полностью автоматизирован и, например, имеется этап проверки, который подтверждает корректность структур и доступность целевых директорий после развертывания перед переключением трафика.

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

Выбор подхода будет зависеть от ваших конкретных условий и требований. Я рекомендую сосредоточиться на использовании абсолютных путей и дополнительно протестировать и автоматизировать процесс развертывания, чтобы минимизировать потенциальные проблемы с доступом к директориям и временем простоя.
А если запустить два-три инстанса приложения - то можно их обновлять по очереди и без полной остановки проекта. Само собой если в коде проекта допускается работа в несколько инстансов.
Похожие вопросы