Python中Django项目离线部署后如何优雅地更新

代码跑局域网内,没有外网~无法从 git 拉代码,除了删了然后复制有啥比较方便的操作?谢谢~


Python中Django项目离线部署后如何优雅地更新
14 回复

把 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

关键点:

  1. 版本归档:每次更新都打时间戳包,便于回滚
  2. 原子操作:上传完整包再解压,避免更新中途出错
  3. 服务管理:用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 还是很爽的。一个打包一个安装

感谢,这个感觉很棒。我去研究下

这个是最佳备选方案。。表示有些机子都不给装 docker

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 是重启服务的脚本。

推和拉的选择,很大程度上受限于网络通信

回到顶部