I have the following yaml file set up for github-actions:
name: Build, Test, and Deploy to Staging
on:
push:
branches:
- develop
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
build-and-test:
runs-on: ubuntu-latest
env:
DB_DATABASE: foamfactory_stage
DB_ROOT_USER: root
DB_ROOT_PASSWORD: password
DB_USER: admin
DB_PASSWORD: ${{ secrets.MYSQL_USER_PASSWORD }}
steps:
- name: Set up MySQL
run: |
sudo systemctl start mysql.service
mysql -e 'CREATE DATABASE ${{ env.DB_DATABASE }};' -u${{ env.DB_ROOT_USER }} -p${{ env.DB_ROOT_PASSWORD }}
mysql -e "CREATE USER '${{ env.DB_USER }}'@'localhost' IDENTIFIED BY '${{ env.DB_PASSWORD }}';" -u${{env.DB_ROOT_USER}} -p${{ env.DB_ROOT_PASSWORD }}
mysql -e "CREATE DATABASE IF NOT EXISTS ${{ env.DB_DATABASE }};" -u${{env.DB_ROOT_USER}} -p${{ env.DB_ROOT_PASSWORD }}
mysql -e "GRANT ALL PRIVILEGES ON ${{ env.DB_DATABASE }}.* to '${{ env.DB_USER }}'@'localhost';" -u${{env.DB_ROOT_USER}} -p${{ env.DB_ROOT_PASSWORD }}
mysql -e "FLUSH PRIVILEGES;" -u${{env.DB_ROOT_USER}} -p${{ env.DB_ROOT_PASSWORD }}
- name: Install SSH key to Server
uses: shimataro/ssh-key-action@v2
with:
key: ${{ secrets.STAGE_API_DEPLOY_KEY }}
name: github-actions
known_hosts: ${{ secrets.STAGE_API_HOST_KEY }}
config: |
host stage.api.example.com
IdentityFile ~/.ssh/github-actions
IdentitiesOnly yes
ForwardAgent yes
- uses: actions/checkout@v2
- name: Set up Ruby Environment
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6.1
bundler-cache: true
env:
RAILS_ENV: staging
- name: Setup Database
env:
RAILS_ENV: staging
run: bundle exec rake db:setup
- name: Perform Database Migrations
env:
RAILS_ENV: staging
run: bundle exec rake db:migrate
- name: Run specs
env:
RAILS_ENV: staging
run: bundle exec rails spec
deploy-staging:
needs: build-and-test
runs-on: ubuntu-latest
steps:
- name: Install SSH Host Key
uses: shimataro/ssh-key-action@v2
with:
key: ${{ secrets.STAGE_API_DEPLOY_KEY }}
name: github-actions
known_hosts: ${{ secrets.STAGE_API_HOST_KEY }}
config: |
host stage.api.example.com
IdentityFile ~/.ssh/github-actions
IdentitiesOnly yes
ForwardAgent yes
- uses: actions/checkout@v2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Install SSH Key
run: |
eval "$(ssh-agent -s)"
ssh-add -D
ssh-add ~/.ssh/github-actions
- name: Check SSH Key Viability
run: |
echo "ls -al" | ssh deploy@stage.api.example.com
- name: Deploy to staging
run: |
bundle exec cap staging deploy
The last step, 'Deploy to staging' is failing with the following output:
Run bundle exec cap staging deploy
bundle exec cap staging deploy
shell: /usr/bin/bash -e {0}
#<Thread:0x000055e7af018820@/home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/sshkit-1.21.2/lib/sshkit/runners/parallel.rb:10 run> terminated with exception (report_on_exception is true):
/home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/sshkit-1.21.2/lib/sshkit/runners/parallel.rb:15:in `rescue in block (2 levels) in execute': Exception while executing as deploy@stage.api.example.com: Inappropriate ioctl for device (SSHKit::Runner::ExecuteError)
from /home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/sshkit-1.21.2/lib/sshkit/runners/parallel.rb:11:in `block (2 levels) in execute'
/home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/net-ssh-6.1.0/lib/net/ssh/prompt.rb:45:in `noecho': Inappropriate ioctl for device (Errno::ENOTTY)
from /home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/net-ssh-6.1.0/lib/net/ssh/prompt.rb:45:in `ask'
from /home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/net-ssh-6.1.0/lib/net/ssh/authentication/methods/password.rb:68:in `ask_password'
from /home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/net-ssh-6.1.0/lib/net/ssh/authentication/methods/password.rb:21:in `authenticate'
from /home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/net-ssh-6.1.0/lib/net/ssh/authentication/session.rb:86:in `block in authenticate'
from /home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/net-ssh-6.1.0/lib/net/ssh/authentication/session.rb:72:in `each'
from /home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/net-ssh-6.1.0/lib/net/ssh/authentication/session.rb:72:in `authenticate'
from /home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/net-ssh-6.1.0/lib/net/ssh.rb:255:in `start'
from /home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/sshkit-1.21.2/lib/sshkit/backends/connection_pool.rb:63:in `call'
from /home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/sshkit-1.21.2/lib/sshkit/backends/connection_pool.rb:63:in `with'
from /home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/sshkit-1.21.2/lib/sshkit/backends/netssh.rb:177:in `with_ssh'
from /home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/sshkit-1.21.2/lib/sshkit/backends/netssh.rb:130:in `execute_command'
from /home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/sshkit-1.21.2/lib/sshkit/backends/abstract.rb:148:in `block in create_command_and_execute'
from /home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/sshkit-1.21.2/lib/sshkit/backends/abstract.rb:148:in `tap'
from /home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/sshkit-1.21.2/lib/sshkit/backends/abstract.rb:148:in `create_command_and_execute'
from /home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/sshkit-1.21.2/lib/sshkit/backends/abstract.rb:61:in `test'
from /home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/capistrano-passenger-0.2.1/lib/capistrano/tasks/passenger.cap:43:in `block (3 levels) in <top (required)>'
from /home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/sshkit-1.21.2/lib/sshkit/backends/abstract.rb:31:in `instance_exec'
from /home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/sshkit-1.21.2/lib/sshkit/backends/abstract.rb:31:in `run'
from /home/runner/work/api/api/vendor/bundle/ruby/2.6.0/gems/sshkit-1.21.2/lib/sshkit/runners/parallel.rb:12:in `block (2 levels) in execute'
(Backtrace restricted to imported tasks)
cap aborted!
SSHKit::Runner::ExecuteError: Exception while executing as deploy@stage.api.example.com: Inappropriate ioctl for device
Caused by:
Errno::ENOTTY: Inappropriate ioctl for device
Tasks: TOP => rvm:hook => passenger:rvm:hook => passenger:test_which_passenger
(See full trace by running task with --trace)
deploy@stage.api.example.com's password:
Error: Process completed with exit code 1.
It appears that there is some lack of communication between the ssh-agent and the capistrano task, hence the reason it appears to be asking for a password. However, on the previous step, 'Check SSH Key Viability' it's clear that the SSH key is usable and working:
Run echo "ls -al" | ssh deploy@stage.api.example.com
echo "ls -al" | ssh deploy@stage.api.example.com
shell: /usr/bin/bash -e {0}
Pseudo-terminal will not be allocated because stdin is not a terminal.
Warning: Permanently added the ECDSA host key for IP address 'XXX.XXX.XXX.XXX' to the list of known hosts.
<output of ls command>
I'm not sure what I'm doing incorrectly here, but was wondering if someone might give me a hint as to why this isn't working to deploy from github-actions.
The reason this was failing was that it was using an incorrect SSH key to authenticate to Github, based on what was being used on the server (in this case, the server being api.stage.example.com
). Because, on api.stage.example.com
, my ~/.ssh/config
file showed:
Host github.com
HostName github.com
IdentityFile ~/.ssh/github-actions
It was using that file - ~/.ssh/github-actions
, and not id_rsa
as the private key to authenticate to github. As such, I needed to add a deploy key for the appropriate repository that contained the corresponding ~/.ssh/github_actions.pub
key.
Further, I had to change the line in my config/deploy/staging.rb
file that previously only used id_rsa
to utilize either id_rsa
or github_actions
:
set :ssh_options, {
keys: %w(~/.ssh/id_rsa ~/.ssh/github-actions),
forward_agent: true,
}
Re-deploying then alleviated the errors in question.