ci: stream images to deploy hosts via ssh #10
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Backend Image Pipeline | |
| on: | |
| push: | |
| branches: | |
| - main | |
| tags: | |
| - "v*" | |
| workflow_dispatch: | |
| inputs: | |
| deploy_target: | |
| description: "Manual deploy target" | |
| required: true | |
| default: prod | |
| type: choice | |
| options: | |
| - prod | |
| - staging | |
| image_tag: | |
| description: "Image tag to deploy (defaults to sha-<workflow commit>)" | |
| required: false | |
| type: string | |
| permissions: | |
| contents: read | |
| packages: write | |
| env: | |
| REGISTRY: ghcr.io | |
| jobs: | |
| publish: | |
| name: Build and publish images | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| include: | |
| - name: backend | |
| dockerfile: ./Dockerfile | |
| context: . | |
| image_name: resolvekit-backend | |
| build_args: "" | |
| - name: kb-service | |
| dockerfile: ./knowledge_bases/Dockerfile | |
| context: . | |
| image_name: resolvekit-kb-service | |
| build_args: "" | |
| - name: dashboard | |
| dockerfile: ./dashboard/Dockerfile | |
| context: ./dashboard | |
| image_name: resolvekit-dashboard | |
| build_args: | | |
| NEXT_PUBLIC_API_BASE_URL=https://console.resolvekit.app | |
| NEXT_PUBLIC_IOS_SDK_REPO_URL=https://github.com/resolve-kit/resolvekit-ios-sdk | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@v5 | |
| - name: Set lowercase owner name | |
| id: owner | |
| run: echo "value=${GITHUB_REPOSITORY_OWNER,,}" >> "$GITHUB_OUTPUT" | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Docker metadata | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ steps.owner.outputs.value }}/${{ matrix.image_name }} | |
| tags: | | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| type=sha,prefix=sha- | |
| type=ref,event=tag | |
| - name: Build and push | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: ${{ matrix.context }} | |
| file: ${{ matrix.dockerfile }} | |
| build-args: ${{ matrix.build_args }} | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| deploy-staging: | |
| name: Deploy to staging | |
| runs-on: ubuntu-latest | |
| needs: publish | |
| if: | | |
| (github.event_name == 'push' && github.ref == 'refs/heads/main') || | |
| (github.event_name == 'workflow_dispatch' && inputs.deploy_target == 'staging') | |
| environment: staging | |
| steps: | |
| - name: Resolve image tag | |
| id: image | |
| run: | | |
| if [ -n "${{ inputs.image_tag }}" ]; then | |
| echo "value=${{ inputs.image_tag }}" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "value=sha-${GITHUB_SHA}" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Configure SSH key | |
| run: | | |
| mkdir -p ~/.ssh | |
| printf '%s\n' "${{ secrets.STAGING_SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519 | |
| chmod 600 ~/.ssh/id_ed25519 | |
| - name: Log in to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Stream images to staging host | |
| env: | |
| DEPLOY_HOST: 147.93.62.111 | |
| DEPLOY_USER: resolvekit | |
| IMAGE_TAG: ${{ steps.image.outputs.value }} | |
| run: | | |
| set -euo pipefail | |
| OWNER_LOWER=${GITHUB_REPOSITORY_OWNER,,} | |
| BACKEND_IMAGE="ghcr.io/${OWNER_LOWER}/resolvekit-backend:${IMAGE_TAG}" | |
| KB_IMAGE="ghcr.io/${OWNER_LOWER}/resolvekit-kb-service:${IMAGE_TAG}" | |
| DASHBOARD_IMAGE="ghcr.io/${OWNER_LOWER}/resolvekit-dashboard:${IMAGE_TAG}" | |
| for image in "$BACKEND_IMAGE" "$KB_IMAGE" "$DASHBOARD_IMAGE"; do | |
| docker pull "$image" | |
| docker save "$image" | ssh -o StrictHostKeyChecking=accept-new "$DEPLOY_USER@$DEPLOY_HOST" docker load | |
| done | |
| - name: Update staging backend services | |
| env: | |
| DEPLOY_HOST: 147.93.62.111 | |
| DEPLOY_USER: resolvekit | |
| IMAGE_TAG: ${{ steps.image.outputs.value }} | |
| run: | | |
| ssh -o StrictHostKeyChecking=accept-new "$DEPLOY_USER@$DEPLOY_HOST" " | |
| set -euo pipefail | |
| OWNER_LOWER='${GITHUB_REPOSITORY_OWNER,,}' | |
| BACKEND_IMAGE='ghcr.io/'\"\$OWNER_LOWER\"'/resolvekit-backend:${IMAGE_TAG}' | |
| KB_IMAGE='ghcr.io/'\"\$OWNER_LOWER\"'/resolvekit-kb-service:${IMAGE_TAG}' | |
| DASHBOARD_IMAGE='ghcr.io/'\"\$OWNER_LOWER\"'/resolvekit-dashboard:${IMAGE_TAG}' | |
| docker tag \"\$BACKEND_IMAGE\" resolvekit-backend:local-deploy | |
| docker tag \"\$KB_IMAGE\" resolvekit-kb-service:local-deploy | |
| docker tag \"\$DASHBOARD_IMAGE\" resolvekit-dashboard:local-deploy | |
| cd /home/resolvekit/resolvekit-backend | |
| docker compose -f docker-compose.local-deploy.yml up -d --no-build backend kb-service api dashboard | |
| " | |
| deploy-prod: | |
| name: Deploy to production | |
| runs-on: ubuntu-latest | |
| needs: publish | |
| if: github.event_name == 'workflow_dispatch' && inputs.deploy_target == 'prod' | |
| environment: production | |
| steps: | |
| - name: Resolve image tag | |
| id: image | |
| run: | | |
| if [ -n "${{ inputs.image_tag }}" ]; then | |
| echo "value=${{ inputs.image_tag }}" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "value=sha-${GITHUB_SHA}" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Configure SSH key | |
| run: | | |
| mkdir -p ~/.ssh | |
| printf '%s\n' "${{ secrets.PROD_SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519 | |
| chmod 600 ~/.ssh/id_ed25519 | |
| - name: Log in to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Stream images to production host | |
| env: | |
| DEPLOY_HOST: 92.242.187.124 | |
| DEPLOY_USER: nedas | |
| IMAGE_TAG: ${{ steps.image.outputs.value }} | |
| run: | | |
| set -euo pipefail | |
| OWNER_LOWER=${GITHUB_REPOSITORY_OWNER,,} | |
| BACKEND_IMAGE="ghcr.io/${OWNER_LOWER}/resolvekit-backend:${IMAGE_TAG}" | |
| KB_IMAGE="ghcr.io/${OWNER_LOWER}/resolvekit-kb-service:${IMAGE_TAG}" | |
| DASHBOARD_IMAGE="ghcr.io/${OWNER_LOWER}/resolvekit-dashboard:${IMAGE_TAG}" | |
| for image in "$BACKEND_IMAGE" "$KB_IMAGE" "$DASHBOARD_IMAGE"; do | |
| docker pull "$image" | |
| docker save "$image" | ssh -o StrictHostKeyChecking=accept-new "$DEPLOY_USER@$DEPLOY_HOST" docker load | |
| done | |
| - name: Update production backend services | |
| env: | |
| DEPLOY_HOST: 92.242.187.124 | |
| DEPLOY_USER: nedas | |
| IMAGE_TAG: ${{ steps.image.outputs.value }} | |
| run: | | |
| ssh -o StrictHostKeyChecking=accept-new "$DEPLOY_USER@$DEPLOY_HOST" " | |
| set -euo pipefail | |
| OWNER_LOWER='${GITHUB_REPOSITORY_OWNER,,}' | |
| BACKEND_IMAGE='ghcr.io/'\"\$OWNER_LOWER\"'/resolvekit-backend:${IMAGE_TAG}' | |
| KB_IMAGE='ghcr.io/'\"\$OWNER_LOWER\"'/resolvekit-kb-service:${IMAGE_TAG}' | |
| DASHBOARD_IMAGE='ghcr.io/'\"\$OWNER_LOWER\"'/resolvekit-dashboard:${IMAGE_TAG}' | |
| docker tag \"\$BACKEND_IMAGE\" resolvekit-backend:prod | |
| docker tag \"\$KB_IMAGE\" resolvekit-kb-service:prod | |
| docker tag \"\$DASHBOARD_IMAGE\" resolvekit-dashboard:prod | |
| cd /home/nedas/resolvekit-backend | |
| docker compose -f docker-compose.prod.yml up -d --no-build backend kb-service api dashboard | |
| " |