name: Deploy Telegram Bot on: push: branches: - main env: VERSION: 3.10.0 jobs: # ЧАСТЬ 1: Собираем образы и кладем в Gitea (чтобы делиться с ребятами) build-and-push: runs-on: ubuntu-latest # Замени на метку твоего раннера, если она другая steps: - name: Checkout repository uses: actions/checkout@v4 - name: Login to Gitea Container Registry uses: docker/login-action@v3 with: registry: git.codeanddice.ru # НАПРИМЕР: gitea.my-server.com username: toutsu password: ${{ secrets.GIT_TOKEN }} - name: Build Bot image run: | docker build \ --label "org.opencontainers.image.source=https://git.codeanddice.ru/${{ gitea.repository }}" \ -f src/GmRelay.Bot/Dockerfile \ -t git.codeanddice.ru/toutsu/gmrelay-bot:latest \ -t git.codeanddice.ru/toutsu/gmrelay-bot:${{ env.VERSION }} \ . - name: Push Bot image run: | docker push git.codeanddice.ru/toutsu/gmrelay-bot:latest docker push git.codeanddice.ru/toutsu/gmrelay-bot:${{ env.VERSION }} - name: Build Discord Bot image run: | docker build \ --label "org.opencontainers.image.source=https://git.codeanddice.ru/${{ gitea.repository }}" \ -f src/GmRelay.DiscordBot/Dockerfile \ -t git.codeanddice.ru/toutsu/gmrelay-discord-bot:latest \ -t git.codeanddice.ru/toutsu/gmrelay-discord-bot:${{ env.VERSION }} \ . - name: Push Discord Bot image run: | docker push git.codeanddice.ru/toutsu/gmrelay-discord-bot:latest docker push git.codeanddice.ru/toutsu/gmrelay-discord-bot:${{ env.VERSION }} - name: Build Web image run: | docker build \ --label "org.opencontainers.image.source=https://git.codeanddice.ru/${{ gitea.repository }}" \ -f src/GmRelay.Web/Dockerfile \ -t git.codeanddice.ru/toutsu/gmrelay-web:latest \ -t git.codeanddice.ru/toutsu/gmrelay-web:${{ env.VERSION }} \ . - name: Push Web image run: | docker push git.codeanddice.ru/toutsu/gmrelay-web:latest docker push git.codeanddice.ru/toutsu/gmrelay-web:${{ env.VERSION }} # ЧАСТЬ 1.5: Сканируем собранные образы на уязвимости scan-images: needs: build-and-push runs-on: ubuntu-latest steps: - name: Install Trivy run: | # Install Trivy from the official Docker image instead of the # upstream install.sh. Rationale: # 1. install.sh resolves the positional tag against the # GitHub releases API; when a release is unpublished or # yanked, the script fails with # `unable to find '' - use 'latest' or see ...` # even when the release once existed. We hit this with # v0.71.0. # 2. Docker Hub tags are content-addressed and rarely # removed, so a pinned image tag is much more stable. # 3. The image is multi-arch (linux/amd64, linux/arm64, # linux/ppc64le, linux/s390x) so the same tag works on # the GitHub-hosted runner and on the ARM64 Pi runner. set -euo pipefail TRIVY_VERSION="0.70.0" docker pull --quiet "aquasec/trivy:${TRIVY_VERSION}" docker create --name trivy-tmp "aquasec/trivy:${TRIVY_VERSION}" docker cp trivy-tmp:/usr/local/bin/trivy /usr/local/bin/trivy docker rm trivy-tmp >/dev/null chmod +x /usr/local/bin/trivy trivy --version - name: Scan Bot image run: | trivy image \ --severity HIGH,CRITICAL \ --exit-code 1 \ --format table \ git.codeanddice.ru/toutsu/gmrelay-bot:${{ env.VERSION }} - name: Scan Discord Bot image run: | trivy image \ --severity HIGH,CRITICAL \ --exit-code 1 \ --format table \ git.codeanddice.ru/toutsu/gmrelay-discord-bot:${{ env.VERSION }} - name: Scan Web image run: | trivy image \ --severity HIGH,CRITICAL \ --exit-code 1 \ --format table \ git.codeanddice.ru/toutsu/gmrelay-web:${{ env.VERSION }} # ЧАСТЬ 2: Запускаем эти образы на самом сервере deploy: needs: scan-images runs-on: ubuntu-latest # Тот же локальный раннер steps: - name: Checkout repository uses: actions/checkout@v4 - name: Create .env file with secrets run: | echo "TELEGRAM_BOT_TOKEN=${{ secrets.TELEGRAM_BOT_TOKEN }}" > .env echo "POSTGRES_PASSWORD=${{ secrets.POSTGRES_PASSWORD }}" >> .env echo "DISCORD_BOT_TOKEN=${{ secrets.DISCORD_BOT_TOKEN }}" >> .env echo "TELEGRAM_BOT_USERNAME=${{ secrets.TELEGRAM_BOT_USERNAME }}" >> .env echo "TELEGRAM_MINI_APP_URL=${{ secrets.TELEGRAM_MINI_APP_URL }}" >> .env echo "DISCORD_CLIENT_ID=${{ secrets.DISCORD_CLIENT_ID }}" >> .env echo "DISCORD_CLIENT_SECRET=${{ secrets.DISCORD_CLIENT_SECRET }}" >> .env echo "DISCORD_REDIRECT_URI=${{ secrets.DISCORD_REDIRECT_URI }}" >> .env - name: Deploy Containers run: | # Авторизуемся локальным докером в нашей Gitea docker login git.codeanddice.ru/ -u toutsu -p ${{ secrets.GIT_TOKEN }} # Pull гарантирует, что мы получили нужную версию. docker compose pull bot discord web # Запускаем! Флаг -d оставит их работать в фоне. docker compose up -d # Ждём, пока сервисы перейдут в healthy или упадут SERVICES="bot discord web" MAX_WAIT=40 INTERVAL=5 ELAPSED=0 while [ $ELAPSED -lt $MAX_WAIT ]; do NOT_HEALTHY=0 for svc in $SERVICES; do HEALTH=$(docker compose ps $svc --format="{{.Health}}" 2>/dev/null | head -n1) if [ "$HEALTH" != "healthy" ]; then STATE=$(docker compose ps $svc --format="{{.State}}" 2>/dev/null | head -n1) echo "❌ $svc not healthy yet (state: ${STATE:-unknown})" NOT_HEALTHY=$((NOT_HEALTHY + 1)) fi done if [ $NOT_HEALTHY -eq 0 ]; then echo "✅ All services are healthy!" exit 0 fi sleep $INTERVAL ELAPSED=$((ELAPSED + INTERVAL)) done echo "⏰ Timed out waiting for services to become healthy" docker compose ps exit 1