ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Python程序员必备Linux命令:从开发到部署的实战指南

Python程序员必备Linux命令:从开发到部署的实战指南 1. 为什么Python程序员绕不开Linux先聊个真实的场景。我见过不少Python开发者在Windows上写代码写得飞起一到部署就抓瞎。本地跑得好好的Django项目传到服务器上不是缺依赖就是路径不对折腾一晚上还是没跑起来。说句不客气的话问题多半出在你不熟悉Linux。Python这门语言有一个特点——它的生态和Linux深度绑定。从包管理到进程管理从日志查看到定时任务生产环境里几乎清一色是Linux。哪怕你用的是Docker底层跑的也是Linux内核。你本地用的Windows只是开发环境真正的战场在Linux上。所以很多团队招Python后端工程师的时候都会带上一条熟悉Linux常用命令。这不是门槛是基本功。说白了Linux命令对你的意义不是会不会敲而是能不能在遇到问题的时候第一时间找到关键线索。这篇文章不是让你背命令手册而是从一个Python开发者的实际角度把日常开发、调试、部署、排错过程中真正用得上的命令和思路梳理一遍。文中的命令我都按什么场景下用、为什么这么用、有没有坑来写照着敲就能用。2. 环境隔离虚拟环境与Python版本管理2.1 venvPython项目的第一道隔离墙Python项目最头疼的问题之一就是依赖冲突。项目A要用Django 3.2项目B要升到Django 5.0如果你只有一个全局Python环境早晚要出事。虚拟环境就是干这个的。创建虚拟环境的标准姿势# 进入你的项目目录 cd ~/projects/myblog # 创建虚拟环境名字叫 venv也有人用 .venv看团队习惯 python3 -m venv venv # 激活虚拟环境 source venv/bin/activate激活之后你会注意到命令行前面多了个(venv)前缀这就说明当前shell环境已经切换到这个项目专属的Python环境里了。之后再敲pip install装的包只会出现在这个虚拟环境里不会污染全局。退出虚拟环境用deactivate有一个细节很多新手会忽略激活虚拟环境之后命令行里的python和pip指的都是venv/bin/下的软链接不再是系统的/usr/bin/python3。你可以用which python查看路径确认一下which python # 输出类似~/projects/myblog/venv/bin/python2.2 用requirements.txt锁定依赖虚拟环境搭配requirements.txt是Python项目的标配。生成依赖清单# 导出当前环境的所有依赖及精确版本号 pip freeze requirements.txt在另一台机器上还原环境pip install -r requirements.txt实际工作中我强烈建议你区别对待requirements.txt和requirements-dev.txt。前者只放生产环境需要的依赖Django、gunicorn、redis这些后者额外放开发工具pytest、black、flake8。否则部署的时候会装一堆没用的包浪费时间和磁盘空间。2.3 pyenv管理多个Python版本有时候你手上不止一个项目有的用Python 3.8有的用Python 3.12。光靠系统自带的Python版本是没法满足的。这时候用pyenv。安装pyenv的步骤这里不展开装好之后核心命令很好记# 查看可安装的Python版本 pyenv install --list # 安装指定版本 pyenv install 3.10.14 # 设置当前目录使用的Python版本会在目录下生成 .python-version 文件 pyenv local 3.10.14 # 查看当前使用的版本 pyenv versionspyenv的原理不复杂它把不同版本的Python编译后装到~/.pyenv/versions/目录下再通过PATH环境变量的顺序切换让当前shell优先使用指定版本的Python。相当于给用哪个Python解释器加了一层代理。我自己的习惯是系统Python永远不动全局用pyenv指定一个稳定版本每个项目再用venv隔离依赖三层互不干扰。这套组合拳在本地开发和服务器部署上都适用。3. 日志、文件和文本处理Python程序员的日常操作3.1 查看日志的姿势比你想的重要程序跑起来之后第一件事就是看日志。日志就是程序的体检报告哪行代码出了什么问题、请求耗时多少、有没有报错都在里面。最基础的查看命令# 查看日志文件完整内容 cat app.log # 分页查看适合大文件 less app.log # 只看最后200行部署后最常用 tail -n 200 app.log # 实时跟踪日志输出CtrlC退出 tail -f app.log部署场景里我90%的时候都在用tail -f。比如你用gunicorn跑Django服务启动之后窗口上刷的日志就是标准输出但如果你用nohup或systemd把服务放后台跑日志就落到了文件里。这时候tail -f就能实时看到请求进来了、有没有报500。3.2 日志检索grep才是主角日志文件几十MB甚至上百MB的时候用cat或less翻页完全没有效率。正确做法是用grep检索关键字# 查找所有包含 Traceback 的行 grep Traceback app.log # 查找ERROR级别的日志并显示行号 grep -n ERROR app.log # 不区分大小写且显示匹配行的前后各5行 grep -i -n -C 5 timeout app.log-C 5这个参数特别有用。报错信息往往不在一行里比如Python的异常堆栈Traceback (most recent call last)在顶部真正的原因可能隔了十几行。用-C把上下文带出来才能看清前因后果。如果你要在大量日志里统计某个关键字出现的次数grep -c ERROR app.log # 或者忽略大小写 grep -ci error app.log3.3 用awk和sed做轻量级数据处理Python程序员可能觉得处理文本我直接用Python不就行了当然可以但在Linux命令行环境下awk和sed有时候更顺手尤其是快速看一眼数据时没必要为了一个小需求单独写脚本。awk的核心逻辑是按列处理。日志里最常见的格式是空格或逗号分隔的字段。比如一条Nginx日志127.0.0.1 - - [10/Oct/2024:13:55:36 0800] GET /api/users HTTP/1.1 200 1024我想只看IP、请求路径和状态码awk {print $1, $7, $9} access.logawk默认按空格切分$1是IP$7是请求路径$9是状态码。就这么简单。sed的核心逻辑是按行替换最常用的场景是批量替换配置或数据里的内容# 把 import 后面的 requests 改成 httpx忽略大小写 sed -i s/requests/httpx/g requirements.txt # 只打印第10到20行 sed -n 10,20p app.log3.4 查找文件find和locate项目文件越堆越多经常忘了某个配置文件放哪了。这时候# 在当前目录下递归查找所有 .py 文件 find . -name *.py # 按文件名查找并排除venv目录 find . -name settings.py -not -path ./venv/* # 查找最近10分钟内修改过的文件 find . -mmin -10 # 按文件大小查找大于50MB的文件 find . -size 50Mfind和grep还经常组合在一起用比如查找所有包含requests的Python文件grep -rl requests --include*.py .-r是递归-l是只列出文件名。另外locate命令用数据库索引查文件名速度比find快一个数量级。缺点是索引不是实时的新文件可能查不到需要先执行updatedb更新索引。3.5 磁盘和文件大小排查日志文件过多会把磁盘塞满这是服务器上最常见的故障之一。排查思路# 查看磁盘整体使用情况 df -h # 查看当前目录下各个子目录和文件的占用大小 du -sh * # 按大小排序找到最大的目录 du -sh * | sort -rh | head -n 10df -h看的是挂载点的空间du -sh *看的是实际文件占用。组合使用能快速定位磁盘满的元凶。我遇到过几次生产事故最后都是查du -sh *发现是日志文件没做轮转一直长到几十GB。4. Python项目部署里的关键环节4.1 用systemd管理Python服务开发环境下你可能习惯python manage.py runserver但生产环境这么跑等于裸奔——终端一关服务就没了。正确的做法是把服务交给systemd管理开机自启、崩溃自动重启、日志统一收集。先创建一个service文件sudo vim /etc/systemd/system/myblog.service内容大致长这样[Unit] DescriptionMy Django Blog Afternetwork.target [Service] Userdeploy Groupdeploy WorkingDirectory/home/deploy/projects/myblog ExecStart/home/deploy/projects/myblog/venv/bin/gunicorn config.wsgi:application -b 127.0.0.1:8000 --workers 3 Restartalways RestartSec3 [Install] WantedBymulti-user.target注意ExecStart里我写的是venv/bin/gunicorn而不是全局的gunicorn。这一步非常关键因为在venv里安装的gunicorn只有venv自己知道不写绝对路径的话systemd是在系统环境里找命令大概率会报404找不到。写完配置之后的操作# 重新加载systemd配置 sudo systemctl daemon-reload # 启动服务 sudo systemctl start myblog # 设置开机自启 sudo systemctl enable myblog # 查看服务状态 sudo systemctl status myblog # 实时查看服务日志 sudo journalctl -u myblog -fjournalctl这个命令建议你刻意多用几次它会把你服务的标准输出和标准错误统一收集起来。以后排查问题的时候不需要登录到服务器上一个文件一个文件找直接一条命令全看。4.2 后台运行与持久化日志有些临时脚本不想用systemd托管比如一个跑数据采集的任务你想让它安安静静在后台跑关掉终端也不中断。这时候用nohupnohup python3 spider.py spider.log 21 拆开看是什么意思nohup忽略挂断信号终端关闭进程不退出把标准输出写到 spider.log21把标准错误也写到同一个文件这步千万别省不然报错你看不到最后的是让进程进入后台之后想看任务跑得怎么样# 查看进程是否存活 ps aux | grep spider.py # 看日志尾部 tail -f spider.log # 杀掉进程 kill PID4.3 定时任务crontab数据清洗、报表统计、定时备份这些重复性工作交给crontab最合适。# 编辑当前用户的定时任务 crontab -e一行一个任务格式是分 时 日 月 周 命令。想每天凌晨2点执行一次备份脚本0 2 * * * /home/deploy/projects/backup.sh /home/deploy/backup.log 21这里又一个常见坑cron环境下的PATH和你在终端里看到的不一样基本是最小环境。所以脚本里尽量写命令的绝对路径或者干脆在脚本开头先source ~/.bashrc。不然你会发现手动执行好好的脚本进了cron就报command not found。定时任务的日志一般放在系统日志里# 查看当前用户的cron执行日志 grep CRON /var/log/syslog4.4 端口占用与进程排查服务起不来第一反应不是看代码而是看端口有没有被占。比如8000端口被别的进程占了# 查看谁占用了8000端口新版Linux用ss更方便 ss -tlnp | grep 8000 # 老一点的系统也可以用netstat netstat -tlnp | grep 8000-t是tcp-l是监听状态-n不显示域名直接显示IP-p显示进程名和PID。看到PID之后直接# 杀掉占用端口的进程 kill -9 PID查进程本身# 查看所有Python进程 ps aux | grep python # 只看进程树理清父子关系 pstree -ppstree这个命令在排查进程怎么又多了几个或者谁启动了谁的时候非常直观。比如你用gunicorn起了3个workerpstree能清晰地看到master进程下面挂着3个child进程。4.5 系统资源查看top和free线上服务变慢先看两类资源CPU和内存。# 动态查看系统进程资源占用按CPU排序 top # 按内存排序 top -o %MEM # 实时刷新时按M键也能切换成按内存排序内存方面# 查看内存使用情况 free -hfree -h里有几个指标要注意available才是真正可用的内存不是free列。因为Linux会用空闲内存做文件缓存buff/cache这部分在需要时是可以释放的。你要是拿free列来判断内存够不够很容易误判成内存不足。Python项目常见的内存问题有两个一是进程积压太多请求没释放二是某个长驻进程慢慢涨。这时候用top观察RES列的变化看哪个进程内存持续上涨再结合日志定位代码位置。5. 远程连接与文件传输从本地开发到服务器部署5.1 SSH远程开发的地基到服务器上操作最常用的工具就是SSH。# 连接服务器 ssh deployyour_server_ip # 指定端口连接 ssh -p 2222 deployyour_server_ip # 执行单条命令不进入交互界面 ssh deployyour_server_ip df -hSSH的认证方式生产环境强烈建议用密钥而不是密码。生成密钥对ssh-keygen -t rsa -b 4096生成的公钥在~/.ssh/id_rsa.pub私钥在~/.ssh/id_rsa。把公钥内容追加到服务器上~/.ssh/authorized_keys文件里之后登录就不用输密码了。更省事的方式是用ssh-copy-id直接把公钥推过去ssh-copy-id deployyour_server_ip5.2 scp与rsync文件怎么传到服务器本地文件传到服务器最简单的是scp# 上传本地文件到服务器 scp local_file.py deployyour_server_ip:/home/deploy/ # 上传整个目录加 -r scp -r ./myblog deployyour_server_ip:/home/deploy/ # 从服务器下载文件到本地 scp deployyour_server_ip:/home/deploy/app.log ./scp够用但如果你经常同步代码目录推荐rsync它的增量同步比scp全量复制高效得多# 同步代码目录到服务器排除venv和缓存文件 rsync -avz --exclude venv --exclude __pycache__ ./myblog/ deployyour_server_ip:/home/deploy/myblog/-a是归档模式保文件属性-v是显示过程-z是压缩传输局域网或带宽有限时效果明显。--exclude可以忽略不需要同步的目录比如venv、.git、pycache、.log文件。rsync 还有一点对开发者特别实用如果本地和服务器文件一模一样它会直接跳过不会白白占带宽。本地改了几个文件就只传那几个省时省力。5.3 tmux远程会话不断线SSH登录到服务器干活最怕的是网络一抖会话断开正在跑的任务也没了。tmux就是一个会话保持工具让你的任务在远程终端关闭之后继续跑。# 新建一个会话 tmux new -s work # 脱离会话回到普通shell任务继续在后台跑 Ctrlb 然后按 d # 查看所有会话 tmux ls # 重新接入之前的会话 tmux attach -t work整个流程就是SSH登录服务器tmux new -s deploy在里面跑部署、跑脚本然后Ctrlb d断开。回家关电脑第二天登录服务器tmux attach -t deploy任务还在那儿等你。我部署Django项目、跑数据迁移这类耗时操作几乎都在tmux里做。哪怕服务器SSH断了也不慌重新连上再接回去就行。5.4 快速排查网络问题部署完之后服务没起来或者访问不了按这个顺序排查# 1. 先看端口有没有监听 ss -tlnp | grep 8000 # 2. 本机访问试试 curl -I http://127.0.0.1:8000 # 3. 看对外IP和网关 ip addr ip route # 4. 测试外网访问是否通 ping -c 4 8.8.8.8curl是检验HTTP服务最方便的工具curl -I只看响应头curl -v显示详细交互过程。后端接口返回500还是404用curl一眼就能看出来。6. 基础但高频的命令文件操作与权限6.1 文件目录的基本操作# 查看当前目录 pwd # 列出文件-l 详细信息-a 含隐藏文件-h 人类可读大小 ls -lah # 创建目录-p 递归创建 mkdir -p data/logs # 复制文件-r 复制目录 cp -r project_backup project_new # 移动或重命名 mv old_name.py new_name.py # 删除文件-rf 递归强制删除目录慎用 rm -rf temp_dirrm -rf是Linux里最容易出事故的命令没有之一。我的经验是删除重要东西之前先ls确认路径或者在命令里用绝对路径再核对一遍。尤其不要随手在rm -rf后面加空格和*手一抖整个目录就没了。6.2 权限管理chmod和chownPython项目部署到服务器后经常遇到权限不够或者不能执行的问题。权限的基础知识是每个文件有三组权限分别针对所有者、所属组、其他人。每组权限用字母或数字表示rwx对应4、2、1。# 给脚本添加执行权限 chmod x run.sh # 设置所有者读、写、执行(7)组读执行(5)其他人读执行(5) chmod 755 run.sh # 修改文件所有者为deploy用户 sudo chown deploy:deploy app.log一个常见的场景你从本地rsync文件到服务器所有者是root结果部署用户是deploy程序启动时没权限写日志文件报PermissionError。解决办法就是chown把目录归属改过来sudo chown -R deploy:deploy /home/deploy/myblog/6.3 环境变量让程序能找到配置Python程序里经常需要读取环境变量比如数据库密码、SECRET_KEY。在Linux下设置环境变量# 当前会话临时生效 export DATABASE_URLpostgres://user:passlocalhost/dbname python3 app.py # 永久生效把export写入 ~/.bashrc 或 ~/.profile echo export DATABASE_URLpostgres://user:passlocalhost/dbname ~/.bashrc source ~/.bashrc # 查看某个环境变量 echo $DATABASE_URL在systemd的service文件里也可以用Environment字段配置环境变量。这个比往.bashrc里写更干净服务级别的配置就应该跟服务走。7. 一些能直接提升效率的命令组合7.1 alias把长命令变成快捷键有些命令组合你每天都在敲完全可以收进~/.bashrc里alias activatesource venv/bin/activate alias gsgit status alias gdgit diff alias glgit log --oneline --graph --decorate -n 20 alias llls -lah改完source ~/.bashrc生效。我习惯把git的常用操作也建一套alias省下来的时间积少成多。7.2 history找到你曾经敲过的命令命令记不住没关系shell会替你记。# 查看历史命令 history # 搜索历史命令 history | grep gunicorn # 直接执行历史记录中的第100条 !100还有一个技巧终端里按Ctrlr进入反向搜索输入关键字会自动提示最近匹配的命令。比history | grep更顺手。7.3 组合使用管道符的威力Linux命令的哲学是一个工具只干一件事多个工具通过管道串联成一条流水线。# 查看当前目录下最大的10个文件 find . -type f -exec du -h {} | sort -rh | head -n 10 # 统计日志中各个IP的访问次数 awk {print $1} access.log | sort | uniq -c | sort -rn | head -n 10这两个例子分别用了finddusorthead以及awksortuniqsorthead。单独看每个命令都很简单但串起来就能在几十秒内完成原本要写几十行Python脚本才能做的数据分析。7.4 一键重跑部署任务的思路部署流程重复且机械适合写成一个Shell脚本。比如我常用的一个更新脚本#!/bin/bash set -e echo pull code git pull origin main echo install dependencies source venv/bin/activate pip install -r requirements.txt echo migrate python manage.py migrate --noinput echo collect static python manage.py collectstatic --noinput echo restart service sudo systemctl restart myblog echo doneset -e表示任何一条命令失败就立即退出避免在错误状态下继续跑后续步骤。脚本写好后chmod x deploy.sh ./deploy.sh把重复劳动脚本化是初级开发到高级开发的一个重要分水岭。7.5 开发中的一个小技巧Python -m http.server有时候你想临时起一个简单的HTTP服务让人下载文件或者测试页面# 在当前目录启动一个HTTP服务默认端口8000 python3 -m http.server 8000这个命令对Python开发者来说等于内置了一个轻量的静态文件服务器调试前端代码、临时分享文件都能用。而且它不需要任何第三方库Python自带。8. 一些实用的排查工具和思路8.1 strace黑盒排查利器程序跑不起来或者卡住不动日志又什么都没打。这时候可以用strace跟踪系统调用看程序在干什么# 跟踪某个进程的系统调用 sudo strace -p 12345 # 跟踪程序启动时的系统调用保存到文件 sudo strace -o trace.log python3 app.pystrace能看到程序打开哪些文件、访问哪些网络端口、报了什么系统级别的错误。比如一个常见的场景Python程序启动时报Permission denied但日志里的错误信息很模糊用strace就能看到它到底是哪个文件的权限不够。这是找不到日志原因时的终极大杀器。8.2 lsof文件和端口的对应关系lsof能列出进程打开的文件和网络端口# 查看某个文件被哪个进程占用 lsof app.log # 查看某个用户打开的所有文件 lsof -u deploy # 查看某个端口被哪个进程监听 lsof -i :8000有人说ss已经能看端口占用为什么还要lsof因为lsof的视角更偏文件比如你想知道这个日志文件被谁一直占用导致磁盘删不掉用lsof就能快速定位。8.3 快速定位CPU占用高的Python代码如果你发现线上某个Python服务CPU飙高可以这样快速定位# 1. 找到CPU占用最高的进程 top -o %CPU # 2. 把进程转成线程号 # 记下PID然后用 top -Hp 看线程 top -Hp PID # 3. 用py-spy直接采样Python调用栈重点 sudo py-spy dump --pid PIDpy-spy是一个专门针对Python进程的采样工具不需要重启服务就能看到当前Python代码执行到了哪一行。比用gdb折腾半天高效多了。安装方式pip install py-spy8.4 查看服务运行时间的uptimeuptimeuptime会显示系统运行时间、当前登录用户数、以及1/5/15分钟的平均负载。如果负载持续很高说明系统处于过载状态需要结合top看是CPU-bound还是内存不足导致的swap频繁。9. 最后再聊点实在的坦白说Linux命令这个东西光看不练一点用都没有。你把这篇文章里的命令挨个敲一遍比背十遍命令手册都管用。我自己也是从一个命令在一个项目里被坑了三次才记住的状态过来的踩坑不可怕关键是每次踩坑之后能把对应的命令和思路沉淀下来。我个人的体会是不必追求把所有命令都背得滚瓜烂熟你只需要记住每个场景下有哪些工具可以用具体参数忘了就man或者--help。比如grep的参数那么多常用的就是-n -i -C其他参数真要用了现查也不迟。还有一个建议是尽量养成在Linux环境下开发的好习惯不是让你完全抛弃IDE和图形界面而是说写代码、跑测试、看日志这些操作能到命令行做的就到命令行做。这样你会发现真正上服务器部署排错的时候一切都很自然不会有一种我是在另一个世界干活的割裂感。工具是死的思路是活的。把这些命令串起来形成一套属于自己的排查路径比记住任何单个命令都重要。
返回列表