From 528b2e4d2b45f9f449af5a60e61cd4bea351aae2 Mon Sep 17 00:00:00 2001 From: Mrugesh Mohapatra Date: Thu, 16 Jan 2025 00:13:33 +0530 Subject: [PATCH] feat(deployments): build and deploy the stack --- .github/workflows/build-images.yml | 43 ------------- .github/workflows/deploy.yml | 100 +++++++++++++++++++++++++++++ .github/workflows/docker-docr.yml | 72 +++++++++++++++++++++ 3 files changed, 172 insertions(+), 43 deletions(-) delete mode 100644 .github/workflows/build-images.yml create mode 100644 .github/workflows/deploy.yml create mode 100644 .github/workflows/docker-docr.yml diff --git a/.github/workflows/build-images.yml b/.github/workflows/build-images.yml deleted file mode 100644 index cec68a23a1d..00000000000 --- a/.github/workflows/build-images.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: CI - Build Images -on: - workflow_dispatch: - -jobs: - build: - name: Build (Image) - runs-on: ubuntu-22.04 - strategy: - matrix: - node-version: [20.x] - apps: [api] - site_tlds: [dev, org] - fail-fast: false - - steps: - - name: Checkout Source Files - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Create a tagname - id: tagname - run: | - echo "tagname=$(git rev-parse --short HEAD)-$(date +%Y%m%d)-$(date +%H%M)" >> $GITHUB_ENV - - - name: Build & Tag Image - run: | - docker build \ - --tag registry.digitalocean.com/${{ secrets.DOCR_NAME }}/${{ matrix.site_tlds }}/learn-${{ matrix.apps }}:$tagname \ - --tag registry.digitalocean.com/${{ secrets.DOCR_NAME }}/${{ matrix.site_tlds }}/learn-${{ matrix.apps }}:latest \ - --file docker/${{ matrix.apps }}/Dockerfile . - - - name: Install doctl - uses: digitalocean/action-doctl@v2 - with: - token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} - - - name: Log in to DigitalOcean Container Registry with short-lived credentials - run: doctl registry login --expiry-seconds 1200 - - - name: Push image to DigitalOcean Container Registry - run: | - docker push registry.digitalocean.com/${{ secrets.DOCR_NAME }}/${{ matrix.site_tlds }}/learn-${{ matrix.apps }}:$tagname - docker push registry.digitalocean.com/${{ secrets.DOCR_NAME }}/${{ matrix.site_tlds }}/learn-${{ matrix.apps }}:latest diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 00000000000..0afc923360b --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,100 @@ +name: CD -- Deploy - API (Docker Swarm) + +on: + workflow_dispatch: + +jobs: + static: + runs-on: ubuntu-24.04 + outputs: + site_tld: ${{ steps.static_data.outputs.site_tld }} + environment: ${{ steps.static_data.outputs.environment }} + + steps: + - name: Set site_tld + id: static_data + run: | + if [ "${{ github.ref }}" == "refs/heads/prod-staging" ]; then + echo "site_tld=dev" >> $GITHUB_OUTPUT + echo "environment=staging" >> $GITHUB_OUTPUT + elif [ "${{ github.ref }}" == "refs/heads/prod-current" ]; then + echo "site_tld=org" >> $GITHUB_OUTPUT + echo "environment=production" >> $GITHUB_OUTPUT + else + echo "site_tld=dev" >> $GITHUB_OUTPUT + echo "environment=staging" >> $GITHUB_OUTPUT + fi + + build: + name: Build & Push Docker Image + needs: static + uses: ./.github/workflows/re--docker-docr.yml + with: + site_tld: ${{ needs.static.outputs.site_tld }} + app: api + + deploy: + runs-on: ubuntu-24.04 + needs: [static, build] + permissions: + deployments: write + environment: + name: ${{ needs.static.outputs.environment }} + url: https://api.freecodecamp.${{ needs.static.outputs.site_tld }}/status/ping?version=${{ needs.build.outputs.tagname }} + + steps: + - name: Setup and connect to Tailscale network + uses: tailscale/github-action@v3 + with: + oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} + oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} + tags: tag:ci + version: latest + + - name: Configure SSH + # This is a workaround to avoid the SSH warning about known hosts & strict host key checking. + # It's not a problem for us, because we're using Tailscale to connect. + run: | + mkdir -p ~/.ssh + echo "Host * + UserKnownHostsFile=/dev/null + StrictHostKeyChecking no" > ~/.ssh/config + + - name: Check connection to Deployment Target + run: | + tailscale status | grep -q "$TS_MACHINE_NAME" || { echo "Machine not found"; exit 1; } + ssh $TS_USERNAME@$TS_MACHINE_NAME "uptime" + + - name: Deploy with Docker Stack + env: + STACK_NAME: stg-api + RUNTIME_ENVS: ${{ secrets.RUNTIME_ENVS }} + DEPLOYMENT_VERSION: ${{ needs.build.outputs.tagname }} + run: | + REMOTE_USER=$TS_USERNAME + ssh $TS_USERNAME@$TS_MACHINE_NAME /bin/bash << EOF + + # Change to the config directory + cd /home/${REMOTE_USER}/docker-swarm-config/stacks/api || exit 1 + echo "Debug: Current directory: \$(pwd)" + + # Create temp file for the environment variables + echo "${RUNTIME_ENVS}" > .env.tmp + echo "DEPLOYMENT_VERSION=${DEPLOYMENT_VERSION}" >> .env.tmp + + # Source the environment variables + set -a # Automatically export all variables + source .env.tmp || exit 1 + set +a + + # Clean up the temp file + rm -f .env.tmp + + # Verify the environment variables + echo "Debug: Sanity check variables: " + env | grep -E '^DEPLOYMENT' || echo 'Vars not found' + echo "Debug: Sanity check config: " + docker stack config -c stack-api.yml | rg 'DOMAIN' || echo 'Config not found' + + EOF + shell: bash diff --git a/.github/workflows/docker-docr.yml b/.github/workflows/docker-docr.yml new file mode 100644 index 00000000000..a3ebcca6a9b --- /dev/null +++ b/.github/workflows/docker-docr.yml @@ -0,0 +1,72 @@ +name: Docker -- DOCR + +on: + workflow_dispatch: + inputs: + site_tld: + required: true + type: choice + description: 'Input: The site tld (variant) to build' + options: + - dev + - org + default: 'dev' + app: + required: true + type: string + description: 'Input: The app (component) to build' + default: 'api' + workflow_call: + inputs: + site_tld: + required: true + type: string + description: 'Input: The site tld (variant) to build' + app: + required: true + type: string + description: 'Input: The app (component) to build' + outputs: + tagname: + description: 'Output: The tagname for the image built' + value: ${{ jobs.build.outputs.tagname }} + +jobs: + build: + name: Build (Image) + runs-on: ubuntu-24.04 + permissions: + contents: read + outputs: + tagname: ${{ steps.tagname.outputs.tagname }} + + steps: + - name: Checkout Source Files + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Create a tagname + id: tagname + run: | + tagname=$(git rev-parse --short HEAD)-$(date +%Y%m%d)-$(date +%H%M) + echo "tagname=$tagname" >> $GITHUB_ENV + echo "tagname=$tagname" >> $GITHUB_OUTPUT + + - name: Build & Tag Image + run: | + docker build \ + --tag registry.digitalocean.com/${{ secrets.DOCR_NAME }}/${{ inputs.site_tld }}/learn-${{ inputs.app }}:$tagname \ + --tag registry.digitalocean.com/${{ secrets.DOCR_NAME }}/${{ inputs.site_tld }}/learn-${{ inputs.app }}:latest \ + --file docker/${{ inputs.app }}/Dockerfile . + + - name: Install doctl + uses: digitalocean/action-doctl@v2 + with: + token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + + - name: Log in to DigitalOcean Container Registry with short-lived credentials + run: doctl registry login --expiry-seconds 1200 + + - name: Push image to DigitalOcean Container Registry + run: | + docker push registry.digitalocean.com/${{ secrets.DOCR_NAME }}/${{ inputs.site_tld }}/learn-${{ inputs.app }}:$tagname + docker push registry.digitalocean.com/${{ secrets.DOCR_NAME }}/${{ inputs.site_tld }}/learn-${{ inputs.app }}:latest