ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

PyCharm+SSH+Docker:搭建远程开发环境,解决环境不一致

PyCharm+SSH+Docker:搭建远程开发环境,解决环境不一致 如果你也是那种打开PyCharm写代码、眼睛却盯着远程Docker环境的开发者这篇文章应该能帮你少走不少弯路。常年在本地开发、远端部署的人应该都有过这种体验本地环境跟服务器环境永远差着几个依赖版本改完代码传到服务器上一跑就报错。今天聊的就是一个组合方案——在PyCharm里通过SSH把远程Docker配置好让解释器、依赖、运行全部在服务器上完成。本地只用做一件事写代码。这套方案尤其适合远程服务器开发党、需要多人共用统一环境的团队以及手头有一台闲置Linux机器想利用起来的人。1. 先想清楚为什么要把开发环境放到远程Docker里1.1 本地环境与线上环境不一致的老大难问题大部分项目的开发流程是代码在本地写跑通了再提交到服务器服务器上再拉代码、装依赖、重启服务。这个流程在个人项目里问题不大一旦团队协作或者项目上了规模麻烦就来了。我印象特别深的一次帮同事排查一个报错他在自己电脑上跑得好好的代码推到服务器上就报“找不到模块”。查了半天发现他本地是Windowspip装了一个pymysql的wheel包服务器是Linux解析依赖的时候版本号对不上整个环境就崩了。这种问题不是单纯的“多装一个包”能解决的因为依赖树里可能还有间接依赖系统库版本、C扩展、glibc版本都会掺和进来。后来换成Docker就清爽很多。Docker容器本质上就是一个独立的小型Linux系统你在Dockerfile里写了什么依赖运行环境里就是什么依赖镜像被推到哪台机器环境就是一模一样的。但问题也来了很多人的开发习惯还是本地写代码Docker只在部署阶段才参与壳子和内容还是脱节的。我的做法是把Docker直接前移到开发阶段。具体来说就是让PyCharm的开发环境变成一个远程Docker容器——本地编辑代码运行、调试、装依赖都在容器里完成。这样本地电脑配置再差也无所谓真正的开发环境在服务器上再也不会出现“我本地能跑”这种话了。1.2 为什么偏偏是SSHDocker而不是其它方案PyCharm里配置远程开发其实有好几条路可以走。我列个对比你能看得更清楚方案环境一致性运维成本适合场景纯本机虚拟环境差依赖版本和系统库很难完全统一低个人轻量项目本机Docker Desktop较好但Mac/Windows下需要虚拟层性能有时捉急中本地容器化调试纯SSH远程解释器中Python环境在服务器本机多个项目会互相污染低服务器上只有一个项目VSCode Remote-SSH插件好但扩展在远程主机上的兼容性偶尔出问题中偏编辑器场景PyCharm SSH Docker好环境完全在容器内IDE原生集成度高略高需维护镜像和Compose团队统一环境、远程开发纯SSH远程解释器我也用过一段时间就是把PyCharm的解释器指向服务器上的某个Python路径。能用但有个很现实的问题如果服务器上同时跑三五个项目每个项目依赖的包版本还不一样那不出一个月你的服务器Python环境就会变成一团乱麻。Docker正好解决了这个隔离问题每个项目一个镜像互不干扰。选择“SSH Docker”还有一个理由本机根本不需要装Docker Desktop。很多人被Docker Desktop在Windows上的虚拟化报错折腾得够呛我这个方案直接绕过了这层——只要服务器上有Docker本机装个纯PyCharm专业版就能干所有事。题外话一句如果你之前试过VSCode的Remote-SSH可能见过“此扩展在此工作区中被禁用因为其被定义为在远程扩展主机中运行”的提示PyCharm这边是官方原生集成基本没有这类插件兼容的坑。2. 动手前的准备工作服务器、本机、密钥三件套2.1 远端服务器装好Docker和SSH服务先提个建议别用真实的线上生产服务器折腾最好找一台闲置的Linux机器或云服务器来做这件事。系统用Ubuntu 20.04/22.04都可以其他发行版命令大同小异。Docker的安装就不展开太多了Ubuntu下两条常见方式任选其一# 方式一apt直接装版本可能偏旧但稳定 sudo apt update sudo apt install -y docker.io sudo systemctl enable --now docker # 方式二官方脚本版本较新 curl -fsSL https://get.docker.com | bash sudo systemctl enable --now docker装完之后验证一下docker version能正常输出Client和Server两段信息说明服务已经起来了。如果只看到Client没有Server多半是Docker服务没启动执行sudo systemctl start docker就行。SSH服务这块Ubuntu服务器默认可能只装了客户端没有服务端。确认方式很简单ssh localhost如果提示“Connection refused”那就需要装OpenSSH Serversudo apt install -y openssh-server sudo systemctl enable --now ssh这里有个非常容易踩的坑重启服务器之后SSH连不上。原因往往是防火墙或者云安全组没有放行22端口。本地先确认一下端口状态nc -vz 你的服务器IP 22如果端口不通先去云控制台的安全组和服务器上的防火墙ufw status把22端口放行再谈后面的事。2.2 本机PyCharm与SSH密钥准备PyCharm这边注意一个硬性条件SSH远程解释器和Docker集成都是专业版才有的功能社区版没有。社区版能做本地虚拟环境配置但连不上远程Docker。所以这一步你得准备一个专业版授权官方有30天试用也可以根据需要订阅总之别去碰那些来路不明的激活工具一是安全问题太多二是环境搞坏了反而耽误时间。本机还要准备一套SSH密钥推荐用ed25519算法比rsa短且更安全ssh-keygen -t ed25519 -C your_emailexample.com生成之后把公钥传到服务器ssh-copy-id 用户名服务器IP如果没有ssh-copy-id命令手动追加也很快cat ~/.ssh/id_ed25519.pub | ssh 用户名服务器IP mkdir -p ~/.ssh chmod 700 ~/.ssh cat ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys全部搞定之后在终端里先手动测试一遍ssh 用户名服务器IP docker ps这两条命令都能顺利执行说明SSH和Docker权限链路都通了这时候再打开PyCharm去配置基本不会有大问题。我见过太多人跳过这一步直接去IDE里折腾结果连不上都不知道是密码错了还是网络不通。2.3 设计好项目目录提前决定路径映射在配置之前先想清楚你的项目代码在三层环境里怎么流转第一层本地项目目录比如/Users/me/code/myapp第二层服务器上的一个目录PyCharm会把本地代码自动同步过去第三层容器内的目录也就是代码真正运行的路径我建议在服务器上固定一个工作目录比如~/workspace/myapp专门用来放PyCharm同步过来的代码。别偷懒全丢到home根目录项目多了之后会非常乱。还要提前确认一件事你的项目里有没有docker-compose.yml。如果这个项目后面要连数据库、缓存之类的中间件强烈建议用Compose来编排如果只是一个简单的Python应用那一个Dockerfile就够了。这一步决定了你在PyCharm里选择解释器类型时选哪个所以最好先想清楚。3. 在PyCharm里配置远程SSHDocker解释器3.1 先让PyCharm通过SSH连上远程Docker引擎打开PyCharm进入Settings找到Build, Execution, Deployment点开Docker一栏。这里是管理Docker连接的地方PyCharm默认会尝试连接本机的Docker我们现在要给它加一条远程的。点右上角的“”在连接方式里选择SSHServer address服务器IPPort22Username登录用户比如ubuntu、root都行Authentication选Key pair然后把刚才那个私钥文件路径填进去填完可以先点一下Test ConnectionPyCharm会提示Connection successful。这一步能过说明IDE已经能通过SSH管理远程Docker了接下来你可以在PyCharm的Services面板里直接看服务器上的镜像、容器和日志省去了每次都要SSH进终端敲命令的麻烦。关于认证方式多说一句PyCharm也支持密码登录但如果你经常要重新部署、反复重连密码方式会让你多输好多遍。密钥登录一次配好后面基本无感强烈推荐。3.2 添加SSH解释器把Python环境指向容器接下来是核心操作——添加远程解释器。打开Settings找到Project: 你的项目名点Python Interpreter然后点Add Interpreter选择On SSH。Host服务器IPPort22Username服务器登录用户Authentication同样选Key pairPyCharm会先通过SSH建立一条连接然后弹出下一步让你选择解释器类型。这里有Docker Compose和Docker两个选项选Docker Compose需要指定服务器上的docker-compose.yml路径。PyCharm会读取Compose文件里的服务定义用哪个服务作为解释器环境。选Docker直接选择一个已有的镜像或者指定DockerfilePyCharm会在远程机器上基于这个镜像创建容器并把Python解释器指向容器内的/usr/local/bin/python3。以最常用的Docker为例先选New创建一个Docker配置它会自动识别你刚才在Build, Execution, Deployment里配置的远程连接。然后Image选python:3.11-slim这种基础镜像或者已经有业务依赖的镜像。接下来是Container options这里有几个字段需要填Container name随便起一个比如myapp-devPort bindings如果你项目要监听端口比如Flask默认5000就填5000:5000Volume bindings这里很关键把服务器上存放代码的目录映射到容器内的工作目录比如/home/ubuntu/workspace/myapp:/app等PyCharm在远程Docker上把容器创建好解释器配置就完成了。你会看到PyCharm状态栏右下角的解释器名称变成了类似Remote: Docker的标识控制台的Python版本也变成了容器内的版本。这时候你直接运行项目里的Python文件本质就是在这个容器里执行。PyCharm会自动把本地代码通过SFTP同步到服务器上再以卷挂载的方式传给容器。所以你改完代码一保存再一运行用的就已经是最新版本了不需要手动上传这个机制理解清楚了后面排查代码不同步问题会方便很多。3.3 配置Docker运行配置一键起容器解释器解决的是“代码跑在容器里”但很多项目最终是要作为一个完整服务跑起来的比如Web应用要有固定的端口、环境变量、容器命名。这个时候就需要单独的Docker运行配置。点开右上角的运行配置下拉框选Edit Configurations点左上角“”选择Docker。这里可以配置Image tag镜像名和标签比如myapp:latestContainer name容器启动后的名字Port bindings宿主机端口和容器端口比如8000:8000Volume bindings把服务器上的项目目录挂载进容器与解释器配置里保持一致Environment variables密钥、数据库地址等环境变量配置好之后点运行按钮。PyCharm会在远程Docker上拉取镜像、创建容器、启动服务然后直接在控制台输出日志。你本地浏览器访问http://服务器IP:8000就能看到服务已经在运行了。这里有一个之前提到的容易混淆的点我多说一句解释器配置和Docker运行配置是两件事。开发阶段你频繁改代码主要靠解释器配置它跑起来轻量快速到了想验证整个应用是否具备对外提供服务的能力时再用Docker运行配置。两者可以同时存在不冲突。我个人的习惯是日常开发全用远程解释器写完一个功能节点之后用Docker运行配置起一个完整服务做一次联调。这样既保留了开发效率又能在开发期内就暴露部署环境的问题。3.4 依赖管理从临时容器到可复用镜像依赖管理大概是远程Docker开发里最容易被忽略、后来最让人头疼的部分。用远程解释器的时候你想临时装一个包比如pandas直接在PyCharm的Terminal里敲pip install pandas就行要注意的是因为解释器在容器里这个Terminal默认就已经在容器内部了安装也是装到容器里。但这里有个非常坑的细节如果这个容器是一次性的开发容器下次PyCharm重建解释器时你在容器里手工pip install的那些包就全没了。所以一定要养成两个习惯第一项目里永远维护一份requirements.txt或者pyproject.toml。每装一个新包马上执行pip freeze requirements.txt第二涉及项目基础依赖的写进Dockerfile。这样每次重建镜像依赖都会自动装上不用靠人肉记忆去恢复环境。我自己的Dockerfile通常长这样FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . CMD [python, app.py]这个思路的核心是不能依赖容器内部的临时状态一切环境定义都要落到文件里。否则一旦容器没了你的开发环境也就跟着蒸发了。4. 常见问题排查从连不上到跑不起来4.1 SSH连不上的几大原因SSH连接失败是配置这套环境时遇到概率最高的问题绝大多数情况就这几类现象可能原因解决办法Connection timed out防火墙或云安全组没放行22端口在云控制台和服务器ufw中放行22端口用nc -vz 服务器IP 22检测Permission denied (publickey)公钥没有正确写入authorized_keys用ssh-copy-id重新传公钥检查服务器上~/.ssh和authorized_keys的权限Host key verification failedknown_hosts里记录过时执行ssh-keygen -R 服务器IP清除旧记录Connection refusedopenssh-server没有启动sudo systemctl enable --now ssh确认已安装openssh-server如果你之前用密码能连上、换了密钥就连不上大概率是服务器上/etc/ssh/sshd_config里禁用了密钥认证检查一下PubkeyAuthentication yes这行是不是被注释或者被改成no了。改完记得重启SSH服务。4.2 Docker侧的坑权限、镜像、虚拟化Docker这边最经典的报错是Got permission denied while trying to connect to the Docker daemon socket这个基本就是当前用户不在docker组里。解决方式两条命令sudo usermod -aG docker $USER newgrp docker新开一个SSH终端再试docker ps通常就好了。如果提示docker: command not found那就是Docker根本没装上回头检查docker version有没有正常输出。还有一类经常在Windows本机出现的问题虽然我们的方案本机不需要装Docker但很多读者会因为其他地方用得上而同时装一个Docker Desktop。如果启动时报virtualization support not detected这类错误通常是Windows的虚拟化功能没开启需要去BIOS里打开VT-x或者AMD-V然后在“启用或关闭Windows功能”里勾选Hyper-V和虚拟机平台。这个问题跟远程配置本身无关但顺带一提免得你卡在两种环境之间反复折腾。镜像拉取慢或者拉不下来在国内服务器上很常见。解决思路是给Docker配置镜像加速器具体配置方法每家服务商都不一样按你自己的云厂商文档来就行。记着一个原则加速器只解决拉取慢不解决依赖冲突问题。4.3 PyCharm侧的坑解释器无效、代码不同步用远程解释器跑起来之后最烦人的一类问题就是解释器标红或者提示Invalid interpreter。先检查你选的镜像里到底有没有Python环境。如果镜像只是个基础系统镜像那容器里自然没有/usr/local/bin/python3PyCharm就会找不到解释器。解决办法很简单换成官方python镜像或者确保自己的Dockerfile里装好了Python。代码不同步是另一个高频问题。你在本地改了一个文件运行的时候却还在跑旧版本。先确认几件事本地文件保存了吗PyCharm的自动同步依赖文件保存事件改完要CtrlS。服务器上的代码路径和容器里的卷映射是否一致如果在配置里写死了旧路径改过路径之后没有同步更新就会一直用旧代码。如果频繁出现直接在Tools → Deployment → Options里把Upload automatically打开这样每次保存都会自动同步。还有一个很容易忽视的文件同步顺序。PyCharm默认是先同步到服务器再映射到容器如果服务器临时目录里残留了同名旧文件可能需要手动清理。遇到莫名其妙的问题时直接在Services面板把相关容器停掉再重新运行很多时候就恢复了。4.4 几个帮我省下大量时间的习惯最后分享几个我自己长期使用后沉淀下来的习惯不一定多高级但真的能省时间。第一用~/.ssh/config管理多台服务器。在本地这个文件里写好Host dev-server HostName 你的服务器IP User ubuntu IdentityFile ~/.ssh/id_ed25519写好之后PyCharm里填服务器地址时可以直接填dev-server不用每次都敲IP而且你在终端里ssh dev-server也能连两边统一。第二第一次配置不要用项目完整镜像拿python:3.11-slim这种基础镜像先跑通整条链路。链路通了再换正式镜像不然一边排查环境问题一边排查代码问题很容易让人崩溃。第三容器里临时装的依赖一定要及时用pip freeze requirements.txt固化下来。我吃过一次亏在容器里折腾了一下午装好了一堆包嫌麻烦没更新requirements文件第二天镜像一重建环境全没了一整个下午白干。最后再分享一点这套方案我实际用下来大半年最值的一点不是省了本地几个G的磁盘而是开发环境和生产环境真的能做到同源。以后团队里再来新人克隆代码、拉一个镜像解释器配置好马上就能开始干活不再需要对着安装文档折腾两三天。最后再啰嗦一句第一次配置别指望一步到位拿最基础的镜像把整条链路跑通再去加依赖、加服务编排。链路通了剩下都是细节出问题也容易定位。
返回列表