[{"data":1,"prerenderedAt":2320},["Reactive",2],{"article-20250122":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":7,"published":9,"categories":10,"tags":12,"slug":8,"body":14,"_type":2315,"_id":2316,"_source":2317,"_file":2318,"_extension":2319},"/articles/20250122","articles",false,"","强大的自动化工作流工具，你值得拥有","2025/01/22",[11],"前端",[13],"自动化",{"type":15,"children":16,"toc":2310},"root",[17,25,31,51,56,61,66,71,87,95,100,107,112,117,122,127,132,161,166,173,178,183,201,206,213,218,223,230,235,240,247,252,259,264,329,334,341,346,351,356,361,366,371,378,383,390,395,412,417,424,429,720,732,737,785,790,823,828,967,972,979,984,989,2192,2197,2204,2209,2214,2219,2226,2231,2238,2251,2256,2261,2266,2271,2276,2289,2294,2299,2304],{"type":18,"tag":19,"props":20,"children":22},"element","h2",{"id":21},"背景",[23],{"type":24,"value":21},"text",{"type":18,"tag":26,"props":27,"children":28},"p",{},[29],{"type":24,"value":30},"最近在家忙着开发telegram机器人项目，每次部署到nas上时，都会有一个比较重复的步骤：",{"type":18,"tag":32,"props":33,"children":34},"ol",{},[35,41,46],{"type":18,"tag":36,"props":37,"children":38},"li",{},[39],{"type":24,"value":40},"推送到远程触发ci构建docker镜像，等待镜像构建完成",{"type":18,"tag":36,"props":42,"children":43},{},[44],{"type":24,"value":45},"打开终端ssh进入nas，然后cd到机器人项目的目录",{"type":18,"tag":36,"props":47,"children":48},{},[49],{"type":24,"value":50},"运行docker-compose下拉命令和重新构建命令",{"type":18,"tag":26,"props":52,"children":53},{},[54],{"type":24,"value":55},"重复次数多了之后，我就想能不能找个工具代替（没办法我实在是懒），而且我在外面的时候就没办法进入nas所在的局域网重启了。",{"type":18,"tag":26,"props":57,"children":58},{},[59],{"type":24,"value":60},"我需要一个按钮，按下去，程序就帮我执行完后面的2步。",{"type":18,"tag":26,"props":62,"children":63},{},[64],{"type":24,"value":65},"其实这最后2步也可以挪到ci中完成，但我就是想找一个独立的工具，不去依赖ci。",{"type":18,"tag":26,"props":67,"children":68},{},[69],{"type":24,"value":70},"于是我就想，应该已经有这样的工具了，配置好任务的触发器，触发之后就自动执行写好的脚本。",{"type":18,"tag":26,"props":72,"children":73},{},[74,76,85],{"type":24,"value":75},"带着这个想法，我就立马去搜索关键词，最终搜到了",{"type":18,"tag":77,"props":78,"children":82},"a",{"href":79,"rel":80},"https://docs.n8n.io/",[81],"nofollow",[83],{"type":24,"value":84},"n8n",{"type":24,"value":86},"，基于node写的工作流自动化工具。",{"type":18,"tag":26,"props":88,"children":89},{},[90],{"type":18,"tag":91,"props":92,"children":94},"img",{"alt":7,"src":93},"https://johnhom-img.oss-cn-guangzhou.aliyuncs.com/obsidian/Pasted%20image%2020250122171737.png",[],{"type":18,"tag":26,"props":96,"children":97},{},[98],{"type":24,"value":99},"刚好第二天无意中看到群里有人转了奇舞精选的一篇【2024年最受欢迎的前段项目】n8n赫然在列。",{"type":18,"tag":26,"props":101,"children":102},{},[103],{"type":18,"tag":91,"props":104,"children":106},{"alt":7,"src":105},"https://johnhom-img.oss-cn-guangzhou.aliyuncs.com/obsidian/Pasted%20image%2020250122172417.png",[],{"type":18,"tag":26,"props":108,"children":109},{},[110],{"type":24,"value":111},"好家伙，那我不得高低学一下。",{"type":18,"tag":19,"props":113,"children":115},{"id":114},"搭建自动化工作流",[116],{"type":24,"value":114},{"type":18,"tag":26,"props":118,"children":119},{},[120],{"type":24,"value":121},"n8n有两种方式使用，一种是直接使用官方网站，一种是在自己服务器上搭建n8n，我毫不犹疑就选了后者。毕竟这样可控制的程度更高一些",{"type":18,"tag":26,"props":123,"children":124},{},[125],{"type":24,"value":126},"我们可以直接使用npm启动n8n，",{"type":18,"tag":26,"props":128,"children":129},{},[130],{"type":24,"value":131},"只需要运行：",{"type":18,"tag":133,"props":134,"children":138},"pre",{"className":135,"code":136,"language":137,"meta":7,"style":7},"language-bash shiki shiki-themes github-dark","npx n8n\n","bash",[139],{"type":18,"tag":140,"props":141,"children":142},"code",{"__ignoreMap":7},[143],{"type":18,"tag":144,"props":145,"children":148},"span",{"class":146,"line":147},"line",1,[149,155],{"type":18,"tag":144,"props":150,"children":152},{"style":151},"--shiki-default:#B392F0",[153],{"type":24,"value":154},"npx",{"type":18,"tag":144,"props":156,"children":158},{"style":157},"--shiki-default:#9ECBFF",[159],{"type":24,"value":160}," n8n\n",{"type":18,"tag":26,"props":162,"children":163},{},[164],{"type":24,"value":165},"然后注册一个账号，进入主页就是这样子：",{"type":18,"tag":26,"props":167,"children":168},{},[169],{"type":18,"tag":91,"props":170,"children":172},{"alt":7,"src":171},"https://johnhom-img.oss-cn-guangzhou.aliyuncs.com/obsidian/Pasted%20image%2020250122173325.png",[],{"type":18,"tag":26,"props":174,"children":175},{},[176],{"type":24,"value":177},"为了方便搭建和运行，我决定部署到在nas上，用docker容器运行n8n。",{"type":18,"tag":26,"props":179,"children":180},{},[181],{"type":24,"value":182},"接下来整理一波n8n需要实现的工作流：",{"type":18,"tag":32,"props":184,"children":185},{},[186,191,196],{"type":18,"tag":36,"props":187,"children":188},{},[189],{"type":24,"value":190},"外部某个事件触发",{"type":18,"tag":36,"props":192,"children":193},{},[194],{"type":24,"value":195},"进入到某个文件夹，执行重启脚本",{"type":18,"tag":36,"props":197,"children":198},{},[199],{"type":24,"value":200},"发送邮件提示已经执行完成",{"type":18,"tag":26,"props":202,"children":203},{},[204],{"type":24,"value":205},"开整，我们先点击右上角的【Create Workflow】新建一个工作流，然后点击中间的添加第一步，右侧会弹出可选的触发器：",{"type":18,"tag":26,"props":207,"children":208},{},[209],{"type":18,"tag":91,"props":210,"children":212},{"alt":7,"src":211},"https://johnhom-img.oss-cn-guangzhou.aliyuncs.com/obsidian/Pasted%20image%2020250122173804.png",[],{"type":18,"tag":26,"props":214,"children":215},{},[216],{"type":24,"value":217},"app event的列表我看了一遍，全是国外的应用，看来国外开源项目的唯一缺点就是在国内水土不服。",{"type":18,"tag":26,"props":219,"children":220},{},[221],{"type":24,"value":222},"那就只能用webhook call了，用它来新建一个触发节点，然后我们可以看到：",{"type":18,"tag":26,"props":224,"children":225},{},[226],{"type":18,"tag":91,"props":227,"children":229},{"alt":7,"src":228},"https://johnhom-img.oss-cn-guangzhou.aliyuncs.com/obsidian/Pasted%20image%2020250122174148.png",[],{"type":18,"tag":26,"props":231,"children":232},{},[233],{"type":24,"value":234},"不得不说界面真的挺简洁明了。大概的用法就是，只要请求提供的webhook url，n8n就会从这个webhook节点开始执行任务。",{"type":18,"tag":26,"props":236,"children":237},{},[238],{"type":24,"value":239},"接下来就是执行脚本，继续添加下一步，选择【Execute Command】",{"type":18,"tag":26,"props":241,"children":242},{},[243],{"type":18,"tag":91,"props":244,"children":246},{"alt":7,"src":245},"https://johnhom-img.oss-cn-guangzhou.aliyuncs.com/obsidian/Pasted%20image%2020250123174457.png",[],{"type":18,"tag":26,"props":248,"children":249},{},[250],{"type":24,"value":251},"然后cd到某个目录，执行restart.sh脚本",{"type":18,"tag":26,"props":253,"children":254},{},[255],{"type":18,"tag":91,"props":256,"children":258},{"alt":7,"src":257},"https://johnhom-img.oss-cn-guangzhou.aliyuncs.com/obsidian/Pasted%20image%2020250123174554.png",[],{"type":18,"tag":26,"props":260,"children":261},{},[262],{"type":24,"value":263},"restart.sh脚本内容如下：",{"type":18,"tag":133,"props":265,"children":269},{"className":266,"code":267,"language":268,"meta":7,"style":7},"language-shell shiki shiki-themes github-dark","# 拉取最新的镜像\ndocker-compose pull\n# 重新创建并启动\ndocker-compose up -d --force-recreate\n","shell",[270],{"type":18,"tag":140,"props":271,"children":272},{"__ignoreMap":7},[273,282,296,305],{"type":18,"tag":144,"props":274,"children":275},{"class":146,"line":147},[276],{"type":18,"tag":144,"props":277,"children":279},{"style":278},"--shiki-default:#6A737D",[280],{"type":24,"value":281},"# 拉取最新的镜像\n",{"type":18,"tag":144,"props":283,"children":285},{"class":146,"line":284},2,[286,291],{"type":18,"tag":144,"props":287,"children":288},{"style":151},[289],{"type":24,"value":290},"docker-compose",{"type":18,"tag":144,"props":292,"children":293},{"style":157},[294],{"type":24,"value":295}," pull\n",{"type":18,"tag":144,"props":297,"children":299},{"class":146,"line":298},3,[300],{"type":18,"tag":144,"props":301,"children":302},{"style":278},[303],{"type":24,"value":304},"# 重新创建并启动\n",{"type":18,"tag":144,"props":306,"children":308},{"class":146,"line":307},4,[309,313,318,324],{"type":18,"tag":144,"props":310,"children":311},{"style":151},[312],{"type":24,"value":290},{"type":18,"tag":144,"props":314,"children":315},{"style":157},[316],{"type":24,"value":317}," up",{"type":18,"tag":144,"props":319,"children":321},{"style":320},"--shiki-default:#79B8FF",[322],{"type":24,"value":323}," -d",{"type":18,"tag":144,"props":325,"children":326},{"style":320},[327],{"type":24,"value":328}," --force-recreate\n",{"type":18,"tag":26,"props":330,"children":331},{},[332],{"type":24,"value":333},"到这里我突然想到一个问题，就是我搭建的n8n是在nas里基于容器运行的，在容器内会存在命令空间隔离问题，执行docker命令肯定会提示command not found。",{"type":18,"tag":26,"props":335,"children":336},{},[337],{"type":18,"tag":91,"props":338,"children":340},{"alt":7,"src":339},"https://johnhom-img.oss-cn-guangzhou.aliyuncs.com/obsidian/Pasted%20image%2020250123175119.png",[],{"type":18,"tag":26,"props":342,"children":343},{},[344],{"type":24,"value":345},"于是就想着如何在容器内，也能够控制宿主的docker去拉取某个镜像和重启，但是困难重重：",{"type":18,"tag":26,"props":347,"children":348},{},[349],{"type":24,"value":350},"首先挂载宿主机的docker.sock文件，然后通过Node.js的dockerode库调用docker api去重启容器",{"type":18,"tag":26,"props":352,"children":353},{},[354],{"type":24,"value":355},"由于我是用docker-compose.yml去管理容器，所以换成dockerode-compose去操作，本来以为这样就没问题了，然而打脸来的太快，不知道为啥报错了，过程折腾了好久，最终还是放弃了调用docker api的方案。",{"type":18,"tag":26,"props":357,"children":358},{},[359],{"type":24,"value":360},"然后我回顾一下，如果容器直接通过ssh登录到宿主机上，也可以直接执行脚本了。",{"type":18,"tag":26,"props":362,"children":363},{},[364],{"type":24,"value":365},"只能先这样了，如果大家有什么更好的方法，也可以在评论区发出来我学习一波。",{"type":18,"tag":26,"props":367,"children":368},{},[369],{"type":24,"value":370},"首先问一下ai，在容器里如何获取宿主机的ip：",{"type":18,"tag":26,"props":372,"children":373},{},[374],{"type":18,"tag":91,"props":375,"children":377},{"alt":7,"src":376},"https://johnhom-img.oss-cn-guangzhou.aliyuncs.com/obsidian/Pasted%20image%2020250123180955.png",[],{"type":18,"tag":26,"props":379,"children":380},{},[381],{"type":24,"value":382},"然后在容器内测试一下这个命令，确实可行！",{"type":18,"tag":26,"props":384,"children":385},{},[386],{"type":18,"tag":91,"props":387,"children":389},{"alt":7,"src":388},"https://johnhom-img.oss-cn-guangzhou.aliyuncs.com/obsidian/Pasted%20image%2020250123181208.png",[],{"type":18,"tag":26,"props":391,"children":392},{},[393],{"type":24,"value":394},"再整理一下最新的工作流方案：",{"type":18,"tag":32,"props":396,"children":397},{},[398,402,407],{"type":18,"tag":36,"props":399,"children":400},{},[401],{"type":24,"value":190},{"type":18,"tag":36,"props":403,"children":404},{},[405],{"type":24,"value":406},"执行js代码，通过child_process执行命令获取宿主机的ip地址",{"type":18,"tag":36,"props":408,"children":409},{},[410],{"type":24,"value":411},"通过ssh2进入宿主机，运行命令重启容器。",{"type":18,"tag":26,"props":413,"children":414},{},[415],{"type":24,"value":416},"好的，接下来创建一个Code节点：",{"type":18,"tag":26,"props":418,"children":419},{},[420],{"type":18,"tag":91,"props":421,"children":423},{"alt":7,"src":422},"https://johnhom-img.oss-cn-guangzhou.aliyuncs.com/obsidian/Pasted%20image%2020250123194745.png",[],{"type":18,"tag":26,"props":425,"children":426},{},[427],{"type":24,"value":428},"获取宿主机ip的代码如下：",{"type":18,"tag":133,"props":430,"children":434},{"className":431,"code":432,"language":433,"meta":7,"style":7},"language-javascript shiki shiki-themes github-dark","const { execSync } = require('child_process');\n\n// 获取宿主机ip的命令\nconst findIpCommand = \"ip route | awk '/default/ { print $3 }'\";\n\nconst ip = execSync(findIpCommand, { encoding: 'utf8' }).trim();\nconsole.log('ip', ip);\n\nif (!ip) {\n  throw new Error('宿主ip为空');\n}\nreturn {\n  ip,\n};\n","javascript",[435],{"type":18,"tag":140,"props":436,"children":437},{"__ignoreMap":7},[438,488,497,505,532,540,587,615,623,647,679,688,702,711],{"type":18,"tag":144,"props":439,"children":440},{"class":146,"line":147},[441,447,453,458,463,468,473,478,483],{"type":18,"tag":144,"props":442,"children":444},{"style":443},"--shiki-default:#F97583",[445],{"type":24,"value":446},"const",{"type":18,"tag":144,"props":448,"children":450},{"style":449},"--shiki-default:#E1E4E8",[451],{"type":24,"value":452}," { ",{"type":18,"tag":144,"props":454,"children":455},{"style":320},[456],{"type":24,"value":457},"execSync",{"type":18,"tag":144,"props":459,"children":460},{"style":449},[461],{"type":24,"value":462}," } ",{"type":18,"tag":144,"props":464,"children":465},{"style":443},[466],{"type":24,"value":467},"=",{"type":18,"tag":144,"props":469,"children":470},{"style":151},[471],{"type":24,"value":472}," require",{"type":18,"tag":144,"props":474,"children":475},{"style":449},[476],{"type":24,"value":477},"(",{"type":18,"tag":144,"props":479,"children":480},{"style":157},[481],{"type":24,"value":482},"'child_process'",{"type":18,"tag":144,"props":484,"children":485},{"style":449},[486],{"type":24,"value":487},");\n",{"type":18,"tag":144,"props":489,"children":490},{"class":146,"line":284},[491],{"type":18,"tag":144,"props":492,"children":494},{"emptyLinePlaceholder":493},true,[495],{"type":24,"value":496},"\n",{"type":18,"tag":144,"props":498,"children":499},{"class":146,"line":298},[500],{"type":18,"tag":144,"props":501,"children":502},{"style":278},[503],{"type":24,"value":504},"// 获取宿主机ip的命令\n",{"type":18,"tag":144,"props":506,"children":507},{"class":146,"line":307},[508,512,517,522,527],{"type":18,"tag":144,"props":509,"children":510},{"style":443},[511],{"type":24,"value":446},{"type":18,"tag":144,"props":513,"children":514},{"style":320},[515],{"type":24,"value":516}," findIpCommand",{"type":18,"tag":144,"props":518,"children":519},{"style":443},[520],{"type":24,"value":521}," =",{"type":18,"tag":144,"props":523,"children":524},{"style":157},[525],{"type":24,"value":526}," \"ip route | awk '/default/ { print $3 }'\"",{"type":18,"tag":144,"props":528,"children":529},{"style":449},[530],{"type":24,"value":531},";\n",{"type":18,"tag":144,"props":533,"children":535},{"class":146,"line":534},5,[536],{"type":18,"tag":144,"props":537,"children":538},{"emptyLinePlaceholder":493},[539],{"type":24,"value":496},{"type":18,"tag":144,"props":541,"children":543},{"class":146,"line":542},6,[544,548,553,557,562,567,572,577,582],{"type":18,"tag":144,"props":545,"children":546},{"style":443},[547],{"type":24,"value":446},{"type":18,"tag":144,"props":549,"children":550},{"style":320},[551],{"type":24,"value":552}," ip",{"type":18,"tag":144,"props":554,"children":555},{"style":443},[556],{"type":24,"value":521},{"type":18,"tag":144,"props":558,"children":559},{"style":151},[560],{"type":24,"value":561}," execSync",{"type":18,"tag":144,"props":563,"children":564},{"style":449},[565],{"type":24,"value":566},"(findIpCommand, { encoding: ",{"type":18,"tag":144,"props":568,"children":569},{"style":157},[570],{"type":24,"value":571},"'utf8'",{"type":18,"tag":144,"props":573,"children":574},{"style":449},[575],{"type":24,"value":576}," }).",{"type":18,"tag":144,"props":578,"children":579},{"style":151},[580],{"type":24,"value":581},"trim",{"type":18,"tag":144,"props":583,"children":584},{"style":449},[585],{"type":24,"value":586},"();\n",{"type":18,"tag":144,"props":588,"children":590},{"class":146,"line":589},7,[591,596,601,605,610],{"type":18,"tag":144,"props":592,"children":593},{"style":449},[594],{"type":24,"value":595},"console.",{"type":18,"tag":144,"props":597,"children":598},{"style":151},[599],{"type":24,"value":600},"log",{"type":18,"tag":144,"props":602,"children":603},{"style":449},[604],{"type":24,"value":477},{"type":18,"tag":144,"props":606,"children":607},{"style":157},[608],{"type":24,"value":609},"'ip'",{"type":18,"tag":144,"props":611,"children":612},{"style":449},[613],{"type":24,"value":614},", ip);\n",{"type":18,"tag":144,"props":616,"children":618},{"class":146,"line":617},8,[619],{"type":18,"tag":144,"props":620,"children":621},{"emptyLinePlaceholder":493},[622],{"type":24,"value":496},{"type":18,"tag":144,"props":624,"children":626},{"class":146,"line":625},9,[627,632,637,642],{"type":18,"tag":144,"props":628,"children":629},{"style":443},[630],{"type":24,"value":631},"if",{"type":18,"tag":144,"props":633,"children":634},{"style":449},[635],{"type":24,"value":636}," (",{"type":18,"tag":144,"props":638,"children":639},{"style":443},[640],{"type":24,"value":641},"!",{"type":18,"tag":144,"props":643,"children":644},{"style":449},[645],{"type":24,"value":646},"ip) {\n",{"type":18,"tag":144,"props":648,"children":650},{"class":146,"line":649},10,[651,656,661,666,670,675],{"type":18,"tag":144,"props":652,"children":653},{"style":443},[654],{"type":24,"value":655},"  throw",{"type":18,"tag":144,"props":657,"children":658},{"style":443},[659],{"type":24,"value":660}," new",{"type":18,"tag":144,"props":662,"children":663},{"style":151},[664],{"type":24,"value":665}," Error",{"type":18,"tag":144,"props":667,"children":668},{"style":449},[669],{"type":24,"value":477},{"type":18,"tag":144,"props":671,"children":672},{"style":157},[673],{"type":24,"value":674},"'宿主ip为空'",{"type":18,"tag":144,"props":676,"children":677},{"style":449},[678],{"type":24,"value":487},{"type":18,"tag":144,"props":680,"children":682},{"class":146,"line":681},11,[683],{"type":18,"tag":144,"props":684,"children":685},{"style":449},[686],{"type":24,"value":687},"}\n",{"type":18,"tag":144,"props":689,"children":691},{"class":146,"line":690},12,[692,697],{"type":18,"tag":144,"props":693,"children":694},{"style":443},[695],{"type":24,"value":696},"return",{"type":18,"tag":144,"props":698,"children":699},{"style":449},[700],{"type":24,"value":701}," {\n",{"type":18,"tag":144,"props":703,"children":705},{"class":146,"line":704},13,[706],{"type":18,"tag":144,"props":707,"children":708},{"style":449},[709],{"type":24,"value":710},"  ip,\n",{"type":18,"tag":144,"props":712,"children":714},{"class":146,"line":713},14,[715],{"type":18,"tag":144,"props":716,"children":717},{"style":449},[718],{"type":24,"value":719},"};\n",{"type":18,"tag":26,"props":721,"children":722},{},[723,725],{"type":24,"value":724},"运行前，需要配置n8n支持使用内部和外部的模块，具体可以看这里：",{"type":18,"tag":77,"props":726,"children":729},{"href":727,"rel":728},"https://docs.n8n.io/hosting/configuration/configuration-examples/modules-in-code-node/",[81],[730],{"type":24,"value":731},"modules-in-code-node",{"type":18,"tag":26,"props":733,"children":734},{},[735],{"type":24,"value":736},"由于n8n我是用docker-compose去部署的，所以需要在evnironment字段加上以下的值：",{"type":18,"tag":133,"props":738,"children":742},{"className":739,"code":740,"language":741,"meta":7,"style":7},"language-yml shiki shiki-themes github-dark","environment:\n    - NODE_FUNCTION_ALLOW_EXTERNAL=*\n    - NODE_FUNCTION_ALLOW_BUILTIN=*\n","yml",[743],{"type":18,"tag":140,"props":744,"children":745},{"__ignoreMap":7},[746,760,773],{"type":18,"tag":144,"props":747,"children":748},{"class":146,"line":147},[749,755],{"type":18,"tag":144,"props":750,"children":752},{"style":751},"--shiki-default:#85E89D",[753],{"type":24,"value":754},"environment",{"type":18,"tag":144,"props":756,"children":757},{"style":449},[758],{"type":24,"value":759},":\n",{"type":18,"tag":144,"props":761,"children":762},{"class":146,"line":284},[763,768],{"type":18,"tag":144,"props":764,"children":765},{"style":449},[766],{"type":24,"value":767},"    - ",{"type":18,"tag":144,"props":769,"children":770},{"style":157},[771],{"type":24,"value":772},"NODE_FUNCTION_ALLOW_EXTERNAL=*\n",{"type":18,"tag":144,"props":774,"children":775},{"class":146,"line":298},[776,780],{"type":18,"tag":144,"props":777,"children":778},{"style":449},[779],{"type":24,"value":767},{"type":18,"tag":144,"props":781,"children":782},{"style":157},[783],{"type":24,"value":784},"NODE_FUNCTION_ALLOW_BUILTIN=*\n",{"type":18,"tag":26,"props":786,"children":787},{},[788],{"type":24,"value":789},"如果引入了外部的模块，比如后面会用到的ssh2，需要先用npm安装好，因为我是用的Docker，所以我这边是选择新建一个Dockerfile，引入n8n的镜像，然后运行安装依赖的代码：",{"type":18,"tag":133,"props":791,"children":795},{"className":792,"code":793,"language":794,"meta":7,"style":7},"language-Dockerfile shiki shiki-themes github-dark","FROM docker.n8n.io/n8nio/n8n:latest\nRUN npm config set registry https://registry.npmmirror.com\nRUN npm install -g ssh2\n","Dockerfile",[796],{"type":18,"tag":140,"props":797,"children":798},{"__ignoreMap":7},[799,807,815],{"type":18,"tag":144,"props":800,"children":801},{"class":146,"line":147},[802],{"type":18,"tag":144,"props":803,"children":804},{},[805],{"type":24,"value":806},"FROM docker.n8n.io/n8nio/n8n:latest\n",{"type":18,"tag":144,"props":808,"children":809},{"class":146,"line":284},[810],{"type":18,"tag":144,"props":811,"children":812},{},[813],{"type":24,"value":814},"RUN npm config set registry https://registry.npmmirror.com\n",{"type":18,"tag":144,"props":816,"children":817},{"class":146,"line":298},[818],{"type":18,"tag":144,"props":819,"children":820},{},[821],{"type":24,"value":822},"RUN npm install -g ssh2\n",{"type":18,"tag":26,"props":824,"children":825},{},[826],{"type":24,"value":827},"所以我目前的docker-compose.yml内容如下：",{"type":18,"tag":133,"props":829,"children":833},{"className":830,"code":831,"language":832,"meta":7,"style":7},"language-docker-compose.yml shiki shiki-themes github-dark","version: '3.8'\nservices:\n  n8n:\n    container_name: n8n\n    build: .\n    restart: 'unless-stopped'\n    ports:\n      - '5678:5678'\n    volumes:\n      - ./data:/root/.n8n\n    environment:\n      # 允许http的方式登录\n      - N8N_SECURE_COOKIE=false\n      # 支持所有内部和外部的包\n      - NODE_FUNCTION_ALLOW_EXTERNAL=*\n      - NODE_FUNCTION_ALLOW_BUILTIN=*\n","docker-compose.yml",[834],{"type":18,"tag":140,"props":835,"children":836},{"__ignoreMap":7},[837,845,853,861,869,877,885,893,901,909,917,925,933,941,949,958],{"type":18,"tag":144,"props":838,"children":839},{"class":146,"line":147},[840],{"type":18,"tag":144,"props":841,"children":842},{},[843],{"type":24,"value":844},"version: '3.8'\n",{"type":18,"tag":144,"props":846,"children":847},{"class":146,"line":284},[848],{"type":18,"tag":144,"props":849,"children":850},{},[851],{"type":24,"value":852},"services:\n",{"type":18,"tag":144,"props":854,"children":855},{"class":146,"line":298},[856],{"type":18,"tag":144,"props":857,"children":858},{},[859],{"type":24,"value":860},"  n8n:\n",{"type":18,"tag":144,"props":862,"children":863},{"class":146,"line":307},[864],{"type":18,"tag":144,"props":865,"children":866},{},[867],{"type":24,"value":868},"    container_name: n8n\n",{"type":18,"tag":144,"props":870,"children":871},{"class":146,"line":534},[872],{"type":18,"tag":144,"props":873,"children":874},{},[875],{"type":24,"value":876},"    build: .\n",{"type":18,"tag":144,"props":878,"children":879},{"class":146,"line":542},[880],{"type":18,"tag":144,"props":881,"children":882},{},[883],{"type":24,"value":884},"    restart: 'unless-stopped'\n",{"type":18,"tag":144,"props":886,"children":887},{"class":146,"line":589},[888],{"type":18,"tag":144,"props":889,"children":890},{},[891],{"type":24,"value":892},"    ports:\n",{"type":18,"tag":144,"props":894,"children":895},{"class":146,"line":617},[896],{"type":18,"tag":144,"props":897,"children":898},{},[899],{"type":24,"value":900},"      - '5678:5678'\n",{"type":18,"tag":144,"props":902,"children":903},{"class":146,"line":625},[904],{"type":18,"tag":144,"props":905,"children":906},{},[907],{"type":24,"value":908},"    volumes:\n",{"type":18,"tag":144,"props":910,"children":911},{"class":146,"line":649},[912],{"type":18,"tag":144,"props":913,"children":914},{},[915],{"type":24,"value":916},"      - ./data:/root/.n8n\n",{"type":18,"tag":144,"props":918,"children":919},{"class":146,"line":681},[920],{"type":18,"tag":144,"props":921,"children":922},{},[923],{"type":24,"value":924},"    environment:\n",{"type":18,"tag":144,"props":926,"children":927},{"class":146,"line":690},[928],{"type":18,"tag":144,"props":929,"children":930},{},[931],{"type":24,"value":932},"      # 允许http的方式登录\n",{"type":18,"tag":144,"props":934,"children":935},{"class":146,"line":704},[936],{"type":18,"tag":144,"props":937,"children":938},{},[939],{"type":24,"value":940},"      - N8N_SECURE_COOKIE=false\n",{"type":18,"tag":144,"props":942,"children":943},{"class":146,"line":713},[944],{"type":18,"tag":144,"props":945,"children":946},{},[947],{"type":24,"value":948},"      # 支持所有内部和外部的包\n",{"type":18,"tag":144,"props":950,"children":952},{"class":146,"line":951},15,[953],{"type":18,"tag":144,"props":954,"children":955},{},[956],{"type":24,"value":957},"      - NODE_FUNCTION_ALLOW_EXTERNAL=*\n",{"type":18,"tag":144,"props":959,"children":961},{"class":146,"line":960},16,[962],{"type":18,"tag":144,"props":963,"children":964},{},[965],{"type":24,"value":966},"      - NODE_FUNCTION_ALLOW_BUILTIN=*\n",{"type":18,"tag":26,"props":968,"children":969},{},[970],{"type":24,"value":971},"重启n8n之后，测试运行以下这个节点，输出也没问题：",{"type":18,"tag":26,"props":973,"children":974},{},[975],{"type":18,"tag":91,"props":976,"children":978},{"alt":7,"src":977},"https://johnhom-img.oss-cn-guangzhou.aliyuncs.com/obsidian/Pasted%20image%2020250123194522.png",[],{"type":18,"tag":26,"props":980,"children":981},{},[982],{"type":24,"value":983},"这个节点会自动把return的数据传给下一个节点，接下来就是拿到传入的ip然后通过ssh2来连接宿主机。",{"type":18,"tag":26,"props":985,"children":986},{},[987],{"type":24,"value":988},"我们继续创建新的Core节点，代码如下：",{"type":18,"tag":133,"props":990,"children":992},{"className":431,"code":991,"language":433,"meta":7,"style":7},"const { Client } = require('ssh2');\n\nconst conn = new Client();\n// n8n内部提供获取传入节点数据的方式，具体可以看\n// https://docs.n8n.io/code/builtin/current-node-input/\n// 这里拿到上一个节点写入的ip属性\nconst host = $json.ip;\nconst port = 22;\nconst username = 'root';\nconst password = 'xxxx';\n// docker镜像源的用户名\nconst dockerUser = 'xxxxx';\n// docker镜像源的密码\nconst dockerPassword = 'xxxx';\n\nconst loginCommand = `docker login -u ${dockerUser} -p ${dockerPassword} xxxx`;\nconst cdCommand = 'cd /volume1/docker/xxx';\nconst pullCommand = 'docker-compose pull';\nconst recreateCommand = 'docker-compose up -d --force-recreate';\nconst allCommand = `${loginCommand} && ${cdCommand} && ${pullCommand} && ${recreateCommand}`;\n\nreturn new Promise((resolve) => {\n  conn\n  .on('ready', () => {\n    console.log('Client :: ready');\n    conn.shell((err, stream) => {\n      stream\n        .on('close', (code, signal) => {\n          console.log('执行完成');\n          conn.end();\n        })\n        .on('data', (data) => {\n          console.log(data.toString());\n        })\n        .stderr.on('data', (data) => {\n          console.log('STDERR: ' + data);\n        });\n\n      //执行命令 \n      stream.write(allCommand + '\\n');\n      // 退出\n      stream.write('exit\\n');\n    });\n  }).on('close', () => {\n    resolve([\n      {\n        msg: 'success',\n        code: 0,\n      }\n    ]);\n  })\n  .connect({\n    host,\n    port,\n    username,\n    password,\n  });\n})\n\n",[993],{"type":18,"tag":140,"props":994,"children":995},{"__ignoreMap":7},[996,1037,1044,1073,1081,1089,1097,1118,1143,1168,1193,1201,1226,1234,1258,1265,1310,1336,1362,1388,1452,1460,1502,1511,1547,1573,1617,1626,1678,1704,1722,1731,1773,1800,1808,1849,1880,1889,1897,1906,1949,1958,1991,2000,2033,2047,2056,2075,2093,2102,2111,2120,2138,2147,2156,2165,2174,2183],{"type":18,"tag":144,"props":997,"children":998},{"class":146,"line":147},[999,1003,1007,1012,1016,1020,1024,1028,1033],{"type":18,"tag":144,"props":1000,"children":1001},{"style":443},[1002],{"type":24,"value":446},{"type":18,"tag":144,"props":1004,"children":1005},{"style":449},[1006],{"type":24,"value":452},{"type":18,"tag":144,"props":1008,"children":1009},{"style":320},[1010],{"type":24,"value":1011},"Client",{"type":18,"tag":144,"props":1013,"children":1014},{"style":449},[1015],{"type":24,"value":462},{"type":18,"tag":144,"props":1017,"children":1018},{"style":443},[1019],{"type":24,"value":467},{"type":18,"tag":144,"props":1021,"children":1022},{"style":151},[1023],{"type":24,"value":472},{"type":18,"tag":144,"props":1025,"children":1026},{"style":449},[1027],{"type":24,"value":477},{"type":18,"tag":144,"props":1029,"children":1030},{"style":157},[1031],{"type":24,"value":1032},"'ssh2'",{"type":18,"tag":144,"props":1034,"children":1035},{"style":449},[1036],{"type":24,"value":487},{"type":18,"tag":144,"props":1038,"children":1039},{"class":146,"line":284},[1040],{"type":18,"tag":144,"props":1041,"children":1042},{"emptyLinePlaceholder":493},[1043],{"type":24,"value":496},{"type":18,"tag":144,"props":1045,"children":1046},{"class":146,"line":298},[1047,1051,1056,1060,1064,1069],{"type":18,"tag":144,"props":1048,"children":1049},{"style":443},[1050],{"type":24,"value":446},{"type":18,"tag":144,"props":1052,"children":1053},{"style":320},[1054],{"type":24,"value":1055}," conn",{"type":18,"tag":144,"props":1057,"children":1058},{"style":443},[1059],{"type":24,"value":521},{"type":18,"tag":144,"props":1061,"children":1062},{"style":443},[1063],{"type":24,"value":660},{"type":18,"tag":144,"props":1065,"children":1066},{"style":151},[1067],{"type":24,"value":1068}," Client",{"type":18,"tag":144,"props":1070,"children":1071},{"style":449},[1072],{"type":24,"value":586},{"type":18,"tag":144,"props":1074,"children":1075},{"class":146,"line":307},[1076],{"type":18,"tag":144,"props":1077,"children":1078},{"style":278},[1079],{"type":24,"value":1080},"// n8n内部提供获取传入节点数据的方式，具体可以看\n",{"type":18,"tag":144,"props":1082,"children":1083},{"class":146,"line":534},[1084],{"type":18,"tag":144,"props":1085,"children":1086},{"style":278},[1087],{"type":24,"value":1088},"// https://docs.n8n.io/code/builtin/current-node-input/\n",{"type":18,"tag":144,"props":1090,"children":1091},{"class":146,"line":542},[1092],{"type":18,"tag":144,"props":1093,"children":1094},{"style":278},[1095],{"type":24,"value":1096},"// 这里拿到上一个节点写入的ip属性\n",{"type":18,"tag":144,"props":1098,"children":1099},{"class":146,"line":589},[1100,1104,1109,1113],{"type":18,"tag":144,"props":1101,"children":1102},{"style":443},[1103],{"type":24,"value":446},{"type":18,"tag":144,"props":1105,"children":1106},{"style":320},[1107],{"type":24,"value":1108}," host",{"type":18,"tag":144,"props":1110,"children":1111},{"style":443},[1112],{"type":24,"value":521},{"type":18,"tag":144,"props":1114,"children":1115},{"style":449},[1116],{"type":24,"value":1117}," $json.ip;\n",{"type":18,"tag":144,"props":1119,"children":1120},{"class":146,"line":617},[1121,1125,1130,1134,1139],{"type":18,"tag":144,"props":1122,"children":1123},{"style":443},[1124],{"type":24,"value":446},{"type":18,"tag":144,"props":1126,"children":1127},{"style":320},[1128],{"type":24,"value":1129}," port",{"type":18,"tag":144,"props":1131,"children":1132},{"style":443},[1133],{"type":24,"value":521},{"type":18,"tag":144,"props":1135,"children":1136},{"style":320},[1137],{"type":24,"value":1138}," 22",{"type":18,"tag":144,"props":1140,"children":1141},{"style":449},[1142],{"type":24,"value":531},{"type":18,"tag":144,"props":1144,"children":1145},{"class":146,"line":625},[1146,1150,1155,1159,1164],{"type":18,"tag":144,"props":1147,"children":1148},{"style":443},[1149],{"type":24,"value":446},{"type":18,"tag":144,"props":1151,"children":1152},{"style":320},[1153],{"type":24,"value":1154}," username",{"type":18,"tag":144,"props":1156,"children":1157},{"style":443},[1158],{"type":24,"value":521},{"type":18,"tag":144,"props":1160,"children":1161},{"style":157},[1162],{"type":24,"value":1163}," 'root'",{"type":18,"tag":144,"props":1165,"children":1166},{"style":449},[1167],{"type":24,"value":531},{"type":18,"tag":144,"props":1169,"children":1170},{"class":146,"line":649},[1171,1175,1180,1184,1189],{"type":18,"tag":144,"props":1172,"children":1173},{"style":443},[1174],{"type":24,"value":446},{"type":18,"tag":144,"props":1176,"children":1177},{"style":320},[1178],{"type":24,"value":1179}," password",{"type":18,"tag":144,"props":1181,"children":1182},{"style":443},[1183],{"type":24,"value":521},{"type":18,"tag":144,"props":1185,"children":1186},{"style":157},[1187],{"type":24,"value":1188}," 'xxxx'",{"type":18,"tag":144,"props":1190,"children":1191},{"style":449},[1192],{"type":24,"value":531},{"type":18,"tag":144,"props":1194,"children":1195},{"class":146,"line":681},[1196],{"type":18,"tag":144,"props":1197,"children":1198},{"style":278},[1199],{"type":24,"value":1200},"// docker镜像源的用户名\n",{"type":18,"tag":144,"props":1202,"children":1203},{"class":146,"line":690},[1204,1208,1213,1217,1222],{"type":18,"tag":144,"props":1205,"children":1206},{"style":443},[1207],{"type":24,"value":446},{"type":18,"tag":144,"props":1209,"children":1210},{"style":320},[1211],{"type":24,"value":1212}," dockerUser",{"type":18,"tag":144,"props":1214,"children":1215},{"style":443},[1216],{"type":24,"value":521},{"type":18,"tag":144,"props":1218,"children":1219},{"style":157},[1220],{"type":24,"value":1221}," 'xxxxx'",{"type":18,"tag":144,"props":1223,"children":1224},{"style":449},[1225],{"type":24,"value":531},{"type":18,"tag":144,"props":1227,"children":1228},{"class":146,"line":704},[1229],{"type":18,"tag":144,"props":1230,"children":1231},{"style":278},[1232],{"type":24,"value":1233},"// docker镜像源的密码\n",{"type":18,"tag":144,"props":1235,"children":1236},{"class":146,"line":713},[1237,1241,1246,1250,1254],{"type":18,"tag":144,"props":1238,"children":1239},{"style":443},[1240],{"type":24,"value":446},{"type":18,"tag":144,"props":1242,"children":1243},{"style":320},[1244],{"type":24,"value":1245}," dockerPassword",{"type":18,"tag":144,"props":1247,"children":1248},{"style":443},[1249],{"type":24,"value":521},{"type":18,"tag":144,"props":1251,"children":1252},{"style":157},[1253],{"type":24,"value":1188},{"type":18,"tag":144,"props":1255,"children":1256},{"style":449},[1257],{"type":24,"value":531},{"type":18,"tag":144,"props":1259,"children":1260},{"class":146,"line":951},[1261],{"type":18,"tag":144,"props":1262,"children":1263},{"emptyLinePlaceholder":493},[1264],{"type":24,"value":496},{"type":18,"tag":144,"props":1266,"children":1267},{"class":146,"line":960},[1268,1272,1277,1281,1286,1291,1296,1301,1306],{"type":18,"tag":144,"props":1269,"children":1270},{"style":443},[1271],{"type":24,"value":446},{"type":18,"tag":144,"props":1273,"children":1274},{"style":320},[1275],{"type":24,"value":1276}," loginCommand",{"type":18,"tag":144,"props":1278,"children":1279},{"style":443},[1280],{"type":24,"value":521},{"type":18,"tag":144,"props":1282,"children":1283},{"style":157},[1284],{"type":24,"value":1285}," `docker login -u ${",{"type":18,"tag":144,"props":1287,"children":1288},{"style":449},[1289],{"type":24,"value":1290},"dockerUser",{"type":18,"tag":144,"props":1292,"children":1293},{"style":157},[1294],{"type":24,"value":1295},"} -p ${",{"type":18,"tag":144,"props":1297,"children":1298},{"style":449},[1299],{"type":24,"value":1300},"dockerPassword",{"type":18,"tag":144,"props":1302,"children":1303},{"style":157},[1304],{"type":24,"value":1305},"} xxxx`",{"type":18,"tag":144,"props":1307,"children":1308},{"style":449},[1309],{"type":24,"value":531},{"type":18,"tag":144,"props":1311,"children":1313},{"class":146,"line":1312},17,[1314,1318,1323,1327,1332],{"type":18,"tag":144,"props":1315,"children":1316},{"style":443},[1317],{"type":24,"value":446},{"type":18,"tag":144,"props":1319,"children":1320},{"style":320},[1321],{"type":24,"value":1322}," cdCommand",{"type":18,"tag":144,"props":1324,"children":1325},{"style":443},[1326],{"type":24,"value":521},{"type":18,"tag":144,"props":1328,"children":1329},{"style":157},[1330],{"type":24,"value":1331}," 'cd /volume1/docker/xxx'",{"type":18,"tag":144,"props":1333,"children":1334},{"style":449},[1335],{"type":24,"value":531},{"type":18,"tag":144,"props":1337,"children":1339},{"class":146,"line":1338},18,[1340,1344,1349,1353,1358],{"type":18,"tag":144,"props":1341,"children":1342},{"style":443},[1343],{"type":24,"value":446},{"type":18,"tag":144,"props":1345,"children":1346},{"style":320},[1347],{"type":24,"value":1348}," pullCommand",{"type":18,"tag":144,"props":1350,"children":1351},{"style":443},[1352],{"type":24,"value":521},{"type":18,"tag":144,"props":1354,"children":1355},{"style":157},[1356],{"type":24,"value":1357}," 'docker-compose pull'",{"type":18,"tag":144,"props":1359,"children":1360},{"style":449},[1361],{"type":24,"value":531},{"type":18,"tag":144,"props":1363,"children":1365},{"class":146,"line":1364},19,[1366,1370,1375,1379,1384],{"type":18,"tag":144,"props":1367,"children":1368},{"style":443},[1369],{"type":24,"value":446},{"type":18,"tag":144,"props":1371,"children":1372},{"style":320},[1373],{"type":24,"value":1374}," recreateCommand",{"type":18,"tag":144,"props":1376,"children":1377},{"style":443},[1378],{"type":24,"value":521},{"type":18,"tag":144,"props":1380,"children":1381},{"style":157},[1382],{"type":24,"value":1383}," 'docker-compose up -d --force-recreate'",{"type":18,"tag":144,"props":1385,"children":1386},{"style":449},[1387],{"type":24,"value":531},{"type":18,"tag":144,"props":1389,"children":1391},{"class":146,"line":1390},20,[1392,1396,1401,1405,1410,1415,1420,1425,1429,1434,1438,1443,1448],{"type":18,"tag":144,"props":1393,"children":1394},{"style":443},[1395],{"type":24,"value":446},{"type":18,"tag":144,"props":1397,"children":1398},{"style":320},[1399],{"type":24,"value":1400}," allCommand",{"type":18,"tag":144,"props":1402,"children":1403},{"style":443},[1404],{"type":24,"value":521},{"type":18,"tag":144,"props":1406,"children":1407},{"style":157},[1408],{"type":24,"value":1409}," `${",{"type":18,"tag":144,"props":1411,"children":1412},{"style":449},[1413],{"type":24,"value":1414},"loginCommand",{"type":18,"tag":144,"props":1416,"children":1417},{"style":157},[1418],{"type":24,"value":1419},"} && ${",{"type":18,"tag":144,"props":1421,"children":1422},{"style":449},[1423],{"type":24,"value":1424},"cdCommand",{"type":18,"tag":144,"props":1426,"children":1427},{"style":157},[1428],{"type":24,"value":1419},{"type":18,"tag":144,"props":1430,"children":1431},{"style":449},[1432],{"type":24,"value":1433},"pullCommand",{"type":18,"tag":144,"props":1435,"children":1436},{"style":157},[1437],{"type":24,"value":1419},{"type":18,"tag":144,"props":1439,"children":1440},{"style":449},[1441],{"type":24,"value":1442},"recreateCommand",{"type":18,"tag":144,"props":1444,"children":1445},{"style":157},[1446],{"type":24,"value":1447},"}`",{"type":18,"tag":144,"props":1449,"children":1450},{"style":449},[1451],{"type":24,"value":531},{"type":18,"tag":144,"props":1453,"children":1455},{"class":146,"line":1454},21,[1456],{"type":18,"tag":144,"props":1457,"children":1458},{"emptyLinePlaceholder":493},[1459],{"type":24,"value":496},{"type":18,"tag":144,"props":1461,"children":1463},{"class":146,"line":1462},22,[1464,1468,1472,1477,1482,1488,1493,1498],{"type":18,"tag":144,"props":1465,"children":1466},{"style":443},[1467],{"type":24,"value":696},{"type":18,"tag":144,"props":1469,"children":1470},{"style":443},[1471],{"type":24,"value":660},{"type":18,"tag":144,"props":1473,"children":1474},{"style":320},[1475],{"type":24,"value":1476}," Promise",{"type":18,"tag":144,"props":1478,"children":1479},{"style":449},[1480],{"type":24,"value":1481},"((",{"type":18,"tag":144,"props":1483,"children":1485},{"style":1484},"--shiki-default:#FFAB70",[1486],{"type":24,"value":1487},"resolve",{"type":18,"tag":144,"props":1489,"children":1490},{"style":449},[1491],{"type":24,"value":1492},") ",{"type":18,"tag":144,"props":1494,"children":1495},{"style":443},[1496],{"type":24,"value":1497},"=>",{"type":18,"tag":144,"props":1499,"children":1500},{"style":449},[1501],{"type":24,"value":701},{"type":18,"tag":144,"props":1503,"children":1505},{"class":146,"line":1504},23,[1506],{"type":18,"tag":144,"props":1507,"children":1508},{"style":449},[1509],{"type":24,"value":1510},"  conn\n",{"type":18,"tag":144,"props":1512,"children":1514},{"class":146,"line":1513},24,[1515,1520,1525,1529,1534,1539,1543],{"type":18,"tag":144,"props":1516,"children":1517},{"style":449},[1518],{"type":24,"value":1519},"  .",{"type":18,"tag":144,"props":1521,"children":1522},{"style":151},[1523],{"type":24,"value":1524},"on",{"type":18,"tag":144,"props":1526,"children":1527},{"style":449},[1528],{"type":24,"value":477},{"type":18,"tag":144,"props":1530,"children":1531},{"style":157},[1532],{"type":24,"value":1533},"'ready'",{"type":18,"tag":144,"props":1535,"children":1536},{"style":449},[1537],{"type":24,"value":1538},", () ",{"type":18,"tag":144,"props":1540,"children":1541},{"style":443},[1542],{"type":24,"value":1497},{"type":18,"tag":144,"props":1544,"children":1545},{"style":449},[1546],{"type":24,"value":701},{"type":18,"tag":144,"props":1548,"children":1550},{"class":146,"line":1549},25,[1551,1556,1560,1564,1569],{"type":18,"tag":144,"props":1552,"children":1553},{"style":449},[1554],{"type":24,"value":1555},"    console.",{"type":18,"tag":144,"props":1557,"children":1558},{"style":151},[1559],{"type":24,"value":600},{"type":18,"tag":144,"props":1561,"children":1562},{"style":449},[1563],{"type":24,"value":477},{"type":18,"tag":144,"props":1565,"children":1566},{"style":157},[1567],{"type":24,"value":1568},"'Client :: ready'",{"type":18,"tag":144,"props":1570,"children":1571},{"style":449},[1572],{"type":24,"value":487},{"type":18,"tag":144,"props":1574,"children":1576},{"class":146,"line":1575},26,[1577,1582,1586,1590,1595,1600,1605,1609,1613],{"type":18,"tag":144,"props":1578,"children":1579},{"style":449},[1580],{"type":24,"value":1581},"    conn.",{"type":18,"tag":144,"props":1583,"children":1584},{"style":151},[1585],{"type":24,"value":268},{"type":18,"tag":144,"props":1587,"children":1588},{"style":449},[1589],{"type":24,"value":1481},{"type":18,"tag":144,"props":1591,"children":1592},{"style":1484},[1593],{"type":24,"value":1594},"err",{"type":18,"tag":144,"props":1596,"children":1597},{"style":449},[1598],{"type":24,"value":1599},", ",{"type":18,"tag":144,"props":1601,"children":1602},{"style":1484},[1603],{"type":24,"value":1604},"stream",{"type":18,"tag":144,"props":1606,"children":1607},{"style":449},[1608],{"type":24,"value":1492},{"type":18,"tag":144,"props":1610,"children":1611},{"style":443},[1612],{"type":24,"value":1497},{"type":18,"tag":144,"props":1614,"children":1615},{"style":449},[1616],{"type":24,"value":701},{"type":18,"tag":144,"props":1618,"children":1620},{"class":146,"line":1619},27,[1621],{"type":18,"tag":144,"props":1622,"children":1623},{"style":449},[1624],{"type":24,"value":1625},"      stream\n",{"type":18,"tag":144,"props":1627,"children":1629},{"class":146,"line":1628},28,[1630,1635,1639,1643,1648,1653,1657,1661,1666,1670,1674],{"type":18,"tag":144,"props":1631,"children":1632},{"style":449},[1633],{"type":24,"value":1634},"        .",{"type":18,"tag":144,"props":1636,"children":1637},{"style":151},[1638],{"type":24,"value":1524},{"type":18,"tag":144,"props":1640,"children":1641},{"style":449},[1642],{"type":24,"value":477},{"type":18,"tag":144,"props":1644,"children":1645},{"style":157},[1646],{"type":24,"value":1647},"'close'",{"type":18,"tag":144,"props":1649,"children":1650},{"style":449},[1651],{"type":24,"value":1652},", (",{"type":18,"tag":144,"props":1654,"children":1655},{"style":1484},[1656],{"type":24,"value":140},{"type":18,"tag":144,"props":1658,"children":1659},{"style":449},[1660],{"type":24,"value":1599},{"type":18,"tag":144,"props":1662,"children":1663},{"style":1484},[1664],{"type":24,"value":1665},"signal",{"type":18,"tag":144,"props":1667,"children":1668},{"style":449},[1669],{"type":24,"value":1492},{"type":18,"tag":144,"props":1671,"children":1672},{"style":443},[1673],{"type":24,"value":1497},{"type":18,"tag":144,"props":1675,"children":1676},{"style":449},[1677],{"type":24,"value":701},{"type":18,"tag":144,"props":1679,"children":1681},{"class":146,"line":1680},29,[1682,1687,1691,1695,1700],{"type":18,"tag":144,"props":1683,"children":1684},{"style":449},[1685],{"type":24,"value":1686},"          console.",{"type":18,"tag":144,"props":1688,"children":1689},{"style":151},[1690],{"type":24,"value":600},{"type":18,"tag":144,"props":1692,"children":1693},{"style":449},[1694],{"type":24,"value":477},{"type":18,"tag":144,"props":1696,"children":1697},{"style":157},[1698],{"type":24,"value":1699},"'执行完成'",{"type":18,"tag":144,"props":1701,"children":1702},{"style":449},[1703],{"type":24,"value":487},{"type":18,"tag":144,"props":1705,"children":1707},{"class":146,"line":1706},30,[1708,1713,1718],{"type":18,"tag":144,"props":1709,"children":1710},{"style":449},[1711],{"type":24,"value":1712},"          conn.",{"type":18,"tag":144,"props":1714,"children":1715},{"style":151},[1716],{"type":24,"value":1717},"end",{"type":18,"tag":144,"props":1719,"children":1720},{"style":449},[1721],{"type":24,"value":586},{"type":18,"tag":144,"props":1723,"children":1725},{"class":146,"line":1724},31,[1726],{"type":18,"tag":144,"props":1727,"children":1728},{"style":449},[1729],{"type":24,"value":1730},"        })\n",{"type":18,"tag":144,"props":1732,"children":1734},{"class":146,"line":1733},32,[1735,1739,1743,1747,1752,1756,1761,1765,1769],{"type":18,"tag":144,"props":1736,"children":1737},{"style":449},[1738],{"type":24,"value":1634},{"type":18,"tag":144,"props":1740,"children":1741},{"style":151},[1742],{"type":24,"value":1524},{"type":18,"tag":144,"props":1744,"children":1745},{"style":449},[1746],{"type":24,"value":477},{"type":18,"tag":144,"props":1748,"children":1749},{"style":157},[1750],{"type":24,"value":1751},"'data'",{"type":18,"tag":144,"props":1753,"children":1754},{"style":449},[1755],{"type":24,"value":1652},{"type":18,"tag":144,"props":1757,"children":1758},{"style":1484},[1759],{"type":24,"value":1760},"data",{"type":18,"tag":144,"props":1762,"children":1763},{"style":449},[1764],{"type":24,"value":1492},{"type":18,"tag":144,"props":1766,"children":1767},{"style":443},[1768],{"type":24,"value":1497},{"type":18,"tag":144,"props":1770,"children":1771},{"style":449},[1772],{"type":24,"value":701},{"type":18,"tag":144,"props":1774,"children":1776},{"class":146,"line":1775},33,[1777,1781,1785,1790,1795],{"type":18,"tag":144,"props":1778,"children":1779},{"style":449},[1780],{"type":24,"value":1686},{"type":18,"tag":144,"props":1782,"children":1783},{"style":151},[1784],{"type":24,"value":600},{"type":18,"tag":144,"props":1786,"children":1787},{"style":449},[1788],{"type":24,"value":1789},"(data.",{"type":18,"tag":144,"props":1791,"children":1792},{"style":151},[1793],{"type":24,"value":1794},"toString",{"type":18,"tag":144,"props":1796,"children":1797},{"style":449},[1798],{"type":24,"value":1799},"());\n",{"type":18,"tag":144,"props":1801,"children":1803},{"class":146,"line":1802},34,[1804],{"type":18,"tag":144,"props":1805,"children":1806},{"style":449},[1807],{"type":24,"value":1730},{"type":18,"tag":144,"props":1809,"children":1811},{"class":146,"line":1810},35,[1812,1817,1821,1825,1829,1833,1837,1841,1845],{"type":18,"tag":144,"props":1813,"children":1814},{"style":449},[1815],{"type":24,"value":1816},"        .stderr.",{"type":18,"tag":144,"props":1818,"children":1819},{"style":151},[1820],{"type":24,"value":1524},{"type":18,"tag":144,"props":1822,"children":1823},{"style":449},[1824],{"type":24,"value":477},{"type":18,"tag":144,"props":1826,"children":1827},{"style":157},[1828],{"type":24,"value":1751},{"type":18,"tag":144,"props":1830,"children":1831},{"style":449},[1832],{"type":24,"value":1652},{"type":18,"tag":144,"props":1834,"children":1835},{"style":1484},[1836],{"type":24,"value":1760},{"type":18,"tag":144,"props":1838,"children":1839},{"style":449},[1840],{"type":24,"value":1492},{"type":18,"tag":144,"props":1842,"children":1843},{"style":443},[1844],{"type":24,"value":1497},{"type":18,"tag":144,"props":1846,"children":1847},{"style":449},[1848],{"type":24,"value":701},{"type":18,"tag":144,"props":1850,"children":1852},{"class":146,"line":1851},36,[1853,1857,1861,1865,1870,1875],{"type":18,"tag":144,"props":1854,"children":1855},{"style":449},[1856],{"type":24,"value":1686},{"type":18,"tag":144,"props":1858,"children":1859},{"style":151},[1860],{"type":24,"value":600},{"type":18,"tag":144,"props":1862,"children":1863},{"style":449},[1864],{"type":24,"value":477},{"type":18,"tag":144,"props":1866,"children":1867},{"style":157},[1868],{"type":24,"value":1869},"'STDERR: '",{"type":18,"tag":144,"props":1871,"children":1872},{"style":443},[1873],{"type":24,"value":1874}," +",{"type":18,"tag":144,"props":1876,"children":1877},{"style":449},[1878],{"type":24,"value":1879}," data);\n",{"type":18,"tag":144,"props":1881,"children":1883},{"class":146,"line":1882},37,[1884],{"type":18,"tag":144,"props":1885,"children":1886},{"style":449},[1887],{"type":24,"value":1888},"        });\n",{"type":18,"tag":144,"props":1890,"children":1892},{"class":146,"line":1891},38,[1893],{"type":18,"tag":144,"props":1894,"children":1895},{"emptyLinePlaceholder":493},[1896],{"type":24,"value":496},{"type":18,"tag":144,"props":1898,"children":1900},{"class":146,"line":1899},39,[1901],{"type":18,"tag":144,"props":1902,"children":1903},{"style":278},[1904],{"type":24,"value":1905},"      //执行命令 \n",{"type":18,"tag":144,"props":1907,"children":1909},{"class":146,"line":1908},40,[1910,1915,1920,1925,1930,1935,1940,1945],{"type":18,"tag":144,"props":1911,"children":1912},{"style":449},[1913],{"type":24,"value":1914},"      stream.",{"type":18,"tag":144,"props":1916,"children":1917},{"style":151},[1918],{"type":24,"value":1919},"write",{"type":18,"tag":144,"props":1921,"children":1922},{"style":449},[1923],{"type":24,"value":1924},"(allCommand ",{"type":18,"tag":144,"props":1926,"children":1927},{"style":443},[1928],{"type":24,"value":1929},"+",{"type":18,"tag":144,"props":1931,"children":1932},{"style":157},[1933],{"type":24,"value":1934}," '",{"type":18,"tag":144,"props":1936,"children":1937},{"style":320},[1938],{"type":24,"value":1939},"\\n",{"type":18,"tag":144,"props":1941,"children":1942},{"style":157},[1943],{"type":24,"value":1944},"'",{"type":18,"tag":144,"props":1946,"children":1947},{"style":449},[1948],{"type":24,"value":487},{"type":18,"tag":144,"props":1950,"children":1952},{"class":146,"line":1951},41,[1953],{"type":18,"tag":144,"props":1954,"children":1955},{"style":278},[1956],{"type":24,"value":1957},"      // 退出\n",{"type":18,"tag":144,"props":1959,"children":1961},{"class":146,"line":1960},42,[1962,1966,1970,1974,1979,1983,1987],{"type":18,"tag":144,"props":1963,"children":1964},{"style":449},[1965],{"type":24,"value":1914},{"type":18,"tag":144,"props":1967,"children":1968},{"style":151},[1969],{"type":24,"value":1919},{"type":18,"tag":144,"props":1971,"children":1972},{"style":449},[1973],{"type":24,"value":477},{"type":18,"tag":144,"props":1975,"children":1976},{"style":157},[1977],{"type":24,"value":1978},"'exit",{"type":18,"tag":144,"props":1980,"children":1981},{"style":320},[1982],{"type":24,"value":1939},{"type":18,"tag":144,"props":1984,"children":1985},{"style":157},[1986],{"type":24,"value":1944},{"type":18,"tag":144,"props":1988,"children":1989},{"style":449},[1990],{"type":24,"value":487},{"type":18,"tag":144,"props":1992,"children":1994},{"class":146,"line":1993},43,[1995],{"type":18,"tag":144,"props":1996,"children":1997},{"style":449},[1998],{"type":24,"value":1999},"    });\n",{"type":18,"tag":144,"props":2001,"children":2003},{"class":146,"line":2002},44,[2004,2009,2013,2017,2021,2025,2029],{"type":18,"tag":144,"props":2005,"children":2006},{"style":449},[2007],{"type":24,"value":2008},"  }).",{"type":18,"tag":144,"props":2010,"children":2011},{"style":151},[2012],{"type":24,"value":1524},{"type":18,"tag":144,"props":2014,"children":2015},{"style":449},[2016],{"type":24,"value":477},{"type":18,"tag":144,"props":2018,"children":2019},{"style":157},[2020],{"type":24,"value":1647},{"type":18,"tag":144,"props":2022,"children":2023},{"style":449},[2024],{"type":24,"value":1538},{"type":18,"tag":144,"props":2026,"children":2027},{"style":443},[2028],{"type":24,"value":1497},{"type":18,"tag":144,"props":2030,"children":2031},{"style":449},[2032],{"type":24,"value":701},{"type":18,"tag":144,"props":2034,"children":2036},{"class":146,"line":2035},45,[2037,2042],{"type":18,"tag":144,"props":2038,"children":2039},{"style":151},[2040],{"type":24,"value":2041},"    resolve",{"type":18,"tag":144,"props":2043,"children":2044},{"style":449},[2045],{"type":24,"value":2046},"([\n",{"type":18,"tag":144,"props":2048,"children":2050},{"class":146,"line":2049},46,[2051],{"type":18,"tag":144,"props":2052,"children":2053},{"style":449},[2054],{"type":24,"value":2055},"      {\n",{"type":18,"tag":144,"props":2057,"children":2059},{"class":146,"line":2058},47,[2060,2065,2070],{"type":18,"tag":144,"props":2061,"children":2062},{"style":449},[2063],{"type":24,"value":2064},"        msg: ",{"type":18,"tag":144,"props":2066,"children":2067},{"style":157},[2068],{"type":24,"value":2069},"'success'",{"type":18,"tag":144,"props":2071,"children":2072},{"style":449},[2073],{"type":24,"value":2074},",\n",{"type":18,"tag":144,"props":2076,"children":2078},{"class":146,"line":2077},48,[2079,2084,2089],{"type":18,"tag":144,"props":2080,"children":2081},{"style":449},[2082],{"type":24,"value":2083},"        code: ",{"type":18,"tag":144,"props":2085,"children":2086},{"style":320},[2087],{"type":24,"value":2088},"0",{"type":18,"tag":144,"props":2090,"children":2091},{"style":449},[2092],{"type":24,"value":2074},{"type":18,"tag":144,"props":2094,"children":2096},{"class":146,"line":2095},49,[2097],{"type":18,"tag":144,"props":2098,"children":2099},{"style":449},[2100],{"type":24,"value":2101},"      }\n",{"type":18,"tag":144,"props":2103,"children":2105},{"class":146,"line":2104},50,[2106],{"type":18,"tag":144,"props":2107,"children":2108},{"style":449},[2109],{"type":24,"value":2110},"    ]);\n",{"type":18,"tag":144,"props":2112,"children":2114},{"class":146,"line":2113},51,[2115],{"type":18,"tag":144,"props":2116,"children":2117},{"style":449},[2118],{"type":24,"value":2119},"  })\n",{"type":18,"tag":144,"props":2121,"children":2123},{"class":146,"line":2122},52,[2124,2128,2133],{"type":18,"tag":144,"props":2125,"children":2126},{"style":449},[2127],{"type":24,"value":1519},{"type":18,"tag":144,"props":2129,"children":2130},{"style":151},[2131],{"type":24,"value":2132},"connect",{"type":18,"tag":144,"props":2134,"children":2135},{"style":449},[2136],{"type":24,"value":2137},"({\n",{"type":18,"tag":144,"props":2139,"children":2141},{"class":146,"line":2140},53,[2142],{"type":18,"tag":144,"props":2143,"children":2144},{"style":449},[2145],{"type":24,"value":2146},"    host,\n",{"type":18,"tag":144,"props":2148,"children":2150},{"class":146,"line":2149},54,[2151],{"type":18,"tag":144,"props":2152,"children":2153},{"style":449},[2154],{"type":24,"value":2155},"    port,\n",{"type":18,"tag":144,"props":2157,"children":2159},{"class":146,"line":2158},55,[2160],{"type":18,"tag":144,"props":2161,"children":2162},{"style":449},[2163],{"type":24,"value":2164},"    username,\n",{"type":18,"tag":144,"props":2166,"children":2168},{"class":146,"line":2167},56,[2169],{"type":18,"tag":144,"props":2170,"children":2171},{"style":449},[2172],{"type":24,"value":2173},"    password,\n",{"type":18,"tag":144,"props":2175,"children":2177},{"class":146,"line":2176},57,[2178],{"type":18,"tag":144,"props":2179,"children":2180},{"style":449},[2181],{"type":24,"value":2182},"  });\n",{"type":18,"tag":144,"props":2184,"children":2186},{"class":146,"line":2185},58,[2187],{"type":18,"tag":144,"props":2188,"children":2189},{"style":449},[2190],{"type":24,"value":2191},"})\n",{"type":18,"tag":26,"props":2193,"children":2194},{},[2195],{"type":24,"value":2196},"测试一下试试：",{"type":18,"tag":26,"props":2198,"children":2199},{},[2200],{"type":18,"tag":91,"props":2201,"children":2203},{"alt":7,"src":2202},"https://johnhom-img.oss-cn-guangzhou.aliyuncs.com/obsidian/Pasted%20image%2020250123195725.png",[],{"type":18,"tag":26,"props":2205,"children":2206},{},[2207],{"type":24,"value":2208},"也是顺利执行完成，在nas管理页面也看到镜像拉取到最新的版本，并且自动重新启动了。",{"type":18,"tag":26,"props":2210,"children":2211},{},[2212],{"type":24,"value":2213},"最后我加上发送邮件的节点，运行到这个节点就给我的邮箱发送邮件通知，这个节点搭建也比较简单，我这边就不展示了。",{"type":18,"tag":26,"props":2215,"children":2216},{},[2217],{"type":24,"value":2218},"目前我的重启容器工作流如下：",{"type":18,"tag":26,"props":2220,"children":2221},{},[2222],{"type":18,"tag":91,"props":2223,"children":2225},{"alt":7,"src":2224},"https://johnhom-img.oss-cn-guangzhou.aliyuncs.com/obsidian/Pasted%20image%2020250123200211.png",[],{"type":18,"tag":26,"props":2227,"children":2228},{},[2229],{"type":24,"value":2230},"触发的方式就是直接请求从Webhook节点里拿到的生产环境url：",{"type":18,"tag":26,"props":2232,"children":2233},{},[2234],{"type":18,"tag":91,"props":2235,"children":2237},{"alt":7,"src":2236},"https://johnhom-img.oss-cn-guangzhou.aliyuncs.com/obsidian/Pasted%20image%2020250123200336.png",[],{"type":18,"tag":26,"props":2239,"children":2240},{},[2241,2243,2249],{"type":24,"value":2242},"当ci的docker镜像构建完之后，就可以通过",{"type":18,"tag":140,"props":2244,"children":2246},{"className":2245},[],[2247],{"type":24,"value":2248},"curl \u003Cwebhook_url>",{"type":24,"value":2250},"的方式触发nas拉取镜像并重启容器。",{"type":18,"tag":26,"props":2252,"children":2253},{},[2254],{"type":24,"value":2255},"其实还需要实现一个步骤就是内网穿透，需要把这个webhook_url暴露给外网环境，否则只能在内网里触发webhook。目前碍于篇幅的原因，我就不在这篇文章里展开啦。",{"type":18,"tag":19,"props":2257,"children":2259},{"id":2258},"总结",[2260],{"type":24,"value":2258},{"type":18,"tag":26,"props":2262,"children":2263},{},[2264],{"type":24,"value":2265},"经过以上的步骤，已经大致摸清了n8n这个自动化工具的使用流程。它的用户界面让我印象特别深刻，特别的简洁明了，让人一目了然整个工作流的执行顺序和操作流程，让一个没使用过的人都能轻易上手创建工作流。",{"type":18,"tag":26,"props":2267,"children":2268},{},[2269],{"type":24,"value":2270},"不仅如此，这个工具内置了许多的触发器和节点类型，功能已经相当完善，可以满足大多数人的使用需求。在官方的示例中，甚至可以跟AI结合，接收excel表格并按要求处理后导出，还有更多强大的功能等待着我们去发现和发掘。",{"type":18,"tag":26,"props":2272,"children":2273},{},[2274],{"type":24,"value":2275},"在使用过程中，我也发现了一些问题：",{"type":18,"tag":32,"props":2277,"children":2278},{},[2279,2284],{"type":18,"tag":36,"props":2280,"children":2281},{},[2282],{"type":24,"value":2283},"代码节点运行js时，只能运行cjs规范的代码，目前暂不支持esm规范。",{"type":18,"tag":36,"props":2285,"children":2286},{},[2287],{"type":24,"value":2288},"能作为触发器的app基本都是海外，国内的还未适配。",{"type":18,"tag":26,"props":2290,"children":2291},{},[2292],{"type":24,"value":2293},"但是这并不影响我对这款工具的喜爱。",{"type":18,"tag":26,"props":2295,"children":2296},{},[2297],{"type":24,"value":2298},"希望后面能够引入AI助手，我们只需要动动嘴，AI就会帮我们创建好工作流。",{"type":18,"tag":26,"props":2300,"children":2301},{},[2302],{"type":24,"value":2303},"这样不就更加接近漫威世界里钢铁侠的贾维斯了？",{"type":18,"tag":2305,"props":2306,"children":2307},"style",{},[2308],{"type":24,"value":2309},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":7,"searchDepth":284,"depth":284,"links":2311},[2312,2313,2314],{"id":21,"depth":284,"text":21},{"id":114,"depth":284,"text":114},{"id":2258,"depth":284,"text":2258},"markdown","content:articles:20250122.md","content","articles/20250122.md","md",1772793492640]