使用Paramiko SSH设置virtualenv

9

我对Python和Django在Windows上有一些有限的经验,现在我正在尝试了解如何将我的代码部署到Ubuntu 16.04 LTS VPS。在阅读了各种教程和大量SE上的答案后,我已经取得了相当大的进展(对于我来说),但现在我陷入了困境。

通过Putty手动操作,我可以执行以下操作:

# check that Python 3.5 is installed
python3 --version  
# install pip
sudo -kS apt-get -y install python3-pip  
# upgrade pip to newest version
pip3 install --upgrade pip
# check result
pip3 --version  
# install venv
sudo -kS pip3 install virtualenv virtualenvwrapper 
# create venv
virtualenv ~/Env/firstsite  
# make sure venv is created 
ls -l ~/Env/firstsite/bin/python  # /home/droplet/Env/firstsite/bin/python3.5 -> python3
# switch on venv
source ~/Env/firstsite/bin/activate  # (firstsite) droplet@hostname:~$
# check that python3 is taken from venv
which python3  # /home/droplet/Env/firstsite/bin/python3

虚拟环境已经创建并启动,我可以继续安装Django。

但是当我尝试使用Paramiko在自动化模式下执行相同的操作时(我使用paramiko.SSHClient().exec_command(cmd, input_string, get_pty=False执行命令),一切都进行得完美,直到最后一个命令:

exec_command('which python3')

返回结果为/usr/bin/python3。因此,我假设通过Paramiko的SSH无法使用source activate

  1. 为什么?
  2. 我该如何应对?
  3. 有没有更直接(且可靠)的方式检查虚拟环境是否已启用?
3个回答

2
如果您正在使用Anaconda并通过此方式创建虚拟环境,我找到了一个解决方法。从[此github页面][1]中获取,我通过paramiko将以下命令发送到我的远程计算机:
f'source ~/anaconda3/etc/profile.d/conda.sh && conda activate {my_env} && {command}'
我希望您只需激活venv,然后所有后续命令都在venv中,但这种解决方法很好,因为我唯一需要更改的是venv名称。由于所有内容都在一行中,它可以完美执行,我不需要重新激活任何内容。如果您只是在Python中编写包装函数,那么使用和阅读都非常简单。例如:
def venv_wrapper(command, ssh, venv=None):
    if venv:
        conda_location = 'source ~/anaconda3/etc/profile.d/conda.sh'
        activate_env = f'conda activate {venv}'
        command = f'{conda_location} && {activate_env} && {command}'
    ssh.exec_command(command, get_pty=True)

我只需通过这段代码(在我的工具包中稍微更加完善和复杂)发送所有命令,无论是否使用虚拟环境。目前运行得相当顺利。

[1]: https://github.com/conda/conda/issues/7980

这在miniconda上也很好用!! - undefined

2
我们可以轻松激活虚拟环境并在其中执行命令。
例如:
import paramiko

hostname = 'host'
port = 22
username = 'root'
password = 'root'
s = paramiko.SSHClient()
s.load_system_host_keys()
s.set_missing_host_key_policy(paramiko.AutoAddPolicy())
s.connect(hostname, port, username, password)
command = 'source /root/Envs/env/bin/activate;python3 --version;qark;echo hello'
(stdin, stdout, stderr) = s.exec_command(command)
for line in stdout.readlines():
    print(line)
for line in stderr.readlines():
    print(line)
s.close()

我不同意“轻松激活”是可能的,因为仅仅在每个内部命令前加上 source <venv_path>/bin/activate; <cmd> 的可能性并不容易。如果可以执行 source ... 命令一次,然后通过 paramiko 输入的每个命令都在虚拟环境中键入,那对我来说就是理想的。但这似乎是不可能的。 :( - WhyWhat

1

以下内容来自@Pablo Navarro在此处的回答:如何在Bash脚本中获取virtualenv激活,这个回答帮助了我解决了同样的问题(在paramiko ssh会话中激活环境)。

在exec_command中提供环境内Python可执行文件的路径,例如:

stdin, stdout, stderr = ssh.exec_command(/path/to/env/bin/python script.py)

在我的情况下(使用miniconda和名为pyODBC的环境):
stdin, stdout, stderr = ssh.exec_command(~/miniconda2/envs/pyODBC/bin/python run_script.py)

运行命令~/miniconda2/envs/pyODBC/bin/python -m pip list会打印出此环境中的模块列表以进行确认。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接