You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ansible中用include_vars加载YAML变量作环境变量失败排查

问题排查:Ansible加载环境变量到django_manage任务失败

操作步骤与初始问题

我尝试在Ansible剧本中从YAML文件加载变量,作为后续任务的环境变量,操作步骤如下:

  1. 以YAML格式模板化主机变量
- name: builtin | template | template host variables file
  ansible.builtin.template:
    src: templates/django/hostvars.j2
    dest: "host_vars/{{ inventory_hostname_short }}.yml"
    mode: 0640
    output_encoding: "utf-8"
  delegate_to: localhost

生成的文件内容示例:

--
# Host variables to be set as environment variables in tasks that need it
POSTGRES_PASSWORD: "<password>"
POSTGRES_USER: "dbuser"
POSTGRES_DB: "dbname"
POSTGRES_HOST: "dbhost"
POSTGRES_PORT: 5432
POSTGRES_SSLMODE: "verify-full"
POSTGRES_SSLCA: "/etc/ssl/certs/ISRG_Root_X1.pem"
POSTGRES_APPNAME: "myproject"
DJANGO_SITE_NAME: "mysite"
DJANGO_SITE_PASSWORD: "mypassword"
DJANGO_SITE_USER: "myuser"
DJANGO_SITE_ID: 2
DJANGO_SECRET_KEY: "<very-long-and-random-secret>"
[...]
  1. 使用include_vars将变量加载到剧本中
- name: builtin | include_vars | load host vars
  ansible.builtin.include_vars:
    file: "host_vars/{{ inventory_hostname_short }}.yml"
    name: envvars
  1. 验证变量已加载
- name: builtin | debug | print variable 'envvars'
  ansible.builtin.debug:
    var: envvars

调试结果显示变量已成功加载,输出示例:

