Capistrano部署在git:check阶段失败 - 权限被拒绝(publickey)
Capistrano部署在git:check阶段失败 - 权限被拒绝(publickey)
本地操作系统:Windows 10 Pro(使用Git Bash作为终端)
暂存服务器操作系统:Ubuntu 16.04 LTS
我一直在努力在暂存服务器上实现基本的Capistrano部署。我按照此指南设置了Capistrano。
部署过程总是在git:check
阶段失败,据称没有权限访问我在GitLab上的仓库。我确定我的SSH代理转发正常工作,因为我能够使用我的SSH密钥SSH登录服务器并访问GitLab。SSH密钥没有存储在我的服务器上:
$ ssh deploy@myserver.com deploy@MyServer:~$ ssh -T git@gitlab.com debug1: client_input_channel_open: ctype auth-agent@openssh.com rchan 2 win 65536 max 16384 debug1: channel 1: new [authentication agent connection] debug1: confirm auth-agent@openssh.com Welcome to GitLab, Alexander!debug1: channel 1: FORCE input drain
到目前为止,关于这个问题的所有问题都没有起作用。
以下是我的部署文件:
deploy.rb
set :application, "myapp"
set :branch, "master"
set :repo_url, "git@gitlab.com:MyApp/myapp.git"
# Defaults to false
# Skip migration if files in db/migrate were not modified
set :conditionally_migrate, true
set :ssh_options, { forward_agent: true }
set :rvm_ruby_version, '2.2.6'
# Default deploy_to directory is /var/www/my_app_name
set :deploy_to, "/var/www/#{fetch(:application)}/"
set :deploy_user, "deploy"
# Tells Capistrano to store config/database.yml file inside a directory called /shared, which is meant for any files
# we want to persist between deploys
set :linked_files, fetch(:linked_files, []).push('config/database.yml', 'config/secrets.yml')
# Directories that are meant to persist between deploys, and they will also be stored inside /shared
set :linked_dirs, fetch(:linked_dirs, []).push('bin', 'log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system', 'public/uploads')
# The specs that should be run before deployment is allowed to continue
set :tests, []
# Delayed Job Config: https://github.com/AgileConsultingLLC/capistrano3-delayed-job
set :delayed_job_workers, 3
# Keep the last 5 deploys for rollback purposes
set :keep_releases, 5
namespace :deploy do
after :restart, :clear_cache do
on roles(:web), in: :groups, limit: 3, wait: 10 do
# Here we can do anything such as:
# within release_path do
# execute :rake, 'cache:clear'
# end
end
end
end
staging.rb
set :stage, :staging
set :rails_env, :staging
role :app, %w{deploy@myserver.com}
role :web, %w{deploy@myserver.com}
role :db, %w{deploy@myserver.com}
以下是我部署时的Capistrano调试日志:
$ bundle exec cap staging deploy --trace ** Invoke staging (first_time) ** Execute staging ** Invoke load:defaults (first_time) ** Execute load:defaults ** Invoke rvm:hook (first_time) ** Invoke passenger:rvm:hook (first_time) ** Invoke passenger:test_which_passenger (first_time) ** Execute passenger:test_which_passenger ** Execute passenger:rvm:hook ** Execute rvm:hook ** Invoke rvm:check (first_time) ** Execute rvm:check rvm 1.29.3 (latest) by Michal Papis, Piotr Kuczynski, Wayne E. Seguin [https://rvm.io] ruby-2.2.6 ruby 2.2.6p396 (2016-11-15 revision 56800) [x86_64-linux] ** Invoke bundler:map_bins (first_time) ** Invoke passenger:bundler:hook (first_time) ** Execute passenger:bundler:hook ** Execute bundler:map_bins ** Invoke deploy:set_rails_env (first_time) ** Execute deploy:set_rails_env ** Invoke deploy:set_linked_dirs (first_time) ** Execute deploy:set_linked_dirs ** Invoke deploy:set_rails_env ** Invoke deploy (first_time) ** Execute deploy ** Invoke deploy:starting (first_time) ** Execute deploy:starting ** Invoke deploy:check (first_time) ** Invoke git:check (first_time) ** Invoke git:wrapper (first_time) ** Execute git:wrapper 00:00 git:wrapper 01 mkdir -p /tmp 01 deploy@myserver.com 0.286s Uploading /tmp/git-ssh-myapp-staging-localuser.sh 100.0% 02 chmod 700 /tmp/git-ssh-myapp-staging-localuser.sh 02 deploy@myserver.com 0.277s ** Execute git:check 00:01 git:check 01 git ls-remote git@gitlab.com:MyApp/myapp.git HEAD 01 Permission denied (publickey). 01 fatal: Could not read from remote repository. 01 01 Please make sure you have the correct access rights 01 and the repository exists. cap aborted! SSHKit::Runner::ExecuteError: Exception while executing as deploy@myserver.com: git exit status: 128 git stdout: Nothing written git stderr: Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists. C:/Ruby22/lib/ruby/gems/2.2.0/gems/sshkit-1.15.1/lib/sshkit/runners/parallel.rb:15:in `rescue in block (2 levels) in execute' C:/Ruby22/lib/ruby/gems/2.2.0/gems/sshkit-1.15.1/lib/sshkit/runners/parallel.rb:11:in `block (2 levels) in execute' Caused by: SSHKit::Command::Failed: git exit status: 128 git stdout: Nothing written git stderr: Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists. C:/Ruby22/lib/ruby/gems/2.2.0/gems/sshkit-1.15.1/lib/sshkit/command.rb:99:in `exit_status=' C:/Ruby22/lib/ruby/gems/2.2.0/gems/sshkit-1.15.1/lib/sshkit/backends/netssh.rb:169:in `execute_command' C:/Ruby22/lib/ruby/gems/2.2.0/gems/sshkit-1.15.1/lib/sshkit/backends/abstract.rb:141:in `block in create_command_and_execute' C:/Ruby22/lib/ruby/gems/2.2.0/gems/sshkit-1.15.1/lib/sshkit/backends/abstract.rb:141:in `tap' C:/Ruby22/lib/ruby/gems/2.2.0/gems/sshkit-1.15.1/lib/sshkit/backends/abstract.rb:141:in `create_command_and_execute' C:/Ruby22/lib/ruby/gems/2.2.0/gems/sshkit-1.15.1/lib/sshkit/backends/abstract.rb:74:in `execute' C:/Ruby22/lib/ruby/gems/2.2.0/gems/capistrano-3.10.1/lib/capistrano/scm/git.rb:77:in `git' C:/Ruby22/lib/ruby/gems/2.2.0/gems/capistrano-3.10.1/lib/capistrano/scm/git.rb:38:in `check_repo_is_reachable' C:/Ruby22/lib/ruby/gems/2.2.0/gems/capistrano-3.10.1/lib/capistrano/scm/tasks/git.rake:19:in `block (4 levels) in eval_rakefile' C:/Ruby22/lib/ruby/gems/2.2.0/gems/sshkit-1.15.1/lib/sshkit/backends/abstract.rb:93:in `with' C:/Ruby22/lib/ruby/gems/2.2.0/gems/capistrano-3.10.1/lib/capistrano/scm/tasks/git.rake:18:in `block (3 levels) in eval_rakefile' C:/Ruby22/lib/ruby/gems/2.2.0/gems/sshkit-1.15.1/lib/sshkit/backends/abstract.rb:29:in `instance_exec' C:/Ruby22/lib/ruby/gems/2.2.0/gems/sshkit-1.15.1/lib/sshkit/backends/abstract.rb:29:in `run' C:/Ruby22/lib/ruby/gems/2.2.0/gems/sshkit-1.15.1/lib/sshkit/runners/parallel.rb:12:in `block (2 levels) in execute' Tasks: TOP => deploy:check => git:check The deploy has failed with an error: Exception while executing as deploy@myserver.com: git exit status: 128 git stdout: Nothing written git stderr: Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists. ** Invoke deploy:failed (first_time) ** Execute deploy:failed ** DEPLOY FAILED ** Refer to log/capistrano.log for details. Here are the last 20 lines: DEBUG [6b6ba2d0] Finished in 0.471 seconds with exit status 0 (successful). DEBUG [c6e2d7dc] Running ~/.rvm/bin/rvm 2.2.6 do ruby --version as deploy@myserver.com DEBUG [c6e2d7dc] Command: ~/.rvm/bin/rvm 2.2.6 do ruby --version DEBUG [c6e2d7dc] ruby 2.2.6p396 (2016-11-15 revision 56800) [x86_64-linux] DEBUG [c6e2d7dc] Finished in 0.608 seconds with exit status 0 (successful). INFO [fd5500a8] Running /usr/bin/env mkdir -p /tmp as deploy@myserver.com DEBUG [fd5500a8] Command: /usr/bin/env mkdir -p /tmp INFO [fd5500a8] Finished in 0.286 seconds with exit status 0 (successful). DEBUG Uploading /tmp/git-ssh-myapp-staging-localuser.sh 0.0% INFO Uploading /tmp/git-ssh-myapp-staging-localuser.sh 100.0% INFO [f33d4873] Running /usr/bin/env chmod 700 /tmp/git-ssh-myapp-staging-localuser.sh as deploy@myserver.com DEBUG [f33d4873] Command: /usr/bin/env chmod 700 /tmp/git-ssh-myapp-staging-localuser.sh INFO [f33d4873] Finished in 0.277 seconds with exit status 0 (successful). INFO [86d3cd5a] Running /usr/bin/env git ls-remote git@gitlab.com:MyApp/myapp.git HEAD as deploy@myserver.com DEBUG [86d3cd5a] Command: ( export GIT_ASKPASS="/bin/echo" GIT_SSH="/tmp/git-ssh-myapp-staging-localuser.sh" ; /usr/bin/env git ls-remote git@gitlab.com:MyApp/myapp.git HEAD ) DEBUG [86d3cd5a] Permission denied (publickey). DEBUG [86d3cd5a] fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists.
我尝试手动在本地和远程服务器上运行Capistrano尝试的命令,它们都成功。我真的很困惑,非常感谢任何帮助!
Capistrano部署失败的问题出现的原因是Git Bash没有在运行chmod 700 ~/.ssh
时将~/.ssh
目录的权限更改为0700。这导致在Capistrano部署时SSH代理转发无法正常工作,但在手动SSH登录到服务器时可以正常工作。为了解决这个问题,我决定尝试使用Bash on Ubuntu on Windows(BUW)而不是Git Bash,并且部署成功了!我将相同的配置和密钥从Git Bash复制到了BUW中。唯一的区别是我能够将BUW的~/.ssh
目录权限更改为0700。因此,以下是我的问题的解决方法:
1. 创建部署密钥并将其添加到GitLab
正如as、和M所指出的,我需要为GitLab创建一个部署密钥并在服务器上授权它。以下是我完成这个步骤的方法:
- 在本地机器上生成一个新的SSH密钥:
ssh-keygen -t rsa -b 4096
- 复制公钥的输出:
cat ~/.ssh/id_rsa.pub
- SSH登录到我的服务器
- 将公钥添加到
~/.ssh/authorized_keys
的末尾 - 回到本地机器,在浏览器中打开GitLab,进入我的仓库页面,在设置 > 仓库 > 部署密钥中粘贴公钥
2. 使用BUW代替Git Bash
- 在本地机器上,我按照这个Stack Overflow答案的指示设置BUW在会话加载时启动SSH代理。
- 更改
~/.ssh
的权限:chmod 700 ~/.ssh
- 启动SSH代理并将我的部署密钥添加到其中:
eval $(ssh-agent -s) ssh-add ~/.ssh/id_rsa
我从我的deploy.rb
文件中删除了set :ssh_options
行,因为没有它也可以正常工作。
就是这样!从现在开始,看来我将使用BUW进行部署。
根据cap deploy的输出,看起来从你的笔记本电脑到服务器的SSH连接不是问题所在。
这个问题是在capistrano尝试通过SSH运行git ls-remote git.com:MyApp/myapp.git HEAD时出现的。
你需要将公钥添加到GitLab中的SSH Keys,因为SSH代理转发需要在所有目标系统上安装公钥。在你的情况下,GitLab是一个目标系统。
cat ~/.ssh/id_rsa.pub # 复制公钥的内容(文件名可能不同)
登录到GitLab,并将公钥粘贴到你的存储库的SSH Keys中(在存储库设置中找到),然后应该没问题了。
你还需要在ssh_options中指定使用SSH密钥创建的用户。
set :ssh_options, {
forward_agent: true,
user: 'deploy',
}
感谢你的回答。使用SSH代理转发,如果我已经在我的本地环境中使用了密钥,那么一旦我SSH到服务器上,代理不应该对密钥有访问权限吗?我已经将公钥放在服务器上的authorized_keys文件中。
你本地环境和服务器之间的SSH连接不是问题所在。问题在于服务器和GitLab之间的连接。我已经更新了我的答案(请参见EDIT部分)。
当你部署到staging时,你是从哪里运行capistrano的?从你的本地工作站,还是从另一台服务器上运行?
我是从我的本地工作站上运行cap staging deploy的。
如果你以deploy用户身份登录到staging服务器并以deploy用户身份运行git ls-remote git.com:MyApp/myapp.git HEAD,是否成功?
是的,确实成功了。
你的staging服务器上是否正在运行ssh-agent?此外,你是否检查了staging服务器上sshd_config的输出,以确保允许AllowAgentForwarding?
是的,在我通过SSH登录后,它正在我的staging服务器上运行。我在我的sshd_config中设置了AllowAgentForwarding yes。
你是否将公钥添加到Gitlab中?SSH代理转发确实需要在所有目标系统上安装公钥。在这种情况下,Gitlab是一个目标系统。
问题原因:在部署过程中出现了“Permission denied (publickey)”错误,原因是缺少公钥或公钥未正确配置。
解决方法:
1. 在本地系统上检查是否存在“~/.ssh/id_rsa.pub”公钥文件,如果不存在,则创建一个新的:
$ ssh-keygen -t rsa
2. 将新创建的公钥“~/.ssh/id_rsa.pub”添加到仓库的部署(访问)密钥中:
- Bitbucket:按照以下链接中的步骤添加公钥:[https://confluence.atlassian.com/bitbucket/set-up-ssh-for-git-728138079.html#SetupSSHforGit-Step4.InstallthepublickeyonyourBitbucketaccount](https://confluence.atlassian.com/bitbucket/set-up-ssh-for-git-728138079.html#SetupSSHforGit-Step4.InstallthepublickeyonyourBitbucketaccount)
- Github:按照以下链接中的步骤添加公钥:[https://developer.github.com/v3/guides/managing-deploy-keys/#deploy-keys](https://developer.github.com/v3/guides/managing-deploy-keys/#deploy-keys)
- GitLab:按照以下链接中的步骤添加公钥:[https://docs.gitlab.com/ce/ssh/README.html#deploy-keys](https://docs.gitlab.com/ce/ssh/README.html#deploy-keys)
3. 将公钥加载到ssh-agent中:
- 检查ssh-agent是否正在运行,如果没有,请启动ssh agent:
$ ssh-agent /bin/bash
- 将“id_rsa”密钥添加到ssh agent:
$ ssh-add ~/.ssh/id_rsa
注意:如果在部署过程中出现“Access denied to the repository”错误,则有时需要在每次部署之前执行此步骤。
4. 将本地SSH密钥添加到部署服务器的Authorized Keys文件中(记得将端口号替换为自定义的端口号):
$ cat ~/.ssh/id_rsa.pub | ssh -p port_num user_ip 'cat >> ~/.ssh/authorized_keys'
5. 修改deploy.rb文件中的ssh_options配置:
set :ssh_options, { forward_agent: true, user: "deploy", auth_methods: ['publickey'], keys: %w(~/.ssh/privatekey.pem) }
将“~/.ssh/privatekey.pem”替换为SSH私钥文件的路径。
6. 运行部署命令:
$ cap staging deploy
将“staging”替换为所需的环境。
如果以上步骤仍然无法解决问题,可以尝试按照第二步中的链接中提供的更详细步骤进行操作,并确保正确添加公钥到仓库的部署(访问)密钥中。