Difference between revisions of "Github Action using ssh"
From Logic Wiki
| Line 26: | Line 26: | ||
== Action == | == Action == | ||
<pre> | <pre> | ||
| − | + | name: Deploy:Live:IONOS | |
| − | + | on: | |
| − | + | push: | |
| − | + | branches: | |
| − | + | - main | |
| − | + | env: | |
| − | + | ENVIRONMENT: prod | |
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | - | + | |
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | jobs: | |
| − | + | build: | |
| − | + | runs-on: ubuntu-latest | |
| − | + | 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 | ||
</pre> | </pre> | ||
| + | |||
| + | === 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. | ||
| + | |||
| + | To hide echo in the logs I used | ||
| + | <pre> | ||
| + | echo "::group::Hidden section" | ||
| + | ...... | ||
| + | echo "::endgroup::" | ||
| + | </pre> | ||
| + | |||
| + | to use sudo with password I used this syntax | ||
| + | echo ${{ secrets.IONOS_SUDO_PASS }} | sudo -S bash -c "echo \"export RABBITMQ_DEFAULT_USER='${{ needs.build.outputs.RABBITMQ_DEFAULT_USER }}'\" >> /etc/environment" | ||
Revision as of 13:17, 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
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.
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"