我有一个Django / Gunicorn / Nginx网站,我使用Ansible playbook构建。我目前正在我的playbook中标记那些需要在我添加新功能或修复bug并想重新加载我的Django代码时运行的任务。我的目标是,只要我在登台服务器上测试它们,就可以将任何此类更改推送到生产中,而无需关闭我的生产服务器。
我的Playbook目前已设置好,每当我想将更改推送到生产时,它将删除整个网站目录并重建Pip虚拟环境,以便没有剩余的“残缺”。问题是,当我运行Ansible playbook时,我在删除网站目录时会出现一个短暂的500服务器错误。然后,只要从Github检出代码的下一个任务运行,错误就会消失。显然,每当我重新加载我的代码库时,如果任何用户在该任务运行的时刻访问我的网站,他们也会得到这500个错误。我一直在想,一旦Gunicorn启动并且我的Django代码被加载到内存中,我可以删除并重新加载我的代码并重新启动Gunicorn而不会中断服务。其他Stackover question似乎应该是这种情况。但是,我的测试表明不是这样。
当客户端浏览器向Django发送请求时,Django会将所有.pyc文件重新加载到内存中吗?这是什么导致了这个问题?当我重新加载我的Django代码而不删除删除旧代码的任务时,有没有办法防止这种短暂的中断?
以下是我的Ansible剧本的摘录:
- name: configure web server
hosts: webservers
gather_facts: True
tasks:
# This task causes momentary 500 server error
- name: delete any existing project repo
file: >
path={{ repo_path }}
state=absent
tags: reload
- name: check out {{ repo_version }} of Github repo
git: >
repo={{ repo_url }}
version={{ repo_version }}
dest={{ repo_path }}
accept_hostkey=yes
register: checkout
until: checkout|success
retries: 5
delay: 10
become: true
become_user: "{{ me }}"
tags: reload
# ... more tasks
- name: install python packages into virtual environment
pip: >
requirements={{ repo_path }}/requirements/{{ server_tier }}.txt
state=present
virtualenv={{ venvs_path }}/{{ commit_hash }}
tags: reload
# ... more tasks
- name: reload gunicorn
command: pkill -HUP gunicorn
become: true
become_user: root
tags: reload
答案 0 :(得分:0)
解决方案:将django根目录设为symb链接。
让我详细解释一下我的解决方案。确保您的代码根是指向为流量提供服务的实际代码版本的符号链接。在部署期间,您的ansible脚本将基本上创建一个新的virtualenv,并安装需求。并在新目录中提取代码,该目录应在名称中包含当前时间戳。而你做任何你需要做的事情都可以为交通服务做好准备。然后在最后一步中,您将开始将django根目录链接指向新位置。
/home/ubuntu/project/current -> /home/ubuntu/project/releases/145678/
/home/ubuntu/project/releases/123456/
/home/ubuntu/project/releases/134567/
/home/ubuntu/project/releases/145678/
在上面的目录结构中,您可以将当前点指向其中一个版本。对于每个新部署,您都可以创建新版本,然后将当前指向新版本目录。
在此之后,您可以重新启动gunicorn以刷新新代码库中的设置。
您可以使用cron作业从计算机中删除非常旧的版本。
如果您需要更多说明,请与我们联系。