如何使用 ansible 在远程机器上激活 python 虚拟环境?

How to activate python virtual environment on remote machine with ansible?

我正在学习 Vagrant 和 Ansible,我正在尝试使用 Nginx 在 ubuntu20.04 中为基本的 flask 应用程序设置本地开发环境。

我的 vagrantfile 看起来像这样:

Vagrant.configure("2") do |config|
  config.vm.define :ubuntuserver do | ubuntuserver |
    ubuntuserver.vm.box = "bento/ubuntu-20.04"
    ubuntuserver.vm.hostname = "ubuntuserver"
    ubuntuserver.vm.provision :ansible do | ansible |
      ansible.playbook = "development.yml"
    end
    ubuntuserver.vm.network "private_network", ip:"10.11.1.105"
    ubuntuserver.vm.network "forwarded_port", guest: 80, host: 8080
    ubuntuserver.vm.network "public_network", bridge: "en1: Wi-Fi (AirPort)"
    ubuntuserver.vm.provider :virtualbox do |vb|
      vb.memory = "1024"
    end
    ubuntuserver.vm.synced_folder "./shared", "/var/www"
  end
end

我的 ansible-playbook 是这样的:

-
  name: local env
  hosts: ubuntuserver
  tasks:
    - name: update and upgrade apt packages
      become: yes
      apt: 
        upgrade: yes
        update_cache: yes

    - name: install software properties common
      apt:
        name: software-properties-common
        state: present

    - name: install nginx
      become: yes
      apt:
        name: nginx
        state: present
        update_cache: yes

    - name: ufw allow http
      become: yes
      community.general.ufw:
        rule: allow
        name: "Nginx HTTP"
    
    - name: installing packages for python env
      become: yes
      apt:
        name: 
          - python3-pip
          - python3-dev
          - build-essential
          - libssl-dev
          - libffi-dev
          - python3-setuptools
          - python3-venv
        update_cache: yes
    
    - name: Create app directory if it does not exist
      ansible.builtin.file:
        path: /var/www/app
        state: directory
        mode: '0774'

    - name: Install virtualenv via pip
      become: yes
      pip:
        name: virtualenv
        executable: pip3

    - name: Set python virual env
      command:
        cmd: virtualenv /var/www/app/ -p python3
        creates: "/var/www/app/"

    - name: Install requirements
      pip:
        requirements: /var/www/requirements.txt
        virtualenv: /var/www/app/appenv
        virtualenv_python: python3

我的剧本在下一个任务中失败并出现错误:

- name: Activate /var/www/app/appenv
      become: yes
      command: source /var/www/app/appenv/bin/activate
fatal: [ubuntuserver]: FAILED! => {"changed": false, "cmd": "source /var/www/app/appenv/bin/activate", "msg": "[Errno 2] No such file or directory: b'source'", "rc": 2}

剧本的其余部分

   
    - name: ufw allow 5000
      become: yes
      community.general.ufw:
        rule: allow
        to_port: 5000
    
    - name: Run app
      command: python3 /var/www/app/appenv/app.py

根据我在 this 线程中的理解,必须从 vagrant 机器内部使用“source”命令。 (我尝试了线程中的解决方案但无法让它工作) 如果我 ssh 进入 vagrant 机器并手动执行我的剧本的最后三个命令:

source /var/www/app/appenv/bin/activate
sudo ufw allow 5000
python3 /var/www/app/appenv/app.py

我的基本 Flask 应用程序 运行 在 vagrantfile 10.11.1.105 中设置的 IP 端口 5000 上

我的问题是:

我怎样才能让 playbook 工作而不必通过 ssh 进入机器来完成同样的事情?

我的方法是否正确,知道我的最终目标是在 vagrant 机器中复制一个与生产环境类似的环境,并从 synced folder 中的本地机器开发 flask 应用程序?

提供最多的信息,如果有人想重现这个。 我还有一个 shared/app/appenv/app.py 文件,其中包含基本的烧瓶应用程序

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "<h1 style='color:blue'>Hello There!</h1>"

if __name__ == "__main__":
    app.run(host='0.0.0.0')

和shared/requirements.txt文件

wheel
uwsgi
flask

我为 Linux 台 Python 3.x 的计算机写了这篇文章。在这种情况下,这是您的 Ansible 开发机器。首先,验证安装的 Python 版本和路径:

# check Python version
$ python3 -V
Python 3.6.8

$ which python3
/usr/bin/python3

我建议为虚拟环境设置一个目录:

$ mkdir python-venv
$ cd !$

创建新的虚拟环境

$ python3 -m venv ansible2.9
$ ls
ansible2.9

激活python venv

$ source ansible2.9/bin/activate
(ansible2.9)$ python3 -V
Python 3.6.8

升级点数

(ansible2.9)$ python3 -m pip install --upgrade pip

在虚拟环境中安装Ansible

(ansible2.9)$ python3 -m pip install ansible==2.9
(ansible2.9)$ which ansible
~/python-venv/ansible2.9/bin/ansible

验证您的新安装:

 (ansible2.9)$ ansible --version
    ansible 2.9.0
      config file = /etc/ansible/ansible.cfg
      configured module search path = ['/home/devops/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/devops/python-venv/ansible2.9/lib64/python3.6/site-packages/ansible
  executable location = /home/devops/python-venv/ansible2.9/bin/ansible
  python version = 3.6.8 (default, Jan 09 2021, 10:57:11) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)]

安装 Ansible 角色或集合

(ansible2.9)$ ansible-galaxy collection install \
  kubernetes.core:==1.2.1 -p collections

停用 Python 虚拟环境

(ansible2.9)$ deactivate

为 Ansible 3.0

创建另一个 Python 虚拟环境
$ python3 -m venv ansible3.0
$ ls -1
ansible2.9
ansible3.0
$ source ansible3.0/bin/activate
(ansible3.0)$ which python
~/python-venv/ansible3.0/bin/python
(ansible3.0)$ python3 -m pip install --upgrade pip
(ansible3.0)$ python3 -m pip install ansible==3.0

这个问题来自对 python venv 的误解。 我认为为了在虚拟环境中安装软件包,它必须被激活。 例如:

source env/bin/activate
pip install package_name

后来我明白了我可以在 venv 中安装软件包而不激活它:

env/bin/pip install package_name

所以ansible的解决方案不是激活venv来安装包,而是

- name: "Install python packages with the local instance of pip"
   shell: "{{virtualenv_path}}/bin/pip3 install package_name"
   become: no

甚至使用 pip 模块和 requirements.txt 文件中的包更好:

- name: Install project requirements in venv
  pip:
    requirements: '{{project_path}}/requirements.txt'
    virtualenv: '{{virtualenv_path}}'
    virtualenv_python: python3