Automated deployment using github actions ssh and shell script
This article covers a very simple method using github actions to execute a deployment shell script on your remote server over ssh.
“How to deploy your code from Github action using shell script and ssh”
We are going to be using the following github action.
https://github.com/marketplace/actions/install-ssh-key
Using this github action it allows you to set the ssh key file, and known hosts file within the github virtual machine, running the action (also know as a github ‘runner’).
Once these values are set, you can then run commands from within your github action with a ssh session to your remote machine.
These commands could be, rsync
or scp
. In this particular case, we run ssh
to kick off a deployment script on our remote server.
The first setup is to setup your ssh keys. On your remote server, run the command ssh-keygen
dont enter any passcode. This will generate some files in your ./ssh
direcotry (as long as you used the defaults)
first, copy your public key to authorised_keys file
> cp id_rsa.pub authorized_keys
Then you need to add your private key into your github secrets with the variable name
> cat id_rsa
Then you can delete your private key file
> rm id_rsa
Once you have your keys all setup, you can start to build up your github action script.
This is a very basic example below.
name: CI Script
on: [push]
jobs:
# Deploy Process
deploy:
runs-on: ubuntu-18.04
steps:
- name: Install SSH Key
uses: shimataro/ssh-key-action@v2.1.0
with:
key: $ { { secrets.SSH_KEY } }
known_hosts: $ { { secrets.KNOWN_HOSTS } }
- name: Execute test Script
run: ssh username@myserver.com bash test.sh
In the script above, you can use a dummy know hosts file for setup and demonstration purposes.
known_hosts: github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2
A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIc
r6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzL
NnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6m
UoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJ
dsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJ
iS5ap43JXiUFFAaQ==
This script will set the ssh_key
and known_hosts
values, and then run the ssh command and kick off a shell script.
If your server is behind a firewall, for example, if it is a test or stage server, then you need to allow github ip address range access your server.
The list of IPs can be found below. In this particular case, we only need the IPs listed under ‘actions’.
When you make a change to main branch, ie, on push, this script will trigger.
It will run the script on your remote server, from your github action machine.
Keep this in mind when setting up your script on the remote machine.
You can see my repository with this in action here github.com/aalshukri/DevOps-Drupal-Deploy-TEST
In my example, I have added the server and username to github secrets, as to not expose them in a public script.
for example
${ { secrets.USERNAME } }
${ { secrets.SERVER } }
Would be set as
USERNAME = username
SERVER = myserver.com
so the run command in the github action script becomes
run: ssh ${ { secrets.USERNAME } }@${ { secrets.SERVER } } bash test.sh
or
run: ssh ${ { secrets.USERNAME } }@${ { secrets.SERVER } } bash /home/${ { secrets.USERNAME } }/test.sh
The entire script would be as follows below.
name: CI Script
on: [push]
jobs:
# Deploy Process
deploy:
runs-on: ubuntu-18.04
steps:
- name: Install SSH Key
uses: shimataro/ssh-key-action@v2.1.0
with:
key: ${ { secrets.SSH_KEY } }
known_hosts: ${ { secrets.KNOWN_HOSTS } }
- name: Execute test Script
run: ssh ${ { secrets.USERNAME } }@${ { secrets.SERVER } } bash test.sh
If you would like to replicate my test.sh
script, I have listed that below.
#!/bin/bash
now=$(date)
echo "Output $now" > output.txt
As you can see, this is a simple script to generate an output file along with the date.
I done some testing for the script execution time. I added a line to sleep the script for 100 seconds. I found the github action to wait until script is completed. This needs to be considered in your deployment scnario. You might want to run bash test.sh &
to push the script to the background, and then exit.
The script I used to test this out was below.
#!/bin/bash
now=$(date)
echo "Output $now" > output.txt
sleep 100
echo "Done $now" >> output.txt
This will overwite output.txt on each excution, with the line output but then append the done line after the specificed wait time is compelted.
Some issues I encountered.
jailshell: test.sh: command not found
You need to either call the script with root directory, or you need to include the bash command.
ie.
ssh username@myserver.com bash test.sh
or
ssh username@myserver.com /home/username/test.sh
Warning: Permanently added the RSA host key for IP address
to the list of known hosts.
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = (unset),
LC_ALL = (unset),
LANG = "C.UTF-8"
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = (unset),
LC_ALL = (unset),
LANG = "C.UTF-8"
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
jailshell: test.sh: command not found
Error: Process completed with exit code 127.
As solution as above.
ssh: connect to host username@myserver.com port 22: Connection timed out
Need to add github IP addresses so github server can access your sever.
You can read more about how I have used devops in my previous projects.
If you have any questions or comments you can contact me.