Difference between revisions of "Github Action using ssh"

From Logic Wiki
Jump to: navigation, search
 
Line 37: Line 37:
 
   build:
 
   build:
 
     runs-on: ubuntu-latest
 
     runs-on: ubuntu-latest
 +
    if: contains(github.event.head_commit.message, 'database update')
 +
 
 
     outputs:
 
     outputs:
 
       RABBITMQ_DEFAULT_USER: ${{ steps.ssm.outputs.RABBITMQ_DEFAULT_USER }}
 
       RABBITMQ_DEFAULT_USER: ${{ steps.ssm.outputs.RABBITMQ_DEFAULT_USER }}
Line 47: Line 49:
 
       KEYCLOAK_ADMIN_PASSWORD: ${{ steps.ssm.outputs.KEYCLOAK_ADMIN_PASSWORD }}
 
       KEYCLOAK_ADMIN_PASSWORD: ${{ steps.ssm.outputs.KEYCLOAK_ADMIN_PASSWORD }}
 
     steps:
 
     steps:
      - name: Exit early if file not changed
+
        run: |
+
          FILE="docker-compose-data.yml"
+
 
+
          # Compare against previous commit for push
+
          if git diff --name-only HEAD~1 HEAD | grep -qv "^$FILE$"; then
+
            # Check if our file is among the changes
+
            if ! git diff --name-only HEAD~1 HEAD | grep -q "^$FILE$"; then
+
              echo "$FILE not changed — exiting workflow successfully."
+
              exit 0
+
            fi
+
          fi
+
 
       - name: Configure AWS credentials
 
       - name: Configure AWS credentials
 
         uses: aws-actions/configure-aws-credentials@v4
 
         uses: aws-actions/configure-aws-credentials@v4
Line 157: Line 148:
 
Build job must output the variables to use them in deploy job. If steps are in the same job there is no need to do that.
 
Build job must output the variables to use them in deploy job. If steps are in the same job there is no need to do that.
  
In the first step it checks if docker-compose-data.yml is changed. If not it exits with success
+
This action only be triggered if commit message contains "database update"
 +
  if: contains(github.event.head_commit.message, 'database update')
  
 
To hide echo in the logs I used  
 
To hide echo in the logs I used  

Latest revision as of 14:25, 5 December 2025


Introducing github to server

First create a ssh key in the local machine (I named it as "github-deploy" when it asked)

ssh-keygen -t ed25519 -C "github-deploy"

-t ed25519 : encryption algorithm

-C "github-deploy" : puts a comment in public key file

Copy it to server

ssh-copy-id -i ~/.ssh/github-deploy.pub bookit

Create a secret in Github repo and store private key in it.

OR

Create the key on the server and copy private key to github secrets

Server Side

  • Add public key to authorized_keys
  • install docker
  • install docker-compose
  • create folder for deployment

Action

name: Deploy:Live:IONOS
on:
  push:
    branches:
      - main
env: 
  ENVIRONMENT: prod