TASK [builtin | debug | print variable 'envvars'] ***************************************************************
ok: [django1.mydomain.com] => {
    "envvars": {
        "DJANGO_DEBUG": 0,
        "DJANGO_LOGS_DIR": "/opt/django/logs",
        "DJANGO_MEDIA_BASE": "/opt/django/media",
        "DJANGO_SECRET_KEY": "<very-long-and-random-secret>",
        [...]
  1. 使用django_manage更新数据库schema
- name: community.general | django_manage | update database schema
  community.general.django_manage:
    command: migrate
    settings: myproject.settings
    project_path: "/opt/django/src"
    virtualenv: "/opt/django/venv"
  become: true
  become_user: django
  become_method: su
  environment: "{{ envvars }}"

但该任务失败,Django提示找不到SECRET_KEY环境变量(本应基于DJANGO_SECRET_KEY生成)。此外,执行env命令的任务未输出任何内容:

- name: print environment variables
  ansible.builtin.command: env
  become: true
  become_user: django
  become_method: su
  environment: "{{ envvars }}"

编辑后的测试与新报错

修改任务列表后:

- name: builtin | shell | capture DJANGO_ environment variables
  debugger: on_failed
  ansible.builtin.shell:
    cmd: "env | grep DJANGO_"
  register: out
  environment: "{{ envvars }}"
  become: true
  become_user: django
  become_method: su

- name: builtin | debug | print content of out.stdout
  ansible.builtin.debug:
    var: out.stdout

- name: builtin | debug | print variable 'envvars'
  ansible.builtin.debug:
    var: envvars

- name: community.general | django_manage | populate the static subdirectory
  community.general.django_manage:
    command: collectstatic
    clear: yes
    project_path: "/opt/django/src"
    virtualenv: "/opt/django/venv"
  become: true
  become_user: django
  become_method: su
  environment: "{{ envvars }}"

此时shell任务能正确获取到DJANGO_开头的环境变量,debug也能输出envvars的内容,但django_manage的collectstatic任务仍失败,报错核心信息:

ModuleNotFoundError: No module named 'None'

完整报错回溯:

TASK [community.general | django_manage | populate the static subdirectory] ************************************************************************************************
fatal: [django1.domain.com]: FAILED! => {"changed": false, "cmd": ["./manage.py", "collectstatic", "--noinput", "--clear"], "msg": "
:stderr: Traceback (most recent call last):
  File "/opt/django/venv/lib/python3.9/site-packages/django/core/management/__init__.py", line 204, in fetch_command
    app_name = commands[subcommand]
KeyError: 'collectstatic'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/django/src/./manage.py", line 22, in <module>
    execute_from_command_line(sys.argv)
  File "/opt/django/venv/lib/python3.9/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
    utility.execute()
  File "/opt/django/venv/lib/python3.9/site-packages/django/core/management/__init__.py", line 375, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/opt/django/venv/lib/python3.9/site-packages/django/core/management/__init__.py", line 211, in fetch_command
    settings.INSTALLED_APPS
  File "/opt/django/venv/lib/python3.9/site-packages/django/conf/__init__.py", line 57, in __getattr__
    self._setup(name)
  File "/opt/django/venv/lib/python3.9/site-packages/django/conf/__init__.py", line 44, in _setup
    self._wrapped = Settings(settings_module)
  File "/opt/django/venv/lib/python3.9/site-packages/django/conf/__init__.py", line 107, in __init__
    mod = importlib.import_module(self.SETTINGS_MODULE)
  File "/usr/lib/python3.9/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 790, in exec_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "/opt/django/src/black_pearl/settings/production.py", line 3, in <module>
    from black_pearl.settings.common import *
  File "/opt/django/src/black_pearl/settings/common.py", line 301, in <module>
    path_app = import_module(app).__path__
  File "/usr/lib/python3.9/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
ModuleNotFoundError: No module named 'None'
", "path": "/opt/django/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "syspath": ["/tmp/ansible_community.general.django_manage_payload_l53eeo4g/ansible_community.general.django_manage_payload.zip", "/usr/lib/python39.zip", "/usr/lib/python3.9", "/usr/lib/python3.9/lib-dynload", "/usr/local/lib/python3.9/dist-packages", "/usr/lib/python3/dist-packages"]}

问题分析与解决步骤

核心问题定位

报错的根源是common.py第301行尝试导入名为None的模块,说明代码中某个app变量的值被设置为None,而这个变量大概率是从环境变量中读取的。

具体排查与修复

  1. 检查生成的YAML变量文件
    打开host_vars/{{ inventory_hostname_short }}.yml,确认是否有变量值为None(而非空字符串),比如类似DJANGO_EXTRA_APPS: None的条目。Ansible会将YAML中的None解析为Python的None类型,传递给环境变量时会被转为字符串"None",导致Django代码尝试导入这个不存在的模块。

  2. 统一django_manage任务的settings参数
    之前的migrate任务指定了settings: myproject.settings,但collectstatic任务未指定,可能导致加载了不同的配置文件(比如默认的production.py)。给collectstatic任务加上相同的settings参数:

    - name: community.general | django_manage | populate the static subdirectory
      community.general.django_manage:
        command: collectstatic
        clear: yes
        project_path: "/opt/django/src"
        virtualenv: "/opt/django/venv"
        settings: myproject.settings  # 新增该行
      become: true
      become_user: django
      become_method: su
      environment: "{{ envvars }}"
    
  3. 修复Django配置中的环境变量处理逻辑
    查看common.py第301行的代码,确认app变量的来源。如果是从环境变量读取后直接拆分,需要处理空值情况:

    # 错误示例:未处理空环境变量
    extra_apps = os.getenv('DJANGO_EXTRA_APPS')
    for app in extra_apps.split(','):
        path_app = import_module(app).__path__
    

    修改为:

    # 正确处理:给默认空字符串,过滤空条目
    extra_apps = os.getenv('DJANGO_EXTRA_APPS', '').split(',')
    for app in extra_apps:
        app = app.strip()
        if app:  # 仅导入非空的app名称
            path_app = import_module(app).__path__
    
  4. 验证环境变量的完整性
    在django_manage任务前添加debug任务,打印envvars的所有键值对,确认没有异常值:

    - name: builtin | debug | print full envvars details
      ansible.builtin.debug:
        var: envvars
        verbosity: 2
    

内容的提问来源于stack exchange,提问作者Jaume Sabater

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 22:30:49