Ответ
В последнем production-проекте мы использовали CI/CD пайплайн на GitHub Actions с Docker. Целью была полная автоматизация от пуша кода в main до обновления сервиса на сервере.
Основные этапы пайплайна (.github/workflows/deploy.yml):
-
Тестирование и сборка:
jobs: test-and-build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: { node-version: '20' } - run: npm ci - run: npm run lint # ESLint - run: npm test # Jest - run: npm run build # Если есть сборка (TypeScript, etc.) -
Сборка и публикация Docker-образа:
build-and-push: needs: test-and-build runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build Docker image run: docker build -t ${{ secrets.DOCKER_USERNAME }}/my-app:${{ github.sha }} . - name: Push to Docker Hub run: | echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin docker push ${{ secrets.DOCKER_USERNAME }}/my-app:${{ github.sha }} -
Деплой на продакшен-сервер:
deploy: needs: build-and-push runs-on: ubuntu-latest steps: - name: Deploy via SSH uses: appleboy/ssh-action@v1 with: host: ${{ secrets.SSH_HOST }} username: ${{ secrets.SSH_USER }} key: ${{ secrets.SSH_PRIVATE_KEY }} script: | cd /opt/my-app docker-compose pull docker-compose up -d --remove-orphans docker image prune -f
Инфраструктура на сервере:
- Приложение и зависимости (PostgreSQL, Redis) описаны в
docker-compose.prod.yml. - Nginx как reverse proxy и для раздачи статики.
- PM2 или аналогичный процесс-менеджер не требуется, так как контейнером управляет Docker.
- Для staging-окружения использовался аналогичный пайплайн, но с триггером на пуши в ветку
developи деплоем на отдельный сервер.
Ответ 18+ 🔞
Слушай, а вот это реально годная штука, когда всё само катается от пуша до прода. Мы на прошлом проекте так и сделали — настроили CI/CD на GitHub Actions, чтобы не ебаться руками каждый раз. Цель была простая: закоммитил в main — и через пятнадцать минут твой сервис уже обновился на боевом сервере, пока ты кофе пьёшь. Ёперный театр, удобно же!
Вот как этот пайплайн в .github/workflows/deploy.yml выглядел, по шагам:
-
Сначала всё проверяем и собираем:
jobs: test-and-build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: { node-version: '20' } - run: npm ci - run: npm run lint # ESLint - run: npm test # Jest - run: npm run build # Если есть сборка (TypeScript, etc.)То есть, сначала линтер прогоняем, потом тесты. Если тесты не прошли — всё, приехали, дальше пайплайн накрывается медным тазом. И правильно, зачем нам кривой код деплоить?
-
Потом Docker-образ лепим и в репозиторий пихаем:
build-and-push: needs: test-and-build runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build Docker image run: docker build -t ${{ secrets.DOCKER_USERNAME }}/my-app:${{ github.sha }} . - name: Push to Docker Hub run: | echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin docker push ${{ secrets.DOCKER_USERNAME }}/my-app:${{ github.sha }}Тут прикол в теге
${{ github.sha }}— каждый коммит получает свой уникальный образ. Хуй с горы, зато всегда можно откатиться к конкретной версии. -
Ну и финальный аккорд — деплой на сервак:
deploy: needs: build-and-push runs-on: ubuntu-latest steps: - name: Deploy via SSH uses: appleboy/ssh-action@v1 with: host: ${{ secrets.SSH_HOST }} username: ${{ secrets.SSH_USER }} key: ${{ secrets.SSH_PRIVATE_KEY }} script: | cd /opt/my-app docker-compose pull docker-compose up -d --remove-orphans docker image prune -fПодключается по SSH, заходит в папку, дёргает свежий образ и перезапускает контейнеры. Команда
prune -fстарые образы подчищает, чтобы диск не засрать. Красота, ебушки-воробушки!
А на сервере что творилось:
- Всё хозяйство — приложение, PostgreSQL, Redis — в одном
docker-compose.prod.yml. Порядок, бля. - Nginx спереди как reverse proxy, он же статику отдаёт.
- PM2 или какой другой процесс-менеджер был нахуй не нужен, потому что контейнер сам как сервис работает. Доверия ебать ноль к этим менеджерам, когда есть Docker.
- Для тестового стенда (staging) был такой же пайплайн, но он срабатывал на пуши в ветку
developи катал всё на отдельный сервер. Чтобы не бздеть, что сломаем продакшен.