jobs:
  build:
    runs-on: ubuntu-latest
    if: contains(github.event.head_commit.message, 'database update') 
   
    outputs:
      RABBITMQ_DEFAULT_USER: ${{ steps.ssm.outputs.RABBITMQ_DEFAULT_USER }}
      RABBITMQ_DEFAULT_PASS: ${{ steps.ssm.outputs.RABBITMQ_DEFAULT_PASS }}
      MONGO_INITDB_ROOT_USERNAME: ${{ steps.ssm.outputs.MONGO_INITDB_ROOT_USERNAME }}
      MONGO_INITDB_ROOT_PASSWORD: ${{ steps.ssm.outputs.MONGO_INITDB_ROOT_PASSWORD }}
      POSTGRES_USER: ${{ steps.ssm.outputs.POSTGRES_USER }}
      POSTGRES_PASSWORD: ${{ steps.ssm.outputs.POSTGRES_PASSWORD }}
      KEYCLOAK_ADMIN: ${{ steps.ssm.outputs.KEYCLOAK_ADMIN }}
      KEYCLOAK_ADMIN_PASSWORD: ${{ steps.ssm.outputs.KEYCLOAK_ADMIN_PASSWORD }}
    steps:
 
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_REGION }}

      - name: Load multiple AWS parameters
        id: ssm
        run: |
          PARAMS=$(aws ssm get-parameters \
            --names "/${{env.ENVIRONMENT}}/bookitfor.me.uk/rabbitMQ/username" \
                    "/${{env.ENVIRONMENT}}/bookitfor.me.uk/rabbitMQ/password" \
                    "/${{env.ENVIRONMENT}}/bookitfor.me.uk/mongodb/username" \
                    "/${{env.ENVIRONMENT}}/bookitfor.me.uk/mongodb/password" \
                    "/${{env.ENVIRONMENT}}/bookitfor.me.uk/postgresql/username" \
                    "/${{env.ENVIRONMENT}}/bookitfor.me.uk/postgresql/password" \
                    "/${{env.ENVIRONMENT}}/bookitfor.me.uk/keycloak/username" \
                    "/${{env.ENVIRONMENT}}/bookitfor.me.uk/keycloak/password" \
            --output json )

          RABBITMQ_DEFAULT_USER=$(echo "$PARAMS" | jq -r '.Parameters[] | select(.Name=="/${{env.ENVIRONMENT}}/bookitfor.me.uk/rabbitMQ/username") | .Value')
          RABBITMQ_DEFAULT_PASS=$(echo "$PARAMS" | jq -r '.Parameters[] | select(.Name=="/${{env.ENVIRONMENT}}/bookitfor.me.uk/rabbitMQ/password") | .Value')
          MONGO_INITDB_ROOT_USERNAME=$(echo "$PARAMS" | jq -r '.Parameters[] | select(.Name=="/${{env.ENVIRONMENT}}/bookitfor.me.uk/mongodb/username") | .Value')
          MONGO_INITDB_ROOT_PASSWORD=$(echo "$PARAMS" | jq -r '.Parameters[] | select(.Name=="/${{env.ENVIRONMENT}}/bookitfor.me.uk/mongodb/password") | .Value')
          POSTGRES_USER=$(echo "$PARAMS" | jq -r '.Parameters[] | select(.Name=="/${{env.ENVIRONMENT}}/bookitfor.me.uk/postgresql/username") | .Value')
          POSTGRES_PASSWORD=$(echo "$PARAMS" | jq -r '.Parameters[] | select(.Name=="/${{env.ENVIRONMENT}}/bookitfor.me.uk/postgresql/password") | .Value')
          KEYCLOAK_ADMIN=$(echo "$PARAMS" | jq -r '.Parameters[] | select(.Name=="/${{env.ENVIRONMENT}}/bookitfor.me.uk/keycloak/username") | .Value')
          KEYCLOAK_ADMIN_PASSWORD=$(echo "$PARAMS" | jq -r '.Parameters[] | select(.Name=="/${{env.ENVIRONMENT}}/bookitfor.me.uk/keycloak/password") | .Value')
          echo "::group::Hidden section"
          echo "RABBITMQ_DEFAULT_USER=$RABBITMQ_DEFAULT_USER" >> $GITHUB_OUTPUT
          echo "RABBITMQ_DEFAULT_PASS=$RABBITMQ_DEFAULT_PASS" >> $GITHUB_OUTPUT
          echo "MONGO_INITDB_ROOT_USERNAME=$MONGO_INITDB_ROOT_USERNAME" >> $GITHUB_OUTPUT
          echo "MONGO_INITDB_ROOT_PASSWORD=$MONGO_INITDB_ROOT_PASSWORD" >> $GITHUB_OUTPUT
          echo "POSTGRES_USER=$POSTGRES_USER" >> $GITHUB_OUTPUT
          echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> $GITHUB_OUTPUT
          echo "KEYCLOAK_ADMIN=$KEYCLOAK_ADMIN" >> $GITHUB_OUTPUT
          echo "KEYCLOAK_ADMIN_PASSWORD=$KEYCLOAK_ADMIN_PASSWORD" >> $GITHUB_OUTPUT 
          echo "::endgroup::"  
  deploy:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      
      - name: Set up SSH
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.IONOS_SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
         
      - name: Test SSH connection
        run: |
         ssh -o StrictHostKeyChecking=accept-new \
              ${{ secrets.IONOS_REMOTE_USER }}@${{ secrets.IONOS_REMOTE_HOST }} "echo Connected successfully"

      - name: Copy files to remote server
        run: |
          scp -i ~/.ssh/id_rsa -r ./docker-compose-data.yml \
             ${{ secrets.IONOS_REMOTE_USER }}@${{ secrets.IONOS_REMOTE_HOST }}:/home/logicmade/bookitfor.me.uk/            
          scp -i ~/.ssh/id_rsa -r ./sql \
             ${{ secrets.IONOS_REMOTE_USER }}@${{ secrets.IONOS_REMOTE_HOST }}:/home/logicmade/bookitfor.me.uk/sql

      - name: Persist env variables on remote host
        uses: appleboy/ssh-action@v1.2.0
        with:
          host: ${{ secrets.IONOS_REMOTE_HOST }}
          username: ${{ secrets.IONOS_REMOTE_USER }}
          key: ${{ secrets.IONOS_SSH_PRIVATE_KEY }}
          script: |
            echo "::group::Hidden section"
            echo ${{ secrets.IONOS_SUDO_PASS }} | sudo -S bash -c "echo \"export RABBITMQ_DEFAULT_USER='${{ needs.build.outputs.RABBITMQ_DEFAULT_USER }}'\" >> /etc/environment"
            echo ${{ secrets.IONOS_SUDO_PASS }} | sudo -S bash -c "echo \"export RABBITMQ_DEFAULT_PASS='${{ needs.build.outputs.RABBITMQ_DEFAULT_PASS }}'\" >> /etc/environment"
            echo ${{ secrets.IONOS_SUDO_PASS }} | sudo -S bash -c "echo \"export MONGO_INITDB_ROOT_USERNAME='${{ needs.build.outputs.MONGO_INITDB_ROOT_USERNAME }}'\" >> /etc/environment"
            echo ${{ secrets.IONOS_SUDO_PASS }} | sudo -S bash -c "echo \"export MONGO_INITDB_ROOT_PASSWORD='${{ needs.build.outputs.MONGO_INITDB_ROOT_PASSWORD }}'\" >> /etc/environment"
            echo ${{ secrets.IONOS_SUDO_PASS }} | sudo -S bash -c "echo \"export POSTGRES_USER='${{ needs.build.outputs.POSTGRES_USER }}'\" >> /etc/environment"
            echo ${{ secrets.IONOS_SUDO_PASS }} | sudo -S bash -c "echo \"export POSTGRES_PASSWORD='${{ needs.build.outputs.POSTGRES_PASSWORD }}'\" >> /etc/environment"
            echo ${{ secrets.IONOS_SUDO_PASS }} | sudo -S bash -c "echo \"export KEYCLOAK_ADMIN='${{ needs.build.outputs.KEYCLOAK_ADMIN }}'\" >> /etc/environment"
            echo ${{ secrets.IONOS_SUDO_PASS }} | sudo -S bash -c "echo \"export KEYCLOAK_ADMIN_PASSWORD='${{ needs.build.outputs.KEYCLOAK_ADMIN_PASSWORD }}'\" >> /etc/environment"  
            echo "::endgroup::"
            echo "Environment updated."
           
      - name: Restart Docker containers on remote server
        uses: appleboy/ssh-action@v1.2.0
        with:
          host: ${{ secrets.IONOS_REMOTE_HOST }}
          username: ${{ secrets.IONOS_REMOTE_USER }}
          key: ${{ secrets.IONOS_SSH_PRIVATE_KEY }}
          script: |          
            cd /home/logicmade/bookitfor.me.uk/
            docker compose -f docker-compose-data.yml down
            docker compose -f docker-compose-data.yml up -d --build

Notes about the Yaml file

Build job must output the variables to use them in deploy job. If steps are in the same job there is no need to do that.

This action only be triggered if commit message contains "database update"

  if: contains(github.event.head_commit.message, 'database update') 

To hide echo in the logs I used

     echo "::group::Hidden section"
     ......
     echo "::endgroup::"

to use sudo with password I used this syntax

echo $Template:Secrets.IONOS SUDO PASS | sudo -S bash -c "echo \"export RABBITMQ_DEFAULT_USER='$Template:Needs.build.outputs.RABBITMQ DEFAULT USER'\" >> /etc/environment"