Python中Django项目离线部署后如何优雅地更新
代码跑局域网内,没有外网~无法从 git 拉代码,除了删了然后复制有啥比较方便的操作?谢谢~
Python中Django项目离线部署后如何优雅地更新
把 git 也建在内网
离线部署Django项目后,优雅更新的核心是自动化和版本控制。我通常用Fabric或Ansible写个部署脚本,把整个流程固化下来。
这是我最常用的一个Fabric 2示例脚本,你可以保存为 fabfile.py:
# fabfile.py
from fabric import Connection, task
from pathlib import Path
# 你的服务器配置
PROJECT_NAME = "myproject"
REMOTE_HOST = "your-server-ip"
REMOTE_USER = "deploy"
CODE_DIR = f"/var/www/{PROJECT_NAME}"
VENV_PATH = f"{CODE_DIR}/venv"
@task
def deploy(c):
"""一键部署更新"""
print("=== 开始离线部署更新 ===")
# 1. 打包本地更新
local_archive = _create_archive()
# 2. 上传到服务器
_upload_archive(c, local_archive)
# 3. 执行远程更新
_remote_update(c, local_archive)
print("=== 更新完成 ===")
def _create_archive():
"""创建部署包,排除不需要的文件"""
import tarfile
import datetime
archive_name = f"deploy-{datetime.datetime.now().strftime('%Y%m%d-%H%M')}.tar.gz"
with tarfile.open(archive_name, "w:gz") as tar:
# 添加项目文件,按需调整exclude模式
tar.add(".",
arcname=PROJECT_NAME,
filter=lambda x: None if any(p in x.name for p in [
'.git', '__pycache__', '.env', '*.pyc', '*.log',
'node_modules', 'staticfiles'
]) else x)
print(f"创建部署包: {archive_name}")
return archive_name
def _upload_archive(c, archive_path):
"""上传部署包"""
print(f"上传 {archive_path} 到服务器...")
c.put(archive_path, f"/tmp/{archive_path}")
def _remote_update(c, archive_path):
"""执行远程更新操作"""
archive_name = Path(archive_path).name
with c.cd(CODE_DIR):
# 备份当前版本
print("备份当前版本...")
c.run(f"tar -czf /tmp/backup-{archive_name} .", warn=True)
# 解压新版本
print("解压新版本...")
c.run(f"tar -xzf /tmp/{archive_name} --strip-components=1")
# 激活虚拟环境执行更新命令
print("安装依赖...")
c.run(f"{VENV_PATH}/bin/pip install -r requirements.txt")
print("执行数据库迁移...")
c.run(f"{VENV_PATH}/bin/python manage.py migrate --noinput")
print("收集静态文件...")
c.run(f"{VENV_PATH}/bin/python manage.py collectstatic --noinput")
# 重启服务
print("重启服务...")
c.run("sudo systemctl restart gunicorn", warn=True)
c.run("sudo systemctl restart nginx", warn=True)
# 清理临时文件
c.run(f"rm /tmp/{archive_name}")
# 使用方式:
# 1. pip install fabric
# 2. 配置上面的常量
# 3. 运行: fab -H your-server deploy
关键点:
- 版本归档:每次更新都打时间戳包,便于回滚
- 原子操作:上传完整包再解压,避免更新中途出错
- 服务管理:用systemctl管理进程,确保服务重启
再配个简单的回滚脚本:
@task
def rollback(c, backup_file):
"""快速回滚到指定备份"""
with c.cd(CODE_DIR):
c.run(f"tar -xzf /tmp/{backup_file} --overwrite")
c.run(f"{VENV_PATH}/bin/python manage.py migrate")
c.run("sudo systemctl restart gunicorn")
实际部署时,你还需要:
- 在
requirements.txt中固定所有依赖版本 - 用
settings.py区分环境配置 - 数据库迁移要兼容旧版本
这样每次更新就是一行命令:fab -H 服务器IP deploy。所有操作可重复、可回滚,比手动SFTP覆盖靠谱多了。
总结:用自动化脚本固化部署流程。
emmm 要部署到多个地方
写成 sh
自己打成发行版支持的安装包格式,也可以参考一些跨发行版方案,比如 appimage 之类的。
打包 docker image 导来导去
我目前是这么干的。。sh 还是很爽的。一个打包一个安装
感谢,这个感觉很棒。我去研究下
snap 可能更适合,做好趟坑的准备吧。。
emm。。。看了下似乎都是很有趣。。但是有点麻烦的感觉。
我以前做过类似的项目,服务器和开发机都是在同一个局域网内。
直接在服务器上安装 Git 服务,然后初始化一个空的 git 远程仓库。
在开发机上把代码直接 push 到服务器远程仓库。
在远程仓库的写个 post-receive 钩子脚本,用来在 push 新代码后自动触发事件,自动更新代码和重启服务。
钩子脚本很简单
# =======================================
#!/bin/bash
# File_Name=post-receive
# git 用来 push 后部署代码到网站的钩子
# put this file under git-repo/project.git/hooks/ and chmod +x
webdir=’/webapps/djangosite’
gitdir=’/home/gitrepo/djangosite.git’
git --work-tree=$webdir --git-dir=$gitdir checkout -f
chmod +x $webdir/*.sh
$webdir/run.sh restart
# ========================================
run.sh 是重启服务的脚本。
推和拉的选择,很大程度上受限于网络通信


