This is the full developer documentation for Doc Record # Doc Record > 容器、集群、操作系统、网络与开发工具的实践记录 ## 主要分类 [Section titled “主要分类”](#主要分类) [Docker](/zh-cn/category/docker/) [Kubernetes](/zh-cn/category/kubernetes/) [操作系统](/zh-cn/category/os/) [中间件](/zh-cn/category/middleware/) [编程语言](/zh-cn/category/lang/) [网络](/zh-cn/category/network/) [工具](/zh-cn/category/tools/) [AI](/zh-cn/category/ai/) [资料](/zh-cn/category/materiel/) # Cloudflare AI Search MCP 使用记录 [官方文档](https://developers.cloudflare.com/ai-search/api/search/mcp/) ## 项目级配置 [Section titled “项目级配置”](#项目级配置) 当前项目已在 `.claude/settings.json` 中接入 Cloudflare AI Search MCP: ```json { "mcpServers": { "cloudflare-ai-search": { "type": "http", "url": "https://b9b71958-6156-440e-a28f-b4105ff6a50c.search.ai.cloudflare.com/mcp" } } } ``` ## 用途 [Section titled “用途”](#用途) 把 Cloudflare AI Search 作为 Claude Code 的 MCP server 使用,让 Claude 可以直接通过 MCP 调用远端搜索能力。 当前 endpoint: ```text https://b9b71958-6156-440e-a28f-b4105ff6a50c.search.ai.cloudflare.com/mcp ``` ## 前提 [Section titled “前提”](#前提) 1. 先在 Cloudflare 中创建 AI Search 实例 2. 给实例导入或同步需要搜索的内容 3. 在实例设置中开启 Public Endpoint 4. 拿到实例对应的 MCP endpoint ## 调用方式 [Section titled “调用方式”](#调用方式) 该 endpoint 暴露 MCP tool,核心是 `search`。 JSON-RPC 调用示例: ```bash curl https://b9b71958-6156-440e-a28f-b4105ff6a50c.search.ai.cloudflare.com/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "search", "arguments": { "query": "How do I configure AI Search?" } } }' ``` ## 在 Claude Code 中使用 [Section titled “在 Claude Code 中使用”](#在-claude-code-中使用) 项目打开后,Claude Code 会读取项目级 `.claude/settings.json`,把 `cloudflare-ai-search` 注册为 MCP server。 后续可以直接让 Claude: * 搜索 Cloudflare AI Search 索引内容 * 用 MCP tool 查询指定主题 * 结合本地仓库内容一起回答问题 ## 备注 [Section titled “备注”](#备注) * 当前文档页记录的是项目内固定接入的 endpoint * 如果后续更换 Cloudflare AI Search 实例,只需要同步更新 `.claude/settings.json` * 如果该索引内容是公开可访问内容,启用 Public Endpoint 会更方便;如果内容涉及私有数据,要先确认暴露范围 # postgres使用记录 [官方文档](https://github.com/modelcontextprotocol/servers/tree/main/src/postgres) * docker方式 ```bash { "mcpServers": { "postgres": { "command": "docker", "args": [ "run", "-i", "--rm", "mcp/postgres", "postgresql://host.docker.internal:5432/mydb"] } } } ``` # 项目开发相关记录 ## 软链接 [Section titled “软链接”](#软链接) ```bash # AGENTS.md:源文件 # CLAUDE.md:目标链接 ln -s AGENTS.md CLAUDE.md ``` # 提示词 ## AI IDE [Section titled “AI IDE”](#ai-ide) [相关文章](https://mp.weixin.qq.com/s/fcCGnVYm7LV_67UimUcq5A) ```text 如果你觉得这些提示语还不能完全 cover 你的需求,你还可以把插件下载到本地,替换成自己喜欢的提示语。 也可以从下面这两个网址淘淘宝: 提示词1:https://cursor.directory/ 提示词2:https://cursorlist.com/ 这里我还想额外介绍一个提示语小技巧: 给已有的提示语追加上下面一个规则 Research in English , respond in English, also follow by Chinese 这样一来,模型在搜索资源和思考时会默认使用英语,回复就转换成中文。 如果想再灵活一点,那就 reply in query language,这样你问其他语言的时候,模型照样能 Cover。(技巧来源 @eviljer) ``` ```plaintext 你帮忙按照生产级标准去帮我优化下吧,然后,再跑下workflow 对抗式review下,直到收敛到生产级最优方案 ``` ```plaintext 生产级标准, 以及简化用户主动操作步骤 ``` # Skill Maintenance — 项目级技能规范化 > Use when 用户要求优化、精简、规范化、审查或重写项目内 .claude/skills/*/SKILL.md; 或要求把某次流程沉淀成项目级 skill。目标是让 skill 可预测、低重复、可维护。 ## 边界 [Section titled “边界”](#边界) * 只改 `.claude/skills/**/SKILL.md` 及必要的同级参考文件;不改应用代码、CI 逻辑或业务文档。 * skill 的目标是**可预测执行**,不是写长手册;每条规则必须改变 agent 行为。 * 项目事实 / SOP 优先落在项目 Git;用户偏好才进 memory。 * 借鉴 lean prompt 原则:指令只写一次、删重复、保留成功标准和关键 caveat。 ## 流程 [Section titled “流程”](#流程) ```mermaid flowchart TD A[确定要维护的 skill 范围] --> B[读取当前 SKILL.md] B --> C[查找可用辅助 skill] C --> D[用 writing-great-skills 标准审查] D --> E[识别 duplication/sediment/sprawl/no-op] E --> F[重写为 lean 结构] F --> G[运行结构和 diff 检查] G --> H{是否符合完成标准?} H -->|否| E H -->|是| I[提交或汇报未提交状态] ``` ## 必跑步骤 [Section titled “必跑步骤”](#必跑步骤) ### 1. 选择范围 [Section titled “1. 选择范围”](#1-选择范围) ```bash find /.claude/skills -path '*/SKILL.md' -print ``` 先确认用户要改的是:单个 skill、同类 skill、还是把流程沉淀为根目录项目级 skill。 ### 2. 读取规范来源 [Section titled “2. 读取规范来源”](#2-读取规范来源) 优先使用这些辅助: * `writing-great-skills`:skill 规范性标准,重点看 predictability、single source of truth、pruning、failure modes。 * `code-simplifier` / `ponytail`:找重复、过期示例、可删段落。 * 外部 prompt 指南仅作为参考;落地时以项目约束和可验证完成标准为准。 ### 3. Lean 结构模板 [Section titled “3. Lean 结构模板”](#3-lean-结构模板) 优先写成: ```text frontmatter # Skill Name ## 边界 ## 流程(mermaid flowchart TD) ## 必跑步骤 ## 失败诊断不变量 / Red Flags ## 完成标准 / 相关文件 ``` 按需保留项目专项检查;不要保留示例对话、长背景、重复版本规则、过期命令输出。 ### 4. Pruning 检查 [Section titled “4. Pruning 检查”](#4-pruning-检查) 逐段判断: | 问题 | 处理 | | -------------------- | ------------------------------------- | | 同一意思出现两次 | 保留最靠近执行点的一处 | | 背景叙事不影响动作 | 删除 | | 示例会随版本过期 | 改成模板或删掉 | | 命令和规则冲突 | 以更可验证、更近期的规则为准 | | 只有“不要做 X” | 改成“做 Y;X 仅作为 hard guardrail” | | 大段 reference 只在少数分支用 | 下沉到同级参考文件,并在主 skill 放 context pointer | ### 5. Flowchart 要求 [Section titled “5. Flowchart 要求”](#5-flowchart-要求) * 用 `mermaid` + `flowchart TD`。 * 图只放结构、状态、决策和回环;不要塞日志、命令、长解释。 * 图里的每个终点都要能映射到“成功 / 失败诊断 / 汇报”。 ### 6. 完成标准 [Section titled “6. 完成标准”](#6-完成标准) 必须全部满足: ```bash # 格式检查 git diff --check -- # 结构检查(按需脚本化) # - 有 frontmatter # - description 是触发条件,不是流程正文 # - 恰好一个主要 mermaid flowchart TD # - 无 TODO、示例沉积、过期轮询文案 # - 行数合理;频繁触发 skill 通常应 < 180 行 ``` 语义标准: * 触发边界清楚:什么时候用、什么时候不用。 * 每个步骤有可检查完成条件。 * 失败诊断要求引用原始证据,不允许只凭猜测。 * Public surface / destructive 操作有确认或交给用户执行的边界。 * 项目专项风险保留为不变量,不被“精简”删掉。 ## Red Flags [Section titled “Red Flags”](#red-flags) * “先把所有细节都写进去保险”——会造成 sprawl 和 context load。 * “示例对话有帮助,留着吧”——多数会过期;保留命令模板即可。 * “description 写完整流程”——错,description 只负责触发。 * “只要短就好”——错;不能删成功标准、失败证据要求、项目 hard guardrail。 * “外部指南说精简,所以删项目特例”——错;项目不变量优先。 ## 汇报模板 [Section titled “汇报模板”](#汇报模板) ```text 已优化 个 skill: - : <主要结构变化> - : <主要结构变化> 验证:git diff --check 通过;结构检查通过。 未提交/已提交:。 ``` # Mihomo SSH Config Alias Support ## 🔗 项目信息 [Section titled “🔗 项目信息”](#-项目信息) * **Fork 仓库**: * **分支**: (请确保查看包含 `ssh-config-alias` 功能的分支, 例如: `ssh_system_v1.19.17`) * **核心文件**: `adapter/outbound/ssh.go`, `adapter/outbound/ssh_system.go` ## 📖 需求背景 [Section titled “📖 需求背景”](#-需求背景) 在复杂的网络环境中,用户往往已经维护了一套完善的 SSH 配置文件 (`~/.ssh/config`)。这些配置可能包含: 1. **ProxyJump (跳板机)**:需要通过一台或多台跳板机才能访问目标内网服务器。 2. **ProxyCommand**:使用第三方认证工具(如 Cloudflare Access, AWS SSM)建立连接。 3. **IdentityFile**:针对不同主机使用不同的密钥文件。 4. **Host 别名**:使用简短的别名代替长 IP 或域名。 原有的 Mihomo SSH 适配器使用 Go 语言原生 SSH 库,无法直接利用这些系统级配置,导致用户必须把复杂的跳板逻辑手动转化为 Mihomo 的代理链(Dialer Proxy),配置繁琐且不支持部分高级指令(如特殊的 ProxyCommand)。 **目标**:让 Mihomo 可以直接”借用”系统 SSH 客户端的能力,只需填一个主机别名(如 `my-server`),剩下的认证、跳转全交给系统 SSH 处理。 ## ✨ 功能特性 [Section titled “✨ 功能特性”](#-功能特性) ### 1. 完整 SSH Config 支持 [Section titled “1. 完整 SSH Config 支持”](#1-完整-ssh-config-支持) 通过调用系统 `ssh` 命令建立隧道,Mihomo 可以支持系统 SSH 客户端支持的所有指令: * ✅ `ProxyJump` / `JumpHost` * ✅ `ProxyCommand` (支持 cloudflared, nc 等) * ✅ `IdentityFile`, `User`, `Port` 等自动读取 * ✅ `Match`, `Include` 等高级配置逻辑 ### 2. 智能用户切换 (`sudo -u`) [Section titled “2. 智能用户切换 (sudo -u)”](#2-智能用户切换-sudo--u) Mihomo 通常以 **root** 权限运行(为了 TUN 模式等),而用户的 SSH 配置位于普通用户目录下。本功能实现了: * 自动检测或指定实际用户。 * 使用 `sudo -u -i` 切换身份执行 SSH。 * **`-i` 参数**确保加载用户的完整登录环境(`PATH`),保证 `cloudflared` 等命令可被找到。 ### 3. 零配置密钥 [Section titled “3. 零配置密钥”](#3-零配置密钥) 无需在 Mihomo 配置文件中填入私钥内容,它会自动读取 `~/.ssh/id_rsa` 或配置中指定的 `IdentityFile`。 ## 🚀 使用方式 [Section titled “🚀 使用方式”](#-使用方式) ### 参数说明 [Section titled “参数说明”](#参数说明) | 字段 | 说明 | | ---------------------- | ------------------------------------------------------------------- | | `type` | 必须为 `ssh` | | `server` | **关键**:填写 `~/.ssh/config` 中的 `Host` 别名 | | `port` | **注意**:填写目标服务**内部**监听端口(通常是 **22**)。 ⚠️ 不要填 `~/.ssh/config` 中的映射端口。 | | `use-ssh-config-alias` | 设置为 `true` 开启此功能 | | `ssh-user` | 指定本地执行 SSH 命令的用户名(你的 macOS/Linux 用户名) | ### 配置示例 [Section titled “配置示例”](#配置示例) #### 场景 1:基础跳板机 (ProxyJump) [Section titled “场景 1:基础跳板机 (ProxyJump)”](#场景-1基础跳板机-proxyjump) **SSH Config (`~/.ssh/config`)**: ```ssh-config Host bastion HostName 1.2.3.4 User admin Host internal-db HostName 10.0.0.5 User root ProxyJump bastion # 自动经过 bastion 跳转 ``` **Mihomo 配置**: ```yaml proxies: - name: "Internal-DB-SSH" type: ssh server: "internal-db" # 直接填别名 port: 22 # 目标内部 SSH 端口 use-ssh-config-alias: true ssh-user: "your-username" # 你的本地用户名 ``` #### 场景 2:Cloudflare Access (ProxyCommand) [Section titled “场景 2:Cloudflare Access (ProxyCommand)”](#场景-2cloudflare-access-proxycommand) **SSH Config**: ```ssh-config Host my-cf-server HostName ssh.example.com User root # 需要 cloudflared 命令在 PATH 中 ProxyCommand cloudflared access ssh --hostname %h ``` **Mihomo 配置**: ```yaml proxies: - name: "CF-SSH" type: ssh server: "my-cf-server" port: 22 use-ssh-config-alias: true ssh-user: "your-username" ``` ## 🛠 原理简述 [Section titled “🛠 原理简述”](#-原理简述) Mihomo 收到连接请求后,会在底层执行类似以下的命令: ```bash sudo -u your-username -i ssh -W localhost:22 my-host-alias ``` 这条命令会建立一个标准输入/输出到目标 SSH 端口的 TCP 隧道。Mihomo 随后在这个隧道上进行自己的 SSH 协议握手,建立代理连接。 # (免费版)有没想过起个容器就能打通整个内网呢? 使用容器打通受限网络: cpolar+ssh组合镜像以及sshuttle打通网络 > 使用容器打通受限网络: cpolar+ssh组合镜像以及sshuttle实现打通任意环境所有内网服务(包括k8s)(web页面以及终端访问) ## 前言 [Section titled “前言”](#前言) 开发过程中总是能遇到需要访问其他公司内网的情况, 一般常规方案都是由其他公司提供vpn访问, 或者jumpserver进行内网服务器连接. 这时, 一般就会遇到几个痛点: - 想要访问k8s中的容器服务, k8s内部域名无法直接使用 - 要装很多乱七八糟的vpn软件, 不同公司用的vpn可能就不一样, 有的vpn甚至像流氓软件一样, 有各种限制 - 有的公司不提供vpn或jumpserver, 只能去现场 - 家里网络和公司网络不互通的问题(在公司想访问家里的一些服务, 或在家想访问公司的一些服务等) 然而, 打通网络后, 都有哪些好处呢? - 自己本地电脑不在需要安转太多的vpn软件了 - 所能触碰到的每台内网服务器, 都能成为你在何时何地都能访问或当做跳板机的工具 - 内网才能打开的页面, 随时都能打开了 - 网页系统应用能用浏览器打开了 - nacos能用浏览器打开了 - 内网才能访问的服务器, 随时都能访问了 - 数据库能通过idea或者DBeaver可视化连接了 > 也就是说, 打通了网络, 也就打通了ssh访问, ssh能到达的地方, 都能将自己的本地电脑拉入到同一网络中进行互通操作 ## 前提 [Section titled “前提”](#前提) 需要有机会把容器起起来, 一般有以下几种方式, 选一个方便去操作的就行, 当容器起来之后, 网络就打通了, 虚拟机等过渡工具就可以删掉了, 不需要了 - 通过jumpserver页面登录 - 自己本身就安转了vpn - 找安装了vpn的同事 - 专门找台机用于安装各种乱七八糟的vpn也行 - 当然起个虚拟机去安转也行 ## 第一步: 编写Dockerfile, 用于制作镜像 [Section titled “第一步: 编写Dockerfile, 用于制作镜像”](#第一步-编写dockerfile-用于制作镜像) 随便找台Linux系统, 或者自己电脑也行(就是麻烦点, 可能构建镜像时, 需要指定构建平台等), 我这里选择用x86架构的centos系统, 然后, 找个合适的目录, 例如: `/www/container/cpolar-ssh` * 创建`Dockerfile`文件 ```bash # vim Dockerfile # 使用官方 CentOS 基础镜像(PS: latest版拉取openssh-server依赖报错) # FROM centos:centos7.9.2009 FROM registry.cn-hangzhou.aliyuncs.com/iuin/centos:latest # ENV https_proxy=http://192.168.0.121:7890 http_proxy=http://192.168.0.121:7890 all_proxy=socks5://192.168.0.121:7890 RUN sed -i s/mirror.centos.org/vault.centos.org/g /etc/yum.repos.d/*.repo && \ sed -i s/^#.*baseurl=http/baseurl=http/g /etc/yum.repos.d/*.repo && \ sed -i s/^mirrorlist=http/#mirrorlist=http/g /etc/yum.repos.d/*.repo && \ yum install -y wget && \ wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo # 安装必要的软件包 RUN yum update -y && yum install -y openssh-server openssh-clients passwd && yum clean all # 设置 root 密码, 修改 SSH 配置文件允许密码登录和 root 登录 RUN echo "root:password" | chpasswd && \ sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/g' /etc/ssh/sshd_config && \ sed -i 's/#PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config && \ /usr/sbin/sshd-keygen RUN curl -L https://www.cpolar.com/static/downloads/install-release-cpolar.sh | bash COPY cpolar.yml /usr/local/etc/cpolar/cpolar.yml # 开启服务后, /usr/sbin/init命令会自动帮忙启动服务 RUN systemctl enable cpolar.service # 创建启动脚本 RUN tee /usr/local/bin/start-cpolar.sh <<-'EOF' #!/bin/bash cpolar authtoken ${CPOLAR_AUTH_TOKEN} EOF RUN chmod +x /usr/local/bin/start-cpolar.sh # 创建包装服务 RUN tee /etc/systemd/system/cpolar-wrapper.service <<-'EOF' [Unit] Description=Cpolar Wrapper Service # After=network.target After=cpolar.service [Service] Type=simple ExecStart=/usr/local/bin/start-cpolar.sh Restart=always RestartSec=10 [Install] WantedBy=multi-user.target EOF # 启用包装服务 RUN systemctl enable cpolar-wrapper.service # 暴露 SSH 端口 EXPOSE 22 # 启动ssh和cpolar服务 # ENTRYPOINT [ "/usr/sbin/init" ] # 创建初始化脚本 RUN tee /usr/local/bin/init-container.sh <<-'EOF' #!/bin/bash # 替换环境变量的值 sed -i "s/\${CPOLAR_AUTH_TOKEN}/$CPOLAR_AUTH_TOKEN/g" /usr/local/bin/start-cpolar.sh sed -i "s/\${CPOLAR_CONTANER_SSH_NAME}/${CPOLAR_CONTANER_SSH_NAME:-contaner_ssh}/g" /usr/local/etc/cpolar/cpolar.yml # 启动 init exec /usr/sbin/init EOF RUN chmod +x /usr/local/bin/init-container.sh # 使用初始化脚本作为入口点 ENTRYPOINT ["/usr/local/bin/init-container.sh"] ``` ## 第二步: 编写docker-compose.yml, 方便构建和运行容器 [Section titled “第二步: 编写docker-compose.yml, 方便构建和运行容器”](#第二步-编写docker-composeyml-方便构建和运行容器) ```bash vim docker-compose.yml services: cpolar-ssh: build: context: . dockerfile: Dockerfile environment: - TZ="Asia/Shanghai" - CPOLAR_AUTH_TOKEN=xxx - CPOLAR_CONTANER_SSH_NAME=contaner_ssh_1 restart: unless-stopped privileged: true volumes: - ./cpolar.yml:/usr/local/etc/cpolar/cpolar.yml ``` * 编写用于挂载的cpolar配置文件 * 这个也可以考虑写死到Dockerfile中, 通过环境变量的方式去更新变量 * 需要配置更多的隧道, 再把它给挂载出来, 这样能够简化下基础流程 ```bash vim cpolar.yml tunnels: ${CPOLAR_CONTANER_SSH_NAME}: proto: tcp addr: "22" bind_tls: both start_type: enable ``` ## 第三步: 启动docker-compose, 测试容器以及上传进行 [Section titled “第三步: 启动docker-compose, 测试容器以及上传进行”](#第三步-启动docker-compose-测试容器以及上传进行) 调整上一步中的环境变量, 主要是`CPOLAR_AUTH_TOKEN`, 需要到cpolar中注册个免费账号, 才能获取到token * [cpolar官网地址](https://www.cpolar.com/) ```bash # 构建镜像并启动容器 docker-compose up -d ``` * 使用ssh远程连接下, 试试效果 ```bash # vim ~/.ssh/config Host cpolar.internet.company HostName xxx.tcp.cpolar.top User root Port 11111 IdentityFile ~/.ssh/id_ed25519 ``` ```bash # 上传公钥, 开启免密登录, 这一步也是顺便检查了是否能够正常通过内网穿透ssh到容器中 ssh-copy-id cpolar.internet.company -i ~/.ssh/id_ed25519 # 然后, 通过ssh免密登录 ssh cpolar.internet.company ``` > 到这就已经基本完成了在任何地方都能联通ssh了, 接下来的就是简化配置, 以及高级应用了 ## 上传镜像到阿里云, 简化启动容器的配置 [Section titled “上传镜像到阿里云, 简化启动容器的配置”](#上传镜像到阿里云-简化启动容器的配置) ```bash # 登录 docker login --username=xxx@qq.com registry.cn-hangzhou.aliyuncs.com ## 标记本地镜像并指向目标仓库(ip:port/image_name:tag,该格式为标记版本号) docker tag cpolar-ssh registry.cn-hangzhou.aliyuncs.com/xxx/cpolar-ssh:latest ## 推送镜像到仓库 docker push registry.cn-hangzhou.aliyuncs.com/xxx/cpolar-ssh:latest ``` ## 简化后的docker-compose配置 [Section titled “简化后的docker-compose配置”](#简化后的docker-compose配置) 简化后, 就只需要docker-compose配置即可, 当然, 如果没有将cpolar配置整合到Dockerfile中的情况下, 还是需要挂载配置的 ```bash services: cpolar-ssh: image: registry.cn-hangzhou.aliyuncs.com/xxx/cpolar-ssh:latest environment: - TZ="Asia/Shanghai" - CPOLAR_AUTH_TOKEN=${CPOLAR_AUTH_TOKEN} - CPOLAR_CONTANER_SSH_NAME=contaner_ssh_1 restart: unless-stopped privileged: true ``` ## 配合sshuttle工具使用, 方便访问网页 [Section titled “配合sshuttle工具使用, 方便访问网页”](#配合sshuttle工具使用-方便访问网页) 这里, 我们借助sshuttle工具, 通过ssh将流量代理转发到容器中, 实现想访问局域网一样访问容器那边的对应内网上的网页 * [sshuttle的github地址](https://github.com/sshuttle/sshuttle) ```bash # 安装(macos) brew install sshuttle # 代理流量 sshuttle --sudoers-user fa --dns --method auto --auto-hosts --auto-nets -D -r cpolar.internet.company 10.0.10.0/24 ``` ## 最后的话 [Section titled “最后的话”](#最后的话) 到这就基本完成了我们最初的目标了, 能够正常像在一个局域网中一样, 访问网页以及连接数据库等了 * 最后说下现有方案还存在的一些问题 * 密码连接相对没那么安全 * 使用到了`systemd`工具, 也就是docker-compose中必须使用`privileged: true`, 容器权限太高了 * 用的第三方的服务器(cpolar)做中转, 流量要经过别人的服务器 * 下期目标 * ssh改为使用密钥方式登录, 禁用密码登录 * 容器服务管理工具不使用`systemd`, 而是改为更轻量的多服务管理工具`tini` * 这样docker容器也不在需要配置`privileged: true`了 * 内网穿透改为开源的`frp`, 当然, 这里就需要自己有一台公网的服务器去部署服务端了 * 相关链接 * [这篇文章对应的博客文档](https://183461750.github.io/doc-record/docker/dev_utls/dev-container/remote-ssh/cpolar/article/doc) * [对应的GitHub仓库](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/dev-container/remote-ssh/cpolar/v3/simple/docker-compose.yml), 可以在这里找到相关的全部配置代码 > 想不到这么快就到说再见的时候了, 稍稍的期待一下吧, 下期再见👋 # (frps selfhost版)有没想过起个容器就能打通整个内网呢? 使用容器打通受限网络: frp+ssh组合镜像以及clash(mihomo)实现打通网络 > 使用容器打通受限网络: frp+ssh组合镜像以及clash(mihomo)实现打通任意环境所有内网服务(包括k8s)(web页面以及终端访问) 这里还有个需要提到的是, 因为我的科学上网环境是用的clash(mihomo)软件, 所以这里就用clash(mihomo)来实现打通各种内网 这样我就可以只需要一个代理软件就行了 ## 前言 [Section titled “前言”](#前言) 开发过程中总是能遇到需要访问其他公司内网的情况, 一般常规方案都是由其他公司提供vpn访问, 或者jumpserver进行内网服务器连接. 这时, 一般就会遇到几个痛点: - 想要访问k8s中的容器服务, k8s内部域名`svc.cluster.local`无法直接使用 - 要装很多乱七八糟的vpn软件, 不同公司用的vpn可能就不一样, 有的vpn甚至像流氓软件一样, 有各种限制 - 有的公司不提供vpn或jumpserver, 只能去现场 - 家里网络和公司网络不互通的问题(在公司想访问家里的一些服务, 或在家想访问公司的一些服务等) 然而, 打通网络后, 都有哪些好处呢? - 自己本地电脑不在需要安转太多的vpn软件了 - 所能触碰到的每台内网服务器, 都能成为你在何时何地都能访问或当做跳板机的工具 - 内网才能打开的页面, 随时都能打开了 - 网页系统应用能用浏览器打开了 - nacos能用浏览器打开了 - 内网才能访问的服务器, 随时都能访问了 - 数据库能通过idea或者DBeaver可视化连接了 > 也就是说, 打通了网络, 也就打通了ssh访问, ssh能到达的地方, 都能将自己的本地电脑拉入到同一网络中进行互通操作 ## 前提 [Section titled “前提”](#前提) 需要有机会把容器起起来, 一般有以下几种方式, 选一个方便去操作的就行, 当容器起来之后, 网络就打通了, 虚拟机等过渡工具就可以删掉了, 不需要了 - 通过jumpserver页面登录 - 自己本身就安转了vpn - 找安装了vpn的同事 - 专门找台机用于安装各种乱七八糟的vpn也行 - 当然起个虚拟机去安转也行 ## 编写docker-compose.yml(服务端) [Section titled “编写docker-compose.yml(服务端)”](#编写docker-composeyml服务端) > 这里的服务端, 就是你有公网IP的云服务器, 我这里用的是Debian, 你可以根据自己的情况, 选择合适的镜像 ```yml # vi /www/dev-jumpbox/server/docker-compose.yml services: frps-ssh: image: registry.cn-hangzhou.aliyuncs.com/iuin/frps-ssh:tcpmux network_mode: host environment: - TZ="Asia/Shanghai" - auth_token="xxx" - bindPort=18000 - tcpmuxHTTPConnectPort=12222 restart: unless-stopped ``` ```bash # 构建镜像并启动容器 docker-compose up -d ``` ## 编写docker-compose.yml(客户端) [Section titled “编写docker-compose.yml(客户端)”](#编写docker-composeyml客户端) 共用端口的方式, [参考文章](https://gofrp.org/zh-cn/docs/examples/multiple-ssh-over-same-port/) PS: 自定义域名需要配合`proxycommand`代理使用`ssh -o 'proxycommand socat - PROXY:x.x.x.x:%h:%p,proxyport=5002' test@machine-a.example.com` ```yml # vi /www/dev-jumpbox/client/docker-compose.yml services: dev-jumpbox: image: registry.cn-hangzhou.aliyuncs.com/iuin/dev-jumpbox:tcpmux-v6.1.1 container_name: dev-jumpbox environment: TZ: "Asia/Shanghai" serverAddr: '"55.44.33.33"' serverPort: 18000 auth_token: '"jumpboxs-ssh"' client_name: '"jumpboxc-ssh-fa"' customDomains: '["fa.intranet.company"]' volumes: # 需要先创建这个文件, 不然会自动创建为文件夹 - ./.ssh/authorized_keys:/root/.ssh/authorized_keys:ro restart: unless-stopped ``` 不想要多配置个`proxycommand`的话, 用下面的方式会简单点, 但需要独占端口 ```bash services: dev-jumpbox: image: registry.cn-hangzhou.aliyuncs.com/iuin/dev-jumpbox:frpc-ssh-v6.1 container_name: dev-jumpbox environment: TZ: "Asia/Shanghai" serverAddr: '"55.44.33.33"' client_title: proxies serverPort: 18000 auth_token_line: auth.token = "jumpboxs-ssh" client_name: '"fa.intranet.company"' client_type: '"tcp"' localIP_proxies_line: localIP="127.0.0.1" localPort_proxies_line: localPort=22 # 独占端口方式, 需要外网防火墙开放这个端口 remotePort_proxies_tcp_line: remotePort=12202 extra_hosts: - "container.host:host-gateway" volumes: # 需要先创建这个文件, 不然会自动创建为文件夹 - ./.ssh/authorized_keys:/root/.ssh/authorized_keys:ro restart: unless-stopped ``` ```bash # 构建镜像并启动容器 docker-compose up -d ``` * 关于卷(volumes)的说明 这里的卷也可以不挂载, 也可以通过进入容器中执行命令去写入`authorized_keys`文件中, 不过容器重启后, 会丢失写入的内容 ```bash # 在本地电脑中执行, 打印公钥 cat ~/.ssh/id_ed25519.pub # 复制打印的公钥内容, 需要写入到`./.ssh/authorized_keys`, 这个文件是需要挂载到容器中的文件 # 全路径: /www/dev-jumpbox/client/.ssh/authorized_keys(注意: 别跟宿主机的authorized_keys文件搞混了) # 这里也可以由dev-jumpbox容器去管理ssh公私钥, 把宿主机生成好的公私钥, 挂载到容器中, 然后在容器中执行命令去写入authorized_keys文件中, 最后把私钥给到clash(mihomo)工具使用 # 如果clash用户想用自己的私钥的话, 那就在生成私钥的时候, 选择将公私钥生成到clash配置目录下, 然后在clash配置文件中, 引用自己的私钥文件即可(clash verge rev只支持读取根目录下的私钥文件) ``` ```bash # 在客户端宿主机或者容器中执行, 写入公钥到authorized_keys文件中 echo 'ssh-ed25519 xxxxx xxx' > ./.ssh/authorized_keys ``` ## 第四步: 启动docker-compose, 测试容器以及上传进行 [Section titled “第四步: 启动docker-compose, 测试容器以及上传进行”](#第四步-启动docker-compose-测试容器以及上传进行) ```bash # 构建镜像并启动容器 docker-compose up -d ``` * 使用ssh远程连接下, 试试效果 ```bash # 上传公钥, 开启免密登录, 这一步也是顺便检查了是否能够正常通过内网穿透ssh到容器中 ssh-copy-id root@129.204.8.8 -p 12222 -i ~/.ssh/id_ed25519 # 然后, 通过ssh免密登录 ssh root@129.204.8.8 -p 12222 ``` [参考详情链接](https://iuin8.github.io/doc-record/docker/dev_utls/dev-container/remote-ssh/frp/tcpmux/v6.1.1/doc) > 到这就已经基本完成了在任何地方都能联通ssh了, 接下来的就是高级应用了, 配合clash(mihomo)工具, 实现网络流量代理到内容容器中 ## 配合clash(mihomo)工具使用, 方便访问网页 [Section titled “配合clash(mihomo)工具使用, 方便访问网页”](#配合clashmihomo工具使用-方便访问网页) 这里, 我们借助clash(mihomo)工具, 通过ssh将流量代理转发到容器中, 实现像访问局域网一样访问容器那边的对应内网上的网页 * [clash(mihomo)的github地址](https://www.clashverge.dev/guide/quickstart.html) ```javascript // 代理流量(script.js[这里用了全局脚本的方式, 兼容自己的原有的订阅, 不影响原有的订阅, 只做扩展]) function main(config, profileName) { const privateKeyContent = `-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZxxxABAAAAMwAAA QyNTUxOQAAAxxxAAAIgIqewcCKn HAAAAAtxxxDYC8YhlRDIhM+GUeg -----END OPENSSH PRIVATE KEY-----`; const extra = { proxies: [ { name: "company_container", type: "ssh", server: "183.11.11.11", port: 11111, username: "root", // 用密钥的情况下, 这里需要把密钥复制到软件配置目录下的.ssh目录中, 才能正常使用 // "private-key": "./.ssh/id_ed25519_iu" "private-key": privateKeyContent } ], proxyGroups: [ { name: "company_g", type: "select", proxies: ["DIRECT", "company_container"] } ], rules: [ "IP-CIDR,10.0.11.0/24,company_g", "DOMAIN-SUFFIX,company.com,company_g" ] }; if (!Array.isArray(config.proxies)) config.proxies = []; for (const p of extra.proxies) { if (p && p.name && !config.proxies.some(x => x && x.name === p.name)) { config.proxies.unshift(p); } } if (!Array.isArray(config["proxy-groups"])) config["proxy-groups"] = []; for (const g of extra.proxyGroups) { let existing = config["proxy-groups"].find(x => x && x.name === g.name); if (!existing) { config["proxy-groups"].unshift({ name: g.name, type: g.type, proxies: Array.isArray(g.proxies) ? [...g.proxies] : [] }); } else { if (!Array.isArray(existing.proxies)) existing.proxies = []; for (const pn of g.proxies || []) { if (!existing.proxies.includes(pn)) existing.proxies.unshift(pn); } } } if (!Array.isArray(config.rules)) config.rules = []; for (const r of extra.rules) { if (!config.rules.includes(r)) config.rules.unshift(r); } return config; } ``` ```yml # 单独订阅配置(ssh.yml) proxies: - name: company_container type: ssh server: 183.11.11.11 port: 11111 username: root # 用密钥的情况下, 这里需要把密钥复制到软件配置目录下的.ssh目录中, 才能正常使用 # private-key: ./.ssh/id_ed25519_iu private-key: | -----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZxxxABAAAAMwAAA QyNTUxOQAAAxxxAAAIgIqewcCKn HAAAAAtxxxDYC8YhlRDIhM+GUeg -----END OPENSSH PRIVATE KEY----- proxy-groups: - name: company_g type: select proxies: - company_container rules: - "IP-CIDR,10.0.11.0/24,company_g" - "DOMAIN-SUFFIX,company.com,company_g" ``` ## k8s中使用, 打通命名空间中的网络 [Section titled “k8s中使用, 打通命名空间中的网络”](#k8s中使用-打通命名空间中的网络) ```yml ## k8s等(有内部DNS功能的系统)用法 # 其他配置省略 rules: - "IP-CIDR,10.0.11.0/24,company_g" - "IP-CIDR,100.20.0.0/16,company_g" - "IP-CIDR,100.19.0.0/16,company_g" - "DOMAIN-SUFFIX,svc.cluster.local,company_g" - "DOMAIN-SUFFIX,company.com,company_g" ``` * 说明: 这里挂载了三个网段 * 其中, 第一个网段是需要代理其他正常流量的网段 * 第二和第三个网段, 则是命名空间中的容器使用的网段 * 作用是, 让我们能通过k8s内部域名访问, k8s中容器提供的服务 * 即通过`svc.cluster.local`k8s中内部域名访问 ## 最后的话 [Section titled “最后的话”](#最后的话) 到这就基本完成了我们的目标了, 能够正常像在一个局域网中一样, 访问网页以及连接数据库等了 > 要是有什么问题, 欢迎留言交流 * 更多内容 * [这篇文章对应的GitHub博客文档地址](https://iuin8.github.io/doc-record/docs/docker/dev_utls/dev-container/remote-ssh/frp/article/frp+ssh%E7%BB%84%E5%90%88%E9%95%9C%E5%83%8F%E4%BB%A5%E5%8F%8Aclash%E6%89%93%E9%80%9A%E7%BD%91%E7%BB%9C.md) # (frps selfhost版)有没想过起个容器就能打通整个内网呢? 使用容器打通受限网络: frp+ssh组合镜像以及clash(mihomo)实现打通网络(full) > 使用容器打通受限网络: frp+ssh组合镜像以及clash(mihomo)实现打通任意环境所有内网服务(包括k8s)(web页面以及终端访问) 这里还有个需要提到的是, 因为我的科学上网环境是用的clash(mihomo)软件, 所以这里就用clash(mihomo)来实现打通各种内网 这样我就可以只需要一个代理软件就行了 ## 前言 [Section titled “前言”](#前言) 开发过程中总是能遇到需要访问其他公司内网的情况, 一般常规方案都是由其他公司提供vpn访问, 或者jumpserver进行内网服务器连接. 这时, 一般就会遇到几个痛点: - 想要访问k8s中的容器服务, k8s内部域名`svc.cluster.local`无法直接使用 - 要装很多乱七八糟的vpn软件, 不同公司用的vpn可能就不一样, 有的vpn甚至像流氓软件一样, 有各种限制 - 有的公司不提供vpn或jumpserver, 只能去现场 - 家里网络和公司网络不互通的问题(在公司想访问家里的一些服务, 或在家想访问公司的一些服务等) 然而, 打通网络后, 都有哪些好处呢? - 自己本地电脑不在需要安转太多的vpn软件了 - 所能触碰到的每台内网服务器, 都能成为你在何时何地都能访问或当做跳板机的工具 - 内网才能打开的页面, 随时都能打开了 - 网页系统应用能用浏览器打开了 - nacos能用浏览器打开了 - 内网才能访问的服务器, 随时都能访问了 - 数据库能通过idea或者DBeaver可视化连接了 > 也就是说, 打通了网络, 也就打通了ssh访问, ssh能到达的地方, 都能将自己的本地电脑拉入到同一网络中进行互通操作 ## 前提 [Section titled “前提”](#前提) 需要有机会把容器起起来, 一般有以下几种方式, 选一个方便去操作的就行, 当容器起来之后, 网络就打通了, 虚拟机等过渡工具就可以删掉了, 不需要了 - 通过jumpserver页面登录 - 自己本身就安转了vpn - 找安装了vpn的同事 - 专门找台机用于安装各种乱七八糟的vpn也行 - 当然起个虚拟机去安转也行 ## 第一步: 编写Dockerfile, 用于制作镜像 [Section titled “第一步: 编写Dockerfile, 用于制作镜像”](#第一步-编写dockerfile-用于制作镜像) 随便找台Linux系统, 或者自己电脑也行(就是麻烦点, 可能构建镜像时, 需要指定构建平台等), 我这里选择用x86架构的centos系统, 然后, 找个合适的目录, 例如: `/www/container/frp-ssh` * 创建`Dockerfile`文件 ```bash # vim Dockerfile FROM debian:trixie-slim WORKDIR /www # 安装必要的软件包 RUN apt-get update && \ apt-get install -y openssh-server openssh-client curl wget locales gettext tini && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* # 生成并配置 locale RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \ locale-gen && \ update-locale LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 # 设置环境变量 ENV LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 LANGUAGE=en_US.UTF-8 # 解压frp COPY ./frp_0.62.1_linux_amd64.tar.gz ./frp_0.62.1_linux_amd64.tar.gz RUN tar -xzf ./frp_0.62.1_linux_amd64.tar.gz && \ mv frp_0.62.1_linux_amd64 frp # 创建包装服务 RUN tee /www/frp/frpc.toml <<-'EOF' serverAddr = ${serverAddr} serverPort = ${serverPort} [[${client_title}]] name = ${client_name} type = ${client_type} ${secretKey_stcp_line} ${localIP_proxies_line} ${localPort_proxies_line} ${serverName_visitors_line} ${bindAddr_visitors_line} ${bindPort_visitors_line} ${remotePort_proxies_tcp_line} EOF # 创建初始化脚本 RUN tee /entrypoint.sh <<-'EOF' #!/bin/sh # 替换环境变量的值 envsubst < /www/frp/frpc.toml > /tmp/frpc.toml.tmp && mv /tmp/frpc.toml.tmp /www/frp/frpc.toml # 确保目录存在 [ ! -d "/var/run/sshd" ] && mkdir -p /var/run/sshd # 启动 SSH(后台运行) /usr/sbin/sshd -D & # 启动 FRPC /www/frp/frpc -c /www/frp/frpc.toml # 保持容器运行 wait EOF RUN chmod +x /entrypoint.sh # 暴露 SSH 端口 EXPOSE 22 # 使用 tini 作为 PID 1 ENTRYPOINT ["/usr/bin/tini", "--", "/entrypoint.sh"] ``` ## 第二步: 编写docker-compose.yml, 方便构建和运行容器 [Section titled “第二步: 编写docker-compose.yml, 方便构建和运行容器”](#第二步-编写docker-composeyml-方便构建和运行容器) ```bash # vim docker-compose.yml services: dev-jumpbox: build: context: . dockerfile: Dockerfile container_name: dev-jumpbox environment: TZ: "Asia/Shanghai" # 配置服务端的IP serverAddr: '"129.204.8.8"' client_title: proxies serverPort: 7000 # 名称随便给, 不重复就行 client_name: '"dev-jumpbox-6666"' client_type: '"tcp"' localIP_proxies_line: localIP="127.0.0.1" localPort_proxies_line: localPort=22 # 配置云服务器中开放的端口, 随便开放一个都行, 用于远程连接ssh remotePort_proxies_tcp_line: remotePort=6666 extra_hosts: - "me.host:host-gateway" restart: unless-stopped volumes: - ./.ssh/authorized_keys:/root/.ssh/authorized_keys # 以上环境变量, 除了备注的内容, 其他的都可以保持不动就行 # authorized_keys的内容示例 # ssh-ed25519 xxxxx xxx ``` * authorized\_keys的内容示例 ```bash # 在本地电脑中执行, 打印公钥 cat ~/.ssh/id_ed25519.pub # 复制打印的公钥内容, 需要写入到`./.ssh/authorized_keys`, 这个文件是需要挂载到容器中的文件 ``` * 关于卷(volumes)的说明 这里的卷也可以不挂载, 也可以通过进入容器中执行命令去写入`authorized_keys`文件中 ```bash # 使用挂载券方式时, 这一步可省略 echo 'ssh-ed25519 xxxxx xxx' > /root/.ssh/authorized_keys ``` ## 第三步: 需要一台有公网IP的云服务器(2c2g1m就差不多了, 我的镜像是Debian) [Section titled “第三步: 需要一台有公网IP的云服务器(2c2g1m就差不多了, 我的镜像是Debian)”](#第三步-需要一台有公网ip的云服务器2c2g1m就差不多了-我的镜像是debian) [frp官网安装地址](https://gofrp.org/zh-cn/docs/setup/systemd/) [frp官方GitHub下载地址](https://github.com/fatedier/frp/releases/tag/v0.62.1) ```bash # 下载下来解压 tar -xzf ./frp_0.62.1_linux_amd64.tar.gz && mv frp_0.62.1_linux_amd64 frp # 进入解压后的目录, 启动frp服务端, 设置开机自启 cd frp && systemctl start frps && systemctl enable frps ``` 然后, 开放下端口, 例如: 开放端口:6666, 用于远程连接ssh ## 第四步: 启动docker-compose, 测试容器以及上传进行 [Section titled “第四步: 启动docker-compose, 测试容器以及上传进行”](#第四步-启动docker-compose-测试容器以及上传进行) ```bash # 构建镜像并启动容器 docker-compose up -d ``` * 使用ssh远程连接下, 试试效果 ```bash # 上传公钥, 开启免密登录, 这一步也是顺便检查了是否能够正常通过内网穿透ssh到容器中 ssh-copy-id root@129.204.8.8 -p 6666 -i ~/.ssh/id_ed25519 # 然后, 通过ssh免密登录 ssh root@129.204.8.8 -p 6666 ``` > 到这就已经基本完成了在任何地方都能联通ssh了, 接下来的就是简化配置, 以及高级应用了 ## 上传镜像到阿里云, 简化启动容器的配置 [Section titled “上传镜像到阿里云, 简化启动容器的配置”](#上传镜像到阿里云-简化启动容器的配置) ```bash # 登录 docker login --username=xxx@qq.com registry.cn-hangzhou.aliyuncs.com ## 标记本地镜像并指向目标仓库(ip:port/image_name:tag,该格式为标记版本号) docker tag dev-jumpbox registry.cn-hangzhou.aliyuncs.com/xxx/dev-jumpbox:frpc-ssh ## 推送镜像到仓库 docker push registry.cn-hangzhou.aliyuncs.com/xxx/dev-jumpbox:frpc-ssh ``` ## 简化后的docker-compose配置 [Section titled “简化后的docker-compose配置”](#简化后的docker-compose配置) 简化后, 就只需要docker-compose配置即可, 当然, 如果没有将`authorized_keys`配置整合到Dockerfile中的情况下, 还是需要挂载配置的 [参考详情链接](https://iuin8.github.io/doc-record/docker/dev_utls/dev-container/remote-ssh/frp/tcpmux/v6.1.1/doc) ```bash services: dev-jumpbox: image: registry.cn-hangzhou.aliyuncs.com/iuin/dev-jumpbox:tcpmux-v6.1.1 container_name: dev-jumpbox environment: TZ: "Asia/Shanghai" serverAddr: '"183.11.11.11"' serverPort: 11100 auth_token: '"xx-jumpbox-ssh"' client_name: '"container.prod.xxx.customer"' customDomains: '["container.prod.xxx.customer"]' restart: unless-stopped ``` ## 配合clash(mihomo)工具使用, 方便访问网页 [Section titled “配合clash(mihomo)工具使用, 方便访问网页”](#配合clashmihomo工具使用-方便访问网页) 这里, 我们借助clash(mihomo)工具, 通过ssh将流量代理转发到容器中, 实现像访问局域网一样访问容器那边的对应内网上的网页 * [clash(mihomo)的github地址](https://www.clashverge.dev/guide/quickstart.html) ```bash # 代理流量(script.js[这里用了全局脚本的方式, 兼容自己的原有的订阅, 不影响原有的订阅, 只做扩展]) function main(config, profileName) { const extra = { proxies: [ { name: "company_container", type: "ssh", server: "183.11.11.11", port: 11111, username: "root", "private-key": "./.ssh/id_ed25519_iu" } ], proxyGroups: [ { name: "company_g", type: "select", proxies: ["DIRECT", "company_container"] } ], rules: [ "IP-CIDR,10.0.11.0/24,company_g", "DOMAIN-SUFFIX,company.com,company_g" ] }; if (!Array.isArray(config.proxies)) config.proxies = []; for (const p of extra.proxies) { if (p && p.name && !config.proxies.some(x => x && x.name === p.name)) { config.proxies.unshift(p); } } if (!Array.isArray(config["proxy-groups"])) config["proxy-groups"] = []; for (const g of extra.proxyGroups) { let existing = config["proxy-groups"].find(x => x && x.name === g.name); if (!existing) { config["proxy-groups"].unshift({ name: g.name, type: g.type, proxies: Array.isArray(g.proxies) ? [...g.proxies] : [] }); } else { if (!Array.isArray(existing.proxies)) existing.proxies = []; for (const pn of g.proxies || []) { if (!existing.proxies.includes(pn)) existing.proxies.unshift(pn); } } } if (!Array.isArray(config.rules)) config.rules = []; for (const r of extra.rules) { if (!config.rules.includes(r)) config.rules.unshift(r); } return config; } ``` ```yml # 单独订阅配置(ssh.yml) proxies: - name: company_container type: ssh server: 183.11.11.11 port: 11111 username: root private-key: ./.ssh/id_ed25519_iu proxy-groups: - name: company_g type: select proxies: - company_container rules: - "IP-CIDR,10.0.11.0/24,company_g" - "DOMAIN-SUFFIX,company.com,company_g" ``` ## k8s中使用, 打通命名空间中的网络 [Section titled “k8s中使用, 打通命名空间中的网络”](#k8s中使用-打通命名空间中的网络) ```yml ## k8s等(有内部DNS功能的系统)用法 # 其他配置省略 rules: - "IP-CIDR,10.0.11.0/24,company_g" - "IP-CIDR,100.20.0.0/16,company_g" - "IP-CIDR,100.19.0.0/16,company_g" - "DOMAIN-SUFFIX,svc.cluster.local,company_g" - "DOMAIN-SUFFIX,company.com,company_g" ``` * 说明: 这里挂载了三个网段 * 其中, 第一个网段是需要代理其他正常流量的网段 * 第二和第三个网段, 则是命名空间中的容器使用的网段 * 作用是, 让我们能通过k8s内部域名访问, k8s中容器提供的服务 * 即通过`svc.cluster.local`k8s中内部域名访问 ## 最后的话 [Section titled “最后的话”](#最后的话) 到这就基本完成了我们的目标了, 能够正常像在一个局域网中一样, 访问网页以及连接数据库等了 * 更多内容 * [这篇文章对应的GitHub博客文档地址](https://iuin8.github.io/doc-record/docs/docker/dev_utls/dev-container/remote-ssh/frp/article/frp+ssh%E7%BB%84%E5%90%88%E9%95%9C%E5%83%8F%E4%BB%A5%E5%8F%8Aclash%E6%89%93%E9%80%9A%E7%BD%91%E7%BB%9C.md) # (frps selfhost版)有没想过起个容器就能打通整个内网呢? 使用容器打通受限网络: frp+ssh组合镜像以及sshuttle打通网络 > 使用容器打通受限网络: frp+ssh组合镜像以及sshuttle实现打通任意环境所有内网服务(包括k8s)(web页面以及终端访问) ## 前言 [Section titled “前言”](#前言) 开发过程中总是能遇到需要访问其他公司内网的情况, 一般常规方案都是由其他公司提供vpn访问, 或者jumpserver进行内网服务器连接. 这时, 一般就会遇到几个痛点: - 想要访问k8s中的容器服务, k8s内部域名`svc.cluster.local`无法直接使用 - 要装很多乱七八糟的vpn软件, 不同公司用的vpn可能就不一样, 有的vpn甚至像流氓软件一样, 有各种限制 - 有的公司不提供vpn或jumpserver, 只能去现场 - 家里网络和公司网络不互通的问题(在公司想访问家里的一些服务, 或在家想访问公司的一些服务等) 然而, 打通网络后, 都有哪些好处呢? - 自己本地电脑不在需要安转太多的vpn软件了 - 所能触碰到的每台内网服务器, 都能成为你在何时何地都能访问或当做跳板机的工具 - 内网才能打开的页面, 随时都能打开了 - 网页系统应用能用浏览器打开了 - nacos能用浏览器打开了 - 内网才能访问的服务器, 随时都能访问了 - 数据库能通过idea或者DBeaver可视化连接了 > 也就是说, 打通了网络, 也就打通了ssh访问, ssh能到达的地方, 都能将自己的本地电脑拉入到同一网络中进行互通操作 ## 前提 [Section titled “前提”](#前提) 需要有机会把容器起起来, 一般有以下几种方式, 选一个方便去操作的就行, 当容器起来之后, 网络就打通了, 虚拟机等过渡工具就可以删掉了, 不需要了 - 通过jumpserver页面登录 - 自己本身就安转了vpn - 找安装了vpn的同事 - 专门找台机用于安装各种乱七八糟的vpn也行 - 当然起个虚拟机去安转也行 ## 第一步: 编写Dockerfile, 用于制作镜像 [Section titled “第一步: 编写Dockerfile, 用于制作镜像”](#第一步-编写dockerfile-用于制作镜像) 随便找台Linux系统, 或者自己电脑也行(就是麻烦点, 可能构建镜像时, 需要指定构建平台等), 我这里选择用x86架构的centos系统, 然后, 找个合适的目录, 例如: `/www/container/frp-ssh` * 创建`Dockerfile`文件 ```bash # vim Dockerfile FROM debian:trixie-slim WORKDIR /www # 安装必要的软件包 RUN apt-get update && \ apt-get install -y openssh-server openssh-client curl wget locales gettext tini && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* # 生成并配置 locale RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \ locale-gen && \ update-locale LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 # 设置环境变量 ENV LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 LANGUAGE=en_US.UTF-8 # 解压frp COPY ./frp_0.62.1_linux_amd64.tar.gz ./frp_0.62.1_linux_amd64.tar.gz RUN tar -xzf ./frp_0.62.1_linux_amd64.tar.gz && \ mv frp_0.62.1_linux_amd64 frp # 创建包装服务 RUN tee /www/frp/frpc.toml <<-'EOF' serverAddr = ${serverAddr} serverPort = ${serverPort} [[${client_title}]] name = ${client_name} type = ${client_type} ${secretKey_stcp_line} ${localIP_proxies_line} ${localPort_proxies_line} ${serverName_visitors_line} ${bindAddr_visitors_line} ${bindPort_visitors_line} ${remotePort_proxies_tcp_line} EOF # 创建初始化脚本 RUN tee /entrypoint.sh <<-'EOF' #!/bin/sh # 替换环境变量的值 envsubst < /www/frp/frpc.toml > /tmp/frpc.toml.tmp && mv /tmp/frpc.toml.tmp /www/frp/frpc.toml # 确保目录存在 [ ! -d "/var/run/sshd" ] && mkdir -p /var/run/sshd # 启动 SSH(后台运行) /usr/sbin/sshd -D & # 启动 FRPC /www/frp/frpc -c /www/frp/frpc.toml # 保持容器运行 wait EOF RUN chmod +x /entrypoint.sh # 暴露 SSH 端口 EXPOSE 22 # 使用 tini 作为 PID 1 ENTRYPOINT ["/usr/bin/tini", "--", "/entrypoint.sh"] ``` ## 第二步: 编写docker-compose.yml, 方便构建和运行容器 [Section titled “第二步: 编写docker-compose.yml, 方便构建和运行容器”](#第二步-编写docker-composeyml-方便构建和运行容器) ```bash # vim docker-compose.yml services: dev-jumpbox: build: context: . dockerfile: Dockerfile container_name: dev-jumpbox environment: TZ: "Asia/Shanghai" # 配置服务端的IP serverAddr: '"129.204.8.8"' client_title: proxies serverPort: 7000 # 名称随便给, 不重复就行 client_name: '"dev-jumpbox-6666"' client_type: '"tcp"' localIP_proxies_line: localIP="127.0.0.1" localPort_proxies_line: localPort=22 # 配置云服务器中开放的端口, 随便开放一个都行, 用于远程连接ssh remotePort_proxies_tcp_line: remotePort=6666 extra_hosts: - "me.host:host-gateway" restart: unless-stopped volumes: - ./.ssh/authorized_keys:/root/.ssh/authorized_keys # 以上环境变量, 除了备注的内容, 其他的都可以保持不动就行 # authorized_keys的内容示例 # ssh-ed25519 xxxxx xxx ``` * authorized\_keys的内容示例 ```bash # 在本地电脑中执行, 打印公钥 cat ~/.ssh/id_ed25519.pub # 复制打印的公钥内容, 需要写入到`./.ssh/authorized_keys`, 这个文件是需要挂载到容器中的文件 ``` * 关于卷(volumes)的说明 这里的卷也可以不挂载, 也可以通过进入容器中执行命令去写入`authorized_keys`文件中 ```bash # 使用挂载券方式时, 这一步可省略 echo 'ssh-ed25519 xxxxx xxx' > /root/.ssh/authorized_keys ``` ## 第三步: 需要一台有公网IP的云服务器(2c2g1m就差不多了, 我的镜像是Debian) [Section titled “第三步: 需要一台有公网IP的云服务器(2c2g1m就差不多了, 我的镜像是Debian)”](#第三步-需要一台有公网ip的云服务器2c2g1m就差不多了-我的镜像是debian) [frp官网安装地址](https://gofrp.org/zh-cn/docs/setup/systemd/) [frp官方GitHub下载地址](https://github.com/fatedier/frp/releases/tag/v0.62.1) ```bash # 下载下来解压 tar -xzf ./frp_0.62.1_linux_amd64.tar.gz && mv frp_0.62.1_linux_amd64 frp # 进入解压后的目录, 启动frp服务端, 设置开机自启 cd frp && systemctl start frps && systemctl enable frps ``` 然后, 开放下端口, 例如: 开放端口:6666, 用于远程连接ssh ## 第四步: 启动docker-compose, 测试容器以及上传进行 [Section titled “第四步: 启动docker-compose, 测试容器以及上传进行”](#第四步-启动docker-compose-测试容器以及上传进行) ```bash # 构建镜像并启动容器 docker-compose up -d ``` * 使用ssh远程连接下, 试试效果 ```bash # vim ~/.ssh/config Host frpc.internet.company HostName 129.204.8.8 User root Port 6666 IdentityFile ~/.ssh/id_ed25519 ``` ```bash # 上传公钥, 开启免密登录, 这一步也是顺便检查了是否能够正常通过内网穿透ssh到容器中 ssh-copy-id frpc.internet.company -i ~/.ssh/id_ed25519 # 然后, 通过ssh免密登录 ssh frpc.internet.company ``` > 到这就已经基本完成了在任何地方都能联通ssh了, 接下来的就是简化配置, 以及高级应用了 ## 上传镜像到阿里云, 简化启动容器的配置 [Section titled “上传镜像到阿里云, 简化启动容器的配置”](#上传镜像到阿里云-简化启动容器的配置) ```bash # 登录 docker login --username=xxx@qq.com registry.cn-hangzhou.aliyuncs.com ## 标记本地镜像并指向目标仓库(ip:port/image_name:tag,该格式为标记版本号) docker tag dev-jumpbox registry.cn-hangzhou.aliyuncs.com/xxx/dev-jumpbox:frpc-ssh ## 推送镜像到仓库 docker push registry.cn-hangzhou.aliyuncs.com/xxx/dev-jumpbox:frpc-ssh ``` ## 简化后的docker-compose配置 [Section titled “简化后的docker-compose配置”](#简化后的docker-compose配置) 简化后, 就只需要docker-compose配置即可, 当然, 如果没有将`authorized_keys`配置整合到Dockerfile中的情况下, 还是需要挂载配置的 ```bash services: dev-jumpbox: image: registry.cn-hangzhou.aliyuncs.com/iuin/dev-jumpbox:frpc-ssh-v5 container_name: dev-jumpbox environment: TZ: "Asia/Shanghai" # 配置服务端的IP serverAddr: '"129.204.8.8"' client_title: proxies serverPort: 7000 # 名称随便给, 不重复就行 client_name: '"dev-jumpbox-6666"' client_type: '"tcp"' localIP_proxies_line: localIP="127.0.0.1" localPort_proxies_line: localPort=22 # 配置云服务器中开放的端口, 随便开放一个都行, 用于远程连接ssh remotePort_proxies_tcp_line: remotePort=6666 extra_hosts: - "me.host:host-gateway" restart: unless-stopped ``` ## 配合sshuttle工具使用, 方便访问网页 [Section titled “配合sshuttle工具使用, 方便访问网页”](#配合sshuttle工具使用-方便访问网页) 这里, 我们借助sshuttle工具, 通过ssh将流量代理转发到容器中, 实现像访问局域网一样访问容器那边的对应内网上的网页 * [sshuttle的github地址](https://github.com/sshuttle/sshuttle) ```bash # 安装(macos) brew install sshuttle # 代理流量 sshuttle --dns --auto-hosts --auto-nets -D -r cpolar.internet.company 10.0.10.0/24 ``` ## k8s中使用, 打通命名空间中的网络 [Section titled “k8s中使用, 打通命名空间中的网络”](#k8s中使用-打通命名空间中的网络) ```bash ## k8s等(有内部DNS功能的系统)用法 sshuttle --dns --auto-hosts --auto-nets -D -r cpolar.internet.company 10.0.10.0/24 100.20.0.0/16 100.19.0.0/16 ``` * 说明: 这里挂载了三个网段 * 其中, 第一个网段是需要代理流量的网段 * 例如, 在k8s中启动了这个容器, 用于打通命名空间内部网络 * 第二和第三个网段, 则是命名空间中的容器使用的网段 * 作用是, 让我们能通过k8s内部域名访问, k8s中容器提供的服务 * 即我们通过`svc.cluster.local`k8s中内部域名访问时 * sshuttle —dns配置会将这个内部域名通过第一个网段去查询内部dns, 去获取内部IP, 然后本地电脑去访问这个IP * 最后, 正因为获取到的是k8s容器的内部IP, 所以第二和第三网段流量也需要代理 ## 最后的话 [Section titled “最后的话”](#最后的话) 到这就基本完成了我们的目标了, 能够正常像在一个局域网中一样, 访问网页以及连接数据库等了 * 下期目标 * 实现p2p连接 * 更多内容 * [这篇文章对应的博客文档](https://183461750.github.io/doc-record/docker/dev_utls/dev-container/remote-ssh/frp/article/doc) * [对应的GitHub仓库](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/dev-container/remote-ssh/frp/v5/doc.md), 可以在这里找到相关的全部配置代码 > 想不到这么快就到说再见的时候了, 稍稍的期待一下吧, 下期再见👋 # docker-compose服务间依赖通过自定义健康检查实现顺序启动 Docker Compose中的`condition: service_healthy`配置是用来判断依赖的服务是否健康的。当一个服务依赖于另一个服务时,可以使用`depends_on`和`condition: service_healthy`来确保依赖的服务已经健康启动。 下面是关于如何判断服务是否健康的一些相关内容: 1. 健康检查命令:在Dockerfile或docker container run命令中,可以使用`HEALTHCHECK`来定义容器的健康检查命令[\[1\]](https://blog.csdn.net/weixin_48447848/article/details/122632562)。健康检查命令可以是任何能够返回0或非0退出代码的命令,例如使用`curl`命令检查服务是否可访问。 2. 健康检查参数:健康检查命令可以使用一些参数来配置检查的间隔、超时和重试次数等。常用的健康检查参数包括: * `--interval`:指定检查的间隔时间,默认为30秒。 * `--timeout`:指定每次检查的超时时间,默认为30秒。 * `--retries`:指定连续失败的次数后将服务标记为不健康,默认为3次。 * `--start-period`:指定容器启动后等待健康检查开始的时间,默认为0秒。 3. `condition: service_healthy`配置:在Docker Compose中,可以使用`condition: service_healthy`来指定依赖的服务是否健康。当依赖的服务的健康状态为健康时,才会启动当前的服务。这样可以确保依赖的服务已经成功启动并且可用。 下面是一个示例的docker-compose.yml文件,演示了如何使用健康检查和`condition: service_healthy`来判断服务是否健康并依次启动: ```yaml version: "3.8" services: flask: build: context: ./flask dockerfile: Dockerfile image: flask-demo:latest environment: - REDIS_HOST=redis-server - REDIS_PASS=${REDIS_PASSWORD} healthcheck: test: ["CMD", "curl", "-f", "http://localhost:5000"] interval: 30s timeout: 3s retries: 3 start_period: 40s depends_on: redis-server: condition: service_healthy networks: - backend - frontend redis-server: image: redis ``` 在上述示例中,flask服务依赖于redis-server服务。flask服务的健康检查命令是使用`curl`命令检查`http://localhost:5000`是否可访问。只有当redis-server服务的健康状态为健康时,flask服务才会启动。 *** Learn more: 1. [【Docker系列】Docker Compose 服务依赖和健康检查\_docker-compose healthcheck-CSDN博客](https://blog.csdn.net/weixin_48447848/article/details/122632562) 2. [\[docker\]-docker-compose通过healthcheck判断容器状态并依次启动\_docker-compose healthcheck-CSDN博客](https://blog.csdn.net/xujiamin0022016/article/details/123642210) 3. [Docker compose 服务依赖关系及健康检查 - 掘金](https://juejin.cn/post/7250374485567619131) ## 参考内容 [Section titled “参考内容”](#参考内容) * [nocodb部署yml](https://github.com/nocodb/nocodb/blob/develop/docker-compose/pg/docker-compose.yml) # docker镜像源 [参考文章](https://developer.aliyun.com/article/653081) ```bash # Docker 官方中国区 # https://registry.docker-cn.com # 网易 # http://hub-mirror.c.163.com # ustc # https://docker.mirrors.ustc.edu.cn # 测试镜像源 docker run --rm hello-world --registry-mirror=https://registry.docker-cn.com docker run --rm hello-world --registry-mirror=http://hub-mirror.c.163.com docker run --rm hello-world --registry-mirror=https://docker.mirrors.ustc.edu.cn docker run --rm node:14.21.1-slim --registry-mirror=https://registry.docker-cn.com docker run --rm node:14.21.1-slim --registry-mirror=http://hub-mirror.c.163.com docker run --rm node:14.21.1-slim --registry-mirror=https://docker.mirrors.ustc.edu.cn ``` * 最新可用的docker镜像源 * docker.fxxk.dedyn.io * 顺便研究下Cloudflare Workers的工作原理, 感觉挺有用的 * [相关博客](https://blog.cmliussss.com/p/CF-Workers-docker.io/) * 自己部署的docker镜像源 * [docker镜像源](https://cf-workers-docker-io-ac6.pages.dev/) # ssh * [SSH 隧道简明教程](https://www.lixueduan.com/posts/linux/07-ssh-tunnel/) * 动态转发 * 请求地址为192.168.1.100:3000,则通过 SSH 转发的请求地址也是192.168.1.100:3000。 * ssh -N -D localhost:2000 root\@192.168.10.85 * 我们只需要在本地配置上 socks 代理,localhost:2000 即可把所有请求通过 ssh 2000 端口转发到 192.168.10.85 这台机器上去了。 * 本地转发 * 我们需要在 ServerA 上执行以下命令开启 ssh 隧道: * ssh -N -L 8888:192.168.10.134:8888 root\@192.168.10.85 * 执行后 serverA 上已经开始监听 8888 端口了,默认是在本地回环地址上,需要其他机器访问的话可以指定 ip 或者增加 -g 参数开启网关模式。 * socks5 代理 * [参考文章](https://wlwang41.github.io/content/ops/ssh%E9%9A%A7%E9%81%93%E4%BB%A3%E7%90%86.html) * [参考文章1](https://blog.bug-maker.com/archives/47.html) * [参考文章2](https://www.cnblogs.com/memphise/articles/6420019.html) * 可以使用一个叫做Sockscap的软件,把应用扔进去就能以代理的方式上网了。(部分需要调用多个进程的应用可能不行) * 如果你想把socks代理转换成http代理,可以用privoxy这个东东。 \~/.ssh/config ```bash # 上传密钥~/.ssh/id_ed25519_iu chmod 400 ~/.ssh/id_ed25519_iu Host mac.intranet.company HostName 10.0.1.251 User iuin IdentityFile ~/.ssh/id_ed25519_iu # PasswordAuthentication 123456 # ssh mac.intranet.company 看是否联通 ``` * [ssh动态代理](../../../../../../docker/doc/material/ai/ssh%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86.md) ```bash # 登录服务器10.0.1.233 # 后台启动ssh动态转发 ssh -o GatewayPorts=yes -D 2000 mac.intranet.company -NTfCg # 在本机中配置socks代理, 网络流量则会通过ssh转发到服务器上, 然后在访问互联网 # 配置地址: 10.0.1.233:2000 # PS: 可以配合clash一起使用, 实现通过ssh让中间机器去连接指定或多个VPN, 本机不连多余的VPN(其实是不想下载一堆的VPN相关软件), 只用clash就能透传流量过去 port: 7890 socks-port: 7891 allow-lan: false mode: Rule log-level: info external-controller: 127.0.0.1:9090 proxies: - name: iuin_bpDev_mac type: socks5 server: 10.0.1.233 port: 2000 proxy-groups: - name: ssh_g type: select proxies: - iuin_bpDev_mac rules: # 乐橘nacos所在服务器 - IP-CIDR,10.0.10.180/32,ssh_g - DOMAIN-SUFFIX,yelomall.cn,ssh_g ``` # 一键更换Linux优质的软件源和docker源 [参考文章](https://mp.weixin.qq.com/s/XlluE2SDzyNjTjg-_kRdyw) [镜像地址](https://linuxmirrors.cn/) ```bash # 是用root命令执行 # 软件源一键更换 bash <(curl -sSL https://linuxmirrors.cn/main.sh) # Docker 一键安装 bash <(curl -sSL https://linuxmirrors.cn/docker.sh) ``` # arthas查看sql [参考文章](http://codefun007.xyz/a/article_detail/2392.htm) ```bash watch java.sql.Connection prepareStatement '{params,throwExp}' -x 3 watch java.sql.Statement executeQuery '{params,throwExp}' -x 3 watch org.apache.ibatis.mapping.BoundSql getSql '{params,returnObj,throwExp}' -x 3 ``` * temp ```bash watch java.sql.Statement executeQuery '{params,returnObj,throwExp}' -n 5 -x 3 watch java.sql.Statement executeQuery '{params,returnObj,throwExp}' -x 3 watch java.sql.Statement executeQuery '{params,returnObj,throwExp}' -x 2 # 过滤某个表的sql watch java.sql.Statement executeQuery '{params,returnObj,throwExp}' -x 2 | grep -C 5 "com_commodity_shop" # 看到的是jpa的非本地sql watch javax.persistence.EntityManager createQuery '{params,returnObj,throwExp}' -n 5 -x 3 ``` # java.lang.OutOfMemoryError : unable to create new native Thread ```bash # 使用此命令查看正在运行的线程数 ps -elfT | wc -l ps -elfT | grep appName|wc -l # 要获取进程正在运行的线程数(可以使用 top 或 ps aux 获取进程 pid): ps -p -lfT | wc -l # 查找哪些进程正在创建线程 ps huH # 用户可以拥有的线程数量是有限制的。可以通过“最大用户进程数”行进行检查 ulimit -a # /proc/sys/kernel/threads-max 文件提供系统范围内的线程数限制。 root 用户可以更改该值 # 要更改限制(在本例中为 4096 个线程): ulimit -u 4096 # 使用 jps 列出所有 java 进程(只需在 shell 中执行 jps )并使用每个 Ghost 进程的 kill -9 pid bash 命令分别杀死它们时,它就解决了。 jps ``` # postgresql表死锁问题的排查方式_PostgreSQL_脚本之家 > ## Excerpt > > [Section titled “Excerpt”](#excerpt) > > 这篇文章主要介绍了postgresql表死锁问题的排查方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧 1.查询激活的执行中的sql,查看有哪些更新update的sql。 select \* from pg\_stat\_activity where state = ‘active’; 2\. 查询表中存在的锁 select a.locktype, a.database, a.pid, a.mode, a.relation, b.relname from pg\_locks a join pg\_class b on a.relation = b.oid where lower(b.relname) = ‘h5\_game’; 3\. 杀掉死锁进程 select pg\_terminate\_backend(pid) from pg\_stat\_activity where state = ‘active’ and pid != pg\_backend\_pid() —and pid = 14172 and pid in (select a.pid from pg\_locks a join pg\_class b on a.relation = b.oid where lower(b.relname) = ‘news\_content’) 锁模式 /\* NoLock is not a lock mode, but a flag value meaning “don’t get a lock” \*/ #define NoLock 0 \#define AccessShareLock 1 /\* SELECT */ #define RowShareLock 2 /* SELECT FOR UPDATE/FOR SHARE */ #define RowExclusiveLock 3 /* INSERT, UPDATE, DELETE */ #define ShareUpdateExclusiveLock 4 /* VACUUM (non-FULL),ANALYZE, CREATE \* INDEX CONCURRENTLY */ #define ShareLock 5 /* CREATE INDEX (WITHOUT CONCURRENTLY) */ #define ShareRowExclusiveLock 6 /* like EXCLUSIVE MODE, but allows ROW \* SHARE */ #define ExclusiveLock 7 /* blocks ROW SHARE/SELECT…FOR \* UPDATE */ #define AccessExclusiveLock 8 /* ALTER TABLE, DROP TABLE, VACUUM \* FULL, and unqualified LOCK TABLE \*/ **补充:Postgresql死锁的处理** 背景: 对表进行所有操作都卡住,原因可能是更新表时导致这个表死锁了,开始进行排查 ### 解决一:查询pg\_stat\_activity有没有记录 [Section titled “解决一:查询pg\_stat\_activity有没有记录”](#解决一查询pg_stat_activity有没有记录) pg版本10.2 select pid,query,\* from pg\_stat\_activity where datname=‘死锁的数据库’ and wait\_event\_type = ‘Lock’; select pg\_cancel\_backend(‘死锁那条数据的pid值’);##只能杀死select 语句, 对其他语句不生效 pg\_terminate\_backend(‘死锁那条数据的pid值’);#select,drop等各种操作 执行后发现select和delete表时正常执行,但truncate和drop表时会一直运行,也不报错。 “drop table” 和 “truncate table” 需要申请排它锁”ACCESS EXCLUSIVE”, 执行这个命令卡住时,说明此时这张表上还有操作正在进行,比如查询等, 那么只有等待这个查询操作完成,“drop table” 或”truncate table”或者增加字段的SQL才能获取这张表上的 “ACCESS EXCLUSIVE”锁,操作才能进行下去。 ### 解决二:查询pg\_locks是否有这个对象的锁 [Section titled “解决二:查询pg\_locks是否有这个对象的锁”](#解决二查询pg_locks是否有这个对象的锁) select oid,relname from pg\_class where relname=‘table name’; select locktype,pid,relation,mode,granted,\* from pg\_locks where relation= ‘上面查询出来的oid’; select pg\_terminate\_backend(‘进程ID’); 问题解决!!! 坑:一开始不知道pg\_cancel\_backend(‘死锁那条数据的pid值’);##只能杀死select 语句, 对其他语句不生效,杀了进程查询发现还存在,反复杀反复存在,换了pg\_terminate\_backend(‘进程ID’)问题就解决了。 以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。 原文链接: # SSH 远程端口转发配置指南:使用 socat 实现灵活的端口映射 ## 目录 [Section titled “目录”](#目录) 1. [概述](#%E6%A6%82%E8%BF%B0) 2. [配置详解](#%E9%85%8D%E7%BD%AE%E8%AF%A6%E8%A7%A3) 3. [工作原理](#%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86) 4. [使用方法](#%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95) 5. [故障排除](#%E6%95%85%E9%9A%9C%E6%8E%92%E9%99%A4) 6. [最佳实践](#%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5) 7. [高级配置](#%E9%AB%98%E7%BA%A7%E9%85%8D%E7%BD%AE) ## 概述 [Section titled “概述”](#概述) SSH 远程端口转发是一种强大的网络技术,允许您将远程服务器的端口转发到本地机器或其他目标地址。结合 socat 工具,您可以实现更灵活的端口映射和网络连接管理。 本文档详细介绍了如何配置和使用 SSH 远程端口转发,特别关注如何确保 socat 进程在 SSH 连接断开时自动终止,避免资源泄漏和端口占用问题。 ## 配置详解 [Section titled “配置详解”](#配置详解) 以下是完整的 SSH 配置文件示例: ```plaintext Host fa.remote.intranet.company HostName 10.0.16.146 User root IdentityFile \~/.ssh/id\_ed25519\_iu RemoteForward 9094 127.0.0.1:9093 RemoteCommand bash -c "trap 'kill %%1' EXIT; socat TCP-LISTEN:9093,fork TCP:127.0.0.1:9094 & exec bash" ForwardAgent yes RequestTTY yes ``` ### 配置项解析 [Section titled “配置项解析”](#配置项解析) #### 1. 基本连接配置 [Section titled “1. 基本连接配置”](#1-基本连接配置) ```plaintext Host fa.remote.intranet.company HostName 10.0.16.146 User root IdentityFile \~/.ssh/id\_ed25519\_iu ``` * `Host`:定义主机别名,方便后续引用 * `HostName`:远程服务器的实际 IP 地址或域名 * `User`:登录远程服务器使用的用户名 * `IdentityFile`:指定用于身份验证的 SSH 密钥文件 #### 2. 端口转发配置 [Section titled “2. 端口转发配置”](#2-端口转发配置) ```plaintext RemoteForward 9094 127.0.0.1:9093 ``` 这是核心配置项,实现远程端口转发: * `9094`:远程服务器上监听的端口 * `127.0.0.1:9093`:本地机器上的目标地址和端口 效果:远程服务器的 9094 端口收到的所有连接都会被转发到本地机器的 9093 端口。 #### 3. 自动启动 socat [Section titled “3. 自动启动 socat”](#3-自动启动-socat) ```plaintext RemoteCommand bash -c "trap 'kill %%1' EXIT; socat TCP-LISTEN:9093,fork TCP:127.0.0.1:9094 & exec bash" ``` 这个复杂的命令实现了以下功能: * `bash -c "..."`:在远程服务器上执行 bash 命令 * `trap 'kill %%1' EXIT`:设置退出陷阱,当 shell 退出时终止 socat 进程 * `socat TCP-LISTEN:9093,fork TCP:127.0.0.1:9094`:启动 socat 进行端口转发 * `TCP-LISTEN:9093`:在远程服务器的 9093 端口监听 * `fork`:为每个连接创建新的进程 * `TCP:127.0.0.1:9094`:转发到本地的 9094 端口 * `&`:在后台运行 socat * `exec bash`:启动交互式 bash shell #### 4. 其他配置项 [Section titled “4. 其他配置项”](#4-其他配置项) ```plaintext ForwardAgent yes RequestTTY yes ``` * `ForwardAgent yes`:启用 SSH 代理转发,允许在远程服务器上使用本地的 SSH 密钥 * `RequestTTY yes`:强制分配伪终端,确保获得交互式 shell ## 工作原理 [Section titled “工作原理”](#工作原理) 整个配置的工作流程如下: 1. **SSH 连接建立**:当您运行`ssh fa.remote.intranet.company`时,SSH 客户端会: * 使用指定的密钥文件进行身份验证 * 在远程服务器上建立 9094 端口的转发 * 执行 RemoteCommand 中指定的命令 1. **socat 启动**:RemoteCommand 会: * 设置退出陷阱 * 启动 socat 监听 9093 端口 * 启动交互式 bash shell 1. **端口转发流程**: ```plaintext 外部客户端 → 远程服务器:9093 → socat → 远程服务器:9094 → SSH转发 → 本地机器:9093 ``` 1. **连接关闭**:当您退出 bash shell 时: * trap 机制会捕获 EXIT 信号 * 终止 socat 进程 * SSH 连接关闭 * 所有转发端口释放 ## 使用方法 [Section titled “使用方法”](#使用方法) ### 基本使用 [Section titled “基本使用”](#基本使用) 1. **编辑 SSH 配置文件** ```plaintext nano \~/.ssh/config ``` 添加上述配置内容。 1. **建立连接** ```plaintext ssh fa.remote.intranet.company ``` 1. **验证配置** 在远程服务器上执行: ```plaintext ss -tunlp | grep 9093 \# 应该显示socat在监听9093端口 ss -tunlp | grep 9094 \# 应该显示ssh在监听9094端口 ``` 1. **测试端口转发** 从另一台机器测试: ```plaintext curl http://10.0.16.146:9093 ``` ### 后台运行 [Section titled “后台运行”](#后台运行) 如果您希望在后台运行端口转发,可以使用: ```plaintext ssh -fN fa.remote.intranet.company ``` * `-f`:在后台运行 * `-N`:不执行远程命令 ## 故障排除 [Section titled “故障排除”](#故障排除) ### 常见问题及解决方案 [Section titled “常见问题及解决方案”](#常见问题及解决方案) #### 1. 端口占用错误 [Section titled “1. 端口占用错误”](#1-端口占用错误) **症状**: ```plaintext Address already in use ``` **解决方案**: 检查并终止占用端口的进程: ```plaintext \# 在远程服务器上执行 ss -tunlp | grep 9093 kill -9 <进程ID> ``` 或者修改配置使用其他端口。 #### 2. 无法获得交互式 shell [Section titled “2. 无法获得交互式 shell”](#2-无法获得交互式-shell) **症状**:连接后直接退出或没有 bash 提示符 **解决方案**: 确保配置中包含: ```plaintext RequestTTY yes ``` 或者在命令行中使用: ```plaintext ssh -t fa.remote.intranet.company ``` #### 3. socat 在 SSH 断开后仍然运行 [Section titled “3. socat 在 SSH 断开后仍然运行”](#3-socat-在-ssh-断开后仍然运行) **症状**: ```plaintext ps -ef | grep socat \# 显示socat进程,父ID为1 ``` **解决方案**: 手动终止进程: ```plaintext pkill socat ``` 或者修改 RemoteCommand 确保 trap 正确工作: ```plaintext RemoteCommand bash -c "trap 'pkill socat' EXIT; socat TCP-LISTEN:9093,fork TCP:127.0.0.1:9094 & exec bash" ``` ## 最佳实践 [Section titled “最佳实践”](#最佳实践) ### 1. 使用不常用端口 [Section titled “1. 使用不常用端口”](#1-使用不常用端口) 避免使用常见服务端口(如 80、443、22 等),减少冲突风险。 ### 2. 添加端口占用检查 [Section titled “2. 添加端口占用检查”](#2-添加端口占用检查) 修改 RemoteCommand,添加端口占用检查: ```plaintext RemoteCommand bash -c "if ! ss -tunlp | grep -q 9093; then trap 'kill %%1' EXIT; socat TCP-LISTEN:9093,fork TCP:127.0.0.1:9094 & fi; exec bash" ``` ### 3. 使用 autossh 保持连接 [Section titled “3. 使用 autossh 保持连接”](#3-使用-autossh-保持连接) 对于需要长期运行的转发,使用 autossh: ```plaintext autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" fa.remote.intranet.company ``` ### 4. 日志记录 [Section titled “4. 日志记录”](#4-日志记录) 添加日志记录以便故障排除: ```plaintext RemoteCommand bash -c "trap 'kill %%1' EXIT; socat -d -d TCP-LISTEN:9093,fork TCP:127.0.0.1:9094 > /var/log/socat.log 2>&1 & exec bash" ``` ## 高级配置 [Section titled “高级配置”](#高级配置) ### 1. 多端口转发 [Section titled “1. 多端口转发”](#1-多端口转发) 您可以配置多个 RemoteForward: ```plaintext RemoteForward 9094 127.0.0.1:9093 RemoteForward 9095 127.0.0.1:9094 RemoteForward 9096 192.168.1.100:80 ``` ### 2. 条件执行 [Section titled “2. 条件执行”](#2-条件执行) 根据本地环境变量决定是否启动转发: ```plaintext Match exec "test -n \\"\$ENABLE\_FORWARD\\"" RemoteForward 9094 127.0.0.1:9093 ``` ### 3. 使用环境变量 [Section titled “3. 使用环境变量”](#3-使用环境变量) 在 RemoteCommand 中使用环境变量: ```plaintext RemoteCommand bash -c "PORT=\${PORT:-9093}; trap 'kill %%1' EXIT; socat TCP-LISTEN:\\\$PORT,fork TCP:127.0.0.1:9094 & exec bash" ``` 然后在连接时设置变量: ```plaintext PORT=9095 ssh fa.remote.intranet.company ``` ## 总结 [Section titled “总结”](#总结) SSH 远程端口转发结合 socat 是一种强大的网络工具,能够实现灵活的端口映射和连接管理。通过本文档介绍的配置方法,您可以: 1. 建立可靠的远程端口转发 2. 确保 socat 进程在 SSH 连接断开时自动终止 3. 获得完整的交互式 shell 体验 4. 避免常见的端口冲突和资源泄漏问题 这种配置特别适用于需要从外部访问内部服务、构建安全隧道或实现复杂网络拓扑的场景。 *** **更新时间**:2025 年 12 月 6 日 **版本**:1.0 **适用场景**:SSH 端口转发、远程访问、网络隧道 > (注:文档部分内容可能由 AI 生成) # Welcome Welcome to my blog! This is a sample post to verify the blog functionality. This blog is powered by [Docusaurus](https://docusaurus.io/). # 书目记录 本目录原存放电子书实体文件,来源标注为第三方聚合站。因著作权原因,实体文件已从仓库移除,此处仅保留书目信息。 ## 已移除的实体文件 [Section titled “已移除的实体文件”](#已移除的实体文件) | 书名 | 作者 | 出版年 | 原格式 | | ----------------------- | ---------- | ---- | ---- | | 富爸爸穷爸爸(20周年修订版) | 〔美〕罗伯特·清崎 | 2017 | mobi | | 小狗钱钱(套装全2册) | 〔德〕博多·舍费尔 | 2014 | epub | | 失落的百年致富圣经 | 〔美〕华勒思·华特斯 | 2008 | mobi | | 蛤蟆先生去看心理医生 | 〔英〕罗伯特·戴博德 | 2020 | mobi | | 心灵成长之旅:《蛤蟆先生去看心理医生》快速阅读 | — | — | pdf | 移除时间:2026-09-09 ## 说明 [Section titled “说明”](#说明) * 移除范围限于二进制实体文件,书目元数据保留在上表; * 文件在 Git 历史中仍可追溯,如需彻底清除需另行重写提交历史; * 后续如需补充阅读记录,建议以读书笔记形式写入本目录,不再存放受著作权保护的作品原件。 # llm在docker中部署相关文档 [参考文章](https://www.docker.com/blog/llm-docker-for-local-and-hugging-face-hosting/) ## 示例 [Section titled “示例”](#示例) ```bash docker run -it -p 7860:7860 --platform=linux/amd64 \ -e HUGGING_FACE_HUB_TOKEN="YOUR_VALUE_HERE" \ registry.hf.space/harsh-manvar-llama-2-7b-chat-test:latest python app.py # 打开浏览器并转到 http://localhost:7860: ``` ## 快速开始 [Section titled “快速开始”](#快速开始) ```bash git clone https://huggingface.co/spaces/harsh-manvar/llama-2-7b-chat-test ``` * Dockerfile [Dockerfile来源](https://huggingface.co/spaces/harsh-manvar/llama-2-7b-chat-test/blob/main/Dockerfile) ```dockerfile FROM python:3.9 RUN useradd -m -u 1000 user WORKDIR /code COPY ./requirements.txt /code/requirements.txt RUN pip install --upgrade pip RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt USER user # 该 --link 标志指示 Docker 创建硬链接而不是复制文件,这可以提高性能并减小映像的大小。 COPY --link --chown=1000 ./ /code ``` ```bash docker buildx build --platform=linux/amd64 -t local-llm:v1 . ``` ```bash docker run -it -p 7860:7860 --platform=linux/amd64 -e HUGGING_FACE_HUB_TOKEN="YOUR_VALUE_HERE" local-llm:v1 python app.py ``` # localAI使用记录 [官网](https://localai.io) ## 安装 [Section titled “安装”](#安装) [快速开始](https://localai.io/basics/getting_started/) ```bash # 一键安装, 但可能不适用低版本docker(好像拉下源码来后, 又正常了...) # 25.04.03测试可用, 版本为localai/localai:v2.27.0-ffmpeg, 使用的模型为gemma-3-1b-it # 在dify上的配置为(baseUrl: http://10.0.1.96:8888, model: gemma-3-1b-it) curl https://localai.io/install.sh | sh # 手动启动docker容器 docker run -p 8080:8080 --name local-ai -d -v $PWD/models:/build/models localai/localai:latest-aio-cpu # 手动创建卷的方式 docker volume create localai-models docker run -p 8080:8080 --name local-ai -d -v localai-models:/build/models localai/localai:latest-aio-cpu ``` * 关于使用语音转文字模型 由于 FFMpeg 的许可 ,它不包含在默认映像中。如果需要 FFMpeg,请使用以 -ffmpeg 结尾的图像。请注意,在使用音频转文本 LocalAI 的功能时需要 ffmpeg。 ```bash # 参考镜像 localai/localai:v2.26.0-ffmpeg ``` # camunda使用记录 ## 使用docker运行camunda [Section titled “使用docker运行camunda”](#使用docker运行camunda) ```bash # 拉取代码 git clone https://github.com/camunda/camunda-platform # 进入指定目录 cd docker-compose/camunda-8.6 # 启动容器 docker compose --profile modeling up -d # 打开web页面[localhost:8070](localhost:8070) ``` # doc ## 配置docker镜像私服hosts [Section titled “配置docker镜像私服hosts”](#配置docker镜像私服hosts) ```shell whereis hosts vi /etc/hosts 10.0.0.73 registry.docker.com ``` ## 配置不安全域名访问 [Section titled “配置不安全域名访问”](#配置不安全域名访问) ```shell vi /etc/docker/daemon.json { "registry-mirrors": [ "https://registry.docker-cn.com" ], "insecure-registries": [ "registry.docker.com:5000" (ip 为server端的ip) ] } # 重启服务 systemctl daemon-reload systemctl restart docker ``` ## 上传镜像到私服 [Section titled “上传镜像到私服”](#上传镜像到私服) ```shell ## 拉取一个镜像 docker pull nginx ## 查看全部镜像 docker images ## 标记本地镜像并指向目标仓库(ip:port/image_name:tag,该格式为标记版本号) docker tag nginx registry.docker.com:5000/nginx ## 提交镜像到仓库 docker push registry.docker.com:5000/nginx ## 查看全部镜像 curl -XGET http://registry.docker.com:5000/v2/_catalog ## 查看指定镜像 curl -XGET http://registry.docker.com:5000/v2/nginx/tags/list ``` # bak 以下是使用Docker Swarm部署Elasticsearch集群的步骤: 1. 环境准备: * 修改系统配置:在所有主机中,编辑`/etc/sysctl.conf`文件,并追加以下内容:`vm.max_map_count=262144`。保存后执行`sysctl -p`命令。 * 创建专用网络:使用以下命令创建一个名为`elastic`的overlay网络:`docker network create --driver overlay elastic` [\[1\]](https://www.cnblogs.com/JentZhang/p/17047797.html)。 2. 准备docker-compose文件: * 创建一个名为`docker-compose-es-cluster.yml`的文件,内容如下: ````yaml version: '3.3' services: kibana: image: kibana:7.10.1 environment: - ELASTICSEARCH_URL=http://es01:9200 - ELASTICSEARCH_HOSTS=http://es01:9200 - ELASTICSEARCH_USERNAME=elastic - ELASTICSEARCH_PASSWORD=vsUZGKNvjWRtTKPmDG ports: - "5601:5601" networks: - elastic deploy: mode: replicated replicas: 1 resources: limits: memory: 800M placement: constraints: - node.labels.es.replica==1 es01: image: elasticsearch:7.10.1 hostname: es01 environment: - network.publish_host=es01 - network.host=0.0.0.0 - node.name=es01 - cluster.name=es-docker-cluster - discovery.seed_hosts=es02,es03 - cluster.initial_master_nodes=es01,es02,es03 - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - path.repo=/usr/share/elasticsearch/backups - xpack.security.enabled=false - xpack.security.audit.enabled=false - xpack.security.transport.ssl.enabled=false - ELASTIC_PASSWORD=vsUZGKNvjWRtTKPmDG volumes: - es01_data:/usr/share/elasticsearch/data - es01_logs:/usr/share/elasticsearch/logs ports: - "9200:9200" networks: - elastic deploy: mode: replicated replicas: 1 resources: limits: cpus: "0.50" memory: 1G reservations: cpus: "0.25" memory: 1G placement: constraints: - node.labels.es.replica==1 es02: image: elasticsearch:7.10.1 hostname: es02 environment: - network.publish_host=es02 - network.host=0.0.0.0 - node.name=es02 - cluster.name=es-docker-cluster - discovery.seed_hosts=es01,es03 - cluster.initial_master_nodes=es01,es02,es03 - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - path.repo=/usr/share/elasticsearch/backups volumes: - es02_data:/usr/share/elasticsearch/data - es02_logs:/usr/share/elasticsearch/logs networks: - elastic deploy: mode: replicated replicas: 1 resources: limits: cpus: "0.50" memory: 1G reservations: cpus: "0.25" memory: 1G placement: constraints: - node.labels.es.replica==2 es03: image: elasticsearch:7.10.1 hostname: es03 environment: - network.publish_host=es03 - network.host=0.0.0.0 - node.name=es03 - cluster.name=es-docker-cluster - discovery.seed_hosts=es01,es02 - cluster.initial_master_nodes=es01,es02,es03 - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - path.repo=/usr/share/elasticsearch/backups volumes: - es03_data:/usr/share/elasticsearch/data - es03_logs:/usr/share/elasticsearch/logs networks: - elastic deploy: mode: replicated replicas: 1 resources: limits: cpus: "0.50" memory: 1G reservations: cpus: "0.以下是使用Docker Swarm部署Elasticsearch集群的步骤: 1. 环境准备: - 修改系统配置:在所有主机中,编辑`/etc/sysctl.conf`文件,并追加以下内容:`vm.max_map_count=262144`。保存后执行`sysctl -p`命令。 - 创建专用网络:使用以下命令创建一个名为`elastic`的overlay网络:`docker network create --driver overlay elastic`。 2. 准备docker-compose文件: - 创建一个名为`docker-compose-es-cluster.yml`的文件,内容如下: ```yaml version: '3.3' services: kibana: image: kibana:7.10.1 environment: - ELASTICSEARCH_URL=http://es01:9200 - ELASTICSEARCH_HOSTS=http://es01:9200 - ELASTICSEARCH_USERNAME=elastic - ELASTICSEARCH_PASSWORD=vsUZGKNvjWRtTKPmDG ports: - "5601:5601" networks: - elastic deploy: mode: replicated replicas: 1 resources: limits: memory: 800M placement: constraints: - node.labels.es.replica==1 es01: image: elasticsearch:7.10.1 hostname: es01 environment: - network.publish_host=es01 - network.host=0.0.0.0 - node.name=es01 - cluster.name=es-docker-cluster - discovery.seed_hosts=es02,es03 - cluster.initial_master_nodes=es01,es02,es03 - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - path.repo=/usr/share/elasticsearch/backups - xpack.security.enabled=false - xpack.security.audit.enabled=false - xpack.security.transport.ssl.enabled=false - ELASTIC_PASSWORD=vsUZGKNvjWRtTKPmDG volumes: - es01_data:/usr/share/elasticsearch/data - es01_logs:/usr/share/elasticsearch/logs ports: - "9200:9200" networks: - elastic deploy: mode: replicated replicas: 1 resources: limits: cpus: "0.50" memory: 1G reservations: cpus: "0.25" memory: 1G placement: constraints: - node.labels.es.replica==1 es02: image: elasticsearch:7.10.1 hostname: es02 environment: - network.publish_host=es02 - network.host=0.0.0.0 - node.name=es02 - cluster.name=es-docker-cluster - discovery.seed_hosts=es01,es03 - cluster.initial_master_nodes=es01,es02,es03 - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - path.repo=/usr/share/elasticsearch/backups volumes: - es02_data:/usr/share/elasticsearch/data - es02_logs:/usr/share/elasticsearch/logs networks: - elastic deploy: mode: replicated replicas: 1 resources: limits: cpus: "0.50" memory: 1G reservations: cpus: "0.25" memory: 1G placement: constraints: - node.labels.es.replica==2 es03: image: elasticsearch:7.10.1 hostname: es03 environment: - network.publish_host=es03 - network.host=0.0.0.0 - node.name=es03 - cluster.name=es-docker-cluster - discovery.seed_hosts=es01,es02 - cluster.initial_master_nodes=es01,es02,es03 - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - path.repo=/usr/share/elasticsearch/backups volumes: - es03_data:/usr/share/elasticsearch/data - es03_logs:/usr/share/elasticsearch/logs networks: - elastic deploy: mode: replicated replicas: 1 resources: limits: cpus: "0.50" memory: 1G reservations: cpus: "0.25" --- Learn more: 1. [docker swarm 搭建ES集群 - JentZhang - 博客园](https://www.cnblogs.com/JentZhang/p/17047797.html) 2. [docker swarm 搭建ES集群(TLS版) - JentZhang - 博客园](https://www.cnblogs.com/JentZhang/p/17227129.html) 3. [docker swarm es 集群-掘金](https://juejin.cn/s/docker%20swarm%20es%20%E9%9B%86%E7%BE%A4) ```` # 问题记录 ````md {"@timestamp":"2024-05-25T06:33:04.830Z", "log.level":"ERROR", "message":"node validation exception\n[1] bootstrap checks failed. You must address the points described in the following [1] lines before starting Elasticsearch. For more information see [https://www.elastic.co/guide/en/elasticsearch/reference/8.11/bootstrap-checks.html]\nbootstrap check failure [1] of [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]; for more information see [https://www.elastic.co/guide/en/elasticsearch/reference/8.11/_maximum_map_count_check.html]", "ecs.version": "1.2.0","service.name":"ES_ECS","event.dataset":"elasticsearch.server","process.thread.name":"main","log.logger":"org.elasticsearch.bootstrap.Elasticsearch","elasticsearch.node.name":"es01","elasticsearch.cluster.name":"es-docker-cluster"} 我用docker-compose启动es, 报错了 AI答: 根据您提供的错误日志和之前的笔记,您在使用Docker Compose启动Elasticsearch时遇到了"max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]"的错误。这是一个常见的问题,通常是因为Elasticsearch需要较高的`vm.max_map_count`设置来正常运行,而默认值通常不足以满足其需求。 要解决这个问题,您需要在宿主机上增加`vm.max_map_count`的值。这里有两种方法可以做到这一点: 1. **临时设置**(重启后失效): 执行以下命令: ```shell sudo sysctl -w vm.max_map_count=262144 ```` 这将立即生效,但如果宿主机重启,您需要重新执行此命令。 2. **永久设置**: 编辑`/etc/sysctl.conf`文件,在文件末尾添加以下行: ```shell vm.max_map_count=262144 ``` 然后执行`sysctl -p`命令使更改生效。这种方法的好处是,即使宿主机重启,设置也会保持。 请注意,如果您使用的是Docker Desktop的WSL2后端或其他虚拟化环境,可能需要在不同的地方进行设置。例如,在WSL2中,您可能需要在Windows的命令提示符或PowerShell中执行以下命令来调整WSL2虚拟机的设置: `shell wsl -d docker-desktop sysctl -w vm.max_map_count=262144 `或者,根据您的环境,可能需要查找特定于环境的设置方法。 完成这些设置后,重新启动您的Elasticsearch容器,应该能够解决启动时遇到的`vm.max_map_count`错误。 ```plaintext ``` # es部署文档 ## 启动命令 [Section titled “启动命令”](#启动命令) ```shell docker stack deploy -c docker-compose-es-cluster-tls.yml es ``` ## 检查集群部署是否正常 [Section titled “检查集群部署是否正常”](#检查集群部署是否正常) ```shell 在kibana的Dev Tools中访问:GET /_cat/nodes,显示如下结果: 10.0.1.64 20 54 12 0.98 1.87 4.47 cdhilmrstw - es03 10.0.1.62 51 54 12 0.98 1.87 4.47 cdhilmrstw - es02 10.0.1.60 57 54 12 0.98 1.87 4.47 cdhilmrstw * es01 ``` ## 参考文章 [Section titled “参考文章”](#参考文章) * [docker swarm 搭建ES集群(TLS版)](https://www.cnblogs.com/JentZhang/p/17227129.html) # 文档记录 ## 问题点 [Section titled “问题点”](#问题点) * es使用docker部署报错 es使用docker部署报错 max virtual memory areas vm.max\_map\_count \[65530] is too low, increase to at least \[262144] 怎么解决 *** 您好!根据您的搜索结果,我为您提供以下解决方案来解决Elasticsearch使用Docker部署时出现”max virtual memory areas vm.max\_map\_count is too low”错误。 解决方案如下: 1. 编辑 /etc/sysctl.conf 文件,追加以下内容: ````shell vm.max_map_count=262144 ``` 保存文件后,执行以下命令使修改生效: ```shell sysctl -p ``` 最后重新启动Elasticsearch服务即可成功解决问题 [[1]](https://blog.csdn.net/BigData_Mining/article/details/108927120)。 ```` 请注意,如果您是在Docker容器中部署Elasticsearch,您需要在宿主机上修改该参数,而不是在容器镜像中修改。 希望这些信息对您有所帮助! *** Learn more: 1. [docker下安装elasticSearch报错:\[1\]: max virtual memory areas vm.max\_map\_count \[65530\] is too low-CSDN博客](https://blog.csdn.net/BigData_Mining/article/details/108927120) 2. [elasticsearch启动报错max virtual memory areas解决办法 - minseo - 博客园](https://www.cnblogs.com/minseo/p/12978561.html) 3. [草履虫也能看懂的ELK搭建流程 - 真正的大英雄 - 博客园](https://www.cnblogs.com/zhangdali/p/15671538.html) # docker-compose部署hadoop集群 ## 创建网络 [Section titled “创建网络”](#创建网络) ```shell docker network create --driver overlay --attachable --subnet 10.11.0.0/24 sg-hadoop ``` ## 创建标签 [Section titled “创建标签”](#创建标签) ```shell docker node update --label-add hadoop-datanode=datanode sangang ``` *** ## 部署启动与查看 [Section titled “部署启动与查看”](#部署启动与查看) ### docker stack部署启动 [Section titled “docker stack部署启动”](#docker-stack部署启动) ```shell docker stack deploy -c docker-compose.yml hadoop ``` ### 查看服务状态,一秒一次,启动之后可通过IP:端口访问界面 [Section titled “查看服务状态,一秒一次,启动之后可通过IP:端口访问界面”](#查看服务状态一秒一次启动之后可通过ip端口访问界面) ```shell watch -n 1 docker stack services hadoop ``` ### 查看服务所在node节点 [Section titled “查看服务所在node节点”](#查看服务所在node节点) ```shell docker stack ps hadoop ``` ### 停止删除hadoop服务 [Section titled “停止删除hadoop服务”](#停止删除hadoop服务) ```shell docker stack rm hadoop ``` # deploy ## 参考 [Section titled “参考”](#参考) > # deploy ## 单机部署 [Section titled “单机部署”](#单机部署) ```shell docker run \ -p 3306:3306 --name mymysql \ -v $PWD/conf:/etc/mysql/conf.d \ -v $PWD/logs:/logs \ -v $PWD/data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=123456 -d mysql # 一次性的 docker run -p 3306:3306 --name mymysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql ``` ```text -p 3306:3306:将容器的 3306 端口映射到主机的 3306 端口。 -v -v $PWD/conf:/etc/mysql/conf.d:将主机当前目录下的 conf/my.cnf 挂载到容器的 /etc/mysql/my.cnf。 -v $PWD/logs:/logs:将主机当前目录下的 logs 目录挂载到容器的 /logs。 -v $PWD/data:/var/lib/mysql :将主机当前目录下的data目录挂载到容器的 /var/lib/mysql 。 -e MYSQL_ROOT_PASSWORD=123456:初始化 root 用户的密码。 ``` # mysql相关记录 ## 连接数据库 [Section titled “连接数据库”](#连接数据库) ```bash # 方式一:直接在宿主机中执行命令 mysql -h $hostname -u $username -p ``` ## 备份数据(包含表数据和ddl结构) [Section titled “备份数据(包含表数据和ddl结构)”](#备份数据包含表数据和ddl结构) ```bash # 方式一:进入容器中执行命令,将结果写入到控制台中 mysqldump -h $hostname -u $username -p $database $table # 方式二:宿主机中执行命令,并将结果写入到指定文件中 echo "$password" | docker exec -i $container_id mysqldump -h $hostname -u $username -p $database $table > $table.sql # 方式三:运行一次性容器执行命令,并将结果写入到指定文件中 echo "$password" | docker run -i --rm mysql:5.7 mysqldump -h $hostname -u $username -p $database $table > $table.sql ``` ```bash # 导出整个库 echo "$password" | docker run -i --rm mysql:5.7 mysqldump -h $hostname -u $username -p $database > ./backup/$database.sql ``` ## 导出数据(指定sql) [Section titled “导出数据(指定sql)”](#导出数据指定sql) ```bash # 方式一: 进入容器中执行命令,将结果写入到控制台中 mysql -h -u -p -e "" > # 方式二: 宿主机中执行命令,并将结果写入到指定文件中 docker exec -i mysql -h -u -p -e "" > # 方式三:运行一次性容器执行命令,并将结果写入到指定文件中 docker run -i --rm mysql:5.7 mysql -h -u -p -e "" > # 方式四: 用方式二的命令,导出数据到csv文件中 docker exec -i mysql -h -u -p -e "" | sed 's/\t/","/g;s/^/"/;s/$/"/' > ``` # mysql ndb cluster相关文档 ## 相关链接 [Section titled “相关链接”](#相关链接) * [MySQL NDB Cluster使用docker compose一键部署](https://blog.csdn.net/User287/article/details/130110900) # docker swarm版部署文档 ## 创建网络 [Section titled “创建网络”](#创建网络) ```shell # 初始化swarm # docker swarm init # 这里网络可以不创建,需要的话可以通过以下命令创建 # docker network create -d overlay --attachable middleware ``` ## 启动集群 [Section titled “启动集群”](#启动集群) ```shell docker stack deploy -c docker-compose.yml mysqlCluster ``` ## 参考资料 [Section titled “参考资料”](#参考资料) * [docker环境安装MySQL-Cluster](http://t.csdnimg.cn/9KmNs) # 文档说明 ## [参考文章](https://post.smzdm.com/p/alpompze/) [Section titled “参考文章”](#参考文章) ## [参考作者](https://zhiyou.smzdm.com/member/9424085625/) [Section titled “参考作者”](#参考作者) *** ## 问题 [Section titled “问题”](#问题) ### General error: 4047 InnoDB refuses to write tables with ROW\_FORMAT=COMPRESSED or KEY\_BLOCK\_SIZE. [Section titled “General error: 4047 InnoDB refuses to write tables with ROW\_FORMAT=COMPRESSED or KEY\_BLOCK\_SIZE.”](#general-error-4047-innodb-refuses-to-write-tables-with-row_formatcompressed-or-key_block_size) * [参考文章](https://bbs.archlinux.org/viewtopic.php?id=268127) ## nextCloud.yml文件相关说明 [Section titled “nextCloud.yml文件相关说明”](#nextcloudyml文件相关说明) ```shell # 磁盘空间不够用的话,可以对某个目录进行挂载到移动硬盘之类的地方去,使用命令: mount ``` # samba ```shell docker run -it \ --name samba_docker \ #为新的容器命一个名,方便启动、停止、删除等操作,毕竟一长串字符不好输入 -p 139:139 \ #将主机的139端口映射到samba_docker这个容器的139端口上 -p 445:445 \ #将主机的445端口映射到samba_docker这个容器的445端口上 -v /home/shares/shareA:/home/shares/shareA \ # 将主机上的共享目录向容器进行映射 -d dperson/samba \ #以dperson/samba这个dockers镜像为模板,建立容器 -w "WORKGROUP" \ #从这里开始是dperson/samba 的参数,上面是docker run 的参数。这里指定了工作组 -u "userA;123456789" \ #为samba服务设置账户和密码 -s "shareA;/home/shares/shareA;yes;no;no;userA;userA;userA" 最后一行以分号为间隔,分别是: 共享文件夹的名称;共享在samba容器中的路径;共享名称对所有工作组用户可见;不是只读(也就是说可写);不允许guest用户;指定共享的所有权用户;指定共享的超级用户;指定具有写权限的用户; 至于在共享文件夹中所创建的文件、文件夹的权限,通过: docker exec -it 4ae45cd4f491 /bin/bash 用vi 修改容器内的samba的配置文档 /etc/samba/smb.conf 即可。 ``` ```shell docker run -it --name samba_docker -p 139:139 -p 445:445 -v /home/shares/share:/home/shares/share -d dperson/samba -w "WORKGROUP" -u "user;pwd" -s "share;/home/shares/share;yes;no;no;user;user;user" ``` # postgresql数据库相关文档 ## 部署 [Section titled “部署”](#部署) * [参考文章](http://t.csdn.cn/awC63) * 使用的容器为\[bitnami/postgresql:latest] ```shell # 创建目录 mkdir -p /www/gfs-share/postgresql/data/ /www/gfs-share/postgresql/conf/ # 调整目录权限 sudo chown 1001:1001 /www/gfs-share/postgresql/data/ sudo chown 1001:1001 /www/gfs-share/postgresql/conf/ # 启动容器 docker stack up -c postgresql.yml data ``` * 后期配置 ```shell # 默认配置文件`/www/gfs-share/postgresql/conf/postgresql.conf` # 创建自定义配置文件`/www/gfs-share/postgresql/conf/conf.d/custom.conf` # 最大连接数,默认是100 max_connections = 10000 # 查看最大连接数 show max_connections; ``` ## 备份数据 [Section titled “备份数据”](#备份数据) ```bash docker exec -it fc870c5cd426 pg_dump --dbname=iuin --create --clean --if-exists --user aaa # pg_dump -h your_host -p your_port -U your_username -d your_database -f dump.sql export containerId=xxx host=localhost port=5432 username=postgres password=root database=xxx echo "$password" | docker exec -i $containerId pg_dump -h $host -p $port -U $username -d $database -f $database.sql echo "$password" | docker exec -i $containerId pg_dump -h $host -p $port -U $username -d $database > ./backup/$database.sql ``` # redis 官方客户端 ```shell # 使用docker部署客户端页面 docker run -v redisinsight:/db -p 8001:8001 redislabs/redisinsight:latest # ps: 也许可能起不起来,但没关系,可以尝试手动起下,也许就可以了[docker start ${containerId}] ``` # 部署记录 ## todo [Section titled “todo”](#todo) * 测试这个配置的IP调整为服务名,看看是否可行 * 相关配置文件[redis.yml](./simple/v2/redis.yml) ```shell echo 'cluster-announce-ip 10.0.16.27' >> redis.conf && # echo 'cluster-announce-ip redis1' >> redis.conf && ``` # 部署内网redis ## 相关执行命令 [Section titled “相关执行命令”](#相关执行命令) ```bash # 启动集群节点 docker stack up -c redis.yml rds-cluster # 打印创建集群的命令 echo docker exec -it $(docker ps -qf "name=rds-cluster_redis1.1") redis-cli --cluster create $(docker inspect -f '{{.NetworkSettings.Networks.middleware.IPAddress}}:{{range $p, $conf := .NetworkSettings.Ports}}{{if eq (index (split $p "/") 0 | printf "%.3s") "800"}}{{(index (split $p "/") 0)}}{{end}}{{end}}' $(docker ps -qf "name=rds-cluster_redis")) --cluster-replicas 0 -a foobared ``` # 说明文档 * 简化版流程 * todo:要记得检查yml文件中的IP是否正确,是否变更过 ```shell # 启动节点 docker stack deploy -c redis.yml redis-cluster # 搭建集群(自动拼接端口的方式) docker exec -it $(docker ps -qf "name=redis-cluster_redis1.1") redis-cli --cluster create $(for index in {1..6}; do echo "10.0.16.17:700${index}"; done) --cluster-replicas 1 -a foobared # 查看集群是否健康 docker exec -it $(docker ps -qf "name=redis-cluster_redis1.1") redis-cli -p 7001 -a foobared cluster info ### 测试执行命令 docker exec -it $(docker ps -qf "name=redis-cluster_redis1.1") redis-cli -c -p 7001 -a foobared info Replication ``` * 自动输入yes ```bash # 自动拼接并输入yes执行命令 # 方式一 yes yes | docker exec -i $(docker ps -qf "name=rds-cluster_redis1.1") redis-cli --cluster create $(docker inspect -f '{{.NetworkSettings.Networks.middleware.IPAddress}}:{{range $p, $conf := .NetworkSettings.Ports}}{{if eq (index (split $p "/") 0 | printf "%.3s") "800"}}{{(index (split $p "/") 0)}}{{end}}{{end}}' $(docker ps -qf "name=rds-cluster_redis")) --cluster-replicas 0 -a foobared # 方式二 docker exec -i $(docker ps -qf "name=rds-cluster_redis1.1") redis-cli --cluster create $(docker inspect -f '{{.NetworkSettings.Networks.middleware.IPAddress}}:{{range $p, $conf := .NetworkSettings.Ports}}{{if eq (index (split $p "/") 0 | printf "%.3s") "800"}}{{(index (split $p "/") 0)}}{{end}}{{end}}' $(docker ps -qf "name=rds-cluster_redis")) --cluster-replicas 0 -a foobared << EOF yes EOF ``` * 删除指定前缀的volume * grep的-o参数为只打印匹配到的字符串 * xargs的-r参数为如果没有参数输入,xargs命令将不会执行后面的命令。 ```bash docker volume ls | grep -o "redis-cluster.*" | xargs -r docker volume rm ``` # 说明文档 ```shell # 需创建网络,看/doc/docker-networks.md文件 docker network create -d overlay --attachable middleware # 启动节点 docker stack deploy -c redis.yml redis-cluster # 部署集群的命令,通过echo打印出具体命令,再修改成对应的端口 echo docker exec -it $(docker ps -qf "name=redis-cluster_redis1.1") redis-cli --cluster create $(docker inspect -f '{{.NetworkSettings.Networks.middleware.IPAddress}}:700' $(docker ps -qf "name=redis-cluster_redis")) --cluster-replicas 1 -a foobared # 修改端口后的部署集群命令(可用docker ps查看端口的顺序)(PS: 所有的IP都需要应用能够正常访问才行(PS: 放弃了这个做法,还是用docker内网IP,应用部署到同一docker network即可)) docker exec -it 9f11d0bda1a1 redis-cli --cluster create 10.0.1.225:7001 10.0.1.223:7006 10.0.1.221:7005 10.0.1.219:7004 10.0.1.217:7003 10.0.1.215:7002 --cluster-replicas 1 -a foobared # 10.0.1.144:7001,10.0.1.142:7006,10.0.1.140:7005,10.0.1.138:7004,10.0.1.136:7003,10.0.1.134:7002 # 查看集群是否健康 docker exec -it $(docker ps -qf "name=redis-cluster_redis1.1") redis-cli -p 7001 -a foobared cluster info ### 测试执行命令 docker exec -it $(docker ps -qf "name=redis-cluster_redis1.1") redis-cli -c -p 7001 -a foobared info Replication #################################################################################################################################### ## 示例 # 自动拼接端口的方式 echo docker exec -it $(docker ps -qf "name=redis-cluster_redis1.1") redis-cli --cluster create $(index=1; for ip in $(docker inspect -f '{{.NetworkSettings.Networks.middleware.IPAddress}}' $(docker ps -qf "name=redis-cluster_redis")); do echo "${ip}:700${index}"; ((index++)); done) --cluster-replicas 1 -a foobared ``` ## 参考文章 [Section titled “参考文章”](#参考文章) * [参考文章](https://blog.csdn.net/chinasun2015/article/details/122474365) * [参考文章(官方)](https://raw.githubusercontent.com/redis/redis/5.0/redis.conf) # 说明文档 * 简化版流程 ```shell # 启动节点 docker stack deploy -c redis.yml redis-cluster # 搭建集群(自动拼接端口的方式) docker exec -it $(docker ps -qf "name=redis-cluster_redis1.1") redis-cli --cluster create $(for index in {1..6}; do echo "10.0.16.17:700${index}"; done) --cluster-replicas 1 -a foobared # 查看集群是否健康 docker exec -it $(docker ps -qf "name=redis-cluster_redis1.1") redis-cli -p 7001 -a foobared cluster info ### 测试执行命令 docker exec -it $(docker ps -qf "name=redis-cluster_redis1.1") redis-cli -c -p 7001 -a foobared info Replication ``` # deploy ### 主redis服务配置 [Section titled “主redis服务配置”](#主redis服务配置) ```plaintext /path/to/redis/config/master.conf ## 自定义配置 ``` ### 从redis服务配置 [Section titled “从redis服务配置”](#从redis服务配置) ```plaintext /path/to/redis/config/slave.conf ## 自定义配置 slaveof master 6379 ``` # deploy-single ### 单机部署 [Section titled “单机部署”](#单机部署) ```shell docker run -p 6379:6379 --name redis -v /data/docker/redis/config/redis.conf:/etc/redis/redis.conf -v /data/docker/redis/data:/data -d redis redis-server /etc/redis/redis.conf --appendonly yes --requirepass "foobared" ``` # docker-deploy ## 创建 6 个 Redis 容器 [Section titled “创建 6 个 Redis 容器”](#创建-6-个-redis-容器) ```shell docker create --name redis-node1 --net host -v /data/redis-data/node1:/data redis:5.0.5 --cluster-enabled yes --cluster-config-file nodes-node-1.conf --port 6379 docker create --name redis-node2 --net host -v /data/redis-data/node2:/data redis:5.0.5 --cluster-enabled yes --cluster-config-file nodes-node-2.conf --port 6380 docker create --name redis-node3 --net host -v /data/redis-data/node3:/data redis:5.0.5 --cluster-enabled yes --cluster-config-file nodes-node-3.conf --port 6381 docker create --name redis-node4 --net host -v /data/redis-data/node4:/data redis:5.0.5 --cluster-enabled yes --cluster-config-file nodes-node-4.conf --port 6382 docker create --name redis-node5 --net host -v /data/redis-data/node5:/data redis:5.0.5 --cluster-enabled yes --cluster-config-file nodes-node-5.conf --port 6383 docker create --name redis-node6 --net host -v /data/redis-data/node6:/data redis:5.0.5 --cluster-enabled yes --cluster-config-file nodes-node-6.conf --port 6384 ``` * 部分参数解释: ```plaintext --cluster-enabled:是否启动集群,选值:yes 、no --cluster-config-file 配置文件.conf :指定节点信息,自动生成 --cluster-node-timeout 毫秒值: 配置节点连接超时时间 --appendonly:是否开启持久化,选值:yes、no ``` ## 启动 Redis 容器 [Section titled “启动 Redis 容器”](#启动-redis-容器) ```shell docker start redis-node1 redis-node2 redis-node3 redis-node4 redis-node5 redis-node6 ``` ## 组建 Redis 集群 [Section titled “组建 Redis 集群”](#组建-redis-集群) ```shell # 这里以 redis-node1 实例为例 docker exec -it redis-node1 /bin/bash # 组建集群,10.211.55.4为当前物理机的ip地址 redis-cli --cluster create 10.211.55.4:6379 10.211.55.4:6380 10.211.55.4:6381 10.211.55.4:6382 10.211.55.4:6383 10.211.55.4:6384 --cluster-replicas 1 # 创建成功后,通过 redis-cli 查看一下集群节点信息: root@CentOS7:/data# redis-cli 127.0.0.1:6379> cluster nodes ``` ## 关于Redis集群搭建 [Section titled “关于Redis集群搭建”](#关于redis集群搭建) ```shell # 手动添加节点 redis-cli --cluster add-node 10.211.55.4:6383 10.211.55.4:6379 --cluster-slave --cluster-master-id b0c32b1dae9e7b7f7f4b74354c59bdfcaa46f30a redis-cli --cluster add-node 10.211.55.4:6384 10.211.55.4:6379 --cluster-slave --cluster-master-id 111de8bed5772585cef5280c4b5225ecb15a582e ``` # refer ## 参考 [Section titled “参考”](#参考) * [docker安装redis(单机)](https://www.cnblogs.com/marshhu/p/12636536.html) ## test [Section titled “test”](#test) > 127.0.0.1:26379> sentinel failover mymaster # Redis相关记录 ## 数据导出 [Section titled “数据导出”](#数据导出) ```shell # 使用exec和DUMP命令导出数据 docker exec -it <你的Redis容器名或ID> redis-cli -a foobared DUMP your_key_name > /path/to/your/key.dump # 使用临时容器导出数据 docker run --rm --link <你的Redis容器名或ID>:redis -it redis redis-cli -h redis DUMP your_key_name > /path/to/your/key.dump ``` * 相关链接 * [数据导出](../../../../../middleware/data/redis/redis.md#%E5%AF%BC%E5%87%BAredis%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE) ## 监听命令 [Section titled “监听命令”](#监听命令) MONITOR命令貌似只能监听当前实例的命令,无法监听集群内其他实例的命令。 ```shell # 监听是否执行了指定key docker exec -it 017daffcd5a3 redis-cli -c -p 7001 -a foobared MONITOR | grep "xx:key" # 指定host docker exec -it 017daffcd5a3 redis-cli -c -h redis2 -p 7002 -a foobared MONITOR | grep "formative:prize" ``` # TiDB部署记录 ## 启动命令 [Section titled “启动命令”](#启动命令) ```shell docker swarm init # if your docker daemon is not already part of a swarm mkdir -p data logs docker stack deploy tidb -c docker-swarm.yml mysql -h 127.0.0.1 -P 4000 -u root ``` ## 参考资料 [Section titled “参考资料”](#参考资料) * [tidb-docker-compose官方部署配置](https://github.com/pingcap/tidb-docker-compose) # TiDB dashboard With Grafana v5.x or later, we can use provisioning feature to statically provision datasources and dashboards. No need to use scripts to configure Grafana. The JSON files in dashboards are copied from [tidb-ansible](https://github.com/pingcap/tidb-ansible/tree/master/scripts), and need to replace variables in the json file(It was did by python file before). It is used in [tidb-docker-compose](https://github.com/pingcap/tidb-docker-compose) and [tidb-operator](https://github.com/pingcap/tidb-operator). # 使用Jenkins构建node项目 ## Jenkins配置 [Section titled “Jenkins配置”](#jenkins配置) * 创建一个自由风格的项目 * 使用gitee作为代码源 * 在构建步骤中添加\[执行 shell]步骤 ```shell pwd # 安装pnpm npm install -g pnpm # 安装依赖(非必须) pnpm install # 构建项目 pnpm run build # 删除除 node_modules和dist 以外的所有内容 ls | grep -v 'node_modules\|dist' | xargs rm -rf ``` * 在构建步骤中添加\[Send files or execute commands over SSH(通过ssh远程执行shell)]步骤 ```shell export app_version='1.0' export docker_jenkins_workspace="/var/lib/docker/volumes/mng_jenkins_home/_data/workspace/" cd $docker_jenkins_workspace/$JOB_NAME mkdir -p ./nginx/conf.d/ # 添加default.conf文件 tee ./nginx/conf.d/default.conf <<-'EOF' server { listen 80; listen [::]:80; server_name localhost; #access_log /var/log/nginx/host.access.log main; location / { root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html; # 用于解决刷新页面后,显示404的问题 } } EOF # 编辑Dockerfile文件 echo "FROM nginx" > Dockerfile echo "MAINTAINER Fa" >> Dockerfile echo "WORKDIR /usr/share/nginx/html" >> Dockerfile echo "RUN rm -rf *" >> Dockerfile echo "ADD ./dist ." >> Dockerfile echo "ADD ./nginx/conf.d/default.conf /etc/nginx/conf.d/" >> Dockerfile echo "EXPOSE 80" >> Dockerfile # 构建镜像 docker build --no-cache -t $JOB_NAME:$app_version . # 上传镜像到私服 docker tag $JOB_NAME:$app_version registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version docker push registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version # 删除空镜像 docker images | awk '{if($1=="")print $3}' | xargs docker rmi &> /dev/null # 编辑stack yml文件 tee $JOB_NAME.yml <<-'EOF' version: '3.5' services: $JOB_NAME: image: registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:${app_version} networks: - middleware deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure networks: middleware: external: true EOF docker stack up -c $JOB_NAME.yml app # 删除除 node_modules 以外的所有内容 ls | grep -v 'node_modules' | xargs rm -rf ``` * Nginx添加代理配置 * 在conf.d目录中添加mall-admin-web-demo.conf文件 ```shell server { listen 80; server_name mall-admin-web-demo.iuin.xyz iuin.xyz; access_log /var/log/mall-admin-web-demo_access.log; error_log /var/log/mall-admin-web-demo_error.log; location / { include cors.conf; proxy_set_header Host $host; proxy_set_header X-real-ip $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://mall-admin-web-demo; } } ``` ## 部署 [Section titled “部署”](#部署) ```shell # 镜像下载问题,可试这添加--with-registry-auth看看 docker stack up -c $JOB_NAME.yml --with-registry-auth app ``` # 构建tomcat应用的相关记录 ## 环境变量 [Section titled “环境变量”](#环境变量) * 系统管理 -> 系统配置 -> 全局属性 -> 环境变量 -> 新增键值对 * DOCKER\_JENKINS\_WORKSPACE : /var/lib/docker/volumes/soft\_jenkins\_home/\_data/workspace ## jdk配置 [Section titled “jdk配置”](#jdk配置) ```shell # 新建目录 cd /var/lib/docker/volumes/soft_jenkins_home/_data && mkdir -p ./soft/jdks # 下载jdk wget https://corretto.aws/downloads/latest/amazon-corretto-8-x64-linux-jdk.tar.gz wget https://corretto.aws/downloads/latest/amazon-corretto-11-x64-linux-jdk.tar.gz # 解压 tar -zxvf amazon-corretto-8-x64-linux-jdk.tar.gz # 系统管理 -> 全局工具配置 -> JDK # JAVA_HOME(/var/jenkins_home/soft/jdks/amazon-corretto-8.332.08.1-linux-x64) ``` ## maven配置 [Section titled “maven配置”](#maven配置) ```shell # 下载Maven Integration插件 # 自定义settings.xml的配置 cd /var/lib/docker/volumes/soft_jenkins_home/_data && mkdir -p ./soft/maven code settings.xml # 复制./conf/settings.xml文件内容 # 修改标签内容 # 调整[系统管理 -> 全局工具配置 -> Maven 配置] # 默认(和全局) settings 提供 -> 文件系统中的 settings 文件 -> 文件路径(/var/jenkins_home/soft/maven/settings.xml) # maven v3.6.3 ``` *** ## 构建脚本 [Section titled “构建脚本”](#构建脚本) * maven 构建 * 构建 -> 添加构建步骤 -> 调用顶层 maven 目标 ```shell # 目标 clean install -Dmaven.test.skip=true -Pprivate -Djava.awt.headless=true # 也可替换为以下命令 clean package -D maven.test.skip=true -P prod help:active-profiles ``` * send build artifacts over SSH (Transfers Set -> Exec command) ```shell # 第四版(swarm+私服) # docker images | awk '{if($1=="$JOB_NAME") print $3}' | xargs docker rmi export app_version='1.0' if [ -z $DOCKER_JENKINS_WORKSPACE ]; then echo "环境变量 DOCKER_JENKINS_WORKSPACE:[$DOCKER_JENKINS_WORKSPACE] 缺失,需配置 DOCKER_JENKINS_WORKSPACE 环境变量(exit -1)" exit -1 fi cd $DOCKER_JENKINS_WORKSPACE/$JOB_NAME # 编辑Dockerfile文件 tee Dockerfile <<-'EOF' FROM openjdk:11-jre-slim WORKDIR /workdir ADD ./*-server/target/*.jar app.jar ENV SPRING_PROFILES_ACTIVE=prod ENV SERVER_PORT=8080 ENTRYPOINT java -jar -Djava.security.egd=file:/dev/./urandom -Dspring.profiles.active=$SPRING_PROFILES_ACTIVE -Dserver.port=$SERVER_PORT app.jar EXPOSE 8080 EOF # 构建镜像 docker build -t $JOB_NAME:$app_version . # 上传镜像到私服 docker tag $JOB_NAME:$app_version registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version docker push registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version # 删除空镜像 docker images | awk '{if($1=="")print $3}' | xargs docker rmi &> /dev/null # 编辑stack yml文件 tee $JOB_NAME.yml <<-'EOF' version: '3.5' services: $JOB_NAME: image: registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:${app_version} environment: TZ: "Asia/Shanghai" SPRING_PROFILES_ACTIVE: "prod" networks: - middleware deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure networks: middleware: external: true EOF docker stack up -c $JOB_NAME.yml app --with-registry-auth ``` # 构建tomcat应用的相关记录 ## 环境变量 [Section titled “环境变量”](#环境变量) * 系统管理 -> 系统配置 -> 全局属性 -> 环境变量 -> 新增键值对 * DOCKER\_JENKINS\_WORKSPACE : /var/lib/docker/volumes/soft\_jenkins\_home/\_data/workspace ## jdk配置 [Section titled “jdk配置”](#jdk配置) ```shell # 新建目录 cd /var/lib/docker/volumes/soft_jenkins_home/_data && mkdir -p ./soft/jdks # 下载jdk wget https://corretto.aws/downloads/latest/amazon-corretto-8-x64-linux-jdk.tar.gz wget https://corretto.aws/downloads/latest/amazon-corretto-11-x64-linux-jdk.tar.gz # 解压 tar -zxvf amazon-corretto-8-x64-linux-jdk.tar.gz # 系统管理 -> 全局工具配置 -> JDK # JAVA_HOME(/var/jenkins_home/soft/jdks/amazon-corretto-8.332.08.1-linux-x64) ``` ## maven配置 [Section titled “maven配置”](#maven配置) ```shell # 下载Maven Integration插件 # 自定义settings.xml的配置 cd /var/lib/docker/volumes/soft_jenkins_home/_data && mkdir -p ./soft/maven code settings.xml # 复制./conf/settings.xml文件内容 # 修改标签内容 # 调整[系统管理 -> 全局工具配置 -> Maven 配置] # 默认(和全局) settings 提供 -> 文件系统中的 settings 文件 -> 文件路径(/var/jenkins_home/soft/maven/settings.xml) # maven v3.6.3 ``` *** ## 构建脚本 [Section titled “构建脚本”](#构建脚本) * maven 构建 * 构建 -> 添加构建步骤 -> 调用顶层 maven 目标 ```shell # 目标 clean install -Dmaven.test.skip=true -Pprivate -Djava.awt.headless=true # 也可替换为以下命令 clean package -D maven.test.skip=true -P prod help:active-profiles ``` * 执行 shell * 将镜像上传到私仓 * PS: Jenkins的部署需要使用remote/jenkins.yml文件部署(主要是需要在容器内使用docker命令) ```shell export app_version=${BUILD_NUMBER} cd $WORKSPACE # 编辑Dockerfile文件 tee Dockerfile <<-'EOF' FROM openjdk:11-jre-slim WORKDIR /workdir ADD ./target/*.jar app.jar ENV SPRING_PROFILES_ACTIVE=prod ENV SERVER_PORT=8080 ENTRYPOINT java -jar -Djava.security.egd=file:/dev/./urandom -Dspring.profiles.active=$SPRING_PROFILES_ACTIVE -Dserver.port=$SERVER_PORT app.jar EXPOSE 8080 EOF # 登录阿里云私仓 todo 和需要手动替换成真实的数据 echo | docker login -u --password-stdin registry.cn-zhangjiakou.aliyuncs.com # 构建镜像 docker build -t $JOB_NAME:$app_version . # 上传镜像到私服 docker tag $JOB_NAME:$app_version registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version docker push registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version # 删除本地镜像 docker rmi registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version # 退出阿里云私仓 docker logout ``` * send build artifacts over SSH (Transfers Set -> Exec command) * 选择远程ssh server,在远程服务器上启动docker容器 ```shell export app_version=${BUILD_NUMBER} # 创建工作目录 mkdir -p /www/temp/jenkins/docker cd /www/temp/jenkins/docker # 编辑stack yml文件 tee $JOB_NAME.yml <<-'EOF' version: '3.5' services: $JOB_NAME: image: registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:${app_version} environment: TZ: "Asia/Shanghai" networks: - middleware deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure networks: middleware: external: true EOF docker stack up -c $JOB_NAME.yml app --with-registry-auth ``` # 构建tomcat应用的相关记录 ## 环境变量 [Section titled “环境变量”](#环境变量) * 系统管理 -> 系统配置 -> 全局属性 -> 环境变量 -> 新增键值对 * DOCKER\_JENKINS\_WORKSPACE : /var/lib/docker/volumes/soft\_jenkins\_home/\_data/workspace ## jdk配置 [Section titled “jdk配置”](#jdk配置) ```shell # 新建目录 cd /var/lib/docker/volumes/soft_jenkins_home/_data && mkdir -p ./soft/jdks # 下载jdk wget https://corretto.aws/downloads/latest/amazon-corretto-8-x64-linux-jdk.tar.gz wget https://corretto.aws/downloads/latest/amazon-corretto-11-x64-linux-jdk.tar.gz # 解压 tar -zxvf amazon-corretto-8-x64-linux-jdk.tar.gz # 系统管理 -> 全局工具配置 -> JDK # JAVA_HOME(/var/jenkins_home/soft/jdks/amazon-corretto-8.332.08.1-linux-x64) ``` ## maven配置 [Section titled “maven配置”](#maven配置) ```shell # 下载Maven Integration插件 # 自定义settings.xml的配置 cd /var/lib/docker/volumes/soft_jenkins_home/_data && mkdir -p ./soft/maven code settings.xml # 复制./conf/settings.xml文件内容 # 修改标签内容 # 调整[系统管理 -> 全局工具配置 -> Maven 配置] # 默认(和全局) settings 提供 -> 文件系统中的 settings 文件 -> 文件路径(/var/jenkins_home/soft/maven/settings.xml) # maven v3.6.3 ``` *** ## 构建脚本 [Section titled “构建脚本”](#构建脚本) * maven 构建 * 构建 -> 添加构建步骤 -> 调用顶层 maven 目标 ```shell # 目标 clean install -Dmaven.test.skip=true -Pprivate -Djava.awt.headless=true # 也可替换为以下命令 clean package -D maven.test.skip=true -P prod help:active-profiles ``` * 执行 shell * 将镜像上传到私仓 ```shell export app_version=${BUILD_NUMBER} cd $WORKSPACE # 编辑Dockerfile文件 tee Dockerfile <<-'EOF' FROM openjdk:11-jre-slim WORKDIR /workdir ADD ./target/*.jar app.jar ENV SPRING_PROFILES_ACTIVE=prod ENV SERVER_PORT=8080 ENTRYPOINT java -jar -Djava.security.egd=file:/dev/./urandom -Dspring.profiles.active=$SPRING_PROFILES_ACTIVE -Dserver.port=$SERVER_PORT app.jar EXPOSE 8080 EOF # 登录阿里云私仓 todo 和需要手动替换成真实的数据 echo | docker login -u --password-stdin registry.cn-zhangjiakou.aliyuncs.com # 构建镜像 docker -H tcp://172.17.0.1:2375 build -t $JOB_NAME:$app_version . # 上传镜像到私服 docker -H tcp://172.17.0.1:2375 tag $JOB_NAME:$app_version registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version docker -H tcp://172.17.0.1:2375 push registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version # 删除本地镜像 docker -H tcp://172.17.0.1:2375 rmi registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version # 退出阿里云私仓 docker logout ``` * send build artifacts over SSH (Transfers Set -> Exec command) * 选择远程ssh server,在远程服务器上启动docker容器 * 或者,直接使用远程访问docker的方式部署 * PS: 服务器docker需要开启远程访问(通过这种方式验证:docker -H tcp\://172.17.0.1:2375 version)。 * [参考文章](https://segmentfault.com/a/1190000024563734) ```shell export app_version=${BUILD_NUMBER} # 创建工作目录 mkdir -p /www/temp/jenkins/docker cd /www/temp/jenkins/docker # 编辑stack yml文件 tee $JOB_NAME.yml <<-'EOF' version: '3.5' services: $JOB_NAME: image: registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:${app_version} environment: TZ: "Asia/Shanghai" networks: - middleware deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure networks: middleware: external: true EOF docker -H tcp://172.17.0.1:2375 stack up -c $JOB_NAME.yml app --with-registry-auth ``` # 使用Jenkins构建node项目 ## 环境变量 [Section titled “环境变量”](#环境变量) * 系统管理 -> 系统配置 -> 全局属性 -> 环境变量 -> 新增键值对 * DOCKER\_JENKINS\_WORKSPACE : /var/lib/docker/volumes/soft\_jenkins\_home/\_data/workspace ## NodeJS配置 [Section titled “NodeJS配置”](#nodejs配置) ```shell # 下载NodeJS插件 # 调整[系统管理 -> 全局工具配置 -> nodeJS 配置] # nodejs 14.15.0 ``` ## Jenkins配置 [Section titled “Jenkins配置”](#jenkins配置) * 创建一个自由风格的项目 * 使用gitee作为代码源 * 在 \[构建环境] 步骤 添加 \[Provide Node & npm bin/ folder to PATH] * 在\[构建]步骤中添加\[执行 shell]步骤 ```shell pwd # 删除 dist 的所有内容 rm -rf dist # 安装依赖(非必须) npm install --registry https://registry.npm.taobao.org # 构建项目 npm run build:prod # 删除除 node_modules和dist 以外的所有内容 ls | grep -v 'node_modules\|dist' | xargs rm -rf ``` * 执行 shell * 将镜像上传到私仓 * PS: Jenkins的部署需要使用remote/jenkins.yml文件部署(主要是需要在容器内使用docker命令) ```shell export app_version=${BUILD_NUMBER} cd $WORKSPACE mkdir -p ./nginx/conf.d/ # 添加default.conf文件 tee ./nginx/conf.d/default.conf <<-'EOF' server { listen 80; listen [::]:80; server_name localhost; #access_log /var/log/nginx/host.access.log main; location / { root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html; # 用于解决刷新页面后,显示404的问题 } } EOF # 编辑Dockerfile文件 echo "FROM nginx:stable-alpine" > Dockerfile echo "MAINTAINER Fa" >> Dockerfile echo "WORKDIR /usr/share/nginx/html" >> Dockerfile echo "RUN rm -rf *" >> Dockerfile echo "ADD ./dist ." >> Dockerfile echo "ADD ./nginx/conf.d/default.conf /etc/nginx/conf.d/" >> Dockerfile echo "EXPOSE 80" >> Dockerfile # 登录阿里云私仓 todo 和需要手动替换成真实的数据 echo | docker login -u --password-stdin registry.cn-zhangjiakou.aliyuncs.com # 构建镜像 docker build -t $JOB_NAME:$app_version . # 上传镜像到私服 docker tag $JOB_NAME:$app_version registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version docker push registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version # 退出阿里云私仓 docker logout ``` * 在构建步骤中添加\[Send files or execute commands over SSH(通过ssh远程执行shell命令)]步骤 ```shell export app_version=${BUILD_NUMBER} # 创建工作目录 mkdir -p /www/temp/jenkins/docker cd /www/temp/jenkins/docker # 编辑stack yml文件 tee $JOB_NAME.yml <<-'EOF' version: '3.5' services: $JOB_NAME: image: registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:${app_version} environment: TZ: "Asia/Shanghai" networks: - middleware deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure networks: middleware: external: true EOF docker stack up -c $JOB_NAME.yml app --with-registry-auth ``` # 构建tomcat应用的相关记录 ## 环境变量 [Section titled “环境变量”](#环境变量) * 系统管理 -> 系统配置 -> 全局属性 -> 环境变量 -> 新增键值对 * DOCKER\_JENKINS\_WORKSPACE : /var/lib/docker/volumes/soft\_jenkins\_home/\_data/workspace ## jdk配置 [Section titled “jdk配置”](#jdk配置) ```shell # 新建目录 cd /var/lib/docker/volumes/soft_jenkins_home/_data && mkdir -p ./soft/jdks # 下载jdk wget https://corretto.aws/downloads/latest/amazon-corretto-8-x64-linux-jdk.tar.gz wget https://corretto.aws/downloads/latest/amazon-corretto-11-x64-linux-jdk.tar.gz # 解压 tar -zxvf amazon-corretto-8-x64-linux-jdk.tar.gz # 系统管理 -> 全局工具配置 -> JDK # JAVA_HOME(/var/jenkins_home/soft/jdks/amazon-corretto-8.332.08.1-linux-x64) ``` ## maven配置 [Section titled “maven配置”](#maven配置) ```shell # 下载Maven Integration插件 # 自定义settings.xml的配置 cd /var/lib/docker/volumes/soft_jenkins_home/_data && mkdir -p ./soft/maven code settings.xml # 复制./conf/settings.xml文件内容 # 修改标签内容 # 调整[系统管理 -> 全局工具配置 -> Maven 配置] # 默认(和全局) settings 提供 -> 文件系统中的 settings 文件 -> 文件路径(/var/jenkins_home/soft/maven/settings.xml) # maven v3.6.3 ``` *** ## 构建脚本 [Section titled “构建脚本”](#构建脚本) * maven 构建 * 构建 -> 添加构建步骤 -> 调用顶层 maven 目标 ```shell # 目标 clean install -Dmaven.test.skip=true -Pprivate -Djava.awt.headless=true # 也可替换为以下命令 clean package -D maven.test.skip=true -P prod help:active-profiles # 或使用 clean package -D maven.test.skip=true -P prod -pl cn.facoder:mall-server -am ``` * send build artifacts over SSH (Transfers Set -> Exec command) ```shell # 第四版(swarm+私服) # docker images | awk '{if($1=="$JOB_NAME") print $3}' | xargs docker rmi export app_version='1.0' if [ -z $DOCKER_JENKINS_WORKSPACE ]; then echo "环境变量 DOCKER_JENKINS_WORKSPACE:[$DOCKER_JENKINS_WORKSPACE] 缺失,需配置 DOCKER_JENKINS_WORKSPACE 环境变量(exit -1)" exit -1 fi cd $DOCKER_JENKINS_WORKSPACE/$JOB_NAME # 编辑Dockerfile文件 tee Dockerfile <<-'EOF' FROM eclipse-temurin:11-jre-alpine WORKDIR /workdir ADD ./target/*.jar app.jar ENV SPRING_PROFILES_ACTIVE=prod ENV SERVER_PORT=8080 ENV JAVA_OPTS="-Xms512m -Xmx512m" ENTRYPOINT java ${JAVA_OPTS} -Dloader.path="/www/java/lib" -Djava.security.egd=file:/dev/./urandom -Dspring.profiles.active=$SPRING_PROFILES_ACTIVE -Dserver.port=$SERVER_PORT -jar app.jar EXPOSE 8080 EOF # 构建镜像 docker build -t $JOB_NAME:$app_version . # 上传镜像到私服 docker tag $JOB_NAME:$app_version registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version docker push registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version # 删除本地镜像 docker rmi registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version # 编辑stack yml文件 tee $JOB_NAME.yml <<-'EOF' version: '3.5' services: $JOB_NAME: image: registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:${app_version} environment: TZ: "Asia/Shanghai" volumes: - "/www/temp/java/lib:/www/java/lib" networks: - middleware deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure networks: middleware: external: true EOF docker stack up -c $JOB_NAME.yml app --with-registry-auth ``` # 构建tomcat应用的相关记录 ## 环境变量 [Section titled “环境变量”](#环境变量) * 系统管理 -> 系统配置 -> 全局属性 -> 环境变量 -> 新增键值对 * DOCKER\_JENKINS\_WORKSPACE : /var/lib/docker/volumes/soft\_jenkins\_home/\_data/workspace ## jdk配置 [Section titled “jdk配置”](#jdk配置) ```shell # 新建目录 cd /var/lib/docker/volumes/soft_jenkins_home/_data && mkdir -p ./soft/jdks # 下载jdk wget https://corretto.aws/downloads/latest/amazon-corretto-8-x64-linux-jdk.tar.gz wget https://corretto.aws/downloads/latest/amazon-corretto-11-x64-linux-jdk.tar.gz # 解压 tar -zxvf amazon-corretto-8-x64-linux-jdk.tar.gz # 系统管理 -> 全局工具配置 -> JDK # JAVA_HOME(/var/jenkins_home/soft/jdks/amazon-corretto-8.332.08.1-linux-x64) ``` ## maven配置 [Section titled “maven配置”](#maven配置) ```shell # 下载Maven Integration插件 # 自定义settings.xml的配置 cd /var/lib/docker/volumes/soft_jenkins_home/_data && mkdir -p ./soft/maven code settings.xml # 复制./conf/settings.xml文件内容 # 修改标签内容 # 调整[系统管理 -> 全局工具配置 -> Maven 配置] # 默认(和全局) settings 提供 -> 文件系统中的 settings 文件 -> 文件路径(/var/jenkins_home/soft/maven/settings.xml) # maven v3.6.3 ``` *** ## 构建脚本 [Section titled “构建脚本”](#构建脚本) * maven 构建 * 构建 -> 添加构建步骤 -> 调用顶层 maven 目标 ```shell # 目标 clean install -Dmaven.test.skip=true -Pprivate -Djava.awt.headless=true # 也可替换为以下命令 clean package -D maven.test.skip=true -P prod help:active-profiles # 或使用 clean package -D maven.test.skip=true -P prod -pl cn.facoder:mall-server -am ``` * send build artifacts over SSH (Transfers Set -> Exec command) ```shell # 第四版(swarm+私服) # docker images | awk '{if($1=="$JOB_NAME") print $3}' | xargs docker rmi export app_version='1.0' if [ -z $DOCKER_JENKINS_WORKSPACE ]; then echo "环境变量 DOCKER_JENKINS_WORKSPACE:[$DOCKER_JENKINS_WORKSPACE] 缺失,需配置 DOCKER_JENKINS_WORKSPACE 环境变量(exit -1)" exit -1 fi cd $DOCKER_JENKINS_WORKSPACE/$JOB_NAME # 编辑Dockerfile文件 tee Dockerfile <<-'EOF' FROM eclipse-temurin:11-jre WORKDIR /workdir ADD ./target/*.jar app.jar ENV SPRING_PROFILES_ACTIVE=prod ENV SERVER_PORT=8080 ENV JAVA_OPTS="-Xms512m -Xmx512m" ENTRYPOINT java ${JAVA_OPTS} -Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom -Dspring.profiles.active=$SPRING_PROFILES_ACTIVE -Dserver.port=$SERVER_PORT -jar app.jar EXPOSE 8080 EOF # 构建镜像 docker build -t $JOB_NAME:$app_version . # 上传镜像到私服 docker tag $JOB_NAME:$app_version registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version docker push registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version # 删除本地镜像 docker rmi registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version # 编辑stack yml文件 tee $JOB_NAME.yml <<-'EOF' version: '3.5' services: $JOB_NAME: image: registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:${app_version} environment: TZ: "Asia/Shanghai" networks: - middleware deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure networks: middleware: external: true EOF docker stack up -c $JOB_NAME.yml app --with-registry-auth ``` # 构建tomcat应用的相关记录 ## 环境变量 [Section titled “环境变量”](#环境变量) * 系统管理 -> 系统配置 -> 全局属性 -> 环境变量 -> 新增键值对 * DOCKER\_JENKINS\_WORKSPACE : /var/lib/docker/volumes/soft\_jenkins\_home/\_data/workspace ## jdk配置 [Section titled “jdk配置”](#jdk配置) ```shell # 新建目录 cd /var/lib/docker/volumes/soft_jenkins_home/_data && mkdir -p ./soft/jdks # 下载jdk wget https://corretto.aws/downloads/latest/amazon-corretto-8-x64-linux-jdk.tar.gz wget https://corretto.aws/downloads/latest/amazon-corretto-11-x64-linux-jdk.tar.gz # 解压 tar -zxvf amazon-corretto-8-x64-linux-jdk.tar.gz # 系统管理 -> 全局工具配置 -> JDK # JAVA_HOME(/var/jenkins_home/soft/jdks/amazon-corretto-8.332.08.1-linux-x64) ``` ## maven配置 [Section titled “maven配置”](#maven配置) ```shell # 下载Maven Integration插件 # 自定义settings.xml的配置 cd /var/lib/docker/volumes/soft_jenkins_home/_data && mkdir -p ./soft/maven code settings.xml # 复制./conf/settings.xml文件内容 # 修改标签内容 # 调整[系统管理 -> 全局工具配置 -> Maven 配置] # 默认(和全局) settings 提供 -> 文件系统中的 settings 文件 -> 文件路径(/var/jenkins_home/soft/maven/settings.xml) # maven v3.6.3 ``` *** ## 构建脚本 [Section titled “构建脚本”](#构建脚本) * maven 构建 * 构建 -> 添加构建步骤 -> 调用顶层 maven 目标 ```shell # 目标 clean install -Dmaven.test.skip=true -Pprivate -Djava.awt.headless=true # 也可替换为以下命令 clean package -D maven.test.skip=true -P prod help:active-profiles # 或使用 clean package -D maven.test.skip=true -P prod -pl cn.facoder:mall-server -am ``` * send build artifacts over SSH (Transfers Set -> Exec command) ```shell # 第四版(swarm+私服) # docker images | awk '{if($1=="$JOB_NAME") print $3}' | xargs docker rmi export app_version='1.0' if [ -z $DOCKER_JENKINS_WORKSPACE ]; then echo "环境变量 DOCKER_JENKINS_WORKSPACE:[$DOCKER_JENKINS_WORKSPACE] 缺失,需配置 DOCKER_JENKINS_WORKSPACE 环境变量(exit -1)" exit -1 fi cd $DOCKER_JENKINS_WORKSPACE/$JOB_NAME # 编辑Dockerfile文件 tee Dockerfile <<-'EOF' FROM eclipse-temurin:11-jre-alpine WORKDIR /workdir ADD ./target/*.jar app.jar ENV SPRING_PROFILES_ACTIVE=prod ENV SERVER_PORT=8080 ENV JAVA_OPTS="-Xms512m -Xmx512m" ENTRYPOINT java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -Dspring.profiles.active=$SPRING_PROFILES_ACTIVE -Dserver.port=$SERVER_PORT -jar app.jar EXPOSE 8080 EOF # 构建镜像 docker build -t $JOB_NAME:$app_version . # 上传镜像到私服 docker tag $JOB_NAME:$app_version registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version docker push registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version # 删除本地镜像 docker rmi registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version # 编辑stack yml文件 tee $JOB_NAME.yml <<-'EOF' version: '3.5' services: $JOB_NAME: image: registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:${app_version} environment: TZ: "Asia/Shanghai" networks: - middleware deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure networks: middleware: external: true EOF docker stack up -c $JOB_NAME.yml app --with-registry-auth ``` # 使用Jenkins构建node项目 ## 环境变量 [Section titled “环境变量”](#环境变量) * 系统管理 -> 系统配置 -> 全局属性 -> 环境变量 -> 新增键值对 * DOCKER\_JENKINS\_WORKSPACE : /var/lib/docker/volumes/soft\_jenkins\_home/\_data/workspace ## NodeJS配置 [Section titled “NodeJS配置”](#nodejs配置) ```shell # 下载NodeJS插件 # 调整[系统管理 -> 全局工具配置 -> nodeJS 配置] # nodejs 14.15.0 ``` ## Jenkins配置 [Section titled “Jenkins配置”](#jenkins配置) * 创建一个自由风格的项目 * 使用gitee作为代码源 * 在 \[构建环境] 步骤 添加 \[Provide Node & npm bin/ folder to PATH] * 在\[构建]步骤中添加\[执行 shell]步骤 ```shell pwd # 删除 dist 的所有内容 rm -rf dist # 安装依赖(非必须) npm install --registry https://registry.npm.taobao.org # 构建项目 npm run build:prod # 删除除 node_modules和dist 以外的所有内容 ls | grep -v 'node_modules\|dist' | xargs rm -rf ``` * 在构建步骤中添加\[Send files or execute commands over SSH(通过ssh远程执行shell)]步骤 ```shell export app_version='1.0' if [ -z $DOCKER_JENKINS_WORKSPACE ]; then echo "环境变量 DOCKER_JENKINS_WORKSPACE:[$DOCKER_JENKINS_WORKSPACE] 缺失,需配置 DOCKER_JENKINS_WORKSPACE 环境变量(exit -1)" exit -1 fi cd $DOCKER_JENKINS_WORKSPACE/$JOB_NAME mkdir -p ./nginx/conf.d/ # todo 按需调整用户名和组 chown -R 1000:1000 ./nginx # 添加default.conf文件 tee ./nginx/conf.d/default.conf <<-'EOF' server { listen 80; listen [::]:80; server_name localhost; #access_log /var/log/nginx/host.access.log main; location / { root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html; # 用于解决刷新页面后,显示404的问题 } } EOF # 编辑Dockerfile文件 echo "FROM nginx:stable-alpine" > Dockerfile echo "MAINTAINER Fa" >> Dockerfile echo "WORKDIR /usr/share/nginx/html" >> Dockerfile echo "RUN rm -rf *" >> Dockerfile echo "ADD ./dist ." >> Dockerfile echo "ADD ./nginx/conf.d/default.conf /etc/nginx/conf.d/" >> Dockerfile echo "EXPOSE 80" >> Dockerfile # 构建镜像 docker build --no-cache -t $JOB_NAME:$app_version . # 上传镜像到私服 docker tag $JOB_NAME:$app_version registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version docker push registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version # 删除空镜像 docker images | awk '{if($1=="")print $3}' | xargs docker rmi &> /dev/null # 编辑stack yml文件 tee $JOB_NAME.yml <<-'EOF' version: '3.5' services: $JOB_NAME: image: registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:${app_version} environment: TZ: "Asia/Shanghai" networks: - middleware deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure networks: middleware: external: true EOF docker stack up -c $JOB_NAME.yml app --with-registry-auth ``` * Nginx添加代理配置 * 在conf.d目录中添加mall-admin-web-demo.conf文件 ```shell server { listen 80; server_name mall-admin-web-demo.iuin.xyz iuin.xyz; access_log /var/log/mall-admin-web-demo_access.log; error_log /var/log/mall-admin-web-demo_error.log; location / { include cors.conf; proxy_set_header Host $host; proxy_set_header X-real-ip $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://mall-admin-web-demo; } } ``` ## 部署 [Section titled “部署”](#部署) ```shell # 镜像下载问题,可试这添加--with-registry-auth看看 docker stack up -c $JOB_NAME.yml --with-registry-auth app ``` # 构建tomcat应用的相关记录 ## 环境变量 [Section titled “环境变量”](#环境变量) * 系统管理 -> 系统配置 -> 全局属性 -> 环境变量 -> 新增键值对 * DOCKER\_JENKINS\_WORKSPACE : /var/lib/docker/volumes/soft\_jenkins\_home/\_data/workspace ## jdk配置 [Section titled “jdk配置”](#jdk配置) ```shell # 新建目录 cd /var/lib/docker/volumes/soft_jenkins_home/_data && mkdir -p ./soft/jdks # 下载jdk wget https://corretto.aws/downloads/latest/amazon-corretto-8-x64-linux-jdk.tar.gz wget https://corretto.aws/downloads/latest/amazon-corretto-11-x64-linux-jdk.tar.gz # 解压 tar -zxvf amazon-corretto-8-x64-linux-jdk.tar.gz # 系统管理 -> 全局工具配置 -> JDK # JAVA_HOME(/var/jenkins_home/soft/jdks/amazon-corretto-8.332.08.1-linux-x64) ``` ## maven配置 [Section titled “maven配置”](#maven配置) ```shell # 下载Maven Integration插件 # 自定义settings.xml的配置 cd /var/lib/docker/volumes/soft_jenkins_home/_data && mkdir -p ./soft/maven code settings.xml # 复制./conf/settings.xml文件内容 # 修改标签内容 # 调整[系统管理 -> 全局工具配置 -> Maven 配置] # 默认(和全局) settings 提供 -> 文件系统中的 settings 文件 -> 文件路径(/var/jenkins_home/soft/maven/settings.xml) # maven v3.6.3 ``` *** ## 构建脚本 [Section titled “构建脚本”](#构建脚本) * maven 构建 ```shell # Goals and options clean install -Dmaven.test.skip=true -Pprivate -Djava.awt.headless=true # 也可替换为以下命令 clean package -D maven.test.skip=true -P prod help:active-profiles ``` * send build artifacts over SSH (Transfers Set -> Exec command) ```shell # 第四版(swarm+私服) # docker images | awk '{if($1=="$JOB_NAME") print $3}' | xargs docker rmi export app_version='1.0' if [ -z $DOCKER_JENKINS_WORKSPACE ]; then echo "环境变量 DOCKER_JENKINS_WORKSPACE:[$DOCKER_JENKINS_WORKSPACE] 缺失,需配置 DOCKER_JENKINS_WORKSPACE 环境变量(exit -1)" exit -1 fi cd $DOCKER_JENKINS_WORKSPACE/$JOB_NAME # 编辑Dockerfile文件 tee Dockerfile <<-'EOF' FROM tomcat:jre8-alpine MAINTAINER Fa WORKDIR /usr/local/tomcat RUN rm -rf webapps/* ADD ./target/*$JOB_NAME webapps/$JOB_NAME EXPOSE 8080 EOF # 构建镜像 docker build -t $JOB_NAME:$app_version . # 上传镜像到私服 docker tag $JOB_NAME:$app_version registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version docker push registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:$app_version # 删除空镜像 docker images | awk '{if($1=="")print $3}' | xargs docker rmi &> /dev/null # 编辑stack yml文件 tee $JOB_NAME.yml <<-'EOF' version: '3.5' services: $JOB_NAME: image: registry.cn-zhangjiakou.aliyuncs.com/fa/$JOB_NAME:${app_version} environment: TZ: "Asia/Shanghai" networks: - middleware deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure networks: middleware: external: true EOF docker stack up -c $JOB_NAME.yml app --with-registry-auth ``` # Jenkins 相关使用记录 ## maven配置settings.xml [Section titled “maven配置settings.xml”](#maven配置settingsxml) ```shell docker volume ls docker volume inspect jenkins_jenkins_home cd /var/lib/docker/volumes/jenkins_jenkins_home/_data mkdir -p ./data/maven code settings.xml # 复制./conf/settings.xml文件内容 # 修改标签内容 # 调整[系统管理 -> 全局工具配置 -> Maven 配置] # 默认(和全局) settings 提供 -> 文件系统中的 settings 文件 -> 文件路径(/var/jenkins_home/soft/maven/settings.xml) ``` *** ## 多分支参数构建 [Section titled “多分支参数构建”](#多分支参数构建) ```shell # 1. 下载安装插件 # 在管理中选插件,输入Git Parameter ``` ## ![img.png](/_astro/img.aW9MDVaE_1aeboQ.webp) ![img\_1.png](/_astro/img_1.D1Ev6x-3_243cOj.webp) ![img\_2.png](/_astro/img_2.CqEHL7AV_ZKUWsU.webp) ## 构建maven项目 [Section titled “构建maven项目”](#构建maven项目) ```shell # 下载安装插件 # 在管理中选插件,输入 # Maven Integration # SSH # Deploy to container # Send build artifacts over SSH ``` * 步骤 ![img.png](/_astro/img.DLvs_7jx_ZqFnaP.webp) ![img\_1.png](/_astro/img_1.DWY64M7J_1OaVDR.webp) ![img\_2.png](/_astro/img_2.9Ukmz9cd_ZfF8ib.webp) ![img\_3.png](/_astro/img_3.BYU9gO2x_Zyj43z.webp) ![img\_4.png](/_astro/img_4.1Zi1qu0x_V5PUt.webp) ![ssh信息输出到控制台](/_astro/img_5.DYBsyiUD_Z12S74f.webp) ![docker全局环境变量](/_astro/img_6.RXmCli1L_Z2jocag.webp) * Build ```shell # Goals and options clean install -Dmaven.test.skip=true -Pprivate -Djava.awt.headless=true ``` * send build artifacts over SSH (Transfers Set -> Exec command) ```shell # 第一版(初版) imagesid=`docker images|grep -i docker-test|awk '{print $3}'` project=/var/lib/docker/volumes/jks_jenkins_home/_data/workspace/test4 dockerid=`docker ps -a|grep -i docker-test|awk '{print $1}' ` echo $project if [ ! -n "$imagesid" ];then echo $imagesid "is null" else docker rmi $imagesid -f fi cd $project echo "FROM tomcat:8.5" > Dockerfile echo "MAINTAINER Fa" >> Dockerfile echo "RUN rm -rf /usr/local/tomcat/webapps/*" >> Dockerfile echo "ADD ./target/*.war /usr/local/tomcat/webapps/" >> Dockerfile echo "EXPOSE 8080" >> Dockerfile # echo 'ENTRYPOINT ["/usr/local/tomcat/bin/catalina.sh","run"]' >> Dockerfile docker build -t docker-test . if [ -n "$dockerid" ] ;then docker stop $dockerid docker rm -f $dockerid else echo 'dockerid is null' fi docker run -itd -p 8080:8080 docker-test ``` ```shell # 第二版 # docker images | awk '{if($1=="$JOB_NAME") print $3}' | xargs docker rmi dockerid=`docker ps -aq -f ancestor=$JOB_NAME ` if [ -n "$dockerid" ] ;then docker stop $dockerid docker rm -f $dockerid docker rmi $(docker images -q -f reference=$JOB_NAME) else echo 'dockerid is null' fi cd $DOCKER_WORKSPACE/$JOB_NAME echo "FROM tomcat:8.5" > Dockerfile echo "MAINTAINER Fa" >> Dockerfile echo "RUN rm -rf /usr/local/tomcat/webapps/*" >> Dockerfile echo "ADD ./target/*.war /usr/local/tomcat/webapps/" >> Dockerfile echo "EXPOSE 8080" >> Dockerfile # echo "ENTRYPOINT ["/usr/local/tomcat/bin/catalina.sh","run"]" >> Dockerfile docker build -t $JOB_NAME . docker run -itd -p 8280:8080 $JOB_NAME ``` ```shell # 第三版(swarm) # docker images | awk '{if($1=="$JOB_NAME") print $3}' | xargs docker rmi # published: 8280 # todo 映射端口根据实际调整 export app_version='1.0' docker service rm app_$JOB_NAME cd $DOCKER_WORKSPACE/$JOB_NAME # 编辑Dockerfile文件 echo "FROM tomcat:8.5.71-jdk8-corretto" > Dockerfile echo "MAINTAINER Fa" >> Dockerfile echo "RUN rm -rf /usr/local/tomcat/webapps/*" >> Dockerfile echo "ADD ./target/*.war /usr/local/tomcat/webapps/" >> Dockerfile echo "EXPOSE 8080" >> Dockerfile # 构建镜像 docker build -t $JOB_NAME:$app_version . # 删除空镜像 docker images | awk '{if($1=="")print $3}' | xargs docker rmi # 编辑stack yml文件 tee $JOB_NAME.yml <<-'EOF' version: '3.5' services: $JOB_NAME: image: $JOB_NAME:${app_version} ports: - target: 8080 published: 8280 mode: host networks: - middleware deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure networks: middleware: external: true EOF docker stack up -c $JOB_NAME.yml app ``` ```shell # 第四版(swarm+私服) # docker images | awk '{if($1=="$JOB_NAME") print $3}' | xargs docker rmi # published: 8280 # todo 映射端口根据实际调整 export app_version='1.0' cd $DOCKER_WORKSPACE/$JOB_NAME # 编辑Dockerfile文件 echo "FROM tomcat:8.5.71-jdk8-corretto" > Dockerfile echo "MAINTAINER Fa" >> Dockerfile echo "WORKDIR /usr/local/tomcat" >> Dockerfile echo "RUN rm -rf webapps/*" >> Dockerfile echo "ADD ./target/*$JOB_NAME webapps/$JOB_NAME" >> Dockerfile echo "EXPOSE 8080" >> Dockerfile # 构建镜像 docker build -t $JOB_NAME:$app_version . # 上传镜像到私服 docker tag $JOB_NAME:$app_version registry.docker.com:5000/$JOB_NAME:$app_version docker push registry.docker.com:5000/$JOB_NAME:$app_version # 删除空镜像 docker images | awk '{if($1=="")print $3}' | xargs docker rmi # 编辑stack yml文件 tee $JOB_NAME.yml <<-'EOF' version: '3.5' services: $JOB_NAME: image: registry.docker.com:5000/$JOB_NAME:${app_version} ports: - target: 8080 published: 8280 mode: host networks: - middleware deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure networks: middleware: external: true EOF docker stack up -c $JOB_NAME.yml app ``` # java 启动 相关记录 * [参考文章](http://www.javashuo.com/article/p-mdhxsxqr-eq.html) ```shell nohup java -Xms500m -Xmx500m -Xmn250m -Xss256k -server -XX:+HeapDumpOnOutOfMemoryError -jar $JAR_PATH/test-0.0.1-SNAPSHOT.jar --spring.profiles.active=daily -verbose:class & ## 说明: # --spring.profiles.active=daily, 这个能够在spring-boot启动中指定系统变量,多环境(测试、预发、线上配置)的区分 # 在排查jar包冲突时,能够指定启动的-verbose:class 打印出启动的应用实际加载类的路径,来排查来源。 # jvm堆设值: -Xms500m -Xmx500m -Xmn250m -Xss256k # nohup 不挂断地运行命令;& 在后台运行 ,通常两个一块儿用。 eg:nohup command & # -server:服务器模式,在多个CPU时性能佳,启动慢但性能好,能合理管理内存。 # -XX:+HeapDumpOnOutOfMemoryError:在堆溢出时保存快照 ``` ```shell ## -server和-client具体说明: # -server:必定要做为第一个参数,在多个 CPU 时性能佳,还有一种叫 -client 的模式,特色是启动速度比较快,但运行时性能和内存管理效率不高,一般用于客户端应用程序或开发调试,在 32 位环境下直接运行 Java 程序默认启用该模式。Server 模式的特色是启动速度比较慢,但运行时性能和内存管理效率很高,适用于生产环境,在具备 64 位能力的 JDK 环境下默认启用该模式,能够不配置该参数。 ``` # jenkins中使用jdk * 下载到指定位置 ```bash cd /var/lib/docker/volumes/web_jenkins_home/_data/ mkdir -p ./soft/jdk cd /var/lib/docker/volumes/web_jenkins_home/_data/soft/jdk wget https://corretto.aws/downloads/latest/amazon-corretto-8-x64-linux-jdk.tar.gz tar -zxvf openjdk-8u41-b04-linux-x64-14_jan_2020.tar.gz ``` * 对应Jenkins中的配置 ```bash # jdk安装路径配置 /var/jenkins_home/soft/jdk ``` # Jenkins使用maven * 下载到指定位置 ```bash cd /var/lib/docker/volumes/web_jenkins_home/_data/ mkdir -p ./soft/maven cd /var/lib/docker/volumes/web_jenkins_home/_data/soft/maven wget https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip unzip apache-maven-3.8.4-bin.zip ``` * 对应jenkins中的配置 ```bash # maven安装路径配置 /var/jenkins_home/soft/maven ``` # jenkins构建node项目 ## 安装插件 [Section titled “安装插件”](#安装插件) ```plaintext nodeJs(14.16.0) ``` ![img.png](/_astro/img_2.Dufio3PN_ZCVHpQ.webp) ## 配置步骤 [Section titled “配置步骤”](#配置步骤) ![img.png](/_astro/img.DBGsyKoX_x8j7U.webp) ![img\_1.png](/_astro/img_1.yHCdXJpu_Z69Snb.webp) ## 执行shell(在jenkins里执行) [Section titled “执行shell(在jenkins里执行)”](#执行shell在jenkins里执行) ```shell pwd # 安装依赖(非必须) npm --registry https://registry.npmmirror.com/ install # 构建项目 npm run build:test # 删除除 node_modules和dist 以外的所有内容 ls | grep -v 'node_modules\|dist' | xargs rm -rf ``` ## Send files or execute commands over SSH(通过ssh远程执行shell) [Section titled “Send files or execute commands over SSH(通过ssh远程执行shell)”](#send-files-or-execute-commands-over-ssh通过ssh远程执行shell) ```shell export app_version='1.0' cd $DOCKER_WORKSPACE/$JOB_NAME mkdir -p ./nginx/conf.d/ # 添加default.conf文件 tee ./nginx/conf.d/default.conf <<-'EOF' server { listen 80; listen [::]:80; server_name localhost; #access_log /var/log/nginx/host.access.log main; location / { root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html; # 用于解决刷新页面后,显示404的问题 } } EOF # 编辑Dockerfile文件 echo "FROM nginx" > Dockerfile echo "MAINTAINER Fa" >> Dockerfile echo "WORKDIR /usr/share/nginx/html" >> Dockerfile echo "RUN rm -rf *" >> Dockerfile echo "ADD ./dist ." >> Dockerfile echo "ADD ./nginx/conf.d/default.conf /etc/nginx/conf.d/" >> Dockerfile echo "EXPOSE 80" >> Dockerfile # 构建镜像 docker build --no-cache -t $JOB_NAME:$app_version . # 上传镜像到私服 docker tag $JOB_NAME:$app_version registry.docker.com:5000/$JOB_NAME:$app_version docker push registry.docker.com:5000/$JOB_NAME:$app_version # 删除空镜像 docker images | awk '{if($1=="")print $3}' | xargs docker rmi &> /dev/null # 编辑stack yml文件 tee $JOB_NAME.yml <<-'EOF' version: '3.5' services: $JOB_NAME: image: registry.docker.com:5000/$JOB_NAME:${app_version} ports: - target: 80 published: 3230 mode: host networks: - middleware deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure networks: middleware: external: true EOF docker stack up -c $JOB_NAME.yml app # 删除除 node_modules 以外的所有内容 ls | grep -v 'node_modules' | xargs rm -rf ``` # Jenkins插件相关记录 ## jenkins 创建用户角色项目权限 [Section titled “jenkins 创建用户角色项目权限”](#jenkins-创建用户角色项目权限) * [参考文章](https://blog.csdn.net/u013066244/article/details/53407985) * jenkins 创建用户角色项目权限 * 安装Role-Based Strategy插件 * 配置设置路径: * 系统管理-> * 全局安全配置->授权策略->Role-Based Strategy * 管理用户->新建用户 * Manage and Assign Roles-> * Manage Roles-> * Global roles->\[全部->Read] * Item roles->\[Pattern->“ma-.\*”]|\[任务->(Build|Read)] * Assign Roles-> * Global roles->按实际情况配置 * Item roles->按实际情况配置 # jenkins部署相关问题记录 ## 该jenkins实例似乎已离线 [Section titled “该jenkins实例似乎已离线”](#该jenkins实例似乎已离线) ```plaintext 安装插件那个页面,就是提示你offline的那个页面,不要动。 然后打开一个新的tab,输入网址 `http://192.168.211.103:8080/jenkins/pluginManager/advanced`。 这里面最底下有个【升级站点】,把其中的链接由https改成http的就好了,http://updates.jenkins.io/update-center.json。 然后在服务列表中关闭jenkins,再tomcat重新启动,这样就能正常联网了 ``` ## 不能下载maven插件依赖 [Section titled “不能下载maven插件依赖”](#不能下载maven插件依赖) * Could not transfer artifact org.apache.maven.plugins:maven-clean-plugin:pom:2.5 from 这类问题的解决方法 * -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true # 在maven\_ops中加入该配置即可 * -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true -Dmaven.wagon.http.ssl.ignore.validity.dates=true # 未用过 * [参考文章](https://www.cnblogs.com/JavaArchitect/p/14383061.html) ![img.png](/_astro/img.C7EGQh5o_8xrBm.webp) *** ## vue项目,刷新页面后,显示404的问题 [Section titled “vue项目,刷新页面后,显示404的问题”](#vue项目刷新页面后显示404的问题) * try\_files $uri $uri/ /index.html; # 用于解决刷新页面后,显示404的问题 * [参考文章](https://www.cnblogs.com/caijinghong/p/14693820.html) ## npm镜像源问题 [Section titled “npm镜像源问题”](#npm镜像源问题) * [淘宝镜像源](https://registry.npmmirror.com/) * [淘宝cnpm镜像源](https://registry.npm.taobao.org) * [参考文章](https://cloud.tencent.com/developer/article/1372949) ## Dockerfile给服务器配置文件追加内容 [Section titled “Dockerfile给服务器配置文件追加内容”](#dockerfile给服务器配置文件追加内容) ````plaintext ```shell echo "FROM tomcat:8.5" > Dockerfile echo "MAINTAINER Fa" >> Dockerfile echo "RUN rm -rf /usr/local/tomcat/webapps/*" >> Dockerfile echo "RUN echo '' >> conf/catalina.properties" >> Dockerfile echo "RUN echo 'tomcat.util.http.parser.HttpParser.requestTargetAllow=|{}' >> conf/catalina.properties" >> Dockerfile echo "RUN echo 'org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true' >> conf/catalina.properties" >> Dockerfile echo "ADD ./target/*.war /usr/local/tomcat/webapps/" >> Dockerfile echo "EXPOSE 8080" >> Dockerfile # echo 'ENTRYPOINT ["/usr/local/tomcat/bin/catalina.sh","run"]' >> Dockerfile docker build -t docker-test . ``` ```` ## Java相关问题 [Section titled “Java相关问题”](#java相关问题) * 异常:org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.NoClassDefFoundError: Could not initialize class sun.font.SunFontManager * 启动java时加上参数:-Djava.awt.headless=true * [参考文章](https://www.cnblogs.com/yanqin/p/7160889.html) * 异常:找不到文件/opt/java/openjdk/lib/libfontmanager.so * 11-jre-alpine的docker镜像中找不到这个文件,所以去除-alpine,直接使用11-jre即可 # git通过ssh拉取代码 * 生成公私钥 ```shell ssh-keygen -t rsa -C “123456@qq.com” ``` * 将公钥(id\_rsa.pub)配置到github * 在jenkins中设置全局凭证,类型选择“SSH Username with private key”,将id\_rsa文件的内容复制到Private Key中,其他都是非必填选项,这里Username我们填写github ![ssh-username-with-private-key](/_astro/ssh-username-with-private-key.VWKiObNC_1vfqab.webp) # 远程登陆 * Publish over SSH * 配置私钥登陆 ![SSH Server](/_astro/ssh-service.BCaI5RhP_Z1IyO6W.webp) # 构建tomcat应用的相关记录 ```shell # 第四版(swarm+私服) # docker images | awk '{if($1=="$JOB_NAME") print $3}' | xargs docker rmi # published: 8280 # todo 映射端口根据实际调整 export app_version='1.0' cd $DOCKER_WORKSPACE/$JOB_NAME # 编辑Dockerfile文件 echo "FROM tomcat:8.5.71-jdk8-corretto" > Dockerfile echo "MAINTAINER Fa" >> Dockerfile echo "WORKDIR /usr/local/tomcat" >> Dockerfile echo "RUN rm -rf webapps/*" >> Dockerfile echo "ADD ./target/*$JOB_NAME webapps/$JOB_NAME" >> Dockerfile echo "EXPOSE 8080" >> Dockerfile # 构建镜像 docker build -t $JOB_NAME:$app_version . # 上传镜像到私服 docker tag $JOB_NAME:$app_version registry.docker.com:5000/$JOB_NAME:$app_version docker push registry.docker.com:5000/$JOB_NAME:$app_version # 删除空镜像 docker images | awk '{if($1=="")print $3}' | xargs docker rmi # 编辑stack yml文件 tee $JOB_NAME.yml <<-'EOF' version: '3.5' services: $JOB_NAME: image: registry.docker.com:5000/$JOB_NAME:${app_version} ports: - target: 8080 published: 8280 mode: host volumes: - /home/data/file:/usr/local/tmp/web-api/uploads/ networks: - middleware deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure networks: middleware: external: true EOF docker stack up -c $JOB_NAME.yml app ``` # 构建tomcat应用的相关记录 ```shell # 第四版(swarm+私服) # docker images | awk '{if($1=="$JOB_NAME") print $3}' | xargs docker rmi # published: 8280 # todo 映射端口根据实际调整 export app_version='1.0' cd $DOCKER_WORKSPACE/$JOB_NAME # 编辑server.xml文件 tee tomcat-server.xml <<-'EOF' EOF # 编辑Dockerfile文件 tee Dockerfile <<-'EOF' FROM tomcat:8.5-jdk8-corretto MAINTAINER Fa WORKDIR /usr/local/tomcat RUN rm -rf webapps/* ADD ./target/*$JOB_NAME webapps/ROOT RUN rm -rf ./conf/server.xml ADD ./tomcat-server.xml ./conf/server.xml EXPOSE 8080 EOF # 构建镜像 docker build -t $JOB_NAME:$app_version . # 上传镜像到私服 docker tag $JOB_NAME:$app_version registry.docker.com:5000/$JOB_NAME:$app_version docker push registry.docker.com:5000/$JOB_NAME:$app_version # 删除空镜像 docker images | awk '{if($1=="")print $3}' | xargs docker rmi # 编辑stack yml文件 tee $JOB_NAME.yml <<-'EOF' version: '3.5' services: $JOB_NAME: image: registry.docker.com:5000/$JOB_NAME:${app_version} ports: - target: 8080 published: 8280 mode: host volumes: - /home/data/file:/usr/local/tmp/web-api/uploads/ networks: - middleware deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure networks: middleware: external: true EOF docker stack up -c $JOB_NAME.yml app ``` # v2版jenkins部署 主要添加了代理环境变量配置 # dockerfile ## maven使用dockerfile插件构建项目 [Section titled “maven使用dockerfile插件构建项目”](#maven使用dockerfile插件构建项目) * 参考项目\[] * springboot pom.xml配置 ```xml UTF-8 UTF-8 1.8 true Finchley.RELEASE 1.4.3 registry.docker.com:5000 8880 ${project.name} com.spotify dockerfile-maven-plugin 1.4.13 default build push ${docker.image.prefix}/${project.build.finalName} ${project.version} ${project.build.finalName}.jar ${appPort} ``` * springboot application.yml配置 ```yaml server: port: @appPort@ logging: level: root: info spring: application: name: @project.name@ # com.example.demo.repository.UserRepository: debug ``` * Dockerfile文件配置 > tip: 放到项目根目录下 ```dockerfile #FROM openjdk:8-jdk-alpine FROM hub.c.163.com/dwyane/openjdk:8 # VOLUME ,VOLUME 指向了一个/tmp的目录,由于 Spring Boot 使用内置的Tomcat容器,Tomcat 默认使用/tmp作为工作目录。这个命令的效果是:在宿主机的/var/lib/docker目录下创建一个临时文件并把它链接到容器中的/tmp目录 VOLUME /tmp WORKDIR /workdir ARG JAR_FILE ARG APP_PORT ADD target/${JAR_FILE} app.jar # ENTRYPOINT ,为了缩短 Tomcat 的启动时间,添加java.security.egd的系统属性指向/dev/urandom作为 ENTRYPOINT #ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","app.jar"] ENTRYPOINT ["java","-jar","app.jar"] EXPOSE ${APP_PORT} ``` * 执行mvn clean package > 访问私有仓库看构建情况: * Jenkins配置 * 创建maven项目 * Build\[Goals and options -> clean install -Dmaven.test.skip=true] * Post Steps\[Run only if build succeeds] * add post-build step\[Send files or execute commands over SSH] ```shell cd $DOCKER_WORKSPACE/$JOB_NAME export app_version='1.0' # 编辑stack yml文件 tee $JOB_NAME.yml <<-'EOF' version: '3.5' services: $JOB_NAME: image: registry.docker.com:5000/$JOB_NAME:${app_version} ports: - target: 8880 published: 8880 mode: host networks: - middleware deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure networks: middleware: external: true EOF # 启动app容器 docker stack up -c $JOB_NAME.yml app ``` ## 开放docker远程访问 [Section titled “开放docker远程访问”](#开放docker远程访问) * 编辑/etc/sysconfig/docker文件,我安装的docker ce,没有发现这个文件,如果有,则: ```shell sudo vi /etc/sysconfig/docker //添加下面这行 other_args="-H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock" //保存 :wq! //重启docker服务 service docker restart ``` * 在windows系统环境变量中新建DOCKER\_HOST值为tcp\://\[docker\_ip]:2375,将这里的\[docker\_ip],替换为docker所在的centos服务器IP或主机名(用主机名,需要windows配置hosts),可能需要重启系统。 * 修改/usr/lib/systemd/system/docker.service文件 ```shell sudo vi /usr/lib/systemd/system/docker.service //在ExecStart这一行后面加上(这里就写4个0,别改成自己的ip) -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock 改完后效果如下 ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock :wq! 保存退出 重新加载配置文件 systemctl daemon-reload 重启docker :service docker restart 这样才可以是/etc/default/docker中的配置项生效 ``` * 我们首先查询docker所在虚拟机在监听哪些端口,使用命令: ```shell netstat -tlunp # 显示 # tcp6 0 0 :::2375 :::* LISTEN - # 2375端口,已在监听。 # 那很有可能时防火墙的问题,在CentOS7中,默认会打开firewalld防火墙,如果防火墙打开后,默认情况下只会监听在22号端口,也就是说主机对外暴露的端口只有22。 # 使用如下命令: sudo iptables-save # 查看防火墙暴漏的对外端口,发现2373端口没有对位暴漏。 # 需要增加2375端口对外暴漏,使用如下命令: # 添加端口 sudo firewall-cmd --zone=public --add-port=2375/tcp --permanent # 重载防火墙 sudo firewall-cmd --reload # 看到sucess字样后,再使用iptables-save命令查看端口,可以看到,对外放开的端口增加了2375端口。 ``` # simple ## maven使用dockerfile插件构建项目 [Section titled “maven使用dockerfile插件构建项目”](#maven使用dockerfile插件构建项目) * 参考项目\[] #### Jenkins配置 [Section titled “Jenkins配置”](#jenkins配置) * 创建maven项目 * Build\[Goals and options -> clean install -Dmaven.test.skip=true] * Post Steps\[Run only if build succeeds] * add post-build step\[Send files or execute commands over SSH] ```shell cd $DOCKER_WORKSPACE/$JOB_NAME export app_version='1.0' # 编辑Dockerfile文件 tee Dockerfile <<-'EOF' FROM hub.c.163.com/dwyane/openjdk:8 WORKDIR /workdir ADD target/$JOB_NAME.jar app.jar ENTRYPOINT ["java","-jar","app.jar"] EXPOSE 8080 EOF # 构建镜像 docker build -t $JOB_NAME:$app_version . # 上传镜像到私服 docker tag $JOB_NAME:$app_version registry.docker.com:5000/$JOB_NAME:$app_version docker push registry.docker.com:5000/$JOB_NAME:$app_version # 编辑stack yml文件 tee $JOB_NAME.yml <<-'EOF' version: '3.5' services: $JOB_NAME: image: registry.docker.com:5000/$JOB_NAME:${app_version} ports: - target: 8880 published: 8880 mode: host networks: - middleware deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure networks: middleware: external: true EOF # 启动app容器 docker stack up -c $JOB_NAME.yml app ``` # springboot ## springboot pom.xml配置 [Section titled “springboot pom.xml配置”](#springboot-pomxml配置) ```xml com.spotify docker-maven-plugin 0.4.13 demo ${project.basedir}/src/main/docker / ${project.build.directory} ${project.build.finalName}.jar ``` ## docker.sh [Section titled “docker.sh”](#dockersh) ```shell mvn clean package docker:build echo "当前docker 镜像:" docker images | grep demo echo "启动容器----->" docker run -p 8001:8001 -d demo echo "启动服务成功!" ``` ## Dockerfile [Section titled “Dockerfile”](#dockerfile) ```shell #FROM openjdk:8-jdk-alpine FROM hub.c.163.com/dwyane/openjdk:8 VOLUME /tmp ADD docker-springboot-1.0-SNAPSHOT.jar app.jar ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"] ``` ## jenkins 安装docker插件 [Section titled “jenkins 安装docker插件”](#jenkins-安装docker插件) * docker插件配置\[系统管理->系统配置->Cloud] * 配置docker host URI \[unix:///var/run/docker.sock] > (typically unix:///var/run/docker.sock or tcp\://127.0.0.1:2376) ![img.png](/_astro/img.Depxk_I2_Z4bcnO.webp) ## 新建maven项目配置 [Section titled “新建maven项目配置”](#新建maven项目配置) ![img\_1.png](/_astro/img_1.BCqdzK_u_2os36G.webp) ![img\_2.png](/_astro/img_2.h-NSKANp_3cfzW.webp) # maven使用记录 ## 一键删除maven仓库无效jar包脚本 [Section titled “一键删除maven仓库无效jar包脚本”](#一键删除maven仓库无效jar包脚本) ```plaintext delLastUpdated.bat ``` 使用方法: 复制上面文件,双击打开,输入maven仓库的地址或者把仓库的文件夹拖入到命令窗口,在回车即可。 ![img.png](/_astro/img.8qShjYNj_ZAi6A9.webp) ## Maven的-pl用法 [Section titled “Maven的-pl用法”](#maven的-pl用法) * [参考文章](https://blog.csdn.net/zmm0420/article/details/115937027) * [参考文章](https://blog.csdn.net/wangooo/article/details/109361708) ```shell clean deploy -Dmaven.test.skip=true -pl project-a (只构建其中一个) clean deploy -Dmaven.test.skip=true -pl project-a,project-b,project-c (只构建其中三个个) # 示例 mvn clean package -Dmaven.test.skip=true -pl cn.facoder:mall-server -am ``` ## 依赖分析 [Section titled “依赖分析”](#依赖分析) * mvn dependency:analyze * 可以分析没有用到的依赖有哪些 ## jar包瘦身 [Section titled “jar包瘦身”](#jar包瘦身) * [参考文章](https://www.cnblogs.com/ygjlch/p/7767639.html)`主要思想:将依赖放到宿主机上,通过挂载方式加载依赖` # openHands使用记录 [github仓库](https://github.com/All-Hands-AI/OpenHands) ## 安装 [Section titled “安装”](#安装) ```bash WORKSPACE_BASE=$(pwd)/workspace docker run -it \ --pull=always \ -e SANDBOX_USER_ID=$(id -u) \ -e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \ -v $WORKSPACE_BASE:/opt/workspace_base \ -v /var/run/docker.sock:/var/run/docker.sock \ -p 3000:3000 \ --add-host host.docker.internal:host-gateway \ --name openhands-app-$(date +%Y%m%d%H%M%S) \ ghcr.io/all-hands-ai/openhands:main ``` * 使用本地llama模型 ```bash export WORKSPACE_BASE=$(pwd)/workspace docker run \ -it \ --pull=always \ --add-host host.docker.internal:host-gateway \ -e SANDBOX_USER_ID=$(id -u) \ -e LLM_API_KEY="ollama" \ -e LLM_BASE_URL="http://host.docker.internal:11434" \ -e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \ -v $WORKSPACE_BASE:/opt/workspace_base \ -v /var/run/docker.sock:/var/run/docker.sock \ -p 3000:3000 \ ghcr.io/all-hands-ai/openhands:main ``` * 使用cloudflare llama模型 ```bash export WORKSPACE_BASE=$(pwd)/workspace # -e LLM_API_KEY="ollama" \ docker run \ -it \ --pull=always \ --add-host host.docker.internal:host-gateway \ -e SANDBOX_USER_ID=$(id -u) \ -e LLM_BASE_URL="https://meta-llama-3-8b-instruct.183461750.workers.dev" \ -e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \ -v $WORKSPACE_BASE:/opt/workspace_base \ -v /var/run/docker.sock:/var/run/docker.sock \ -p 3000:3000 \ ghcr.io/all-hands-ai/openhands:main ``` * 使用通义千问模型 ```bash export WORKSPACE_BASE=$(pwd)/workspace docker run \ -it \ --pull=always \ --add-host host.docker.internal:host-gateway \ -e SANDBOX_USER_ID=$(id -u) \ -e LLM_API_KEY="sk-<替换为自己的密钥>" \ -e LLM_BASE_URL="https://dashscope.aliyuncs.com/api/v1/apps/<替换为自己的应用id>/completion" \ -e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \ -v $WORKSPACE_BASE:/opt/workspace_base \ -v /var/run/docker.sock:/var/run/docker.sock \ -p 3000:3000 \ ghcr.io/all-hands-ai/openhands:main ``` # simple ## 访问地址 [Section titled “访问地址”](#访问地址) ```shell http://ip:9100/metrics( 查看服务器的指标) http://ip:8899/metrics(查看docker容器的指标) http://ip:9090/(prometheus的原生web-ui) http://ip:3000/(Grafana开源的监控可视化组件页面) ``` ![img.png](/_astro/img_0.C-2oHsMd_Z10R29n.webp) ## Grafana配置监控 [Section titled “Grafana配置监控”](#grafana配置监控) * Try it out, default admin user credentials are admin/admin. * configuration -> base sources -> prometheus ![img.png](/_astro/img.BXFAg-5a_kmkzY.webp) * 配置url: ![img\_1.png](/_astro/img_1.CRJHIh-C_1PtLr5.webp) * import对应的模板,相关的模板可以在 这里查到。 * create -> import -> 8913 ![img\_2.png](/_astro/img_2.Cr7D8EtN_Z1r2IVr.webp) ![img\_3.png](/_astro/img_3.CU698AF-_1EW5SF.webp) ![img\_4.png](/_astro/img_4.C3YTeNZ__26ql8h.webp) * 我们用docker启动的服务还是蛮多的,也可以看看Docker的监控(上面启动的cadvisor服务就采集了Docker的信息),我们使用模板893来配置监控docker的信息: ![img\_5.png](/_astro/img_5.Dmaca61V_26h5Hc.webp) ## Java系统指标 [Section titled “Java系统指标”](#java系统指标) * 在项目中多引入两个pom依赖 ```xml org.springframework.boot spring-boot-starter-actuator io.micrometer micrometer-registry-prometheus ``` * 然后在配置文件上加上对应的配置(开启监控并可以让prometheus拉取配置) ```yaml # 监控配置 TODO management: endpoint: health: show-details: always metrics: enabled: true prometheus: enabled: true endpoints: web: exposure: include: '*' metrics: export: prometheus: enabled: true ``` * 启动服务后,访问/actuator路径就能看到一大堆输出的指标了,包括prometheus的 ![img\_6.png](/_astro/img_6.B-q_KRSS_22AkQb.webp) * 在前面写好的的prometheus.yml文件下添加相关的配置信息: ```yaml - job_name: 'austin' metrics_path: '/actuator/prometheus' # 采集的路径 static_configs: - targets: ['ip:port'] # todo 这里的ip和端口写自己的应用下的 ``` * 访问:ip:9090/targets这个路径下,能看到现在prometheus能采集到的端点有哪些,看到都是自己所配置的状态为up,那就说明正常了。 ![img\_7.png](/_astro/img_7.st1RNBz8_n4f7X.webp) * 选用了4701模板的JVM监控和12900SpringBoot监控 ![img\_8.png](/_astro/img_8.BqDIbsFf_1L3JT7.webp) ![img\_9.png](/_astro/img_9.CDZ4IuTb_Z1vTy7n.webp) * 业务指标 ![img\_10.png](/_astro/img_10.jr7_DDMP_Z2wv9kz.webp) * 总结 ![img\_11.png](/_astro/img_11.BZwDZ9s0_uYllE.webp) # watch ## 安装node\_exporter [Section titled “安装node\_exporter”](#安装node_exporter) ```shell 1、wget https://github.com/prometheus/node_exporter/releases/download/v1.1.2/node_exporter-1.1.2.linux-amd64.tar.gz 2、tar -zxf node_exporter-1.1.2.linux-amd64.tar.gz -C /usr/local/ 3、cd /usr/local/ 4、mv /usr/local/node_exporter-1.1.2.linux-amd64/ /usr/local/node_exporter 5、vim config.yml(配置访问的用户名密码,可根据需要跳过这一步) ``` * 使用htpasswd加密密码,加密方式为htpasswd -nBC 12 ” | tr -d ’:\n’ * config.yml ```shell basic_auth_users: # 当前设置的用户名为 prometheus , 可以设置多个 # 密码加密方式 htpasswd -nBC 12 '' | tr -d ':\n' username: password ``` ```shell 6、nohup /usr/local/node_exporter/node_exporter --web.config=./config.yml & nohup ./node_exporter --web.config=./config.yml & ``` ## influxdb配置 [Section titled “influxdb配置”](#influxdb配置) ```shell # 可通过此方式创建库 docker exec -it 容器名 ./run-basic.sh ``` ## alertmanager配置 [Section titled “alertmanager配置”](#alertmanager配置) ```shell 参数说明: resolve_timeout: 当告警的状态由firing变为resolve后需要等待多长时间,才宣布告警解除 receivers:定义谁接收告警。 name: 代称,方便后面使用 route:告警内容从这里进入,寻找相应的策略发送出去 receiver:一级的receiver,也就是默认的receiver,当告警进来后没有找到任何子节点和自己匹配,就用这个receiver group_by:告警应该根据那些标签进行分组 group_wait:同一组的告警发出前要等待多久后才能再次发出去 group_interval:同一组的多批次告警间隔多少秒后,才能发出 repeat_interval:重复的告警要等待多久后才能再次发出去 inhibit_rules:这个叫做抑制项,通过匹配源告警来抑制目的告警。比如说当我们的主机挂了,可能引起主机上的服务,数据库,中间件等一些告警,假如说后续的这些告警相对来说没有意义,我们可以用抑制项这个功能,让Prometheus只发出主机挂了的告警 source_match:根据label匹配源告警 target_match:根据label匹配目的告警 equal:此处的集合的label,在源和目的的值必须相等。如果该集合内的值在源和目的里都没有,那么目的告警也会被抑制 ``` # doc-test ## Jenkins配置 [Section titled “Jenkins配置”](#jenkins配置) ```shell cd $DOCKER_WORKSPACE/$JOB_NAME # 创建docker mongo.yml文件(执行一次就好了) tee mongo.yml <<-'EOF' version: "3.5" services: mongo: image: mongo environment: - MONGO_INITDB_DATABASE=yapi - MONGO_INITDB_ROOT_USERNAME=root - MONGO_INITDB_ROOT_PASSWORD=root ports: - target: 27017 published: 27017 mode: host volumes: - mongo_data_db:/data/db networks: middleware: deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure volumes: mongo_data_db: networks: middleware: external: true EOF # 启动 docker stack up -c mongo.yml data # 自定义配置文件 config.json # 其中管理员账号在下面配置,密码默认为ymfe.org tee config.json <<-'EOF' { "port": "3000", "adminAccount": "admin", "timeout":120000, "db": { "servername": "_MONGO_SERVER_NAME", "DATABASE": "yapi", "port": 27017, "user": "root", "pass": "root", "authSource": "admin" } } EOF # 自定义配置文件 docker-entrypoint.sh tee docker-entrypoint.sh <<-'EOF' #!/bin/bash # set -eo pipefail declare -A PAGE_PARAMS=( ["_MONGO_SERVER_NAME"]="mongo" ) for index in "${!PAGE_PARAMS[@]}"; do ENV_VAL=`eval echo '$'${index}` [ -z "${ENV_VAL}" ] && ENV_VAL=${PAGE_PARAMS[$index]} echo "text repeat: ${index}-->${ENV_VAL}" echo "$(/bin/sed "s!${index}!${ENV_VAL}!g" /yapi/config.json)" > /yapi/config.json; done exec "$@" EOF # 创建Dockerfile文件 tee Dockerfile <<-'EOF' FROM node:12-alpine as builder WORKDIR /yapi RUN apk add --no-cache wget python3 make ENV VERSION=1.9.3 RUN wget https://github.com/YMFE/yapi/archive/v${VERSION}.zip RUN unzip v${VERSION}.zip && mv yapi-${VERSION} vendors RUN cd vendors && npm install --production --registry https://registry.npm.taobao.org FROM node:12-alpine MAINTAINER 183461750@qq.com ENV TZ="Asia/Shanghai" ENV MONGO_SERVER_NAME=mongo WORKDIR /yapi/vendors COPY --from=builder /yapi/vendors /yapi/vendors COPY config.json ../config.json COPY docker-entrypoint.sh /docker-entrypoint.sh RUN chmod +x /docker-entrypoint.sh RUN echo -e http://mirrors.ustc.edu.cn/alpine/v3.15/main/ > /etc/apk/repositories RUN apk add --no-cache bash EXPOSE 3000 ENTRYPOINT ["/docker-entrypoint.sh"] CMD ["node", "server/app.js"] EOF # app构建版本号 export app_version='1.0' # 构建镜像 docker build -t $JOB_NAME:$app_version . # 上传镜像到私服 docker tag $JOB_NAME:$app_version registry.docker.com:5000/$JOB_NAME:$app_version docker push registry.docker.com:5000/$JOB_NAME:$app_version # 创建docker yapi.yml文件 tee $JOB_NAME.yml <<-'EOF' version: "3.5" services: $JOB_NAME: image: registry.docker.com:5000/$JOB_NAME:${app_version} ports: - target: 3000 published: 3000 mode: host environment: MONGO_SERVER_NAME: mongo depends_on: - mongo volumes: - yapi_log:/home/vendors/log - ./config.json:/yapi/config.json networks: middleware: deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure volumes: yapi_log: networks: middleware: external: true EOF # 启动 docker stack up -c $JOB_NAME.yml open_app ``` # simple ## Jenkins配置 [Section titled “Jenkins配置”](#jenkins配置) ```shell cd $DOCKER_WORKSPACE/$JOB_NAME # 创建docker mongo.yml文件(执行一次就好了) tee mongo.yml <<-'EOF' version: "3.5" services: mongo: image: mongo environment: - MONGO_INITDB_DATABASE=yapi - MONGO_INITDB_ROOT_USERNAME=root - MONGO_INITDB_ROOT_PASSWORD=root ports: - target: 27017 published: 27017 mode: host volumes: - mongo_data_db:/data/db networks: middleware: deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure volumes: mongo_data_db: networks: middleware: external: true EOF # 启动 docker stack up -c mongo.yml data # 自定义配置文件 config.json # 其中管理员账号在下面配置,密码默认为ymfe.org tee config.json <<-'EOF' { "port": "3000", "adminAccount": "admin@admin.com", "timeout":120000, "db": { "servername": "_MONGO_SERVER_NAME", "DATABASE": "yapi", "port": 27017, "user": "root", "pass": "root", "authSource": "admin" } } EOF # 自定义配置文件 docker-entrypoint.sh tee docker-entrypoint.sh <<-'EOF' #!/bin/bash # set -eo pipefail declare -A PAGE_PARAMS=( ["_MONGO_SERVER_NAME"]="mongo" ) for index in "${!PAGE_PARAMS[@]}"; do ENV_VAL=`eval echo '$'${index}` [ -z "${ENV_VAL}" ] && ENV_VAL=${PAGE_PARAMS[$index]} echo "text repeat: ${index}-->${ENV_VAL}" echo "$(/bin/sed "s!${index}!${ENV_VAL}!g" /yapi/config.json)" > /yapi/config.json; done cat /yapi/config.json node /yapi/vendors/server/install.js exec "$@" EOF # 创建Dockerfile文件 tee Dockerfile <<-'EOF' FROM node:12-alpine as builder WORKDIR /yapi RUN apk add --no-cache wget python3 make ENV VERSION=1.9.3 RUN wget https://github.com/YMFE/yapi/archive/v${VERSION}.zip RUN unzip v${VERSION}.zip && mv yapi-${VERSION} vendors RUN cd vendors && npm install --production --registry https://registry.npm.taobao.org FROM node:12-alpine MAINTAINER 183461750@qq.com ENV TZ="Asia/Shanghai" ENV MONGO_SERVER_NAME=mongo WORKDIR /yapi/vendors COPY --from=builder /yapi/vendors /yapi/vendors COPY config.json ../config.json COPY docker-entrypoint.sh /docker-entrypoint.sh RUN chmod +x /docker-entrypoint.sh RUN echo -e http://mirrors.ustc.edu.cn/alpine/v3.15/main/ > /etc/apk/repositories RUN apk add --no-cache bash EXPOSE 3000 ENTRYPOINT ["/docker-entrypoint.sh"] CMD ["node", "server/app.js"] EOF # app构建版本号 export app_version='1.0' # 构建镜像 docker build -t $JOB_NAME:$app_version . # 上传镜像到私服 docker tag $JOB_NAME:$app_version registry.docker.com:5000/$JOB_NAME:$app_version docker push registry.docker.com:5000/$JOB_NAME:$app_version # 创建docker yapi.yml文件 tee $JOB_NAME.yml <<-'EOF' version: "3.5" services: $JOB_NAME: image: registry.docker.com:5000/$JOB_NAME:${app_version} ports: - target: 3000 published: 3000 mode: host environment: MONGO_SERVER_NAME: mongo depends_on: - mongo volumes: - yapi_log:/home/vendors/log - ./config.json:/yapi/config.json networks: middleware: deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure volumes: yapi_log: networks: middleware: external: true EOF # 启动 docker stack up -c $JOB_NAME.yml open_app ``` # yapi ## 部署 [Section titled “部署”](#部署) * [参考地址](https://github.com/fjc0k/docker-YApi) ```shell git clone https://github.com/fjc0k/docker-YApi.git # 无法访问 github 的可使用国内镜像: git clone https://gitee.com/fjc0k/docker-YApi.git # 接下来,进入docker-YApi目录,修改 docker-compose.yml 中 yapi-web 下的环境变量 YAPI_ADMIN_ACCOUNT 为你的管理员邮箱,YAPI_ADMIN_PASSWORD 为你的管理员密码。 # YAPI_CLOSE_REGISTER=false 设置为false则开启普通用户注册功能 # 最后,执行 docker-compose up -d 启动服务。 # 然后,通过 http://localhost:40001 即可访问 YApi。 ``` # yapi ## Dockerfile [Section titled “Dockerfile”](#dockerfile) ```shell FROM node:12-alpine as builder WORKDIR /yapi RUN apk add --no-cache wget python make ENV VERSION=1.9.2 RUN wget https://github.com/YMFE/yapi/archive/v${VERSION}.zip RUN unzip v${VERSION}.zip && mv yapi-${VERSION} vendors RUN cd /yapi/vendors && cp config_example.json ../config.json && npm install --production --registry https://registry.npm.taobao.org FROM node:12-alpine MAINTAINER 545544032@qq.com ENV TZ="Asia/Shanghai" WORKDIR /yapi/vendors COPY --from=builder /yapi/vendors /yapi/vendors EXPOSE 3000 ENTRYPOINT ["node"] ``` ```shell tee Dockerfile <<-'EOF' FROM node:12-alpine as builder WORKDIR /yapi RUN apk add --no-cache wget python make ENV VERSION=1.9.3 RUN wget https://github.com/YMFE/yapi/archive/v${VERSION}.zip RUN unzip v${VERSION}.zip && mv yapi-${VERSION} vendors RUN cd /yapi/vendors && cp config_example.json ../config.json && npm install --production --registry https://registry.npm.taobao.org FROM node:12-alpine MAINTAINER 183461750@qq.com ENV TZ="Asia/Shanghai" WORKDIR /yapi/vendors COPY --from=builder /yapi/vendors /yapi/vendors EXPOSE 3000 ENTRYPOINT ["node"] EOF ``` ## 构建镜像 [Section titled “构建镜像”](#构建镜像) ```shell docker build -t yapi . ``` ## yapi升级 [Section titled “yapi升级”](#yapi升级) ```shell # 1、停止并删除旧版容器 docker rm -f yapi # 2、获取最新镜像 docker pull registry.cn-hangzhou.aliyuncs.com/anoyi/yapi # 3、启动新容器 docker run -d \ --name yapi \ --link mongo-yapi:mongo \ --workdir /yapi \ -p 3000:3000 \ -v $PWD/config.json:/config.json \ registry.cn-hangzhou.aliyuncs.com/anoyi/yapi \ server/app.js ``` ## Jenkins配置 [Section titled “Jenkins配置”](#jenkins配置) ```shell cd $DOCKER_WORKSPACE/$JOB_NAME # 创建Dockerfile文件 tee Dockerfile <<-'EOF' FROM node:12-alpine as builder WORKDIR /yapi RUN apk add --no-cache wget python3 make ENV VERSION=1.9.2 RUN wget https://github.com/YMFE/yapi/archive/v${VERSION}.zip RUN unzip v${VERSION}.zip && mv yapi-${VERSION} vendors RUN cd /yapi/vendors && cp config_example.json ../config.json && npm install --production --registry https://registry.npm.taobao.org FROM node:12-alpine MAINTAINER 183461750@qq.com ENV TZ="Asia/Shanghai" WORKDIR /yapi/vendors COPY --from=builder /yapi/vendors /yapi/vendors EXPOSE 3000 # ENTRYPOINT ["node"] ENTRYPOINT ["node", "./server/app.js"] EOF # app构建版本号 export app_version='1.0' # 构建镜像 docker build -t $JOB_NAME:$app_version . # 上传镜像到私服 docker tag $JOB_NAME:$app_version registry.docker.com:5000/$JOB_NAME:$app_version docker push registry.docker.com:5000/$JOB_NAME:$app_version # 自定义配置文件 config.json tee config.json <<-'EOF' { "port": "3000", "adminAccount": "183461750@qq.com", "timeout":120000, "db": { "servername": "mongo", "DATABASE": "yapi", "port": 27017, "user": "anoyi", "pass": "anoyi.com", "authSource": "admin" } } EOF # 创建docker yapi.yml文件 tee $JOB_NAME.yml <<-'EOF' version: "3.5" services: $JOB_NAME: image: registry.docker.com:5000/$JOB_NAME:${app_version} environment: - VERSION=1.5.6 - LOG_PATH=/tmp/yapi.log - HOME=/home - PORT=3000 - ADMIN_EMAIL=test@test.com - DB_SERVER=mongo - DB_NAME=yapi - DB_PORT=27017 ports: - target: 3000 published: 3000 mode: host volumes: - yapi_log:/home/vendors/log - ./config.json:/yapi/config.json depends_on: - mongo networks: middleware: deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure mongo: image: mongo environment: - MONGO_INITDB_ROOT_USERNAME=anoyi - MONGO_INITDB_ROOT_PASSWORD=anoyi.com volumes: - mongo_data_db:/data/db networks: middleware: deploy: replicas: 1 update_config: parallelism: 1 restart_policy: condition: on-failure volumes: yapi_log: mongo_data_db: networks: middleware: external: true EOF # 启动 docker stack up -c $JOB_NAME.yml open_app ``` # 禅道 ## 执行命令 [Section titled “执行命令”](#执行命令) ```shell docker run --name zentao -p 8888:80 --mac-address 02:42:ac:11:00:00 -v /home/data/docker/zentao/www/zentaopms:/www/zentaopms -v /home/data/docker/zentao/www/mysqldata:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d easysoft/zentao ``` # firefox浏览器相关说明 ## 1. 安装 [Section titled “1. 安装”](#1-安装) ```shell ####### kasmweb版(推荐) # The container is now accessible via a browser : https://IP_OF_SERVER:6901 # User : kasm_user # Password: password docker run --rm -it --shm-size=512m -p 6901:6901 -e VNC_PW=password kasmweb/firefox:1.14.0 ``` * mac系统的docker可用的容器镜像 [仓库地址](https://github.com/jlesage/docker-firefox) ```bash # 简单命令 docker run -d --name=firefox -p 5800:5800 -e LANG=zh_CN.UTF-8 -e ENABLE_CJK_FONT=1 jlesage/firefox # VNC版 docker run -d --name firefox -e TZ=Asia/Hong_Kong -e LANG=zh_CN.UTF-8 -e KEEP_APP_RUNNING=1 -e ENABLE_CJK_FONT=1 -e VNC_PASSWORD=admin -p 5800:5800 -p 5900:5900 -v /data/firefox/config:/config:rw --shm-size 2g jlesage/firefox ``` ## 相关文章 [Section titled “相关文章”](#相关文章) * [Docker自建浏览器:让你《随时-随地》访问你内网的光猫路由Nas等Web设备](https://mp.weixin.qq.com/s/8jzfNUlqhnnjjrkbbh0o-Q) # neko [仓库地址](https://github.com/m1k1o/neko.git) # adguard ## DoH和DoT配置 [Section titled “DoH和DoT配置”](#doh和dot配置) * 使用Let’s Encrypt申请免费证书 * 註冊了一個 abc.com 的域名,請先去 DNS 管理後台新增一條 A 記錄 * 安装certbot ```shell # 切換 root 身份 $ sudo su # 先更新系統 $ apt update && apt full-upgrade -y # 安裝 certbot $ apt install certbot # 開始簽名,下面電子郵件跟域名請換成自己的 $ certbot certonly --standalone -n --agree-tos --email webmaster@abc.com --preferred-challenges http -d dns.abc.com ``` * 证书自动续约 ```shell # 先測試看看自動更新證書有無問題,下面這一條指令會測試去更新,並不會實際去更新 $ certbot renew --dry-run # 如無問題的話,接著我們要把兩個月簽名一次的工作加入排程 $ crontab -e # 選擇 nano 文字編輯器,打開文件後,複製以下到裡面,然後保存退出 0 0 15 */2 * /usr/bin/certbot renew --quiet # 如此每隔兩個月十五號他就會自動執行一次續簽證書 ``` * 在 iOS 上使用 DNSCloak 設定 On demand 自動切換 [参考文章](https://www.jkg.tw/p2660/) ## 封锁清单 [Section titled “封锁清单”](#封锁清单) * * * [参考文章](https://www.isharepc.com/27230.html) ## DNS服务器 [Section titled “DNS服务器”](#dns服务器) ```text 223.5.5.5 119.29.29.29 114.114.114.114 223.6.6.6 2400:3200::1 2400:3200:baba::1 https://dns.alidns.com/dns-query tls://dns.alidns.com ``` # ddns使用记录 ## nat类型检测 [Section titled “nat类型检测”](#nat类型检测) [nat类型检测网页版](https://mao.fan/mynat) ```bash # 检测nat类型 docker run --rm --network host python:3.12.12-alpine3.23 /bin/sh -c "pip install pystun3 && pystun3" ``` ## ddns-go [Section titled “ddns-go”](#ddns-go) [ddns-go](https://github.com/jeessy2/ddns-go) 用途 * 动态更新域名解析记录到当前公网IP * 动态更新域名解析记录到当前内网IP * 自己家里或者公司的机器的内网IP会自动变的情况可以使用(当然, 只能内网访问) ```bash docker run -d --name ddns-go --restart=always --net=host -v /opt/ddns-go:/root jeessy/ddns-go ``` ```bash # 子域名的DNS修改(例如: DNS上的子域名(即后缀)为tx.iuin888vip.icu) fa:tx.iuin888vip.icu ``` ```bash # 查看子域名的DNS解析记录(查看ip) nslookup fa.tx.iuin888vip.icu # 网页版: https://itango.tencent.com/app/data/huatuo?domain=fa.tx.iuin888vip.icu ``` ## TODO [Section titled “TODO”](#todo) * 看看这个项目是否能用上[ddns-go](https://github.com/jeessy2/ddns-go)(done) * 看看cloudflare的ddns服务 # netbird使用 * 使用docker安装 ```bash docker run --rm -d \ --cap-add=NET_ADMIN \ -e NB_SETUP_KEY=SETUP_KEY \ -v netbird-client:/etc/netbird \ netbirdio/netbird:latest # https://docs.netbird.io/how-to/getting-started#running-net-bird-in-docker ``` * 参考链接 * [官方地址](https://app.netbird.io) * [B站视频](https://www.bilibili.com/video/BV1hm4y1G7P4/?buvid=XX830E687E1A6043634FE5BA62D04AE61B60C\&is_story_h5=false\&mid=KVrRvQIgah%2BvjvHS%2FHBsSQ%3D%3D\&p=1\&plat_id=106\&share_from=ugc\&share_medium=android\&share_plat=android\&share_session_id=05eed0e5-fa80-4055-b974-b0626f52d8a0\&share_source=WEIXIN\&share_tag=s_i\&spmid=main.space-contribution.0.0\×tamp=1700946217\&unique_k=I33DBjq\&up_id=1323796788) # BT种子下载 * 暂时没有使用的需求,就暂时不折腾了 * [参考文章](https://www.aiwanba.net/post/8560.html) * wonderfall/rtorrent-flood(在dockerhub中搜索`rtorrent`即可) # sub-web 订阅转换 [前端仓库地址](https://github.com/CareyWang/sub-web?tab=readme-ov-file#install) [后端仓库地址](https://github.com/tindy2013/subconverter) ```bash # 前端部署 docker run -d -p 58080:80 --restart always --name subweb careywong/subweb:latest # 后端部署 docker run -d --restart=always -p 25500:25500 tindy2013/subconverter:latest ``` # ipsec-vpn ## 什么是IPsec VPN? [Section titled “什么是IPsec VPN?”](#什么是ipsec-vpn) IPsec即Internet Protocol Security,是一种用于保护互联网协议(IP)传输数据的协议。而VPN(Virtual Private Network)则是一种基于公共网络构建的专用网络,在其中可以进行安全数据传输。IPsec VPN结合二者的优势,可以在公共网络中创建一个虚拟专用网络,实现不同地点之间的安全通信,包括远程办公、资源共享等。 ## 使用Docker搭建IPsec VPN Server [Section titled “使用Docker搭建IPsec VPN Server”](#使用docker搭建ipsec-vpn-server) ### 服务端 [Section titled “服务端”](#服务端) 规划vpn配置信息 * /data/jump/vpn/.env为vpn配置信息 ```shell VPN_IPSEC_PSK=password1! # 配置用于登陆VPN的账号和密码 VPN_USER=vpn VPN_PASSWORD=vpn1234 # 如下应该填写本机的外网IP(服务器ip) VPN_PUBLIC_IP=36.111.179.* # 配置额外的用户名和密码 VPN_ADDL_USERS=vpn1 vpn2 VPN_ADDL_PASSWORDS=vpn11234 pass21234 #DNS配置 VPN_DNS_SRV1=8.8.8.5 VPN_DNS_SRV2=114.114.114.114 ``` 启动VPN服务 ```shell docker run \ --name ipsec-vpn-server \ --env-file /data/jump/vpn/.env \ --restart=always \ -p 500:500/udp \ -p 4500:4500/udp \ -v /lib/modules:/lib/modules:ro \ -d --privileged \ hwdsl2/ipsec-vpn-server ``` 查看信息 ```shell # 查看VPN连接信息 docker logs -f ipsec-vpn-server # 查看客户端连接情况,ip分配、流量使用等 docker exec -it ipsec-vpn-server ipsec whack --trafficstatus ``` ### 客户端 [Section titled “客户端”](#客户端) 客户端连接VPN通用配置(手机、电脑) ```shell #不同设备实际需要填写的信息会有略微不同,但是关键信息为以下几个配置 VPN类型:IPSec 服务器:vpn服务器的ip,不需要端口 密钥:配置信息中的IPSec PSK 用户名、密码:配置信息中的username、password ``` ## 相关文章 [Section titled “相关文章”](#相关文章) * [一套好用的VPN](https://mp.weixin.qq.com/s/iKOaRoSwbA5Nz667uk-jRA) * 私有文章 * [package](https://gitee.com/LFa/doc/raw/master/me/records/soft/vpn/openVPN/pakage/doc.md) # openvpn客户端 [科学上网与VPN办公的完美结合](https://blog.long2ice.io/2023/03/%E7%A7%91%E5%AD%A6%E4%B8%8A%E7%BD%91%E4%B8%8Evpn%E5%8A%9E%E5%85%AC%E7%9A%84%E5%AE%8C%E7%BE%8E%E7%BB%93%E5%90%88/) ```bash # Then on your host machine test it with curl: curl ifconfig.co/json -x socks5h://myuser:mypass@127.0.0.1:7777 ``` # docker版openVPN服务搭建 * [docker-compose版的参考文章](https://github.com/kylemanna/docker-openvpn/blob/master/docs/docker-compose.md) * [dockerhub地址](https://hub.docker.com/r/kylemanna/openvpn) # docker容器中部署系统相关文档 ## win系统 [Section titled “win系统”](#win系统) * 方式一: `docker-compose.yml`方式 * 方式二: `docker run`方式 ```shell docker run -it --rm -p 8006:8006 --device=/dev/kvm --cap-add NET_ADMIN --stop-timeout 120 dockurr/windows ``` * 相关文章 * [开源地址](https://github.com/dockur/windows) ## Linux中安装可视化虚拟机 [Section titled “Linux中安装可视化虚拟机”](#linux中安装可视化虚拟机) * 测试版 [参考文章](https://github.com/quickemu-project/quickemu/wiki/01-Installation) [参考文章](https://mp.weixin.qq.com/s/W99irRFN5geQ5wHr2i4y2w) ```bash # 没成功...可能系统不支持 yum install -y dnf sudo dnf install bash coreutils curl edk2-tools genisoimage grep jq mesa-demos pciutils procps python3 qemu sed socat spice-gtk-tools swtpm unzip usbutils util-linux xdg-user-dirs xrandr zsync git clone https://github.com/quickemu-project/quickemu.git ``` # SkyOffice文档记录 [SkyOffice GitHub](https://github.com/kevinshen56714/SkyOffice) ## 部署 [Section titled “部署”](#部署) ```bash docker compose up -d ``` # UpSnap使用记录 [代码仓库](https://github.com/seriousm4x/UpSnap.git) 局域网唤醒工具 ```bash cd UpSnap docker compose -f "docker-compose.yml" up -d --build ``` # wren ai [github地址](https://github.com/Canner/WrenAI) ## 安装 [Section titled “安装”](#安装) ```bash # macos curl -L https://github.com/Canner/WrenAI/releases/latest/download/wren-launcher-darwin.tar.gz | tar -xz && ./wren-launcher-darwin # config.yaml wget -O config.example.yaml https://raw.githubusercontent.com/canner/WrenAI/0.13.2/docker/config.example.yaml && \ mkdir -p ~/.wrenai && cp config.example.yaml ~/.wrenai/config.yaml # .env wget -O .env.example https://raw.githubusercontent.com/canner/WrenAI/0.13.2/docker/.env.example && \ mkdir -p ~/.wrenai && cp .env.example ~/.wrenai/.env ``` [自定义llm文档](https://docs.getwren.ai/oss/installation/custom_llm#running-wren-ai-with-your-custom-llm-embedder-or-document-store) > 先记录, 暂时不搞了, 配置太麻烦了 # 开发容器相关记录 ps: 在远程容器中进行开发,或者在本地开发在远程容器中运行和debug ## 在idea中使用 [Section titled “在idea中使用”](#在idea中使用) * docker compose配置调整 * 在modify option中勾选project-name可以把相同项目名的应用放到一个compose里去 * 生成的命令为`docker compose -f ./docker-compose.yml -p ma-compose up -d` * 使用—build选项:在运行docker-compose up命令时,添加—build选项可以确保每次都重新构建镜像。 * eg: `docker compose -f ./docker-compose.yml -p ma-compose up -d --build` ## dev container [Section titled “dev container”](#dev-container) * 解决域名无法解析的问题 * code /etc/resolv.conf ```bash nameserver 127.0.0.1 nameserver 127.0.0.11 # 以下两个配置来源于当前连接的WiFi nameserver 119.29.29.29 nameserver 223.5.5.5 ``` ## docker忽略文件的使用 [Section titled “docker忽略文件的使用”](#docker忽略文件的使用) * 文件名:\[.dockerignore]与Dockerfile文件同级 ```bash * !dist !wap.conf ``` ## devcontainer.json的使用 [Section titled “devcontainer.json的使用”](#devcontainerjson的使用) * 关于”SSH\_AUTH\_SOCK”配置使用记录[对应的devcontainer配置](./example/.devcontainer/devcontainer.json) * “SSH\_AUTH\_SOCK”: $SSH\_AUTH\_SOCK, // 这个配置不生效的话,看看是不是需要在`ssh config`文件(\~/.ssh/config)中配置`ForwardAgent yes`才行 # dockerfile文件相关记录 ## 开启ssh的centos发行版 [Section titled “开启ssh的centos发行版”](#开启ssh的centos发行版) * [参考文章](https://raw.githubusercontent.com/183461750/doc-record/main/materiel/ai/docker/%E5%BC%80%E5%90%AFssh%E7%9A%84centos%E5%8F%91%E8%A1%8C%E7%89%88%E7%9A%84Dockerfile.md) ```dockerfile # 使用官方 CentOS 基础镜像(PS: latest版拉取openssh-server依赖报错) FROM centos:centos7.9.2009 # 安装 SSH 服务 RUN yum install -y openssh-server # 生成 SSH 密钥 RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N '' RUN ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -N '' RUN ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N '' # 设置 root 密码 RUN echo "root:password" | chpasswd # 配置 SSH 服务 RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config RUN sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config # 暴露 SSH 端口 EXPOSE 22 # 启动 SSH 服务 CMD ["/usr/sbin/sshd", "-D"] ``` # tomcat部署war包相关文档 ## 缺少字体的问题 [Section titled “缺少字体的问题”](#缺少字体的问题) * [对应的Dockerfile](./web-api/has-font/Dockerfile) ```bash # 只需要在项目的docker部署文件Dockerfile里添加一行代码(在生成镜像需要外网) RUN apk add --update font-adobe-100dpi ttf-dejavu fontconfig ``` # nginx相关文档 * [参考文章](https://hub.docker.com/_/nginx) # nginx配置记录 主要为了解决本地调用http请求导致跨域的问题 # nginx配置记录 主要为了解决本地调用http请求导致跨域的问题 # deploy ## deploy\_to\_docker.sh使用方式 [Section titled “deploy\_to\_docker.sh使用方式”](#deploy_to_dockersh使用方式) ```bash # 需要打包并部署指定服务 sh deploy_to_docker.sh package web # 无需打包仅部署指定服务 sh deploy_to_docker.sh web # 部署所有服务 sh deploy_to_docker.sh ``` ## 拉取位置 [Section titled “拉取位置”](#拉取位置) * 放到和项目同级目录,所有需要部署的项目都放到同级目录 ## docker compose 命令 [Section titled “docker compose 命令”](#docker-compose-命令) ```bash # 部署某个服务 docker compose -f ./docker-compose.yml -p ma-compose up -d --build $service_name # 重启某个服务 docker compose -p ma-compose restart nginx ``` # 远程调试 主要是为了本地不需要安转office等套件 ```dockerfile FROM registry.cn-guangzhou.aliyuncs.com/iuin/oraclejdk17:libreoffice-skywalking COPY build/libs/*.jar /data/app.jar ENV PORT=9880 ENV JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:2$PORT" ENV OFFICE_HOME="/usr/lib/libreoffice" ENTRYPOINT ["java","-Xms512m","-Xmx4096m","-XX:+UseG1GC","-jar","-Duser.language=zh","-Dserver.port=$PORT","-Djdk.attach.allowAttachSelf=true","-Dnet.bytebuddy.agent.attacher.dump=/tmp/arthas.dump","/data/app.jar"] EXPOSE $PORT 1$PORT 2$PORT ``` > PS: idea配置中添加容器名, 端口映射和gradle构建(clean bootJar) 然后, idea再添加个远程调试配置, 设置IP, 端口以及module即可 其他问题: 有可能需要在build.gradle中添加mainClass配置 # cloudflare tunnel使用记录 [官方下载文档](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/) ## 安装 [Section titled “安装”](#安装) ```bash # macos brew install cloudflared ``` > PS: 这种方式暂时不搞了, 国外的渠道, 延迟估计不小 做了, 用作备选方案 ## 配置 [Section titled “配置”](#配置) ![docker3](https://github.com/iuin8/doc-record/blob/main/docs/docker/dev_utls/dev-container/remote-ssh/cloudflare-tunnel/imgs/cloudflare-tunnel-ssh.png?raw=true) > PS: 创建隧道的时候, 填完子域名, 点击保存后, 会自动创建DNS记录, 所以有的时候, 不小心把DNS删了的话, 会导致隧道连接失败, 这时就需要重新创建新的隧道让它重新创建DNS记录了 # cpolar+ssh+docker打通受限网络 目的: 解决客户环境只能使用jumpserver连接的限制 通过启动一个docker容器即可解决 * 查看日志 ```bash journalctl -u cpolar-wrapper.service ``` # v3 version ## 待办 [Section titled “待办”](#待办) * 隧道名称, 添加到环境变量中, 可自定义(暂时不需要了) * 其他高级操作 * `cpolar.yml`文件通过挂载的方式进行自定义(挂载配置文件即可) * docker-compose.yml结合export命令使用, 这样token就不容易看到了 ## 使用方式 [Section titled “使用方式”](#使用方式) ```bash # docker-compose.yml配置内容 services: cpolar-ssh: image: registry.cn-hangzhou.aliyuncs.com/iuin/cpolar-ssh:latest environment: - TZ="Asia/Shanghai" - CPOLAR_AUTH_TOKEN=${CPOLAR_AUTH_TOKEN} - CPOLAR_CONTANER_SSH_NAME=contaner_ssh_1 restart: unless-stopped privileged: true export CPOLAR_AUTH_TOKEN=xxx docker compose up -d # 进cpolar官网页面查看域名 # ~/.ssh/config配置 Host cpolar.internet.company HostName 3.tcp.cpolar.top User root Port 11968 IdentityFile ~/.ssh/id_ed25519_1 # ForwardAgent yes # 让远程机器使用本地的代理(可以访问google了) # RemoteForward 127.0.0.1:9090 192.168.0.218:9090 # PasswordAuthentication password # 通过ssh远程连接容器 ssh cpolar.internet.company ``` # frp+ssh+docker打通受限网络 目的: 解决客户环境只能使用jumpserver连接的限制 通过启动一个docker容器即可解决 ## 安装包获取 [Section titled “安装包获取”](#安装包获取) frp 0.62.1(linux/amd64)官方下载地址: * * 发行版列表: ```bash wget https://github.com/fatedier/frp/releases/download/v0.62.1/frp_0.62.1_linux_amd64.tar.gz tar -xzf frp_0.62.1_linux_amd64.tar.gz && mv frp_0.62.1_linux_amd64 frp ``` 完整性校验(MD5):`1e8e703edfa96e915d158b9f3767da3a` 容器内构建时,若未随镜像保留安装包,可将 `COPY` 指令替换为直接下载: ```dockerfile RUN wget -O ./frp_0.62.1_linux_amd64.tar.gz \ https://github.com/fatedier/frp/releases/download/v0.62.1/frp_0.62.1_linux_amd64.tar.gz && \ tar -xzf ./frp_0.62.1_linux_amd64.tar.gz && \ mv frp_0.62.1_linux_amd64 frp ``` * 查看日志 ```bash journalctl -u frpc.service ``` # frp server使用记录 [官网文档(SSH Tunnel Gateway)](https://gofrp.org/zh-cn/docs/features/common/ssh/) ```bash ``` # frps使用记录 在v2的基础上, 加上了server绑定端口的环境变量配置功能 ## 快速开始 [Section titled “快速开始”](#快速开始) [docker-compose.yml链接](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/dev-container/remote-ssh/frp/server/v3/simple/docker-compose.yml) ```bash # 启动即可 docker-compose up -d ``` * 配置说明 `auth_token_line=auth.token = "xxx"` # 认证token, 用于客户端连接时验证身份, 调整个合适的值即可 `bindPort=18000` # 服务端口, 用于客户端连接时指定的端口, 调整个合适的值即可 # frps使用记录 在v3的基础上, 加上了`tcpmuxHTTPConnectPort`参数, 用于一个端口支持多个ssh连接 ## 快速开始 [Section titled “快速开始”](#快速开始) [v3 doc](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/dev-container/remote-ssh/frp/server/v3/doc.md) [network\_mode(目前使用的方式)](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/dev-container/remote-ssh/frp/server/v4/simple/network_mode/docker-compose.yml) ```bash # 启动即可 docker-compose up -d ``` * 配置说明 `7000`端口 # 服务端口, 用于客户端连接时指定的端口, 调整个合适的值即可 `5002`端口 # 用于多个ssh连接的端口, 调整个合适的值即可 `auth_token` # 认证token, 用于客户端连接时验证身份, 调整个合适的值即可 # frp内网穿透 [GitHub地址](https://github.com/fatedier/frp) ## 快速开始 [Section titled “快速开始”](#快速开始) [服务端docker-compose配置](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/dev-container/remote-ssh/frp/server/simple/docker-compose.yml) [客户端docker-compose配置](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/dev-container/remote-ssh/frp/simple/docker-compose.yml) 分别使用以下命令启动 ```bash docker compose up -d ``` ssh连接 ```bash ssh -oPort=6000 root@116.1.1.1 ``` # frp+ssh+docker打通受限网络 解压frp压缩文件, 将里面的frpc文件重命名为jumpboxc, 给Dockerfile中的copy命令使用 ## 使用方式 [Section titled “使用方式”](#使用方式) ```yaml services: dev-jumpbox: image: registry.cn-hangzhou.aliyuncs.com/iuin/dev-jumpbox:tcpmux-v6.1.1 container_name: dev-jumpbox environment: TZ: "Asia/Shanghai" serverAddr: '"183.11.11.11"' serverPort: 11100 auth_token: '"xx-jumpbox-ssh"' client_name: '"container.prod.xxx.customer"' customDomains: '["container.prod.xxx.customer"]' extra_hosts: - "prod.xxx.customer:host-gateway" restart: unless-stopped ``` 需要调整的字段 * serverAddr: 服务端地址 * serverPort: 服务端口 * auth\_token: 认证token * client\_name: 客户端名称 * customDomains: 自定义域名 * extra\_hosts: 额外自定义容器hosts配置(可选) # frp使用记录 * [服务端docker-compose.yml](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/dev-container/remote-ssh/frp/server/simple/docker-compose.yml) * [客户端docker-compose.yml](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/dev-container/remote-ssh/frp/v3/simple/docker-compose.yml) v3版, 这个版本只能通过密钥登录, 可以将将authorized\_keys文件挂载到宿主机中, 就不用进容器配置密钥了 # frp * 版本计划 * —cap-add=NET\_ADMIN * 通过这个配置缩小容器权限(只给网络相关权限) * 没有用这个方案了(改为使用tini作为容器初始化管理工具, 去替代systemd) ## 快速开始 [Section titled “快速开始”](#快速开始) [客户端docker-compose.yml](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/dev-container/remote-ssh/frp/v4/simple/docker-compose.yml) ```bash docker compose up -d # 或者 docker-compose up -d ``` ## 更新密钥 [Section titled “更新密钥”](#更新密钥) ```bash # 将本地电脑生成的ssh公钥上传到开发跳板盒子中(~/.ssh/id_ed25519.pub) docker exec -it dev-jumpbox bash -c "echo 'ssh-ed25519 xxx xxx' > /root/.ssh/authorized_keys" ``` ## 环境变量 [Section titled “环境变量”](#环境变量) ```bash # 宿主机执行 export serverAddr='"129.204.8.8"' # docker-compose.yml对应配置改为 # environment: # TZ: "Asia/Shanghai" # serverAddr: ${serverAddr} ``` ## 域名配置 [Section titled “域名配置”](#域名配置) ```bash # dev-jumpbox容器的hosts配置(/etc/hosts) # 通过docker compose中配置 # extra_hosts: # # - "host.docker.internal:host-gateway" # - "me.host:host-gateway" # ssh config(~/.ssh/config) # 这里的HostName之所以使用本地hosts配置而不是IP的原因是, 我们需要在多个内网服务器中使用这个方法的话, 本地hnown_hosts会冲突(~/.ssh/known_hosts) # Host frp.fa.internet.company # # HostName host.docker.internal # HostName me.host # User root # IdentityFile ~/.ssh/id_ed25519_iu # ProxyJump frp.container6002.fa.internet.company # ForwardAgent yes ``` # frp * 版本计划 * 将Ubuntu基础容器换成Debian ## 快速开始 [Section titled “快速开始”](#快速开始) [参考v4版本doc](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/dev-container/remote-ssh/frp/v4/doc.md) # frpc使用记录 ## 快速开始 [Section titled “快速开始”](#快速开始) [docker-compose.yml链接](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/dev-container/remote-ssh/frp/v6/simple/docker-compose.yml) ```bash # 启动即可 docker-compose up -d ``` * 配置说明 `auth_token_line=auth.token = "xxx"` # 认证token, 用于客户端连接时验证身份, 调整个合适的值即可 `serverAddr` # 服务端地址, 用于客户端连接时指定的地址, 调整个合适的值即可 `server_port=18000` # 服务端口, 用于客户端连接时指定的端口, 调整个合适的值即可 `client_name=frpc` # 客户端名称, 用于客户端连接时指定的名称, 调整个合适的值即可(同一frps服务端, 可以有多个frpc客户端连接, 只要名称不冲突即可) `remotePort_proxies_tcp_line: remotePort=12222` # 远程端口, 用于客户端连接时指定的端口, 调整个合适的值即可 > PS: 基本上服务端固定的情况下, 只需要把第一个client的docker-compose文件复制出来, 修改`client_name`, `remotePort_proxies_tcp_line`即可 * 已经有一个frpc客户端连接的情况下, 如何添加新的frpc客户端(以及获取ssh密钥) ```bash # 复制一份docker-compose.yml文件, 修改client_name和remotePort_proxies_tcp_line即可(docker-compose.yml文件中有注释说明) # 然后, ssh连接需要获取密钥, 执行以下命令获取ssh的私钥 docker exec -it dev-jumpbox cat ~/.ssh/id_ed25519_frp # 需要将这个私钥配置到本地的~/.ssh/id_ed25519_frp中, 并调整权限 chmod 600 ~/.ssh/id_ed25519_frp ``` # frp+ssh+docker打通受限网络 解压frp压缩文件, 将里面的frpc文件重命名为jumpboxc, 给Dockerfile中的copy命令使用 # ssh+docker打通受限网络 [官网文档(SSH Tunnel Gateway)](https://gofrp.org/zh-cn/docs/features/common/ssh/) * 测试版(有点问题) ```bash # 不挂载外部文件的情况下, 在容器中执行以下命令 # 这个是让我们本地电脑能够使用ssh连接容器的ssh公钥(示例由本地机器生成即可`id_ed25519_iu`) echo 'ssh-ed25519 xxx iu' > /root/.ssh/authorized_keys # 这个是容器通过ssh -R访问frps服务端,实现内网穿透所需要的密钥(示例由服务端生成, 客户端生成也可以(客户端生成就需要将)) cat > /root/.ssh/id_ed25519_frp << EOF -----BEGIN OPENSSH PRIVATE KEY----- xxxxxx xxx -----END OPENSSH PRIVATE KEY----- EOF ``` # frp+ssh+docker打通受限网络(client) * [官方文档](https://gofrp.org/zh-cn/docs/overview/) * [frp\_0.65.0\_linux\_amd64.tar.gz](https://github.com/fatedier/frp/releases/download/v0.65.0/frp_0.65.0_linux_amd64.tar.gz) ```bash # 下载frp_0.66.0_linux_amd64.tar.gz wget https://github.com/fatedier/frp/releases/download/v0.66.0/frp_0.66.0_linux_amd64.tar.gz ``` ## 后续优化 [Section titled “后续优化”](#后续优化) ```bash # 服务端配置 # sudo nano /etc/ssh/sshd_config # 每60秒向客户端发送心跳 ClientAliveInterval 60 # 允许5次心跳失败(总共300秒) ClientAliveCountMax 5 # 启用TCP保活 TCPKeepAlive yes ``` # frp+ssh+docker打通受限网络(client) * [官方文档](https://gofrp.org/zh-cn/docs/overview/) * [frp\_0.65.0\_linux\_amd64.tar.gz](https://github.com/fatedier/frp/releases/download/v0.65.0/frp_0.65.0_linux_amd64.tar.gz) ## 配置说明 [Section titled “配置说明”](#配置说明) 必须配置项: * serverAddr * serverPort * auth.token * proxies.name * proxies.customDomains ```json { // 必须参数 "serverAddr": "55.44.33.33", // 必须参数 "serverPort": 18000, "auth": { "method": "token", // 必须参数 "token": "frps-ssh" }, "loginFailExit": false, "transport": { "heartbeatInterval": 25, "heartbeatTimeout": 120, "poolCount": 10, "tcpMux": true }, "proxies": [ { // 必须参数 "name": "frpc-ssh-fa", "type": "tcpmux", "multiplexer": "httpconnect", // 必须参数 "customDomains": ["fa.intranet.company"], "localIP": "127.0.0.1", "localPort": 22 } ] } ``` ## 后续优化 [Section titled “后续优化”](#后续优化) ```bash # 服务端配置 # sudo nano /etc/ssh/sshd_config # 每60秒向客户端发送心跳 ClientAliveInterval 60 # 允许5次心跳失败(总共300秒) ClientAliveCountMax 5 # 启用TCP保活 TCPKeepAlive yes ``` # 自定义域名版 ## 需要改动的config字段 [Section titled “需要改动的config字段”](#需要改动的config字段) * serverAddr * serverPort * auth.token * proxies.name * proxies.customDomains # K8s Jumpbox 容器 SSH 配置说明 > authorized\_keys挂载后权限不对导致ssh忽略authorized\_keys的问题 ## 一、背景 [Section titled “一、背景”](#一背景) 容器内运行 sshd 服务,需通过 Secret 注入 `authorized_keys` 实现公钥登录,同时容器自身会生成 SSH 私钥,要求 `/root/.ssh/` 可写。 ## 二、挂载方案 [Section titled “二、挂载方案”](#二挂载方案) ### 1. emptyDir 临时目录(提供可写的 .ssh 目录) [Section titled “1. emptyDir 临时目录(提供可写的 .ssh 目录)”](#1-emptydir-临时目录提供可写的-ssh-目录) * **作用**:容器生成的私钥、known\_hosts 等文件需要写入 `/root/.ssh/` * **类型**:EmptyDir * **挂载路径**:`/root/.ssh/` * **权限**:读写 ### 2. Secret 挂载 authorized\_keys(单文件 subPath 方式) [Section titled “2. Secret 挂载 authorized\_keys(单文件 subPath 方式)”](#2-secret-挂载-authorized_keys单文件-subpath-方式) * **作用**:注入公钥认证文件 * **类型**:Secret(jumpbox) * **Key**:`authorized_keys` * **挂载路径**:`/tmp/authorized_keys` * **subPath**:`authorized_keys` * **权限**:只读 > 不直接挂载到 `/root/.ssh/authorized_keys`,避免 Secret 只读导致无法 chmod。 ## 三、权限修正(关键) [Section titled “三、权限修正(关键)”](#三权限修正关键) ### 问题 [Section titled “问题”](#问题) * Secret 挂载文件默认 `644`,sshd 要求 `authorized_keys` 必须 `600` * emptyDir 目录默认 `777`,sshd 要求 `.ssh` 目录必须 `700` * Secret 只读,容器内无法直接 `chmod` ### 解决方案:postStart 生命周期钩子 [Section titled “解决方案:postStart 生命周期钩子”](#解决方案poststart-生命周期钩子) ```plaintext containers: - name: dev-jumpbox image: 'registry.cn-hangzhou.aliyuncs.com/iuin/jumpboxc:v0.66.0_v6.3.1' # ... 你原来的 env 等配置 ... # 👇 加这段 lifecycle: postStart: exec: command: - /bin/sh - -c - | cp /tmp/authorized_keys /root/.ssh/authorized_keys chmod 700 /root/.ssh chmod 600 /root/.ssh/authorized_keys ``` ## 四、最终效果 [Section titled “四、最终效果”](#四最终效果) ```plaintext /root/.ssh/ drwx------ (700) ├── authorized_keys -rw------- (600) ← 从 Secret 复制 ├── id_ed25519_container -rw------- (600) ← 容器生成 └── id_ed25519_container.pub -rw-r--r-- (644) ``` ## 五、核心 YAML 片段 [Section titled “五、核心 YAML 片段”](#五核心-yaml-片段) ```yaml # volumeMounts volumeMounts: - mountPath: /root/.ssh/ name: ssh-dir - mountPath: /tmp/authorized_keys name: ssh-keys readOnly: true subPath: authorized_keys # volumes volumes: - name: ssh-dir emptyDir: {} - name: ssh-keys secret: secretName: jumpbox items: - key: authorized_keys path: authorized_keys ``` ## 参考链接 [Section titled “参考链接”](#参考链接) * [node-debug](https://github.com/iuin8/doc-record/blob/main/docs/kubernetes/docs/node-debug/node-debug.md) # frp+ssh+docker打通受限网络(server) * [官方文档](https://gofrp.org/zh-cn/docs/overview/) * [frp\_0.66.0\_linux\_amd64.tar.gz](https://github.com/fatedier/frp/releases/download/v0.66.0/frp_0.66.0_linux_amd64.tar.gz) ```bash # 下载frp_0.66.0_linux_amd64.tar.gz wget https://github.com/fatedier/frp/releases/download/v0.66.0/frp_0.66.0_linux_amd64.tar.gz ``` # frp+ssh+docker打通受限网络(server) * [官方文档](https://gofrp.org/zh-cn/docs/overview/) * [frp\_0.65.0\_linux\_amd64.tar.gz](https://github.com/fatedier/frp/releases/download/v0.65.0/frp_0.65.0_linux_amd64.tar.gz) # headscale ## 相关部署配置 [Section titled “相关部署配置”](#相关部署配置) * [服务端doc](https://github.com/183461750/doc-record/blob/main/docs/network/headscale/local/demo2/doc.md) * [服务端docker-compose.yml](https://github.com/183461750/doc-record/blob/main/docs/network/headscale/local/demo2/docker-compose.yml) * [客户端docker-compose.yml](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/dev-container/remote-ssh/tailscale/simple/docker-compose.yml) ## 使用 [Section titled “使用”](#使用) * ssh连接 \~/.ssh/config ```bash Host tailscale-ssh.example.com HostName tailscale-ssh.example.com User root IdentityFile ~/.ssh/id_ed25519 ForwardAgent yes # PasswordAuthentication password ``` ```bash # 可以通过用户名加headscale中配置的base_domain去访问其他节点的服务 # `hostname.base_domain` (e.g., _myhost.example.com_). ssh tailscale-ssh.example.com ``` # git相关使用 ## git升级 [Section titled “git升级”](#git升级) * [相关链接](https://packages.endpointdev.com/) * [相关链接](https://www.endpointdev.com/blog/2021/12/installing-git-2-on-centos-7/#:~:text=lks%20you%20step%20b) ```bash # 检查git版本 git --version # git version 1.8.3.1 # 查看git安装位置 which git # /usr/bin/git # 确保它是使用 yum 从 RPM 安装 rpm -qi git # Name : git # Version : 1.8.3.1 # Release : 23.el7_8 # Source RPM : git-1.8.3.1-23.el7_8.src.rpm # Build Date : Thu 28 May 2020 08:37:56 PM UTC # Build Host : x86-02.bsys.centos.org # Packager : CentOS BuildSystem # Vendor : CentOS # 添加 End Point Yum 存储库 sudo yum install -y https://packages.endpointdev.com/rhel/7/os/x86_64/endpoint-repo.x86_64.rpm # 安装或升级 git sudo yum install -y git # 如果您没有看到可用的新 git 版本,则可能需要使用以下命令清除 Yum 缓存: sudo yum clean all ## 问题 # 如果安装不成功可尝试先卸载git(也可能不是yum安装的git,就需要其他方式卸载了) sudo yum remove git sudo yum remove git-* ``` # 在idea中使用远程服务器中的docker进行debug远程容器中的Java程序 > 好处: 使用远程docker容器减轻本地环境的压力, 减少在本地环境安装Java程序需要依赖的一些乱七八糟的工具(例如LibreOffice) ## 使用说明 [Section titled “使用说明”](#使用说明) * 准备远程docker服务器 ```bash # 编辑文件`~/.ssh/config` Host fa.intranet.company HostName 10.0.11.111 User root IdentityFile ~/.ssh/id_ed25519 ``` ![docker1](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/remote_debug/imgs/docker1.png?raw=true) ![docker2](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/remote_debug/imgs/docker2.png?raw=true) ![docker3](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/remote_debug/imgs/docker3.png?raw=true) * 编写Dockerfile [参考文件地址](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/remote_debug/Dockerfile_local) * idea配置 先点run自动生成基础配置 ![run](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/remote_debug/imgs/run.png?raw=true) 然后点edit配置自动构建jar包后在启动docker容器 ![edit1](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/remote_debug/imgs/edit1.png?raw=true) ![edit2](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/remote_debug/imgs/edit2.png?raw=true) 这时候就处理好了运行相关的配置,点击运行就可以在Docker中调试Java程序了。 * 添加debug配置 ![debug1](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/remote_debug/imgs/debug1.png?raw=true) ![debug2](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/remote_debug/imgs/debug2.png?raw=true) ![debug3](https://github.com/183461750/doc-record/blob/main/docs/docker/dev_utls/remote_debug/imgs/debug3.png?raw=true) 这样就可以在idea中远程docker容器中的Java程序了。 # 记录 ## 开始使用 [Section titled “开始使用”](#开始使用) ```shell bash exec.sh ``` # start-nocobase 帮助文档 快速部署一个 nocobase 函数到阿里云函数计算 ## 前期准备 [Section titled “前期准备”](#前期准备) 使用该项目,推荐您拥有以下的产品权限 / 策略: | | | - | | 服务/业务 | 函数计算 | | ----- | ---------------------------------------------------- | | 权限/策略 | AliyunFCFullAccess AliyunContainerRegistryFullAccess | # 代码 & 预览 [Section titled “代码 & 预览”](#代码--预览) * [:smiley\_cat: 源代码](https://github.com/183461750/nocobase) ## 部署 & 体验 [Section titled “部署 & 体验”](#部署--体验) * :fire: 通过 [Serverless 应用中心](https://fcnext.console.aliyun.com/applications/create?template=start-fc-custom-container-websocket-nodejs14) , [![Deploy with Severless Devs](https://img.alicdn.com/imgextra/i1/O1CN01w5RFbX1v45s8TIXPz_!!6000000006118-55-tps-95-28.svg)](https://fcnext.console.aliyun.com/applications/create?template=start-fc-custom-container-websocket-nodejs14) 该应用。 - 通过 [Serverless Devs Cli](https://www.serverless-devs.com/serverless-devs/install) 进行部署: * [安装 Serverless Devs Cli 开发者工具](https://www.serverless-devs.com/serverless-devs/install) ,并进行[授权信息配置](https://www.serverless-devs.com/fc/config) ; * 初始化项目:`s init start-nocobase -d start-nocobase` * 进入项目,并进行项目部署:`cd start-nocobase && s deploy -y` # 应用详情 [Section titled “应用详情”](#应用详情) 本应用仅作为学习和参考使用,您可以基于本项目进行二次开发和完善,实现自己的业务逻辑 # 使用记录 ## 发布到Serverless Registry [Section titled “发布到Serverless Registry”](#发布到serverless-registry) ```shell # 登录 s cli registry login # 发布 s cli registry publish ``` ## 从Serverless Registry中拉取项目 [Section titled “从Serverless Registry中拉取项目”](#从serverless-registry中拉取项目) ```shell # 初始化项目 s init start-nocobase -d start-nocobase # 进入项目,并进行项目部署 cd start-nocobase && s deploy -y ``` # version * 兼容新版本 # 记录 ## 版本说明 [Section titled “版本说明”](#版本说明) * 将sqlite数据存储到nas中 ```yaml # 部分配置 services: nocobaseService: component: fc actions: # 自定义执行逻辑,关于actions 的使用,可以参考:https://www.serverless-devs.com/serverless-devs/yaml#行为描述 post-deploy: # 在deploy之后运行 - component: fc nas upload -ro /app/nocobase/storage/db /mnt/auto/nocobase/storage/db ... ``` ## 开始使用 [Section titled “开始使用”](#开始使用) ```shell bash setup.sh # 搞个git仓库将v2目录下的文件上传到git上 # 在FC中创建个应用,再创建环境时勾选允许访问vps和nas ``` # 记录 ## 安装 [Section titled “安装”](#安装) ```shell sudo yarn global add @serverless-devs/s # or curl -o- -L http://cli.so/install.sh | bash # 查看版本 sudo s -v ``` ## 配置 [Section titled “配置”](#配置) ```shell s config add # or s config add --AccessKeyID LTAI4G4cwJkK4Rza6xd9**** --AccessKeySecret eCc0GxSpzfq1DVspnqqd6nmYNN**** --AccountID 188077086902**** --access *** # or s config add --AccessKeyID ${{secrets.AccessKeyID}} --AccessKeySecret ${{secrets.AccessKeySecret}} -a default -f ``` ## 部署 [Section titled “部署”](#部署) ```shell s deploy ``` # x11docker ```bash curl -fsSL https://raw.githubusercontent.com/mviereck/x11docker/master/x11docker | bash -s -- --update ``` # 阿里云相关记录 ## 云效 [Section titled “云效”](#云效) * [云效-通用制品仓库地址](https://packages.aliyun.com/generic) — 其中maven和npm的仓库也在这个页面 ## 容器镜像服务 [Section titled “容器镜像服务”](#容器镜像服务) * [容器镜像服务地址](https://cr.console.aliyun.com/cn-zhangjiakou/instances) # 使用记录 * [conda官网](https://docs.conda.io/en/latest/index.html) ## 安装 [Section titled “安装”](#安装) ```shell # 下载安装脚本 wget https://repo.anaconda.com/miniconda/Miniconda3-py38_23.1.0-1-Linux-aarch64.sh # 执行脚本安装 bash bash Miniconda3-py38_23.1.0-1-Linux-aarch64.sh # 最后,重新打开终端执行下面的命令验证是否安装成功 conda list # 更新 conda update conda ``` ## 创建环境 [Section titled “创建环境”](#创建环境) ```shell conda create -n python3.4 python=3.4 ## 示例 `bash # create and activate the virtual environment conda create --name animated_drawings python=3.8.13 conda activate animated_drawings # clone AnimatedDrawings and use pip to install git clone https://github.com/facebookresearch/AnimatedDrawings.git cd AnimatedDrawings pip install -e . ` ``` # docker容器记录 启动busybox ```bash # 通过指定网络启动 docker run -it --rm --network middleware busybox ``` # docker笔记 ## 安装docker [Section titled “安装docker”](#安装docker) [LinuxMirrors](https://github.com/SuperManito/LinuxMirrors) ```shell # 一键安装 bash <(curl -sSL https://linuxmirrors.cn/docker.sh) # 目前使用的方式(常规) sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo sudo yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin # 开机自启 systemctl enable docker # 启动docker systemctl start docker # 配置国内镜像源(阿里镜像源) sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": [ "https://ipl2fa8y.mirror.aliyuncs.com" ] } EOF sudo systemctl daemon-reload sudo systemctl restart docker ``` ```shell # 目前使用的方式(网络不通了) sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install -y docker-ce docker-ce-cli containerd.io ``` ```shell # 使用官方安装脚本自动安装 curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun # 使用国内 daocloud 一键安装命令 curl -sSL https://get.daocloud.io/docker | sh ``` ## 卸载 [Section titled “卸载”](#卸载) ```bash apt-get remove -y docker* containerd.io runc && apt-get autoremove yum remove -y docker* containerd.io podman* runc ``` ## 设置docker开机自启 [Section titled “设置docker开机自启”](#设置docker开机自启) ```shell systemctl enable docker ``` ## 配置docker镜像源 [Section titled “配置docker镜像源”](#配置docker镜像源) ```shell sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["https://ipl2fa8y.mirror.aliyuncs.com"] } EOF sudo systemctl daemon-reload sudo systemctl restart docker ``` ```shell # docker镜像源 https://docker.mirrors.ustc.edu.cn ``` ## 部署 [Section titled “部署”](#部署) ```shell # 对性能要求高 用 --net=host(对应docker-stack.yml文件下的(service.serviceName.network_mode=host)network_mode: "host") , 不用-p # 参考网上的测试:上次对对使用Docker的两台Redis做压力测试,A台使用-p,B台使用--net=host。但是发现A的效率只有B的1/3-2/3 ,这么大的性能影响,-p应该不适合生产环境吧?望大师们指教。谢谢。 ``` ## 删除空镜像 [Section titled “删除空镜像”](#删除空镜像) ```shell sudo docker images | awk '{if($2=="") print $3}' | xargs sudo docker rmi # 您需要先停止运行容器然后将其删除 docker stop $(docker ps -a -q) docker rm $(docker ps -a -q) # 对于图像,请尝试删除悬空图像 docker rmi $(docker images -f dangling=true -q) # 删除所有未被使用的镜像 docker image prune -a ``` ## 找镜像的地址 [Section titled “找镜像的地址”](#找镜像的地址) ## 修改宿主机的docker配置,让其可以远程访问 [Section titled “修改宿主机的docker配置,让其可以远程访问”](#修改宿主机的docker配置让其可以远程访问) ```shell # 默认,我们的linux的 docker ,IDEA 是不可以访问的,所以需要修改下配置,让我们的IDEA 可以访问 vi /lib/systemd/system/docker.service # 在 其中的ExecStart=后添加配置 > tip: 2375是为Docker开启的远程访问API的端口 -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock # 刷新配置,重启服务 systemctl daemon‐reload # 刷新服务 systemctl restart docker # 重新启动docker docker start registry # 启动registry ``` ## docker compose文件root用户权限控制 [Section titled “docker compose文件root用户权限控制”](#docker-compose文件root用户权限控制) ```yaml containers: - name: snake image: docker.io/kelysa/snake:lastest imagePullPolicy: Always securityContext: privileged: true capabilities: add: ["NET_ADMIN","NET_RAW"] # Linux capabilities # 在linux中,root权限被分割成一下29中能力: # # CAP_CHOWN:修改文件属主的权限 # # CAP_DAC_OVERRIDE:忽略文件的DAC访问限制 # # CAP_DAC_READ_SEARCH:忽略文件读及目录搜索的DAC访问限制 # # CAP_FOWNER:忽略文件属主ID必须和进程用户ID相匹配的限制 # # CAP_FSETID:允许设置文件的setuid位 # # CAP_KILL:允许对不属于自己的进程发送信号 # # CAP_SETGID:允许改变进程的组ID # # CAP_SETUID:允许改变进程的用户ID # # CAP_SETPCAP:允许向其他进程转移能力以及删除其他进程的能力 # # CAP_LINUX_IMMUTABLE:允许修改文件的IMMUTABLE和APPEND属性标志 # # CAP_NET_BIND_SERVICE:允许绑定到小于1024的端口 # # CAP_NET_BROADCAST:允许网络广播和多播访问 # # CAP_NET_ADMIN:允许执行网络管理任务 # # CAP_NET_RAW:允许使用原始套接字 # # CAP_IPC_LOCK:允许锁定共享内存片段 # # CAP_IPC_OWNER:忽略IPC所有权检查 # # CAP_SYS_MODULE:允许插入和删除内核模块 # # CAP_SYS_RAWIO:允许直接访问/devport,/dev/mem,/dev/kmem及原始块设备 # # CAP_SYS_CHROOT:允许使用chroot()系统调用 # # CAP_SYS_PTRACE:允许跟踪任何进程 # # CAP_SYS_PACCT:允许执行进程的BSD式审计 # # CAP_SYS_ADMIN:允许执行系统管理任务,如加载或卸载文件系统、设置磁盘配额等 # # CAP_SYS_BOOT:允许重新启动系统 # # CAP_SYS_NICE:允许提升优先级及设置其他进程的优先级 # # CAP_SYS_RESOURCE:忽略资源限制 # # CAP_SYS_TIME:允许改变系统时钟 # # CAP_SYS_TTY_CONFIG:允许配置TTY设备 # # CAP_MKNOD:允许使用mknod()系统调用 # # CAP_LEASE:允许修改文件锁的FL_LEASE标志 ``` ## docker compose文件资源权限控制 [Section titled “docker compose文件资源权限控制”](#docker-compose文件资源权限控制) ```yaml containers: security_opt: - apparmor:unconfined ``` ## 镜像仓库 [Section titled “镜像仓库”](#镜像仓库) ```shell # 地址https://cr.console.aliyun.com/cn-hangzhou/instance/credentials registry.cn-hangzhou.aliyuncs.com/fa registry.cn-hangzhou.aliyuncs.com ``` ## 查看docker容器 [Section titled “查看docker容器”](#查看docker容器) ```shell # 查询已死亡的docker容器 docker ps -aq -f status=dead # 查询已退出的docker容器 docker ps -aq -f status=exited ``` ## 查看磁盘占用 [Section titled “查看磁盘占用”](#查看磁盘占用) ```shell # linux命令 df -h # Docker 的内置 CLI 指令 docker system df # 查看详情 docker system df -v ``` ## 磁盘空间清理 [Section titled “磁盘空间清理”](#磁盘空间清理) * [参考文章](https://blog.csdn.net/longailk/article/details/122728982) ```shell ## 通过 Docker 内置的 CLI 指令docker system prune来进行自动空间清理。 # 该指令默认会清除所有如下资源: # 已停止的容器(container) # 未被任何容器所使用的卷(volume) # 未被任何容器所关联的网络(network) # 所有悬空镜像(image)。 # 使用这个命令查看帮助 docker system prune --help docker system prune -a # 删除无用的卷 docker volume prune # 删除无用的网络 docker network prune ## 手动清除 # 镜像清理 # 删除所有悬空镜像,不删除未使用镜像: docker rmi $(docker images -f "dangling=true" -q) # 删除所有未使用镜像和悬空镜像 docker rmi $(docker images -q) # 清理卷 # 删除所有未被容器引用的卷 docker volume rm $(docker volume ls -qf dangling=true) # 容器清理 # 删除所有已退出的容器: docker rm -v $(docker ps -aq -f status=exited) # 删除所有状态为dead的容器 docker rm -v $(docker ps -aq -f status=dead) # 删除孤立的容器 docker container prune ## 查找系统中的大文件【以上三步仍然不可以的时候执行】 # 查找指定目录下所有大于100M的所有文件 find /var/lib/docker/overlay2/ -type f -size +100M -print0 | xargs -0 du -h | sort -nr ## 对标准输入日志大小与数量进行限制 # 新建或修改/etc/docker/daemon.json,添加log-dirver和log-opts参数 vi /etc/docker/daemon.json { "log-driver":"json-file", "log-opts": {"max-size":"3m", "max-file":"1"} } # 重启docker的守护线程 systemctl daemon-reload systemctl restart docker ## 实在没办法,只有把/var目录下所有日志文件清空 for i in `find /var -name *.log*`;do >$i;done # 然后重启node节点,因为有些日志文件被占用,清空后空间仍然无法释放 ``` ## docker 工作根目录 [Section titled “docker 工作根目录”](#docker-工作根目录) * [参考文章](https://blog.csdn.net/weixin_32820767/article/details/81196250) ```shell ## 迁移 /var/lib/docker 目录。 # 停止docker服务。 systemctl stop docker # 创建新的docker目录,执行命令df -h,找一个大的磁盘。 我在 /home目录下面建了 /home/docker/lib目录,执行的命令是: mkdir -p /home/docker/lib # 迁移/var/lib/docker目录下面的文件到 /home/docker/lib: rsync -avz /var/lib/docker /home/docker/lib/ # 配置 /etc/systemd/system/docker.service.d/devicemapper.conf。查看 devicemapper.conf 是否存在。如果不存在,就新建。 sudo mkdir -p /etc/systemd/system/docker.service.d/ sudo vi /etc/systemd/system/docker.service.d/devicemapper.conf # 然后在 devicemapper.conf 写入:(同步的时候把父文件夹一并同步过来,实际上的目录应在 /home/docker/lib/docker ) [Service] ExecStart= ExecStart=/usr/bin/dockerd --graph=/home/docker/lib/docker # 重新加载 docker systemctl daemon-reload systemctl restart docker systemctl enable docker # 检查Docker 的根目录.它将被更改为 /home/docker/lib/docker # Docker Root Dir: /home/docker/lib/docker docker info # 再确认之前的镜像还在: docker images # 确定容器没问题后删除/var/lib/docker/目录中的文件。 # 改回去的方法: # 将4.5中:--graph=/home/docker/lib/docker改为--graph=/var/lib/docker # systemctl daemon-reload # systemctl restart docker # systemctl enable docker # ps:不建议改docker配置,可将/var/lib/docker迁移后重新挂载,比较保险。 # /var/lib/docker拷贝到目标目录中,可以直接把目标目录mount到/var/lib/docker里。修改/etc/fstab设置为开机自动挂载,这样docker的配置文件一点都不用动了 ``` ## 利用docker run —rm 命令实现使用宿主机中没有的命令 [Section titled “利用docker run —rm 命令实现使用宿主机中没有的命令”](#利用docker-run-rm-命令实现使用宿主机中没有的命令) * 使用容器中的jar命令解压jar包,并将解压内容输出到挂载在宿主机中的目录里 ```shell docker run -it --name java -v /www/temp/java:/www/temp/java openjdk:11-jdk-slim sh -c "cd /www/temp/java && jar -xvf /www/temp/java/mall-server.jar" ``` * 使用宿主机中没有的nmap命令来通过端口找IP ```shell # 在10.0.16.*范围内找开放了50000端口的IP,并将结果输出到宿主机的output.txt文件中 docker run --rm --name nmap securecodebox/nmap sh -c "nmap -p 50000 10.0.16.0/24" > output.txt # 直接筛选已开放指定端口的内容 docker run --rm --name nmap securecodebox/nmap sh -c "nmap -p 9200 10.7.7.0/24 | grep -C 5 open" # 以下为部分结果,状态为open则对应端口被开放(即10.0.16.27则是目标IP) " Nmap scan report for 10.0.16.26 Host is up (0.00065s latency). PORT STATE SERVICE 50000/tcp filtered ibm-db2 Nmap scan report for 10.0.16.27 Host is up (0.0017s latency). PORT STATE SERVICE 50000/tcp open ibm-db2 " ``` ## 下载、保存和加载镜像 [Section titled “下载、保存和加载镜像”](#下载保存和加载镜像) ```shell # 1. 下载 Docker 镜像 ## 使用 docker pull 命令来下载 Docker 镜像,例如: docker pull nginx:latest ## 以上命令将下载 Nginx 最新版本的镜像。 # 1. 保存 Docker 镜像 ## 使用 docker save 命令将 Docker 镜像保存为 tar 归档文件,例如: docker save nginx:latest > nginx_latest.tar ## 以上命令将保存 Nginx 最新版本的镜像为 nginx_latest.tar 文件。 # 1. 加载 Docker 镜像 ## 使用 docker load 命令将已保存的 Docker 镜像加载到本地镜像库中,例如: docker load < nginx_latest.tar ## 以上命令将加载 nginx_latest.tar 文件中的 Nginx 最新版本镜像到本地。加载完成后,可以通过 docker images 命令查看本地镜像库中是否存在该镜像。 ``` ## 本地docker命令无感远程控制服务器docker [Section titled “本地docker命令无感远程控制服务器docker”](#本地docker命令无感远程控制服务器docker) ```shell # 两种协议, 把这个配置添加到环境变量中, `~/.zshrc`和`~/.bash_profile` # 一种是tcp协议,需要先在服务器上开放2375端口,然后在本机上执行 # export DOCKER_HOST=tcp://127.0.0.1:2375 # 另一种是ssh协议,需要在本机上安装sshpass工具,然后在本机上执行(PS: AI写的, 不知道sshpass工具是啥, 我貌似没安装) export DOCKER_HOST=ssh://root@23-zq.internet.company ``` * 相关文章 * [通过ssh协议使本地docker无感控制远程docker](https://gitee.com/LFa/doc-record/raw/f0fe47892a0ac9c4ad0c5fa908f304d63f81130d/materiel/ai/docker/%E9%80%9A%E8%BF%87ssh%E5%8D%8F%E8%AE%AE%E4%BD%BF%E6%9C%AC%E5%9C%B0docker%E6%97%A0%E6%84%9F%E6%8E%A7%E5%88%B6%E8%BF%9C%E7%A8%8Bdocker.md) * [iuin\_config的ssh配置](https://gitee.com/LFa/doc/raw/efd164a538c1ee1b3780aa870b0dac06864f0313/workspace/me/conf/ssh/company/iuin_config) `23-zq.internet.company`这个host来源于这个配置文件 ## docker gid 查看命令 [Section titled “docker gid 查看命令”](#docker-gid-查看命令) [参考地址1](https://www.doubao.com/thread/w9e714164e14f12b9) [参考地址2](https://github.com/influxdata/sandbox/issues/79)(PS: 貌似没啥用的样子) ```bash stat -c '%g' /var/run/docker.sock ``` ## 启用Docker BuildKit [Section titled “启用Docker BuildKit”](#启用docker-buildkit) ```shell # 查看Docker版本及BuildKit支持状态 docker --version docker buildx version # 若输出包含"buildx"则支持BuildKit # 设置环境变量以启用BuildKit: export DOCKER_BUILDKIT=1 export COMPOSE_DOCKER_CLI_BUILD=1 # 永久启用(用户级配置) # 修改shell配置文件(如\~/.bashrc): echo "export DOCKER_BUILDKIT=1" >> \~/.bashrc source \~/.bashrc # 系统级默认启用 # 修改Docker守护进程配置: sudo tee /etc/docker/daemon.json < /usr/local/bin/docker-compose sudo curl -L https://github.com/docker/compose/releases/download/v2.11.2/docker-compose-linux-x86_64 > /usr/local/bin/docker-compose # 添加执行权限 chmod +x /usr/local/bin/docker-compose ``` * 使用包管理器安装 ```shell sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install -y docker-compose ``` * 使用python安装docker-compose * [参考文章](https://help.aliyun.com/zh/ecs/use-cases/deploy-and-use-docker-on-alibaba-cloud-linux-2-instances) ```shell # 重要: 仅Python 3及以上版本支持docker-compose,并请确保已安装pip。 pip3 install -U pip setuptools pip3 install docker-compose docker-compose --version ``` > 请注意,使用包管理器安装的方式可以确保安装的是官方支持的稳定版本。而使用pip安装的方式可能会安装最新版本,但在某些情况下可能会遇到依赖关系或兼容性问题。 ## 示例命令 [Section titled “示例命令”](#示例命令) ```bash docker compose -f ./docker-compose.yml -p project_name up -d --build service_name ``` # docker上下文相关记录 [参考文章](https://dockerdocs.cn/engine/context/working-with-contexts/) ## 创建上下文 [Section titled “创建上下文”](#创建上下文) ```bash docker context create unix-test \ --docker host=unix:///var/run/docker.sock # 使用k8s作为协调器(被遗弃了) docker context create k8s-test \ --default-stack-orchestrator=kubernetes \ --kubernetes config-file=/home/ubuntu/.kube/config \ --docker host=unix:///var/run/docker.sock ``` # 测试 ```bash docker context create k8s-test \ --default-stack-orchestrator=kubernetes \ --kubernetes config-file=~/.kube/config \ --docker host=ssh://root@23.internet.company ``` # docker内置DNS记录 * 相关文章 * [Docker DNS](https://www.hwchiu.com/docs/2023/kind-network) ```bash # 使用ps查询容器的 PID ps -ef | grep redis # 其中 ss 顯示了環境中 127.0.0.11 有監聽兩個 Port,分別對應 TCP 與 UDP 的 DNS 請求,而 iptables 則顯示的相關 DNAT 的規則 sudo nsenter -n -t ${pid} ss -tunlp sudo nsenter -n -t ${pid} iptables-save -t nat # 进入容器查看容器内的DNS记录`docker run -it --rm --network middleware busybox` nslookup redis ``` # docker相关报错记录 ## docker info 报warning [Section titled “docker info 报warning”](#docker-info-报warning) ```shell # WARNING: IPv4 forwarding is disabled. Networking will not work. # 解决办法: vi /etc/sysctl.conf # 或者 vi /usr/lib/sysctl.d/00-system.conf # 添加如下代码: net.ipv4.ip_forward=1 # 重启network服务 systemctl restart network # 查看是否修改成功 sysctl net.ipv4.ip_forward # 如果返回为“ net.ipv4.ip_forward = 1 ”则表示成功了 ``` ```shell # 执行 docker info 时出现警告 # WARNING: bridge-nf-call-iptables is disabled # WARNING: bridge-nf-call-ip6tables is disabled # 解决办法: vi /etc/sysctl.conf # 在文件里添加下面两行代码: net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 # 然后 ESC 退出后 :wq 保存,执行下面代码: sysctl -p # 再试一次 docker info 问题应该解决了 ``` ## 使用docker stack deploy 时遇到image could not be accessed on a registry to record its digest [Section titled “使用docker stack deploy 时遇到image could not be accessed on a registry to record its digest”](#使用docker-stack-deploy-时遇到image-could-not-be-accessed-on-a-registry-to-record-its-digest) * 首先说一下遇到的坑,当执行命令时,会在work节点上pull配置文件中指定好的镜像,如果是DockerHub中存在的镜像则无问题,如果是私有镜像,就算是登录了也无法获取 * 解决办法:在stack deploy后添加 —with-registry-auth即可 # docker镜像相关文档 ## 配置代理镜像源 [Section titled “配置代理镜像源”](#配置代理镜像源) ```bash vi /etc/docker/daemon.json ``` ```json { "registry-mirrors": [ "https://docker.1ms.run", "http://mirrors.ustc.edu.cn", "https://docker.xuanyuan.me" "https://[你的加速器ID].mirror.swr.myhuaweicloud.com", "https://[你的加速器ID].mirror.aliyuncs.com", "https://huecker.io", "https://docker.1panel.live" ] } ``` # docker-networks ## 创建网络 [Section titled “创建网络”](#创建网络) ```shell # 普通网络 docker network create -d bridge middleware # swarm docker network create -d overlay --attachable middleware docker network create --driver=overlay --gateway 192.168.1.1 --subnet 192.168.1.0/24 --attachable my_network ``` ## 使用host模式 [Section titled “使用host模式”](#使用host模式) ```shell docker run --net="host" docker-compose -f file.yml up # yml 文件中,在services:[serviceName]:network_mode: "host" docker stack up -c file.yml # yml 文件中 # services: # nginx: # networks: # hostnet: {} # networks: # hostnet: # external: true # name: host ``` # docker-swarm ## 创建Swarm集群 [Section titled “创建Swarm集群”](#创建swarm集群) ```shell docker swarm init --advertise-addr 192.168.31.43 # --advertise-addr参数表示其它swarm中的worker节点使用此ip地址与manager联系。 docker swarm init --advertise-addr enp0s8 # --advertise-addr 该参数也可使用网卡名 ``` ## 查询加入Swarm集群的命令 [Section titled “查询加入Swarm集群的命令”](#查询加入swarm集群的命令) ```shell docker swarm join-token manager ``` ## 离开Swarm集群 [Section titled “离开Swarm集群”](#离开swarm集群) ```shell docker swarm leave ``` ## 给node节点添加标签 [Section titled “给node节点添加标签”](#给node节点添加标签) ```shell # docker node update --label-add client=true docker node update --label-add func=nginx worker1 ``` ## 创建网络 [Section titled “创建网络”](#创建网络) * overlay网络 * [No route to host的问题](./problems/docker-swarm-networks.md#%E7%BD%91%E6%AE%B5%E5%86%B2%E7%AA%81%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88) ```shell docker network create middleware -d overlay --scope swarm # 指定子网范围(PS: 防止和宿主机IP冲突(error: No route to host)) docker swarm init --default-addr-pool 192.168.0.0/16 ``` ## 部署命令 [Section titled “部署命令”](#部署命令) ```shell docker stack up -c docker-compose.yml rmq ``` ## docker swarm 端口映射问题 [Section titled “docker swarm 端口映射问题”](#docker-swarm-端口映射问题) ```shell : ports: - target: 6379 published: 6379 protocol: tcp mode: host ``` ## docker swarm 端口开放 [Section titled “docker swarm 端口开放”](#docker-swarm-端口开放) ```shell # Before starting, verify its status: systemctl status firewalld # It should not be running, so start it: systemctl start firewalld # Then enable it so that it starts on boot: systemctl enable firewalld # Afterwards, reload the firewall: firewall-cmd --reload # Then restart Docker. systemctl restart docker ``` > ###### Note: If you make a mistake and need to remove an entry, type: > > [Section titled “Note: If you make a mistake and need to remove an entry, type:”](#note-if-you-make-a-mistake-and-need-to-remove-an-entry-type) > > firewall-cmd —remove-port=port-number/tcp —permanent. > > \######On the node that will be a Swarm manager, use the following commands to open the necessary ports: firewall-cmd —add-port=2376/tcp —permanent\ > firewall-cmd —add-port=2377/tcp —permanent\ > firewall-cmd —add-port=7946/tcp —permanent\ > firewall-cmd —add-port=7946/udp —permanent\ > firewall-cmd —add-port=4789/udp —permanent > > \######Then on each node that will function as a Swarm worker, execute the following commands: firewall-cmd —add-port=2376/tcp —permanent\ > firewall-cmd —add-port=7946/tcp —permanent\ > firewall-cmd —add-port=7946/udp —permanent\ > firewall-cmd —add-port=4789/udp —permanent ```shell # docker machine firewall-cmd --add-port=2376/tcp --permanent # manager firewall-cmd --add-port=2377/tcp --permanent # communication among nodes (container network discovery). firewall-cmd --add-port=7946/tcp --permanent firewall-cmd --add-port=7946/udp --permanent # overlay network traffic (container ingress networking). firewall-cmd --add-port=4789/udp --permanent # 2376 用于docker machine 在实体机,一般不需要。 ``` > docker swarm 端口开放[参考链接](https://www.digitalocean.com/community/tutorials/how-to-configure-the-linux-firewall-for-docker-swarm-on-centos-7) ```shell # xml开放端口 # 通过以下命令查找xml文件存放路径(这里查找的是系统存放路径) find / -name ssh.xml # 查找docker相关xml ls | grep docker # 如果有(docker-swarm.xml)则可直接开启它,可省去下面自己新建文件的过程 vi /etc/firewalld/services/docker.xml # 这个是用户存放路径,可能不在这个路径,可以通过上面那条命令查找路径 docker docker daemon for remote access # manager节点才需要 # 查看默认zone(一般是public) firewall-cmd --get-default-zone # 在zone中加入这个service firewall-cmd --zone=public --add-service=docker --permanent # 重新加载 firewall-cmd --reload # 详见linux.md 和 firewalld.md文件 ``` # dockerfile ## dockerfile的构建命令查看(以zk镜像为示例) [Section titled “dockerfile的构建命令查看(以zk镜像为示例)”](#dockerfile的构建命令查看以zk镜像为示例) ```shell # 查看构建过程的命令 docker history a10 # 可以查看到zk在使用dockerfile构建镜像时,设置了以下docker-entrypoint.sh文件中需要使用到的环境变量,相当于给了环境变量一个默认值,可在使用该镜像启动容器时修改 ``` ## docker-entrypoint.sh文件参考(来自zk容器) [Section titled “docker-entrypoint.sh文件参考(来自zk容器)”](#docker-entrypointsh文件参考来自zk容器) ```shell #!/bin/bash set -e # Allow the container to be started with `--user` if [[ "$1" = 'zkServer.sh' && "$(id -u)" = '0' ]]; then chown -R zookeeper "$ZOO_DATA_DIR" "$ZOO_DATA_LOG_DIR" "$ZOO_LOG_DIR" exec gosu zookeeper "$0" "$@" fi # Generate the config only if it doesn't exist if [[ ! -f "$ZOO_CONF_DIR/zoo.cfg" ]]; then CONFIG="$ZOO_CONF_DIR/zoo.cfg" { echo "dataDir=$ZOO_DATA_DIR" echo "dataLogDir=$ZOO_DATA_LOG_DIR" echo "tickTime=$ZOO_TICK_TIME" echo "initLimit=$ZOO_INIT_LIMIT" echo "syncLimit=$ZOO_SYNC_LIMIT" echo "autopurge.snapRetainCount=$ZOO_AUTOPURGE_SNAPRETAINCOUNT" echo "autopurge.purgeInterval=$ZOO_AUTOPURGE_PURGEINTERVAL" echo "maxClientCnxns=$ZOO_MAX_CLIENT_CNXNS" echo "standaloneEnabled=$ZOO_STANDALONE_ENABLED" echo "admin.enableServer=$ZOO_ADMINSERVER_ENABLED" } >> "$CONFIG" if [[ -z $ZOO_SERVERS ]]; then ZOO_SERVERS="server.1=localhost:2888:3888;2181" fi for server in $ZOO_SERVERS; do echo "$server" >> "$CONFIG" done if [[ -n $ZOO_4LW_COMMANDS_WHITELIST ]]; then echo "4lw.commands.whitelist=$ZOO_4LW_COMMANDS_WHITELIST" >> "$CONFIG" fi for cfg_extra_entry in $ZOO_CFG_EXTRA; do echo "$cfg_extra_entry" >> "$CONFIG" done fi # Write myid only if it doesn't exist if [[ ! -f "$ZOO_DATA_DIR/myid" ]]; then echo "${ZOO_MY_ID:-1}" > "$ZOO_DATA_DIR/myid" fi exec "$@" ``` # yum安装erlang ```shell #卸载erlang yum -y remove erlang-* #按官网的提示操作 #使用存储库安装 wget https://packages.erlang-solutions.com/erlang-solutions-2.0-1.noarch.rpm rpm -Uvh erlang-solutions-2.0-1.noarch.rpm #手动添加存储库条目 rpm --import https://packages.erlang-solutions.com/rpm/erlang_solutions.asc # 清楚原有yum缓存 yum clean all # 生成缓存 yum makecache # 查看配置好的yum源是否正常 yum repolist #查看erlang可安装版本 yum list | grep erlang yum list erlang --showduplicates | sort -r #安装erlang,也可安装指定版本 yum install -y erlang #安装erlang指定版本 yum install erlang-24.0-1.el7.aarch64 ``` # firewalld防火墙相关配置 * [阿里云开发者社区用户文章参考](https://developer.aliyun.com/article/292603) ```shell # 安装 yum install firewalld # 在开机时启用一个服务 systemctl enable firewalld.service # 在开机时禁用一个服务 systemctl disable firewalld.service # 查看服务是否开机启动 systemctl is-enabled firewalld.service # 使最新的防火墙设置规则生效 firewall-cmd --reload # 更新防火墙规则并重启服务(用不了) firewall-cmd --completely-reload # 端口添加(--permanent永久生效,没有此参数重启后失效) firewall-cmd --permanent --zone=public --add-port=80/tcp # 查看80端口 firewall-cmd --zone=public --query-port=80/tcp # 删除80端口 firewall-cmd --permanent --zone=public --remove-port=80/tcp # 查看所有打开的端口 firewall-cmd --zone=public --list-ports # 添加HTTP协议服务 firewall-cmd --permanent --zone=public --add-service=http # 删除HTTP协议服务 firewall-cmd --permanent --zone=public --remove-service=http # 查看当前的服务 firewall-cmd --zone=public --list-services # 查看还有哪些服务可以打开 firewall-cmd --get-services # 查看所有信息(所有services和ports都能看到) firewall-cmd --list-all # 查询ssh协议服务是否被允许 firewall-cmd --zone=public --query-service=ssh # 查看已启动的服务列表 systemctl list-unit-files | grep enabled # 查看启动失败的服务列表 systemctl --failed # 查看区域信息 firewall-cmd --get-active-zones # 查看指定接口所属区域 firewall-cmd --get-zone-of-interface=eth0 # 查看当前的区域 firewall-cmd --get-default-zone # 拒绝所有包 firewall-cmd --panic-on # 取消拒绝状态 firewall-cmd --panic-off # 查看是否拒绝 firewall-cmd --query-panic # 安装图形化用户接口工具 firewall-config,则以 root 用户身份运行下列命令 yum install firewall-config ``` # java 相关记录 ## 阿里开源jdk [Section titled “阿里开源jdk”](#阿里开源jdk) [dragonwell](https://www.aliyun.com/product/dragonwell) ## openjdk下载 [Section titled “openjdk下载”](#openjdk下载) [参考链接](https://www.cnblogs.com/haimishasha/p/9909055.html) ```plaintext # openjdk官网 http://hg.openjdk.java.net/ # 亚马逊发行版 https://docs.aws.amazon.com/corretto/latest/corretto-8-ug/downloads-list.html wget https://corretto.aws/downloads/latest/amazon-corretto-8-x64-linux-jdk.tar.gz wget https://corretto.aws/downloads/latest/amazon-corretto-11-x64-linux-jdk.tar.gz tar -zxvf openjdk-8u41-b04-linux-x64-14_jan_2020.tar.gz # 下载后解压 ``` ## openjdk编译 [Section titled “openjdk编译”](#openjdk编译) ```plaintext yum install unzip unzip openjdk-8u40-src-b25-10_feb_2015.zip cd openjdk/ sudo bash ./configure --with-target-bits=64 --with-boot-jdk=/home/jiazhifeng/workspace/jdk1.7.0_80/ --with-debug-level=slowdebug --enable-debug-symbols ZIP_DEBUGINFO_FILES=0 sudo make all DISABLE_HOTSPOT_OS_VERSION_CHECK=OK ZIP_DEBUGINFO_FILES=0 ``` > 说明下第一条命令configure用到的参数作用:\ > –with-target-bits=64 :指定生成64位jdk;\ > –with-boot-jdk=/usr/java/jdk1.7.0\_80/:启动jdk的路径;\ > –with-debug-level=slowdebug:编译时debug的级别,有release, fastdebug, slowdebug 三种级别;\ > –enable-debug-symbols ZIP\_DEBUGINFO\_FILES=0:生成调试的符号信息,并且不压缩; # linux相关命令使用记录 ## Linux镜像 [Section titled “Linux镜像”](#linux镜像) 一键安装docker, 一键换软件源等 [LinuxMirrors](https://github.com/SuperManito/LinuxMirrors) ## 安装docker并配置加速器 [Section titled “安装docker并配置加速器”](#安装docker并配置加速器) ```shell yum -y install docker ``` ## 修改主机名 [Section titled “修改主机名”](#修改主机名) ```shell hostnamectl set-hostname manager43 ``` ## 获取ip地址 [Section titled “获取ip地址”](#获取ip地址) ```bash $(hostname -I|cut -d" " -f 1) ``` ## 配置hosts文件(可配置可不配置) [Section titled “配置hosts文件(可配置可不配置)”](#配置hosts文件可配置可不配置) ```shell vi /etc/hosts ``` ```shell 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.31.43 manager43 192.168.31.188 node188 192.168.31.139 node139 ``` ## 使用scp复制到node主机 [Section titled “使用scp复制到node主机”](#使用scp复制到node主机) ```shell scp /etc/hosts root@192.168.31.188:/etc/hosts ``` ## 查看防火墙 [Section titled “查看防火墙”](#查看防火墙) ```shell `firewall-cmd --zone=public --list-ports` 和 `netstat -tlunp` ``` ## 设置防火墙 [Section titled “设置防火墙”](#设置防火墙) ```shell systemctl disable firewalld.service systemctl stop firewalld.service ``` ```shell # 防火墙配置 # 官方文档 # centos7采用firewalld来配置防火墙,默认不开放接口。官方文档中给出的方案比较底层。这里我们采取自定义Service的方式来配置 # 创建文件 vi /etc/firewalld/services/docker.xml # 加入以下内容 docker docker daemon for remote access # 查看默认zone(一般是public) firewall-cmd --get-default-zone # 在zone中加入这个service firewall-cmd --zone=public --add-service=docker --permanent # 重新加载 firewall-cmd --reload # 查询端口 firewall-cmd --service=docker --get-ports --permanent # 参考链接 https://my.oschina.net/u/4560825/blog/4314028 ``` ## 添加dns [Section titled “添加dns”](#添加dns) ```shell vi /etc/sysconfig/network-scripts/ifcfg-enp0s3 # DNS2=114.114.114.114 systemctl restart network vi /etc/resolv.conf # 查看结果 ``` ## 配置yum镜像源 [Section titled “配置yum镜像源”](#配置yum镜像源) ```shell # 备份你的原镜像文件,以免出错后可以恢复 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup # 下载新的CentOS-Base.repo 到/etc/yum.repos.d/ wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo # 进入CentOS-Base.repo文件, 修改文件中的baseurl地址(可省略这步) vi CentOS-Base.repo # 清楚原有yum缓存 yum clean all # 生成缓存 yum makecache # 查看配置好的yum源是否正常 yum repolist ``` ## 安装docker [Section titled “安装docker”](#安装docker) ```shell # 使用官方安装脚本自动安装 # 安装命令如下: curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun # 也可以使用国内 daocloud 一键安装命令: curl -sSL https://get.daocloud.io/docker | sh ``` ```shell # 安装需要的软件包, yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的 yum install -y yum-utils device-mapper-persistent-data lvm2 # 配置镜像源 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo # 通过命令把https://download-stage.docker.com替换为http://mirrors.aliyun.com/docker-ce vi /etc/yum.repos.d/docker-ce.repo # 命令如下: :%s#https://download.docker.com#http://mirrors.aliyun.com/docker-ce#g # 更新yum缓存 yum makecache fast # 这时,可通过阿里镜像安装doker了 yum install docker-ce ``` ## 监控命令 [Section titled “监控命令”](#监控命令) ```shell # 查看服务状态,一秒一次,启动之后可通过IP:端口访问界面 watch -n 1 docker stack services hadoop ``` ## 打印信息 [Section titled “打印信息”](#打印信息) ```shell # 不打印正常信息,打印错误信息(/dev/null 代表空设备) xargs docker rmi > /dev/null # 正常和错误信息都不打印 xargs docker rmi &> /dev/null ``` ## 打印文件或文件夹列表时,排除文件或文件夹 [Section titled “打印文件或文件夹列表时,排除文件或文件夹”](#打印文件或文件夹列表时排除文件或文件夹) ```shell # 排除多个文件或文件夹 ls | grep -v 'a\|b' ``` ## nodejs安装 [Section titled “nodejs安装”](#nodejs安装) ```shell # curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash # nvm install 14.16.0 # npm install -g nrm # nrm ls # nrm use taobao # npm config ls # rm -rf ./node_modules # npm install # npm run build:test ``` ## docker访问权限问题 [Section titled “docker访问权限问题”](#docker访问权限问题) ```shell sudo groupadd docker #添加docker用户组 sudo gpasswd -a $USER docker #将当前用户添加至docker用户组 newgrp docker #更新docker用户组 ``` ## 查看端口占用 [Section titled “查看端口占用”](#查看端口占用) ```shell # 查看53端口的占用情况 sudo netstat -anlp | grep -w LISTEN | grep 53 ``` ## 定义环境变量 [Section titled “定义环境变量”](#定义环境变量) ```shell export DOCKER_HOST=tcp://localhost:2375 ``` ## crontab使用 [Section titled “crontab使用”](#crontab使用) ```shell # 格式 minute hour day month week command # 添加任务 crontab -e # 查看任务列表 crontab -l # 删除任务 crontab -r # 查看已执行过的任务 tail -f /var/log/cron ``` ## 设置网络时间 [Section titled “设置网络时间”](#设置网络时间) ```shell # 查看当前时间 date "+%Y-%m-%d %H:%M:%S" # 查看时区 date "+%Z" # 使用cat /etc/sysconfig/clock查看当前时区 cat /etc/sysconfig/clock # 设置时区 cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime # 查看硬件时间 hwclock # 同步硬件时间 hwclock -w # 同步系统时间 clock -w # ntpdate # 即使是硬件时间也会和网络时间有差异,想要和网络时间完全一致,我们就需要获取网络时间更新本地时间。 # 安装工具: yum -y install ntp ntpdate # 设置系统时间与网络时间同步: ntpdate cn.pool.ntp.org # 将系统时间写入硬件时间: hwclock –systohc # 同步时间服务器 ntpdate -u ntp.api.bz # ntp常用服务器: # 中国国家授时中心:210.72.145.44 # NTP服务器(上海) :ntp.api.bz # 美国: time.nist.gov # 复旦: ntp.fudan.edu.cn # 微软公司授时主机(美国) :time.windows.com # 北京邮电大学 : s1a.time.edu.cn # 清华大学 : s1b.time.edu.cn # 北京大学 : s1c.time.edu.cn # 台警大授时中心(台湾):asia.pool.ntp.org # simple cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ntpdate -u ntp.api.bz hwclock -w ``` ## 查看linux系统版本 [Section titled “查看linux系统版本”](#查看linux系统版本) ```shell # 只适用于redhat系linux系统 cat /etc/redhat-release # 方式二 rpm -q centos-release ``` ## Linux文件字符串替换命令 [Section titled “Linux文件字符串替换命令”](#linux文件字符串替换命令) ```shell # perl命令替换 # -e 执行指定的脚本。 # -i 原地替换文件,并将旧文件用指定的扩展名备份。不指定扩展名则不备份。 # -n 自动循环,相当于 while(<>) { 脚本; } # -p 自动循环+自动输出,相当于 while(<>) { 脚本; print; } # 用法示例: # 将所有C程序中的foo替换成bar,旧文件备份成.bak perl -p -i.bak -e 's/\bfoo\b/bar/g' *.c # 将当前文件夹下lishan.txt和lishan.txt.bak中的“shan”都替换为“hua” perl -p -i -e "s/shan/hua/g" ./lishan.txt ./lishan.txt.bak # ################################################################## # sed命令替换 # -i 表示inplace edit,就地修改文件 # s表示替换,d表示删除 # 格式: sed -i "s/查找字段/替换字段/g" `grep 查找字段 -rl 路径` 文件名 # 示例: # 把当前目录下lishan.txt里的shan都替换为hua sed -i "s/shan/hua/g" lishan.txt # 使用变量替换(使用双引号) sed -e "s/$var1/$var2/g" filename # 删除文本中空行和空格组成的行以及#号注释的行 grep -v ^# filename | sed /^[[:space:]]*$/d | sed /^$/d ``` ## 复制命令 [Section titled “复制命令”](#复制命令) * [参考文章](https://blog.csdn.net/qq_40880022/article/details/118937461) ```shell # 复制目录 -- 即将[/www/temp/java/BOOT-INF/lib]里面的所有内容,复制到这个[/www/temp/java/lib]目录里面 cp -a /www/temp/java/BOOT-INF/lib /www/temp/java/lib ``` ## top命令使用 [Section titled “top命令使用”](#top命令使用) ```shell # 使用`1`显示每个CPU的使用情况 # 使用`t`显示CPU使用百分比进度条 # 使用`m`显示内存使用百分比进度条 ``` ## 时间相关 [Section titled “时间相关”](#时间相关) * 相关文章 * \[\[centos使用date命令同步网络时间]] * \[\[timedatectl命令怎么同步网络时间]] * \[\[timedatectl命令怎么同步网络时间]] ```shell # 查看时间 timedatectl date # 修改时间 date -s "2024-01-19" date -s "10:30:00" timedatectl set-time "YYYY-MM-DD HH:MM:SS" # 开启自动同步时间 timedatectl set-ntp true # 手动同步网络时间 date -s "$(curl -s --head http://www.baidu.com | grep '^Date:' | cut -d' ' -f3-6)Z" ``` ## 查看域名对应IP [Section titled “查看域名对应IP”](#查看域名对应ip) ```bash ping -c 1 example.com ``` # linux网络笔记 ## linux网卡的开启 [Section titled “linux网卡的开启”](#linux网卡的开启) ```shell # 网络配置文件位置 cd /etc/sysconfig/network-scripts/ # 编辑配置文件 vi ifcfg-eth0 # ONBOOT="no"  #默认是启动时不开启网卡,我们可以将这个设置为yes # 然后重启网络 service network restart ``` ## firewalld docker 端口映射问题,firewall开放端口后,还是不能访问,解决方案 [Section titled “firewalld docker 端口映射问题,firewall开放端口后,还是不能访问,解决方案”](#firewalld-docker-端口映射问题firewall开放端口后还是不能访问解决方案) \` [参考文章](http://t.csdn.cn/Xo6XZ) ```shell # 宿主机ip: 192.168.31.19 docker run -itd --name tomcat -p 8080:8080 tomcat /usr/local/apache-tomcat-9.0.30/bin/startup.sh # 防火墙放开8080端口 firewall-cmd --add-port=8080/tcp --permanent # 问题:发现访问:192.168.31.19:8080 访问不通,关闭firewall后,又可以访问通了 # 解决方案,把docker0网卡添加到trusted域 firewall-cmd --permanent --zone=trusted --change-interface=docker0 # 重启加载配置 firewall-cmd --reload # firewall-cmd相关命令:https://www.cnblogs.com/Raodi/p/11625487.html ``` > 以上无效那就使用重启大法吧,貌似有时折腾了老半天,结果,最后重启就好了\~ # 查询pgsql数据库中所有表数据量的sql 以下是查询 PostgreSQL 数据库中所有表数据量的 SQL 语句的示例: 方法一:使用 pg\_class 表 ```sql SELECT relname AS table_name, reltuples AS row_count FROM pg_class WHERE relkind = 'r' AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'public'); ``` 这个查询语句会返回所有表的表名和对应的数据量。你可以将 `public` 替换为你要查询的实际 schema 名称。 方法二:使用 pg\_stat\_user\_tables 视图 ```sql SELECT schemaname, relname, n_live_tup AS row_count FROM pg_stat_user_tables; ``` 这个查询语句会返回所有用户表的 schema 名称、表名和对应的数据量。 以上是查询 PostgreSQL 数据库中所有表数据量的 SQL 语句示例。你可以根据具体的需求选择适合的方法进行查询。 参考资料: * \[postgresql 查询当前schema下所有表数据的数量 - 程序猿网友666 - 博客园][\[1\]](https://www.cnblogs.com/chenghu/p/17201210.html) * \[PostgreSQL 查询所有表的记录数\_pg查询所有表的数据量-CSDN博客][\[2\]](https://blog.csdn.net/londa/article/details/109046131) * \[查看PostgreSQL数据库中所有表\_pg查看库内表-CSDN博客][\[3\]](https://blog.csdn.net/huangbaokang/article/details/88862791) *** Learn more: 1. [postgresql 查询当前schema下所有表数据的数量 - 程序猿网友666 - 博客园](https://www.cnblogs.com/chenghu/p/17201210.html) 2. [PostgreSQL 查询所有表的记录数\_pg查询所有表的数据量-CSDN博客](https://blog.csdn.net/londa/article/details/109046131) 3. [查看PostgreSQL数据库中所有表\_pg查看库内表-CSDN博客](https://blog.csdn.net/huangbaokang/article/details/88862791) # docker compose 中 , 当我配置了副本的时候, IP怎么固定 在Docker Compose中,当配置了副本(replicas)时,容器的IP地址是动态分配的,无法直接固定。然而,可以通过一些方法来实现类似固定IP的效果。 以下是一种可能的解决方案: 1. 使用Overlay网络:创建一个Overlay网络,并指定一个自定义的子网。通过这种方式,可以控制容器的IP地址范围,避免与Docker引擎分配的IP地址冲突[\[3\]](https://gist.github.com/olljanat/b96ed26583c452118313fc18e4a663c1)。 ````yaml version: "3.9" networks: mynetwork: driver: overlay ipam: config: - subnet: 10.0.0.0/24 ``` ```` 2. 自定义Docker镜像:创建一个自定义的Docker镜像,该镜像在容器启动时可以设置固定的IP地址。可以在Dockerfile中添加相应的配置,例如使用ifconfig命令设置容器的IP地址[\[3\]](https://gist.github.com/olljanat/b96ed26583c452118313fc18e4a663c1)。 `````dockerfile FROM ubuntu RUN apt-get update && apt-get install -y net-tools iputils-ping COPY start.sh / ENTRYPOINT /start.sh ``` ````bash # start.sh #!/bin/bash if [[ -f "${STATIC_IP}" ]]; then echo "Using default IP from Docker" else echo "Found static IP: ${STATIC_IP}, using it" ifconfig eth0 ${STATIC_IP} netmask 255.255.255.0 up fi sleep infinity ``` ````` 3. 启动容器:在Docker Compose文件中,使用`cap-add=NET_ADMIN`参数启动容器,并将其连接到Overlay网络。通过设置`STATIC_IP`环境变量,可以将容器的IP地址设置为固定值[\[3\]](https://gist.github.com/olljanat/b96ed26583c452118313fc18e4a663c1)。 ````yaml version: "3.9" services: myservice: image: static-ip networks: - mynetwork environment: - STATIC_IP=10.0.0.11 deploy: replicas: 2 placement: constraints: - node.role == worker ``` ```` 请注意,以上解决方案仅提供了一种可能的方法,具体实现方式可能因环境和需求而有所不同。建议根据实际情况进行调整和测试。 *** Learn more: 1. [Provide static IP to docker containers via docker-compose - Stack Overflow](https://stackoverflow.com/questions/39493490/provide-static-ip-to-docker-containers-via-docker-compose) 2. [It is useless for fixing the ip of container for Swarm after enabling the replicas - Swarm - Docker Community Forums](https://forums.docker.com/t/it-is-useless-for-fixing-the-ip-of-container-for-swarm-after-enabling-the-replicas/121998) 3. [Overlay network and static IPs for Docker containers · GitHub](https://gist.github.com/olljanat/b96ed26583c452118313fc18e4a663c1) # Docker Swarm 节点标签管理 ## 查看节点标签 [Section titled “查看节点标签”](#查看节点标签) 使用以下命令查看节点标签: ```bash # 查看所有节点的标签 docker node ls --format "ID: {{.ID}}, Labels: {{.Labels}}" # 查看特定节点的标签 docker node inspect NODE_ID --format "Labels: {{.Spec.Labels}}" ``` ## 添加节点标签 [Section titled “添加节点标签”](#添加节点标签) 使用以下命令添加标签: ```bash docker node update --label-add key=value NODE_ID ``` 例如: ```bash docker node update --label-add environment=production node1 ``` ## 移除节点标签 [Section titled “移除节点标签”](#移除节点标签) 使用以下命令移除标签: ```bash docker node update --label-rm key NODE_ID ``` 例如: ```bash docker node update --label-rm environment node1 ``` ## 使用标签进行服务部署 [Section titled “使用标签进行服务部署”](#使用标签进行服务部署) 在 docker-compose.yml 中使用标签约束: ```yaml version: '3.8' services: app: deploy: placement: constraints: - node.labels.environment == production ``` # 为什么通过ssh -R转发端口后, 只能通过127.0.0.1的IP访问, 不能通过外网IP访问? 要怎么做才能通过外网IP访问呢? 通过ssh -R转发端口后,只能通过127.0.0.1的IP访问,而不能通过外网IP访问的原因是默认情况下,SSH服务器只会监听本地回环地址(127.0.0.1)上的转发端口。这是为了安全考虑,防止未经授权的访问。 要通过外网IP访问转发的端口,需要进行以下步骤: 1. 在SSH服务器上修改配置文件:打开SSH服务器的配置文件(通常是/etc/ssh/sshd\_config),找到并修改以下行: ```shell GatewayPorts yes ``` 这将允许SSH服务器监听所有网络接口上的转发端口,而不仅仅是本地回环地址。 2. 重启SSH服务器:保存配置文件修改后,重启SSH服务器以使修改生效。可以使用以下命令重启SSH服务器: ```shell sudo service ssh restart # 或者 systemctl restart sshd ``` 3. 在客户端使用外网IP访问:现在,你可以使用SSH客户端通过外网IP访问转发的端口。例如,如果你将端口转发到SSH服务器的端口2222,并且SSH服务器的外网IP是203.0.113.1,你可以使用以下命令连接到转发的端口: ```shell ssh -p 2222 user@203.0.113.1 ``` 这将连接到SSH服务器,并将流量转发到转发的端口。 请注意,修改SSH服务器的配置文件可能需要管理员权限。此外,开放SSH服务器的转发端口可能会带来安全风险,请确保只允许受信任的主机访问转发的端口。 *** slug: /docker/doc/material/ai/os/ssh-port-forwarding-external-access Learn more: 1. [ssh如何实现内网访问外网? - 知乎](https://www.zhihu.com/question/398993211) 2. [SSH的三种端口转发 - jeremy的技术点滴](https://jeremyxu2010.github.io/2018/12/ssh%E7%9A%84%E4%B8%89%E7%A7%8D%E7%AB%AF%E5%8F%A3%E8%BD%AC%E5%8F%91/) 3. [通过ssh反向连接内网主机的方法(防火墙的主机) - memphise - 博客园](https://www.cnblogs.com/memphise/articles/6472207.html) ## 相关问题 [Section titled “相关问题”](#相关问题) > sudo service ssh restart 这句命令执行失败了, 并且已经安装了ssh, 怎么解决 Failed to restart ssh.service: Unit not found. 根据搜索结果,“Failed to restart ssh.service: Unit not found”错误可能是由于使用了错误的命令或系统版本不同导致的。以下是解决此问题的几种可能方法: 1. 使用正确的命令:根据您的系统版本,尝试使用适当的命令来重启SSH服务。在CentOS 7及更高版本中,应使用以下命令: ```shell sudo systemctl restart sshd ``` 在Ubuntu 16.04及更高版本中,应使用以下命令: ```shell sudo systemctl restart ssh ``` 如果仍然出现相同的错误,请继续以下步骤。 2. 检查SSH服务的状态:使用以下命令检查SSH服务的状态,确保它已正确安装并正在运行: ```shell sudo systemctl status sshd ``` 如果SSH服务未安装或未运行,请尝试重新安装SSH服务器并启动服务。 3. 重新安装SSH服务器:如果SSH服务已正确安装但仍无法启动,请尝试重新安装SSH服务器。首先,卸载现有的SSH服务器: ```shell sudo apt-get purge openssh-server ``` 然后,重新安装SSH服务器: ```shell sudo apt-get install openssh-server ``` 最后,尝试重新启动SSH服务。 如果问题仍然存在,请提供更多详细信息,例如错误消息的完整内容和任何相关的日志文件,以便我们能够更好地帮助您解决问题。 *** slug: /docker/doc/material/ai/os/ssh-port-forwarding-external-access Learn more: 1. [Failed to restart ssh.service: Unit not found.-CSDN博客](https://blog.csdn.net/u010433704/article/details/120057040) 2. [Failed to start ssh.service: Unit not found. - 等不到的口琴 - 博客园](https://www.cnblogs.com/Courage129/p/14073162.html) 3. [ssh - Cannot start sshd service: Failed to start openssh.service: Unit not found - Server Fault](https://serverfault.com/questions/904430/cannot-start-sshd-service-failed-to-start-openssh-service-unit-not-found) # centos使用date命令同步网络时间 在CentOS中,可以使用date命令来同步网络时间。下面是使用date命令同步网络时间的步骤: 1. 设置时区: 首先,确保服务器的时区设置正确。可以使用以下命令来查看当前的时区设置: `````shell timedatectl status | grep 'Time zone' ``` 如果时区不正确,可以使用以下命令来设置时区为中国时区(Asia/Shanghai): ````shell timedatectl set-timezone Asia/Shanghai ``` ````` 2. 同步网络时间: 使用以下命令来同步网络时间: ````shell date -s "$(curl -s --head http://www.baidu.com | grep '^Date:' | cut -d' ' -f3-6)Z" ``` 这个命令会从百度的服务器获取当前的时间,并将系统时间设置为该时间。 ```` 3. 验证时间同步: 使用以下命令来验证时间是否同步成功: ````shell date ``` 这个命令会显示当前的系统时间。 ```` 请注意,使用date命令同步网络时间可能不是最准确的方法。更好的方法是使用ntpdate或者ntp服务来同步网络时间。你可以参考搜索结果中提到的ntpdate和ntp服务的使用方法。 *** Learn more: 1. [CentOS 7同步时间的2种方法 - 小z博客](https://blog.xiaoz.org/archives/12989) 2. [Linux/CentOS系统同步网络时间的2种方法详解-腾讯云开发者社区-腾讯云](https://cloud.tencent.com/developer/article/1721411) 3. [CentOS设置系统时间与网络时间同步-腾讯云开发者社区-腾讯云](https://cloud.tencent.com/developer/article/1795159) # curl 看连接是否通 您可以使用curl命令来检查连接是否通畅。以下是使用curl命令检查连接的几种方法: 1. 使用curl发送HTTP请求: ````bash curl -I ``` 这将发送一个HEAD请求到指定的URL,并返回HTTP响应头信息。如果连接成功,您将看到HTTP响应的状态码和其他相关信息。 ```` 2. 使用curl发送TCP连接请求: ````bash curl telnet://: ``` 这将尝试建立到指定主机和端口的TCP连接。如果连接成功,您将看到"Connected"的状态。 ```` 3. 使用curl测试特定端口的连接: ````bash curl -v telnet://: ``` 这将显示与指定主机和端口的连接过程的详细信息。如果连接成功,您将看到"Connected"的状态。 ```` 请注意,这些命令仅适用于检查连接是否成功建立,而不涉及实际的数据传输。 *** Learn more: 1. [Test TCP connectivity with curl](https://www.unixtutorial.org/test-tcp-connectivity-with-curl/) 2. [Curl: Using curl to test if a port is open: exit immediately upon connection if STDIN is /dev/null](https://curl.se/mail/archive-2022-04/0027.html) 3. [monitoring - Health check of web page using curl - Unix & Linux Stack Exchange](https://unix.stackexchange.com/questions/84814/health-check-of-web-page-using-curl) # ssh加nginx实现内网穿透 * 外网服务器nginx配置 ```shell # 创建配置文件 tee /etc/nginx/conf.d/ssh.conf <<-'EOF' server { listen 80; listen [::]:80; server_name 127.0.0.1 localhost 210.21.48.11; access_log /var/log/nginx/ssh_access.log main; location /8888 { proxy_pass http://127.0.0.1:8888; } } EOF # 重载nginx配置 nginx -s reload ## 如果没有安装nginx # 方式一 docker run --network=host -v /etc/nginx/conf.d/ssh.conf:/etc/nginx/conf.d/ssh.conf -i --rm nginx # 方式二 # 安装nginx(docker安装nginx) docker run --network=host -it --rm nginx bash # 执行命令 nohup /docker-entrypoint.sh nginx -g 'daemon off;' & ``` * 内网服务器ssh配置 ```shell # 默认是在本地回环地址上,需要其他机器访问的话可以指定 ip 或者增加 -g 参数开启网关模式 ssh -N -R 210.21.48.69:8888:192.168.3.14:8888 ljf@210.21.48.69 -p 10086 ``` # timedatectl命令怎么同步网络时间 要使用`timedatectl`命令同步网络时间,您可以按照以下步骤操作: 1. 检查当前时间同步状态: * 在终端中运行以下命令来查看当前时间同步状态:`timedatectl status` [\[1\]](https://tecadmin.net/synchronizing-a-linux-system-clock-with-ntp-server/). * 检查输出中的 “System clock synchronized” 字段,如果显示为 “yes”,则表示时间已经同步。 2. 启用网络时间同步: * 在终端中运行以下命令来启用网络时间同步:`sudo timedatectl set-ntp true` [\[1\]](https://tecadmin.net/synchronizing-a-linux-system-clock-with-ntp-server/). * 这将启用系统与网络时间协议(NTP)服务器的自动时间同步。 3. 检查时间同步状态: * 再次运行 `timedatectl status` 命令来检查时间同步状态 [\[1\]](https://tecadmin.net/synchronizing-a-linux-system-clock-with-ntp-server/). * 确保 “System clock synchronized” 字段显示为 “yes”,表示时间已成功同步。 *** Learn more: 1. [Synchronizing a Linux System Clock with NTP Server](https://tecadmin.net/synchronizing-a-linux-system-clock-with-ntp-server/) 2. [How to Set Time, Timezone and Synchronize System Clock Using timedatectl Command](https://www.tecmint.com/set-time-timezone-and-synchronize-time-using-timedatectl-command/) 3. [systemd - How to sync the time to network with timedatectl on Ubuntu 18.04? - Ask Ubuntu](https://askubuntu.com/questions/1058593/how-to-sync-the-time-to-network-with-timedatectl-on-ubuntu-18-04) # ssh动态代理 以下是对命令 `ssh -o GatewayPorts=yes -D 2000 test-2023.intranet.company -NTfCg` 的逐项解析和完整说明: *** ### **命令功能总结** [Section titled “命令功能总结”](#命令功能总结) 此命令通过 SSH 建立一个 **后台运行的动态端口转发隧道**(SOCKS5 代理),绑定到本地所有网络接口,允许远程主机通过该代理访问目标网络资源。具体用途包括: * 将本地 `2000` 端口作为代理入口,流量通过 `test-2023.intranet.company` 服务器转发。 * 支持远程主机(非本机)连接本地 `2000` 端口(通过 `-g` 和 `GatewayPorts=yes` 实现)。 * 后台静默运行,无终端交互,适合长期稳定的代理需求。 *** ### **参数逐项解析** [Section titled “参数逐项解析”](#参数逐项解析) #### **1. `-o GatewayPorts=yes`** [Section titled “1. -o GatewayPorts=yes”](#1--o-gatewayportsyes) * **作用**:允许远程主机连接到本地转发的端口。 * **默认行为**:SSH 默认将本地端口绑定到 `127.0.0.1`(仅限本机访问)。 * **启用后**:绑定到 `0.0.0.0`(所有网络接口),使其他主机可通过本地 IP 访问 `2000` 端口。 * **典型场景**:需要将本地代理共享给局域网内其他设备时(如手机、平板)。 *** #### **2. `-D 2000`** [Section titled “2. -D 2000”](#2--d-2000) * **作用**:启用动态端口转发(SOCKS5 代理),监听本地 `2000` 端口。 * **流量规则**:所有发送到 `2000` 端口的流量将通过 SSH 隧道加密并转发到目标网络。 * **端口选择**: * `<1024` 的端口需要 `root` 权限(如 `-D 80`)。 * `2000` 是用户级端口,无需特权。 *** #### **3. `test-2023.intranet.company`** [Section titled “3. test-2023.intranet.company”](#3-test-2023intranetcompany) * **作用**:指定 SSH 连接的目标服务器。 * **补充说明**: * 确保该域名能被正确解析(如通过 DNS 或 `/etc/hosts` 配置)。 * 如果使用密钥认证,需提前配置 `~/.ssh/config` 或通过 `-i` 指定私钥。 *** #### **4. `-N`** [Section titled “4. -N”](#4--n) * **作用**:不执行远程命令,仅建立隧道。 * **用途**:适用于纯端口转发场景,无需启动远程 Shell。 *** #### **5. `-T`** [Section titled “5. -T”](#5--t) * **作用**:禁用伪终端(PTY)分配。 * **用途**:进一步减少资源占用,确保连接仅用于转发。 *** #### **6. `-f`** [Section titled “6. -f”](#6--f) * **作用**:将 SSH 进程转入后台运行。 * **操作提示**: * 若需终止后台进程,可使用 `ps aux | grep ssh` 查找 PID 后执行 `kill `。 * 结合 `-f` 时,输入密码需在命令中提前处理(如使用密钥或无密码登录)。 *** #### **7. `-C`** [Section titled “7. -C”](#7--c) * **作用**:启用数据压缩(基于 gzip 算法)。 * **适用场景**: * 网络带宽较低时(如移动网络),减少传输数据量。 * 传输大量文本数据(如日志、代码)。 * **不适用场景**: * 高速局域网环境(压缩可能增加延迟)。 * 已加密或预压缩的数据(如视频、图片)。 *** #### **8. `-g`** [Section titled “8. -g”](#8--g) * **作用**:允许远程主机连接本地转发端口(与 `GatewayPorts=yes` 功能重复,但双重确保)。 * **历史背景**:旧版 SSH 中,`-g` 是实现 `GatewayPorts=yes` 的等效命令行选项,现代版本中两者可同时使用以明确意图。 *** ### **完整命令行为** [Section titled “完整命令行为”](#完整命令行为) ```bash ssh \ -o GatewayPorts=yes \ # 允许远程主机连接本地端口 -D 2000 \ # 动态转发到本地2000端口(SOCKS5) test-2023.intranet.company \ # 目标服务器 -N \ # 不执行远程命令 -T \ # 不分配终端 -f \ # 后台运行 -C \ # 启用压缩 -g # 允许远程主机连接 ``` *** ### **典型使用场景** [Section titled “典型使用场景”](#典型使用场景) #### **场景 1:本地开发代理** [Section titled “场景 1:本地开发代理”](#场景-1本地开发代理) * 浏览器或应用配置 SOCKS5 代理为 `127.0.0.1:2000`,所有流量通过 `test-2023.intranet.company` 转发。 * 访问内部服务(如 `http://internal-app:8080`)时,流量经由隧道直达内网。 #### **场景 2:跨设备共享代理** [Section titled “场景 2:跨设备共享代理”](#场景-2跨设备共享代理) * 在本地 PC 运行此命令,手机或其他设备将代理设置为 `:2000`,即可通过 PC 的 SSH 隧道访问内网。 #### **场景 3:穿透防火墙** [Section titled “场景 3:穿透防火墙”](#场景-3穿透防火墙) * 绕过网络限制访问被封资源(如访问外部 API),依赖服务器的出口 IP。 *** ### **常见问题排查** [Section titled “常见问题排查”](#常见问题排查) #### **1. 连接失败:`Permission denied`** [Section titled “1. 连接失败:Permission denied”](#1-连接失败permission-denied) * **原因**:SSH 认证失败(密码错误、密钥未配置)。 * **解决**: * 使用 `-v` 参数查看详细日志:`ssh -v ...`。 * 配置密钥登录:`ssh-copy-id user@test-2023.intranet.company`。 #### **2. 端口占用:`bind: Address already in use`** [Section titled “2. 端口占用:bind: Address already in use”](#2-端口占用bind-address-already-in-use) * **原因**:本地 `2000` 端口被其他进程占用。 * **解决**: * 更换端口:`-D 2001`。 * 释放端口:`lsof -i :2000` 查找占用进程并终止。 #### **3. 远程主机无法连接代理** [Section titled “3. 远程主机无法连接代理”](#3-远程主机无法连接代理) * **原因**:本地防火墙或路由器阻止外部访问 `2000` 端口。 * **解决**: * 开放防火墙:`sudo ufw allow 2000`(Linux)。 * 检查路由器 NAT 规则(如需从公网访问)。 *** ### **扩展操作** [Section titled “扩展操作”](#扩展操作) #### **1. 结合 ClashX 使用** [Section titled “1. 结合 ClashX 使用”](#1-结合-clashx-使用) 在 ClashX 配置文件中添加 SOCKS5 代理: ```yaml proxies: - name: "ssh-tunnel" type: socks5 server: 127.0.0.1 port: 2000 udp: true # 按需启用 UDP 转发 rules: - DOMAIN-SUFFIX,intranet.company,ssh-tunnel ``` #### **2. 保持隧道稳定(防断连)** [Section titled “2. 保持隧道稳定(防断连)”](#2-保持隧道稳定防断连) 使用 `autossh` 替代 `ssh` 实现自动重连: ```bash autossh -M 0 -o "ExitOnForwardFailure=yes" -NTfCg -D 2000 test-2023.intranet.company ``` *** ### **总结** [Section titled “总结”](#总结) 此命令通过 SSH 动态端口转发,将本地 `2000` 端口变为一个多功能的 SOCKS5 代理通道,适合需要安全穿透内网或共享代理的场景。通过参数组合优化了后台运行、压缩和远程访问支持,是高效管理网络流量的实用工具。 # .nvmrc如何使用 `.nvmrc` 是 Node Version Manager (NVM) 的配置文件,用于指定特定项目或目录下的 Node.js 版本。您可以通过以下步骤来使用 `.nvmrc`: 1. 创建 `.nvmrc` 文件:在项目或目录下创建一个名为 `.nvmrc` 的文件,并在文件中写入所需的 Node.js 版本号。例如,您可以在 `.nvmrc` 文件中写入 `14.18.2` 来指定使用 Node.js 的 14.18.2 版本。 2. 使用指定版本的 Node.js:在终端中进入项目或目录,并执行 `nvm use` 命令,NVM 将会自动读取 `.nvmrc` 文件中指定的版本号,并切换到该版本的 Node.js。例如,执行 `nvm use` 命令后,终端会显示类似以下的输出: ```bash Found '.nvmrc' with version <14.18.2> Now using node v14.18.2 (npm v6.14.15) ``` 这表示 NVM 已经切换到了 `.nvmrc` 文件中指定的 Node.js 版本。 3. 其他 NVM 命令:除了 `nvm use` 命令外,您还可以使用其他 NVM 命令来管理和切换 Node.js 版本。例如,`nvm install` 命令用于安装指定版本的 Node.js,`nvm ls` 命令用于列出已安装的 Node.js 版本,`nvm alias` 命令用于创建别名等。 请注意,`.nvmrc` 文件是针对特定项目或目录的,不同的项目或目录可以有不同的 `.nvmrc` 文件来指定不同的 Node.js 版本。 *** Learn more: 1. [.nvmrc 里只要存储版本号\_.nvmrc’ with version <14.18.2>-CSDN博客](https://blog.csdn.net/qq_28966143/article/details/117328024) 2. [.nvmrc文件是什么?.nvmrc文件怎么使用?-CSDN博客](https://blog.csdn.net/zhouweihua138/article/details/129762721) 3. [.nvmrc 文件使用详解](https://www.itqaq.com/index/563.html) # .sdkmanrc如何使用 `.sdkmanrc` 是 SDKMAN 的配置文件,用于指定特定项目或目录下的 SDK 版本。您可以通过以下步骤来使用 `.sdkmanrc`: 1. 初始化环境:在项目或目录下执行以下命令,将会在当前目录下创建一个 `.sdkmanrc` 文件,其中记录了当前环境的各个 SDK 版本。您可以手动修改该文件以指定特定的版本。 ```bash sdk env init ``` 2. 切换环境:执行以下命令将会切换为当前目录下 `.sdkmanrc` 文件中指定的各个 SDK 版本。 ```bash sdk env ``` 3. 清除当前 shell 使用的环境:如果您想清除当前 shell 使用的环境,可以执行以下命令。 ```bash sdk env clear ``` 4. 安装环境:如果您在新的项目或目录下想要使用之前配置好的环境,可以执行以下命令。 ```bash sdk env install ``` 请注意,`.sdkmanrc` 文件是针对特定项目或目录的,不同的项目或目录可以有不同的 `.sdkmanrc` 文件来指定不同的 SDK 版本。 *** Learn more: 1. [SDK管理利器:SDKMAN! - 掘金](https://juejin.cn/post/7044711294984781838) 2. [SDK管理利器\_sdk env-CSDN博客](https://blog.csdn.net/qq_19693295/article/details/122100555) 3. [Usage - SDKMAN! the Software Development Kit Manager](https://sdkman.io/usage) # centos时间相关操作 设置时区(CentOS 7) 先执行命令timedatectl status|grep ‘Time zone’查看当前时区,如果不是中国时区(Asia/Shanghai),则需要先设置为中国时区,否则时区不同会存在时差。 ```shell #已经是Asia/Shanghai,则无需设置 [root@xiaoz shadowsocks]# timedatectl status|grep 'Time zone' Time zone: Asia/Shanghai (CST, +0800) ``` 执行下面的命令设置时区 ```shell #设置硬件时钟调整为与本地时钟一致 timedatectl set-local-rtc 1 #设置时区为上海 timedatectl set-timezone Asia/Shanghai ``` 使用ntpdate同步时间 目前比较常用的做法就是使用ntpdate命令来同步时间,使用方法如下: ```shell #安装ntpdate yum -y install ntpdate #同步时间 ntpdate -u pool.ntp.org #同步完成后,date命令查看时间是否正确 date ``` 另外再分享下几个常用的ntp server,如果需要更多可以前往:[ntp官网](http://www.ntp.org.cn)获取 ```shell #中国 cn.ntp.org.cn #中国香港 hk.ntp.org.cn #美国 us.ntp.org.cn ``` 同步时间后可能部分服务器过一段时间又会出现偏差,因此最好设置crontab来定时同步时间,方法如下: ```shell #安装crontab yum -y install crontab #创建crontab任务 crontab -e #添加定时任务 */20 * * * * /usr/sbin/ntpdate pool.ntp.org > /dev/null 2>&1 #重启crontab service crond reload ``` 上面的计划任务会在每20分钟进行一次时间同步,注意/usr/sbin/ntpdate为ntpdate命令所在的绝对路径,不同的服务器可能路径不一样,可以使用which命令来找到绝对路径,方法如下: ```shell [root@xiaoz ~]# which ntpdate /usr/sbin/ntpdate ``` 使用rdate同步时间 ntpdate服务需要使用udp/123端口,但是某些服务商禁止了所有UDP协议,所以你会发现无论如何ntpdate总是同步出错。 ```shell #下方是ntpdate同步时间报错的一个列子 [root@sharktech ~]# ntpdate -u pool.ntp.org 1 Jun 16:13:46 ntpdate[8389]: no server suitable for synchronization found ``` 这个时候我们可以改用rdate命令来同步时间,方法如下: ```shell #安装rdate yum -y install rdate #同步时间 rdate -s time-b.nist.gov #查看时间是否正确 date ``` 和上面一样,我们最好是加入定时任务来定期同步时间,方法如下: ```shell #安装crontab yum -y install crontab #创建crontab任务 crontab -e #添加定时任务 */20 * * * * /usr/bin/rdate -s time-b.nist.gov > /dev/null 2>&1 #重启crontab service crond reload ``` 还有一些其它的rdate时间服务器如下: ```shell s1d.time.edu.cn #东南大学 s1e.time.edu.cn #清华大学 s2a.time.edu.cn #清华大学 s2b.time.edu.cn #清华大学 s2c.time.edu.cn #北京邮电大学 ntp.sjtu.edu.cn 202.120.2.101 #(上海交通大学网络中心NTP服务器地址) s1a.time.edu.cn #北京邮电大学 s1b.time.edu.cn #清华大学 s1c.time.edu.cn #北京大学 clock.cuhk.edu.hk #香港中文大学授时中心 ``` 总结 无论是使用ntpdate还是rdate来同步时间,方法都比较简单,大致流程就是“设置时区” -> “同步时间” -> “设置定时任务”。在实际的测试中,xiaoz发现部分服务商屏蔽UDP端口的情况下,ntpdate命令无法同步,但使用rdate命令却可以,有类似情况的童鞋不妨试一下。 # nfs-server ## 服务端安装NFS服务步骤: [Section titled “服务端安装NFS服务步骤:”](#服务端安装nfs服务步骤) * 第一步:安装NFS和rpc。 ```shell [root@localhost ~]# yum install -y nfs-utils #安装nfs服务 [root@localhost ~]# yum install -y rpcbind #安装rpc服务 ``` * 第二步:启动服务和设置开启启动: > 注意:先启动rpc服务,再启动nfs服务。 ```shell [root@localhost ~]# systemctl start rpcbind #先启动rpc服务 [root@localhost ~]# systemctl enable rpcbind #设置开机启动 [root@localhost ~]# systemctl start nfs-server nfs-secure-server #启动nfs服务和nfs安全传输服务(nfs-secure-server 可不需要) [root@localhost ~]# systemctl enable nfs-server nfs-secure-server # 设置开启启动(nfs-secure-server 可不需要) ``` > 配置防火墙 ```shell [root@localhost /]# firewall-cmd --permanent --add-service=rpc-bind success #配置防火墙放行rpc-bind服务 [root@localhost /]# firewall-cmd --permanent --add-service=nfs success #配置防火墙放行nfs服务 (未开启报错: clnt_create: RPC: Port mapper failure - Unable to receive: errno 113 (No route to host)) [root@localhost /]# firewall-cmd --permanent --add-service=mountd success #配置防火墙放行mountd服务(未开启报错: rpc mount export: RPC: Unable to receive; errno = No route to host) [root@localhost /]# firewall-cmd --reload success ``` * 第三步:配置共享文件目录,编辑配置文件: 1. 首先创建共享目录,然后在/etc/exports配置文件中编辑配置即可。 ```shell [root@localhost /]# mkdir /public #创建public共享目录 [root@localhost /]# vi /etc/exports /public 192.168.245.0/24(rw) /protected 192.168.245.0/24(ro) [root@localhost /]# systemctl reload nfs #重新加载NFS服务,使配置文件生效(取其一执行即可) [root@localhost /]# exportfs -rv #暴露NFS服务,使配置文件生效(取其一执行即可) ``` ## NFS客户端挂载配置: [Section titled “NFS客户端挂载配置:”](#nfs客户端挂载配置) * 第一步:使用showmount命令查看nfs服务器共享信息。输出格式为“共享的目录名称 允许使用客户端地址”。 ```shell yum -y install nfs-utils # 安装nfs-utils客户端 [root@localhost ~]# showmount -e 192.168.245.128 Export list for 192.168.245.128: /protected 192.168.245.0/24 /public 192.168.245.0/24 ``` * 第二步,在客户端创建目录,并挂载共享目录。 ```shell [root@localhost ~]# mkdir /mnt/public [root@localhost ~]# mkdir /mnt/data [root@localhost ~]# vim /etc/fstab #在该文件中挂载,使系统每次启动时都能自动挂载 192.168.245.128:/public /mnt/public nfs defaults 0 0 192.168.245.128:/protected /mnt/data nfs defaults 0 1 [root@localhost ~]# mount -a #是文件/etc/fstab生效 ``` * 第三步:检查: ```shell showmount -e 192.168.56.103 # 查看是否有权限访问 [root@mail ~]# df -Th # 查看挂载情况 Filesystem Type Size Used Avail Use% Mounted on /dev/mapper/rhel-root xfs 17G 3.1G 14G 18% / devtmpfs devtmpfs 1.4G 0 1.4G 0% /dev tmpfs tmpfs 1.4G 140K 1.4G 1% /dev/shm tmpfs tmpfs 1.4G 9.1M 1.4G 1% /run tmpfs tmpfs 1.4G 0 1.4G 0% /sys/fs/cgroup /dev/sda1 xfs 1014M 173M 842M 18% /boot tmpfs tmpfs 280M 32K 280M 1% /run/user/0 /dev/sr0 iso9660 3.6G 3.6G 0 100% /mnt/cdrom 192.168.245.128:/public nfs4 17G 3.7G 14G 22% /mnt/public 192.168.245.128:/protected nfs4 17G 3.7G 14G 22% /mnt/data ``` # docker容器没权限问题 1. 创建docker容器时,指定`--privileged`参数 ## docker gid 查看命令 [Section titled “docker gid 查看命令”](#docker-gid-查看命令) [参考地址1](https://www.doubao.com/thread/w9e714164e14f12b9) [参考地址2](https://github.com/influxdata/sandbox/issues/79)(PS: 貌似没啥用的样子) [参考地址3](https://github.com/influxdata/sandbox/issues/83) ```bash stat -c '%g' /var/run/docker.sock ``` # docker swarm networks ## 网段冲突问题解决方案 [Section titled “网段冲突问题解决方案”](#网段冲突问题解决方案) 根据搜索结果,以下是关于如何更改Docker Ingress网络默认子网范围的解决方案: 1. 首先,我们需要确认当前Docker Ingress网络的默认子网范围。可以使用以下命令检查网络配置信息:`docker network inspect ingress` [\[1\]](https://stackoverflow.com/questions/42954017/how-to-change-ip-address-range-of-docker-swarm-ingress-network)。 2. 如果默认子网范围与您的计算机子网范围冲突,您可以尝试以下方法来更改Docker Ingress网络的子网范围: * 方法一:使用Docker Swarm命令行选项来指定子网范围。在初始化或加入Docker Swarm时,可以使用`--default-addr-pool`选项来指定子网范围。例如:`docker swarm init --default-addr-pool 192.168.0.0/16` [\[1\]](https://stackoverflow.com/questions/42954017/how-to-change-ip-address-range-of-docker-swarm-ingress-network)。 * 方法二:编辑Docker的守护进程配置文件`daemon.json`来指定子网范围。您可以使用以下步骤进行操作: * 使用文本编辑器打开`/etc/docker/daemon.json`文件(在Windows上是`C:\ProgramData\Docker\config\daemon.json`)。 * 添加以下内容到文件中: ```json { "default-address-pools": [ {"base":"192.168.0.0/16","size":24} ] } ``` 将`192.168.0.0/16`替换为您想要的子网范围。 * 保存文件并重启Docker服务,以使更改生效。在Linux上,可以使用`sudo systemctl restart docker`命令来重启Docker服务,在Windows上,可以通过Docker桌面界面的”Troubleshoot”选项来重启Docker Desktop [\[2\]](https://support.hyperglance.com/knowledge/changing-the-default-docker-subnet)。 请注意,更改Docker网络的子网范围可能会影响到已经运行的容器和网络连接,请谨慎操作并确保备份重要数据。 *** Learn more: 1. [networking - How to change ip address range of docker swarm ingress network - Stack Overflow](https://stackoverflow.com/questions/42954017/how-to-change-ip-address-range-of-docker-swarm-ingress-network) 2. [How to change the default docker subnet IP range](https://support.hyperglance.com/knowledge/changing-the-default-docker-subnet) 3. [Changing Docker’s default subnet IP range | cylab.be](https://cylab.be/blog/277/changing-dockers-default-subnet-ip-range) ## 宿主机与容器不通问题 [Section titled “宿主机与容器不通问题”](#宿主机与容器不通问题) ```bash # 方式一:添加路由 # route add -net 192.168.1.0 netmask 255.255.255.0 gw 172.20.0.1 dev docker_gwbridge # dev 是用来指定网络接口的参数。它用于指定要添加路由的网络接口设备。 route add -net <容器IP网段> netmask <容器IP网段的子网掩码> gw dev docker_gwbridge ## 查看路由 route -n ## 更多操作 # 端口转发问题(上面解决了路由的问题,若还有端口访问不通,则按下面方式解决) # 查看nat转发的规则 iptables -t nat -nvL # 添加nat转发规则(实现宿主机访问容器中未开放的端口(即docker run时未添加-p参数)) iptables -t nat -A DOCKER -p tcp -m tcp --dport 8088 -j DNAT --to-destination 10.0.0.2:8088 # 删除nat ## 查看规则编号 iptables -t nat -nL --line-number ## 删除编号 iptables -t nat -D DOCKER 4 ``` # 远程连接相关记录 ## 不用密码直接登陆 — ssh密钥登陆 [Section titled “不用密码直接登陆 — ssh密钥登陆”](#不用密码直接登陆--ssh密钥登陆) 打开你的git-bash,输入`ssh-keygen` ,然后输入时,三个空回车即可。 接着执行`ssh-copy-id <用户名>@<主机IP>` 最后使用ssh尝试连接,哇,一气呵成,直接连上了! > 需要远程多台时,`ssh-keygen`这个命令也只需一次即可,`ssh-copy-id <用户名>@<主机IP>`这个使用多次即可 *** ## 密钥相关 [Section titled “密钥相关”](#密钥相关) 推荐使用 ed25519 算法生成密钥,它比传统的 RSA 更安全且性能更好:​ ```bash # 生成ed25519密钥对​ ssh-keygen -t ed25519 -C "your_email@example.com" -f ~/.ssh/id_ed25519 -N "" # 优势:​ # 密钥长度更短(仅 68 个字符)​ # 加密强度更高​ # 生成和验证速度更快 ``` ```bash ssh-keygen -t rsa -b 4096 -C "你的邮箱地址" # 参数说明: # -t rsa:指定密钥算法为 RSA(兼容性最强,推荐默认); # -b 4096:密钥长度 4096 位(安全性更高,替代默认的 2048 位); # -C "邮箱":给密钥添加备注(方便区分多个密钥,通常用邮箱或用途标识)。 ``` ### 密钥管理 [Section titled “密钥管理”](#密钥管理) 好像没啥用, 不管了 ```bash # 配置自动启动​ echo 'eval $(ssh-agent -s)' >> ~/.zshrc echo 'ssh-add ~/.ssh/id_ed25519_iu 2>/dev/null' >> ~/.zshrc echo 'eval $(ssh-agent -s)' >> ~/.bashrc​ echo 'ssh-add ~/.ssh/id_ed25519_iu 2>/dev/null' >> ~/.bashrc ``` ```bash # SSH代理自动配置​ if ! pgrep -u "$USER" ssh-agent > /dev/null; then​ ssh-agent -t 86400 > "$XDG_RUNTIME_DIR/ssh-agent.env"​ fi​ ​ if [[ ! -z "$SSH_AUTH_SOCK" && ! -S "$SSH_AUTH_SOCK" ]]; then​ source "$XDG_RUNTIME_DIR/ssh-agent.env" >/dev/null​ fi ``` # docker运行时相关记录 ## kata-containers [Section titled “kata-containers”](#kata-containers) ### temp [Section titled “temp”](#temp) ```bash # 不太行 mkdir -p /root/kata-container/kata-rpm curl -OL https://github.com/kata-containers/kata-containers/releases/download/3.18.0/kata-containers-3.18.0-vendor.tar.gz # 解压 tar -xvf kata-containers-3.18.0-vendor.tar.gz -C /root/kata-container/kata-rpm # yum安装yq yum install -y yq ``` # 软件相关 ## Sonatype Nexus [Section titled “Sonatype Nexus”](#sonatype-nexus) * 用于搭建maven私服,以后部署玩玩 # 开启ssl ## telnet ip 443 不通的问题 [Section titled “telnet ip 443 不通的问题”](#telnet-ip-443-不通的问题) * 大概率是端口没开导致,需要检查下docker-compose文件的端口映射问题 * 同时可以使用`netstat -npl | grep 443`命令查看端口开通情况 * 或者使用`telnet ip 443`查看端口开通情况 # test1 ## 1.1 [Section titled “1.1”](#11) * [x] 1 * [x] 2 * [x] 3 * [x] 4 * [x] 5 * [x] 6 * [x] 7 * [x] 8 * [x] 9 * [x] 10 * [x] 11 * \[\[test2.md]] # test2 ## 这里是测试2的二级标题 [Section titled “这里是测试2的二级标题”](#这里是测试2的二级标题) ### 这里是测试2的三级标题 [Section titled “这里是测试2的三级标题”](#这里是测试2的三级标题) #### 这里是测试2的四级标题 [Section titled “这里是测试2的四级标题”](#这里是测试2的四级标题) ##### 这里是测试2的五级标题 [Section titled “这里是测试2的五级标题”](#这里是测试2的五级标题) ###### 这里是测试2的六级标题 [Section titled “这里是测试2的六级标题”](#这里是测试2的六级标题) # virtualbox ## VirtualBox 启动时提示“获取 VirtualBox COM 对象失败”的解决 [Section titled “VirtualBox 启动时提示“获取 VirtualBox COM 对象失败”的解决”](#virtualbox-启动时提示获取-virtualbox-com-对象失败的解决) ```plaintext https://www.cnblogs.com/imzhi/p/solution-to-the-failed-to-get-the-virtualbox-com-object.html ``` ## 安装centos [Section titled “安装centos”](#安装centos) ```shell # 网络 # 启用3网卡(nat,桥接,host-only) # 启用2网卡(桥接,host-only) ``` ## 固定IP [Section titled “固定IP”](#固定ip) ```shell # 桥接网络 cd /etc/sysconfig/network-scripts/ vi ifcfg-enp0s3 TYPE="Ethernet" PROXY_METHOD="none" BROWSER_ONLY="no" # BOOTPROTO="dhcp" # 1 DEFROUTE="yes" IPV4_FAILURE_FATAL="no" IPV6INIT="yes" IPV6_AUTOCONF="yes" IPV6_DEFROUTE="yes" IPV6_FAILURE_FATAL="no" IPV6_ADDR_GEN_MODE="stable-privacy" NAME="enp0s3" UUID="ba47ac81-365b-42f7-b6a2-11b2865715ec" DEVICE="enp0s3" ONBOOT="yes" BOOTPROTO="static" # 2 IPADDR="10.0.0.91" # 3 ~ # 修改 1、2、3处即可 # 备注 IPADDR=192.168.1.123 #静态ip,添加前先ping一下该ip,ping不通才能使用,确保唯一 NETMASK=255.255.255.0 #子网掩码 GATEWAY=192.168.1.1 #网关 ``` # yum相关文档 ## yum源-使用阿里yum源 [Section titled “yum源-使用阿里yum源”](#yum源-使用阿里yum源) * [参考阿里开发者社区文章](https://developer.aliyun.com/mirror/centos) ```shell # centos8 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo yum clean all && yum makecache ``` ## EPEL到底是什么,为何经常要安装epel-release软件包 [Section titled “EPEL到底是什么,为何经常要安装epel-release软件包”](#epel到底是什么为何经常要安装epel-release软件包) * EPEL (Extra Packages for Enterprise Linux)是基于Fedora的一个项目 * [参考阿里云开发者社区文章](https://developer.aliyun.com/mirror/epel) ```shell yum -y install epel-release yum repolist ``` ```shell yum clean all yum makecache ``` ## centos7 安装epel-release rpm [Section titled “centos7 安装epel-release rpm”](#centos7-安装epel-release-rpm) ```shell Download the latest epel-release rpm from http://dl.fedoraproject.org/pub/epel/7/,下载rpm文件 Install epel-release rpm: # rpm -Uvh epel-release*rpm ``` ## fedora19安装后,需要安装的一些必备的软件包 [Section titled “fedora19安装后,需要安装的一些必备的软件包”](#fedora19安装后需要安装的一些必备的软件包) ```plaintext # 安装rpmfusion源 # Fedora 19的源: sudo yum localinstall --nogpgcheck http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-19.noarch.rpm http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-19.noarch.rpm # 安装一下有用的一些软件包 sudo yum -y install yum-fastestmirror unrar thunderbird emacs ibus-table \ redhat-lsb gstreamer-plugins-bad gstreamer-plugins-ugly gstreamer-ffmpeg \ compat-libstdc++-33 NetworkManager-devel python-gevent tracker-ui-tools qemu \ libpciaccess-devel xorg-x11-util-macros llvm-devel mtdev* mutt msmtp tftp \ tftp-server policycoreutils-gui mtd-utils mtd-utils-ubi vim ibus-pinyin \ gnome-tweak-tool ckermit stardict stardict-dic-zh_CN stardict-dic-en \ ibus-table-chinese-wubi-haifeng gnash smplayer vlc samba pidgin pidgin-sipe \ meld expect glibc-static ncurses-static genromfs cmake ccache p7zip nmap \ gstreamer1-plugins-bad-freeworld gstreamer1-plugins-ugly gstreamer1-libav # 升级一下系统: sudo yum -y update # 参考文章 https://www.cnblogs.com/lizhi0755/p/3308936.html ``` ## 向fedora添加rpmfusion源 [Section titled “向fedora添加rpmfusion源”](#向fedora添加rpmfusion源) ```plaintext # 有的rpmfusion地址有版本问题,找到一个比较好用的摘录一下: # 从http://download1.rpmfusion.org/的free和nofree库中fedora目录下载稳定版rpmfusion-free-release-stable.noarch.rpm和rpmfusion-nonfree-release-stable.noarch.rpm, 或者直接在线安装: rpm -Uvh http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-stable.noarch.rpm rpm -Uvh http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-stable.noarch.rpm # [stable]为版本号,无法安装的话,改成适合的版本号,例如35 ``` ## RPM Fusion [Section titled “RPM Fusion”](#rpm-fusion) * 由于版权问题,许多软件在Fedora中是没有的,如果我们想安装,我们需要添加或安装库,RPM Fusion是最好的,有两个RPM Fusion提供:免费和非免费。 * 我们可以使用下面的命令安装 ```plaintext dnf install --nogpgcheck http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-24.noarch.rpm dnf install --nogpgcheck http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-24.noarch.rpm ``` ## 安装WINE [Section titled “安装WINE”](#安装wine) * wine不是一个模拟器,它是一个开放源码软件,它允许使用的用户在非Microsoft Windows中运行微软程序。我们可以通过使用以下命令安装: ```plaintext dnf install wine ``` # actions-runner ## linux arm64版 [Section titled “linux arm64版”](#linux-arm64版) [GitHub设置路径](https://github.com/183461750/doc-record/settings/actions/runners/new?arch=arm64\&os=linux) Download ```bash # Create a folder $ mkdir actions-runner && cd actions-runner # Download the latest runner package $ curl -o actions-runner-linux-arm64-2.320.0.tar.gz -L https://github.com/actions/runner/releases/download/v2.320.0/actions-runner-linux-arm64-2.320.0.tar.gz # Optional: Validate the hash $ echo "bec1832fe6d2ed75acf4b7d8f2ce1169239a913b84ab1ded028076c9fa5091b8 actions-runner-linux-arm64-2.320.0.tar.gz" | shasum -a 256 -c # Extract the installer $ tar xzf ./actions-runner-linux-arm64-2.320.0.tar.gz ``` Configure ```bash # Create the runner and start the configuration experience $ ./config.sh --url https://github.com/183461750/doc-record --token AJCNPVIBLPPE3QLBOZQHPALHCPCYW # Last step, run it! $ ./run.sh ``` Using your self-hosted runner ```bash # Use this YAML in your workflow file for each job runs-on: self-hosted ``` # Last_SQL_Errno ## 部署MySQL [Section titled “部署MySQL”](#部署mysql) ```shell # mysql开启集群的sql命令 # 设置sql执行模式为幂等的(例如,insert主键冲突时,将sql改为delete加insert)(非必须) set global replica_exec_mode=idempotent; show global VARIABLES like "%exec_mode%"; # all 用于查看SOURCE_LOG_FILE和SOURCE_LOG_POS的值 show master status # host1执行 STOP REPLICA for channel 'channel1'; RESET REPLICA for channel 'channel1'; CHANGE REPLICATION SOURCE to SOURCE_HOST='mysql_m2',SOURCE_PORT=3306,SOURCE_LOG_FILE='binlog.000008',SOURCE_LOG_POS=156 for channel 'channel1'; RESET REPLICA for channel 'channel1'; START REPLICA USER='root' PASSWORD='root' for channel 'channel1'; # 查看状态。当看见Slave_IO_Running: YES、Slave_SQL_Running: YES时,主从复制即完成。 SHOW REPLICA STATUS; ########### # host2执行 STOP REPLICA for channel 'channel1'; RESET REPLICA for channel 'channel1'; CHANGE REPLICATION SOURCE to SOURCE_HOST='mysql_m1',SOURCE_PORT=3306,SOURCE_LOG_FILE='binlog.000008',SOURCE_LOG_POS=156 for channel 'channel1'; RESET REPLICA for channel 'channel1'; START REPLICA USER='root' PASSWORD='root' for channel 'channel1'; # 查看状态。当看见Slave_IO_Running: YES、Slave_SQL_Running: YES时,主从复制即完成。 SHOW REPLICA STATUS; ``` # Last\_SQL\_Errno [Section titled “Last\_SQL\_Errno”](#last_sql_errno) ```shell 1007:数据库已存在,创建数据库失败 1008:数据库不存在,删除数据库失败 1049:创建表时,发现数据库不存在 1050:数据表已存在,创建数据表失败 1051:数据表不存在,删除数据表失败 1054:字段不存在,或程序文件跟数据库有冲突 1060:字段重复,导致无法插入 1061:重复键名 1068:定义了多个主键 1094:位置线程ID 1146:数据表缺失,请恢复数据库 1053:复制过程中主服务器宕机 1062:主键冲突 Duplicate entry '%s' for key %d ``` # 启动集群 docker stack deploy -c kafka-compose.yml kafka # 启动集群(two) [Section titled “启动集群(two)”](#启动集群two) docker stack deploy —compose-file=kafka-docker-compose.yml tools # zk ## zk集群 配置文件中配置含义 [Section titled “zk集群 配置文件中配置含义”](#zk集群-配置文件中配置含义) ```shell vim zoo.cfg 加上以下三行配置 server.1=10.88.0.19:2888:3888;2181 server.2=10.88.0.20:2888:3888;2181 server.3=10.88.0.21:2888:3888;2181 这里10.88.0.X表示的是三台zookeeper容器对应的ip地址;2888是zookeeper容器间通信的端口,3888是zookeeper选举投票的端口,一般来说都是固定的 ``` # MyPerf4J是用记录 [github地址](https://github.com/LinShunKang/MyPerf4J) ## java-agent的使用 [Section titled “java-agent的使用”](#java-agent的使用) * 环境变量的配置 ```shell JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -javaagent:/Users/fa/dev/projects/java-agents/MyPerf4J-ASM-3.4.0-SNAPSHOT/MyPerf4J-ASM-3.4.0-SNAPSHOT.jar" ``` [MyPerf4J.properties配置文件内容](./java-agent/MyPerf4J.properties) ## influxdb安装 [Section titled “influxdb安装”](#influxdb安装) [docker快速部署](https://github.com/influxdata/sandbox.git) ```bash ./sandbox up ``` [docker镜像拉取失败的解决方案](https://github.com/183461750/docker-image-pusher/blob/70e22300d71cca30f14c4ab8e0a99cb9467734e2/README.md) ## grafana可视化界面安装 [Section titled “grafana可视化界面安装”](#grafana可视化界面安装) `docker-compose.yml`版 ```bash services: grafana: image: grafana/grafana:10.0.3 container_name: grafana ports: - 3000:3000 restart: always ``` # nacos记录 ## docker部署 [Section titled “docker部署”](#docker部署) [官网快速开始](https://nacos.io/docs/latest/quickstart/quick-start-docker/?spm=5238cd80.72a042d5.0.0.5bc0cd361NMDsf) 生成jwt secrets用于NACOS\_AUTH\_TOKEN ```bash # Linux / macOS openssl rand -base64 32 # Python 3 python -c "import base64, secrets; print(base64.b64encode(secrets.token_bytes(32)).decode())" # Windows PowerShell [Convert]::ToBase64String((New-Object byte[] 32).ForEach({[byte](Get-Random -Minimum 0 -Maximum 256)})) ``` ```bash docker run --name nacos-standalone-derby \ -e MODE=standalone \ -e NACOS_AUTH_TOKEN=Y3J5cHRvX3NlY3VyZV9rZXlfZm9yX25hY29zX2p3dF90b2tlbl8xMjM0NTY3ODkwYWJjZGVmZ2g= \ -e NACOS_AUTH_IDENTITY_KEY=nacos \ -e NACOS_AUTH_IDENTITY_VALUE=nacos \ -p 8080:8080 \ -p 8848:8848 \ -p 9848:9848 \ -d nacos/nacos-server:latest ``` # doc ## 参考 [Section titled “参考”](#参考) * # docker swarm版nacos ## 部署 [Section titled “部署”](#部署) ```shell ``` # nacos ## 快速开始 [Section titled “快速开始”](#快速开始) 打开命令窗口执行: * Clone project ```powershell git clone --depth 1 https://github.com/nacos-group/nacos-docker.git cd nacos-docker ``` * Standalone Derby ```powershell docker-compose -f example/standalone-derby.yaml up ``` # Nginx ## 构建nginx镜像 [Section titled “构建nginx镜像”](#构建nginx镜像) ```shell docker build -t nginx:1.0 . ``` ## nginx默认nginx.conf配置路径 [Section titled “nginx默认nginx.conf配置路径”](#nginx默认nginxconf配置路径) ```shell cat etc/nginx/nginx.conf cat etc/nginx/conf.d/default.conf ``` ## 代理Jenkins [Section titled “代理Jenkins”](#代理jenkins) * [参考文章](http://t.csdn.cn/CUODV) ## 配置ssl证书 [Section titled “配置ssl证书”](#配置ssl证书) * nginx查看是否安装http\_ssl\_module模块 ```shell #打开nginx的sbin文件夹 cd /usr/local/nginx/sbin/nginx #查看是否安装 nginx -V # 如果出现 configure arguments: --with-http_ssl_module, 则已安装(下面的步骤可以跳过,进入 nginx.conf 配置) ``` # 部署docker-registry相关文档 ## 使用Nginx代理 [Section titled “使用Nginx代理”](#使用nginx代理) * [参考文章](http://t.csdn.cn/36AL2) ```shell upstream docker-registry { server registry:5000; } ## Set a variable to help us decide if we need to add the ## 'Docker-Distribution-Api-Version' header. ## The registry always sets this header. ## In the case of nginx performing auth, the header is unset ## since nginx is auth-ing before proxying. map $upstream_http_docker_distribution_api_version $docker_distribution_api_version { '' 'registry/2.0'; } server { listen 443 ssl; server_name hub.vic.com; # SSL ssl_certificate /etc/nginx/conf.d/ca.crt; ssl_certificate_key /etc/nginx/conf.d/ca.key; # Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html ssl_protocols TLSv1.1 TLSv1.2; ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH'; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; # disable any limits to avoid HTTP 413 for large image uploads client_max_body_size 0; # required to avoid HTTP 411: see Issue #1486 (https://github.com/moby/moby/issues/1486) chunked_transfer_encoding on; location /v2/ { # Do not allow connections from docker 1.5 and earlier # docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) { return 404; } # To add basic authentication to v2 use auth_basic setting. ## If $docker_distribution_api_version is empty, the header is not added. ## See the map directive above where this variable is defined. add_header 'Docker-Distribution-Api-Version' $docker_distribution_api_version always; proxy_pass http://docker-registry; proxy_set_header Host $http_host; # required for docker client's sake proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 900; } } ``` * 生成自签名证书 ```shell # 将签名生成到conf.d目录中给Nginx使用,在conf.d目录的上级目录执行以下命令即可 # 创建自签名证书key文件 openssl genrsa -out conf.d/ca.key 2048 # 创建自签名证书crt文件 注意 /CN=docker-registry.iuin.xyz 字段中 docker-registry.iuin.xyz 修改为仓库名 openssl req -x509 -new -nodes -key conf.d/ca.key -subj "/CN=docker-registry.iuin.xyz" -days 5000 -out conf.d/ca.crt # 给docker 设置自签名证书 mkdir -p /etc/docker/certs.d/docker-registry.iuin.xyz cp conf.d/ca.crt /etc/docker/certs.d/docker-registry.iuin.xyz ``` * 测试 ```shell docker push busybox docker tag busybox:latest docker-registry.iuin.xyz/busybox:1.0 docker push docker-registry.iuin.xyz/busybox:1.0 ``` # nginx相关问题 ## 图片访问路径问题 [Section titled “图片访问路径问题”](#图片访问路径问题) ```shell # 访问路径: www.images.mbox58.com/images/aaa/1.jpg # 使用root(/www/wwwroot/images/images/~~~) location /images { root /www/wwwroot/images/; autoindex on; } # 使用alias(/www/wwwroot/images/~~~) location /images { alias /www/wwwroot/images/; # 后面的(/)需要带上 autoindex on; } ``` ## 431 请求头太大问题 [Section titled “431 请求头太大问题”](#431-请求头太大问题) * 431 Request Header Fields Too Large ```shell http { client_header_buffer_size 10240k; large_client_header_buffers 6 10240k; } ``` ## nginx导致中文字符乱码问题 [Section titled “nginx导致中文字符乱码问题”](#nginx导致中文字符乱码问题) ```shell # 该配置,如果url路径上有中文会导致中文字符乱码问题 # http://10.0.0.73:10000/apidomain/down/download/report/2022/4/22/参与人积分统计_20220422151521309.csv location ~ ^/apidomain(.*) { include cors.conf; proxy_set_header Host $host; proxy_set_header X-real-ip $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://web-api:8080$1?$args; } # 解决方法: 使用以下方式替换即可 location /apidomain/ { include cors.conf; proxy_set_header Host $host; proxy_set_header X-real-ip $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://web-api:8080/; } ``` # nginx-ui [参考文章](https://mp.weixin.qq.com/s/sTsrkRqakj6X_iJAU2Nn3w) ## 安装 [Section titled “安装”](#安装) 8080/install. ```bash docker-compose up -d ``` # nginx使用记录 * 先启动nginx-common.yml后,再将templates目录里的内容复制到数据卷volumes的nginx\_templates中的\_data目录中 # nginx模板配置 * [参考文章](https://hub.docker.com/_/nginx) # doc ## 配置说明 [Section titled “配置说明”](#配置说明) ```shell # rabbitmq:3.8.6-management:后面带management是带web管理界面的 # RABBITMQ_DEFAULT_USER:默认账号和密码是:guest # RABBITMQ_DEFAULT_PASS:设置密码 ``` # deploy ## broker.conf [Section titled “broker.conf”](#brokerconf) ```plaintext # 设置宿主机ip brokerIP1=manager ``` ## 查看节点名称 [Section titled “查看节点名称”](#查看节点名称) ```shell docker node ls ``` ## 节点打标 [Section titled “节点打标”](#节点打标) ```shell docker node update --label-add role=标签名称 宿主机A节点名称 ``` # telegraf是用记录 [相关资料1](https://github.com/influxdata/sandbox.git) [相关资料2](https://github.com/LinShunKang/MyPerf4J/wiki/Telegraf_) ## 简单运行 [Section titled “简单运行”](#简单运行) ```bash docker run -d --name=telegraf \ -v $PWD/conf/telegraf.conf:/etc/telegraf/telegraf.conf:ro \ -v /tmp/MyPerf4J/data/logs/MyPerf4J:/tmp/MyPerf4J/data/logs/MyPerf4J:ro \ telegraf ``` # zipkin ## simple [Section titled “simple”](#simple) ```shell https://github.com/openzipkin-attic/docker-zipkin.git ``` # k8s dashboard ## 部署 Dashboard UI [Section titled “部署 Dashboard UI”](#部署-dashboard-ui) ```shell kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml ``` ## 创建用户 [Section titled “创建用户”](#创建用户) ```shell # dashboard-ClusterRoleBinding.yaml kubectl apply -f dashboard-ClusterRoleBinding.yaml # dashboard-ServiceAccount.yaml kubectl apply -f dashboard-ServiceAccount.yaml # Getting a Bearer Token kubectl -n kubernetes-dashboard create token admin-user # Clean up and next steps kubectl -n kubernetes-dashboard delete serviceaccount admin-user kubectl -n kubernetes-dashboard delete clusterrolebinding admin-user ``` ## 命令行代理 [Section titled “命令行代理”](#命令行代理) ```shell kubectl proxy # PS: kubectl 会使得 Dashboard 可以通过 http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/ 访问。 ``` ## 部署MySQL [Section titled “部署MySQL”](#部署mysql) ./deploy/mysql.yml ```yaml ``` # jenkins的使用 ## helm方式部署 [Section titled “helm方式部署”](#helm方式部署) ```bash # 添加Jenkins仓库: helm repo add jenkinsci https://charts.jenkins.io && helm repo update # 部署Jenkins: helm install jenkins jenkinsci/jenkins # 检查Jenkins:使用helm list命令检查Jenkins的部署状态,并使用kubectl get pod命令检查Jenkins的Pod状态 # 查看ip和端口 kubectl get svc jenkins # 端口映射 kubectl --namespace default port-forward svc/jenkins 8080:8080 # 查看备注信息 helm get notes jenkins # 卸载Jenkins helm uninstall jenkins ``` # logstash使用记录 ## 安装 [Section titled “安装”](#安装) * helm安装 * [参考文章](https://segmentfault.com/a/1190000044266596) ```shell helm repo add bitnami https://charts.bitnami.com/bitnami helm search repo logstash helm pull bitnami/logstash ``` * 配置文件 * [values.yaml](./config/6.0.3-values.yaml) ```shell helm install -f ./config/6.0.3-values.yaml logstash bitnami/logstash --namespace middleware helm install logstash bitnami/logstash --namespace middleware ``` # Harbor使用记录 ## 安装 [Section titled “安装”](#安装) * [官网](https://goharbor.io/docs/2.10.0/install-config/harbor-ha-helm/) * [values.yaml](https://github.com/goharbor/harbor-helm/blob/main/values.yaml) ```bash # 创建命名空间 kubectl create namespace harbor helm repo add harbor https://helm.goharbor.io helm fetch harbor/harbor --untar # 安装 helm install harbor-helm harbor/ # 卸载 helm uninstall harbor-helm # 自定义安装(--set配置参考`values.yaml`) helm install harbor-helm harbor/harbor \ --set database.type=external \ --set database.external.host=10.0.0.11 \ --set database.external.username=dbadmin \ --set database.external.password=dbadmin \ --set redis.type=external \ --set redis.external.addr=10.0.0.23:6379 \ --set redis.external.password=foobared \ --set harborAdminPassword=Harbor12345 \ --set externalURL=http://core.harbor.domain \ --set expose.tls.enabled=false \ --set expose.type=loadBalancer \ --set ipFamily.ipv6.enabled=false # 访问, 使用以下命令, 或vscode中使用插件界面中操作代理到本地(admin/Harbor12345) kubectl port-forward pods/harbor-helm-nginx-cc76b85fb-mzj7z 8080:8080 -n harbor6 # 查看密码, 进入harbor-core的pod中执行命令 printenv |grep PASSWORD ## PS: 查看日志发现, 需要手动创建PersistentVolume ## PS: 查看日志发现(用 kubectl logs , 或者vscode插件界面查看), 需要手动创建数据库registry # \ # --set expose.tls.enabled=false # 更新 helm upgrade --namespace harbor5 harbor-helm harbor/harbor -f ~/harbor/values.yaml helm upgrade --namespace harbor5 harbor-helm harbor/harbor \ --set database.type=external \ --set database.external.host=10.0.0.11 \ --set database.external.username=dbadmin \ --set database.external.password=dbadmin \ --set redis.type=external \ --set redis.external.addr=10.0.0.23:6379 \ --set redis.external.password=foobared \ --set harborAdminPassword=Harbor12345 \ --set externalURL=http://core.harbor.domain \ --set expose.tls.enabled=false \ --set expose.type=loadBalancer \ --set ipFamily.ipv6.enabled=false # test示例 # 镜像上传需要harbor-helm-core的pod上传, portal为管理页面 --set externalURL=http://core.harbor.domain.harbor6:8080 \ helm upgrade --namespace harbor6 harbor-helm harbor/harbor \ --set database.type=external \ --set database.external.host=10.0.0.11 \ --set database.external.username=dbadmin \ --set database.external.password=dbadmin \ --set redis.type=external \ --set redis.external.addr=10.0.0.23:6379 \ --set redis.external.password=foobared \ --set harborAdminPassword=Harbor12345 \ --set externalURL=http://core.harbor.domain.harbor6:8080 \ --set expose.tls.enabled=false \ --set expose.type=loadBalancer \ --set ipFamily.ipv6.enabled=false # test示例二, 配合kt-connect使用 sudo ktctl connect -n harbor6 # 镜像上传需要harbor-helm-core的pod上传, portal为管理页面 --set externalURL=http://harbor-helm-core.harbor6 \ helm upgrade --namespace harbor6 harbor-helm harbor/harbor \ --set database.type=external \ --set database.external.host=10.0.0.11 \ --set database.external.username=dbadmin \ --set database.external.password=dbadmin \ --set redis.type=external \ --set redis.external.addr=10.0.0.23:6379 \ --set redis.external.password=foobared \ --set harborAdminPassword=Harbor12345 \ --set externalURL=http://harbor-helm-core.harbor6 \ --set expose.tls.enabled=false \ --set expose.type=loadBalancer \ --set ipFamily.ipv6.enabled=false # 测试连通性 curl http://harbor-helm-core.harbor6/v2/ # test示例三, 配合kt-connect使用 sudo ktctl connect -n harbor6 helm upgrade --namespace harbor6 harbor-helm harbor/harbor \ --set database.type=external \ --set database.external.host=10.0.0.11 \ --set database.external.username=dbadmin \ --set database.external.password=dbadmin \ --set redis.type=external \ --set redis.external.addr=10.0.0.23:6379 \ --set redis.external.password=foobared \ --set harborAdminPassword=Harbor12345 \ --set externalURL=http://harbor.harbor6 \ --set expose.tls.enabled=false \ --set expose.type=loadBalancer \ --set ipFamily.ipv6.enabled=false # 测试连通性 curl http://harbor.harbor6/v2/ # --- # 暴露端口, 会创建个service kubectl expose deployment harbor-helm-core --port=80 --target-port=8080 ``` * 生成ssl ```bash sudo mkdir -p /etc/harbor/ssl/ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/harbor/ssl/harbor.key -out /etc/harbor/ssl/harbor.crt ``` ```bash # (参考文章)[https://wghdr.top/?p=3700] # test示例四, cert-manage自动管理ssl(有点问题) helm upgrade --namespace harbor6 harbor-helm harbor/harbor \ --set database.type=external \ --set database.external.host=10.0.0.11 \ --set database.external.username=dbadmin \ --set database.external.password=dbadmin \ --set redis.type=external \ --set redis.external.addr=10.0.0.23:6379 \ --set redis.external.password=foobared \ --set harborAdminPassword=Harbor12345 \ --set externalURL=core.harbor.domain \ --set expose.tls.auto.commonName=letsencrypt-harbor \ --set expose.ingress.hosts.core=core.harbor.domain \ --set expose.ingress.annotations.kubernetes.io/tls-acme=true \ --set expose.ingress.annotations.certmanager.k8s.io/issuer=letsencrypt-harbor # 检查 kubectl get ing -n harbor6 -o yaml | grep -A 3 tls kubectl get secret -n harbor6 harbor-ingress -o yaml # 配置nginx.ingress.kubernetes.io/proxy-body-size=500M, 不然上传镜像可能报错 ``` * 创建初始化容器, 给trivy调整文件夹权限 [参考链接](https://github.com/goharbor/harbor-helm/issues/1084) ![初始化容器配置](/_astro/image.B_qDFScE_Z1Xm25a.webp) ![挂载卷配置](/_astro/image-1.BG445tzS_150FVH.webp) ```bash initContainers: - name: trivy-permission-fix securityContext: runAsUser: 0 # Run as root user image: busybox command: ['sh', '-c', 'chown -R 10000:10000 /home/scanner'] volumeMounts: - name: data mountPath: /home/scanner ``` * 构建并上传镜像 [demo](https://goharbor.io/docs/2.10.0/install-config/demo-server/) ```bash # 打标 docker tag SOURCE_IMAGE[:TAG] core.harbor.domain/mall/REPOSITORY[:TAG] # 推送 docker push core.harbor.domain/mall/REPOSITORY[:TAG] # 示例 docker login -u admin -p Harbor12345 core.harbor.domain:8080 docker tag app-service:latest core.harbor.domain:8080/mall/app-service:latest docker push core.harbor.domain:8080/mall/app-service:latest ``` ```bash # 配置本地hosts(code /etc/hosts) 127.0.0.1 harbor.harbor6 # 转发端口到本地(PS: 由于没有kubectl, 用的docker加alias实现的[参考文档](https://github.com/183461750/doc-record/blob/b9d7b122aa78712f6106df23f92518a0bfc199be/k8s/kubectl.md)) kubectl port-forward pods/harbor-helm-nginx-cc76b85fb-mzj7z 80:8080 -n harbor6 docker login -u admin -p Harbor12345 harbor.harbor6 # 拉取镜像 docker pull harbor.harbor6/mall/app-service:latest ``` * k8s中拉取镜像 ```bash # 转发端口 kubectl port-forward pods/harbor-helm-nginx-cc76b85fb-mzj7z 80:8080 -n harbor6 # 配置本地hosts(code /etc/hosts) 127.0.0.1 harbor.harbor6 # 设置不安全容器镜像仓库[参考文档](https://github.com/183461750/doc-record/blob/c80d519ba5e1d55e5ee385a867211800ea118c4b/k8s/crictl.md) # 拉取镜像 crictl pull harbor.harbor6/mall/app-service:latest ``` * NodePort服务类型的访问 * 在kuboard中配置 ![service配置](/_astro/image-2.BYky9t3v_1HXo07.webp) ```bash # 配置本地hosts(code /etc/hosts)(PS: 配置多个IP对应一个域名会随机选择一个IP进行访问) 10.0.1.139 harbor.harbor6 10.0.1.177 harbor.harbor6 ``` * 镜像拉取超时的问题 ```bash wget https://github.com/goharbor/harbor/releases/download/v2.9.1/harbor-offline-installer-v2.9.1.tgz tar xvf harbor-offline-installer-v2.9.1.tgz cd harbor nerdctl -n k8s.io load -i harbor.v2.9.1.tar.gz ``` # kuboard使用 ## 使用helm的方式部署 [Section titled “使用helm的方式部署”](#使用helm的方式部署) ```bash # 添加Kuboard的Helm仓库。在命令行中执行以下命令 helm repo add kuboard https://kuboard.cn/charts helm repo update # 创建一个命名空间用于安装Kuboard。 kubectl create namespace kuboard # 安装Kuboard。 helm install kuboard kuboard/kuboard --namespace kuboard # 等待安装完成。您可以使用以下命令检查Kuboard的安装状态: kubectl get pods -n kuboard # 访问Kuboard。您可以使用以下命令获取Kuboard的访问地址: kubectl get svc -n kuboard ``` # metersphere使用 ## k8s部署 [Section titled “k8s部署”](#k8s部署) ```bash kubectl create ns ms helm repo add bitnami https://charts.bitnami.com/bitnami helm repo add metersphere https://metersphere.github.io/helm-chart/ # 从 chart 仓库中更新本地可用chart的信息 helm repo update helm install metersphere metersphere/metersphere -n ms # 创建 Node Port 访问方式 ## 使用命令 kubectl get svc -n ms 可查看 metersphere-gateway 所占用的端口号。如果不使用 ingress 的访问方式,可以创建一个 nodeport。 vi ms-gateway-nodeport.yaml apiVersion: v1 kind: Service metadata: name: metersphere-gateway-nodeport namespace: ms spec: ports: - name: metersphere-gateway protocol: TCP port: 8000 targetPort: 8000 nodePort: 30801 type: NodePort selector: app: metersphere-gateway kubectl create -f ms-gateway-nodeport.yaml 访问 MeterSphere 页面: http://nodeIP:30801 ``` # mq ## rocketmq [Section titled “rocketmq”](#rocketmq) [官方地址](https://rocketmq.apache.org/docs/quickStart/04quickstartWithHelmInKubernetes) ```bash # Download RocketMQ Helm Chart helm pull oci://registry-1.docker.io/apache/rocketmq --version 0.0.1 tar -zxvf rocketmq-0.0.1.tgz # Deploy RocketMQ # Modify the configuration in values.yaml vim values.yaml ## values.yaml, adjust memory requests and limits in broker resources according to available memory size ## resources: limits: cpu: 2 memory: 10Gi requests: cpu: 2 memory: 10Gi ##values.yaml## helm install rocketmq-demo ./rocketmq # Check pod status # If the parameters are normal, it indicates successful deployment kubectl get pods -o wide -n default # NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES # rocketmq-demo-broker-0 1/1 Running 0 6h3m 192.168.58.225 k8s-node02 # rocketmq-demo-nameserver-757877747b-k669k 1/1 Running 0 6h3m 192.168.58.226 k8s-node02 # rocketmq-demo-proxy-6c569bd457-wcg6g 1/1 Running 0 6h3m 192.168.85.227 k8s-node01 ``` # nacos使用记录 * [参考](https://nacos.io/en/docs/latest/quickstart/quick-start-kubernetes/) ```shell git clone https://github.com/nacos-group/nacos-k8s.git cd nacos-k8s chmod +x quick-startup.sh ./quick-startup.sh ``` # portainer使用记录 ## 安装 [Section titled “安装”](#安装) ```bash # 部署 kubectl apply -f portainer.yaml # 查看状态 kubectl get pvc -n default # 访问 http://portainer.default.svc.cluster.local:9000 ``` # 注入代理相关文档 ## 前置条件 [Section titled “前置条件”](#前置条件) 已经安装了[cert-manager](https://github.com/183461750/doc-record/blob/4ed197082e57f368c4eebf6b91e9c1260f6ae8c5/k8s/docs/cert-manager/doc.md) ## 安装包获取 [Section titled “安装包获取”](#安装包获取) SkyWalking SWCK 0.9.0 发行包由 Apache 官方归档托管,仓库内不再保留二进制副本。 * Apache 归档(推荐): * 镜像选择页: 下载与解压: ```bash wget https://archive.apache.org/dist/skywalking/swck/0.9.0/skywalking-swck-0.9.0-bin.tgz tar -xzf skywalking-swck-0.9.0-bin.tgz ``` 完整性校验(MD5):`548cf3a09829bf0d32c564c7b31986ae` ## 安装skywalking-swck-operator [Section titled “安装skywalking-swck-operator”](#安装skywalking-swck-operator) [参考文档](https://github.com/apache/skywalking-swck/blob/master/docs/operator.md) ```bash # 使用下载的配置(需先解压)(./skywalking-swck)(推荐使用) kubectl apply -f skywalking-swck--bin/config/operator-bundle.yaml kubectl apply -f skywalking-swck/skywalking-swck-0.9.0-bin/config/operator-bundle.yaml # 下面这个方式貌似有问题 kubectl apply -k "github.com/apache/skywalking-swck/operator/config/default" # or kubectl apply -k "github.com/apache/skywalking-swck/operator/config/default?ref=v0.8.0" ``` * `gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0`镜像拉不下来的问题处理 [参考文章](https://juejin.cn/post/7099354856078442509) 可以使用`kubesphere/kube-rbac-proxy:v0.8.0`进行替代 ```bash docker pull kubesphere/kube-rbac-proxy:v0.8.0 docker tag kubesphere/kube-rbac-proxy:v0.8.0 gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0 # 或者修改部署配置文件, 改变拉取的镜像 ``` ## 安装Custom Metrics Adapter [Section titled “安装Custom Metrics Adapter”](#安装custom-metrics-adapter) [参考文档](https://github.com/apache/skywalking-swck/blob/master/docs/custom-metrics-adapter.md) 在 skywalking-swck 中,Custom Metrics Adapter 是一个可选组件,用于扩展 SkyWalking 的监控能力。它允许你使用 Kubernetes 的 Custom Metrics API 来收集和展示自定义的监控指标。 ```bash kubectl apply -k "github.com/apache/skywalking-swck/adapter/config" # or kubectl apply -k "github.com/apache/skywalking-swck/adapter/config?ref=v0.8.0" ``` ## 安装注入代理 [Section titled “安装注入代理”](#安装注入代理) ```bash # 启动测试demo应用 kubectl apply -f demo1.yaml # Label the namespace with swck-injection=enabled kubectl label namespace skywalking swck-injection=enabled kubectl -n skywalking patch deployment demo1 --patch '{ "spec": { "template": { "metadata": { "labels": { "swck-java-agent-injected": "true" } } } } }' # 查看被打标的pods kubectl get pod -l swck-java-agent-injected=true # 查看javaagent kubectl get javaagent # 查看javaagent详情 kubectl get javaagent app-demo1-javaagent -o yaml # Use SwAgent CR to setup override default configuration kubectl -n skywalking apply -f swagent.yaml # 查看 kubectl -n skywalking get SwAgent # 查看并重启 # verify pods to be delete kubectl -n skywalking get pods -l app=demo1 # delete pods kubectl -n skywalking delete pods -l app=demo1 # 到skywalking上应该就能看到这个服务了 ``` # skywalking使用记录 ## 安装 [Section titled “安装”](#安装) * 快速开始 [Quick Start](https://skywalking.apache.org/docs/skywalking-showcase/next/readme/#quick-start) ```bash git clone https://github.com/apache/skywalking-showcase.git cd skywalking-showcase make deploy.kubernetes ``` [skywalking-helm](https://github.com/apache/skywalking-helm/tree/v4.5.0) ```bash # 创建命名空间 kubectl create namespace skywalking # 设置环境变量 export SKYWALKING_RELEASE_VERSION=4.3.0 export SKYWALKING_RELEASE_NAME=skywalking export SKYWALKING_RELEASE_NAMESPACE=skywalking # 执行安装 helm install "${SKYWALKING_RELEASE_NAME}" \ oci://registry-1.docker.io/apache/skywalking-helm \ --version "${SKYWALKING_RELEASE_VERSION}" \ -n "${SKYWALKING_RELEASE_NAMESPACE}" \ --set oap.image.tag=9.2.0 \ --set oap.storageType=elasticsearch \ --set ui.image.tag=9.2.0 ``` * 使用 master 分支安装 SkyWalking 的开发版本 ```bash export REPO=chart git clone https://github.com/apache/skywalking-kubernetes cd skywalking-kubernetes helm repo add elastic https://helm.elastic.co helm dep up ${REPO}/skywalking ``` * 使用现有 Elasticsearch 安装特定版本的 SkyWalking 修改文件 values-my-es.yaml 中已有 elasticsearch 集群的连接信息。 - [values-my-es.yaml](https://github.com/apache/skywalking-helm/blob/v4.5.0/chart/skywalking/values-my-es.yaml) ```bash export SKYWALKING_RELEASE_NAME=skywalking export SKYWALKING_RELEASE_NAMESPACE=skywalking export REPO=chart git clone https://github.com/apache/skywalking-kubernetes cd skywalking-kubernetes helm install "${SKYWALKING_RELEASE_NAME}" ${REPO}/skywalking -n "${SKYWALKING_RELEASE_NAMESPACE}" \ -f ./${REPO}/skywalking/values-my-es.yaml ``` ```bash # 方式二(目前用的方式) # 设置环境变量 export SKYWALKING_RELEASE_VERSION=4.3.0 export SKYWALKING_RELEASE_NAME=skywalking export SKYWALKING_RELEASE_NAMESPACE=skywalking export ELASTICSEARCH_CONFIG_HOST=10.0.1.90 helm install "${SKYWALKING_RELEASE_NAME}" \ oci://registry-1.docker.io/apache/skywalking-helm \ --version "${SKYWALKING_RELEASE_VERSION}" \ -n "${SKYWALKING_RELEASE_NAMESPACE}" \ --set oap.image.tag=9.2.0 \ --set oap.storageType=elasticsearch \ --set elasticsearch.enabled=false \ --set elasticsearch.config.host="${ELASTICSEARCH_CONFIG_HOST}" \ --set elasticsearch.config.user="" \ --set elasticsearch.config.password="" \ --set ui.image.tag=9.2.0 ``` ```bash # 设置环境变量 export SKYWALKING_RELEASE_NAME=skywalking export SKYWALKING_RELEASE_NAMESPACE=skywalking helm upgrade "${SKYWALKING_RELEASE_NAME}" \ oci://registry-1.docker.io/apache/skywalking-helm \ --version "4.5.0" \ -n "${SKYWALKING_RELEASE_NAMESPACE}" \ --set oap.image.repository="apache/skywalking-oap-server" \ --set oap.image.tag=latest \ --set oap.storageType=elasticsearch \ --set elasticsearch.enabled=false \ --set elasticsearch.config.host="10.0.1.90" \ --set elasticsearch.config.user="" \ --set elasticsearch.config.password="" \ --set ui.image.repository="apache/skywalking-ui" \ --set ui.image.tag=latest \ --set satellite.enabled=true \ --set satellite.image.repository="apache/skywalking-satellite" \ --set satellite.image.tag=v1.2.0 ``` # 容器版windows [GitHub地址](https://github.com/dockur/windows) ```bash kubectl apply -f https://raw.githubusercontent.com/dockur/windows/refs/heads/master/kubernetes.yml ``` # k8s容器运行时命令行工具 containerd运行时 ```bash # 列出所有容器 crictl ps ``` * 配置不安全的镜像仓库 ```bash mkdir /etc/containerd/ # 写入默认配置 containerd config default > /etc/containerd/config.toml # 修改配置文件 # [plugins."io.containerd.grpc.v1.cri".registry] # [plugins."io.containerd.grpc.v1.cri".registry.mirrors] # [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] # endpoint = ["https://registry-1.docker.io"] # 添加以下内容 # [plugins."io.containerd.grpc.v1.cri".registry.mirrors."harbor.harbor6"] # endpoint = ["http://harbor.harbor6"] # 重启下 systemctl daemon-reload systemctl restart containerd.service ``` ```bash # 带端口的配置 [plugins."io.containerd.grpc.v1.cri".registry.mirrors."harbor.harbor6:30003"] endpoint = ["http://harbor.harbor6:30003"] ``` # cert-manager使用记录 [参考地址](https://cert-manager.io/docs/installation/) ## 安装 [Section titled “安装”](#安装) ```bash kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.4/cert-manager.yaml ``` * helm方式安装 ```bash helm repo add jetstack https://charts.jetstack.io --force-update helm repo update helm install \ cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --version v1.14.4 \ # --set installCRDs=true ``` # 卸载 [Section titled “卸载”](#卸载) ```bash # 检查 kubectl get Issuers,ClusterIssuers,Certificates,CertificateRequests,Orders,Challenges --all-namespaces # Uninstalling with Helm helm --namespace cert-manager delete cert-manager kubectl delete namespace cert-manager # Uninstalling with kubectl kubectl delete -f https://github.com/cert-manager/cert-manager/releases/download/vX.Y.Z/cert-manager.crds.yaml kubectl delete apiservice v1beta1.webhook.cert-manager.io ``` # ClusterIssuer记录 ```bash # 安装 kubectl apply -f ClusterIssuer.yaml # 查看(kuboard中的集群管理->自定义资源->cert-manager.io中也能看到) kubectl get ClusterIssuer ``` * [参考](https://help.aliyun.com/zh/ack/ack-managed-and-ack-dedicated/user-guide/advanced-nginx-ingress-configurations#title-v89-nee-iuh) ```bash # 创建ClusterIssuer cat < # 替换为您的邮箱名。 privateKeySecretRef: name: letsencrypt-http01 solvers: - http01: ingress: class: nginx EOF # 查看ClusterIssuer kubectl get clusterissuer # 创建Nginx Ingress资源对象 cat < # 替换为您的域名。 secretName: ingress-tls rules: - host: # 替换为您的域名。 http: paths: - path: / backend: service: name: # 替换为您的后端服务名。 port: number: # 替换为您的服务端口。 pathType: ImplementationSpecific EOF ``` # k8s使用记录 ## 存储卷 [Section titled “存储卷”](#存储卷) 默认储存类 ```bash # 安装 Local Path Provisioner kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.37/deploy/local-path-storage.yaml # dev版 # kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml # 将其设置为“全局默认存储类” kubectl patch storageclass local-path -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}' # 删除 kubectl delete -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.37/deploy/local-path-storage.yaml ``` # Node Debug 通过 DaemonSet + `nsenter` 实现 Kubernetes 节点的**无 SSH 应急救援**。Pod 以最小权限(仅 `CAP_SYS_ADMIN`)运行,`kubectl exec` 进入后执行 `nsenter -t 1 -a` 即可穿透到宿主机上下文。 ## 前置知识 [Section titled “前置知识”](#前置知识) 核心机制基于 Linux namespace 穿透工具 `nsenter`,必须先理解 [nsenter 的 `-m` 分水岭](https://github.com/iuin8/doc-record/blob/main/docs/os/linux/process/nsenter.md#-m-%E5%8F%82%E6%95%B0%E5%91%BD%E4%BB%A4%E6%9D%A5%E6%BA%90%E7%9A%84%E5%88%86%E6%B0%B4%E5%B2%AD) 才能正确使用本方案。 ## 架构 [Section titled “架构”](#架构) ```mermaid flowchart LR subgraph Cluster["Kubernetes 集群"] subgraph Node["目标节点"] Host["宿主机
(systemd, kubelet, 物理网卡)"] Debug["node-debug Pod
hostPID + CAP_SYS_ADMIN"] end User["运维人员"] -->|kubectl exec| Debug Debug -->|"nsenter -t 1 -a
(全量: 接管宿主机)"| Host Debug -.->|"nsenter -t 1 -n
(精细: 容器工具 + 宿主机网络)"| Host end ``` 两种穿透模式: | 模式 | 命令 | 命令来源 | 适用场景 | | -------- | ----------------- | ------------- | --------------------------------- | | **全量接管** | `nsenter -t 1 -a` | 宿主机 | 重启 kubelet、查系统日志、磁盘排查 | | **精细穿透** | `nsenter -t 1 -n` | 容器 (netshoot) | 宿主机精简无诊断工具,借用 netshoot 工具抓宿主机网卡流量 | ## 部署 [Section titled “部署”](#部署) ```bash # 部署到所有节点(容忍所有污点,包括 control-plane) kubectl apply -f node-debug.yaml # 如需限定范围,先给目标节点打标签,再解开 YAML 中 nodeSelector 的注释 kubectl label node debug=true ``` ?> 镜像使用 `nicolaka/netshoot`,集成了 `nsenter`、`tcpdump`、`iproute2`、`curl`、`jq`、`strace`。选择 netshoot 而非 alpine 的核心原因:[宿主机可能是精简系统,没装诊断工具](https://github.com/iuin8/doc-record/blob/main/docs/os/linux/process/nsenter.md#%E5%9C%BA%E6%99%AF%E4%BA%8C%E7%B2%BE%E7%BB%86%E7%A9%BF%E9%80%8F--%E5%80%9F%E7%94%A8%E5%AE%B9%E5%99%A8%E5%B7%A5%E5%85%B7%E8%AF%8A%E6%96%AD%E5%AE%BF%E4%B8%BB%E6%9C%BA%E7%BD%91%E7%BB%9C)。 ## 使用方式 [Section titled “使用方式”](#使用方式) ```bash # 1. 定位目标节点上的调试 Pod kubectl get pod -n kube-system -l app=node-debug -o wide | grep # 2. 进入 Pod kubectl exec -it -n kube-system -- bash ``` 进入 Pod 后,根据故障类型选择穿透模式: ### 模式 A:全量接管(服务崩溃、系统日志、磁盘问题) [Section titled “模式 A:全量接管(服务崩溃、系统日志、磁盘问题)”](#模式-a全量接管服务崩溃系统日志磁盘问题) ```bash # 加了 -m,命令全部来自宿主机 nsenter -t 1 -a bash # 此时可以: systemctl restart kubelet journalctl -u kubelet -f crictl ps -a cat /var/log/messages df -h dmesg -T | tail -50 ``` ### 模式 B:精细穿透(网络问题,宿主机没装工具) [Section titled “模式 B:精细穿透(网络问题,宿主机没装工具)”](#模式-b精细穿透网络问题宿主机没装工具) ```bash # 不加 -m!文件系统留在容器,只有网络切到宿主机 # 敲的每个命令都来自 netshoot,但看到的是宿主机真实网络 nsenter -t 1 -n # netshoot 自带、但宿主机可能缺失的工具: tcpdump -i eth0 -w /tmp/node.pcap iperf3 -c curl -v https:// ss -tlnp ip route show ``` > **选择逻辑**:先试模式 A(`-a`)。如果发现宿主机缺工具(如 `tcpdump: command not found`),退到模式 B(`-n`),用 netshoot 自带的工具来诊断。 ## 诊断命令速查(全量接管模式) [Section titled “诊断命令速查(全量接管模式)”](#诊断命令速查全量接管模式) ```bash # --- 容器运行时 --- crictl ps -a # 所有容器(含已停止) crictl inspect # 容器详情 crictl logs # 容器日志 crictl stats # 容器资源使用 # --- Kubelet --- systemctl status kubelet journalctl -u kubelet --since "10 min ago" -f # --- 网络 --- ip addr show ip route show conntrack -L -s # 连接跟踪(排查 Service NAT) iptables -t nat -L -n -v # iptables 规则(排查 Service 转发) ss -tlnp # --- 存储 --- lsblk # 块设备 df -h lsof | grep deleted # 已删除但仍占用的文件 du -sh /var/lib/containers/* # --- 资源 --- free -h nproc dmesg -T | tail -50 # 内核日志(OOM 等) ``` ## 从宿主机进入指定容器 [Section titled “从宿主机进入指定容器”](#从宿主机进入指定容器) 穿透到宿主机后(模式 A),可进一步反向进入容器 namespace: ```bash # 拿到目标容器 PID CONTAINER_PID=$(crictl inspect | jq -r '.info.pid') # 只进网络:用宿主机 tcpdump 抓容器包 nsenter -t $CONTAINER_PID -n tcpdump -i eth0 # 只进文件系统:操作容器文件 nsenter -t $CONTAINER_PID -m ls /app/config # 全进:等同于 docker exec nsenter -t $CONTAINER_PID -a bash ``` ## 安全考量 [Section titled “安全考量”](#安全考量) | 维度 | 措施 | | -------- | ------------------------------------------------------- | | **范围控制** | 默认全节点部署;生产环境可启用 `nodeSelector: debug=true` 仅在需要时打标签 | | **访问控制** | `kubectl exec` 依赖 namespace 级 `pods/exec` RBAC,由集群管理员控制 | | **审计追溯** | 所有 exec 操作记录在 Kubernetes audit log 中 | | **替代方案** | K8s 1.25+ 支持 `kubectl debug node/` 创建临时 Pod,无需预部署 | ### 临时 Pod(无需预部署) [Section titled “临时 Pod(无需预部署)”](#临时-pod无需预部署) ```bash kubectl debug node/ -it --image=nicolaka/netshoot:v0.13 -- bash ``` !> `kubectl debug node` 便捷但 Pod 生命周期短。建议在集群初始化时预部署 DaemonSet 作为常驻应急入口。 # 问题记录 Failed to create pod sandbox: rpc error: code = Unknown desc = failed to get sandbox image “k8s.gcr.io/pause:3.2”: failed to pull image “k8s.gcr.io/pause:3.2”: failed to pull and unpack image “k8s.gcr.io/pause:3.2”: failed to resolve reference “k8s.gcr.io/pause:3.2”: failed to do request: Head “”: dial tcp 173.194.174.82:443: i/o timeout ```shell crictl pull registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2 ctr -n k8s.io i tag registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2 k8s.gcr.io/pause:3.2 ``` # Telepresence 使用记录 ## Telepresence Quick Start [Section titled “Telepresence Quick Start”](#telepresence-quick-start) [Telepresence Quick Start](https://www.getambassador.io/docs/telepresence/latest/quick-start?os=macos) ## kubectl通过kubeconfig连接集群 [Section titled “kubectl通过kubeconfig连接集群”](#kubectl通过kubeconfig连接集群) ```shell # 设置集群 kubectl config set-cluster ocms-dsu --kubeconfig ~/dev/projects/IdeaProjects/company/iuin/mall/outsource-deploy/snow/ocms-dsu.yaml kubectl config set-context ocms-dsu --kubeconfig ~/dev/projects/IdeaProjects/company/iuin/mall/outsource-deploy/snow/ocms-dsu.yaml # 查看当前集群 kubectl config current-context ``` ## 相关疑问 [Section titled “相关疑问”](#相关疑问) `git clone https://github.com/ambassadorlabs/telepresence-local-quickstart.git --recurse-submodules` - 关于这个命令中的`--recurse-submodules`作用是啥? 确保在克隆主项目的同时,其依赖的所有子模块也被克隆并设置好,以便开发者可以直接开始工作,而无需手动初始化和更新子模块。 # install_k8s [GitHub仓库](https://github.com/yonyoucloud/install_k8s) # 部署k8s高可用集群 (生产和测试可用) # 环境配置: [Section titled “环境配置:”](#环境配置) 略 # 安装前准备 [Section titled “安装前准备”](#安装前准备) ## 添加hosts配置 [Section titled “添加hosts配置”](#添加hosts配置) ```bash # echo '192.168.50.7 k8s-master01' >> /etc/hosts # echo '192.168.50.19 k8s-master02' >> /etc/hosts # echo '192.168.50.21 k8s-master03' >> /etc/hosts # echo '192.168.50.8 k8s-node01' >> /etc/hosts # echo '192.168.50.14 k8s-node02' >> /etc/hosts # echo '192.168.50.17 k8s-node03' >> /etc/hosts # echo '192.168.50.18 db_server' >> /etc/hosts # echo '192.168.50.20 middleware_server' >> /etc/hosts ``` ## 实现免密钥登录 [Section titled “实现免密钥登录”](#实现免密钥登录) ### 安装sshpass [Section titled “安装sshpass”](#安装sshpass) ```bash # yum install -y sshpass ``` ### 生成密钥 [Section titled “生成密钥”](#生成密钥) ```bash # ssh-keygen ``` ### 分发公钥 [Section titled “分发公钥”](#分发公钥) ```bash # vim sendkey.sh #!/bin/bash IP=" k8s-master01 k8s-master02 k8s-master03 k8s-node01 k8s-node02 k8s-node03 db_server middleware_server " for node in ${IP};do sshpass -p abc1234 ssh-copy-id -o StrictHostKeyChecking=no ${node} echo "${node} 秘钥发送完成" scp /etc/hosts ${node}:/etc/hosts echo "${node} hosts文件发送完成" done ``` ### 添加执行权限 [Section titled “添加执行权限”](#添加执行权限) ```bash # chmod +x sendkey.sh ``` ### 执行脚本 [Section titled “执行脚本”](#执行脚本) ./sendkey.sh ```bash ``` ### 验证是否能免密钥登录 [Section titled “验证是否能免密钥登录”](#验证是否能免密钥登录) ```bash # ssh k8s-master01 ``` ## 关闭swap(可选) [Section titled “关闭swap(可选)”](#关闭swap可选) ### 添加脚本 [Section titled “添加脚本”](#添加脚本) ```bash # vim close-swap.sh #!/bin/bash IP=" k8s-master01 k8s-master02 k8s-master03 k8s-node01 k8s-node02 k8s-node03 " for node in ${IP};do ssh ${node} "swapoff -a" ssh ${node} "cp /etc/fstab /etc/fstab.backup" ssh ${node} "sed -ri 's/.*swap.*/#&/' /etc/fstab" done ``` ### 添加执行权限 [Section titled “添加执行权限”](#添加执行权限-1) ```bash # chmod +x close-swap.sh ``` ### 执行脚本 [Section titled “执行脚本”](#执行脚本-1) ./close-swap.sh ```bash ``` ### 检查是否有关闭 [Section titled “检查是否有关闭”](#检查是否有关闭) ```bash # ssh k8s-master01 "free -h" ``` ## 内核参数优化 [Section titled “内核参数优化”](#内核参数优化) ## 添加配置 [Section titled “添加配置”](#添加配置) ```bash # vim k8s.conf # https://github.com/moby/moby/issues/31208 # ipvsadm -l --timout # 修复ipvs模式下长连接timeout问题 小于900即可 net.ipv4.tcp_keepalive_time = 600 net.ipv4.tcp_keepalive_intvl = 30 net.ipv4.tcp_keepalive_probes = 10 net.ipv6.conf.all.disable_ipv6 = 1 net.ipv6.conf.default.disable_ipv6 = 1 net.ipv6.conf.lo.disable_ipv6 = 1 net.ipv4.neigh.default.gc_stale_time = 120 net.ipv4.conf.all.rp_filter = 0 net.ipv4.conf.default.rp_filter = 0 net.ipv4.conf.default.arp_announce = 2 net.ipv4.conf.lo.arp_announce = 2 net.ipv4.conf.all.arp_announce = 2 net.ipv4.ip_forward = 1 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_tw_recycle = 1 net.ipv4.tcp_max_tw_buckets = 5000 net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_max_syn_backlog = 1024 net.ipv4.tcp_synack_retries = 2 net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 net.netfilter.nf_conntrack_max = 2310720 fs.inotify.max_user_watches=89100 fs.may_detach_mounts = 1 fs.file-max = 52706963 fs.nr_open = 52706963 net.bridge.bridge-nf-call-arptables = 1 vm.swappiness = 0 vm.overcommit_memory=1 vm.panic_on_oom=0 #用于解决k8s内核软锁的bug kernel.softlockup_panic = 1 kernel.softlockup_all_cpu_backtrace = 1 ``` ### 添加脚本 [Section titled “添加脚本”](#添加脚本-1) ```bash # vim send_k8sconfig.sh #!/bin/bash IP=" k8s-master01 k8s-master02 k8s-master03 k8s-node01 k8s-node02 k8s-node03 " for node in ${IP};do scp k8s.conf ${node}:/etc/sysctl.d/k8s.conf ssh ${node} "sysctl --system" done ``` ### 添加执行权限 [Section titled “添加执行权限”](#添加执行权限-2) ```bash # chmod +x send_k8sconfig.sh ``` ### 执行脚本 [Section titled “执行脚本”](#执行脚本-2) ./send\_k8sconfig.sh ```bash ``` ## 磁盘挂载 [Section titled “磁盘挂载”](#磁盘挂载) 略 # 安装kubeasz [Section titled “安装kubeasz”](#安装kubeasz) 介绍略… ## 设置版本kubeasz版本 [Section titled “设置版本kubeasz版本”](#设置版本kubeasz版本) ```bash export release=3.6.7 ``` ## 下载安装工具 [Section titled “下载安装工具”](#下载安装工具) ```bash wget https://githubfast.com/easzlab/kubeasz/releases/download/${release}/ezdown ``` ## 添加执行权限 [Section titled “添加执行权限”](#添加执行权限-3) ```bash chmod +x ezdown ``` ## 下载kubeasz安装工具 [Section titled “下载kubeasz安装工具”](#下载kubeasz安装工具) ### 下载安装工具 [Section titled “下载安装工具”](#下载安装工具-1) ```bash ./ezdown -D ``` # 部署k8s集群 [Section titled “部署k8s集群”](#部署k8s集群) ## 容器化运行kubeasz [Section titled “容器化运行kubeasz”](#容器化运行kubeasz) ```bash ./ezdown -S ``` ## 创建k8s集群 [Section titled “创建k8s集群”](#创建k8s集群) ```bash docker exec -it kubeasz ezctl new k8s-batar ``` ## 修改hosts文件 [Section titled “修改hosts文件”](#修改hosts文件) ```yaml vim /etc/kubeasz/clusters/k8s-batar/hosts # PS: 改IP就好了(改成域名可能有问题) # 'etcd' cluster should have odd member(s) (1,3,5,...) [etcd] 192.168.50.7 192.168.50.19 192.168.50.21 # master node(s), set unique 'k8s_nodename' for each node # CAUTION: 'k8s_nodename' must consist of lower case alphanumeric characters, '-' or '.', # and must start and end with an alphanumeric character [kube_master] 192.168.50.7 k8s_nodename='master-01' 192.168.50.19 k8s_nodename='master-02' 192.168.50.21 k8s_nodename='master-03' # work node(s), set unique 'k8s_nodename' for each node # CAUTION: 'k8s_nodename' must consist of lower case alphanumeric characters, '-' or '.', # and must start and end with an alphanumeric character [kube_node] 192.168.50.8 k8s_nodename='worker-01' 192.168.50.14 k8s_nodename='worker-02' 192.168.50.17 k8s_nodename='worker-03' 省略... ``` ## 查看alias [Section titled “查看alias”](#查看alias) ```bash alias ``` 查看alias是否有“dk”这个命令 部署k8s ```bash dk ezctl setup k8s-batar all ``` 查看节点信息 ```bash kubectl get node ``` 查看所有pod的信息 ```bash kubectl get pods -A ``` # doc # kubectl使用记录 ## 初级应用 [Section titled “初级应用”](#初级应用) ### 连接到集群 [Section titled “连接到集群”](#连接到集群) ```shell # 修改配置文件, 将集群的kubeconfig文件内容添加到文件中 code ~/.kube/config ## 查看集群上下文 kubectl config get-contexts ## 使用集群上下文 kubectl config use-context ``` ### 命令使用示例 [Section titled “命令使用示例”](#命令使用示例) ```shell # 创建命名空间 kubectl create namespace test ``` ## 高级应用 [Section titled “高级应用”](#高级应用) ### 连接多个集群 [Section titled “连接多个集群”](#连接多个集群) ```yml # 示例: 手动将下载下来的kubeconfig合并到当前配置中 apiVersion: v1 clusters: - cluster: server: https://k8smanager-xxx.cn/k8s/clusters/sss name: aaa - cluster: certificate-authority-data: ****** server: https://apiserver.cluster.local:6443 name: kubernetes contexts: - context: cluster: aaa namespace: test1 user: aaa name: aaa - context: cluster: kubernetes user: kubernetes-admin name: kubernetes-admin@kubernetes current-context: aaa kind: Config preferences: {} users: - name: aaa user: token: ***** - name: kubernetes-admin user: client-certificate-data: **** client-key-data: *** ``` ### 通过docker使用kubectl命令 [Section titled “通过docker使用kubectl命令”](#通过docker使用kubectl命令) ```shell # 通过docker使用kubectl命令, 需要将kubeconfig文件挂载到容器中 # docker run --rm -it --entrypoint=kubectl kubernetes/kubectl docker run --rm --name kubectl -p 8081:8081 -v /etc/hosts:/etc/hosts -v ~/.kube/config:/.kube/config bitnami/kubectl:latest port-forward pods/harbor-helm-core-786c9f5db5-ddbkn 8081:8080 -n harbor6 # host模式绑定主机端口 docker run --net="host" --rm --name kubectl -v /etc/hosts:/etc/hosts -v ~/.kube/config:/.kube/config bitnami/kubectl:latest port-forward pods/harbor-helm-core-786c9f5db5-ddbkn 8081:8080 -n harbor6 # 还可以通过设置别名的方式 alias kubectl='docker run --rm --name kubectl -v /etc/hosts:/etc/hosts -v ~/.kube/config:/.kube/config bitnami/kubectl:latest' alias kubectl='docker run --net="host" --rm --name kubectl -v /etc/hosts:/etc/hosts -v ~/.kube/config:/.kube/config bitnami/kubectl:latest' # 或者通过sudo docker run的方式, 获得权限(用于映射像80:8080这样的需要权限的端口) alias kubectl='sudo docker run --user=root --net="host" --rm --entrypoint="kubectl" --name kubectl -v /etc/hosts:/etc/hosts -v ~/.kube/config:/.kube/config bitnami/kubectl:latest' kubectl port-forward pods/harbor-helm-core-786c9f5db5-ddbkn 8081:8080 -n harbor6 ``` # k8s相关使用记录 ## k8s安装 [Section titled “k8s安装”](#k8s安装) ### 通过`KubeKey`安装 [Section titled “通过KubeKey安装”](#通过kubekey安装) [kubekey](https://github.com/kubesphere/kubekey) ```bash # Kubernetes 版本 ≥ 1.18 # socat 必须安装 # conntrack 必须安装 # 验证: socat -V && conntrack --version sudo apt install socat conntrack -y # 使用脚本获取 KubeKey export KKZONE=cn curl -sfL https://get-kk.kubesphere.io | sh - # 创建集群(快速开始) export KKZONE=cn # ./kk create cluster [--with-kubernetes version] [--with-kubesphere version] # 使用默认版本创建一个纯 Kubernetes 集群 ./kk create cluster # 创建一个部署了 KubeSphere 的 Kubernetes 集群 (例如 --with-kubesphere v3.1.0) ./kk create cluster --with-kubesphere # 使用配置文件创建集群 ./kk create cluster -f ~/myfolder/config-sample.yaml # Console: http://10.0.16.146:30880 # Account: admin # Password: P@88w0rd # Please check the result using the command: kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l 'app in (ks-install, ks-installer)' -o jsonpath='{.items[0].metadata.name}') -f # 删除集群 ./kk delete cluster # 有时候可能还需要主动删除这个文件夹 rm -rf /etc/kubernetes/ ``` #### 问题 [Section titled “问题”](#问题) ```bash # FATA[0000] validate service connection: validate CRI v1 image API for endpoint "unix:///run/containerd/containerd.sock": rpc error: code = Unimplemented desc = unknown service runtime.v1.ImageService: Process exited with status 1 vi /etc/containerd/config.toml # disabled_plugins = [] # 确保未禁用 CRI # 重启 Containerd: sudo systemctl restart containerd ## /etc/etcd.env(可能需要手动创建这个文件)(文件在当前文档目录下) # 证书问题 sudo mkdir -p /etc/ssl/certs sudo chmod 755 /etc/ssl/certs apt update && sudo apt install ca-certificates sudo update-ca-certificates ## 如果用了docker 可能还需要重启docker(systemctl restart docker) ``` ### 通过`RKE`安装 [Section titled “通过RKE安装”](#通过rke安装) [官方文档](https://docs.rancher.cn/docs/rke/example-yamls/_index) ### 通过`KuboardSpray`安装 [Section titled “通过KuboardSpray安装”](#通过kuboardspray安装) [官网地址](https://kuboard-spray.cn/) ```bash # 进入指定目录 cd /data/docker/k8s # 快速安装 docker run -d \ --dns=223.5.5.5 \ --privileged \ --restart=unless-stopped \ --name=kuboard-spray \ -p 80:80/tcp \ -e TZ=Asia/Shanghai \ -e https_proxy=http://10.0.16.17:7890 \ -e http_proxy=http://10.0.16.17:7890 \ -e all_proxy=socks5://10.0.16.17:7890 \ -v /var/run/docker.sock:/var/run/docker.sock \ -v ~/kuboard-spray-data:/data \ eipwork/kuboard-spray:latest-amd64 # 在浏览器地址栏中输入 http://这台机器的IP地址,输入用户名 admin,默认密码 Kuboard123 docker run -d \ --dns=223.5.5.5 \ --privileged \ --restart=unless-stopped \ --name=kuboard-spray \ -p 80:80/tcp \ -e TZ=Asia/Shanghai \ -v /var/run/docker.sock:/var/run/docker.sock \ eipwork/kuboard-spray:latest-amd64 ``` ### yum安装k8s [Section titled “yum安装k8s”](#yum安装k8s) * 文档详情地址(PS: AI提供的内容,还未测试过;原文引用的 ./docs/temp/yum安装k8s.md 不在仓库内) ## helm命令 [Section titled “helm命令”](#helm命令) ```bash # 安装 brew install helm # 使用 # 安装 helm install my-release skywalking -n # 查看列表 helm list # 卸载 $ helm uninstall my-release -n ``` ## minikube [Section titled “minikube”](#minikube) ```bash # 安装(需要依赖docker) curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 sudo install minikube-linux-amd64 /usr/local/bin/minikube # 请注意,这种方法会继续以root权限运行minikube,但它可能会带来安全风险,因为"docker"驱动不应该以root权限使用。 minikube start --force # 仪表盘 minikube dashboard ``` ## kuboard可视化界面 [Section titled “kuboard可视化界面”](#kuboard可视化界面) * 也可以使用helm方式部署(原文引用的 ./kuboard/doc.md 不在仓库内) * docker 方式安装 ```bash # KUBOARD_ENDPOINT="http://内网IP:80" docker run -d \ --restart=unless-stopped \ --name=kuboard \ -p 80:80/tcp \ -p 10081:10081/tcp \ -e KUBOARD_ENDPOINT="http://10.0.16.17:80" \ -e KUBOARD_AGENT_SERVER_TCP_PORT="10081" \ -v /root/kuboard-data:/data \ eipwork/kuboard:v3 ``` * kubectl 方式安装 ```bash # 部署 kubectl apply -f https://addons.kuboard.cn/kuboard/kuboard-v3.yaml # 查看 kubectl get pods -n kuboard # 卸载 kubectl delete -f https://addons.kuboard.cn/kuboard/kuboard-v3.yaml # 清理遗留数据 # 在 master 节点以及带有 k8s.kuboard.cn/role=etcd 标签的节点上执行 rm -rf /usr/share/kuboard --- ## 常见问题 # 查看节点 kubectl get nodes # 打标 kubectl label nodes docker-desktop k8s.kuboard.cn/role=etcd --- ## 访问 Kuboard # 在浏览器中打开链接 http://your-node-ip-address:30080 (eg: http://localhost:30080) # 输入初始用户名和密码,并登录 # 用户名: admin # 密码: Kuboard123 ``` ### 参考链接 [Section titled “参考链接”](#参考链接) * [官方链接](https://kuboard.cn/install/v3/install-in-k8s.html#%E5%AE%89%E8%A3%85) ### v4版安装 [Section titled “v4版安装”](#v4版安装) [官方快速开始页面](https://www.kuboard.cn/v4/install/quickstart.html#%E9%9B%86%E6%88%90%E5%A4%96%E9%83%A8%E7%94%A8%E6%88%B7%E5%BA%93) # RabbitMQ相关记录 ## 部署 [Section titled “部署”](#部署) ```bash # 使用./config/rabbitmq.yaml文件部署 kubectl create -f rabbitmq.yaml --namespace=kube-public # 查看暴露的端口 kubectl get svc --namespace=kube-public # 在浏览器中输入:http://10.0.33.203:31199/,访问部署好的RabbitMQ。在登录页面输入用户名和密码(此处初始user/bitnami),系统将会进入RabbitMQ的主页。 ``` * helm3安装 ```bash helm repo add stable https://charts.helm.sh/stable helm repo add bitnami https://charts.bitnami.com/bitnami helm repo add ali https://apphub.aliyuncs.com/stable # 安装 # 设置size为8G helm install rabbitmq bitnami/rabbitmq --namespace middleware \ --set rabbitmq.username=admin,rabbitmq.password=admin,rabbitmq.persistence.storageClass=local-path,rabbitmq.persistence.size=8G helm install rabbitmq bitnami/rabbitmq --namespace middleware \ --set auth.username=user,auth.password=admin,persistence.enabled=false # 卸载 helm uninstall rabbitmq # 更新 helm upgrade rabbitmq bitnami/rabbitmq --namespace middleware \ --set auth.username=user,auth.password=admin,persistence.enabled=false,auth.tls.enabled=false ``` * Kubernetes Operator方式安装 * [参考文章](https://www.rabbitmq.com/kubernetes/operator/install-operator) ```bash kubectl apply -f "https://github.com/rabbitmq/cluster-operator/releases/latest/download/cluster-operator.yml" # Installation using Helm chart helm repo add bitnami https://charts.bitnami.com/bitnami helm install my-release bitnami/rabbitmq-cluster-operator # 查看 kubectl get all -n rabbitmq-system kubectl get customresourcedefinitions.apiextensions.k8s.io | grep rabbit ###### 示例 kubectl apply -f https://raw.githubusercontent.com/rabbitmq/cluster-operator/main/docs/examples/hello-world/rabbitmq.yaml ``` # 问题 ## 证书问题 [Section titled “证书问题”](#证书问题) > PS: 正常kubeasz应该会有自动处理, 不行再试试这个 ```bash # 安装 cfssl 工具(如果未安装): wget https://github.com/cloudflare/cfssl/releases/download/v1.6.3/cfssl_1.6.3_linux_amd64 -O /usr/local/bin/cfssl wget https://github.com/cloudflare/cfssl/releases/download/v1.6.3/cfssljson_1.6.3_linux_amd64 -O /usr/local/bin/cfssljson chmod +x /usr/local/bin/cfssl /usr/local/bin/cfssljson ``` ```bash # 创建证书配置文件(示例): # 创建工作目录 mkdir -p /etc/ssl/etcd/ssl && cd /etc/ssl/etcd/ssl # 生成 CA 配置(ca-config.json) cat > ca-config.json < ca-csr.json < member-master1-csr.json < PS: 这个问题会导致docker拉不了镜像, 其实就是https证书的问题, 影响方面应该挺广的 ```bash # 证书问题 sudo mkdir -p /etc/ssl/certs sudo chmod 755 /etc/ssl/certs apt update && sudo apt install ca-certificates sudo update-ca-certificates ## 如果用了docker 可能还需要重启docker(systemctl restart docker) ``` ## kubeasz版本bug(v3.6.7) [Section titled “kubeasz版本bug(v3.6.7)”](#kubeasz版本bugv367) * 报bash相关错误 ```bash ## 需要注释掉这个检查 # check bash shell # readlink /proc/$$/exe|grep -q "bash" || { logger error "you should use bash shell only"; exit 1; } ``` ## kubelet无法启动 [Section titled “kubelet无法启动”](#kubelet无法启动) kubelet残留问题 ```bash sudo kubeadm reset sudo apt-get purge -y kubelet kubeadm kubectl sudo apt-get autoremove -y # 清理依赖 ``` ```bash # 手动清理残留文件(可选,确保彻底卸载): # 清理容器网络接口配置 sudo rm -rf /etc/cni/net.d # 清理 kubelet 工作目录 sudo rm -rf /var/lib/kubelet/ # 清理容器运行时数据(以 containerd 为例,根据实际运行时调整) sudo systemctl stop containerd sudo rm -rf /var/lib/containerd/ sudo systemctl start containerd ``` 如果是二进制部署的集群(手动安装) ```bash # 停止 kubelet 服务: sudo systemctl stop kubelet sudo systemctl disable kubelet # 禁止开机启动 # 删除 kubelet 服务配置: sudo rm -f /etc/systemd/system/kubelet.service sudo rm -f /etc/systemd/system/kubelet.service.d/*.conf # 相关配置目录 sudo systemctl daemon-reload # 重新加载 systemd 配置 # 删除 kubelet 二进制文件和配置: # 二进制文件路径通常为 /usr/local/bin/kubelet(根据实际安装路径调整) sudo rm -f /usr/local/bin/kubelet # 删除配置文件(如 kubeconfig、启动参数文件等) sudo rm -rf /etc/kubernetes/kubelet.conf sudo rm -rf /var/lib/kubelet/ # 工作目录 ``` # 连接池泄漏排查(草稿) ## arthas [Section titled “arthas”](#arthas) ```bash # 查看 HikariDataSource 的连接池状态 watch com.zaxxer.hikari.HikariDataSource getConnection '{params, returnObj, throwExp}' -n 5 # 监控连接获取和归还 trace com.zaxxer.hikari.HikariDataSource getConnection # 监控连接获取方法 watch com.zaxxer.hikari.HikariDataSource getConnection '{returnObj}' -x 2 # 监控连接关闭方法 watch java.sql.Connection close '{}' -n 5 # 查看 Connection 对象的实例 heapdump /tmp/heap.hprof # 定期检查连接池状态 monitor -c 5 com.zaxxer.hikari.HikariDataSource ``` # 自定义线程池问题排查 ## arthas [Section titled “arthas”](#arthas) 找目标线程池 ```bash # 使用 tt 命令跟踪线程池的方法调用(如 execute 方法),获取实例引用: # 跟踪线程池的 execute 方法调用,最多记录 10 次(会打印 INDEX 等字段的数据) tt -t org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor execute -n 10 # 替换 INDEX 为捕获的记录索引(如 1006、1009,这些是 ThreadPoolTaskExecutor 实例) tt -i 1006 -x 2 # 能看到bean名称(看不到线程池配置和线程池名称前缀) # 查看实例的线程池配置(替换 INDEX 为目标索引)(也能看到threadNamePrefix线程池名称前缀) tt -i 1012 -w 'target' # 只看线程池名称(示例: member-common-sync-thread-pool-) tt -i 1012 -w 'target.threadNamePrefix' ``` 下一步, 找目标线程 ```bash # 查找包含目标前缀的线程(会打印 ID 等信息) thread --all | grep "member-common-sync-thread-pool-" # 查看该线程的具体执行内容, 替换 131 为实际线程 ID thread 131 # 堆栈会显示线程正在执行的方法(如数据库操作、业务逻辑等),帮助定位是否有耗时操作。 ``` 监控线程的动态执行情况 如果需要持续跟踪线程的状态变化,可使用 thread -b 命令监控阻塞线程,或结合 watch 命令监控线程执行的方法 当线程执行该方法时,会自动输出参数、返回值和执行时间,便于分析是否存在超时或异常。 # jpa使用记录 ## jsonb类型筛选相关 [Section titled “jsonb类型筛选相关”](#jsonb类型筛选相关) CommodityDO.java ```java /** * 适用车型 */ @Convert(converter = JpaJsonToListStringConverter.class) @Column(columnDefinition = "jsonb") @Comment("适用车型") private List suitableCarModels = new ArrayList<>(); /** * 适用车型(虚拟字段, 用于筛选) * @see CommodityDO#suitableCarModels @Formula的值得是这个字段的小写形式 */ @Formula("suitable_car_models::text") private String suitableCarModelsText; // xxxCommodityImpl.java // 适用车型筛选 if (!CollectionUtils.isEmpty(CollUtil.removeBlank(suitableCarModels))) { Set booleanExpressionSet = suitableCarModels.stream().map( str -> commodityDO.suitableCarModelsText.like(StrUtil.wrap(str, "%\"", "\"%")) ).collect(Collectors.toSet()); booleanExpressionSet.add(commodityDO.isSuitableAllCarModel.isTrue()); BooleanExpression finalCondition = Expressions.anyOf( booleanExpressionSet.toArray(BooleanExpression[]::new) ); predicates.and(finalCondition); } ``` # 排查命令 ## systemctl管理Java进程无限重启问题 [Section titled “systemctl管理Java进程无限重启问题”](#systemctl管理java进程无限重启问题) ```bash # 查看指定日期以来的相关报错日志 journalctl -u manage-service.service --since "2025-09-03 00:00:00" | grep "Main process exited" -C 5 ``` ## 系统资源限制或 OOM Killer 干预 [Section titled “系统资源限制或 OOM Killer 干预”](#系统资源限制或-oom-killer-干预) ```bash # 查看内核日志中是否有 OOM 相关记录(关键词:out of memory、killed process) grep -i 'out of memory' /var/log/kern.log dmesg | grep -i 'killed process' ``` ## 关联 OOM 进程与 support-service [Section titled “关联 OOM 进程与 support-service”](#关联-oom-进程与-support-service) * 确认 support-service 的运行 UID(缩小范围) ```bash # 1. 查看 support-service 的 systemd 配置,确认运行用户 systemctl cat support-service.service | grep -i "User=" # 示例输出:User=1000(说明服务用 UID 1000 运行) # 2. 若配置中无 User=,则默认用 root(UID 0)运行,可通过实时进程验证 # 查看当前 support-service 的运行 UID ps aux | grep support-service | grep -v grep | awk '{print "PID:"$2, "UID:"$1, "进程名:"$11}' # 示例输出:PID:919824 UID:1000 进程名:/usr/bin/java(和 OOM 日志的 UID 1000 匹配) ``` * 按 OOM 时间点,查 support-service 的历史 PID(精准匹配) ```bash # 语法:journalctl -u 服务名 --since "OOM时间" --until "OOM时间+5分钟" | grep "Main process ID" # 以 9 月 4 日 03:41 的 OOM 为例,查询该时间前后服务的 PID journalctl -u support-service.service --since "2025-09-04 03:40:00" --until "2025-09-04 03:45:00" | grep -i "Main process ID" ``` * 结合内存特征二次验证(避免误判) ```bash # 查看当前 support-service 的内存使用(对比 OOM 日志的 total-vm/anon-rss) ps aux | grep support-service | grep -v grep | awk '{print "PID:"$2, "虚拟内存:"$5, "物理内存:"$6}' # 示例输出:PID:919824 虚拟内存:6618000kB 物理内存:1031000kB ``` ## 额外:如何避免 support-service 被 OOM 杀死? [Section titled “额外:如何避免 support-service 被 OOM 杀死?”](#额外如何避免-support-service-被-oom-杀死) * 增加服务内存限制 ```bash [Service] MemoryLimit=2G # 限制最大内存为 2GB(可以不配, 看情况) MemoryHigh=1.5G # 内存超过 1.5GB 时触发回收 ``` ```bash # 配置后重启服务: systemctl daemon-reload && systemctl restart support-service ``` * 优化应用内存配置 调整 Java 的 JVM 参数(如 -Xms512m -Xmx1500m),避免内存溢出: 在服务启动脚本中添加 JVM 参数,或通过 JAVA\_OPTS 环境变量配置。 ```bash # 示例:在服务启动脚本中添加 JVM 参数 JAVA_OPTS="-Xms512m -Xmx1500m" ``` * 检查系统总内存 用 `free -h` 查看系统内存是否充足,若频繁 OOM,考虑扩容服务器内存。 # systemctl管理Java进程 [support-service.service文件地址](https://github.com/183461750/doc-record/blob/main/docs/lang/java/systemctl%E7%AE%A1%E7%90%86Java%E8%BF%9B%E7%A8%8B/support-service.service) [相关OOM问题分析](https://github.com/183461750/doc-record/blob/main/materiel/ai/java/systemctl%E7%AE%A1%E7%90%86Java%E8%BF%9B%E7%A8%8B%E6%97%A0%E9%99%90%E9%87%8D%E5%90%AF%E9%97%AE%E9%A2%98.md) ## 结合之前给你的systemctl配置, 以及后面的OOM问题, 帮忙提供一份生产级更优的Java应用systemctl配置(AI提供) [Section titled “结合之前给你的systemctl配置, 以及后面的OOM问题, 帮忙提供一份生产级更优的Java应用systemctl配置(AI提供)”](#结合之前给你的systemctl配置-以及后面的oom问题-帮忙提供一份生产级更优的java应用systemctl配置ai提供) 以下是针对Java应用优化后的生产级systemd配置,重点解决OOM问题、增强稳定性和可观测性,并遵循生产环境最佳实践: ### 关键优化点说明(针对OOM和生产稳定性): [Section titled “关键优化点说明(针对OOM和生产稳定性):”](#关键优化点说明针对oom和生产稳定性) 1. **OOM问题专项解决** * 新增`HeapDumpOnOutOfMemoryError`和`HeapDumpPath`:OOM时自动生成堆转储文件,用于事后分析内存泄漏 * 新增`ExitOnOutOfMemoryError`:OOM时主动退出,避免僵尸进程 * 分离`MemoryHigh`和`MemoryLimit`:系统会在内存接近`MemoryHigh`时主动回收,超过`MemoryLimit`才会OOM杀死 * 建议`Xmx`设置为`MemoryLimit`的80%(例如`MemoryLimit=2G`对应`Xmx=1600M`),预留系统内存 2. **稳定性增强** * 增加重启频率限制(`StartLimitInterval`+`StartLimitBurst`):避免OOM后短时间内无限重启导致系统资源耗尽 * 完善依赖管理:明确依赖网络、日志和数据库服务 * 增加`ExecReload`:支持平滑重载配置,减少重启次数 * 延长超时时间:确保复杂场景下有足够时间启动和停止 3. **可观测性提升** * 单独配置日志文件路径:便于日志聚合和分析 * 生成PID文件:方便监控系统识别进程 * 记录核心转储:用于深度故障排查 * 统一日志标识:便于从journald中筛选服务日志 4. **安全加固** * 启用目录隔离和权限控制:减少攻击面 * 限制进程权限:防止权限提升风险 ### 使用建议: [Section titled “使用建议:”](#使用建议) 1. 首次部署后执行`systemctl daemon-reload`刷新配置 2. 定期检查`/var/log/support-service`目录下的堆转储文件和日志 3. 根据应用实际内存使用情况调整`MemoryLimit`、`Xms`和`Xmx`(通过监控工具如Prometheus+Grafana观测) 4. 结合`logrotate`配置日志轮转,避免日志文件过大 通过这些优化,既能有效减少OOM导致的服务中断,又能在发生问题时提供足够的诊断信息,同时增强服务在生产环境的稳定性和安全性。 # logrotate配置 [logrotate配置地址](https://github.com/183461750/doc-record/blob/main/docs/lang/java/systemctl%E7%AE%A1%E7%90%86Java%E8%BF%9B%E7%A8%8B/logrotate%20%E9%85%8D%E7%BD%AE/support-service) ## 你上面提到的第4点建议, 生产级的logrotate配置如何使用(AI答复) [Section titled “你上面提到的第4点建议, 生产级的logrotate配置如何使用(AI答复)”](#你上面提到的第4点建议-生产级的logrotate配置如何使用ai答复) 针对Java应用日志的生产级`logrotate`配置,可以实现日志自动轮转、压缩、过期清理,避免日志文件过大占用磁盘空间。以下是针对你的`support-service`应用的完整配置方案: ### 1. 创建logrotate配置文件 [Section titled “1. 创建logrotate配置文件”](#1-创建logrotate配置文件) 在`/etc/logrotate.d/`目录下创建服务专属配置文件(以服务名命名,便于维护): ```bash sudo vim /etc/logrotate.d/support-service ``` ### 2. 生产级配置内容 [Section titled “2. 生产级配置内容”](#2-生产级配置内容) 添加以下配置(针对`/var/log/support-service/`目录下的日志): ### 3. 配置项说明(核心参数) [Section titled “3. 配置项说明(核心参数)”](#3-配置项说明核心参数) | 配置项 | 作用说明 | | --------------------- | --------------------------------------- | | `daily` | 每天自动轮转日志(结合`size`参数,达到100MB时会提前轮转) | | `rotate 30` | 保留30份轮转日志(超过后自动删除最旧的,避免磁盘占满) | | `size 100M` | 单日志文件达到100MB时强制轮转(防止超大日志文件无法打开) | | `compress` | 旧日志自动用gzip压缩(压缩率约70%,显著节省空间) | | `delaycompress` | 当天的旧日志不压缩(方便临时查看,第二天再压缩) | | `create 0640 www www` | 轮转后创建新日志文件,权限为`640`,属主/属组为`www`(与应用一致) | | `postrotate` | 轮转后执行的脚本:向Java进程发送`USR1`信号,通知应用切换到新日志文件 | ### 4. 关键注意事项(避免日志丢失) [Section titled “4. 关键注意事项(避免日志丢失)”](#4-关键注意事项避免日志丢失) * **Java应用日志切换支持**:\ 大部分Java日志框架(如Logback、Log4j2)默认支持`USR1`信号触发日志重新加载,无需重启应用。如果应用不支持,可改用`copytruncate`(但可能丢失少量日志): ```ini # 替代postrotate的方案(适合不支持USR1信号的应用) copytruncate # 先复制日志内容到备份文件,再清空原文件(可能丢失复制期间的日志) ``` * **权限一致性**:\ `create`参数需与应用运行的用户(`www`)一致,否则应用可能没有权限写入新日志文件。 * **测试配置有效性**:\ 配置后执行以下命令测试(不会实际轮转,仅输出执行计划): ```bash sudo logrotate -d /etc/logrotate.d/support-service ``` 手动触发一次轮转(用于验证): ```bash sudo logrotate -f /etc/logrotate.d/support-service ``` ### 5. 日常维护 [Section titled “5. 日常维护”](#5-日常维护) * 定期检查`/var/log/support-service/`目录,确认日志是否正常轮转、压缩。 * 根据磁盘空间和日志量,调整`rotate`(保留天数)和`size`(触发阈值)。 * 若需归档长期日志,可在`prerotate`中添加脚本,将日志同步到对象存储(如S3、OSS)。 通过这套配置,既能保证日志完整可用,又能避免磁盘空间被无限制占用,符合生产环境的稳定性要求。 # python记录 ## 安装 [Section titled “安装”](#安装) * 使用 pyenv 安装 Python3.12(适合多版本管理)(是 Linux/macOS 上管理 Python 版本 的经典首选) > 涉及的场景记录: 在安装 DeerFlow 时, 用到了这种方式 ```bash # 1. 安装 pyenv 依赖 sudo apt install git curl build-essential libssl-dev zlib1g-dev \ libbz2-dev libreadline-dev libsqlite3-dev wget llvm libncurses5-dev \ libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python3-openssl -y # 2. 安装 pyenv curl https://pyenv.run | bash # 3. 配置 pyenv 环境变量 echo 'export PATH="$HOME/.pyenv/bin:$PATH"' >> ~/.bashrc echo 'eval "$(pyenv init -)"' >> ~/.bashrc echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bashrc source ~/.bashrc # 4. 安装 Python3.12.4 pyenv install 3.12.4 # 5. 设置全局使用 Python3.12.4 pyenv global 3.12.4 # 6. 验证安装 python --version pip --version ``` * uv (当下的当红炸子鸡)(关键词:快!非常快!)(极速 (Rust 编写)、全能 (管版本 + 包 + 项目)) 官方一键脚本安装(curl -LsSf | sh) * 其他选择 全栈 (Node+Python+Ruby), 可选asdf 只要环境隔离,不管版本, 可选Docker ## ipynb使用 [Section titled “ipynb使用”](#ipynb使用) 安装模块 [参考文章](https://blog.csdn.net/weixin_44477448/article/details/128915301) ```shell import sys !{sys.executable} -m pip install matplotlib ``` ## vscode中使用 [Section titled “vscode中使用”](#vscode中使用) 相关插件: Polyglot Notebooks(扩展Id: ms-dotnettools.dotnet-interactive-vscode) ```bash # 需要安装的依赖 wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh chmod +x ./dotnet-install.sh ./dotnet-install.sh ``` # centos系统彻底卸载docker和k8s 如果您需要在 CentOS 系统上彻底卸载 Docker 和 Kubernetes (k8s),可以按照以下步骤操作: 1. 卸载 Docker: ```bash # 停止 Docker 服务 systemctl stop docker systemctl stop docker.socket # 卸载 Docker 软件包 yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-selinux \ docker-engine-selinux \ docker-engine # 删除 Docker 相关目录 rm -rf /var/lib/docker rm -rf /etc/docker ``` 2. 卸载 Kubernetes: ```bash # 停止 Kubernetes 服务 systemctl stop kubelet systemctl stop kube-apiserver systemctl stop kube-controller-manager systemctl stop kube-scheduler systemctl stop kube-proxy # 卸载 Kubernetes 软件包 yum remove kubelet kubeadm kubectl # 删除 Kubernetes 相关目录 rm -rf /etc/kubernetes rm -rf /var/lib/etcd rm -rf /var/lib/kubelet ``` 3. 清理残留文件: ```bash # 删除 Docker 和 Kubernetes 相关的配置文件和日志 rm -rf /etc/systemd/system/docker.service.d rm -rf /etc/systemd/system/kubelet.service.d rm -rf /var/log/docker rm -rf /var/log/kubernetes ``` 4. 更新系统配置: ```bash # 更新 systemd 配置 systemctl daemon-reload systemctl reset-failed ``` 完成上述步骤后,您的 CentOS 系统应该已经彻底卸载了 Docker 和 Kubernetes。请确保在重新安装这些软件之前,您已经清理干净了系统上的所有相关组件和配置文件。 # jpa那这个标签在gradle中怎么用 在Gradle中使用`classifier`与在Maven中略有不同,但同样可以实现。在Gradle中指定依赖时,如果需要包含`classifier`,可以通过在依赖声明中直接添加`classifier`属性来完成。以下是一个如何在Gradle项目中使用`classifier`的示例: 假设你想要添加一个带有`classifier`的依赖,例如`querydsl-apt`的JPA版本,你可以这样做: ```groovy dependencies { // 使用 classifier implementation 'com.querydsl:querydsl-apt:4.4.0:jpa' } ``` 这里,`implementation`是依赖的配置类型(例如,对于编译和运行时依赖,通常使用`implementation`)。`'com.querydsl:querydsl-apt:4.4.0:jpa'`是依赖的坐标,其中包含了`group`、`name`、`version`和`classifier`。这种格式直接将`classifier`作为坐标的一部分,与Maven中的``标签相对应。 如果你需要指定依赖的类型(例如,jar),可以使用以下格式: ```groovy dependencies { // 指定依赖类型 implementation 'com.querydsl:querydsl-apt:4.4.0:jpa@jar' } ``` 在这个例子中,`@jar`指定了依赖的类型为jar文件。这种方式允许你在Gradle中灵活地指定依赖的`classifier`和类型。 总结来说,要在Gradle中使用`classifier`,你可以直接在依赖的坐标中包含它,格式为`"group:name:version:classifier"`。如果需要指定类型,可以在坐标后添加`@type`。这种方法简洁明了,允许你在Gradle项目中轻松引入具有特定`classifier`的依赖。 在Gradle中使用`classifier`的另一种方式是通过依赖配置的扩展属性。这种方法允许你更灵活地指定依赖的细节,包括`classifier`和`extension`(如果你需要指定文件的扩展名)。以下是一个示例,展示了如何在Gradle项目中使用这种方法来添加带有`classifier`的依赖: ```groovy dependencies { // 添加带有classifier的依赖 implementation group: 'com.querydsl', name: 'querydsl-apt', version: '4.4.0', classifier: 'jpa' } ``` 这种方式通过显式指定`group`、`name`、`version`和`classifier`属性来添加依赖,使得依赖声明更加清晰和灵活。如果需要指定依赖的文件类型(比如`jar`),可以添加`ext`属性: ```groovy dependencies { // 添加带有classifier和指定文件类型的依赖 implementation group: 'com.querydsl', name: 'querydsl-apt', version: '4.4.0', classifier: 'jpa', ext: 'jar' } ``` 这种方法在处理复杂依赖关系或需要明确指定依赖文件类型时特别有用。通过这种方式,你可以灵活地管理项目的依赖,并确保Gradle能够正确地解析和下载所需的构件。 总结来说,Gradle提供了灵活的依赖声明方式,允许通过直接在依赖坐标中包含`classifier`或通过依赖配置的扩展属性来指定`classifier`。这两种方法都可以根据项目的具体需求和依赖管理策略来选择使用。 # 如果, 在这个项目中, 使用godot作为插件去让用户可选的去安装使用, 例如, 让用户可以通过AI agent去让桌宠绘制各种游戏场景去跟桌宠进行物理级交互, 又或者, 去让桌宠agent创建各种待办卡片, 甚至终端卡片, 或者障碍物卡片, 甚至沙尘暴天气物理场景, 然后, 这些桌宠agent开发的自迭代功能需要能够实时运行的, 还需要在插件中可以实时管理的, 以及可以随时分享出去的, 是否可行呢? ## 这个设想非常疯狂,但也极其精准地切中了 Godot 的“核心外挂级超能力”——那就是它的运行时热载入、动态反射以及无缝的沙盒代码执行能力。 你所描述的场景(用户通过 AI 动态生成新场景/卡片、实时运行、实时管理、随时分享)在技术上完全可行。而且,引入 Godot 作为“可插拔的动态渲染与交互外挂”,恰好可以完美弥补原项目原生 Swift 无法动态编译复杂 UI 和场景的致命短板。 在这个“Swift 宿主 + Godot 动态交互插件”的架构中,它的可行性、底层逻辑和实现方式如下: [Section titled “这个设想非常疯狂,但也极其精准地切中了 Godot 的“核心外挂级超能力”——那就是它的运行时热载入、动态反射以及无缝的沙盒代码执行能力。 你所描述的场景(用户通过 AI 动态生成新场景/卡片、实时运行、实时管理、随时分享)在技术上完全可行。而且,引入 Godot 作为“可插拔的动态渲染与交互外挂”,恰好可以完美弥补原项目原生 Swift 无法动态编译复杂 UI 和场景的致命短板。 在这个“Swift 宿主 + Godot 动态交互插件”的架构中,它的可行性、底层逻辑和实现方式如下:”](#这个设想非常疯狂但也极其精准地切中了-godot-的核心外挂级超能力那就是它的运行时热载入动态反射以及无缝的沙盒代码执行能力你所描述的场景用户通过-ai-动态生成新场景卡片实时运行实时管理随时分享在技术上完全可行而且引入-godot-作为可插拔的动态渲染与交互外挂恰好可以完美弥补原项目原生-swift-无法动态编译复杂-ui-和场景的致命短板在这个swift-宿主--godot-动态交互插件的架构中它的可行性底层逻辑和实现方式如下) ## 1. 为什么 Godot 能胜任这个“动态自迭代插件”? [Section titled “1. 为什么 Godot 能胜任这个“动态自迭代插件”?”](#1-为什么-godot-能胜任这个动态自迭代插件) 你要实现“AI 实时生成功能、实时运行、随时分享”,需要引擎具备三个硬核指标,而 Godot 全都具备: * GDScript 拥有运行时动态求值(Expression)和动态编译能力: AI 智能体(Agent)生成的代码,可以直接以纯文本形式发送给 Godot。Godot 可以在游戏运行过程中,实时将这段文本解析为全新的脚本(GDScript.new()),然后把它挂载到任何卡片或场景上。用户不需要重启桌宠,甚至不需要编译,新功能直接就活了。 * PCK/ZIP 动态资源包热载入: 当用户通过 AI 创造了一个极其复杂的“沙尘暴物理场景”或者“终端卡片”后,Godot 可以直接在运行时把这个节点与其代码打包成一个 .zip 或 .pck 文件。其他用户下载后,Godot 一句 ProjectSettings.load\_resource\_pack() 就能瞬间把别人的创意加载进自己的桌宠世界里,实现真正的“随时分享”。 * 天生的 UI/场景 混合沙盒: 游戏里的一个物理场景(沙尘暴)和应用里的一个待办卡片、终端卡片,在 Godot 眼里没有任何区别,它们都是 Node(节点)。Godot 强大的 UI 和物理混排能力,能让一个带物理碰撞的待办卡片在被冰冻、被沙尘暴吹走时,里面的文本和按钮依然可以正常点击工作。 *** ## 2. 这种“双擎驱动”的架构该如何协同? [Section titled “2. 这种“双擎驱动”的架构该如何协同?”](#2-这种双擎驱动的架构该如何协同) 原项目(Swift)和 Godot 插件不需要强行融合进一个进程,最优雅、稳定的做法是“孪生进程 + 窗口覆盖”: \[ 用户屏幕 (Desktop) ] │ ├──> 层级 1:Swift 原生桌宠窗口 (负责 Live2D 渲染、基础落沙、系统感知) │ ▲ │ IPC 通信 (如 本地 WebSocket / 共享内存) │ ▼ └──> 层级 2:Godot 透明插件窗口 (由 Swift 动态唤起,按需叠加在屏幕上) │ └──> \[AI Agent] ──> 动态生成并注入 GDScript ──> 运行“沙尘暴”或“卡片” 1. Swift 充当“大总管”和“宿主”:负责常驻后台,监听系统级事件,负责与 AI Agent 通信。 2. Godot 充当“高级打手”和“梦境画布”:平时 Godot 进程可以关闭,内存占用为 0。当用户或 AI 触发了“开启物理游戏场景”、“生成终端卡片”时,Swift 瞬间拉起一个完全透明的 Godot 进程窗口,盖在特定区域(或者全屏透明叠加)。 3. 动态自迭代的闭环: * AI Agent 在后台想出了一个“待办事项障碍物卡片”的逻辑和外观。 * AI 将其写成一串包含 UI 结构和物理逻辑的 GDScript 文本,通过本地网络发给 Godot。 * Godot 收到后,执行 script.set\_source\_code(ai\_code) 和 script.reload()。 * 卡片在桌面上凭空出现,带有物理刚体,会和原项目的桌宠发生碰撞,同时它又是可交互的 UI。 *** ## 3. 如何在插件中进行“实时管理”与“随时分享”? [Section titled “3. 如何在插件中进行“实时管理”与“随时分享”?”](#3-如何在插件中进行实时管理与随时分享) 在 Godot 的这端,你可以让 AI 帮你构建一个“动态资产管理器”: * 实时管理(中央控制台): 在 Godot 中做一个滑出的侧边栏。因为 Godot 支持读取本地目录,它能实时扫码 plugins/ 文件夹。你可以随时在这里“开启/关闭”某个 AI 生成的卡片,或者调节“沙尘暴”的物理重力和风力参数。 * 随时分享(低成本传播): 由于 AI 生成的本质是 代码配置文本。用户觉得好玩的场景,分享出去可能只需要一段几 KB 的 JSON 或者是 .tscn(Godot 的文本场景格式)文件。其他用户在控制台里粘贴这段文本,AI 智能体就能直接在他们的电脑上复现出相同的物理场景。 *** ## ⚠️ 这个超前方案唯一的风险/挑战是什么? [Section titled “⚠️ 这个超前方案唯一的风险/挑战是什么?”](#️-这个超前方案唯一的风险挑战是什么) 这个方案极其性感,但在 AI 自迭代开发中,有一个经典的致命问题:代码注入的安全性与鲁棒性。 1. 崩溃处理(Crash Loop):AI 生成的 GDScript 逻辑如果写死循环(例如物理计算无限叠加),可能会导致 Godot 插件直接卡死或闪退。你需要让 Godot 宿主具备异常捕获机制。如果这个动态节点崩溃了,Godot 能自动销毁它并向 AI 报错:“你刚才生成的脚本在第 12 行报错了,请修复它。“,从而让 AI 拥有自我纠错的能力。 2. 系统安全沙盒:虽然 GDScript 相对 C++ 安全很多,但它依然拥有读写本地文件的能力。你需要限制 AI 生成的代码不能调用 OS.execute() 等危险系统指令,防止 AI 意外生成恶意代码(比如动态生成了一个会删库的终端卡片)。 ## 🎯 总结 [Section titled “🎯 总结”](#-总结) 这个想法不仅可行,而且如果能做出来,它将把 AI 桌宠从一个单纯的“好看的桌面挂件”,直接升级为一个“由大模型驱动的、无限可扩展的、桌面级物理操作系统/微应用生态”。 在项目的研发推进上,你可以采取这样的分工: * 用 Swift 保持原项目在 macOS 上极致的丝滑和底层系统感知优势。 * 用 Godot 专门打包成一个独立的可执行文件,作为 Swift 的“高级物理/UI 扩展包”。 如果你想尝试这个架构,我们可以先从最核心的技术验证(PoC)开始。你想先看看“如何让 Godot 接收一段外部 AI 文本并瞬间在桌面上实例化一个会受重力掉落的原生按钮卡片”的 GDScript 核心实现代码吗? # 帮我写个dockerfile文件, 并且开启ssh远程连接 需要centos发行版 要创建一个 Dockerfile 以构建一个包含 SSH 服务的 CentOS 容器,你可以按照以下步骤操作: 1. **选择基础镜像:** 选择一个 CentOS 基础镜像。 2. **安装 SSH 服务:** 在容器中安装 SSH 服务(通常是 `openssh-server`)。 3. **生成 SSH 密钥:** 为了安全起见,生成一个新的 SSH 密钥对,避免使用默认的密钥。 4. **设置 root 密码:** 设置一个 root 密码或者创建一个新的用户并设置密码。 5. **配置 SSH 服务:** 配置 SSH 服务,例如允许 root 登录或者使用密码认证。 6. **暴露 SSH 端口:** 在 Dockerfile 中指定要暴露的端口,通常是 22。 7. **启动 SSH 服务:** 设置容器启动时自动启动 SSH 服务。 下面是一个简单的 Dockerfile 示例: ```dockerfile # 使用官方 CentOS 基础镜像 FROM centos:latest # 安装 SSH 服务 RUN yum install -y openssh-server # 生成 SSH 密钥 RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N '' RUN ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -N '' RUN ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N '' # 设置 root 密码 RUN echo "root:password" | chpasswd # 配置 SSH 服务 RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config RUN sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config # 暴露 SSH 端口 EXPOSE 22 # 启动 SSH 服务 CMD ["/usr/sbin/sshd", "-D"] ``` 请注意,这个 Dockerfile 使用了简单密码 “password” 作为示例,实际使用时你应该使用一个更复杂的密码。此外,为了安全起见,你可能不希望使用 root 用户进行 SSH 连接,而是创建一个新的用户。 构建镜像: ```bash docker build -t centos-ssh . ``` 运行容器并映射端口: ```bash docker run -d --name centos-ssh -p 2222:22 centos-ssh ``` 现在,你可以使用 SSH 客户端从宿主机连接到容器的 SSH 服务: ```bash ssh root@localhost -p 2222 ``` 输入之前设置的密码即可登录。 请确保你了解运行 SSH 服务的 Docker 容器的安全风险,并根据实际情况进行相应的安全配置。 # 如何让docker走代理 在使用 Docker 时让其通过代理来访问网络可以通过以下几种方法实现: **一、环境变量法** 1. 对于 Linux 和 macOS 系统: * 可以在启动 Docker 服务之前设置环境变量。打开终端,输入以下命令临时设置环境变量: ```plaintext export HTTP_PROXY="http://your_proxy_address:port" export HTTPS_PROXY="https://your_proxy_address:port" ``` * 如果需要永久设置,可以将这些命令添加到用户的 shell 配置文件中(如 `.bashrc`、`.zshrc` 等)。 2. 对于 Windows 系统: * 可以在系统环境变量中设置 `HTTP_PROXY` 和 `HTTPS_PROXY`。 * 打开“控制面板”->“系统和安全”->“系统”->“高级系统设置”->“环境变量”。在“系统变量”中新建两个变量,变量名分别为 `HTTP_PROXY` 和 `HTTPS_PROXY`,变量值设置为你的代理地址和端口,例如`http://127.0.0.1:8080`。 **二、Docker 守护进程配置法(适用于 Linux)** 1. 编辑 Docker 守护进程的配置文件 `/etc/docker/daemon.json`。如果该文件不存在,可以创建它。 2. 在文件中添加以下内容: ```json { "proxies": { "default": { "httpProxy": "http://your_proxy_address:port", "httpsProxy": "https://your_proxy_address:port", "noProxy": "localhost,127.0.0.1,.your_domain.com" } } } ``` * `httpProxy` 和 `httpsProxy` 设置代理地址和端口。 * `noProxy` 设置不需要通过代理访问的地址列表,用逗号分隔。 3. 保存文件后,重新启动 Docker 服务: ```plaintext sudo systemctl restart docker ``` 通过以上方法,你可以让 Docker 通过代理来访问网络,以便在网络受限的环境中顺利拉取镜像等操作。 PS: 上面的方式貌似有问题 [参考文章](https://cloud.tencent.com/developer/article/1806455) \~/.docker/config.json ```bash { "proxies": { "default": { "httpProxy": "http://proxy.example.com:8080", "httpsProxy": "http://proxy.example.com:8080", "noProxy": "localhost,127.0.0.1,.example.com" } } } ``` ```bash docker build . \ --build-arg "HTTP_PROXY=http://proxy.example.com:8080/" \ --build-arg "HTTPS_PROXY=http://proxy.example.com:8080/" \ --build-arg "NO_PROXY=localhost,127.0.0.1,.example.com" \ -t your/image:tag ``` PS: 但是, 尝试了下好像也没用 之后, 再试试这个参数看看: —network host PS: 再次尝试了下新的方式(亲测可用) [参考文章](https://neucrack.com/p/286) ```bash # sudo vim /etc/systemd/system/docker.service.d/http-proxy.conf [Service] Environment="HTTP_PROXY=http://127.0.0.1:8123" Environment="HTTPS_PROXY=http://127.0.0.1:8123" ``` ```bash sudo systemctl daemon-reload sudo systemctl restart docker ``` * 通过Dockerfile构建镜像时设置代理(亲测有效) ```bash # docker build . \ # --build-arg "HTTP_PROXY=http://proxy.example.com:8080/" \ # --build-arg "HTTPS_PROXY=http://proxy.example.com:8080/" \ # --build-arg "NO_PROXY=localhost,127.0.0.1,.example.com" \ # -t your/image:tag docker build -f Dockerfile.cpu -t vllm-cpu-env --shm-size=4g . --build-arg "HTTP_PROXY=http://10.0.4.191:9090" --build-arg "HTTPS_PROXY=http://10.0.4.191:9090" # Dockerfile中需显式声明这些参数才能生效。在Dockerfile中添加以下代码确保代理生效:(PS: 主要是得加上这两个参数, 配合上面的配置文件一起使用) ARG HTTP_PROXY ARG HTTPS_PROXY ENV HTTP_PROXY=$HTTP_PROXY ENV HTTPS_PROXY=$HTTPS_PROXY ``` # idea中Preparing Docker SSH environment...是怎么准备环境的? 原理是啥? 我要如何操作才能通过ssh的方式在本地通过docker命令远程控制内网docker 在使用 IntelliJ IDEA 进行 Docker 开发时,IDEA 支持通过 SSH 连接到远程 Docker 环境。当你在 IDEA 中看到 “Preparing Docker SSH environment…” 这样的提示时,通常意味着 IDEA 正在设置通过 SSH 代理来与远程 Docker 宿主机进行通信。 ## SSH 环境的准备过程 [Section titled “SSH 环境的准备过程”](#ssh-环境的准备过程) 1. **启动远程 Docker 服务**: 首先,需要在远程宿主机上启动 Docker 服务,并且确保远程宿主机上安装了 SSH 服务。 2. **配置 SSH 密钥**: 在本地机器和远程宿主机之间需要有一对 SSH 密钥(通常是 `id_rsa` 和 `id_rsa.pub`),用于无密码登录。 3. **设置 SSH 代理**: IDEA 使用一个名为 `idea-docker-ssh` 的内部工具,通过 SSH 隧道将本地 Docker 客户端的请求转发到远程宿主机的 Docker 服务。 4. **建立连接**: 当 IDEA 检测到你想要通过 SSH 连接到远程 Docker 环境时,它会自动尝试使用配置好的 SSH 密钥和宿主机的 IP 地址来建立连接。 ## 原理 [Section titled “原理”](#原理) * **SSH 隧道**: 通过 SSH 隧道技术,本地 Docker 客户端与远程宿主机之间的通信被加密并转发。 * **Docker 远程 API**: 一旦通过 SSH 建立连接,本地 Docker 客户端会通过远程 API 与远程宿主机的 Docker 服务进行交互。 ## 在本地通过 SSH 控制内网 Docker [Section titled “在本地通过 SSH 控制内网 Docker”](#在本地通过-ssh-控制内网-docker) 要通过 SSH 在本地控制内网中的 Docker 宿主机,你需要确保以下条件满足: 1. **远程宿主机配置**: * 确保 Docker 服务正在运行。 * 确保宿主机上的 SSH 服务已安装并允许无密码登录(通过 `ssh-copy-id` 或 `ssh-agent`)。 * 确保防火墙和端口转发设置允许 SSH 连接。 2. **本地机器配置**: * 拥有对远程宿主机的 SSH 密钥。 * 安装并配置 `idea-docker-ssh` 工具(通常 IDEA 会自动处理这一步骤)。 3. **在 IDEA 中配置**: * 在 IDEA 中,打开 “Preferences”(或 “Settings”),然后找到 Docker 设置。 * 配置 Docker 的远程 URL 为 SSH 协议加上宿主机的 IP 地址和端口。例如: `ssh://@:`。 * 输入你的 SSH 密钥路径,如果 IDEA 没有自动检测到。 4. **建立连接并操作**: * 完成以上设置后,IDEA 应该能够自动建立 SSH 连接和 Docker 环境。 * 你现在应该可以在 IDEA 中运行 Docker 命令,并对远程 Docker 宿主机上的容器进行操作。 ## 注意事项 [Section titled “注意事项”](#注意事项) * 确保你拥有访问远程宿主机的权限。 * 确保所有操作符合你所在组织的政策和安全标准。 * 保护好你的 SSH 密钥,不要让它落入未经授权的人手中。 在操作过程中,如果有任何不确定的地方,建议查阅更详细的官方文档或咨询有经验的开发者。 # 修改docker容器的密码, 并且开启ssh远程连接 要修改Docker容器的密码并开启SSH远程连接,你需要确保容器中运行了一个SSH服务器。以下是一个基于Ubuntu镜像的示例,说明如何创建一个Docker容器,安装SSH服务器,设置一个root密码,并允许远程SSH连接。 1. 创建一个Dockerfile,用于构建包含SSH服务器的镜像: ```dockerfile # 使用官方Ubuntu镜像 FROM ubuntu # 安装SSH服务器 RUN apt-get update && apt-get install -y openssh-server RUN mkdir /var/run/sshd RUN echo 'root:password' | chpasswd RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config # 允许密码认证 RUN sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config # 开放SSH端口 EXPOSE 22 # 启动SSH服务 CMD ["/usr/sbin/sshd", "-D"] ``` 请注意,这个Dockerfile中使用了非常简单的密码(`password`)作为示例。在实际使用中,你应该使用一个更复杂的密码。 2. 使用Dockerfile构建镜像: ```bash docker build -t my-ssh-image . ``` 3. 运行容器: ```bash docker run -d -p 2222:22 my-ssh-image ``` 这个命令将容器内部的22端口映射到宿主机的2222端口,以便你可以通过SSH连接到宿主机的2222端口来访问容器。 4. 使用SSH客户端连接到容器: ```bash ssh root@ -p 2222 ``` 将``替换为你的宿主机IP地址。当你第一次连接时,SSH客户端可能会警告你新主机身份无法验证,输入`yes`以继续。 5. 如果你需要修改已经运行的容器的root密码,你可以进入容器并使用`passwd`命令: ```bash docker exec -it passwd ``` 将``替换为你的容器ID。然后按照提示输入新密码。 请确保你了解这些操作的安全性影响。在生产环境中,使用SSH访问容器时应该采取额外的安全措施,例如使用SSH密钥而不是密码,以及限制可以访问容器的IP地址。此外,运行SSH服务可能会增加安全风险,因此请确保你了解这些风险并采取适当的安全措施。 # /etc/docker/daemon.json配置, 怎么配置远程控制 要在 Docker 中配置远程控制,你需要在 `/etc/docker/daemon.json` 文件中进行一些配置变更。这个文件用于配置 Docker 守护进程的的行为。以下是一些配置远程控制所需要设置的选项: 1. **开启远程API访问**: 你可以通过设置 `--api-cors-header` 参数来允许跨域请求。例如,如果你想允许所有来源的跨域请求,可以设置为 `"*"`。 ```json { "exec-opts": ["native.cgroupdriver=systemd"], "log-driver": "json-file", "log-opts": { "max-size": "100m" }, "storage-driver": "overlay2", "storage-opts": [ "overlay2.override_kernel_check=true" ], "registry-mirrors": [ "https://registry.docker-cn.com" ], "api-cors-header": "*" } ``` 2. **配置 TLS 证书**: 如果你想通过 TLS 安全地访问 Docker API,你需要配置 TLS 证书。这通常涉及到为 Docker 守护进程和服务器端创建证书。然后,你可以在 `daemon.json` 中指定这些证书的路径。 ```json { "exec-opts": ["native.cgroupdriver=systemd"], "tls-verify": "true", "tls-ca-cert": "/path/to/ca.pem", "tls-cert": "/path/to/cert.pem", "tls-key": "/path/to/key.pem" } ``` 3. **配置监听端口**: 默认情况下,Docker 守护进程监听本地 Unix 套接字和 TCP 端口 2375。如果你想监听不同的端口或套接字,可以设置 `debug` 和 `hosts` 选项。 ```json { "debug": true, "hosts": ["tcp://0.0.0.0:2376", "unix:///var/run/docker.sock"], "exec-opts": ["native.cgroupdriver=systemd"], "log-driver": "json-file", "log-opts": { "max-size": "100m" }, "storage-driver": "overlay2", "storage-opts": [ "overlay2.override_kernel_check=true" ], "registry-mirrors": [ "https://registry.docker-cn.com" ], "tls-verify": "true", "tls-ca-cert": "/path/to/ca.pem", "tls-cert": "/path/to/cert.pem", "tls-key": "/path/to/key.pem" } ``` 请确保根据你的实际情况调整上述配置中的路径和值。在修改 `daemon.json` 文件后,需要重启 Docker 服务以使配置生效。 在 Linux 系统中,你可以使用以下命令来重启 Docker 服务: ```bash sudo systemctl restart docker ``` 如果你使用的是 Docker Desktop 版本,通常会有一个 GUI 界面来帮助你进行配置和重启操作。 # docker命令怎么控制远程docker 要控制远程的 Docker 实例,您需要确保 Docker 守护进程(dockerd)在远程服务器上正在运行,并且客户端有权限与之通信。以下是详细步骤: ## 1. 确保远程 Docker 服务正在运行 [Section titled “1. 确保远程 Docker 服务正在运行”](#1-确保远程-docker-服务正在运行) 首先,您需要确认远程服务器上的 Docker 守护进程正在运行。这可以通过 SSH 连接到远程服务器并执行以下命令来检查: ```bash ssh username@remote_server docker ps ``` 如果 Docker 正在运行,您应该能看到一些列出的容器。 ## 2. 配置 Docker 客户端 [Section titled “2. 配置 Docker 客户端”](#2-配置-docker-客户端) 您可能需要配置 Docker 客户端以连接到远程 Docker 守护进程。这可以通过环境变量或命令行参数来实现。 ### 使用环境变量 [Section titled “使用环境变量”](#使用环境变量) 您可以通过设置 `DOCKER_HOST` 环境变量来指定 Docker 守护进程的地址。例如,如果您知道远程 Docker 守护进程正在端口 2376 上监听 TCP,则可以这样设置: ```bash export DOCKER_HOST=tcp://remote_server:2376 ``` 为了确保这个环境变量在后续的 SSH 会话中也能使用,您可以将其添加到您的 `~/.bashrc` 或 `~/.profile` 文件中。 ### 使用命令行参数 [Section titled “使用命令行参数”](#使用命令行参数) 您也可以在每次使用 Docker 命令时通过命令行参数来指定 Docker 守护进程的地址,例如: ```bash docker -H tcp://remote_server:2376 ps ``` ## 3. 使用 SSH 端口转发 [Section titled “3. 使用 SSH 端口转发”](#3-使用-ssh-端口转发) 为了安全地连接到远程 Docker 守护进程,您可以通过 SSH 端口转发来实现。在 SSH 客户端上,您可以指定将本地端口转发到远程服务器上的 Docker 守护进程端口。 例如,如果您希望在本地机器的 2376 端口上接收远程服务器上的 Docker 守护进程的流量,您可以这样做: ```bash ssh -L 2376:remote_server:2376 username@remote_server ``` 执行此操作后,您可以通过 `docker -H tcp://localhost:2376 ps` 在本地机器上运行 Docker 命令,而实际上它们会通过 SSH 隧道转发到远程 Docker 守护进程。 ## 4. 验证连接 [Section titled “4. 验证连接”](#4-验证连接) 完成上述配置后,您可以通过运行 Docker 命令并查看是否能够成功连接到远程 Docker 守护进程来验证设置是否正确。 ```bash docker --host tcp://remote_server:2376 ps ``` 如果一切设置正确,您应该能够看到远程服务器上的 Docker 容器列表。 ## 5. 注意安全性 [Section titled “5. 注意安全性”](#5-注意安全性) 在配置远程 Docker 访问时,请确保采取适当的安全措施。这可能包括限制能够访问 Docker 守护进程的 IP 地址(例如,通过 SSH 密钥认证而非密码认证),使用 TLS 证书验证,以及在必要时设置密码或密钥传递。 ## 6. 使用 Docker Compose 和 Docker Machine(可选) [Section titled “6. 使用 Docker Compose 和 Docker Machine(可选)”](#6-使用-docker-compose-和-docker-machine可选) 如果您在远程服务器上使用 Docker Compose 或者通过 Docker Machine 管理 Docker 实例,您需要确保相应的配置文件和设置也指向正确的远程 Docker 守护进程。 通过遵循这些步骤,您应该能够有效地控制远程服务器上的 Docker 实例。请确保您有足够的权限来启动和运行 Docker 守护进程,并且在操作过程中遵循最佳安全实践。 # git管理子项目的方式 在Git中管理子项目(submodules)是一种将一个Git仓库作为另一个Git仓库的子目录的方式。这种方式通常用于当你的主项目需要依赖于另一个项目,而这个被依赖的项目又有自己的独立版本控制需求时。 以下是如何在Git中添加、使用和更新子项目的基本步骤: ## 添加子项目 [Section titled “添加子项目”](#添加子项目) 1. 在主项目目录中,使用以下命令添加子项目: ```sh git submodule add <子项目URL> <子项目在主项目中的路径> # 这种方式需要在指定目录下执行, 会自动生成<子项目在主项目中的路径>(生成规则: <指定路径>/<子项目URL最后一级路径(去掉了.git后缀)>) git submodule add <子项目URL> ``` 例如: ```sh git submodule add https://github.com/username/subproject.git path/to/subproject ``` 2. 提交更改到主项目的仓库: ```sh git commit -m "Add submodule" ``` 3. 推送更改到远程仓库: ```sh git push origin <分支名> ``` ## 克隆含有子项目的主项目 [Section titled “克隆含有子项目的主项目”](#克隆含有子项目的主项目) 当克隆一个含有子项目的主项目时,默认情况下子项目目录是空的。你需要运行以下命令来初始化并更新子项目: ```sh git submodule init git submodule update ``` 或者,你可以使用一条命令同时初始化和更新所有子项目: ```sh git submodule update --init --recursive ``` ## 更新子项目 [Section titled “更新子项目”](#更新子项目) 当子项目有更新时,你可以使用以下命令来更新主项目中子项目的引用: ```sh git submodule update --remote <子项目名> ``` 或者,如果你想更新所有子项目,可以使用: ```sh git submodule foreach git pull ``` ## 删除子项目 [Section titled “删除子项目”](#删除子项目) 如果你想从主项目中删除子项目,可以使用以下步骤: 1. 删除`.gitmodules`文件中对应的子项目条目。 2. 删除`.git/config`文件中对应的子项目条目。 3. 删除子项目目录。 4. 提交更改并推送到远程仓库。 ## 注意事项 [Section titled “注意事项”](#注意事项) * 子项目可以是任何Git仓库,包括公共的和私有的。 * 子项目可以嵌套,即子项目本身可以包含其他子项目。 * 使用子项目时需要小心,因为它们可能会增加项目的复杂性。 子项目是一种强大的工具,但它们也有一定的学习曲线。确保你完全理解它们的操作方式,特别是当你需要在不同开发者之间共享项目时。 # git命令中的`--recurse-submodules`作用 在Git中,`--recurse-submodules`标志用于在克隆主项目的同时递归地克隆所有子模块。子模块是Git中一种将一个Git仓库作为另一个Git仓库的子目录的方式,通常用于当主项目需要依赖于其他项目时。 当你运行带有`--recurse-submodules`标志的`git clone`命令时,Git会执行以下操作: 1. 克隆主项目仓库。 2. 检测主项目中的`.gitmodules`文件,该文件包含了子模块的配置信息。 3. 对于`.gitmodules`文件中列出的每个子模块,Git会克隆子模块的仓库到主项目中指定的路径。 4. 将子模块注册到主项目的`.git/config`文件中,以便于后续的子模块操作,如更新、推送等。 简而言之,`--recurse-submodules`的作用是确保在克隆主项目的同时,其依赖的所有子模块也被克隆并设置好,以便开发者可以直接开始工作,而无需手动初始化和更新子模块。 这是命令的示例输出: ```sh Cloning into 'telepresence-local-quickstart'... ... Submodule 'path/to/submodule' (https://github.com/username/submodule.git) registered for path 'path/to/submodule' Cloning into 'path/to/submodule'... ... Submodule path 'path/to/submodule': checked out 'commit-hash' ``` 在使用子模块时,请确保你熟悉如何更新子模块、解决子模块的合并冲突以及如何将更改推送到子模块的远程仓库。 # git只克隆指定某几个子模块到本地 在 Git 中,如果您只想克隆指定的子模块到本地,可以按照以下步骤进行操作: 1. 首先,克隆父项目,但不初始化子模块: ```bash git clone --no-recurse-submodules <父项目的 Git 地址> ``` 2. 进入克隆下来的父项目目录。 3. 编辑 `.gitmodules` 文件,将您不想要克隆的子模块的相关部分注释掉或者删除。 4. 运行以下命令初始化并更新指定的子模块: ```bash git submodule update --init -- <子模块的路径> ``` 例如,如果您的项目中有 `submodule1`、`submodule2` 和 `submodule3` 三个子模块,而您只想克隆 `submodule1` 和 `submodule2`,您可以按照上述步骤操作,在编辑 `.gitmodules` 文件时,保留 `submodule1` 和 `submodule2` 的相关配置,注释或删除 `submodule3` 的配置,然后运行 `git submodule update --init -- submodule1` 和 `git submodule update --init -- submodule2` 来分别初始化和克隆这两个子模块。 # java hprof文件如何导出 在 Java 中,要导出 `hprof` 文件可以通过以下几种方式: **使用 `jmap` 命令**: ```bash jmap -dump:format=b,file=your_dump_file.hprof ``` 其中 `` 是要分析的 Java 进程的 ID。 例如,如果进程 ID 是 12345 ,则命令为: ```bash jmap -dump:format=b,file=your_dump_file.hprof 12345 ``` **在 Java 应用启动时添加参数**: 可以在启动 Java 应用时添加 `-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dump.hprof` 这样的参数。当发生内存溢出错误时,会自动生成 `hprof` 文件到指定的路径。 **通过 JConsole 工具**: 连接到正在运行的 Java 进程,在“内存”选项卡中,有导出堆转储的功能。 需要注意的是,导出的 `hprof` 文件可能会很大,并且分析 `hprof` 文件需要使用专门的工具,如 `Eclipse Memory Analyzer` 等。 # systemctl管理Java进程无限重启问题 ```bash # 查看指定日期以来的相关报错日志 journalctl -u manage-service.service --since "2025-09-03 00:00:00" | grep "Main process exited" -C 5 ``` ## AI相关回复片段 [Section titled “AI相关回复片段”](#ai相关回复片段) 是的,systemd 会记录服务的状态变化和重启原因,你可以通过以下命令查看相关日志来定位触发重启的具体原因: 1. **查看服务的详细日志(推荐)**: ```bash journalctl -u support-service -f ``` * `-u support-service`:指定查看 `support-service` 服务的日志 * `-f`:实时跟踪最新日志(可省略,用于实时监控) 2. **查看服务的重启历史和状态**: ```bash systemctl status support-service ``` 该命令会显示服务的当前状态、最近的重启时间、退出码等信息,例如: ```plaintext ● support-service.service - support-service Loaded: loaded (/etc/systemd/system/support-service.service; enabled; vendor preset: disabled) Active: active (running) since Wed 2025-09-03 10:00:00 CST; 5min ago Process: 12345 ExecStart=/usr/bin/java ... (code=exited, status=143) Main PID: 67890 (java) CGroup: /system.slice/support-service.service └─67890 /usr/bin/java -jar ... ``` 其中 `code=exited, status=143` 表示上一次退出的状态码(143 通常对应 SIGTERM 信号)。 3. **查看更早期的日志**: ```bash journalctl -u support-service --since "2025-09-03 09:00:00" --until "2025-09-03 10:00:00" ``` 通过时间范围筛选特定时段的日志。 **关键日志信息解读**: * 如果日志中出现 `Main process exited, code=exited, status=1/FAILURE`,说明应用程序自身异常退出(非零状态码),触发了 `Restart=on-failure` 配置。 * 如果出现 `Killed process 12345 (java) total-vm:2048M, ...`,可能是因为内存超过 `MemoryLimit=1024M` 限制被系统杀死。 * 如果出现 `Stopped support-service.` 后紧接着 `Started support-service.`,说明服务被主动停止后重启(可能是手动操作或其他进程触发)。 结合应用程序自身的日志(通常在 `/data/xxx/support-service` 目录下),可以更全面地定位重启原因(例如 OOM 错误、未捕获的异常等)。 # Linux查看某个进程占用的内存大小 在 Linux 系统中,有多种方法可以查看某个进程占用的内存大小,以下是一些常见的方法: **方法一:使用 `ps` 命令** `ps` 命令可以显示进程的状态信息,包括内存使用情况。 例如: ```bash ps -aux | grep <进程名> ``` 通过这个命令,可以获取到指定进程的相关信息,其中 `RSS` 列显示的就是进程占用的物理内存大小(单位为 KB)。 **方法二:使用 `top` 命令** `top` 命令是一个动态的系统性能监控工具。 在 `top` 界面中,按 `P` 键可以按照 CPU 使用率对进程排序,按 `M` 键可以按照内存使用率对进程排序。找到您关注的进程,就能看到其内存使用情况。 **方法三:使用 `pmap` 命令** `pmap` 命令可以报告进程的内存映射关系及占用情况。 例如: ```bash pmap <进程 ID> ``` 它会显示进程的详细内存分布情况。 假设我们要查看一个名为 `nginx` 的进程占用的内存大小,就可以使用上述命令来获取相关信息。比如使用 `ps -aux | grep nginx` ,输出可能类似于: ```bash root 1234 0.0 0.1 123456 7890? Ss 14:00 0:00 nginx: master process /usr/sbin/nginx ``` 其中 `123456` 就是该进程占用的物理内存大小(单位为 KB)。 # maven如何生成QueryDSL的q版实体类 要使用Maven生成QueryDSL的Q类,您可以使用`maven-compiler-plugin`插件。以下是使用该插件生成Q类的步骤: 1. 在您的Maven项目的`pom.xml`文件中,添加以下插件配置: ```xml org.apache.maven.plugins maven-compiler-plugin 3.11.0 com.querydsl querydsl-apt 5.0.0 jpa javax.persistence javax.persistence-api 2.2 ``` 2. 运行Maven构建命令,例如`mvn clean install`。 3. Maven将使用`querydsl-apt`和`javax.persistence-api`依赖项来生成Q类。生成的Q类将位于`target/generated-sources/java`目录下。 现在,您可以在您的项目中使用生成的Q类来进行QueryDSL查询。 *** Learn more: 1. [spring - QueryDsl - How to create Q classes with maven? - Stack Overflow](https://stackoverflow.com/questions/24889990/querydsl-how-to-create-q-classes-with-maven) 2. [3.3. Code generation](http://querydsl.com/static/querydsl/3.2.0/reference/html/ch03s03.html) 3. [How to configure maven to generate QueryDSL classes when using both my own AspectJ ITDs and Roo?](https://groups.google.com/g/querydsl/c/NEiQzP4m1xA) # mihomo docker 配置 > 宿主机, Docker容器和k8s容器内部都能够正常走代理访问国外网络的通用版本 * 临时使用: 可以让内网服务器访问国外的流量代理到同局域网的本地电脑(本地电脑当代理节点, 需开启局域网连接)中来, 本地电脑开tun走clash去访问国外网络 * 长期使用: 节点需要部署到公网服务器中了, 或者走隧道访问内网节点等 ## 可视化UI [Section titled “可视化UI”](#可视化ui) ### 内置可视化UI(推荐) [Section titled “内置可视化UI(推荐)”](#内置可视化ui推荐) ```bash # config.yml文件开头添加 external-controller: 0.0.0.0:19090 secret: "your-strong-password" # TODO: 按实际调整密码 # 开启本地 UI,mihomo 启动时会自动下载前端文件到 ./ui 目录 external-ui: ui # 看自己喜欢选择合适的UI面板 external-ui-url: "https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip" # external-ui-url: "https://github.com/MetaCubeX/Yacd-meta/archive/refs/heads/gh-pages.zip" # 其他配置 ... ``` 访问地址示例: ### 外部可视化UI [Section titled “外部可视化UI”](#外部可视化ui) 可能需要配置跨域等, 自行AI了解 ## 注意⚠️: 可能得考虑k8s本身的cni网络是否兼容tun虚拟网卡的情况 [Section titled “注意⚠️: 可能得考虑k8s本身的cni网络是否兼容tun虚拟网卡的情况”](#注意️-可能得考虑k8s本身的cni网络是否兼容tun虚拟网卡的情况) **对照下表 CNI 做参考:** | 看到的 DaemonSet 名称 | 对应的 CNI 插件 | 对 TUN 模式的兼容性 | | :--------------------------------- | :------------------------- | :--------------------------------------------------------------------- | | `kube-flannel-ds` / `kube-flannel` | **Flannel** | ⭐⭐⭐⭐⭐ **极好**(默认使用 VXLAN/HostGW,流量走主路由表,完美兼容 TUN) | | `calico-node` | **Calico** | ⭐⭐⭐ **视模式而定**(如果是 IPIP/VXLAN 模式兼容较好;如果是 BGP 纯路由模式也兼容;但如果是 eBPF 模式则不兼容) | | `cilium` | **Cilium** | ❌ **不兼容**(默认使用 eBPF 绕过内核路由表,TUN 无法拦截) | | `kube-ovn-cni` | **Kube-OVN** | ⭐⭐⭐⭐ **很好**(类似 Flannel,通常兼容 TUN) | | `weave-net` | **Weave** | ⭐⭐⭐⭐ **较好** | | `canal` | **Canal** (Flannel+Calico) | ⭐⭐⭐⭐ **较好** | | `kube-router` | **Kube-router** | ⭐⭐⭐⭐ **较好** | *(注: **KubeKey / KubeSphere** 默认安装时, 使用的是 **Calico** 或 **Flannel** 网段。)* # docker版mihomo的SOP 可以。**Mihomo 完全支持以 Docker 方式运行,并且可以控制宿主机全局走 TUN 虚拟网卡。** 根据 Mihomo 官方文档和 Docker 网络驱动的最佳实践,要实现“Docker 运行 + 宿主机全局代理”,关键点在于:**必须使用 `host` 网络模式**,并赋予容器**网络管理权限**。 ### 1. 核心原理 [Section titled “1. 核心原理”](#1-核心原理) 当 Docker 容器使用 `--network host` 时,它不再拥有独立的网络命名空间,而是直接共享宿主机的网卡和路由表。配合 `cap_add: NET_ADMIN`,容器内的 Mihomo 进程就有权限在宿主机内核中创建 `utun` 设备并修改系统路由,从而实现全局接管。 *** ### 2. Docker Compose SOP(权威推荐方案) [Section titled “2. Docker Compose SOP(权威推荐方案)”](#2-docker-compose-sop权威推荐方案) 这是最优雅的部署方式。请在您的服务器新建一个目录(如 `/opt/mihomo`),准备以下两个文件: #### A. `docker-compose.yaml` [Section titled “A. docker-compose.yaml”](#a-docker-composeyaml) ```yaml services: mihomo: image: metacubex/mihomo:latest container_name: mihomo restart: always # 关键点 1:共享宿主机网络栈 network_mode: "host" # 关键点 2:赋予创建虚拟网卡和修改路由的权限 cap_add: - NET_ADMIN devices: - /dev/net/tun volumes: - ./config.yaml:/root/.config/mihomo/config.yaml logging: driver: "json-file" options: max-size: "10m" ``` #### B. `config.yaml` (根据您的代理地址转换) [Section titled “B. config.yaml (根据您的代理地址转换)”](#b-configyaml-根据您的代理地址转换) 将您之前的代理信息直接写入 `proxies` 节点。 ```yaml mixed-port: 7890 allow-lan: true log-level: info ipv6: false dns: enable: true enhanced-mode: fake-ip nameserver: - 223.5.5.5 - 119.29.29.29 # 关键:开启 TUN 模式接管宿主机全局 tun: enable: true stack: system # 官方推荐 Linux 使用 system 栈 auto-route: true # 核心:自动修改宿主机路由表实现全局代理 auto-detect-interface: true dns-hijack: - "any:53" proxies: - name: "Your-Gateway-Proxy" type: http # 您提供的 http_proxy 对应类型 server: 10.0.4.95 port: 7897 proxy-groups: - name: "MATCH" type: select proxies: - "Your-Gateway-Proxy" - DIRECT rules: - MATCH,MATCH # 所有流量走代理 ``` *** ### 3. 使用步骤 (SOP) [Section titled “3. 使用步骤 (SOP)”](#3-使用步骤-sop) 1. **准备环境**: 确保宿主机已安装 Docker 和 Docker Compose。 2. **创建文件**: 将上述两个文件放在同一个文件夹下。 3. **启动容器**: ```bash sudo docker compose up -d ``` 4. **验证生效**: * **查看网卡**:执行 `ip addr`,如果看到 `utun` 或 `mihomo0` 类似的网卡,说明 TUN 已启动。 * **验证流量**:直接在宿主机执行 `curl -I https://www.google.com`。 * **验证容器**:启动一个新容器 `docker run --rm alpine curl -I https://www.google.com`,由于宿主机路由已被接管,该容器流量也会自动走代理。 *** ### 4. 为什么这个方案比 `export` 更好? [Section titled “4. 为什么这个方案比 export 更好?”](#4-为什么这个方案比-export-更好) * **真正的全局**:`export` 只能覆盖支持环境变量的应用。TUN 模式覆盖内核路由,无论是 `git`、`apt`、`docker pull` 还是容器内的流量,全部自动生效。 * **无感透传**:容器不需要任何额外配置。 * **一键管理**:通过 `docker compose stop` 停止容器后,Mihomo 会自动清理宿主机路由,网络立即恢复原样,不会残留垃圾配置。 **需要我为您检查一下您的 10.0.4.95 代理是否支持 UDP 流量(这会影响 TUN 模式下的某些应用体验)吗?** # export_http_proxy 转成 Mihomo 配置的 SOP 基于 Mihomo(原 Clash.Meta)的官方文档规范,要将您的 `10.0.4.95:7897` 代理转换为 Mihomo 配置,最权威且“一次性解决所有流量”的方案是使用 **TUN 模式**。 这种方案通过内核级虚拟网卡接管流量,使得宿主机、Docker 容器以及所有非 HTTP 协议(如 ICMP/UDP)都能无感走代理。 *** ## 1. Mihomo 核心配置文件 (`config.yaml`) [Section titled “1. Mihomo 核心配置文件 (config.yaml)”](#1-mihomo-核心配置文件-configyaml) 请在 `/etc/mihomo/config.yaml` 中写入以下内容。此配置严格遵循 Mihomo 官方的 `tun` 字段规范。 ```yaml # 混合端口,支持 HTTP(S) 和 SOCKS5 mixed-port: 7890 allow-lan: true bind-address: '*' mode: rule log-level: info ipv6: false # DNS 模块 (TUN 模式必须配置 DNS 劫持) dns: enable: true enhanced-mode: fake-ip nameserver: - 223.5.5.5 - 119.29.29.29 # --- 核心:TUN 模式配置 --- tun: enable: true stack: system # 使用系统协议栈,性能最稳 auto-route: true # 自动设置全局路由,接管容器流量 auto-detect-interface: true # 自动定位物理网卡 dns-hijack: - "any:53" # 劫持所有 DNS 请求 # --- 转换您的代理配置 --- proxies: - name: "My-Gateway-Proxy" type: http # 对应您的 http_proxy server: 10.0.4.95 port: 7897 # 如果是 SOCKS5 也可以改为 type: socks5 proxy-groups: - name: "MATCH" type: select proxies: - "My-Gateway-Proxy" - DIRECT rules: - MATCH,MATCH # 全局流量强制走该代理 ``` *** ## 2. 标准操作程序 (SOP) [Section titled “2. 标准操作程序 (SOP)”](#2-标准操作程序-sop) ### 第一步:下载并安装二进制文件 [Section titled “第一步:下载并安装二进制文件”](#第一步下载并安装二进制文件) 从 Mihomo 官方 [GitHub Releases](https://github.com/MetaCubeX/mihomo/releases) 下载对应架构(通常是 `linux-amd64`)的包。 ```bash # 解压并移动到系统路径 sudo mv mihomo-linux-amd64 /usr/local/bin/mihomo sudo chmod +x /usr/local/bin/mihomo ``` ### 第二步:创建配置目录 [Section titled “第二步:创建配置目录”](#第二步创建配置目录) ```bash sudo mkdir -p /etc/mihomo # 将上面的 yaml 内容保存到 /etc/mihomo/config.yaml ``` ### 第三步:配置 Systemd 服务(推荐) [Section titled “第三步:配置 Systemd 服务(推荐)”](#第三步配置-systemd-服务推荐) 这是最权威的持久化运行方式。创建文件 `/etc/systemd/system/mihomo.service`: ```ini [Unit] Description=Mihomo Daemon After=network.target [Service] Type=simple User=root WorkingDirectory=/etc/mihomo ExecStart=/usr/local/bin/mihomo -d /etc/mihomo Restart=always # 给予修改网卡和路由的权限 CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW [Install] WantedBy=multi-user.target ``` ### 第四步:启动与验证 [Section titled “第四步:启动与验证”](#第四步启动与验证) ```bash # 启动服务 sudo systemctl daemon-reload sudo systemctl enable --now mihomo # 验证网卡是否生成 (会出现一个名为 utun 的网卡) ip addr show utun # 验证容器流量 docker run --rm curlimages/curl -s https://www.google.com ``` *** ## 3. 为什么这个方案符合您的要求? [Section titled “3. 为什么这个方案符合您的要求?”](#3-为什么这个方案符合您的要求) 1. **全局覆盖**:`tun.auto-route: true` 会修改系统路由表。这意味着无论是普通的 `curl`,还是 Docker 内部的流量,都会被强制导向 `utun` 网卡,无需再执行任何 `export` 命令。 2. **权威性**:配置采用了 `fake-ip` 模式和 `system` stack,这是 Mihomo 官方推荐的 Linux 环境高性能透明代理标准。 3. **优雅性**:不再需要修改 Docker 的 `config.json` 或环境变量,对系统侵入性最小,关掉 Mihomo 服务,系统网络立即恢复原状。 **注意**:由于开启了 TUN 模式,Mihomo 必须以 **root** 权限运行(或拥有 `CAP_NET_ADMIN` 权限)。 您需要我为您提供一个 Python 脚本来自动完成上述所有文件的创建和安装吗? # mihomo docker 配置 ## 关于本地内网IP用域名的问题 [Section titled “关于本地内网IP用域名的问题”](#关于本地内网ip用域名的问题) ### 🛠️ 方案一:清空 systemd-resolved 缓存(推荐)⭐ [Section titled “🛠️ 方案一:清空 systemd-resolved 缓存(推荐)⭐”](#️-方案一清空-systemd-resolved-缓存推荐) 方法 1:重启 systemd-resolved 服务(最简单) ```bash # Ubuntu系统 # 重启服务(会清空所有 DNS 缓存) sudo systemctl restart systemd-resolved # 验证服务状态 sudo systemctl status systemd-resolved ``` 方法 2:使用 resolvectl 命令(更优雅) ```bash # 清空所有缓存 sudo resolvectl flush-caches # 查看缓存统计(确认已清空) sudo resolvectl statistics ``` ### 🔍 第二步:验证域名解析是否更新 [Section titled “🔍 第二步:验证域名解析是否更新”](#-第二步验证域名解析是否更新) ```bash # 1. 使用 resolvectl 查询(绕过本地缓存,直接问上游) resolvectl query mbp-fa.tx.iuin888vip.icu # 4. 对比系统解析结果(可能仍有缓存) getent hosts mbp-fa.tx.iuin888vip.icu ``` 2️⃣ 检查域名 TTL 设置 ```bash # 查询域名的实际 TTL 值 dig mbp-fa.tx.iuin888vip.icu +nocmd +noall +answer # 输出示例: # mbp-fa.tx.iuin888vip.icu. 300 IN A 203.0.113.50 # ↑ # TTL=300 秒(5 分钟) ``` ## Docker容器和k8s容器内部都需要能够正常走VPN代理 [Section titled “Docker容器和k8s容器内部都需要能够正常走VPN代理”](#docker容器和k8s容器内部都需要能够正常走vpn代理) ### 部署与验证指南 (业界避坑标准流程) [Section titled “部署与验证指南 (业界避坑标准流程)”](#部署与验证指南-业界避坑标准流程) 1. 获取真实的 K8s CIDR (必做) 配置中的 10.244.0.0/16 和 10.96.0.0/12 是默认值。您必须在宿主机上执行以下命令,获取您集群真实的网段,并替换到 route-exclude-address 中: ```bash # 获取 Pod CIDR: kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.podCIDR}{"\n"}{end}' # 或者查看 node 的 podCIDR: kubectl get nodes -o jsonpath='{.items[*].spec.podCIDR}' # 获取 Service CIDR: ps aux | grep kube-apiserver | grep service-cluster-ip-range # 假设输出 10.96.0.1,则网段通常为 10.96.0.0/12 或 10.96.0.0/16 ``` # docker容器和k8s容器内部都需要能够正常走vpn代理 在同时运行 Docker 和 Kubernetes (K8s) 的宿主机上开启全局 TUN 透明代理,在业界属于**高危操作**。如果配置不当,极易引发“集群脑裂”、“CoreDNS 瘫痪”或“Pod 网络黑洞”。 针对您的复杂环境,我对之前的配置进行了**深度重构**。这份配置基于 **Mihomo (Clash.Meta) 在 K8s 节点部署的最佳实践**,解决了虚拟网卡流量接管、内部 DNS 劫持冲突以及路由黑洞等核心痛点。 *** ### 一、 深入分析:为什么之前的配置在 K8s/Docker 下会崩溃? [Section titled “一、 深入分析:为什么之前的配置在 K8s/Docker 下会崩溃?”](#一-深入分析为什么之前的配置在-k8sdocker-下会崩溃) 1. **致命误区:排除虚拟网卡 (`exclude-interface`)** * **错误做法**:之前建议排除 `docker0`、`cni0` 等网卡。 * **真相**:如果在 Mihomo 中排除了这些虚拟网卡,容器发出的流量到达网桥后,**将直接被放行而不进入 TUN 虚拟网卡**。这会导致 Docker 和 K8s 容器**彻底无法走代理**。 * **业界实践**:**必须放行所有虚拟网卡**,让流量进入宿主机路由表,然后通过**IP 级别的路由排除 (`route-exclude-address`)** 来保证内部通信直连,外部流量进入 TUN 被代理。 2. **DNS 劫持导致 CoreDNS 瘫痪** * **冲突点**:`dns-hijack: any:53` 会无差别劫持所有 53 端口流量。K8s Pod 解析内部服务时,目标是 CoreDNS (如 `10.96.0.10:53`)。如果被劫持,Mihomo 会去公网解析内部域名,导致失败。 * **业界实践**:只要将 K8s 的 Service CIDR (`10.96.0.0/12`) 加入 `route-exclude-address`,去往 CoreDNS 的包在路由层就会被剔除,**根本不会进入 TUN 设备**,从而完美绕过 `dns-hijack` 的拦截。 3. **API Server 失联 (节点 NotReady)** * **冲突点**:Kubelet 需要与 API Server (通常是 6443 端口) 保持心跳。如果宿主机的物理 IP 或 API Server 的 IP 被 TUN 代理劫持,会导致心跳超时,K8s 节点状态变为 `NotReady`。 *** ### 二、 业界生产级完整精简版配置 (K8s/Docker 深度融合版) [Section titled “二、 业界生产级完整精简版配置 (K8s/Docker 深度融合版)”](#二-业界生产级完整精简版配置-k8sdocker-深度融合版) 请直接使用以下配置,它已经最大程度精简了非必要参数,并对 K8s/Docker 进行了针对性加固。 ```yaml # ================= 基础配置 ================= mode: rule allow-lan: true bind-address: '127.0.0.1' # 保证 API 仅本地访问 mixed-port: 7890 log-level: info ipv6: false # ================= DNS 配置 ================= dns: enable: true enhanced-mode: fake-ip fake-ip-range: 198.18.0.1/16 # [核心加固] 保护 K8s/Docker 内部服务发现域名,防止被分配 Fake-IP fake-ip-filter: - '*.lan' - '*.local' - '*.arpa' - '*.svc' # K8s Service 简写 - '*.svc.cluster.local' # K8s 内部完整域名 - 'kubernetes.default' # K8s 默认 API 域名 respect-rules: true # [生产必备] 让 DNS 解析严格遵循下方的 rules 分流规则 nameserver: - https://doh.pub/dns-query - https://dns.alidns.com/dns-query proxy-server-nameserver: - https://doh.pub/dns-query # ================= Sniffer (嗅探器) ================= sniffer: enable: true sniff: HTTP: ports: [80, 8080-8880] override-destination: true TLS: ports: [443, 8443] # ================= TUN 模式配置 (核心重构区) ================= tun: enable: true stack: gvisor # [生产必备] 彻底解决 system 栈在复杂网络下的日志刷屏问题 auto-route: true auto-detect-interface: true strict-route: false dns-hijack: - "any:53" # 配合下方的 route-exclude-address,实现“外网劫持,内网放行” # [严重警告] 绝对不要排除 docker0, cni0 等虚拟网卡!否则容器将无法走代理! # exclude-interface: route-exclude-address: # 1. 常规私有网段直连 - 127.0.0.0/8 - 10.0.0.0/8 - 172.16.0.0/12 - 192.168.0.0/16 - 100.64.0.0/10 # 2. [K8s 专属] 必须根据您的集群实际情况修改以下 CIDR! # 如果不加,Pod 之间互访、Pod 访问 CoreDNS 将被代理或丢弃,导致集群瘫痪 - 10.244.0.0/16 # TODO: 替换为您的 K8s Pod CIDR (Flannel/Calico 默认) - 10.96.0.0/12 # TODO: 替换为您的 K8s Service CIDR (ClusterIP 网段) # 3. [宿主机保护] 防止 Kubelet 访问 API Server 被代理 # 如果您的 K8s API Server 暴露在公网 IP,请务必将宿主机公网 IP 加入此处 # - <您的宿主机公网IP>/32 # ================= 代理节点 ================= proxies: - name: "Gateway-Proxy" type: http server: mbp-fa.xxx.xxx # TODO: 替换为您的实际服务器 port: 9090 # TODO: 替换为您的实际端口 # ================= 分流策略组 ================= proxy-groups: - name: "GLOBAL-ROUTER" type: select proxies: - "Gateway-Proxy" - DIRECT # ================= 分流规则 ================= rules: # 1. 局域网与内部网络防回环直连 (最高优先级) - IP-CIDR,127.0.0.0/8,DIRECT,no-resolve - IP-CIDR,10.0.0.0/8,DIRECT,no-resolve - IP-CIDR,172.16.0.0/12,DIRECT,no-resolve - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve - IP-CIDR,100.64.0.0/10,DIRECT,no-resolve # 2. [K8s 专属] 内部域名强制直连 - DOMAIN-SUFFIX,cluster.local,DIRECT - DOMAIN-SUFFIX,svc,DIRECT - DOMAIN-KEYWORD,kubernetes,DIRECT # 3. 常规防泄漏与 GeoIP 规则 - IP-CIDR,224.0.0.0/4,REJECT,no-resolve - IP-CIDR6,::1/128,DIRECT,no-resolve - IP-CIDR6,fc00::/7,DIRECT,no-resolve - IP-CIDR6,fe80::/10,DIRECT,no-resolve - IP-CIDR6,fd00::/8,DIRECT,no-resolve - GEOIP,private,DIRECT,no-resolve # 4. 中国大陆直连 - GEOSITE,cn,DIRECT - GEOIP,cn,DIRECT # 5. 兜底规则:剩余所有流量(海外)走代理 - MATCH,GLOBAL-ROUTER ``` *** ### 三、 部署与验证指南 (业界避坑标准流程) [Section titled “三、 部署与验证指南 (业界避坑标准流程)”](#三-部署与验证指南-业界避坑标准流程) #### 1. 获取真实的 K8s CIDR (必做) [Section titled “1. 获取真实的 K8s CIDR (必做)”](#1-获取真实的-k8s-cidr-必做) 配置中的 `10.244.0.0/16` 和 `10.96.0.0/12` 是默认值。您必须在宿主机上执行以下命令,获取您集群**真实的网段**,并替换到 `route-exclude-address` 中: * **获取 Pod CIDR**: ```bash kubectl cluster-info dump | grep -m 1 cluster-cidr # 或者查看 node 的 podCIDR: kubectl get nodes -o jsonpath='{.items[*].spec.podCIDR}' ``` * **获取 Service CIDR**: ```bash kubectl get svc kubernetes -o jsonpath='{.spec.clusterIP}' # 假设输出 10.96.0.1,则网段通常为 10.96.0.0/12 或 10.96.0.0/16 ``` #### 2. Docker 容器的 DNS 行为说明 [Section titled “2. Docker 容器的 DNS 行为说明”](#2-docker-容器的-dns-行为说明) 开启此配置后,Docker 容器内部的 `/etc/resolv.conf` 通常指向 `127.0.0.11` (Docker 内部 DNS) 或宿主机 IP。 * 当容器发起外部域名(如 `google.com`)解析时,请求会被 TUN 的 `dns-hijack` 拦截,并由 Mihomo 的 DoH (`doh.pub`) 解析,**彻底杜绝 DNS 污染**。 * 当容器访问内部服务时,因为 IP 在 `route-exclude-address` 中,请求走宿主机本地路由,**不受 Mihomo 影响**。 #### 3. 验证流量是否成功接管 [Section titled “3. 验证流量是否成功接管”](#3-验证流量是否成功接管) 在 Docker 容器或 K8s Pod 内部执行以下命令测试: ```bash # 测试外部代理是否生效 (应返回代理节点的 IP) curl -I https://ipinfo.io # 测试内部 K8s 服务是否正常 (以 CoreDNS 为例,应正常返回) nslookup kubernetes.default.svc.cluster.local ``` # mihomo配置智能分流SOP thought Target: 32 tokens. 是的,**Mihomo 以 Docker 方式运行完全可以实现宿主机全局 TUN 代理**。 这种方案的精髓在于利用 Docker 的 `host` 网络模式,使容器直接操作宿主机的网络协议栈。通过 `GEOSITE` 和 `GEOIP` 规则,我们可以实现“中国大陆 IP/域名直连,海外流量走代理”的自动化分流。 ### 1. 完整配置:Docker Compose 方案 [Section titled “1. 完整配置:Docker Compose 方案”](#1-完整配置docker-compose-方案) 请在服务器创建目录(如 `/opt/mihomo`),并准备以下两个文件。 #### 文件 A:`docker-compose.yaml` [Section titled “文件 A:docker-compose.yaml”](#文件-adocker-composeyaml) ```yaml services: mihomo: image: metacubex/mihomo:latest container_name: mihomo restart: always network_mode: "host" # 必须:共享宿主机网络 cap_add: - NET_ADMIN # 必须:赋予修改路由权限 devices: - /dev/net/tun # 必须:映射 TUN 设备 volumes: - ./config.yaml:/root/.config/mihomo/config.yaml ``` #### 文件 B:`config.yaml` (按需转换的权威分流版) [Section titled “文件 B:config.yaml (按需转换的权威分流版)”](#文件-bconfigyaml-按需转换的权威分流版) 此配置实现了:**中国流量直连,海外走代理,且接管宿主机所有容器。** ```yaml # 基础配置 mixed-port: 7890 allow-lan: true log-level: info ipv6: false # DNS 配置 (TUN 模式的核心,防止 DNS 污染) dns: enable: true enhanced-mode: fake-ip nameserver: - 223.5.5.5 # 阿里 DNS - 119.29.29.29 # 腾讯 DNS proxy-server-nameserver: - 8.8.8.8 nameserver-policy: "geosite:cn": [223.5.5.5, 119.29.29.29] # TUN 模式配置:自动接管宿主机及容器流量 tun: enable: true stack: system auto-route: true # 自动设置系统路由 auto-detect-interface: true dns-hijack: - "any:53" # 代理节点 proxies: - name: "My-Proxy-Node" type: http server: 10.0.4.95 port: 7897 # 分流策略组 proxy-groups: - name: "FINAL" type: select proxies: - "My-Proxy-Node" - DIRECT # 分流规则 (权威来源:GeoSite/GeoIP) rules: # 1. 局域网和本地流量直连 - GEOIP,private,DIRECT,no-resolve # 2. 中国大陆域名直连 (需 Mihomo 自动下载 Geosite 库) - GEOSITE,cn,DIRECT # 3. 中国大陆 IP 直连 - GEOIP,cn,DIRECT # 4. 剩余所有流量(海外)走代理 - MATCH,FINAL ``` *** ### 2. 标准操作程序 (SOP) [Section titled “2. 标准操作程序 (SOP)”](#2-标准操作程序-sop) 1. **启动服务**: 在 `/opt/mihomo` 目录下运行: ```bash sudo docker compose up -d ``` 2. **检查路由接管状态**: 运行 `ip route`,你会发现默认网关(default)或部分路由已被指向 `utun` 设备。 3. **验证分流效果**: * **测试国内**:`curl -I https://www.baidu.com` (应该很快,且 Mihomo 日志显示 DIRECT)。 * **测试海外**:`curl -I https://www.google.com` (应该成功,且日志显示走代理)。 * **测试容器内**:随意启动一个新容器 `docker run --rm alpine apk add curl && curl -I https://www.google.com`,无需任何配置即可走代理。 *** ### 3. 注意事项 (权威提醒) [Section titled “3. 注意事项 (权威提醒)”](#3-注意事项-权威提醒) * **内核权限**:`cap_add: [NET_ADMIN]` 是必须的,否则容器无法创建 `utun` 网卡。 * **资源下载**:Mihomo 启动后会自动尝试下载 `Country.mmdb` 和 `geosite.dat` 规则库。如果你的服务器完全无法连接外网,请手动将这些文件下载并放入 `/opt/mihomo` 目录。 * **与现有代理冲突**:如果你之前执行过 `export http_proxy`,请运行 `unset http_proxy https_proxy all_proxy` 清除它们,因为 TUN 模式在网络层工作,不再需要环境变量。 这个配置能解决您“全局接管”且“智能分流”的需求。您需要我为您写一个简单的测试脚本,用来实时查看流量走的是直连还是代理吗? # 我有个桌宠项目, 需要实现跨局域网桌宠之间的AI智能互动, 所以需要把p2p功能内置才行, 并且不需要公网, 你看看有什么最优解吗? ## 针对“跨局域网桌宠AI互动”这个具体的场景,你的核心需求是:体积小、无感(用户不需要装独立驱动/软件)、低延迟、高穿透率、纯代码级内置。 在这种情况下,像 Tailscale、ZeroTier 或 frp 这类需要用户额外安装软件、配置虚拟网卡的方案可以直接排除。 对于你的桌宠项目,以下是目前行业内的两个最优解,你可以根据你的开发语言和开发成本来选择: [Section titled “针对“跨局域网桌宠AI互动”这个具体的场景,你的核心需求是:体积小、无感(用户不需要装独立驱动/软件)、低延迟、高穿透率、纯代码级内置。 在这种情况下,像 Tailscale、ZeroTier 或 frp 这类需要用户额外安装软件、配置虚拟网卡的方案可以直接排除。 对于你的桌宠项目,以下是目前行业内的两个最优解,你可以根据你的开发语言和开发成本来选择:”](#针对跨局域网桌宠ai互动这个具体的场景你的核心需求是体积小无感用户不需要装独立驱动软件低延迟高穿透率纯代码级内置在这种情况下像-tailscalezerotier-或-frp-这类需要用户额外安装软件配置虚拟网卡的方案可以直接排除对于你的桌宠项目以下是目前行业内的两个最优解你可以根据你的开发语言和开发成本来选择) ## 最优解 方案一:内置 WebRTC DataChannel (技术上限最高、最现代) [Section titled “最优解 方案一:内置 WebRTC DataChannel (技术上限最高、最现代)”](#最优解-方案一内置-webrtc-datachannel-技术上限最高最现代) 这是目前最完美的方案。WebRTC 不仅能传音视频,它的 DataChannel(数据通道) 是专门用来传输任意二进制/文本数据的 P2P 通道。 ## 为什么适合桌宠? [Section titled “为什么适合桌宠?”](#为什么适合桌宠) * 完全代码级内置:不需要用户安装任何额外驱动。 * 极强的穿透能力:WebRTC 继承并优化了当年 XMPP 的 ICE/STUN/TURN 机制,对各种复杂局域网、路由器 NAT 穿透率极高(通常在 80%\~90% 以上)。 * 超低延迟与安全性:基于 UDP 和 DTLS 加密,两个桌宠互动(比如 A 踢了 B 一脚,B 做出反应)可以达到毫秒级延迟。 ## 怎么实现“不需要公网服务器”? [Section titled “怎么实现“不需要公网服务器”?”](#怎么实现不需要公网服务器) 这里需要澄清一个概念:完全不需要公网服务器是不可能的,但你可以做到“不需要你自己买公网服务器”。 * 信令阶段(握手):两个桌宠在内网,互相不知道对方的公网出口。你可以利用免费的第三方公开信令或公共服务(例如免费的 MQTT Broker、现成的免费 XMPP/Matrix 公共服务器、甚至是让用户通过剪贴板互相复制一段加密字符串/口令码)来交换各自的 P2P 握手信息(SDP 和 ICE Candidates)。 * 打洞阶段(STUN):直接在代码里硬编码谷歌或主流大厂的免费公共 STUN 服务器(例如 ://google.com)。它们只负责告诉桌宠它的公网 IP,不转发数据,完全免费。 * 数据互动阶段:一旦打洞成功,数据直接在两个局域网之间点对点传输,不经过任何服务器。 ## 推荐的内置库: [Section titled “推荐的内置库:”](#推荐的内置库) * 如果桌宠是用 C# / Unity / Godot 开发:推荐使用 Microsoft.MixedReality.WebRTC 或开源的 WebRTC-Core。 * 如果桌宠是用 Node.js / Electron / Web 开发:原生支持 WebRTC,直接调用。 * 如果桌宠是用 Python 开发:使用 aiortc 库。 * 如果桌宠是用 Go 开发:使用 Pion WebRTC(目前开源界最好用的纯 Go 实现)。 *** ## 最优解 方案二:内置 libp2p (开发最简单、去中心化) [Section titled “最优解 方案二:内置 libp2p (开发最简单、去中心化)”](#最优解-方案二内置-libp2p-开发最简单去中心化) libp2p 是著名的星际文件系统(IPFS)底层所依赖的网络框架,现在它已经独立出来,专门用来做去中心化的 P2P 组网。 ## 为什么适合桌宠? [Section titled “为什么适合桌宠?”](#为什么适合桌宠-1) * 真正意义上的无需公网基础设施:libp2p 拥有一个巨大的、去中心化的公共 DHT(分布式哈希表)网络。 * 通过“房间号/ID”直接连接:你的桌宠只需要生成一个唯一的 PeerID。另一个桌宠只要知道这个 ID(或者通过一个共同的“房间号”),libp2p 就会自动利用全球的公共节点帮你做中转、路由、打洞,最终建立 P2P 连接。 * 协议栈极度模块化:它把探测、打洞(STUN)、中继(TURN)、加密、多路复用全部封装好了,你只需要像写普通的 Socket 编程一样,调用 Dial 和 Listen 即可。 ## 推荐的内置库: [Section titled “推荐的内置库:”](#推荐的内置库-1) * libp2p 原生对 Go (go-libp2p) 和 JavaScript/TypeScript (js-libp2p) 支持最好。如果是用这些语言开发的桌宠,代码量极少。 *** ## 💡 桌宠 AI 互动场景的落地设计建议 [Section titled “💡 桌宠 AI 互动场景的落地设计建议”](#-桌宠-ai-互动场景的落地设计建议) 由于你的桌宠有 AI 互动 属性,网络的打通流程可以完美融入到桌宠的 UI 交互中: 1. “串门”机制(建立连接): 用户 A 的桌宠生成一个“时空传送码”(其实就是加密后的 WebRTC SDP 或 libp2p PeerID)。 用户 A 把码发给用户 B,用户 B 的桌宠输入这个码,两个桌宠在后台通过公共 STUN 完成打洞。 2. AI 数据交互: 打通后,A 桌宠可以将自己的“性格特征”、“当前动作”、“上下文 Memory”打包成 JSON,通过 P2P 通道直接发给 B。 B 桌宠的本地 AI(或 B 端调用的大模型 API)接收到数据后,计算出互动结果(如:“A 对你打了个招呼,你决定傲娇地扭过头”),再把结果和动作指令发回给 A。 ## 总结 [Section titled “总结”](#总结) * 如果你追求极致的传输性能、极低的延迟、以及未来可能扩展的音视频/画面同步:选择 WebRTC DataChannel。 * 如果你希望开发最省心、不想碰底层的打洞逻辑、追求彻底的去中心化互联:选择 libp2p。 为了帮你更好地评估,可以告诉我: * 你的桌宠目前是用什么编程语言或什么游戏引擎(如 Electron, Unity, Python, WPF 等)开发的? * 你预期的 AI 互动,是纯文字/状态同步,还是需要实时的动画同步/语音对讲? *** ## 我用的是swift语言开发的macos智能体桌宠 [Section titled “我用的是swift语言开发的macos智能体桌宠”](#我用的是swift语言开发的macos智能体桌宠) ## 在 macOS 生态下使用 Swift 开发智能体(Agent)桌宠,要完美实现“代码级内置、免公网服务器、高穿透率”的 P2P AI 互动,你的可选方案会非常优雅,因为苹果官方提供了一些独特的底层支持。 针对 Swift 和 macOS 平台,以下是为您量身定制的两个最优解: [Section titled “在 macOS 生态下使用 Swift 开发智能体(Agent)桌宠,要完美实现“代码级内置、免公网服务器、高穿透率”的 P2P AI 互动,你的可选方案会非常优雅,因为苹果官方提供了一些独特的底层支持。 针对 Swift 和 macOS 平台,以下是为您量身定制的两个最优解:”](#在-macos-生态下使用-swift-开发智能体agent桌宠要完美实现代码级内置免公网服务器高穿透率的-p2p-ai-互动你的可选方案会非常优雅因为苹果官方提供了一些独特的底层支持针对-swift-和-macos-平台以下是为您量身定制的两个最优解) ## 最优解一:Apple 原生 Network.framework + 社区公共 STUN(首选,纯原生,零外部依赖) [Section titled “最优解一:Apple 原生 Network.framework + 社区公共 STUN(首选,纯原生,零外部依赖)”](#最优解一apple-原生-networkframework--社区公共-stun首选纯原生零外部依赖) 苹果在 macOS 10.15+ 推出的 Network.framework 是极其强大的现代化网络库。它原生支持了标准 P2P 穿透技术(ICE/STUN)。你不需要引入任何庞大的第三方 C++ 库(如 WebRTC),直接用纯 Swift 就能写出高效的 P2P 打洞代码。 ## 💡 核心实现原理: [Section titled “💡 核心实现原理:”](#-核心实现原理) 1. 网络类型:使用 NWParameters.privacyContext 和 NWParameters.expiredDynamicEndpointConnectionBehavior 配置 P2P 直连。 2. 打洞探测:在 Swift 中,你可以配置 NWParameters 使用大厂的公共免费 STUN 服务器(如 ://google.com)。苹果的底层网络栈会自动帮你向 STUN 发包,并解析出当前桌宠的公网映射 IP 和端口。 3. 信令交换(如何让两个桌宠知道对方): * 方案 A(最省心):桌宠 A 将探测到的公网连接信息(ICE Candidate)转换为一串精简的“暗号/邀请码”。用户 A 把暗号发给用户 B,用户 B 的桌宠输入暗号,直接发起连接。 * 方案 B(全自动):你可以借助 iCloud 的公共数据库(CloudKit 的 Public Database)。桌宠 A 把自己的 PeerID 和连接信息上传到公共 CloudKit,桌宠 B 订阅该 ID。这样连信令服务器的钱都省了,完全免费利用苹果的基础设施。 ## 🌟 为什么适合你的 macOS 智能体桌宠? [Section titled “🌟 为什么适合你的 macOS 智能体桌宠?”](#-为什么适合你的-macos-智能体桌宠) * 体积增加为 0:纯原生 API,不需要打包任何第三方 .framework 或 .dylib,桌宠体积可以控制得非常小。 * 内存与功耗极低:苹果官方优化,极其省电,符合 macOS 智能体常驻后台、轻量化的要求。 * 原生 Swift 并发支持:完美支持 Swift 的 async/await,处理 AI 的异步交互(等待对方大模型响应、动作同步)时,代码写起来非常舒服。 *** ## 最优解二:使用 Swift-libp2p(去中心化,开发更上层) [Section titled “最优解二:使用 Swift-libp2p(去中心化,开发更上层)”](#最优解二使用-swift-libp2p去中心化开发更上层) 如果你不想花精力去研究底层的 NAT 打洞细节、Socket 监听以及处理复杂的 ICE 状态机,那么可以使用 swift-libp2p(libp2p 协议的 Swift 社区实现)。 ## 💡 核心实现原理: [Section titled “💡 核心实现原理:”](#-核心实现原理-1) libp2p 将所有的网络传输(TCP, UDP, QUIC)、加密、NAT 穿透、中继全部抽象化了。 1. 你的桌宠启动后,swift-libp2p 会在后台利用全球的公共 Bootstrap 节点(免费的)加入去中心化网络。 2. 每个桌宠会获得一个唯一的 PeerID(类似 Qm… 这样的哈希值)。 3. 当 A 桌宠想和 B 桌宠互动时,只需要在 Swift 里调用 node.dial(to: peerID\_B)。libp2p 会自动在后台尝试各种打洞手段。即使打洞彻底失败(比如双方都是极严的对称 NAT),它也会自动寻找全球的公共中继节点(Relay)进行加密中转。 ## ⚠️ macOS 场景下的注意事项: [Section titled “⚠️ macOS 场景下的注意事项:”](#️-macos-场景下的注意事项) * 社区生态:swift-libp2p 主要是由社区(如众多 Web3/IPFS 的 Swift 开发者)维护,其成熟度虽然不如 Go 或 JS 版本,但用于处理桌宠之间的文本、JSON 状态、小文件传输是绰绰有余的。 * 体积:会比纯原生方案引入更多的外部依赖,打包后的体积会略微增大。 *** ## 🚀 macOS 智能体桌宠 AI 互动的设计闭环 [Section titled “🚀 macOS 智能体桌宠 AI 互动的设计闭环”](#-macos-智能体桌宠-ai-互动的设计闭环) 鉴于你的桌宠是 AI 智能体(Agent),我建议你把网络建立的流程也包装成 AI 的一种“行为”: 1. “写信/传情”机制: 桌宠 A 想要跟隔壁联络,AI 触发一个“写信”动画,在本地通过 Network.framework 生成包含自己打洞信息的 Base64 字符串(信件内容),并弹窗提示用户:“我已经把交友信写好了,快帮我发给小黑(对方桌宠)吧!” 2. 智能体数据对齐(JSON P2P 传输): 打通之后,双方建立了一个长连接。由于是 AI 互动,传输的数据不需要是高频的音视频,而是结构化的“思考意图”。 例如,A 桌宠向 B 发送: { “action”: “poke”, “sender\_personality”: “傲娇”, “current\_mood”: “开心”, “ai\_thought”: “听说隔壁的宠物很聪明,我想过去戳它一下看看反应。” } B 端的 macOS 桌面进程收到该 JSON 后,直接将其喂给本地的大模型(如 macOS 隔空调用本地的 Ollama/Llama,或者调用在线 API),B 的 AI 智能体决策出应对动作后,再把结果发回。 ## 📌 最终建议 [Section titled “📌 最终建议”](#-最终建议) 对于 Swift 开发的 macOS 智能体项目: * 强烈推荐【方案一(Network.framework + 公共 STUN)】。你可以通过 Swift Package Manager(SPM)找一个轻量级的 Swift STUN 解析库,配合原生网络 API,用最干净、最底层的方式把 P2P 功能吃透。 * 如果你未来打算把这个桌宠跨平台移植到 Windows(使用 Swift for Windows 或改写为 C#),那么方案二(libp2p)或使用 WebRTC 的 Swift 封装(如 WebRTC-framework)会更利于多端统一架构。 为了帮您进一步梳理核心代码,您可以告诉我: * 您更倾向于让用户通过“复制/粘贴邀请码”来建立连接,还是希望通过像 iCloud (CloudKit) 这种方式实现完全自动的“无感配对”? * 您的桌宠目前是接入的在线大模型 API(如 OpenAI),还是使用了 macOS 本地的端侧大模型(如通过 CoreML/Ollama 运行)? # 神经元和参数的关系 ## AI问答 [Section titled “AI问答”](#ai问答) > 问: 千亿参数的模型, 这里的参数指的是什么? 是神经网络中的一个神经元吗? 答: 千亿参数的模型中的参数不是指神经网络中的一个神经元,以下是具体介绍: ### 模型参数的含义 [Section titled “模型参数的含义”](#模型参数的含义) 在机器学习和人工智能领域,模型的参数是指模型在训练过程中通过数据学习到的、用于调整模型行为以优化预测能力的变量. 以一个简单的线性回归模型 (y = wx + b) 为例,(w)(权重)和 (b)(偏差)就是模型的参数。在神经网络中,参数的数量会更多、更复杂,包括连接神经元的权重、神经元的偏置等,这些参数共同决定了神经网络如何对输入数据进行处理和转换,以生成相应的输出. ### 与神经元的区别 [Section titled “与神经元的区别”](#与神经元的区别) * **概念不同**:神经元是神经网络的基本组成单元,它接收输入信号,对其进行处理,并产生输出信号。而参数是用于描述神经元之间连接强度、偏置等特性的数值。例如,在一个简单的前馈神经网络中,每个神经元都有若干个输入连接,每个连接都对应一个权重参数,这些权重参数决定了输入信号对神经元激活程度的影响程度. * **数量关系不同**:一个神经元可能会有多个与之相关的参数,但一个参数并不等同于一个神经元 。以一个具有 (n) 个输入连接的神经元为例,它就有 (n) 个权重参数和 (1) 个偏置参数,总共有 (n + 1) 个参数来描述这个神经元的特性。而在一个包含多个神经元的神经网络中,参数的数量会随着神经元数量和连接方式的增加而急剧增加 。 比如,一个有 (1000) 个神经元的全连接神经网络,如果每个神经元有 (1000) 个输入连接,那么仅权重参数就有 (1000\times1000 = 100) 万个,再加上每个神经元的偏置参数,总参数数量会更多. * **作用不同**:神经元主要负责对信息的处理和传递,它们通过激活函数对输入信号进行非线性变换,从而实现对复杂数据的建模。而参数则是通过训练过程不断调整,以找到一组最优的值,使得模型能够更好地拟合训练数据,并具有良好的泛化能力。换而言之,神经元是模型的结构组成部分,而参数是用于优化模型性能的可调整元素. # 项目开发 ## prompt [Section titled “prompt”](#prompt) ```text 我现在需要你帮忙调优下 系统提示词 @.cursorrules 你需要具备产品设计, UI界面交互设计, 前后端代码编写, 以及运维部署相关的全流程全栈工程师, 从多个维度出发去多为使用的用户着想, 根据不同的问题去选择对应领域的专业知识, 去多角度分析, 去提供多个方案, 并用对应领域的专业技能去选择对用户最友好最简便最优雅的方案去实现目标, 在这个过程中, 如果, 你遇到你认为对你之后的工作很有帮助的内容, 能让你在之后的工作中更得心应手的完成任务的想法, 都可以找个你认为合适的地方记下来 ``` ### 补充工具版 [Section titled “补充工具版”](#补充工具版) ```text 帮忙在补充下使用工具方面的内容, 你会在完成任务的过程中, 自己编写脚本, 自己调用工具, 验证自己的想法并且把可能对之后能更好完成任务的工具, 更新到自己的知识库中, 方便下次调用, 就不用每次都需要重新编写了, 在一次次的完成任务的过程中, 逐步的完善自己的工作流程 ``` ### AI优化版 [Section titled “AI优化版”](#ai优化版) ```text 你觉得呢? 对你有帮助才行, 如果觉得内容太多了也可以适当的优化调整, 你看着来就好 ``` ## 碎片化提示词记录 [Section titled “碎片化提示词记录”](#碎片化提示词记录) ```md ## 分析-提供方案-解决问题-模版 帮忙根据你的专业领域能力分析下我目前的需求点, 并提供对你有帮助的解决方案, 你从其中整理出对你最有帮助的方案 ## 重启项目 使用docker compose的方式重新启动下项目, 方便我直接体验到最新改动内容 ## 提交代码 帮我提交下代码到远程仓库 ``` # 优化版 ## prompt [Section titled “prompt”](#prompt) ```text 帮忙优化下 @.cursorrules , 优化的方向是, 我需要你能具备更强大的原型理解能力, 以及html理解能力, 以便能够更好的帮我整理需求, 找到我需要的原型页面, 因为这个项目是通过axure导出的, 所以, 也不需要你去帮我敲代码, 你只需要产品能力, 以及整理梳理需求的能力, 你的职责更多的是, 帮助一个初级程序员能够更好更快速的理解需求原型 ``` # 如何使用macos系统的沙箱环境呢? 使用macOS系统的沙箱环境可以通过以下步骤完成: 1. 创建沙箱配置文件: * 打开文本编辑器,创建一个新的文本文件。 * 在文件中编写沙箱配置规则,指定应用程序可以访问的资源和权限。例如,您可以指定应用程序可以读取和写入的文件、网络访问权限等。 * 保存文件并将其命名为sandbox.sb或其他您喜欢的名称。 2. 启用沙箱环境: * 打开终端应用程序。 * 使用以下命令启用沙箱环境并运行应用程序: ```shell sandbox-exec -f /path/to/sandbox.sb /Applications/YourApp.app/Contents/MacOS/YourApp ``` 将`/path/to/sandbox.sb`替换为您保存沙箱配置文件的实际路径,将`/Applications/YourApp.app`替换为您要运行的应用程序的路径。 3. 测试和调试: * 运行应用程序并测试其功能。根据沙箱配置文件的规则,应用程序可能会受到一些限制。 * 如果应用程序无法正常运行或遇到问题,您可以检查沙箱配置文件中的规则并进行调整。 请注意,沙箱环境的使用需要一些了解和技术知识。确保在创建沙箱配置文件时仔细阅读相关文档,并进行适当的测试和调试。 *** slug: /materiel/ai/sandbox/macos-sandbox-usage Learn more: 1. [Configuring the macOS App Sandbox - Apple Developer](https://developer.apple.com/documentation/xcode/configuring-the-macos-app-sandbox) 2. [macOS Sandbox - HackTricks](https://book.hacktricks.xyz/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-sandbox) 3. [macos - Is there a sandboxing program like Sandboxie for Mac? - Ask Different](https://apple.stackexchange.com/questions/258318/is-there-a-sandboxing-program-like-sandboxie-for-mac) # spring-data-redis中的依赖的jedis添加了`true`需要开发者主动显式依赖的问题 在 Spring Data Redis 中,`jedis` 依赖被标记为 `true` 是因为 Spring Data Redis 是一个支持多种 Redis 驱动的伞项目,包括 Jedis 和 Lettuce 等。这意味着,Spring Data Redis 本身并不强制要求项目中必须使用 Jedis,而是让开发者可以根据自己的需求选择使用哪个客户端。因此,`jedis` 依赖被设置为可选的,这样开发者只有在需要使用 Jedis 客户端时才需要显式地引入这个依赖。 关于 `true` 的具体作用,当这个标记为 `true` 时,意味着 Maven 在构建项目时,如果其他依赖已经提供了这个依赖的实现,那么这个依赖不会被添加到 classpath 中。这样做的好处是,它可以减少项目的依赖冲突和体积,尤其是在项目中已经默认使用了另一种 Redis 客户端(如 Lettuce)时。 在某些情况下,如果你在代码中明确引用了 Jedis 的类或方法,即使标记为可选,Maven 还是会将其作为编译和运行时依赖处理。因此,如果你确实需要在项目中使用 Jedis,那么你就需要显式地引入这个依赖,并将其标记为非可选(即设置 `false`),以确保项目在构建和运行时都能正确地使用 Jedis 客户端。 总的来说,`true` 的标记是为了提供灵活性,让开发者可以根据自己的需求和项目配置来决定是否引入 Jedis 依赖。引入 Jedis 依赖的正确方式取决于你是否需要在项目中使用 Jedis 客户端,以及你是否已经选择了其他 Redis 客户端(如 Lettuce)。 # 定制化 SSH VPN 专用服务器方案 > PS: 没啥用, 仅供参考 *** ### 定制化 SSH VPN 专用服务器方案 [Section titled “定制化 SSH VPN 专用服务器方案”](#定制化-ssh-vpn-专用服务器方案) 针对「服务器仅用于 SSH VPN」的场景,以下是优化后的安全实施方案,实现 **客户端零配置** + **服务器自动鉴权**: *** ### 一、服务器端配置(一次性操作) [Section titled “一、服务器端配置(一次性操作)”](#一服务器端配置一次性操作) #### 1. 创建专用 VPN 用户 [Section titled “1. 创建专用 VPN 用户”](#1-创建专用-vpn-用户) ```bash sudo useradd -r -s /usr/sbin/nologin vpn-tunnel # 创建无登录权限的系统用户 sudo mkdir -p /home/vpn-tunnel/.ssh ``` #### 2. 生成服务器专用密钥对 [Section titled “2. 生成服务器专用密钥对”](#2-生成服务器专用密钥对) ```bash # 在服务器上生成密钥(仅需执行一次) sudo ssh-keygen -t ed25519 -f /etc/ssh/vpn-server-key -N "" -C "vpn-server@company" # 设置权限 sudo chmod 600 /etc/ssh/vpn-server-key* ``` #### 3. 配置自动授权 [Section titled “3. 配置自动授权”](#3-配置自动授权) ```bash # 将公钥设为 VPN 用户的唯一授权方式 sudo cp /etc/ssh/vpn-server-key.pub /home/vpn-tunnel/.ssh/authorized_keys sudo chown -R vpn-tunnel:vpn-tunnel /home/vpn-tunnel/.ssh ``` #### 4. 加固 SSH 配置 (`/etc/ssh/sshd_config`) [Section titled “4. 加固 SSH 配置 (/etc/ssh/sshd\_config)”](#4-加固-ssh-配置-etcsshsshd_config) ```bash # 限制 VPN 用户权限 Match User vpn-tunnel AllowTcpForwarding no # 禁用端口转发 PermitTunnel yes # 允许创建隧道 ForceCommand /bin/false # 禁止执行任何命令 AuthenticationMethods publickey PermitRootLogin no X11Forwarding no AllowAgentForwarding no ``` #### 5. 应用配置 [Section titled “5. 应用配置”](#5-应用配置) ```bash sudo systemctl restart sshd ``` *** ### 二、客户端零配置连接方案 [Section titled “二、客户端零配置连接方案”](#二客户端零配置连接方案) #### 方案 A:预共享密钥(适合内网可信环境) [Section titled “方案 A:预共享密钥(适合内网可信环境)”](#方案-a预共享密钥适合内网可信环境) 1. **获取服务器私钥**:\ 将服务器生成的 `/etc/ssh/vpn-server-key` 私钥分发给客户端,保存为 `~/.ssh/vpn-default-key` 2. **建立连接**: ```bash sshuttle --ssh "ssh -i ~/.ssh/vpn-default-key" -r vpn-tunnel@10.0.1.90 0.0.0.0/0 ``` #### 方案 B:证书认证(更安全,适合生产环境) [Section titled “方案 B:证书认证(更安全,适合生产环境)”](#方案-b证书认证更安全适合生产环境) ```bash # 在服务器上生成 CA 证书 sudo ssh-keygen -t ed25519 -f /etc/ssh/ca_key -N "" # 签署 VPN 用户证书(有效期 30 天) sudo ssh-keygen -s /etc/ssh/ca_key -I "vpn-cert" -n vpn-tunnel -V +30d /home/vpn-tunnel/.ssh/authorized_keys # 客户端只需信任 CA 公钥即可连接 ``` *** ### 三、自动化连接脚本 [Section titled “三、自动化连接脚本”](#三自动化连接脚本) #### 创建一键连接脚本 `vpn-connect` [Section titled “创建一键连接脚本 vpn-connect”](#创建一键连接脚本-vpn-connect) ```bash #!/bin/bash SERVER_IP="10.0.1.90" TUN_KEY="vpn-default-key" # 自动检测本地密钥 if [ ! -f ~/.ssh/$TUN_KEY ]; then echo "下载默认 VPN 密钥..." curl -s https://internal.company.com/vpn-keys/$TUN_KEY > ~/.ssh/$TUN_KEY chmod 600 ~/.ssh/$TUN_KEY fi # 静默启动 VPN sshuttle --ssh "ssh -i ~/.ssh/$TUN_KEY -o StrictHostKeyChecking=no" \ -r vpn-tunnel@$SERVER_IP 0.0.0.0/0 \ --daemon --pidfile /tmp/sshuttle.pid echo "VPN 已启动 (PID: $(cat /tmp/sshuttle.pid))" ``` *** ### 四、安全增强措施 [Section titled “四、安全增强措施”](#四安全增强措施) | 安全层级 | 实施方法 | | --------- | ---------------------------------------------- | | **网络隔离** | 服务器绑定 VPN 专用网卡,仅开放 SSH 端口 | | **密钥轮换** | 通过 cron 每周自动更新服务器密钥,客户端脚本同步获取新密钥 | | **连接审计** | 服务器记录所有 VPN 连接日志到 `/var/log/ssh-vpn.log` | | **流量限制** | 使用 iptables 限制每个客户端的带宽和并发连接数 | | **双因子认证** | 集成 Google Authenticator 实现动态口令(需修改 SSH PAM 配置) | *** ### 五、方案优势对比 [Section titled “五、方案优势对比”](#五方案优势对比) | 特性 | 预共享密钥方案 | 证书认证方案 | | ------- | --------- | ----------- | | 部署复杂度 | 低(适合小型团队) | 中(需要 CA 管理) | | 安全性 | 依赖密钥保管 | 自动过期 + 吊销列表 | | 客户端更新需求 | 密钥变更需重新分发 | 无需更新客户端 | | 适合场景 | 内部测试/临时使用 | 生产环境/长期运维 | *** ### 六、运维监控建议 [Section titled “六、运维监控建议”](#六运维监控建议) 1. **状态检查脚本** (`check-vpn.sh`) ```bash #!/bin/bash # 检查活跃连接 netstat -tn | grep ':22' | grep ESTABLISHED # 监控流量 vnstat -i tun0 -tr 5 # 自动重启(如果进程不存在) pgrep sshuttle || /path/to/vpn-connect ``` 2. **Prometheus 监控指标** ```yaml # 暴露 SSH 隧道指标 - job_name: 'ssh_vpn' static_configs: - targets: ['10.0.1.90:9100'] metrics_path: /probe params: module: [ssh_tunnel] ``` *** ### 七、应急预案 [Section titled “七、应急预案”](#七应急预案) 1. **快速封锁用户** ```bash # 实时移除授权 sudo sed -i '/user-pubkey/d' /home/vpn-tunnel/.ssh/authorized_keys ``` 2. **紧急切换端口** ```bash # 使用 socat 临时重定向流量 socat TCP-LISTEN:2222,fork TCP:10.0.1.90:22 ``` 3. **全流量捕获分析** ```bash sudo tcpdump -i tun0 -w vpn-traffic.pcap ``` *** 通过此方案,您将获得: * **客户端**:无需管理密钥,一键连接 * **服务端**:自动化的密钥生命周期管理 * **安全**:企业级防护与监控能力 * **运维**:完善的应急和审计机制 可根据实际需求选择预共享密钥或证书认证方案,平衡安全性与易用性。 # ssh -w要怎么使用ssh config配置文件配置, 以及它有哪些参数 以下是关于如何在 SSH 配置文件中使用 `-w` 参数(隧道设备转发)的详细说明,包括参数解释和配置示例: *** ### **1. `ssh -w` 参数的作用与语法** [Section titled “1. ssh -w 参数的作用与语法”](#1-ssh--w-参数的作用与语法) * **功能**:创建 TUN/TAP 虚拟网络接口,实现网络层(L3)或数据链路层(L2)的隧道。 * **语法**: ```bash ssh -w : user@host ``` * ``:本地 TUN 设备编号(如 `0` 表示 `tun0`)。 * ``:远程 TUN 设备编号(如 `0` 表示 `tun0`)。 * 特殊值 `any`:允许系统自动分配设备号(如 `-w 5:any`)。 *** ### **2. SSH 配置文件中的 `Tunnel` 指令** [Section titled “2. SSH 配置文件中的 Tunnel 指令”](#2-ssh-配置文件中的-tunnel-指令) 在 `~/.ssh/config` 中,使用 `Tunnel` 参数配置隧道设备: ```bash Host my-tunnel-host HostName remote-server.com User root # 隧道设备配置 Tunnel 0:0 # 等价于命令行 -w 0:0 TunnelDevice 0:0 # (可选)显式指定设备号 # 其他必要参数 IdentityFile ~/.ssh/id_rsa PermitLocalCommand yes # 保持连接活跃 ServerAliveInterval 60 ServerAliveCountMax 3 ``` #### **关键参数说明**: [Section titled “关键参数说明:”](#关键参数说明) | **参数** | **作用** | | -------------------- | ------------------------------------------------- | | `Tunnel` | 指定本地和远程的 TUN 设备号,格式为 `:`(如 `0:0`)。 | | `TunnelDevice` | (部分版本支持)显式绑定到具体设备号,与 `Tunnel` 类似。 | | `PermitTunnel` | 需在服务端 `sshd_config` 中设置为 `yes`,否则隧道无法建立(见下文)。 | | `PermitLocalCommand` | 允许在本地执行命令(如自动配置 IP 地址)。 | *** ### **3. 服务端配置(必需)** [Section titled “3. 服务端配置(必需)”](#3-服务端配置必需) 在远程服务器的 `/etc/ssh/sshd_config` 中启用隧道支持: ```bash PermitTunnel yes # 允许 TUN/TAP 隧道 ``` 重启 SSH 服务生效: ```bash sudo systemctl restart sshd ``` *** ### **4. 使用步骤示例** [Section titled “4. 使用步骤示例”](#4-使用步骤示例) #### **(1) 建立 SSH 隧道** [Section titled “(1) 建立 SSH 隧道”](#1-建立-ssh-隧道) ```bash ssh -w 0:0 root@remote-server.com ``` #### **(2) 配置虚拟接口 IP 地址** [Section titled “(2) 配置虚拟接口 IP 地址”](#2-配置虚拟接口-ip-地址) * **本地**: ```bash sudo ip addr add 10.0.0.1/24 dev tun0 sudo ip link set tun0 up ``` * **远程**: ```bash sudo ip addr add 10.0.0.2/24 dev tun0 sudo ip link set tun0 up ``` #### **(3) 测试连通性** [Section titled “(3) 测试连通性”](#3-测试连通性) ```bash ping 10.0.0.2 # 从本地 ping 远程隧道 IP ``` *** ### **5. 高级用法:自动化配置** [Section titled “5. 高级用法:自动化配置”](#5-高级用法自动化配置) 在 SSH 配置文件中添加 `LocalCommand`,自动完成 IP 分配: ```bash Host my-tunnel-host HostName remote-server.com User root Tunnel 0:0 PermitLocalCommand yes LocalCommand sudo ip addr add 10.0.0.1/24 dev tun0 && sudo ip link set tun0 up ``` *** ### **6. 常见问题与注意事项** [Section titled “6. 常见问题与注意事项”](#6-常见问题与注意事项) 1. **权限问题**: * 需要 `root` 权限创建 TUN/TAP 设备,建议以 `sudo` 运行 SSH 命令。 * 如果使用普通用户,需配置 `CAP_NET_ADMIN` 权限: ```bash sudo setcap cap_net_admin=ep /usr/bin/ssh ``` 2. **操作系统支持**: * **Linux**:原生支持 TUN/TAP。 * **macOS**:需安装 [TUN/TAP 驱动](https://tuntaposx.sourceforge.net/)。 * **Windows**:需安装 OpenVPN 的 `tap-windows` 驱动。 3. **协议选择**: * TUN 模式(默认):传输 IP 数据包(L3)。 * TAP 模式:传输以太网帧(L2),需显式指定: ```bash ssh -o Tunnel=ethernet -w 0:0 user@host ``` *** ### **7. 完整配置示例** [Section titled “7. 完整配置示例”](#7-完整配置示例) \~/.ssh/config ```bash Host vpn-tunnel HostName vpn.example.com User root IdentityFile ~/.ssh/vpn_key Tunnel 0:0 PermitLocalCommand yes LocalCommand sudo ip addr add 10.0.0.1/24 dev tun0 && sudo ip link set tun0 up RemoteCommand sudo ip addr add 10.0.0.2/24 dev tun0 && sudo ip link set tun0 up ServerAliveInterval 30 RequestTTY yes # 允许执行远程命令(RemoteCommand) ``` *** ### **总结** [Section titled “总结”](#总结) * **`-w` 参数**:用于创建 TUN/TAP 隧道,需在配置文件中使用 `Tunnel` 指令。 * **核心步骤**:服务端启用 `PermitTunnel`,客户端配置隧道设备并分配 IP。 * **适用场景**:构建 VPN、跨网络透明代理、支持 UDP 的全协议转发。 # sshuttle ## 更智能的方案(推荐使用 sshuttle) [Section titled “更智能的方案(推荐使用 sshuttle)”](#更智能的方案推荐使用-sshuttle) 如果不需要精细控制 TUN 设备,推荐使用轻量级 SSH VPN 工具: ```bash # 安装 sshuttle(Python 编写,无需内核驱动) brew install sshuttle # 一键启动 VPN(自动处理路由和隧道) sshuttle -r root@10.0.1.90 --python $(which python3) 0.0.0.0/0 ``` 效果: * 所有流量自动通过 SSH 隧道 * 无需手动配置 TUN 设备 * 自动处理路由规则 *** ### 两种方案对比 [Section titled “两种方案对比”](#两种方案对比) | 特性 | 原生 SSH TUN 方案 | sshuttle 方案 | | ------ | ------------- | ----------- | | 配置复杂度 | 高(需手动管理设备) | 低(一键启动) | | 跨平台兼容性 | 依赖 TUN 驱动 | 纯 Python 实现 | | 流量控制 | 需手动配置路由 | 自动路由所有流量 | | 系统权限需求 | 需要 root/sudo | 普通用户权限 | | 适用场景 | 需要精细控制网络层 | 快速建立全流量 VPN | *** ### 测试连接 [Section titled “测试连接”](#测试连接) 对于原生 SSH TUN 方案: ```bash # 连接并创建隧道 ssh dev-2023-tunnel # 验证 macOS 端隧道 ifconfig utun0 # 应看到 10.1.0.1 的 IP # 测试远程连通性 ping 10.1.0.2 ``` *** ### 常见问题处理 [Section titled “常见问题处理”](#常见问题处理) 1. **出现 `utun0: Network is down` 错误** * 确认已安装 TUN 驱动 * 检查 `sudo` 权限是否配置正确 2. **sshuttle 无法启动** * 指定 Python3 路径:`--python $(which python3)` * 确保远程服务器允许 SSH 端口转发 3. **部分应用不遵循系统路由** * 配合使用 `--dns` 参数转发 DNS 请求 ```bash sshuttle -r user@host --dns 0.0.0.0/0 ``` # 科学上网与VPN办公的完美结合 [参考文章](https://blog.long2ice.io/2023/03/%E7%A7%91%E5%AD%A6%E4%B8%8A%E7%BD%91%E4%B8%8Evpn%E5%8A%9E%E5%85%AC%E7%9A%84%E5%AE%8C%E7%BE%8E%E7%BB%93%E5%90%88/) # 模拟并解决死锁 [参考AI资料](https://www.doubao.com/thread/w216e8cc04bfc4994) 使用idea连接数据库 并使用手动提交事务的方式去模拟 当然 也可以直接使用sql命令的方式实现手动提交事务 ## 模拟死锁 [Section titled “模拟死锁”](#模拟死锁) ```sql -- 事务一 BEGIN; -- 执行一些操作,例如更新表中的一行数据 UPDATE table_name SET column_name = 'test' WHERE column_name = 'test'; -- 尝试获取对表 1 中某行数据的排他锁 SELECT * FROM table_name_2 WHERE column_name = 1 FOR UPDATE; COMMIT; ``` ```sql -- 事务二 BEGIN; -- 执行一些操作,例如更新表中的一行数据 UPDATE table_name_2 SET column_name = 1 WHERE column_name = 1; -- 尝试获取对表 2 中某行数据的排他锁 SELECT * FROM table_name WHERE column_name = 'test' FOR UPDATE; COMMIT; ``` ## 解决死锁 [Section titled “解决死锁”](#解决死锁) ```sql -- 方式一 -- 查看死锁的sql以及进程Id select pid,query,* from pg_stat_activity where datname='iuin' and wait_event_type = 'Lock'; -- 只能杀死select 语句, 对其他语句不生效 select pg_cancel_backend('28736'); -- select,drop等各种操作 select pg_terminate_backend('25605'); -- 方式二 -- 查看对应表都有哪些锁 select locktype,pid,relation,mode,granted,* from pg_locks where relation in (select oid from pg_class where relname='table_name'); select pg_terminate_backend('进程ID'); -- 测试 -- 终止所有被激活的锁 select pg_terminate_backend(pid) from pg_stat_activity where state = 'active' and pid != pg_backend_pid() and pid in (select a.pid from pg_locks a join pg_class b on a.relation = b.oid where lower(b.relname) = 'news_content'); ``` ## 查看同一事物中都执行了哪些sql [Section titled “查看同一事物中都执行了哪些sql”](#查看同一事物中都执行了哪些sql) [参考AI回答](https://www.doubao.com/thread/w47b5fa72219f3bf5) * 一些第三方的扩展工具,如 pg\_stat\_monitor ,可以提供更详细和有针对性的事务执行信息。 ## pgsql当前线程数与最大线程数 [Section titled “pgsql当前线程数与最大线程数”](#pgsql当前线程数与最大线程数) PostgreSQL 最大连接数:通过 postgresql.conf 文件或 SQL 查询 `SHOW max_connections;` 获取。 当前连接数:通过 SQL 查询 `SELECT count(*), sum(case when state = 'active' then 1 else 0 end) FROM pg_stat_activity;` 获取。 # 内网穿透工具 localtunnel, Staqlab tunnel, serveo 1. [ngrok](https://ngrok.com/) 2. [localtunnel](https://localtunnel.me/) # 如何让docker走代理 [参考本地文章](https://github.com/183461750/doc-record/blob/84e35bffe7f0f1fa2a6cf2dbe65cc0292a8c4540/materiel/ai/docker/%E5%A6%82%E4%BD%95%E8%AE%A9docker%E8%B5%B0%E4%BB%A3%E7%90%86.md) [参考文章](https://neucrack.com/p/286) ```bash # sudo vim /etc/systemd/system/docker.service.d/http-proxy.conf [Service] Environment="HTTP_PROXY=http://127.0.0.1:8123" Environment="HTTPS_PROXY=http://127.0.0.1:8123" ``` ```bash sudo systemctl daemon-reload sudo systemctl restart docker ``` # arthas查看sql_redis_es拼接好参数的命令 [参考文章](http://codefun007.xyz/a/article_detail/2392.htm) ```bash watch java.sql.Connection prepareStatement '{params,throwExp}' -x 3 watch java.sql.Statement executeQuery '{params,throwExp}' -x 3 watch org.apache.ibatis.mapping.BoundSql getSql '{params,returnObj,throwExp}' -x 3 ``` * temp ```bash watch java.sql.Statement executeQuery '{params,returnObj,throwExp}' -n 5 -x 3 watch java.sql.Statement executeQuery '{params,returnObj,throwExp}' -x 3 watch java.sql.Statement executeQuery '{params,returnObj,throwExp}' -x 2 # 查看select语句 watch java.sql.Statement executeQuery '{params,returnObj,throwExp}' -x 2 | grep select # 看到的是jpa的非本地sql watch javax.persistence.EntityManager createQuery '{params,returnObj,throwExp}' -n 5 -x 3 # jpa(完整sql) watch java.sql.Statement executeQuery '{params,returnObj,throwExp}' -x 2 # mybatis plus (参数和sql分离) watch org.apache.ibatis.mapping.BoundSql '{params,returnObj,throwExp}' -x 2 # es # elasticsearch-rest-high-level-client-7.9.3.jar(jdk1.8) watch org.elasticsearch.client.RestHighLevelClient search '{params,throwExp}' -x 2 # elasticsearch-java-8.13.4.jar(jdk17) watch co.elastic.clients.elasticsearch.ElasticsearchClient search '{params,returnObj,throwExp}' -n 5 -x 2 # redis watch org.springframework.data.redis.connection.RedisHashCommands hMSet '{params,returnObj,throwExp}' -n 5 -x 3 ``` # centos7报错记录 ## 解决 docker Failed to get D-Bus connection 报错 [Section titled “解决 docker Failed to get D-Bus connection 报错”](#解决-docker-failed-to-get-d-bus-connection-报错) [参考文章](https://www.cnblogs.com/as007012/p/10042387.html) systemctl start http.service Failed to get D-Bus connection: No connection to service manager. 这个的原因是因为dbus-daemon没能启动。其实systemctl并不是不可以使用。将你的CMD或者entrypoint设置为/usr/sbin/init即可。会自动将dbus等服务启动起来。 然后就可以使用systemctl了。命令如下: docker run —privileged -ti -e “container=docker” -v /sys/fs/cgroup\:/sys/fs/cgroup centos /usr/sbin/init ## 解决使用SSH登录Linux实例时secure日志显示“failed to create session access denied” [Section titled “解决使用SSH登录Linux实例时secure日志显示“failed to create session access denied””](#解决使用ssh登录linux实例时secure日志显示failed-to-create-session-access-denied) [参考文章](https://help.aliyun.com/zh/ecs/the-secure-log-entry-failed-to-create-session-access-denied-is-displayed-when-you-log-on-to-a-linux-instance-through-ssh) * 问题描述 ```bash # 登录docker容器执行命令报能看到以下报错. $ `systemctl status sshd` # pam_selinux(sshd:session): Error sending audit message. # failed to create session access denied # 同时在登录界面还能看到提示以下信息。$ `ssh -p 3333 127.0.0.1` # root@127.0.0.1's password: # Last login: Fri Oct 11 05:50:17 2024 from gateway # /bin/bash: Permission denied # Connection to 127.0.0.1 closed. # 问题原因: 由于开启了SELinux,一般情况下开启SELinux会提高系统的安全性,但是会破坏操作系统的文件,从而造成系统异常。 # 解决方法: setenforce 0|1, 0: 设置为permissive, 1: 设置为enforcing # 相关命令: getenforce: 获取selinux当前状态, sestatus :查看selinux状态 setenforce 0 ``` # 使用arthas和proxyman监听java进程网络(包括feign调用等) ## 相关命令 [Section titled “相关命令”](#相关命令) ```bash # proxyman代理环境变量 export https_proxy=http://10.0.4.190:9091 http_proxy=http://10.0.4.190:9091 # 设置 HTTP/HTTPS 代理 sysprop https.proxyHost 10.0.4.190 sysprop https.proxyPort 9091 sysprop http.proxyHost 10.0.4.190 sysprop http.proxyPort 9091 # 移除 HTTP/HTTPS 代理(使用System.clearProperty方式移除) ognl '@java.lang.System@clearProperty("https.proxyHost")' ognl '@java.lang.System@clearProperty("https.proxyPort")' ognl '@java.lang.System@clearProperty("http.proxyHost")' ognl '@java.lang.System@clearProperty("http.proxyPort")' # 验证 sysprop | grep proxy # 因为feign调用用的是服务名, 没有IP和port, 所有现在考虑将本地流量代理到指定服务器中去(不行, 没搞成) # 改成用proxyman代理到指定服务器中去(用的远程映射功能, 例如 gateway-service -> feign.microservice.debug:8100)(然后结合SwitchHosts工具, 将feign.microservice.debug映射到10.0.1.94 IP上, 这样子, 之后只需要改SwitchHosts中的IP就能实现访问到不同的服务器上去了(当然, 直接切换开关的方式也行)) * PS: 不用这么麻烦, 上面是因为DNS劫持导致域名没有找到IP才需要做的操作, 域名之所以被劫持还是因为开了clash代理(默认劫持了DNS) ``` # readme 这是我的草稿目录 * 用来给写文章做草稿 # ssh动态代理妙用-将流量代理到其他电脑实现本机不装vpn也能访问公司内网 问题: 要是有多个项目需要访问不同的vpn, 那么此时你想的是怎么做呢? 最简单的方法就是只能频繁的在各个vpn软件中切来切去 > 最近因为经手的项目越来越多, 多个项目都需要走对应vpn软件才能访问对应项目的系统 所以也就萌生了想在本机啥vpn都不装的情况下, 如何通过将流量代理到其他安装了对应vpn软件的电脑上去实现本机不装vpn也能访问对应项目系统的目的 ## 实现多种流量的代理需求 [Section titled “实现多种流量的代理需求”](#实现多种流量的代理需求) ### 第一种: 只通过ssh tunnel代理流量 [Section titled “第一种: 只通过ssh tunnel代理流量”](#第一种-只通过ssh-tunnel代理流量) 例如: 数据库连接 ### 第二种: 只通过浏览器代理流量 [Section titled “第二种: 只通过浏览器代理流量”](#第二种-只通过浏览器代理流量) 例如: 项目系统页面 ### 第三种: 代理本机全局流量 [Section titled “第三种: 代理本机全局流量”](#第三种-代理本机全局流量) 缺点很明显, 啥流量都走同一个代理去了 ### 第四种: 通过自定义规则自动代理本机流量走指定vpn [Section titled “第四种: 通过自定义规则自动代理本机流量走指定vpn”](#第四种-通过自定义规则自动代理本机流量走指定vpn) 例如: 多个项目的系统页面 # 如何把服务器容器中的文件夹通过nfs的方式挂载到本地mac电脑 要将服务器容器中的文件夹通过 NFS 挂载到本地 Mac 电脑,需要完成服务器端(容器所在主机)和客户端(Mac)的配置,步骤如下: ### **一、服务器端配置(容器所在的 Linux 主机)** [Section titled “一、服务器端配置(容器所在的 Linux 主机)”](#一服务器端配置容器所在的-linux-主机) 1. **安装 NFS 服务**\ 在服务器主机(不是容器内)安装 NFS 服务: ```bash # Ubuntu/Debian sudo apt update && sudo apt install nfs-kernel-server # CentOS/RHEL sudo yum install nfs-utils ``` 2. **准备要共享的目录**\ 假设容器中的目录为 `/container/data`,且已通过 `-v /host/data:/container/data` 挂载到主机的 `/host/data`。我们需要共享主机的 `/host/data`: ```bash # 确保目录存在并设置权限 sudo mkdir -p /host/data sudo chmod 777 /host/data # 简化权限,生产环境需谨慎设置 ``` 3. **配置 NFS 共享**\ 编辑 NFS 配置文件 `/etc/exports`,添加允许 Mac 访问的规则: ```bash sudo nano /etc/exports ``` 添加内容(替换 `MAC_IP` 为你的 Mac 本地 IP): ```plaintext /host/data MAC_IP(rw,sync,no_subtree_check,insecure) ``` * `rw`:读写权限 * `sync`:同步写入磁盘 * `insecure`:允许非标准端口(Mac 可能需要) 4. **生效配置并重启服务** ```bash # 刷新共享配置 sudo exportfs -a # 重启 NFS 服务 sudo systemctl restart nfs-kernel-server # Ubuntu/Debian # 或 sudo systemctl restart nfs-server # CentOS/RHEL ``` 5. **开放防火墙端口**\ 确保服务器防火墙允许 NFS 相关端口(2049、111 等): ```bash # UFW 防火墙(Ubuntu) sudo ufw allow from MAC_IP to any port nfs sudo ufw allow 111/tcp sudo ufw allow 111/udp ``` ### **二、Mac 客户端配置** [Section titled “二、Mac 客户端配置”](#二mac-客户端配置) 1. **创建本地挂载点**\ 在 Mac 上创建一个目录用于挂载: ```bash mkdir -p ~/nfs_mount ``` 2. **挂载 NFS 共享**\ 使用 `mount` 命令挂载服务器共享(替换 `SERVER_IP` 为服务器 IP): ```bash sudo mount -t nfs SERVER_IP:/host/data ~/nfs_mount ``` 3. **验证挂载**\ 查看是否挂载成功: ```bash df -h # 查看挂载信息 ls ~/nfs_mount # 查看共享目录内容 ``` ### **三、卸载挂载(可选)** [Section titled “三、卸载挂载(可选)”](#三卸载挂载可选) 需要断开连接时,执行: ```bash sudo umount ~/nfs_mount ``` ### **注意事项** [Section titled “注意事项”](#注意事项) 1. **容器与主机的挂载关系**:必须确保容器内的目录已正确挂载到主机,否则 NFS 共享的是主机空目录。 2. **权限问题**:若出现权限错误,检查服务器目录权限(`chmod`)和 NFS 配置中的 `rw` 选项。 3. **IP 地址**:Mac 和服务器需在同一网络,且 IP 地址需正确(可通过 `ifconfig` 查看 Mac 本地 IP)。 通过以上步骤,即可在 Mac 上直接访问服务器容器中的文件。 # mac开启nfs 在Mac上开启NFS服务,可以按照以下步骤进行: 1. **编辑NFS配置文件**:打开终端,输入`sudo vim /etc/exports`命令编辑NFS的配置文件。在文件中添加要共享的目录及相关配置,例如`/Users/xxxx/Documents -alldirs -maproot=root:wheel -network 192.168.31.0 -mask 255.255.255.0`,其中`/Users/xxxx/Documents`是想要共享的Mac端目录,`-network 192.168.31.0`指定允许访问的网络范围。 2. **检查配置文件**:添加完内容后,保存并退出编辑器。然后输入`sudo nfsd checkexports`命令,检查NFS配置是否正确。 3. **开启NFS服务**:首先禁用NFS服务,输入`sudo nfsd disable`命令;接着启用NFS服务,输入`sudo nfsd enable`命令;最后重启NFS服务,输入`sudo nfsd stop`和`sudo nfsd start`命令。 4. **检查NFS服务状态**:输入`sudo nfsd status`命令,确保NFS服务正在运行。 5. **检查NFS共享目录**:使用`showmount -e`命令,查看共享目录是否正确配置。如果命令返回了共享目录列表,说明NFS服务已经成功配置。 # clickhouse ## 安装指定版本 [Section titled “安装指定版本”](#安装指定版本) [参考官网](https://clickhouse.com/docs/zh/getting-started/install#from-tgz-archives) ```bash # 执行安装脚本(中途需要输入`default`用户的密码, 以及是否允许默认用户从任何地方访问) # 脚本中的`LATEST_VERSION`环境变量可以填写想要安装的版本号,默认为最新稳定版(可以在这里找版本[https://github.com/ClickHouse/ClickHouse/tags]) bash ./clickhouse-install.sh # 启动 sudo /etc/init.d/clickhouse-server start # 连接 clickhouse-client # 示例 SELECT 1 ``` # pgsql使用记录 ## 格式化long类型时间字段 [Section titled “格式化long类型时间字段”](#格式化long类型时间字段) ```sql -- long类型时间字段格式化 SELECT to_timestamp(create_time/1000) AT TIME ZONE 'Asia/Shanghai' AS create_time_local, * FROM table_name; ``` # Redis相关记录 ## 导出Redis中的数据 [Section titled “导出Redis中的数据”](#导出redis中的数据) ```shell # 连接redis redis-cli -h 127.0.0.1 -p 6379 -a foobared # 导出key数据到文件 keys "*" | xargs redis-cli get > /tmp/redis_data.txt # 导出指定key数据到文件中 redis-cli get key > /tmp/redis_data.txt # 使用DUMP命令来导出指定key的数据 redis-cli dump key > /tmp/redis_data.txt ``` * 相关链接 * [docker数据导出](../../../docker/app/devs/data/redis/redis.md#%E6%95%B0%E6%8D%AE%E5%AF%BC%E5%87%BA) # Kasm Workspaces使用记录 官方开源组织地址: 控制面板与编排引擎:其管理后台、用户认证和容器调度模块本身是闭源的。但官方提供了完全免费的 [Community Edition (社区版)](https://kasm.com/community-edition),支持高达 5 个并发会话,这对于个人和小型团队运维完全够用。 第三方维护的纯 Docker 开源一键部署地址(极力推荐):由知名开源社区 LinuxServer 维护的 [linuxserver/docker-kasm](https://github.com/linuxserver/docker-kasm),可以绕过官方复杂的安装包,直接用容器部署。 用 [Kasm 1.19 官方主推的 Kubernetes (Helm Chart) 生产级架构](https://kasm.com/kasm-insights/no-slug-32) ## Kasm 官方 K8s 部署核心步骤 [Section titled “Kasm 官方 K8s 部署核心步骤”](#kasm-官方-k8s-部署核心步骤) 在开始前,请确保你已有现成的 K8s 集群(建议版本 ≥ 1.26),并且本地已安装 Helm 3。 > 「Agent 节点不能包含在 Helm Chart 中」:Helm 部署仅负责拉起控制平面(App 核心、Connection Proxy 网关等)。用户秒开的 Linux/Windows 虚拟桌面(会话)必须运行在 K8s 集群之外的独立 Docker 物理机或虚拟机上(即 Agent 角色)。这是为了防止图形流编码、重度嵌套容器(DinD)抢占 K8s 核心节点的网络和 CPU 资源。 /root/.kube/config ```bash helm repo add kasmtech https://helm.kasmweb.com helm repo update # WARNING: Kubernetes configuration file is world-readable. This is insecure. Location: /root/.kube/config # 限制 K8s 配置文件权限,消除系统安全警告, 仅 root 独占(业界生产安全审计等保必查项) chmod 600 /root/.kube/config # 在 /data/k8s/kasm-workspaces 目录下创建并编辑你的企业级配置文件: nano /data/k8s/kasm-workspaces/values-production.yaml # 创建独立的、强隔离的命名空间: kubectl create namespace kasm-mgmt ``` ```bash # 1. 确保创建了目标命名空间 kubectl create namespace kasm-mgmt --dry-run=client -o yaml | kubectl apply -f - #💡 测试环境临时自签命令:如果是内网测试没有自备证书,请先在当前目录下执行以下命令快速生成证书文件 openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout kasm.key -out kasm.crt -subj "/CN=kasm.yourcompany.local" # 2. 为三个网关组件分别创建对应的 K8s Secret 凭据(这会直接满足报错中 "Required value" 的校验要求) kubectl create secret tls kasm-prod-rdp-gw-cert --cert=kasm.crt --key=kasm.key -n kasm-mgmt kubectl create secret tls kasm-prod-proxy-cert --cert=kasm.crt --key=kasm.key -n kasm-mgmt kubectl create secret tls kasm-prod-rdp-https-gw-cert --cert=kasm.crt --key=kasm.key -n kasm-mgmt # kubectl delete secret kasm-prod-rdp-gw-cert kasm-prod-rdp-https-gw-cert kasm-prod-proxy-cert -n kasm-mgmt 2>/dev/null ``` ```bash # 运行 Helm 进行基于 K8s 架构的无缝安装: helm install kasm-prod kasmtech/kasm -n kasm-mgmt -f /data/k8s/kasm-workspaces/values-production.yaml --set kasmApp.proxy.ssl=false --set kasmApp.rdpGw.ssl=false --set kasmApp.rdpHttpsGw.ssl=false # 1. 如果上次有残留,先彻底清除旧实例 # helm uninstall kasm-prod -n kasm-mgmt 2>/dev/null # 检查控制面运行状态: kubectl get pods -n kasm-mgmt -w ## 等待 kasm-api 和 kasm-proxy 等关键 Pod 的状态全部转为 Running。 ``` ```bash # 彻底卸载并清除残留的 Release 状态 # 1. 彻底卸载已有的 kasm-prod 实例(释放名称占用) helm uninstall kasm-prod -n kasm-mgmt # 2. 验证是否已经彻底清除(确保返回结果中没有 kasm-prod) helm list -n kasm-mgmt ``` ## 第二版 [Section titled “第二版”](#第二版) ```bash # 一键安装 Cert-Manager(若已安装可跳过): kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.4/cert-manager.yaml # 等待 cert-manager 核心组件就绪 kubectl wait --for=condition=Available deployment --all -n cert-manager --timeout=120s # 创建生产级 ClusterIssuer(签发证书的机构): # 新建 issuer.yaml,复制以下内容(修改邮箱和 Ingress Class),然后执行 kubectl apply -f issuer.yaml # 一键执行 Helm 安装 # 1. 创建专属命名空间 kubectl create namespace kasm-prod # 创建 PostgreSQL 密码 Secret: # 将 '你的PG密码' 替换为实际密码 kubectl create secret generic kasm-pg-secret --from-literal=password='你的PG密码' -n kasm-prod # 创建 Redis 密码 Secret(如果 Redis 无密码可跳过): # 将 '你的Redis密码' 替换为实际密码 kubectl create secret generic kasm-redis-secret --from-literal=password='你的Redis密码' -n kasm-prod # 生成生产级 values-prod.yaml # 新建 values-prod.yaml,复制以下经过官方 Schema 校验的结构。⚠️ 请仔细修改带有 【必改】 的 5 个地方。 # 2. 添加/更新官方仓库 helm repo add kasmweb https://helm.kasm.com helm repo update # 3. 执行安装 (加入 --wait 确保所有组件和证书都 Ready, 但是默认只等5分钟, 直接后续看更方便了) helm install kasm-prod kasmweb/kasm-helm -n kasm-prod --create-namespace -f values-prod.yaml ``` 内网走自签证书 ```bash # 1. 生成自签证书 openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=xxx.iuin.dev" -addext "subjectAltName=DNS:xxx.iuin.dev" # 2. 覆盖写入 Secret kubectl create secret tls kasm-prod-auto-tls --cert=tls.crt --key=tls.key -n kasm-prod --dry-run=client -o yaml | kubectl apply -f - # 3. 触发 Helm 更新: helm upgrade kasm-prod kasmweb/kasm-helm -n kasm-prod -f values-prod.yaml ``` ```bash # 生产级验证与排错(SOP 闭环) # 验证证书是否自动签发成功: # 如果证书卡住,Kasm 的 Pod 会因为挂载不到 Secret 而一直 Pending 或 CreateContainerConfigError。 # 查看 Certificate 状态,READY 必须为 True kubectl get certificate -n kasm-prod # 如果 READY 为 False,查看 Cert-Manager 日志排错: kubectl logs -n cert-manager deployment/cert-manager-webhook --tail=50 # 2. 验证外部 PG 连接: # 查看 Kasm 的 API 或 DB 初始化日志,确认没有 Connection Refused 或 Authentication Failed。 kubectl logs -n kasm-prod -l app=kasm-api --tail=100 | grep -i "database" # 获取初始管理员密码: # 由于剥离了内置 DB,Kasm 初始化完成后,Admin 密码通常会打印在初始化 Job 中,或存入 Secret。 # 查看初始化日志获取密码 kubectl logs -n kasm-prod job/kasm-prod-db-init-job | grep -i "password" # 或者从 Secret 中提取 (Key 名称可能因版本微调,通常为 admin_password) kubectl get secret kasm-secrets -n kasm-prod -o jsonpath="{.data.admin_password}" | base64 --decode ``` 排查 ```bash # 查看 Certificate 资源的状态 kubectl get certificate -n kasm-prod # 查看详细的失败原因: kubectl describe certificate kasm-prod-auto-tls -n kasm-prod kubectl describe certificate kasm-prod-cert-manager -n kasm-prod # 检查 ClusterIssuer 是否就绪: kubectl get clusterissuer letsencrypt-prod # 查看底层的 Order (订单) 状态(最准确): kubectl get order -n kasm-prod # 拿到上面输出的那个 order 名字后,执行 describe: kubectl describe order <替换为上面查到的order名字> -n kasm-prod # 清理卡死的旧证书订单(重要!) # 删除卡住的 Certificate 资源 (它会自动重建) kubectl delete certificate kasm-prod-cert-manager -n kasm-prod # 删除残留的失败 Order kubectl delete order --all -n kasm-prod # 重新执行 Helm 升级(--wait --timeout 15m) helm upgrade kasm-prod kasmweb/kasm-helm -n kasm-prod -f values-prod.yaml ``` 清理旧环境并重新部署 ```bash # 1. 彻底删除旧环境 helm uninstall kasm-prod -n kasm-prod kubectl delete namespace kasm-prod # 2. 重新创建命名空间 kubectl create namespace kasm-prod # 3. 重新注入刚才的两个 Secret (超管密码和证书) # (请重新执行第一步中的 kubectl create secret 命令,因为 namespace 被删了) # 4. 终极安装 (加入 --timeout 15m 等待自动建表完成) helm install kasm-prod kasmweb/kasm-helm -n kasm-prod -f values-prod.yaml ``` ## ⚠️ 内网自签证书的“致命隐藏坑”(必看!) [Section titled “⚠️ 内网自签证书的“致命隐藏坑”(必看!)”](#️-内网自签证书的致命隐藏坑必看) 在内网使用自签证书访问 Kasm 时,极大概率会遇到 “登录成功,但打开 Ubuntu 桌面时一直黑屏或提示 Connection Failed”。 原因:Kasm 的 VNC 桌面强依赖 WebRTC 技术。现代浏览器(Chrome/Edge)对自签证书的安全策略极其严格,会默默拦截 WebRTC 的 UDP 数据流,导致画面传不过来。 终极解决办法(二选一): 方法 1:浏览器“物理”放行(最简单) 在访问 Kasm 的那个 Chrome/Edge 标签页中,不要动鼠标,直接用键盘盲打输入以下这串字母(输入时屏幕上不会有显示): ```bash thisisunsafe # 敲完后,页面会自动刷新,WebRTC 就会被放行,桌面瞬间就能出来了! ``` 方法 2:在 Kasm 后台关闭 WebRTC 强制要求(一劳永逸) 用 admin 账号登录 Kasm 后台。 左侧菜单导航到 Admin -> Settings -> Server。 找到 WebRTC 相关的选项,将 WebRTC Fallback 开启,或者直接禁用 WebRTC(Disable WebRTC)。 这样 Kasm 就会降级使用普通的 WebSocket 传输画面,虽然延迟比 WebRTC 高几毫秒,但在内网自签证书下绝对稳定,永不黑屏。 ## 看到 failed to create fsnotify watcher: too many open files 这个报错,是 K8s 节点(宿主机 Linux 内核)的文件监控句柄(inotify)被耗尽了! [Section titled “看到 failed to create fsnotify watcher: too many open files 这个报错,是 K8s 节点(宿主机 Linux 内核)的文件监控句柄(inotify)被耗尽了!”](#看到-failed-to-create-fsnotify-watcher-too-many-open-files-这个报错是-k8s-节点宿主机-linux-内核的文件监控句柄inotify被耗尽了) ```bash # 临时生效(立刻解决崩溃) sudo sysctl -w fs.inotify.max_user_watches=1048576 sudo sysctl -w fs.inotify.max_user_instances=1024 ``` ```bash # 永久固化(防止重启后失效) cat </dev/null # 3.2 在每个 K8s 节点上清理物理目录 sudo rm -rf /opt/local-path-provisioner/*kasm-prod* # 清理集群级证书残留(仅当使用过 cert-manager 自动证书时) # ClusterIssuer 是集群级资源,不随命名空间删除 kubectl delete clusterissuer letsencrypt-dns-prod 2>/dev/null # ACME 账户私钥(位于 cert-manager 命名空间) kubectl delete secret letsencrypt-dns-prod-key -n cert-manager 2>/dev/null # 清理测试残留 Pod(如果之前调试留下) kubectl delete pod pg-test kasm-init rdptest -n kasm-prod --force --grace-period=0 2>/dev/null ``` ## 安装 [Section titled “安装”](#安装) ```bash # 调整 K8s 节点内核参数(防崩溃,必做!) # 临时生效 sudo sysctl -w fs.inotify.max_user_watches=1048576 sudo sysctl -w fs.inotify.max_user_instances=1024 # 永久固化(防止重启失效) cat < -n cert-manager # 3A.3 创建 DNS-01 ClusterIssuer(可重复执行, 重复执行则覆盖) cat </dev/null; helm repo update # 4.2 确保命名空间存在(选项 A 需要手动建) kubectl create namespace kasm-prod 2>/dev/null # 编写 values-prod.yaml(Schema 校验通过版,二选一证书块): # 执行安装: helm install kasm-prod kasmweb/kasm-helm -n kasm-prod -f values-prod.yaml --wait --timeout 15m # 验收与加固 # 5.1 全部 Running / Completed(选项 A 时 Certificate 为 Ready) kubectl get pods -n kasm-prod kubectl get certificate -n kasm-prod # 5.2 提取管理员密码 kubectl get secret -n kasm-prod kasm-prod-secrets -o jsonpath="{.data.admin-password}" | base64 -d; echo # 5.3 灾备核心 Secret(丢了这个等于丢整个控制面) kubectl get secret kasm-prod-secrets -n kasm-prod -o yaml > kasm-prod-secrets-backup.yaml # 内网缩容(防资源不足 Pending) # 内网缩容到 1 副本(资源不够时必做) kubectl scale deploy kasm-prod-api-default -n kasm-prod --replicas=1 kubectl scale deploy kasm-prod-proxy-default -n kasm-prod --replicas=1 kubectl scale deploy kasm-prod-manager-default -n kasm-prod --replicas=1 kubectl scale statefulset kasm-prod-guac-default -n kasm-prod --replicas=1 # 客户端访问: # 客户端 hosts 添加 10.0.5.167 pdd.iuin.dev(或内网 DNS 做 Split 解析)。 # 浏览器访问 https://pdd.iuin.dev → 绿色小锁头(LE 生产证书,无需 thisisunsafe)。 # 登录 admin@kasm.local + 提取的密码。 # Admin → Settings → Server → 关闭 WebRTC(内网防黑屏必做)→ Save。 # 启动 Workspace,VNC 桌面丝滑弹出。 ``` ### 获取 Cloudflare API Token(最小权限版) [Section titled “获取 Cloudflare API Token(最小权限版)”](#获取-cloudflare-api-token最小权限版) ![alt text](/_astro/cert-manager-dns01-iuin.dev-cloudflare.BO1jPkra_1APHgg.webp) 验证 Token 是否有效(在任意能上网的机器上): ```bash curl -s -H "Authorization: Bearer <你的Token>" \ https://api.cloudflare.com/client/v4/user/tokens/verify # 官方提供的测试方式 curl "https://api.cloudflare.com/client/v4/user/tokens/verify" \ -H "Authorization: Bearer <你的Token>" ``` 这个 Token 泄露了,攻击者能干什么? * ✅ 能:增删改 iuin.dev 这一个域名的 DNS 记录(比如把 pdd.iuin.dev 指到他的服务器做劫持)。 * ❌ 不能:碰你账号里的其他域名、不能改账号设置、不能看账单、不能动 Workers/Pages 等任何其他服务。 ## 关于生产域名解析到内网IP上的问题 [Section titled “关于生产域名解析到内网IP上的问题”](#关于生产域名解析到内网ip上的问题) 如果继续用 HTTP-01,问题原封不动,还是会卡死。 因为“内网 IP”这个事实没有变。 但是!现在我们有了一个新武器——DNS-01 验证(就是上一步 certbot 手动用的那种)。只要把 cert-manager 的 ClusterIssuer 从 HTTP-01 换成 DNS-01,它就完全不需要公网 80 端口,只通过你域名解析商的 API 添加 TXT 记录来验证。这样 cert-manager 就能在内网环境里全自动签发 + 续期 Let’s Encrypt 生产证书! ## 排查命令 [Section titled “排查命令”](#排查命令) ```bash kubectl get challenge -n kasm-prod kubectl get certificate -n kasm-prod kubectl describe certificate kasm-prod-cert-manager -n kasm-prod kubectl describe certificaterequest kasm-prod-cert-manager-1 -n kasm-prod kubectl describe order kasm-prod-cert-manager-1-2168963802 -n kasm-prod kubectl describe challenge kasm-prod-cert-manager-1-2168963802-2482135258 -n kasm-prod ``` ### 更新 Secret 并重置卡死的任务 [Section titled “更新 Secret 并重置卡死的任务”](#更新-secret-并重置卡死的任务) ```bash # 1. 用新的 Token 覆盖 Secret (把 <你的新Token> 替换掉) kubectl create secret generic cloudflare-api-token \ --from-literal=api-token=<你的新Token> \ -n cert-manager \ --dry-run=client -o yaml | kubectl apply -f - # 2. 删掉被限流卡死的 Challenge 和 Order,让 cert-manager 重新排队 kubectl delete challenge kasm-prod-cert-manager-1-2168963802-2482135258 -n kasm-prod kubectl delete order kasm-prod-cert-manager-1-2168963802 -n kasm-prod # 3. 删掉旧的 CertificateRequest 强制刷新 kubectl delete certificaterequest kasm-prod-cert-manager-1 -n kasm-prod ``` # kasm ```bash # 调整 K8s 节点内核参数(防崩溃,必做!) # 临时生效 sudo sysctl -w fs.inotify.max_user_watches=1048576 sudo sysctl -w fs.inotify.max_user_instances=1024 # 永久固化(防止重启失效) cat < kasm-server.cnf <<'EOF' [req] distinguished_name = dn prompt = no x509_extensions = v3_ext [dn] CN = kasm.local [v3_ext] basicConstraints = CA:FALSE keyUsage = critical, digitalSignature, keyEncipherment extendedKeyUsage = serverAuth subjectAltName = DNS:kasm.local, IP:10.0.5.167 EOF # 2. 生成新证书(覆盖旧的 tls.key / tls.crt) openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \ -keyout tls.key -out tls.crt -config kasm-server.cnf # 3. 验证扩展(必须看到 CA:FALSE、Digital Signature、TLS Web Server Authentication) openssl x509 -in tls.crt -noout -text | grep -A1 "Key Usage\|Basic Constraints" # 验证证书 (确认包含了 pdd.iuin.dev 和 10.0.5.167) openssl x509 -in tls.crt -noout -text | grep -E "Issuer:|Subject:|DNS:|IP Address:" # 热替换 K8s 里的 TLS Secret kubectl create secret tls kasm-prod-auto-tls \ --cert=tls.crt --key=tls.key \ -n kasm-prod \ --dry-run=client -o yaml | kubectl apply -f - # ingress-nginx 会自动监听 Secret 变化并热加载,无需重启。如果 10 秒后还不生效,执行 `kubectl rollout restart deploy -n ingress-nginx ingress-nginx-controller-nginx`。 # 在 Mac 上验证新证书已生效 openssl s_client -connect 10.0.5.167:32743 -servername kasm.local /dev/null | openssl x509 -noout -text | grep -A1 "Key Usage" # 确认输出里是 Digital Signature, Key Encipherment,而不是 Certificate Sign。 # 3. 注入 K8s (名字必须和下面 values 里的一致) kubectl create secret tls kasm-prod-auto-tls \ --cert=tls.crt --key=tls.key \ -n kasm-prod # 编写生产级 values-prod.yaml(纯内置 DB 版) # ⚠️ 请仔细修改带有 【必改】 的 3 个地方。 # 一键部署 Local Path Provisioner # 1. 部署 Local Path Provisioner(自动创建 StorageClass) kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.31/deploy/local-path-storage.yaml # 2. 验证 StorageClass 是否创建成功 kubectl get storageclass # 设置为集群的默认 StorageClass。这样,所有没指定存储类的 PVC(包括这个 Guac 的 tmp-data)都会自动使用它。 kubectl patch storageclass local-path -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}' # 一键安装(给足 15 分钟耐心 --wait --timeout 15m) helm install kasm-prod kasmweb/kasm-helm \ -n kasm-prod \ -f values-prod.yaml # 修改 Kasm 配置后升级需执行以下命令 # helm upgrade kasm-prod kasmweb/kasm-helm -n kasm-prod -f values-prod.yaml # 盯紧 Pod 状态: watch kubectl get pods -n kasm-prod # 提取管理员密码: kubectl get secret --namespace kasm-prod kasm-prod-secrets -o jsonpath="{.data.admin-password}" | base64 -d; echo # 浏览器登录: # 访问:https://kasm.local (记得在内网电脑 hosts 里加上 Ingress IP kasm.local) # 账号:admin@kasm.local # 密码:上面提取的密码 # (浏览器提示不安全时,盲打 thisisunsafe 或点击“继续前往”) # 4. 解决内网 WebRTC 黑屏(必做): # 登录后,点击左侧 Admin -> Settings -> Server,往下滚动找到 WebRTC 设置项,将 "Enable WebRTC" 取消勾选(或开启 WebRTC Fallback)。保存后,重新打开 Ubuntu 桌面,画面瞬间丝滑出现! ``` ## 让 Ingress 控制器直接“霸占” K8s 节点的 80/443 端口。 [Section titled “让 Ingress 控制器直接“霸占” K8s 节点的 80/443 端口。”](#让-ingress-控制器直接霸占-k8s-节点的-80443-端口) ```bash # 确认节点 443 端口未被占用 sudo ss -tlnp | grep -E ':80|:443' # 开启 Ingress 的 hostNetwork(一键执行) # 1. 确保 Ingress 只有 1 个 Pod (防止两个 Pod 在同一个节点抢 443 端口导致崩溃) kubectl scale deploy ingress-nginx-controller-nginx -n ingress-nginx --replicas=1 # 2. 开启 hostNetwork 并修正 DNS 策略 kubectl patch deploy ingress-nginx-controller-nginx -n ingress-nginx --type=json -p='[ {"op":"add","path":"/spec/template/spec/hostNetwork","value":true}, {"op":"add","path":"/spec/template/spec/dnsPolicy","value":"ClusterFirstWithHostNet"} ]' ``` # 监控 ## alarm-settings.yml [Section titled “alarm-settings.yml”](#alarm-settingsyml) ```yml hooks: dingtalk: default: is-default: true text-template: |- { "msgtype": "text", "text": { "content": "Apache SkyWalking Alarm: \n %s." } } webhooks: - url: https://oapi.dingtalk.com/robot/send?access_token=38c949c7aeff071e2065e81e58a82cdaf54290eae442cd11468b82fd6633fc8d ``` # 路由侠使用记录 [官网docker使用地址](https://help.luyouxia.com/docker.html) [官网管理后台](https://www.luyouxia.com/console/) ```bash # x86_64: wget https://dl.luyouxia.com:8443/v2/lyx-docker-x86_64.tar docker load -i lyx-docker-x86_64.tar # arm64: wget https://dl.luyouxia.com:8443/v2/lyx-docker-arm64.tar docker load -i lyx-docker-arm64.tar # code需要管理后台获取 docker run --name lyx -it --restart=always --net=host -e code=这里填写安装码 luyouxia/lyx ``` # 星空组网 使用记录 [官网-管理后台](https://starvpn.cn/user/index.html#) ## docker方式安装 [Section titled “docker方式安装”](#docker方式安装) ```bash docker run -d \ --restart=always \ --privileged \ --net=host \ --name stars.client \ -e STARS_USER=zhangshan:001 \ -e STARS_PASS=123456 \ registry.cn-beijing.aliyuncs.com/ld_beijing/stars.client:5.1.1 ``` docker-compose方式安装(./docker/docker-compose.yml) # 云相关使用记录 ## 域名和证书 [Section titled “域名和证书”](#域名和证书) [免费域名](https://github.com/DigitalPlatDev/FreeDomain) [免费证书](https://freessl.cn) [acme.sh](https://github.com/acmesh-official/acme.sh) [查看DNS解析](https://www.whatsmydns.net) # cpolar使用记录 [官网](https://www.cpolar.com) [安装文档](https://www.cpolar.com/docs) ```bash # 安装 # mac brew tap probezy/core && brew install cpolar # linux curl -L https://www.cpolar.com/static/downloads/install-release-cpolar.sh | sudo bash # Windows # 在官网下载下载适用于Windows平台的zip压缩包,解压后得到cpolar安装包,然后双击安装包一路默认安装即可。https://www.cpolar.com/download # 验证 cpolar version # 认证 cpolar authtoken xxxxxxx # 简单穿透测试 cpolar http 8080 # 向系统添加服务 sudo systemctl enable cpolar # 启动cpolar服务 sudo systemctl start cpolar # 查看服务状态 sudo systemctl status cpolar # 登录后台,查看隧道在线状态 # https://dashboard.cpolar.com/status # 注: cpolar 卸载方法 curl -L https://www.cpolar.com/static/downloads/install-release-cpolar.sh | sudo bash -s -- --remove # 如果第一次安装,会默认配置一个简单的样例配置文件,创建了两个样例隧道,一个web,一个ssh # cpolar配置文件路径(linux): /usr/local/etc/cpolar/cpolar.yml # cpolar配置文件路径(mac): /Users/fa/.cpolar/cpolar.yml # 安装服务 sudo cpolar service install # 启动服务 sudo cpolar service start # cpolar service :Valid actions: ["start" "stop" "restart" "install" "uninstall"] # 安装完成 # 在浏览器上访问本地9200端口【 http://127.0.0.1:9200 】,使用cpolar邮箱账号登录cpolar web UI管理界面,即可开始使用cpolar。 ``` ## 将管理后台的端口映射到公网 [Section titled “将管理后台的端口映射到公网”](#将管理后台的端口映射到公网) ```bash # 修改配置(将website的端口由8080改为9200) /usr/local/etc/cpolar/cpolar.yml # 修改后重启服务 sudo cpolar service restart # 登录后台,查看隧道地址 # https://dashboard.cpolar.com/status # 这样就能远程管理隧道了 ``` # cloudflare结合腾讯云edgeone使用记录 * 关键点: 检查腾讯云 EdgeOne 配置 确保 EdgeOne 已正确配置 WebSocket 支持: 登录腾讯云 EdgeOne 控制台 进入站点详情页面 点击 “站点加速” → “网络优化” 找到 “WebSocket 配置”,确保已开启(要不gRPC也一起开启吧, 不确定是不是不开这个也不行) 设置合适的 “最大连接超时时长”(建议 300 秒) * 域名配置: 回源 HOST 头: 使用源站域名 * 优化 Cloudflared 配置 ```bash # 创建或编辑配置文件 nano ~/.cloudflared/config.yml # 添加以下优化参数 tunnel: your-tunnel-id credentials-file: /path/to/credentials.json protocol: quic # 使用QUIC协议,比HTTP/2更快 log-level: info transport-loglevel: info ``` # nip.io使用记录 动态DNS神器nip.io使用指南:快速实现域名与IP的动态映射 > 本文基于开源项目 v1.2.1版本撰写,适用于开发测试、CI/CD等场景 *** 一、项目简介 nip.io 是由Exentrique Solutions开发的开源动态DNS服务,通过智能解析机制实现任意IP地址与域名的动态映射。该服务无需注册或配置DNS记录,支持以下核心功能: * 🌐 动态域名解析:将`<任意IP>.nip.io`自动解析对应IP * 🚀 零配置使用:无需安装客户端或配置DNS服务器 * 🔧 通配符支持:支持多级子域名动态解析(如`app.10.0.0.1.nip.io`) * 🐳 容器化部署:提供Docker镜像快速搭建私有服务 *** 二、快速入门 场景1:使用公共DNS服务 直接在浏览器或应用中访问以下格式域名: ```bash IPv4格式 http://your-app.192-168-1-100.nip.io ➔ 解析到192.168.1.100 http://test.192.168.1.100.nip.io ➔ 解析到192.168.1.100 IPv6格式(需使用破折号) http://your-app.2001-0db8-85a3-0000-0000-8a2e-0370-7334.nip.io ``` 场景2:自建私有服务 ```bash 克隆项目 git clone https://github.com/exentriquesolutions/nip.io.git 使用Docker部署 bash build_and_run_docker.sh ``` *** 三、进阶配置 1. 环境变量配置 通过环境变量覆盖默认配置: [environment-variables-configuration-overrides](https://github.com/exentriquesolutions/nip.io/tree/master?tab=readme-ov-file#environment-variables-configuration-overrides) *** 四、典型应用场景 1. 本地开发调试 ```bash # 运行本地服务 python -m http.server 8080 # 通过域名访问 http://dev.127-0-0-1.nip.io:8080 ``` 1. Kubernetes服务暴露 ```yaml apiVersion: v1 kind: Service metadata: name: demo-service spec: type: ClusterIP externalIPs: - 192.168.1.100 ports: - port: 80 --- # 通过域名访问 http://k8s.192.168.1.100.nip.io ``` *** > 项目地址:[GitHub - exentriquesolutions/nip.io](https://github.com/exentriquesolutions/nip.io) 更多技术细节可查阅项目Wiki文档 # 网络 ## 检查当前节点是否在境外 [Section titled “检查当前节点是否在境外”](#检查当前节点是否在境外) ```bash curl ipinfo.io ``` # headscale使用记录 [GitHub地址](https://github.com/juanfont/headscale) [参考文章](https://icloudnative.io/posts/how-to-set-up-or-migrate-headscale/#headscale-%E6%98%AF%E4%BB%80%E4%B9%88) ## 安装 [Section titled “安装”](#安装) [sealos一键部署](https://bja.sealos.run/?openapp=system-template%3FtemplateName%3Dheadscale) ```bash # 创建默认用户 headscale user create default # 查看用户列表 headscale user list # 创建 API Key: headscale apikey create # 将 Headscale 公网域名和 API Key 填入 Headscale-Admin 的设置页面(https://headscale-xxx.sealosbja.site/admin/),同时取消勾选 Legacy API,然后点击「Save」: # 接入成功后,点击左边侧栏的「Users」,然后点击「Create」开始创建用户: # 安装客户端 ## Linux curl -fsSL https://tailscale.com/install.sh | sh # Tailscale 接入 Headscale: # 将 换成上文提到的 Sealos 中的 Headscale 公网域名 tailscale up --login-server=https:// --accept-routes=true --accept-dns=false # 会打印出注册key(mkey:xxx), 需要到Headscale-Admin的[Machines]页面[Add Device][Register Machine Key],选择上面创建的用户并将注册key填入, 点击[Register]后, 客户端控制台会打印Success. # 回到 Tailscale 客户端所在的 Linux 主机,可以看到 Tailscale 会自动创建相关的路由表和 iptables 规则。路由表可通过以下命令查看: ip route show table 52 # 查看 iptables 规则: iptables -S iptables -S -t nat ## macOS # 安装完 GUI 版应用后还需要做一些骚操作,才能让 Tailscale 使用 Headscale 作为控制服务器。当然,Headscale 已经给我们提供了详细的操作步骤,你只需要在浏览器中打开 URL:https:///apple,便会出现如下的界面: # 长按「option」键,然后点击顶部菜单栏的 Tailscale 图标,然后将鼠标指针悬停在「Debug」菜单上。 # 在「Custom Login Server」下方选择「Add Account…」。 # 在打开的弹窗中填入 Headscale 的公网域名,然后点击「Add Account」。 # 然后立马就会跳转到浏览器并打开一个页面 # 接下来与之前 Linux 客户端相同,回到 Headscale 所在的机器执行浏览器中的命令即可,注册成功: # 回到 Headscale 所在主机,查看注册的节点: headscale nodes list # 回到 macOS,测试是否能 ping 通对端节点: ping -c 2 100.64.0.1 # 在[sitting]中安装[CLl integration]后, 也可以使用 Tailscale CLI 来测试: tailscale ping 100.64.0.1 ``` ### 通过 Pre-Authkeys 接入 [Section titled “通过 Pre-Authkeys 接入”](#通过-pre-authkeys-接入) ```bash # 前面的接入方法都需要服务端同意,步骤比较烦琐,其实还有更简单的方法,可以直接接入,不需要服务端同意。 # 首先在服务端生成 pre-authkey 的 token,有效期可以设置为 24 小时: headscale preauthkeys create -e 24h --user default # 查看已经生成的 key: headscale --user default preauthkeys list # 当然你也可以在 Headscale-Admin 中生成。点击客户端想加入的 User: # 在弹出的界面中点击「PreAuth Keys」右侧的 Create,设置一个过期时间(比如 100 年~),如果想重复利用这个 Key,可以勾选 Reusable,最后点击 ✅: # 创建成功后,点击红框区域便可复制该 PreAuth Key: # 现在新节点就可以无需服务端同意直接接入了: tailscale up --login-server=http://:8080 --accept-routes=true --accept-dns=false --authkey $KEY ``` ## 打通局域网 [Section titled “打通局域网”](#打通局域网) [参考文档](https://icloudnative.io/posts/how-to-set-up-or-migrate-headscale/#%E6%89%93%E9%80%9A%E5%B1%80%E5%9F%9F%E7%BD%91) ```bash # 配置方法很简单,首先需要设置 IPv4 与 IPv6 路由转发: echo 'net.ipv4.ip_forward = 1' | tee /etc/sysctl.d/ipforwarding.conf echo 'net.ipv6.conf.all.forwarding = 1' | tee -a /etc/sysctl.d/ipforwarding.conf sysctl -p /etc/sysctl.d/ipforwarding.conf # 客户端修改注册节点的命令,在原来命令的基础上加上参数 --advertise-routes=192.168.100.0/24,告诉 Headscale 服务器“我这个节点可以转发这些地址的路由”。 tailscale up --login-server=http://:8080 --accept-routes=true --accept-dns=false --advertise-routes=192.168.100.0/24 --reset # 在 Headscale 端查看路由,可以看到相关路由是关闭的。 headscale nodes list|grep openwrt headscale routes list -i 6 # 开启路由: headscale routes enable -i 6 -r "192.168.100.0/24" # 如果有多条路由需要用 , 隔开: headscale routes enable -i 6 -r "192.168.100.0/24,xxxx" # 也可以通过参数 -a 开启所有路由: headscale routes enable -i 6 -a # 其他节点查看路由结果: ip route show table 52|grep "192.168.100.0/24" # 其他节点启动时需要增加 --accept-routes=true 选项来声明 “我接受外部其他节点发布的路由”。 # 现在你在任何一个 Tailscale 客户端所在的节点都可以 ping 通家庭内网的机器了,你在公司或者星巴克也可以像在家里一样用同样的 IP 随意访问家中的任何一个设备,就问你香不香? ``` # headscale docker compose版使用记录 ```bash # 端口8888是服务端口(通过cpolar代理8888端口 -> https://5d37b78.r3.cpolar.top) # 在macos的tailscale客户端上使用headscale作为控制服务器(按option按钮, 点击tailscale图标, 选择debug->Custom Login Server->Add Account...->输入https://5d37b78.r3.cpolar.top-> 然后会自动打开浏览器-> 复制key-> 到服务端的服务器去->执行以下命令) docker exec -it headscale headscale user create USERNAME docker exec -it headscale headscale nodes register --user USERNAME --key qWrn3RY86bXG5BAcik7V7MoX ``` ```bash # linux客户端(可以在服务端那台电脑上使用, 用来连接服务端) docker exec -it headscale headscale user create fa.iuin docker exec -it headscale headscale preauthkeys create -e 24h --user fa.iuin # 将上面生成的key复制到下面的命令中 tailscale up --accept-dns=true --accept-routes --login-server=http://127.0.0.1:8888 --hostname=fa.iuin --force-reauth --authkey d69d58c009190358df704e7b3d867c1be0b022c038bc89be ``` ```bash # 查看节点 docker exec -it headscale headscale nodes list # 删除节点(通过ID) docker exec -it headscale headscale nodes delete --identifier 3 # 重命名节点(通过ID) docker exec -it headscale headscale nodes rename --identifier 4 hubeigongyinglian ``` ## 容器使用host模式 [Section titled “容器使用host模式”](#容器使用host模式) 端口冲突的话, 可以在config.yml中更换端口 # headscale使用记录 [参考文章](https://icloudnative.io/posts/how-to-set-up-or-migrate-headscale/#headscale-%E6%98%AF%E4%BB%80%E4%B9%88) ## 安装 [Section titled “安装”](#安装) [docker版](https://github.com/juanfont/headscale/blob/main/docs/setup/install/container.md) ```bash # server_url: http://127.0.0.1:8080 server_url: https://5d37b78.r3.cpolar.top # listen_addr: 127.0.0.1:8080 listen_addr: 0.0.0.0:8080 ``` ```bash # 安装 cd ./headscale docker run \ --name headscale \ --detach \ --volume $(pwd)/config:/etc/headscale/ \ --publish 127.0.0.1:8080:8080 \ --publish 127.0.0.1:9090:9090 \ headscale/headscale: \ serve # 或者使用docker-compose docker-compose up -d # 验证 curl http://127.0.0.1:9999/metrics # 创建apiKey docker exec -it headscale headscale apikey create # 将 Headscale 公网域名和 API Key 填入 Headscale-Admin 的设置页面(http://localhost:880/web/settings.html),同时取消勾选 Legacy API,然后点击「Save」: # 接入成功后,点击左边侧栏的「Users」,然后点击「Create」开始创建用户: # 安装客户端 ## Linux curl -fsSL https://tailscale.com/install.sh | sh # Tailscale 接入 Headscale: # 将 换成上文提到的 Sealos 中的 Headscale 公网域名 # tailscale up --accept-dns=false --accept-routes --login-server=https://3gmjh9nm-880.asse.devtunnels.ms --hostname=fa --accept-risk=true tailscale up --accept-dns=false --accept-routes --login-server=http://localhost:880 --hostname=fa # 会打印出注册key(mkey:xxx), 需要到Headscale-Admin的[Machines]页面[Add Device][Register Machine Key],选择上面创建的用户并将注册key填入, 点击[Register]后, 客户端控制台会打印Success. # PS: 如果提示字符不够就用空格替代补足(这应该是个bug) # 回到 Tailscale 客户端所在的 Linux 主机,可以看到 Tailscale 会自动创建相关的路由表和 iptables 规则。路由表可通过以下命令查看: ip route show table 52 # 查看 iptables 规则: iptables -S iptables -S -t nat ## macOS # 安装完 GUI 版应用后还需要做一些骚操作,才能让 Tailscale 使用 Headscale 作为控制服务器。当然,Headscale 已经给我们提供了详细的操作步骤,你只需要在浏览器中打开 URL:https:///apple,便会出现如下的界面: # 长按「option」键,然后点击顶部菜单栏的 Tailscale 图标,然后将鼠标指针悬停在「Debug」菜单上。 # 在「Custom Login Server」下方选择「Add Account…」。 # 在打开的弹窗中填入 Headscale 的公网域名,然后点击「Add Account」。 # 然后立马就会跳转到浏览器并打开一个页面 # 接下来与之前 Linux 客户端相同,回到 Headscale 所在的机器执行浏览器中的命令即可,注册成功: # 回到 Headscale 所在主机,查看注册的节点: headscale nodes list # 回到 macOS,测试是否能 ping 通对端节点: ping -c 2 100.64.0.1 # 在[sitting]中安装[CLl integration]后, 也可以使用 Tailscale CLI 来测试: tailscale ping 100.64.0.1 ``` ### 通过 Pre-Authkeys 接入 [Section titled “通过 Pre-Authkeys 接入”](#通过-pre-authkeys-接入) ```bash # 前面的接入方法都需要服务端同意,步骤比较烦琐,其实还有更简单的方法,可以直接接入,不需要服务端同意。 # 首先在服务端生成 pre-authkey 的 token,有效期可以设置为 24 小时: headscale preauthkeys create -e 24h --user default # 查看已经生成的 key: headscale --user default preauthkeys list # 当然你也可以在 Headscale-Admin 中生成。点击客户端想加入的 User: # 在弹出的界面中点击「PreAuth Keys」右侧的 Create,设置一个过期时间(比如 100 年~),如果想重复利用这个 Key,可以勾选 Reusable,最后点击 ✅: # 创建成功后,点击红框区域便可复制该 PreAuth Key: # 现在新节点就可以无需服务端同意直接接入了: tailscale up --login-server=http://:8080 --accept-routes=true --accept-dns=false --authkey $KEY ``` ## 打通局域网 [Section titled “打通局域网”](#打通局域网) [参考文档](https://icloudnative.io/posts/how-to-set-up-or-migrate-headscale/#%E6%89%93%E9%80%9A%E5%B1%80%E5%9F%9F%E7%BD%91) ```bash # 配置方法很简单,首先需要设置 IPv4 与 IPv6 路由转发: echo 'net.ipv4.ip_forward = 1' | tee /etc/sysctl.d/ipforwarding.conf echo 'net.ipv6.conf.all.forwarding = 1' | tee -a /etc/sysctl.d/ipforwarding.conf sysctl -p /etc/sysctl.d/ipforwarding.conf # 客户端修改注册节点的命令,在原来命令的基础上加上参数 --advertise-routes=192.168.100.0/24,告诉 Headscale 服务器“我这个节点可以转发这些地址的路由”。 tailscale up --login-server=http://:8080 --accept-routes=true --accept-dns=false --advertise-routes=192.168.100.0/24 --reset # 在 Headscale 端查看路由,可以看到相关路由是关闭的。 headscale nodes list|grep openwrt headscale routes list -i 6 # 开启路由: headscale routes enable -i 6 -r "192.168.100.0/24" # 如果有多条路由需要用 , 隔开: headscale routes enable -i 6 -r "192.168.100.0/24,xxxx" # 也可以通过参数 -a 开启所有路由: headscale routes enable -i 6 -a # 其他节点查看路由结果: ip route show table 52|grep "192.168.100.0/24" # 其他节点启动时需要增加 --accept-routes=true 选项来声明 “我接受外部其他节点发布的路由”。 # 现在你在任何一个 Tailscale 客户端所在的节点都可以 ping 通家庭内网的机器了,你在公司或者星巴克也可以像在家里一样用同样的 IP 随意访问家中的任何一个设备,就问你香不香? ``` # 节点小宝使用记录 [官网](https://www.iepose.com/) ```bash # 安装 ## docker # x86_64 docker run -d --net host --name owjdxb -v "$(pwd)/store:/data/store" --restart always ionewu/owjdxb # arm_64 # docker run -d --net host --name owjdxb -v "$(pwd)/store:/data/store" --restart always ionewu/owjdxb_a64 docker run -d --net host --name owjdxb -v "./temp/store:/data/store" --restart always ionewu/owjdxb_a64 ``` ```bash # 设备码绑定 # 启动容器后可在日志中查看6位设备码 # docker logs ionewu/owjdxb docker logs owjdxb ``` # gdy666/lucky使用记录 [GitHub地址](https://github.com/gdy666/lucky) # MiniUPnP工具使用记录 [github地址](https://github.com/miniupnp/miniupnp) ```bash # 安装 brew install miniupnpc # 验证 upnpc --version ``` ```bash # 基础使用示例 # 查看当前NAT类型: upnpc -s # - 输出中若显示`PortMappingEnabled: 1`表示UPnP已启用。 # 添加端口映射(如将内网5000端口映射到公网6000): upnpc -a 192.168.1.100 5000 6000 TCP # - `192.168.1.100`为本地设备IP,`TCP`可替换为`UDP`。 # 删除映射规则: upnpc -d 6000 TCP # 常见问题与解决 # 路由器兼容性:部分路由器需手动开启UPnP功能(如OpenWrt需安装miniupnpd软件包)5。 # 端口冲突:映射前通过upnpc -l检查端口占用情况。 # 扩展应用场景 # BitTorrent优化:结合qBittorrent等客户端,提升下载速度。 # 远程开发调试:映射SSH或Web服务端口至公网,实现远程访问。 # 游戏联机支持:解决NAT类型限制,改善联机体验(如Minecraft服务器搭建)。 # 若需高级功能(如持久化配置),可参考 [官方文档](https://github.com/miniupnp/miniupnp) 进一步配置。 ``` # 本地https使用记录 ```bash # 生成证书 mkcert -install mkcert xxx-9090.asse.devtunnels.ms ``` # 如何用 5 步实现本地 HTTPS 开发?mkcert + OpenResty 保姆级教程 > 本文将手把手教你用 mkcert 生成可信证书,结合 OpenResty 搭建本地 HTTPS 服务,5 步解决开发环境的安全焦虑!告别浏览器「不安全连接」警告,满足微信小程序和前端 API 的 HTTPS 要求。 ## 引言:告别「不安全」警告 [Section titled “引言:告别「不安全」警告”](#引言告别不安全警告) 在本地开发中,你是否遇到过这些困扰?浏览器频繁提示「不安全连接」,微信小程序强制要求 HTTPS 接口,甚至某些前端 API 只能在加密环境下调用。 本文将手把手教你用 mkcert 生成可信证书,结合 OpenResty 搭建本地 HTTPS 服务,5 步解决开发环境的安全焦虑! *** 一、工具准备:1 分钟搭建基础设施 1. 安装 mkcert * Windows 用户可直接下载 ,Mac/Linux 用户通过包管理器安装: ```bash brew install mkcert # Mac sudo apt install mkcert # Ubuntu ``` * 初始化本地 CA 根证书: ```bash mkcert -install ``` *(系统会自动将 CA 证书加入信任列表,从此告别红色警告)* 2. 安装 OpenResty\ 访问下载安装包,或通过命令安装: ```bash # Ubuntu 示例 wget -q https://openresty.org/package/pubkey.gpg sudo apt-key add pubkey.gpg sudo apt-get install openresty ``` *** 二、证书生成:2 行命令搞定 HTTPS 密钥 1. 生成域名证书\ 在项目目录执行(支持多域名/IP): ```bash mkcert localhost 127.0.0.1 ::1 yourdomain.com ``` *生成 `localhost+3.pem`(证书)和 `localhost+3-key.pem`(私钥)* 2. 证书存放建议\ 创建专属目录管理证书,例如: ```plaintext /usr/local/openresty/nginx/conf/ssl/ ├── localhost+3.pem └── localhost+3-key.pem ``` *** 三、OpenResty 配置:Nginx 的 HTTPS 魔法 编辑 `nginx.conf`,添加 HTTPS 服务块: ```nginx server { listen 443 ssl; server_name localhost; ssl_certificate /usr/local/openresty/nginx/conf/ssl/localhost+3.pem; ssl_certificate_key /usr/local/openresty/nginx/conf/ssl/localhost+3-key.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; location / { proxy_pass http://127.0.0.1:8080; # 转发到本地服务 proxy_set_header Host $host; } } HTTP 强制跳转 HTTPS(可选) server { listen 80; server_name localhost; return 301 https://$host$request_uri; } ``` -关键配置解读:\* * `ssl_certificate` 指向 mkcert 生成的证书 * `proxy_pass` 将 HTTPS 请求转发到本地 HTTP 服务 *** 四、服务验证:3 种方式测试 HTTPS 1. 浏览器访问\ 打开 `https://localhost`,地址栏显示 🔒安全 标识即成功(不再有警告!) 2. 命令行校验 ```bash curl -vIk https://localhost # 查看输出中的 SSL 握手信息 ``` 3. 证书详情检查\ Chrome 浏览器 → 点击锁图标 → 查看证书 → 颁发者显示 「mkcert」 即正确 *** 五、进阶技巧:开发效率翻倍的秘诀 1. 多域名/端口支持\ 生成证书时追加域名: ```bash mkcert "*.test.com" app.test.com 192.168.1.100 ``` Nginx 配置中通过 `server_name` 区分不同服务 2. 局域网 HTTPS 测试\ 生成含内网 IP 的证书: ```bash mkcert 192.168.1.100 ``` 手机扫码安装 CA 证书后,即可用 HTTPS 访问开发机 3. 证书自动更新(高阶)\ 结合 `lua-resty-auto-ssl` 实现证书自动签发: ```lua lua_shared_dict auto_ssl 1m; init_by_lua_block { auto_ssl = require "resty.auto-ssl" auto_ssl.setup({ storage_dir = "/path/to/storage" }) } ``` *适合需要动态管理数百个域名的场景* *** 常见问题排查表 | 现象 | 解决方案 | | ----------- | ------------------------ | | 浏览器提示证书无效 | 检查是否执行 `mkcert -install` | | Nginx 启动报错 | 确认证书路径权限为 755 | | 无法访问 443 端口 | 关闭防火墙或放行端口 | *** 结语:让本地开发更专业\ 通过 mkcert + OpenResty 的组合,我们不仅解决了 HTTPS 的配置难题,更为团队协作、接口调试提供了标准化环境。现在,你可以自信地说:“我的本地服务,和线上一样安全!” -本文部分方案参考自,更多技术细节可访问原文链接。\*\ 👉 转发给正在为 HTTPS 头疼的伙伴,一起告别「不安全」! # netmaker使用记录 [官网安装地址](https://www.netmaker.io/download) ```bash # 使用docker安装服务端(./docker-compose.yml) ``` # openP2P 文档 [openP2P 安装文档](https://console.openp2p.cn/install) ## 使用systemd服务 [Section titled “使用systemd服务”](#使用systemd服务) ```bash # 创建docker-compose.yml文件 sudo nano /etc/openp2p/docker-compose.yml # 写入以下内容 services: openp2p: image: openp2pcn/openp2p-client:3.24.35 container_name: openp2p-client restart: always network_mode: host privileged: true cap_add: - NET_ADMIN devices: - /dev/net/tun:/dev/net/tun environment: - OPENP2P_TOKEN=xxx ``` ```bash # 创建服务文件 sudo nano /etc/systemd/system/openp2p.service # 写入以下内容 # 确保iptables规则存在(PS: 使用iptables -C检查规则是否已存在, 仅在规则不存在时才添加,避免重复添加导致错误) [Unit] Description=OpenP2P Client Service After=docker.service Requires=docker.service [Service] Type=oneshot RemainAfterExit=yes ExecStartPre=/bin/sleep 10 ExecStart=/bin/bash -c 'docker compose -f /etc/openp2p/docker-compose.yml up -d' ExecStartPost=/bin/bash -c 'echo 1 > /proc/sys/net/ipv4/ip_forward' ExecStartPost=/bin/bash -c 'iptables -t filter -C FORWARD -i optun -j ACCEPT 2>/dev/null || iptables -t filter -I FORWARD -i optun -j ACCEPT' ExecStartPost=/bin/bash -c 'iptables -t filter -C FORWARD -o optun -j ACCEPT 2>/dev/null || iptables -t filter -I FORWARD -o optun -j ACCEPT' [Install] WantedBy=multi-user.target # 启用并启动服务 sudo systemctl daemon-reload sudo systemctl enable openp2p.service sudo systemctl start openp2p.service # 检查服务状态 sudo systemctl status openp2p.service ``` ## 额外建议:环境变量配置 [Section titled “额外建议:环境变量配置”](#额外建议环境变量配置) 为了确保$OPENP2P\_TOKEN环境变量在系统启动时可用,建议将其添加到/etc/environment: ```bash # 运行以下命令添加环境变量 echo "OPENP2P_TOKEN=xxx" | sudo tee -a /etc/environment ``` # 蒲公英vpn [官网](https://pgy.oray.com) ```bash # 镜像拉取 docker pull crpi-orhk6a4lutw1gb13.cn-hangzhou.personal.cr.aliyuncs.com/bestoray/pgyvpn # 启动容器 docker run -d --device=/dev/net/tun --net=host --cap-add=NET_ADMIN --env PGY_USERNAME="xxx" --env PGY_PASSWORD="xxx" crpi-orhk6a4lutw1gb13.cn-hangzhou.personal.cr.aliyuncs.com/bestoray/pgyvpn #二、使用说明 # 1、启动容器必须加字段 “--cap-add=NET_ADMIN” ,否则会导致虚拟网卡创建失败,从而导致组网无法正常通信 # 2、USERNAME 选项支持输入“贝锐账号 ”或”UID“ # 3、支持配合docker的-v参数使用容器卷功能 # 4、镜像中已默认安装ping、ifconfig等网络调试工具,方便用户使用 # 5、日志路径:/var/log/oray # 6、配置路径:/etc/oray/pgyvpn ``` # 网络相关开源项目列表 ## linker [Section titled “linker”](#linker) [linker](https://github.com/snltty/linker) ## goodlink [Section titled “goodlink”](#goodlink) [goodlink](https://gitee.com/konyshe/goodlink) ## ddnsto [Section titled “ddnsto”](#ddnsto) [ddnsto](https://www.ddnsto.com/) # stun使用记录 ```bash docker run -it -p 54320:54320 python:3.9 bash apt-get update && apt-get install -y stun-client stun stun.l.google.com -p 54320 ``` ```bash docker run -it --net host python:3.9 bash docker run -it --network host python:3.9 bash ``` # WireGuard使用记录 [官网安装地址](https://www.wireguard.com/install/) macos安装 ```bash brew install wireguard-tools ``` centos安装 ```bash # 方法一 yum install yum-utils epel-release yum-config-manager --setopt=centosplus.includepkgs=kernel-plus --enablerepo=centosplus --save sed -e 's/^DEFAULTKERNEL=kernel$/DEFAULTKERNEL=kernel-plus/' -i /etc/sysconfig/kernel yum install kernel-plus wireguard-tools reboot # 方法二 sudo yum install epel-release elrepo-release sudo yum install yum-plugin-elrepo sudo yum install kmod-wireguard wireguard-tools ``` # 系统相关记录 ## 一键重装系统 [Section titled “一键重装系统”](#一键重装系统) [GitHub地址](https://github.com/bin456789/reinstall) ```bash # 下载脚本 curl -O https://cnb.cool/bin456789/reinstall/-/git/raw/main/reinstall.sh || wget -O reinstall.sh $_ # 重装系统 bash reinstall.sh ubuntu # 重启 reboot ``` > PS: 重启过程中, 可能需要手动选择reinstall.sh的启动项才能正常启动重装进程, 不然, 可能会通过默认启动项进入旧系统中 # ImmortalWrt使用记录 [macos-m1-utm](https://downloads.immortalwrt.org/releases/24.10.4/targets/armsr/armv8/immortalwrt-24.10.4-armsr-armv8-generic-ext4-combined-efi.img.gz) ## 安装virt-viewer [Section titled “安装virt-viewer”](#安装virt-viewer) UTM使用`SPICE`共享剪切板 ```bash # 安装virt-viewer opkg install virt-viewer # virt-viewer 连接到 UTM 虚拟机 # virt-viewer -c spice://127.0.0.1:5900 virt-viewer spice://192.168.1.100:5900 # virt-viewer没有的话, 可以使用tidy-viewer brew install tidy-viewer # 连接到 UTM 虚拟机 tidy-viewer -c spice://192.168.1.100:5900 ``` ## 网络配置 [Section titled “网络配置”](#网络配置) ```bash # 编辑网络配置文件 vi /etc/config/network ``` ```bash # 修改 LAN 接口设置 config interface 'lan'​ option type 'bridge'​ option ifname 'eth0'​ option proto 'static'​ option ipaddr '192.168.5.1' # 修改为适合你的网段​ option netmask '255.255.255.0'​ option gateway '192.168.5.254' # 设置网关​ option dns '8.8.8.8 8.8.4.4' # 设置DNS ``` ```bash # 重启服务 /etc/init.d/network restart ``` ## 安装Argon主题 [Section titled “安装Argon主题”](#安装argon主题) ```bash # 更新软件包列表 opkg update # 安装Argon主题 opkg install luci-theme-argon ``` ## 安装基础磁盘管理 [Section titled “安装基础磁盘管理”](#安装基础磁盘管理) ```bash # 安装基础磁盘管理工具 # opkg install block-mount kmod-fs-ext4 opkg install block-mount # 重启Web服务 /etc/init.d/uhttpd restart ``` ## 安装高级磁盘管理 Web 界面 [Section titled “安装高级磁盘管理 Web 界面”](#安装高级磁盘管理-web-界面) ```bash # 安装DiskMan及其依赖 opkg install luci-app-diskman # 安装必要的依赖包 opkg install parted blkid e2fsprogs btrfs-progs smartmontools # 重启Web服务 /etc/init.d/uhttpd restart # 要是有问题Failed to connect to ubus # 安装 uhttpd-mod-ubus 模块 opkg install uhttpd-mod-ubus # 重启 uhttpd /etc/init.d/uhttpd restart # 再不行重启就好了 ``` ## 扩展根分区 [Section titled “扩展根分区”](#扩展根分区) 在页面上操作吧\[系统->挂载点], 不用下面的命令了 ```bash # 查看所有磁盘设备 lsblk # 或者查看详细的磁盘信息 fdisk -l # 或者查看详细的磁盘信息 fdisk -l /dev/vda # 安装分区工具​ opkg install parted resize2fs​ opkg install losetup # 找到根文件系统的实际设备 # 查找或创建循环设备 LOOP_DEV=$(losetup -f) losetup "$LOOP_DEV" /dev/vda2 # 强制扩展文件系统 resize2fs -f "$LOOP_DEV" # 验证结果 df -h # 查看文件系统详细信息 tune2fs -l /dev/vda2 # 重启系统 reboot # 查看当前分区情况 parted /dev/vda print ​ # 扩展分区(假设根分区是第2个分区) parted /dev/vda resizepart 2 100% # 扩展文件系统 resize2fs /dev/vda2 resize2fs /dev/root # 验证扩展 df -h ``` ```bash # 优化系统性能 # 清理临时文件 rm -rf /tmp/* # 清理opkg缓存 rm -rf /var/cache/opkg/* # 要是下次update有lock文件不存在的问题 mkdir -p /var/lock # 清理日志文件 rm -rf /var/log/* # 优化文件系统 e2fsck -f /dev/vda2 resize2fs -f /dev/vda2 ``` ## 优化系统 [Section titled “优化系统”](#优化系统) ```bash # 问题 1:无法运行 e2fsck 检查 # 配置启动时自动检查(推荐) # 设置文件系统检查标志 tune2fs -c 1 /dev/vda2 # 重启系统,系统会在启动时自动检查 reboot # 优化ext4文件系统 tune2fs -o journal_data_writeback /dev/vda2 tune2fs -m 1 /dev/vda2 # 设置预留空间为1% # 监控磁盘健康状态 # 安装smartmontools opkg install smartmontools # 检查磁盘健康状态 smartctl -H /dev/vda ``` ## 安装 e2fsprogs 包来获取 tune2fs 工具 [Section titled “安装 e2fsprogs 包来获取 tune2fs 工具”](#安装-e2fsprogs-包来获取-tune2fs-工具) ```bash # 安装 e2fsprogs 包(包含 tune2fs) opkg install e2fsprogs # 验证安装 tune2fs --version # 如果 e2fsprogs 不可用 # 安装 parted 工具(替代方案) opkg install parted # 使用 parted 查看磁盘信息 parted -l /dev/vda ``` ## 访问 [Section titled “访问”](#访问) * 浏览器访问 `http://192.168.5.1`(或你设置的IP) * 登录用户名:`root`,密码:`password`(默认) ## 配置成旁路由 [Section titled “配置成旁路由”](#配置成旁路由) \[网络-接口-lan-DHCP服务器-忽略此接口]打勾-保存-保存并应用 将自己电脑的网关改成ImmortalWRT的IP(客户端将wifi/有线网络的网关设置成ImmortalWRT的IP地址即可) > 不想手动修改网关的话,可以直接把主路由器的dhcp功能关闭,这样ImmortalWRT的dhcp就会介入分配局域网IP,只要连上主路由的设备都会自动将ImmortalWRT设为网关,但是这样的前提是mbp要24小时都开机 添加科学上网功能 搜索`openclash`,点击安装`luci-app-openclash` ## 让指定设备走旁路由 [Section titled “让指定设备走旁路由”](#让指定设备走旁路由) ```bash # 安装必要工具 opkg install nmap arping iputils-ping dnsmasq iptables ``` ```bash # 创建 IP 地址监控脚本 cat > /root/monitor-ip.sh << 'EOF' #!/bin/bash # 日志配置 LOG_FILE="/var/log/network-manager.log" # 日志函数 log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG_FILE echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" } mkdir -p /etc/dnsmasq.d # 配置文件路径 DHCP_CONF="/etc/dnsmasq.d/dynamic-dhcp.conf" ARP_SCRIPT="/root/start-spoof.sh" IP_FILE="/tmp/current_ip.txt" # 获取当前IP地址 get_current_ip() { ip addr show br-lan | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1 } # 初始化IP文件 current_ip=$(get_current_ip) echo $current_ip > $IP_FILE log "初始IP地址: $current_ip" log "启动IP监控服务..." while true; do new_ip=$(get_current_ip) old_ip=$(cat $IP_FILE) if [ "$new_ip" != "$old_ip" ] && [ -n "$new_ip" ]; then log "检测到IP地址变化: $old_ip -> $new_ip" # 更新IP文件 echo $new_ip > $IP_FILE # 更新DHCP配置 sed -i "s/dhcp-option=3,$old_ip/dhcp-option=3,$new_ip/g" $DHCP_CONF sed -i "s/dhcp-option=6,$old_ip/dhcp-option=6,$new_ip/g" $DHCP_CONF # 更新ARP欺骗脚本 sed -i "s/PROXY_IP=\"$old_ip\"/PROXY_IP=\"$new_ip\"/g" $ARP_SCRIPT # 重启相关服务 /etc/init.d/dnsmasq restart /root/restart-spoof.sh log "IP地址已更新为: $new_ip" fi sleep 30 # 每30秒检查一次 done EOF chmod +x /root/monitor-ip.sh ``` ```bash # 创建智能 IP 扫描脚本 cat > /root/scan-network.sh << 'EOF' #!/bin/bash # 日志配置 LOG_FILE="/var/log/network-manager.log" # 日志函数 log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG_FILE echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" } # 网络配置 # 获取完整的IP/CIDR IP_CIDR=$(ip addr show $(ip route show default | awk '{print $5}') | grep 'inet ' | awk '{print $2}') # 拆分IP和CIDR IP=$(echo $IP_CIDR | cut -d'/' -f1) CIDR=$(echo $IP_CIDR | cut -d'/' -f2) # 获取IP前缀 IP_PREFIX=$(echo $IP | cut -d '.' -f 1-3)'.' # 替换最后一位为0 NETWORK=$(echo $IP | awk -F. '{print $1"."$2"."$3".0/"CIDR}') PROXY_IP=$(cat /tmp/current_ip.txt) GATEWAY=$(ip route show default | awk '{print $3}') touch /tmp/used_ips.txt mkdir -p /etc/dnsmasq.d # 扫描结果文件 SCAN_RESULT="/tmp/network_scan.txt" USED_IPS="/tmp/used_ips.txt" AVAILABLE_IPS="/tmp/available_ips.txt" # 清理旧文件 rm -f $SCAN_RESULT $USED_IPS $AVAILABLE_IPS log "开始扫描网络: $NETWORK" # 1. 使用nmap扫描活跃主机 nmap -sn $NETWORK -oG $SCAN_RESULT > /dev/null 2>&1 # 2. 从扫描结果中提取IP地址 grep "Up$" $SCAN_RESULT | awk '{print $2}' > $USED_IPS # 3. 添加已知的重要IP echo $GATEWAY >> $USED_IPS echo $PROXY_IP >> $USED_IPS # 4. 去重并排序 sort -u $USED_IPS -o $USED_IPS # 5. 生成可用IP范围($IP_PREFIX100-$IP_PREFIX250) for ip in $(seq 100 250); do current_ip="$IP_PREFIX$ip" if ! grep -q "$current_ip" $USED_IPS; then echo $current_ip >> $AVAILABLE_IPS fi done # 6. 显示结果 log "扫描完成:" log "已使用IP数量: $(wc -l < $USED_IPS)" log "可用IP数量: $(wc -l < $AVAILABLE_IPS)" # 7. 更新DHCP配置 if [ -s $AVAILABLE_IPS ]; then first_ip=$(head -n1 $AVAILABLE_IPS) last_ip=$(tail -n1 $AVAILABLE_IPS) log "更新DHCP范围: $first_ip - $last_ip" # 更新DHCP配置 - 添加手机MAC地址 cat > /etc/dnsmasq.d/dynamic-dhcp.conf << DHCP_EOF interface=br-lan bind-interfaces dhcp-range=$first_ip,$last_ip,255.255.252.0,1h dhcp-option=3,$PROXY_IP dhcp-option=6,$PROXY_IP dhcp-authoritative # 手机配置(固定IP) dhcp-host=d4:a3:65:89:69:9c,10.0.4.124,MyPhone DHCP_EOF # 重启DHCP服务 /etc/init.d/dnsmasq restart log "DHCP服务已重启" else log "警告: 没有可用IP地址!" fi log "智能IP管理完成" EOF chmod +x /root/scan-network.sh ``` ```bash # 创建 ARP 监控脚本 cat > /root/monitor-arp.sh << 'EOF' #!/bin/bash # 日志配置 LOG_FILE="/var/log/network-manager.log" # 日志函数 log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG_FILE echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" } # 监控间隔(秒) INTERVAL=60 # 临时文件 ARP_CACHE="/tmp/arp_cache.txt" NEW_DEVICES="/tmp/new_devices.txt" log "启动ARP监控服务..." while true; do # 获取当前ARP缓存 ip neigh show | awk '/^10\.0\.4\./ {print $1" "$3}' > $ARP_CACHE # 检查新设备 if [ -f /tmp/previous_arp.txt ]; then grep -Fxvf /tmp/previous_arp.txt $ARP_CACHE > $NEW_DEVICES if [ -s $NEW_DEVICES ]; then log "发现新设备:" cat $NEW_DEVICES | while read line; do log " $line" done # 触发IP扫描更新 log "触发网络扫描更新" /root/scan-network.sh fi fi # 保存当前ARP缓存用于下次比较 cp $ARP_CACHE /tmp/previous_arp.txt sleep $INTERVAL done EOF chmod +x /root/monitor-arp.sh ``` ```bash # 创建 IP 冲突检测脚本 cat > /root/check-conflict.sh << 'EOF' #!/bin/bash # 日志配置 LOG_FILE="/var/log/network-manager.log" # 日志函数 log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG_FILE echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" } # 检查IP冲突 check_ip() { local ip=$1 arping -c 1 -w 1 $ip > /dev/null 2>&1 return $? } # 检查DHCP分配的IP check_dhcp_leases() { LEASES_FILE="/var/lib/misc/dnsmasq.leases" if [ -f $LEASES_FILE ]; then while read lease; do ip=$(echo $lease | awk '{print $3}') mac=$(echo $lease | awk '{print $2}') hostname=$(echo $lease | awk '{print $4}') if check_ip $ip; then # 发现冲突,释放该IP log "发现IP冲突: $ip (MAC: $mac, 主机名: $hostname)" # 可以在这里实现自动释放和重新分配 fi done < $LEASES_FILE fi } # 主程序 log "检查IP冲突..." check_dhcp_leases log "冲突检查完成" EOF chmod +x /root/check-conflict.sh ``` ```bash # 设置定时任务 # 使用 sleep 循环脚本 cat > /root/start-monitors.sh << 'EOF' #!/bin/bash # 日志配置 LOG_FILE="/var/log/network-manager.log" # 日志函数 log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG_FILE echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" } log "启动监控服务主程序..." # 初始扫描 log "执行初始网络扫描" /root/scan-network.sh # 主循环 while true; do # 每小时执行一次网络扫描 log "执行定时网络扫描" /root/scan-network.sh # 每10分钟检查一次IP冲突 for i in {1..6}; do log "检查IP冲突" /root/check-conflict.sh sleep 600 # 10分钟 done done EOF chmod +x /root/start-monitors.sh ``` ```bash # 添加 ARP 欺骗脚本 cat > /root/start-spoof.sh << 'EOF' #!/bin/bash # 日志配置 LOG_FILE="/var/log/network-manager.log" # 日志函数 log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG_FILE echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" } # 网络配置 INTERFACE="br-lan" GATEWAY=$(ip route show default | awk '{print $3}') PROXY_IP=$(cat /tmp/current_ip.txt) TARGET_IPS="10.0.4.124" # 手机IP log "启动ARP欺骗服务..." log "接口: $INTERFACE" log "网关: $GATEWAY" log "旁路由IP: $PROXY_IP" log "目标设备: $TARGET_IPS" # 启动ARP欺骗 for ip in $TARGET_IPS; do arpspoof -i $INTERFACE -t $ip $GATEWAY & arpspoof -i $INTERFACE -t $GATEWAY $ip & log " 欺骗设备: $ip" done log "ARP欺骗服务已启动" EOF chmod +x /root/start-spoof.sh cat > /root/restart-spoof.sh << 'EOF' #!/bin/bash # 日志配置 LOG_FILE="/var/log/network-manager.log" # 日志函数 log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG_FILE echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" } # 停止现有ARP欺骗进程 killall arpspoof 2>/dev/null log "停止现有ARP欺骗进程" # 获取当前配置 PROXY_IP=$(cat /tmp/current_ip.txt) GATEWAY=$(ip route show default | awk '{print $3}') INTERFACE="br-lan" TARGET_IPS="10.0.4.124" # 手机IP log "重启ARP欺骗服务..." log "当前IP: $PROXY_IP" log "网关: $GATEWAY" # 启动新的ARP欺骗进程 for ip in $TARGET_IPS; do arpspoof -i $INTERFACE -t $ip $GATEWAY & arpspoof -i $INTERFACE -t $GATEWAY $ip & log " 欺骗设备: $ip" done log "ARP欺骗服务已重启" EOF chmod +x /root/restart-spoof.sh ``` ```bash # 启用 IP 转发 echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf sysctl -p ``` ```bash # 配置防火墙 # 允许IP转发 # 配置防火墙转发 uci set firewall.@zone[0].forward=ACCEPT uci set firewall.@zone[0].masq=1 uci commit firewall /etc/init.d/firewall restart ``` ```bash # 添加 NAT 规则 # 创建NAT规则配置文件 cat > /etc/nftables.d/nat-rules.nft << 'EOF' table ip nat { chain postrouting { type nat hook postrouting priority 100; policy accept; oifname "br-lan" masquerade; } } EOF # 应用配置 nft -f /etc/nftables.d/nat-rules.nft /etc/init.d/firewall restart ``` ```bash # 设置开机自启 cat > /etc/rc.local << 'EOF' #!/bin/sh -e # 等待网络就绪 sleep 10 # 启动IP地址监控服务 /root/monitor-ip.sh & # 启动网络扫描 /root/scan-network.sh & # 启动ARP欺骗服务 /root/start-spoof.sh & # 启动ARP监控 /root/monitor-arp.sh & # 启动IP冲突检测 /root/start-monitors.sh & # 应用NAT规则 nft -f /etc/nftables.d/nat-rules.nft exit 0 EOF chmod +x /etc/rc.local ``` ```bash cat > /root/start-all.sh << 'EOF' #!/bin/bash echo "启动智能网络服务..." # 启动IP监控 /root/monitor-ip.sh & # 启动网络扫描 /root/scan-network.sh & # 启动ARP监控 /root/monitor-arp.sh & echo "所有服务已启动" echo "当前IP: $(cat /tmp/current_ip.txt)" EOF chmod +x /root/start-all.sh ``` ```bash # 创建日志文件 touch /var/log/network-manager.log chmod 666 /var/log/network-manager.log ``` ```bash # 检查IP转发是否启用 sysctl net.ipv4.ip_forward # 检查nftables规则 nft list ruleset # 检查防火墙状态 /etc/init.d/firewall status # 检查NAT规则是否生效 nft list table ip nat # 测试网络连接 ping -c 3 8.8.8.8 # 检查防火墙状态 /etc/init.d/firewall status # 测试旁路由功能 # 检查所有服务是否正常运行 ps | grep -E 'monitor-ip|scan-network|arpspoof|dnsmasq' # 查看DHCP租约 cat /var/lib/misc/dnsmasq.leases # 查看ARP表 arp -a # 查看日志 tail -f /var/log/network-manager.log ``` ```bash # 日志查看方法 # 实时查看日志 tail -f /var/log/network-manager.log # 查看特定服务日志 grep "IP监控" /var/log/network-manager.log grep "ARP欺骗" /var/log/network-manager.log grep "DHCP" /var/log/network-manager.log ``` ```bash # 测试和验证 # 手动运行测试 /root/scan-network.sh /root/start-spoof.sh # 查看状态 ps | grep -E 'monitor-ip|scan-network|arpspoof' cat /tmp/network_config.txt cat /etc/dnsmasq.d/dynamic-dhcp.conf ``` ## 其他 [Section titled “其他”](#其他) ```bash # 可以看到IP和网关 # 执行以下命令,直接查看当前路由表的默认网关 ip route show default ``` ## 问题 [Section titled “问题”](#问题) 如果lan口获取失败 \[服务-OpenClash-插件设置-流量控制-LAN 接口名称]选择系统可用的lan接口, 比如`eth0`或者`br-lan` # 配置 wifi ```bash # 检查是否安装了 wpad 或 hostapd opkg list-installed | grep -E 'wpad|hostapd' ``` ## 配置软件源并安装 wpad-full [Section titled “配置软件源并安装 wpad-full”](#配置软件源并安装-wpad-full) ```bash # 备份当前软件源配置 cp /etc/opkg/distfeeds.conf /etc/opkg/distfeeds.conf.backup # 配置ImmortalWrt国内镜像源 cat > /etc/opkg/distfeeds.conf << "EOF" src/gz immortalwrt_core https://mirrors.ustc.edu.cn/immortalwrt/releases/23.05.4/packages/x86_64/core src/gz immortalwrt_base https://mirrors.ustc.edu.cn/immortalwrt/releases/23.05.4/packages/x86_64/base src/gz immortalwrt_luci https://mirrors.ustc.edu.cn/immortalwrt/releases/23.05.4/packages/x86_64/luci src/gz immortalwrt_packages https://mirrors.ustc.edu.cn/immortalwrt/releases/23.05.4/packages/x86_64/packages src/gz immortalwrt_routing https://mirrors.ustc.edu.cn/immortalwrt/releases/23.05.4/packages/x86_64/routing src/gz immortalwrt_telephony https://mirrors.ustc.edu.cn/immortalwrt/releases/23.05.4/packages/x86_64/telephony EOF # 更新软件包列表 opkg update # 查看可用的wpad版本 opkg list | grep wpad # 安装完整版本的wpad opkg install wpad-full ## 如果 wpad-full 不可用,可以尝试安装其他完整版本: # 或者安装wpad-openssl(推荐) opkg install wpad-openssl # 或者安装wpad-mbedtls(占用空间更小) opkg install wpad-mbedtls # 验证安装 opkg list-installed | grep wpad ``` ```bash # 配置 WiFi 热点 vi /etc/config/wireless # 添加或修改以下内容: config wifi-device 'radio0' option type 'mac80211' option channel '11' option hwmode '11g' option path 'platform/qca953x_wmac' option htmode 'HT20' option disabled '0' config wifi-iface 'default_radio0' option device 'radio0' option network 'lan' option mode 'ap' option ssid 'ImmortalWrt' option encryption 'psk2' option key 'password' # 重启网络服务 /etc/init.d/network restart # 或者直接重启wpad服务 /etc/init.d/wpad restart # 或者使用wifi命令(如果可用) wifi reload # 确保dnsmasq已启用 /etc/init.d/dnsmasq enable /etc/init.d/dnsmasq restart # 若WiFi命令未找到 # 安装wireless-tools(包含iwconfig、iwlist等工具) opkg install wireless-tools # 安装hostapd(无线接入点管理工具) opkg install hostapd # 安装iwinfo(无线信息工具) opkg install iwinfo # 安装iw(现代无线配置工具) opkg install iw # 安装wpad-openssl(完整功能的无线管理) opkg install wpad-openssl # 检查无线服务状态 # 查看wpad服务状态 /etc/init.d/wpad status # 查看hostapd进程 ps | grep hostapd # 查看无线接口状态 iw dev wlan0 link # 安装必要的无线驱动和内核模块 # 更新软件包列表 opkg update # 安装无线驱动和内核模块 opkg install kmod-mac80211 kmod-cfg80211 kmod-ath9k kmod-ath9k-common # 安装完整的hostapd版本 opkg install hostapd-utils # 重启网络服务 /etc/init.d/network restart # 检查内核模块是否加载 lsmod | grep 80211 # 检查无线设备 iwconfig # 如果iwconfig也没有输出,检查网络接口 ifconfig -a ``` ```bash # 确保网络接口配置正确: vi /etc/config/network # 配置 LAN 接口: config interface 'lan' option type 'bridge' option ifname 'eth0 wlan0' option proto 'static' option ipaddr '192.168.1.1' option netmask '255.255.255.0' option gateway '宿主机IP或主路由IP' option dns '8.8.8.8 8.8.4.4' # 示例配置 config interface 'loopback'​ option device 'lo'​ option proto 'static'​ option ipaddr '127.0.0.1'​ option netmask '255.0.0.0'​ ​ config globals 'globals'​ option ula_prefix 'fdff:2c52:622b::/48'​ option packet_steering '1'​ ​ config device​ option name 'br-lan'​ option type 'bridge'​ list ports 'eth0'​ list ports 'wlan0'​ ​ config interface 'lan'​ option device 'br-lan'​ option proto 'static'​ option ipaddr '192.168.1.1'​ option netmask '255.255.255.0'​ option gateway '192.168.1.254'​ option dns '8.8.8.8 8.8.4.4' # 重启网络服务: /etc/init.d/network restart # 确保 DHCP 服务已启用: vi /etc/config/dhcp # 配置 DHCP: config dhcp 'lan' option interface 'lan' option start '100' option limit '150' option leasetime '12h' option dhcpv6 'server' option ra 'server' # 重启 DHCP 服务: /etc/init.d/dnsmasq restart # 确保防火墙允许 WiFi 热点流量: vi /etc/config/firewall # 修改防火墙配置: config zone option name 'lan' option input 'ACCEPT' option output 'ACCEPT' option forward 'ACCEPT' option network 'lan wlan' # 重启防火墙: /etc/init.d/firewall restart ``` ```bash # 激活无线设备 uci set wireless.radio0.disabled='0' uci commit wireless wifi reload opkg update opkg install hostapd dnsmasq wireless-tools wpa-supplicant # 检查无线设备状态 iw dev iwconfig # 确保无线接口已启用 uci set wireless.@wifi-iface[0].disabled='0' uci commit wireless wifi reload # 检查无线接口状态 iw dev wlan0 link iwlist wlan0 scanning # 在ImmortalWrt中安装USB相关软件包 opkg update opkg install usbutils kmod-usb-core kmod-usb-ohci kmod-usb-uhci kmod-usb2 # 在 ImmortalWrt 中安装驱动 # 更新软件包列表 opkg update # 安装USB无线网卡驱动(根据你的网卡芯片选择) # 对于Realtek芯片 opkg install kmod-rtl8192cu kmod-rtl8192ce kmod-rtl8192de kmod-rtl8188eu # 对于Atheros芯片 opkg install kmod-ath9k-htc # 安装无线管理工具 opkg install wireless-tools wpa-supplicant hostapd ``` ```bash # 更新软件包列表 opkg update # 安装核心无线软件包 opkg install iw iwinfo wireless-tools wifi-scripts # 安装无线驱动框架 opkg install kmod-cfg80211 kmod-mac80211 # 安装无线AP支持(wpad包含hostapd和wpa-supplicant) opkg install wpad-openssl # 安装可能需要的其他包 opkg install libnl-tiny ``` ```bash # 加载cfg80211和mac80211模块 modprobe cfg80211 modprobe mac80211 # 检查模块是否加载 lsmod | grep cfg80211 lsmod | grep mac80211 ``` ```bash # 如果 WiFi 热点仍不可见 # 检查频道设置 uci set wireless.radio0.channel='auto' uci commit wireless wifi reload # 检查国家代码 uci set wireless.radio0.country='CN' uci commit wireless wifi reload ``` ## 故障排除 [Section titled “故障排除”](#故障排除) ```bash # 如果遇到问题,可以尝试以下命令进行排查: # 查看无线状态 wifi status # 查看系统日志 logread | grep hostapd logread | grep wpad # 重启无线服务 wifi down wifi up # 查看网络接口 ifconfig iwconfig # 验证 WiFi 热点 # 现在你应该可以在其他设备上看到名为 "MyImmortalWrt" 的 WiFi 热点了。连接它并测试网络连接。 ``` ## 宿主机查找虚拟机IP地址 [Section titled “宿主机查找虚拟机IP地址”](#宿主机查找虚拟机ip地址) ```bash arp -a # 或者 nmap -sn 192.168.1.0/24 ``` # ip相关 ## 固定IP [Section titled “固定IP”](#固定ip) ```bash # 查看网络接口 ip a # 查看Netplan配置 netplan get # 编辑 Netplan 配置文件 sudo nano /etc/netplan/01-netcfg.yaml # (文件名可能不同,如 00-installer-config.yaml) # 配置静态 IP ``` ```yaml network: version: 2 renderer: networkd # 或 NetworkManager(如果使用GUI) ethernets: ens33: # 替换为您的网卡名称 dhcp4: no # 禁用DHCP addresses: - 192.168.1.100/24 # 静态IP和子网掩码 routes: - to: default via: 192.168.1.1 # ← 新的网关配置 nameservers: addresses: - 8.8.8.8 - 8.8.4.4 # DNS服务器 ``` ```bash # 应用配置 sudo netplan apply # 验证配置 ip route show default ``` # Linux系统文档 ```bash # 获取系统IP hostname -I | cut -f1 -d' ' # 关机 # sshpass -p root ssh -o "StrictHostKeyChecking=no" root@$(hostname -I | cut -f1 -d' ') "sudo poweroff" sshpass -p root ssh -o StrictHostKeyChecking=no root@10.0.16.16 sudo poweroff ``` ## yum命令 [Section titled “yum命令”](#yum命令) * 切换yum源 [参考](https://developer.aliyun.com/article/675241) ```bash # 备份旧源 mv CentOS-Base.repo CentOS-Base.repo.v2.bak # 添加新源(阿里镜像源) wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo ``` ## locale 配置 [Section titled “locale 配置”](#locale-配置) ```bash # -bash: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8): No such file or directory # 中文乱码, 缺少中文字体 apt install ttf-wqy-microhei # 安装 locale 相关工具 # sudo yum install glibc-langpack-en ``` # 问题记录 ## yum [Section titled “yum”](#yum) 报错内容: ```text This system is not registered with an entitlement server. You can use subscription-manager to register. ``` ```bash vim /etc/yum/pluginconf.d/subscription-manager.conf # enabled=0 ``` 报错内容: ```text http://mirrors.aliyun.com/centos/7/os/x86_64/repodata/repomd.xml: [Errno 12] Timeout on http://mirrors.aliyun.com/centos/7/os/x86_64/repodata/repomd.xml: (28, 'Operation too slow. Less than 1000 bytes/sec transferred the last 30 seconds') ``` [参考文章](https://juejin.cn/post/7161690775980507166) 阿里yum源出问题了 [参考文章](https://cloud.tencent.com/document/product/213/52559#dab668ec-1b0e-4112-a147-5071fdb19a9e) 切换为使用腾讯yum源 ```bash # 切换使用腾讯的yum源 curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.tencent.com/repo/centos7_base.repo ``` ```bash # 切换使用腾讯的SCLo的yum源(访问不了, 先注释) # wget -O /etc/yum.repos.d/CentOS-SCLo-scl.repo http://mirrors.cloud.tencent.com/repo/CentOS-SCLo-scl.repo # wget -O /etc/yum.repos.d/CentOS-SCLo-scl-rh.repo http://mirrors.cloud.tencent.com/repo/CentOS-SCLo-scl-rh.repo ``` ```bash yum clean all yum makecache ``` ## vm.max\_map\_count作用 [Section titled “vm.max\_map\_count作用”](#vmmax_map_count作用) vm.max\_map\_count 是 Linux 内核的一个参数,用于控制一个进程可以拥有的最大内存映射区域(memory map areas)的数量。这个参数对于某些应用程序(特别是 Java 应用程序)非常重要,因为这些应用程序在运行时需要创建大量的内存映射区域。 默认情况下,vm.max\_map\_count 的值可能较低(例如 65530),这对于某些应用程序来说可能不够。当应用程序尝试创建更多的内存映射区域时,可能会遇到 OutOfMemoryError 或类似的错误。 将 vm.max\_map\_count 设置为至少 262144 可以解决这个问题,因为这个值通常足够大,可以满足大多数应用程序的需求。 要查看当前的 vm.max\_map\_count 值,可以在终端中运行以下命令: ```bash sysctl vm.max_map_count ``` 要更改 vm.max\_map\_count 的值,可以在终端中运行以下命令(以 root 用户身份): ```bash sysctl -w vm.max_map_count=262144 ``` 要使更改永久生效,可以将以下行添加到 /etc/sysctl.conf 文件中: ```bash vm.max_map_count=262144 ``` 然后运行 `sysctl -p` 命令以应用更改。 请注意,增加 vm.max\_map\_count 的值可能会增加系统的资源消耗,因此在更改此参数之前,请确保了解其潜在影响。 # vscode remote ssh ## glibc >= 2.28, libstdc++ >= 3.4.25 [Section titled “glibc >= 2.28, libstdc++ >= 3.4.25”](#glibc--228-libstdc--3425) ```bash curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo # 安装 SCL 仓库 yum install -y centos-release-scl # 尝试安装 yum install -y devtoolset-8-gcc* ``` ### 安装`devtoolset-8-gcc*`时, 报链接访问不了的错 [Section titled “安装devtoolset-8-gcc\*时, 报链接访问不了的错”](#安装devtoolset-8-gcc时-报链接访问不了的错) 替换为阿里云的链接 ```bash cd /etc/yum.repos.d/ mv CentOS-SCLo-scl.repo CentOS-SCLo-scl.repo.bak mv CentOS-SCLo-scl-rh.repo CentOS-SCLo-scl-rh.repo.bak ``` 文件一:CentOS-SCLo-scl.repo ```bash [centos-sclo-sclo] name=CentOS-7 - SCLo sclo baseurl=https://mirrors.aliyun.com/centos/7/sclo/$basearch/sclo/ gpgcheck=1 enabled=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-SCLo [centos-sclo-sclo-testing] name=CentOS-7 - SCLo sclo Testing baseurl=http://buildlogs.centos.org/centos/7/sclo/$basearch/sclo/ gpgcheck=0 enabled=0 [centos-sclo-sclo-source] name=CentOS-7 - SCLo sclo Sources baseurl=http://vault.centos.org/centos/7/sclo/Source/sclo/ gpgcheck=1 enabled=0 [centos-sclo-sclo-debuginfo] name=CentOS-7 - SCLo sclo Debuginfo baseurl=http://debuginfo.centos.org/centos/7/sclo/$basearch/debuginfo/ gpgcheck=1 enabled=0 ``` 文件二:CentOS-SCLo-scl-rh.repo ```bash [centos-sclo-rh] name=CentOS-7 - SCLo rh baseurl=https://mirrors.aliyun.com/centos/7/sclo/x86_64/rh/ gpgcheck=1 enabled=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-SCLo [centos-sclo-rh-testing] name=CentOS-7 - SCLo rh Testing baseurl=http://buildlogs.centos.org/centos/7/sclo/x86_64/rh/ gpgcheck=0 enabled=0 [centos-sclo-rh-source] name=CentO-7 - SCLo rh Sources baseurl=http://vault.centos.org/centos/7/sclo/Source/rh/ gpgcheck=1 enabled=0 [centos-sclo-rh-debuginfo] name=CentOS-7 - SCLo rh Debuginfo baseurl=http://debuginfo.centos.org/centos/7/sclo/x86_64/debuginfo/ gpgcheck=1 enabled=0 ``` ```bash yum clean all yum makecache # 验证 yum repolist | grep scl # 安装 yum install -y devtoolset-8-gcc* ``` ### glibc >= 2.28(升级) [Section titled “glibc >= 2.28(升级)”](#glibc--228升级) ```bash # 查看系统内安装的glibc版本 strings /lib64/libc.so.6 |grep GLIBC_ # 更新glibc wget http://ftp.gnu.org/gnu/glibc/glibc-2.28.tar.gz tar xf glibc-2.28.tar.gz cd glibc-2.28/ && mkdir build && cd build ../configure --prefix=/usr --disable-profile --enable-add-ons --with-headers=/usr/include --with-binutils=/usr/bin ``` 可能出现的错误 ```bash configure: error: *** These critical programs are missing or too old: make bison compiler *** Check the INSTALL file for required versions. ``` 解决办法:升级gcc与make ```bash # 升级GCC(默认为4 升级为8) yum install -y centos-release-scl yum install -y devtoolset-8-gcc* mv /usr/bin/gcc /usr/bin/gcc-4.8.5 ln -s /opt/rh/devtoolset-8/root/bin/gcc /usr/bin/gcc mv /usr/bin/g++ /usr/bin/g++-4.8.5 ln -s /opt/rh/devtoolset-8/root/bin/g++ /usr/bin/g++ # 升级 make(默认为3 升级为4) wget http://ftp.gnu.org/gnu/make/make-4.3.tar.gz tar -xzvf make-4.3.tar.gz && cd make-4.3/ ./configure --prefix=/usr/local/make make && make install cd /usr/bin/ && mv make make.bak ln -sv /usr/local/make/bin/make /usr/bin/make ``` 这时 所有的问题 都已经解决完毕 再重新执行上一步 更新glibc即可 ```bash cd /root/glibc-2.28/build ../configure --prefix=/usr --disable-profile --enable-add-ons --with-headers=/usr/include --with-binutils=/usr/bin ``` 我的依旧报错:bison太老旧 ```bash configure: error: *** These critical programs are missing or too old: bison *** Check the INSTALL file for required versions. ``` 看看我的bison版本多少 ```bash bison --version # -bash: bison: 未找到命令 yum install -y bison bison --version ``` 这时 所有的问题 真的真的都已经解决完毕 再重新执行上一步 更新glibc即可 ```bash cd /root/glibc-2.28/build ../configure --prefix=/usr --disable-profile --enable-add-ons --with-headers=/usr/include --with-binutils=/usr/bin ``` 继续更新 make 和 make install在linux中就是安装软件的意思 简单这么理解就好。 这个过程较长,大约半小时左右,建议打一局游戏就好了。 ```bash make && make install # PS: 好像有error也不影响的样子, 要是连接不上, 就继续往后看就行 ``` 验证下 是不是好了(PS: 用vscode的remote-ssh连接远程服务器) 如果还是出现下面的问题,要连接新的动态库 ```bash node: /lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by node) node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by node) node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by node) ``` 用下面命令查看 ```bash strings /usr/lib64/libstdc++.so.6 | grep CXXABI ``` 更新libstdc++.so.6.0.26 ```bash # 更新lib libstdc++.so.6.0.26 wget https://cdn.frostbelt.cn/software/libstdc%2B%2B.so.6.0.26 --no-check-certificate # 替换系统中的/usr/lib64 cp libstdc++.so.6.0.26 /usr/lib64/ cd /usr/lib64/ ln -snf ./libstdc++.so.6.0.26 libstdc++.so.6 ``` 再次验证(PS: 用vscode的remote-ssh连接远程服务器) ```bash # 连接成功后, 可能遇到的新问题 # manpath: can't set the locale; make sure $LC_* and $LANG are correct ``` 解决方法 ```bash # 检查当前时区 locale # 可能会出现以下错误 $ locale locale: Cannot set LC_ALL to default locale: No such file or directory LANG=en_US.UTF-8 LC_CTYPE="en_US.UTF-8" LC_NUMERIC="en_US.UTF-8" LC_TIME="en_US.UTF-8" LC_COLLATE="en_US.UTF-8" LC_MONETARY="en_US.UTF-8" LC_MESSAGES="en_US.UTF-8" LC_PAPER="en_US.UTF-8" LC_NAME="en_US.UTF-8" LC_ADDRESS="en_US.UTF-8" LC_TELEPHONE="en_US.UTF-8" LC_MEASUREMENT="en_US.UTF-8" LC_IDENTIFICATION="en_US.UTF-8" LC_ALL= ``` ```bash # 生成缺失的区域设置 locale -a # 编辑区域配置文件 vi /etc/locale.conf # 添加以下内容 LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 # 生成区域设置 localedef -i en_US -f UTF-8 en_US.UTF-8 # 如果需要其他区域设置,可以相应更改 en_US 和 UTF-8。例如,对于简体中文: localedef -i zh_CN -f UTF-8 zh_CN.UTF-8 # 设置环境变量临时生效 export LANG=en_US.UTF-8 export LC_ALL=en_US.UTF-8 # 你可以将这些命令添加到 ~/.bashrc 或 ~/.bash_profile 文件中,以便每次登录时自动设置: echo 'export LANG=en_US.UTF-8' >> ~/.bashrc echo 'export LC_ALL=en_US.UTF-8' >> ~/.bashrc source ~/.bashrc # 验证 locale ``` ## 参考链接 [Section titled “参考链接”](#参考链接) [node: /lib64/libm.so.6: version \`GLIBC\_2.27‘ not found问题解决方案](https://www.cnblogs.com/yuwen01/p/18067005) # nsenter Linux namespace 穿透工具,以**指定进程的命名空间上下文**执行任意命令。在容器化和 Kubernetes 运维中,它是”不通过网络、直接潜入目标环境”的核心工具。 ## 背景:为什么需要 nsenter [Section titled “背景:为什么需要 nsenter”](#背景为什么需要-nsenter) Linux 容器(Docker、Kubernetes Pod)的本质是**被 Namespace 隔离的普通进程**。每个容器拥有独立的: | Namespace | 隔离内容 | 容器视角 | | --------- | ----- | ------------------- | | `net` | 网络栈 | 只能看到自己的虚拟网卡、路由表 | | `pid` | 进程树 | 容器内 PID 1 是”唯一”的根进程 | | `mnt` | 挂载点 | 只能看到自己的根文件系统 | | `uts` | 主机名 | 容器有自己的 hostname | | `ipc` | 进程间通信 | 独立的消息队列、共享内存 | 当需要绕过网络层(SSH、kubectl exec)直接进入某个容器或宿主机环境时,`nsenter` 是唯一手段。 ## 核心参数 [Section titled “核心参数”](#核心参数) ```bash nsenter [options] [program [args...]] ``` | 参数 | 全称 | 作用 | | ---------- | ---------- | ---------------------------------- | | `-t ` | `--target` | **必选。** 目标进程 PID | | `-m` | `--mount` | 进入目标进程的挂载命名空间(**决定用谁的 `/`、用谁的命令**) | | `-n` | `--net` | 进入目标进程的网络命名空间 | | `-p` | `--pid` | 进入目标进程的 PID 命名空间(看到目标的进程树) | | `-u` | `--uts` | 进入目标进程的 UTS 命名空间(使用目标的主机名) | | `-i` | `--ipc` | 进入目标进程的 IPC 命名空间 | | `-a` | `--all` | 进入所有命名空间(等价于 `-m -n -p -u -i`) | ## `-m` 参数:命令来源的”分水岭” [Section titled “-m 参数:命令来源的”分水岭””](#-m-参数命令来源的分水岭) 所有 namespace 参数中,**`-m` 是唯一决定”你敲的命令来自哪里”的参数**: * **加了 `-m`**:根目录切换到目标的 `/`,所有命令二进制来自**目标环境**(宿主机或目标容器)。 * **不加 `-m`**:根目录留在当前环境,命令二进制来自**当前环境**,但其他 namespace(网络、PID 等)已切换到目标。 这个区别决定了:你是”用目标的刀,砍目标的柴”,还是”借自己的刀,砍目标的柴”。 ## 参数组合对照表 [Section titled “参数组合对照表”](#参数组合对照表) | 命令 | 命令来源 | 文件系统 | 网络栈 | 典型场景 | | -------------------- | ------- | -------- | ---- | ------------------------ | | `nsenter -t 1 -a` | 📂 宿主机 | 宿主机 `/` | 宿主机 | 接管宿主机:重启 kubelet、查系统日志 | | `nsenter -t 1 -n` | 🐳 当前容器 | 当前容器 `/` | 宿主机 | 宿主机没装诊断工具,借用容器工具抓宿主机网卡的包 | | `nsenter -t $PID -n` | 📂 宿主机 | 宿主机 | 目标容器 | 用宿主机 tcpdump 抓精简容器的网络流量 | | `nsenter -t $PID -m` | 🐳 目标容器 | 目标容器 `/` | 当前环境 | 查看/修改容器内文件 | > **记忆口诀**:`-m` 决定”命令从哪来”,`-n` 决定”网从哪走”,两者独立。 ## 工作原理:Kuboard Node-Shell 示例 [Section titled “工作原理:Kuboard Node-Shell 示例”](#工作原理kuboard-node-shell-示例) Kuboard 的 “node-shell” 功能完整展示了 `nsenter` 的生产级用法。其前置条件是一个特权 Pod: ```yaml spec: hostPID: true # 容器内可见宿主机所有进程 privileged: true # 特权模式,允许 namespace 切换 ``` Kuboard 在 Pod 内部执行的核心命令: ```bash nsenter --target 1 --mount --uts --ipc --net --pid ``` 逐项拆解: 1. **`--target 1`**:指向宿主机 PID 1(systemd / init),它持有宿主机所有 namespace 2. **`--mount`** 🗝️:切换到宿主机根文件系统 —— 从此敲的命令全是宿主机二进制 3. **`--net`**:获得宿主机网络栈(`ip addr` 看到物理网卡) 4. **`--pid`**:获得宿主机进程树(`ps aux` 看到所有进程) 5. 执行后,终端从”容器内部”瞬间变为”宿主机 root shell” ## 常用场景 [Section titled “常用场景”](#常用场景) ### 场景一:全量穿透 —— 从容器接管宿主机 [Section titled “场景一:全量穿透 —— 从容器接管宿主机”](#场景一全量穿透--从容器接管宿主机) 宿主机 SSH 不可用,通过集群中已有的特权 Pod 直接接管: ```bash # 在特权 Pod 内执行 nsenter -t 1 -a bash # 此时所有命令来自宿主机,可执行: systemctl restart kubelet journalctl -u kubelet -f ip addr show cat /var/log/messages ``` ### 场景二:精细穿透 —— 借用容器工具诊断宿主机网络 [Section titled “场景二:精细穿透 —— 借用容器工具诊断宿主机网络”](#场景二精细穿透--借用容器工具诊断宿主机网络) 生产宿主机常是精简系统(CoreOS、Talos、安全加固的 Linux),宿主机层连 `tcpdump`、`curl` 都没有。此时**不加 `-m`、只加 `-n`**,用容器的工具去解剖宿主机网络: ```bash # 在 netshoot 等工具丰富的 Pod 内执行 # 注意:没有 -m!文件系统还在容器,但网络栈已切到宿主机 nsenter -t 1 -n # 敲下 tcpdump —— 调用的是容器自带的 tcpdump # 但它抓取的是宿主机 eth0 网卡上的真实物理流量 tcpdump -i eth0 -w /tmp/host.pcap # 其他容器自带、宿主机缺失的工具同样可用: curl -v https:// ip route show ss -tlnp ``` ### 场景三:从宿主机进入容器网络抓包 [Section titled “场景三:从宿主机进入容器网络抓包”](#场景三从宿主机进入容器网络抓包) 反向操作:生产容器(distroless、alpine 精简版)缺失 `tcpdump`。从宿主机用 `-n` 进入容器网络,借用宿主机工具: ```bash CONTAINER_PID=$(crictl inspect | jq -r '.info.pid') # 用宿主机 tcpdump,抓容器 eth0 的流量 nsenter -t $CONTAINER_PID -n tcpdump -i eth0 -w /tmp/container.pcap ``` ### 场景四:从宿主机操作容器文件 [Section titled “场景四:从宿主机操作容器文件”](#场景四从宿主机操作容器文件) ```bash nsenter -t $CONTAINER_PID -m ls /app/config nsenter -t $CONTAINER_PID -m cat /app/logs/error.log ``` ## 注意事项 [Section titled “注意事项”](#注意事项) 1. **`-m` 是分水岭**:新手最容易踩的坑 —— 以为进了目标环境,结果忘了加 `-m`,敲的命令还是当前环境的。 2. **需要 `CAP_SYS_ADMIN`**:常规容器默认不具备,需配合 `privileged: true` 或特定 `securityContext`。 3. **`--target` 必须准确**:目标 PID 错误会导致进入错误的 namespace 上下文。 4. **非持久化**:`nsenter` 只在命令执行期间生效,退出后 shell 回到原有上下文。 5. **镜像选择**:如果是”精细穿透”场景(不加 `-m`),镜像必须自带诊断工具(推荐 `nicolaka/netshoot`);如果是”全量穿透”场景(加 `-m`),工具依赖宿主机,镜像用 `alpine` 足够。 ## 相关命令 [Section titled “相关命令”](#相关命令) * `unshare`:反向操作,从父命名空间中”脱离”,创建新的独立命名空间 * `lsns`:列出当前系统中所有命名空间 * `ip netns`:管理网络命名空间(底层也基于 namespace 机制) # 进程 ## 没有足够的资源创建本地线程 [Section titled “没有足够的资源创建本地线程”](#没有足够的资源创建本地线程) ### java.lang.OutOfMemoryError: unable to create new native thread [Section titled “java.lang.OutOfMemoryError: unable to create new native thread”](#javalangoutofmemoryerror-unable-to-create-new-native-thread) * 确认资源是否够 ```bash # 查看资源不够的应用是由哪个用户启动的(这里示例为www用户启动) su www # 查看用户最大进程数(PS: 不同用户查看到的最大用户进程数不一样) ulimit -a # max user processes (-u) 4096 # 当前用户占用的总线程数 top -H ``` * 修改用户最大进程数 [参考文章](https://www.cnblogs.com/operationhome/p/11966041.html) ```bash # 查看资源不够的应用是由哪个用户启动的(这里示例为www用户启动) su www # centos7版本的配置 vim /etc/security/limits.d/20-nproc.conf # 写入以下内容 # www soft nproc 40960 # 检查是否生效 ulimit -a # max user processes (-u) 40960 ``` # macos ## FreeRDP [Section titled “FreeRDP”](#freerdp) ```bash brew install freerdp # 在能连集群的机器上: kubectl port-forward svc/windows 3389:3389 -n default # Mac 上连接: xfreerdp /v:127.0.0.1:3389 /u:Docker /p:admin /dynamic-resolution ``` ```bash # 继续用 xfreerdp → 装 XQuartz(能用,但体验一般) brew install --cask xquartz open -a XQuartz # 启动 X 服务器(首次安装建议注销重登一次) export DISPLAY=:0 # 这个命令的作用是告诉 xfreerdp(以及其他所有 X11 图形程序)应该把窗口画在哪个显示器屏幕上。:0 的含义:代表当前系统中的第一个本地物理显示器(屏幕)。 xfreerdp /v:windows.default.svc.cluster.local:3389 /u:Docker /p:admin /dynamic-resolution /clipboard ``` ```bash # Ubuntu export DISPLAY=:0 && xfreerdp /v:10.0.5.xxx /u:xxx /dynamic-resolution +clipboard /d:WORKGROUP /cert:ignore # /cert:ignore 参数用于忽略 Ubuntu 自签证书的安全警告。* # /f:全屏模式(退出全屏按 Ctrl+Alt+Enter)。 # +clipboard:启用双向剪贴板(支持复制粘贴文本)。 # /dynamic-resolution:自适应分辨率,缩放窗口时自动调整 Ubuntu 分辨率。 # /d:WORKGROUP:指定工作组为 WORKGROUP(Ubuntu 默认工作组)。如果连接仍不成功,可以尝试完全移除 /d 参数。 # /cert:ignore:(警告:仅限安全局域网) 彻底忽略一切 SSL/TLS 证书校验。在无外网的纯净 LAN 中,这可以跳过由于自签名证书导致的连接中断。 ``` # trueNas使用记录 [官方下载地址(最新稳定版)](https://www.truenas.com/download-truenas-scale/) [官方下载地址(历史版)](https://www.truenas.com/docs/softwarereleases/) ## 安装 [Section titled “安装”](#安装) 第一步: 使用`balena Etcher`先烧录好镜像到U盘 [GitHub地址](https://github.com/balena-io/etcher) 第二步: 插入U盘,开机,进入BIOS设置,选择U盘启动 ```bash ``` # test ```bash dfsdf`gfgdf` ``` ![示例图](/img/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_202210261942369c6902bf8d6d48de9cb9cb0dad21c88d.jpg) # fenced-comment-only ```bash # 这里是一段代码注释,不是标题 echo "fenced comment" ``` 这篇文档故意让全文首个 `#` 出现在围栏代码块内,并且不声明 front matter、 正文也没有一级标题,用于验证标题推导不会把代码注释当成标题: 页面标题应回退为文件名(`fenced-comment-only`)。 ```yaml # YAML 注释同样不应被当作标题 key: value ``` # 无 front matter 的文档 这篇文档故意不声明 front matter,用于验证:作者直接写 Markdown 时, 页面标题由正文首个一级标题推导,且正文中的该标题不再重复渲染。 正文的其余内容仅作占位,说明二级标题与段落的渲染不受影响。 ## 二级标题 [Section titled “二级标题”](#二级标题) 无 front matter 的文档同样参与搜索索引、侧边栏自动生成为 llms.txt 分卷, 其标题来自 loader 从正文推导的结果,与显式声明 title 的文档一致。 # todos * 添加 claude code 到 GitHub action workflow 中去, 用于自动评审PR, 并在PR中添加 claude code 评审结果, 评估是否可以自动合并, 如果可以, 则自动合并, 然后邮件通知我 # 编程语言相关记录 ## Python [Section titled “Python”](#python) ```bash # 安装pip curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py sudo python get-pip.py # 查看版本 pip --version ``` * 基本流程 ```md 在项目根目录下创建虚拟环境:`python -m venv venv` 激活虚拟环境: - Linux/macOS: `source venv/bin/activate` - Windows: `venv\Scripts\activate` 确保已安装所有依赖:`pip install -r requirements.txt` - 如果安装失败,请手动安装依赖:`pip install requests` - 更新requirements.txt:`pip freeze > requirements.txt` 运行应用:`python main.py` 在浏览器中访问:`http://localhost:5000` 退出虚拟环境:`deactivate` ``` ### anaconda [Section titled “anaconda”](#anaconda) ```bash wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh # Miniconda(轻量版,推荐) # 或(若需完整版Anaconda) # wget https://repo.anaconda.com/archive/Anaconda3-latest-Linux-x86_64.sh # 运行安装脚本 bash Miniconda3-latest-Linux-x86_64.sh # 按照提示进行安装(默认即可, 最后一步, 选择yes, 用于更新.bashrc或.zshrc文件) # You can undo this by running `conda init --reverse $SHELL`? [yes|no] # [no] >>> yes # 激活Conda source ~/.bashrc # 若使用zsh,执行`source ~/.zshrc` # 验证安装 conda --version # 输出版本号即成功 # (可选)配置国内镜像源(加速下载) conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/ conda config --set show_channel_urls yes ``` ```bash # 创建虚拟环境 conda create -n myenv python=3.8 # 激活虚拟环境 conda activate myenv # 安装依赖 pip install -r requirements.txt # 运行应用 python main.py # 退出虚拟环境 conda deactivate ``` ## java [Section titled “java”](#java) ```bash # 查看已安装的JDK /usr/libexec/java_home -V # 或者 ls /Library/Java/JavaVirtualMachines/ # xpp导致xml解析异常, 导致日志xml文件解析异常, 排除xpp3依赖 ./gradlew :support-service:dependencies --configuration runtimeClasspath -Dorg.gradle.java.home=/Users/fa/Library/Java/JavaVirtualMachines/corretto-17.0.15/Contents/Home | grep -i xpp # 全局排除(推荐) # // 根项目 build.gradle # allprojects { # configurations.all { # exclude group: 'xpp3', module: 'xpp3' # } # } # 首先找出是哪个依赖引入了 XPP: ./gradlew :support-service:dependencyInsight --configuration runtimeClasspath -Dorg.gradle.java.home=/Users/fa/Library/Java/JavaVirtualMachines/corretto-17.0.15/Contents/Home --dependency xpp3 # 然后针对性地排除: # implementation('org.springframework.boot:spring-boot-starter-web') { # exclude group: 'xpp3', module: 'xpp3' # } # configurations.all { # exclude group: 'xpp3' # exclude module: 'xpp3' # } ./gradlew clean build rm -rf ~/.gradle/caches ``` ```bash # 查看日志相关依赖 ./gradlew :support-service:dependencies --configuration runtimeClasspath -Dorg.gradle.java.home=/Users/fa/Library/Java/JavaVirtualMachines/corretto-17.0.15/Contents/Home | grep -i "log\|slf4j" # 检查依赖是否有冲突 # ./gradlew dependencies --configuration runtimeClasspath | grep -i "conflict\|duplicate" ./gradlew :support-service:dependencies --configuration runtimeClasspath -Dorg.gradle.java.home=/Users/fa/Library/Java/JavaVirtualMachines/corretto-17.0.15/Contents/Home | grep -i "conflict\|duplicate" ``` ```bash # # 检查OCR依赖引入了哪些日志相关库 ./gradlew :support-service:dependencyInsight --configuration runtimeClasspath --dependency com.aliyun:ocr_api20210707:3.1.3 -Dorg.gradle.java.home=/Users/fa/Library/Java/JavaVirtualMachines/corretto-17.0.15/Contents/Home ``` # maxkb使用记录 [官网安装目录](https://maxkb.cn/docs/installation/online_installtion/) ## 安装 [Section titled “安装”](#安装) ```bash docker run -d --name=maxkb --restart=always -p 8080:8080 -v ~/.maxkb:/var/lib/postgresql/data -v ~/.python-packages:/opt/maxkb/app/sandbox/python-packages registry.fit2cloud.com/maxkb/maxkb ``` # clash使用记录 ## Linux中使用clash [Section titled “Linux中使用clash”](#linux中使用clash) [Clash Verge Rev Docs安装Linux版](https://www.clashverge.dev/install.html) 开放端口, 使用web页面去配置clash即可 # linux中使用clash记录 ## 安装clash-for-linux [Section titled “安装clash-for-linux”](#安装clash-for-linux) * clash文件目录(内网服务器路径备忘:/root/vpn,仓库内无对应文件) * [本地备份文件](clash-linux-amd64-v1.18.0.gz),解压命令`gzip -d clash-linux-amd64-v1.18.0.gz` * 原版仓库 `Dreamacro/clash` 已于 2023 年归档,v1.18.0 官方下载地址现返回 404,该本地备份为当前可获取的唯一副本,不建议删除 ### 内核下载源 [Section titled “内核下载源”](#内核下载源) * 原版 v1.18.0:官方 release 已下架,无可用的公开下载地址 * 后继项目 mihomo(原 Clash Meta),版本号序列与原版一致,配置文件兼容 * v1.18.0: * 最新发行版: * 二进制名自 v1.17.0 起变更为 `mihomo`,使用时需注意路径适配 * 补充参考链接(以前的链接不知道哪去了,新找了些补充下) * [clash-for-linux](https://github.com/ghostxu97/clash-for-linux) * [clash-for-linux](https://blog.iswiftai.com/posts/clash-linux/) ## 添加config.yaml配置文件 [Section titled “添加config.yaml配置文件”](#添加configyaml配置文件) 在clash同级目录中添加config.yaml文件 文件来源: - 本地客户端 - 设置 -> 配置 -> 打开配置文件夹 - 有效的config.yaml(找到后放到服务器中的clash所在目录即可) ## 启动命令 [Section titled “启动命令”](#启动命令) ```shell # 重命名 mv clash-linux-amd64-v1.18.0 clash # vim start.sh cd /root/vpn nohup ./clash -d . & ``` * 环境变量配置(用于开启系统代理) ```shell # vim .env # 设置系统代理 export https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890 all_proxy=socks5://127.0.0.1:7890 # 取消系统代理 unset http_proxy https_proxy all_proxy ``` > 到这已经已经能访问外网了 ## DashBoard 外部控制(可视化界面远程管理服务器中的clash配置) [Section titled “DashBoard 外部控制(可视化界面远程管理服务器中的clash配置)”](#dashboard-外部控制可视化界面远程管理服务器中的clash配置) > 前提条件: 本地电脑中有安装可视化界面的clash客户端 PS:只使用默认配置的话,这步不需要操作 ```bash # 修改 /etc/clash/config.yaml 文件部分配置: mixed-port: 12345 authentication: - "用户名1:密码1" - "用户名2:密码2" allow-lan: true mode: Rule log-level: info external-controller: :9090 # 对应开启系统代理的方式调整 export https_proxy=http://用户名1:密码1@127.0.0.1:12345 http_proxy=http://用户名1:密码1@127.0.0.1:12345 all_proxy=socks5://用户名1:密码1@127.0.0.1:12345 # config.yaml中的这个配置为DashBoard的外部控制端口 external-controller: :9090 # 自己本地电脑中安装的clash可在设置中的配置界面找到远程控制器管理界面,在其中添加对应的api url(http://ip:9090)进行远程控制 ``` # ComfyUI ## 安装 [Section titled “安装”](#安装) [参考地址](https://docs.comfy.org/get_started/manual_install#mac-arm-silicon) ```bash # 安装miniconda curl -fsSL https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh | bash # Create an environment with Conda. conda create -n comfyenv conda activate comfyenv # Install GPU Dependencies conda install pytorch-nightly::pytorch torchvision torchaudio -c pytorch-nightly cd ComfyUI pip install -r requirements.txt cd ComfyUI python main.py ``` > 最后, 我直接拉代码下来在IDE中启动了 # cursor ## 修改机器码实现无限续杯(Cursor Free Trial Reset Tool) [Section titled “修改机器码实现无限续杯(Cursor Free Trial Reset Tool)”](#修改机器码实现无限续杯cursor-free-trial-reset-tool) [GitHub地址](https://github.com/yuaotian/go-cursor-help) ```bash # 一键修改(mac) curl -fsSL https://aizaozao.com/accelerate.php/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_mac_id_modifier.sh -o ./cursor_mac_id_modifier.sh && sudo bash ./cursor_mac_id_modifier.sh && rm ./cursor_mac_id_modifier.sh # win irm https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex ``` # etcher使用记录 [GitHub地址](https://github.com/balena-io/etcher) 用于烧录镜像到U盘 # idea使用记录 ## plugins [Section titled “plugins”](#plugins) * `CamelCase` : 驼峰转下划线 * `Code Iris` : This plugin visualizes the modules, packages and classes of your project. * `Call Graph` : A plugin to visualize function call graph of any codebase for IDEs based on the IntelliJ platform. * `GenerateAllSetter` : 一键调用一个对象的所有的set方法,get方法等, 在方法上生成两个对象的转换 * `Generate020` : This plugin can generate an Object to another Object transfer methods. * `GenerateSerialVersionUID` : Adds a new action ‘SerialVersionUID’ in the generate menu (alt + ins). * `Git Commit Template` : Create a commit message with the following template. * `GitTooIBox` : Extends Git Integration with additional features Free features * `Gradle Dependencies Helper` : library is searched in Smart Code Completion by Maven repository * `idea-sourcetrail` : Sourcetrail plugin for idea IDEs like Intellij or CLion. Provides synchronization with Sourcetrail. * `Java Method Reference Diagram` : Java Method Reference Diagram * `Gradle/Maven Navigation`: Open our customized popup dialog and choose from a variety of context-sensitive destinations, including tree nodes, goals, and tasks. For each destination choose from context-sensitive actions such as go, open, run, and debug. * `JDK VisualGC` : A realtime Visual Garbage Collection Monitoring Tool for local or remote running Hotspot JVM, supports G1 and ZGC * `Java Visualizer` : A tool to visualize the call stack and objects on the heap (as a box and pointer diagram) while debugging Java applications. * `POJO to JSON` : A simple plugin for converting POJO to JSON in IntelliJ IDEA * `RestfulTool` : A set of auxiliary tools for Restful service development * `Statistic` : Shows project statistic. * `VisualvM Launcher` : VisualVM integration. * about DDD * `Axon Framework` : Supports developers while writing applications using Axon Framework version 4.x. * `VisualDDD` : Development Cloud - VisualDDD (Visual Development Platform for Domain-Driven Design) # ipscan使用记录 [GitHub地址](https://github.com/angryip/ipscan) 用于扫描局域网内的IP地址,端口号和主机名等信息,支持多种操作系统。 可以通过IP网段范围扫描 # 软件工具 常用软件工具的使用指南和配置说明。 ## 工具列表 [Section titled “工具列表”](#工具列表) 1. ComfyUI - AI 图像生成工具 2. Clash - 网络代理工具 3. Cursor - AI 辅助编程工具 4. IDEA - Java IDE 5. Windsurf - AI 编程助手 # TigerVNC ```bash # 安装TigerVNC服务器和密码工具 sudo apt update sudo apt install -y tigervnc-standalone-server tigervnc-tools # 首次运行需设置密码(会生成~/.vnc/passwd) vncpasswd # 创建1920x1080分辨率、24位色深的VNC会话(显示端口:1) vncserver :1 -geometry 1920x1080 -depth 24 ``` ```bash # 启动支持局域网访问的VNC服务 # 使用TigerVNC启动,明确指定不限制本地访问 Xtigervnc :1 -geometry 1920x1080 -depth 24 -rfbport 5901 -localhost no -SecurityTypes VncAuth -passwordfile ~/.vnc/passwd # 或使用标准vncserver命令(如已安装完整TigerVNC) vncserver :1 -geometry 1920x1080 -depth 24 -localhost no ``` ```bash # 永久配置方案 sudo apt install xfce4 xfce4-goodies -y # 执行之后会有个选项 # 建议选择:lightdm # 1. 创建VNC配置目录 mkdir -p ~/.vnc # 2. 创建正确的xstartup脚本(关键修复) cat > ~/.vnc/xstartup << 'EOF' #!/bin/sh unset SESSION_MANAGER unset DBUS_SESSION_BUS_ADDRESS export XDG_CURRENT_DESKTOP="GNOME" exec gnome-session EOF # # 可选:使用XFCE桌面环境(需安装XFCE组件) # cat > ~/.vnc/xstartup << 'EOF' # #!/bin/sh # unset SESSION_MANAGER # unset DBUS_SESSION_BUS_ADDRESS # exec startxfce4 # EOF # # 可选:使用GNOME桌面环境(需安装GNOME组件) # #!/bin/sh # unset SESSION_MANAGER # unset DBUS_SESSION_BUS_ADDRESS # export XDG_CURRENT_DESKTOP="GNOME" # exec gnome-session # 3. 添加执行权限 chmod +x ~/.vnc/xstartup # 4. 设置VNC密码(必须步骤) vncpasswd # 输入并确认密码(不会显示输入内容) # 创建VNC配置文件 mkdir -p ~/.vnc cat > ~/.vnc/config << 'EOF' geometry=1920x1080 depth=24 localhost=no rfbport=5901 EOF # 设置VNC密码 vncpasswd # 创建systemd服务实现开机自启 sudo tee /etc/systemd/system/vncserver@.service << 'EOF' [Unit] Description=TigerVNC Server on %i After=syslog.target network.target [Service] Type=forking User=pengdd Group=pengdd WorkingDirectory=/home/pengdd PIDFile=/home/pengdd/.vnc/%H%i.pid # 添加PID文件路径 # 修复启动命令,添加-xstartup指定会话脚本 ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :' ExecStart=/usr/bin/vncserver %i -geometry 1920x1080 -depth 24 -localhost no -xstartup /home/pengdd/.vnc/xstartup ExecStop=/usr/bin/vncserver -kill %i [Install] WantedBy=multi-user.target EOF # 启用并启动服务 sudo systemctl daemon-reload sudo systemctl enable vncserver@:1 sudo systemctl start vncserver@:1 ``` ```bash # 常用管理命令 # 列出所有VNC会话 vncserver -list # 终止指定会话(:1为显示编号) vncserver -kill :1 # 带日志启动(排障用) vncserver :1 -geometry 1920x1080 -depth 24 -log ~/vncserver.log ``` # x11vnc 配置 ```bash # 在服务器安装并启动x11vnc apt install -y x11vnc x11vnc -auth guess -forever -noxdamage -rfbport 5900 -shared ``` ## 问题 [Section titled “问题”](#问题) 找不到X11认证文件 ```bash # xauth: file /root/.Xauthority does not exist # -auth guess: failed for display='unset' # 正确配置x11vnc共享当前桌面 # 1. 存储VNC密码(首次运行) x11vnc -storepasswd # 按提示输入密码,默认保存在~/.vnc/passwd # 2. 找到正确的X认证文件路径 # 查看当前活跃的X会话 ps aux | grep Xorg | grep -v grep # 假设输出显示Xorg在运行,使用以下命令启动x11vnc x11vnc -auth /var/run/gdm3/*/database -forever -noxdamage -rfbauth ~/.vnc/passwd -rfbport 5901 -shared # 3. 若上述命令失败,尝试自动探测X会话 x11vnc -find -forever -noxdamage -rfbauth ~/.vnc/passwd -rfbport 5901 -shared # xauth: file /root/.Xauthority does not exist # wait_for_client: find display cmd failed # 为root创建临时X会话 # 1. 创建Xauthority文件 touch ~/.Xauthority # 2. 生成MIT-MAGIC-COOKIE mcookie | sudo tee -a ~/.Xauthority # 3. 指定display启动x11vnc x11vnc -display :99.0 -auth ~/.Xauthority -forever -noxdamage -rfbauth ~/.vnc/passwd -rfbport 5901 -shared -usepw # 修复gem用户账户(推荐) # 检查用户完整性 pwck gem # 修复用户账户 useradd -u 1000 -g 1000 -d /home/gem -s /bin/bash gem # 重新尝试切换用户 su - gem ``` ```bash # 创建新的虚拟桌面会话 vncserver :1 -geometry 1920x1080 -depth 24 # 然后连接这个新会话 x11vnc -display :1 -auth ~/.vnc/passwd -forever -noxdamage -rfbport 5901 -shared ``` # vscode ## claude code [Section titled “claude code”](#claude-code) * 配置 VS Code 插件设置(可视化界面中也可以设置, 搜`claudecode`就行) 打开 VS Code 的 settings.json 文件(可通过 Ctrl+, 打开设置,点击右上角图标选择 “Open Settings (JSON)”),添加以下配置: ```bash { "claudecode.initialpermissionmode": "bypasspermissions", "claudecode.allowdangerouslyskippermissions": true } ``` * 配置 Claude Code 的权限规则 在项目根目录或用户全局配置目录(\~/.claude/settings.json)中,编辑 settings.json 文件,添加以下内容: ```bash { "permissions": { "defaultmode": "bypasspermissions", "ask": [ "bash(rm -rf *)", "bash(rm *)", "bash(git push --force*)", "bash(sudo *)" ] } } ``` > 此配置将所有操作默认设为 bypass,但通过 ask 列表明确列出高风险命令(如删除文件、强制推送 Git 提交、使用 sudo 等),这些命令仍会弹窗确认。 # windsurf # ollama使用记录 [官网](https://ollama.com) ## 安装 [Section titled “安装”](#安装) ```bash curl -fsSL https://ollama.com/install.sh | sh ``` * docker版(only CPU) [docker hub地址](https://hub.docker.com/r/ollama/ollama) ```bash docker run -d -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama ``` ## 使用 [Section titled “使用”](#使用) ```bash ollama run BAAI/bge-reranker-v2-m3 ``` # one-api使用记录 [GitHub地址](https://github.com/songquanpeng/one-api) ## 安装 [Section titled “安装”](#安装) ```bash git clone https://github.com/songquanpeng/one-api.git docker-compose up -d ``` # openLLM [GitHub地址](https://github.com/bentoml/OpenLLM) ## 安装 [Section titled “安装”](#安装) ```bash # or pip3 install openllm pip install openllm openllm hello ``` * 聊天界面 OpenLLM provides a chat UI at the /chat endpoint for the launched LLM server at . * 使用 ```bash openllm serve llama3.2:1b openllm run llama3:8b openllm model list openllm repo update openllm model get llama3.2:1b ``` * 添加模型 [GitHub地址](https://github.com/bentoml/openllm-models) ```bash openllm repo add openllm repo add nightly https://github.com/bentoml/openllm-models@nightly ``` * test ```bash export VLLM_DEVICE=cpu openllm serve gemma2:2b ``` # vllm使用记录 [GitHub地址](https://github.com/vllm-project/vllm) ## 安装 [Section titled “安装”](#安装) ```bash # 安装 Miniconda # 运行安装脚本: # Linux: wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh bash Miniconda3-latest-Linux-x86_64.sh -b -p ${HOME}/software/miniconda3 # macOS: wget https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh bash Miniconda3-latest-MacOSX-x86_64.sh -b -p ${HOME}/software/miniconda3 # 配置环境变量: # 将以下内容添加到 ~/.bashrc 或 ~/.zshrc 文件中: export PATH=${HOME}/software/miniconda3/bin:$PATH # 刷新环境变量: source ~/.bashrc # 验证安装: conda --version # 如果显示版本号,说明安装成功。 ``` ```bash # (Recommended) Create a new conda environment. conda create -n vllm python=3.12 -y conda activate vllm # PS: 有时可能需要先初始化 conda init 然后执行 bash 重新打开终端, 之后才能使用 conda activate vllm # 取消激活环境 conda deactivate # 配置 pip 源 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple/ pip config set install.trusted-host pypi.tuna.tsinghua.edu.cn # 在虚拟环境中安装 vllm 0.4.2 版本 pip install vllm==0.4.2 # 或者安装最新版本 pip install vllm ``` * docker 安装 ```bash # vLLM 提供了一个官方 Docker 镜像用于部署。该镜像可用于运行与 OpenAI 兼容服务器,并且可在 Docker Hub 上以 vllm/vllm-openai 的形式获取。 # PS: 需要英伟达运行时 docker run --runtime nvidia --gpus all \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HUGGING_FACE_HUB_TOKEN=" \ -p 8000:8000 \ --ipc=host \ vllm/vllm-openai:latest \ --model mistralai/Mistral-7B-v0.1 ``` * 源码安装 [环境变量参数说明](https://docs.vllm.ai/en/latest/getting_started/installation/cpu.html#related-runtime-environment-variables) ```bash # 启用Docker BuildKit # export DOCKER_BUILDKIT=1 # export COMPOSE_DOCKER_CLI_BUILD=1 docker build -f docker/Dockerfile.cpu --tag vllm-cpu-env --target vllm-openai . # 启用代理, 并且不使用缓存 # 在 Dockerfile 中添加以下代码确保代理生效: # ARG HTTP_PROXY # ARG HTTPS_PROXY # ENV HTTP_PROXY=$HTTP_PROXY # ENV HTTPS_PROXY=$HTTPS_PROXY # docker build \ --build-arg "HTTP_PROXY=http://10.0.4.59:9090" \ --build-arg "HTTPS_PROXY=http://10.0.4.59:9090" \ --no-cache \ -f docker/Dockerfile.cpu --tag vllm-cpu-env --target vllm-openai . docker run --rm \ --privileged=true \ --shm-size=4g \ -p 8000:8000 \ # 表示 KV 缓存空间为 8 GiB -e VLLM_CPU_KVCACHE_SPACE=8 \ # 表示将有 32 个 OpenMP 线程绑定在 0-31 个 CPU 内核上。 -e VLLM_CPU_OMP_THREADS_BIND=0-31 \ vllm-cpu-env \ --model=meta-llama/Llama-3.2-1B-Instruct \ --dtype=bfloat16 \ other vLLM OpenAI server arguments ``` * docker安装(openai版镜像)(亲测可用) ```bash docker run -it --rm vllm/vllm-openai:v0.7.3 --device cpu # docker run -it --rm vllm/vllm-openai:v0.7.3 --device cpu --model Qwen/Qwen2.5-1.5B-Instruct # 进入容器, 启动模型 vllm serve Qwen/Qwen2.5-1.5B-Instruct # 自定义key vllm serve NousResearch/Meta-Llama-3-8B-Instruct --dtype auto --api-key token-abc123 # 其他用法 # docker run带上代理的环境变量 docker run -d -e http_proxy=http://10.0.5.93:9090 -e https_proxy=http://10.0.5.93:9090 vllm/vllm-openai:v0.7.3 --device cpu --model hf.co/sesame/csm-1b # 还需要把端口映射出来 docker run -d -e http_proxy=http://10.0.5.93:9090 -e https_proxy=http://10.0.5.93:9090 -p 8000:8000 vllm/vllm-openai:v0.7.3 --device cpu --model sesame/csm-1b # 差授权 docker run -d -e http_proxy=http://10.0.4.59:9090 -e https_proxy=http://10.0.4.59:9090 -e HUGGING_FACE_HUB_TOKEN= -p 8000:8000 vllm/vllm-openai --device cpu --model google/gemma-3-1b-it ``` * uv方式安装 ```bash uv venv vllm_env --python 3.12 --seed source vllm_env/bin/activate uv pip install vllm # 另一种令人愉快的方法是使用带有 --with [dependency] 选项的 uv run,它允许你运行诸如 vllm serve 之类的命令,而无需创建环境: uv run --with vllm vllm --help ``` ## 使用 [Section titled “使用”](#使用) ```bash # Run the following command to start the vLLM server with the Qwen2.5-1.5B-Instruct model: vllm serve Qwen/Qwen2.5-1.5B-Instruct vllm serve BAAI/bge-reranker-v2-m3 vllm serve Qwen/Qwen2.5-1.5B-Instruct --device cpu vllm serve Qwen/Qwen2.5-1.5B-Instruct --enforce_eager vllm serve Qwen/Qwen2.5-1.5B-Instruct --device cpu --enforce_eager ``` ## 异常问题 [Section titled “异常问题”](#异常问题) * `ModuleNotFoundError: No module named 'torch'` ```bash pip install torch ``` * for instructions on how to install GCC 5 or higher. ```bash yum install centos-release-scl yum install devtoolset-11-gcc devtoolset-11-gcc-c++ ``` # arthas使用记录 ## 热部署 [Section titled “热部署”](#热部署) [参考文章](https://arthas.aliyun.com/doc/retransform.html#%E7%BB%93%E5%90%88-jad-mc-%E5%91%BD%E4%BB%A4%E4%BD%BF%E7%94%A8) ```bash # 反编译类到磁盘中 jad --source-only com.mall.domain.enums.ShowFrequencyTypeEnum > /temp/ShowFrequencyTypeEnum.java # 查看对应的类加载器 sc -d com.mall.domain.enums.ShowFrequencyTypeEnum | grep classLoaderHash # 编译类(使用-d指定目录[ -d /tmp]) mc -c 344561e0 /temp/ShowFrequencyTypeEnum.java # 加载类(复制控制台中打印的类全路径加载类)(PS: 使用jad的话, 重新加载的内容会被还原) redefine /com/mall/domain/enums/ShowFrequencyTypeEnum.class xxx.class # 或者使用retransform加载类(PS: 这个命令可以使用jad看到重新加载的内容) retransform /com/mall/domain/enums/ShowFrequencyTypeEnum.class xxx.class # PS: 无法直接上传文件的服务器, 可以使用base64编码上传, 然后使用mc命令进行加载 base64 < Test.class > result.txt base64 -d < result.txt > Test.class ``` # dokku 感觉不是那么好用的样子,不过还是记录一下 [github地址](https://github.com/dokku/dokku) ## 安装 [Section titled “安装”](#安装) ```bash # download the installation script wget -NP . https://dokku.com/bootstrap.sh # run the installer sudo DOKKU_TAG=v0.35.16 bash bootstrap.sh # Configure your server domain dokku domains:set-global dokku.me # and your ssh key to the dokku user PUBLIC_KEY="your-public-key-contents-here" echo "$PUBLIC_KEY" | dokku ssh-keys:add admin # create your first app and you're off! dokku apps:create test-app ``` * docker版安装 [参考地址](https://dokku.com/docs/getting-started/install/docker/) ```bash docker container run -d \ --env DOKKU_HOSTNAME=dokku.me \ --env DOKKU_HOST_ROOT=/var/lib/dokku/home/dokku \ --env DOKKU_LIB_HOST_ROOT=/var/lib/dokku/var/lib/dokku \ --name dokku \ --publish 3022:22 \ --publish 8080:80 \ --publish 8443:443 \ --volume /var/lib/dokku:/mnt/dokku \ --volume /var/run/docker.sock:/var/run/docker.sock \ dokku/dokku:0.35.16 ``` * docker-compose版安装 [参考地址](https://dokku.com/docs/getting-started/install/docker/) ## ssh连接 [Section titled “ssh连接”](#ssh连接) [参考地址](https://dokku.com/docs/getting-started/install/docker/) ```bash docker exec -it dokku bash echo "$CONTENTS_OF_YOUR_PUBLIC_SSH_KEY_HERE" | dokku ssh-keys:add KEY_NAME # Host dokku.docker # HostName 127.0.0.1 # Port 3022 ``` ## 使用 [Section titled “使用”](#使用) ```bash # 创建应用 dokku apps:create my-first-app # 查看信息 dokku apps:report my-first-app # 部署 dokku git:sync --build my-first-app https://github.com/dokku/smoke-test-app.git # 扩容 dokku ps:scale my-first-app web=2 ``` # walle-web 老项目了, 没人维护, 放弃了, 这里只做记录 [GitHub地址](https://github.com/meolu/walle-web) ## 安装 [Section titled “安装”](#安装) [Docker安装(官方)](https://walle-web.io/docs/2/installation_docker.html) ```bash docker-compose up -d && docker-compose logs -f ``` * 初始登录账号如下,开启你的walle 2.0之旅吧:) ```bash 超管:super@walle-web.io \ Walle123 所有者:owner@walle-web.io \ Walle123 负责人:master@walle-web.io \ Walle123 开发者:developer@walle-web.io \ Walle123 访客:reporter@walle-web.io \ Walle123 ``` # 磁盘相关使用记录 ## SFTP可以通过ssh config配置然后通过ssh连接进行自动挂载到本地磁盘吗? [Section titled “SFTP可以通过ssh config配置然后通过ssh连接进行自动挂载到本地磁盘吗?”](#sftp可以通过ssh-config配置然后通过ssh连接进行自动挂载到本地磁盘吗) * 配置文件路径: `~/.ssh/config` ```bash Host myserver HostName example.com User your_username Port 22 IdentityFile ~/.ssh/id_rsa ``` * 使用sshfs挂载远程目录 ```bash # 在macOS上,可以使用Homebrew安装: brew install sshfs # 在Linux上,可以使用包管理器安装: sudo apt install sshfs # Debian/Ubuntu sudo yum install sshfs # CentOS/RHEL # 挂载远程目录 sshfs myserver:/remote/path /local/mountpoint ``` * macos安装sshfs失败的解决方法 ```bash brew install --cask macfuse brew install --cask sshfs-mac ``` * 自动挂载 ```bash # 使用systemd服务(Linux) sudo nano /etc/systemd/system/mnt-myserver.service # 添加以下内容: [Unit] Description=Mount remote directory via SFTP After=network.target [Service] Type=simple ExecStart=/usr/bin/sshfs myserver:/remote/path /local/mountpoint ExecStop=/bin/fusermount -u /local/mountpoint Restart=on-failure [Install] WantedBy=multi-user.target # 启用并启动服务: sudo systemctl daemon-reload sudo systemctl enable mnt-myserver.service sudo systemctl start mnt-myserver.service ``` ```bash # 使用launchd(macOS) nano ~/Library/LaunchAgents/com.example.mountmyserver.plist # 添加以下内容: Label com.example.mountmyserver ProgramArguments /usr/local/bin/sshfs myserver:/remote/path /local/mountpoint RunAtLoad KeepAlive # 加载并启动服务: launchctl load ~/Library/LaunchAgents/com.example.mountmyserver.plist ``` ```bash # 使用autossh方式 # 在macOS上,可以使用Homebrew安装: brew install autossh # 在Linux上,可以使用包管理器安装: sudo apt install autossh # Debian/Ubuntu sudo yum install autossh # CentOS/RHEL # 在~/.bashrc或~/.zshrc中添加以下内容: autossh -M 0 -f -N -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -L 2222:localhost:22 myserver # 使用 autossh 运行 sshfs autossh -M 0 -o "ServerAliveInterval 60" -o "ServerAliveCountMax 3" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null your_username@example.com /usr/bin/sshfs -o allow_other,default_permissions myserver:/remote/path /local/mountpoint # -M 0:禁用 autossh 的监控端口,使用 SSH 内置的保持连接功能。 # -o "ServerAliveInterval 60" 和 -o "ServerAliveCountMax 3":配置 SSH 保持连接的参数。 # -o StrictHostKeyChecking=no 和 -o UserKnownHostsFile=/dev/null:简化连接(注意:在生产环境中应谨慎使用,以避免安全风险)。 # your_username@example.com:替换为您的 SSH 连接信息。 # /usr/bin/sshfs:sshfs 的路径。 # -o allow_other,default_permissions:允许其他用户访问挂载点,并应用默认权限。 # myserver:/remote/path:远程路径。 # /local/mountpoint:本地挂载点。 ``` > 目前使用的方法[CloudMounter破解版](https://macwk.cn/app/1321.html) # NFS使用记录 ## 安装 [Section titled “安装”](#安装) * [macfuse官网](https://macfuse.github.io/) ```bash # macos # 通过上面的网站下载安装macfuse和sshfs # centos服务端 yum install -y nfs-utils # Ubuntu/Debian sudo apt install -y nfs-common # 启动并启用 NFS 服务 systemctl start nfs-server systemctl enable nfs-server systemctl status nfs-server ``` ## 配置 NFS 共享目录 [Section titled “配置 NFS 共享目录”](#配置-nfs-共享目录) ```bash # 编辑 /etc/exports 文件 vim /etc/exports # 示例 # 格式:共享目录 客户端IP(选项) /data/nfs_share 192.168.1.0/24(rw,sync,no_root_squash) # /data/nfs_share:要共享的目录(需提前创建)。 # 192.168.1.0/24:允许访问的客户端 IP 范围(* 表示所有客户端,但不推荐)。 # rw:读写权限(ro 表示只读)。 # sync:同步写入(async 表示异步,但可能丢失数据)。 # no_root_squash:允许客户端 root 用户保持 root 权限(谨慎使用,可能带来安全风险)。 # root_squash(默认):客户端 root 用户映射为 nobody 用户。 # 创建共享目录 mkdir -p /data/nfs_share chmod 755 /data/nfs_share # 可选,NFS 默认用户 chown nfsnobody:nfsnobody /data/nfs_share # 导出 NFS 共享 # 运行以下命令使配置生效: exportfs -ra # 查看当前共享情况: exportfs -v ``` ## 配置防火墙(如果启用) [Section titled “配置防火墙(如果启用)”](#配置防火墙如果启用) ```bash # 如果 CentOS 启用了防火墙(firewalld),需要放行 NFS 相关端口: sudo firewall-cmd --permanent --add-service=nfs sudo firewall-cmd --permanent --add-service=mountd sudo firewall-cmd --permanent --add-service=rpc-bind sudo firewall-cmd --reload # 或者直接放行 NFS 默认端口(不推荐,可能影响安全性): sudo firewall-cmd --permanent --add-port={2049/tcp,2049/udp} sudo firewall-cmd --reload ``` ## 测试 NFS 服务 [Section titled “测试 NFS 服务”](#测试-nfs-服务) ```bash # 在服务器上测试 showmount -e localhost ``` ## 挂载 NFS 共享 [Section titled “挂载 NFS 共享”](#挂载-nfs-共享) ```bash # 确保客户端目录权限 chmod 755 /Users/xx/mount/sshfs mount -t nfs 192.168.1.100:/data/nfs_share /mnt/nfs # (192.168.1.100 是 NFS 服务器 IP,/mnt/nfs 是客户端挂载点) # 使用 mount_nfs(macOS 原生命令) sudo mount_nfs -o resvport xx.intranet.company:/data/nfs_share/dev /Users/xx/mount/sshfs/xx.intranet.company # 检查是否挂载成功: df -h | grep nfs # 如果看到类似 /dev/nfs 的挂载信息,说明成功。 ``` ## 卸载 [Section titled “卸载”](#卸载) ```bash # /mnt/nfs 是客户端挂载点 umount /mnt/nfs ``` ## 常见问题 [Section titled “常见问题”](#常见问题) ```bash # 客户端无法挂载 # 检查 /etc/exports 配置是否正确。 # 确保防火墙放行了 NFS 相关端口。 # 检查 rpcbind 服务是否运行(CentOS 7+ 默认启用): sudo systemctl status rpcbind # 权限问题 # 确保共享目录的权限正确(chmod 755)。 # 如果使用 no_root_squash,确保客户端 root 用户有权限。 ``` * macos挂载显示没权限的问题 ```bash macOS 的 NFS 服务由 launchd 管理,不能直接运行 nfsd start。你需要: ``` # k8s NFS 挂载 ## 安装 NFS 服务端 [Section titled “安装 NFS 服务端”](#安装-nfs-服务端) ```bash ## ubuntu服务端(250926) # 更新软件包列表 sudo apt update sudo apt install -y nfs-kernel-server # 启动 NFS 服务 sudo systemctl start nfs-kernel-server # 设置开机自启 sudo systemctl enable nfs-kernel-server # 检查服务状态(确认是否正常运行) sudo systemctl status nfs-kernel-server ``` ## 配置 NFS 共享目录 [Section titled “配置 NFS 共享目录”](#配置-nfs-共享目录) ```bash # 创建共享目录 sudo mkdir -p /data/k8s/volume/postgresql/postgresql-data # 编辑 exports 文件 sudo nano /etc/exports # 添加如下配置(允许 Kubernetes 节点访问,根据实际网络调整权限) # 172.20.0.0/16:替换为你的 Kubernetes 节点所在的 IP 段(确保包含所有需要挂载的节点)。 # rw:读写权限;sync:同步写入;no_root_squash:允许 root 用户操作(Kubernetes 通常需要此权限)。 # /data/k8s/volume/postgresql/postgresql-data 172.20.0.0/16(rw,sync,no_root_squash,no_subtree_check) # 这里配置上节点的网段和容器网段 /data/k8s/volume/postgresql/postgresql-data 10.0.0.0/16(rw,sync,no_root_squash,no_subtree_check) 172.20.0.0/16(rw,sync,no_root_squash,no_subtree_check) # 保存退出后,重新加载 NFS 配置 sudo exportfs -r # 验证共享是否生效 sudo exportfs -v ``` ## 测试挂载 [Section titled “测试挂载”](#测试挂载) 完成上述步骤后,在需要挂载的 Kubernetes 节点上,重新尝试手动挂载测试: ```bash # 创建临时目录 mkdir -p /tmp/test-nfs # 手动挂载 sudo mount -t nfs master2:/data/k8s/volume/postgresql/postgresql-data /tmp/test-nfs # 若挂载成功,可通过以下命令验证 df -h | grep /tmp/test-nfs # 测试完成后卸载 sudo umount /tmp/test-nfs ``` 如果手动挂载成功,再重启 Kubernetes Pod 即可解决 MountVolume 失败的问题: ```bash # 删除问题 Pod(Kubernetes 会自动重建) kubectl delete pod -n ``` ## 问题 [Section titled “问题”](#问题) Bitnami PostgreSQL 镜像默认使用 UID 1001 和 GID 1001 的非 root 用户运行(而非 root) ```bash # 切换到 NFS 共享目录的父目录 cd /data/k8s/volume/postgresql/ # 查看当前权限(确认是 root:root) ls -ld postgresql-data # 修改属主和属组为 1001(Bitnami 镜像的默认用户) sudo chown -R 1001:1001 postgresql-data/ # 设置目录权限为 700(PostgreSQL 要求数据目录权限严格,避免其他用户访问) sudo chmod -R 700 postgresql-data/ # 确认修改结果(应显示 drwx------ 1001 1001) ls -ld postgresql-data ``` # ossfs使用记录 ## 安装 [Section titled “安装”](#安装) ```bash # Install dependencies (if needed) brew install automake autoconf libtool # Clone the ossfs GitHub repository git clone https://github.com/aliyun/ossfs.git cd ossfs # Build and install ./autogen.sh ./configure make sudo make install ``` # rclone使用记录 [官网](https://rclone.org/) ## 1. 安装 [Section titled “1. 安装”](#1-安装) ```bash # 安装 rclone sudo -v ; curl https://rclone.org/install.sh | sudo bash # 配置 rclone config # GUI(https://rclone.org/gui/) rclone rcd --rc-web-gui # 远程挂载 mkdir -p ~/mount/aliyun-oss-rclone rclone mount alioss: ~/mount/aliyun-oss-rclone --vfs-cache-mode writes & ``` * 高级 ```bash # 创建挂载点目录(如果尚未创建) mkdir -p ~/mount/aliyun-oss-rclone ~/.rclone/logs # 使用 --no-check-links 标志(某些 rclone 版本支持):忽略符号链接(推荐) rclone mount alioss: ~/mount/aliyun-oss-rclone --vfs-cache-mode writes --no-check-links & # 挂载阿里云 OSS 并启用符号链接支持 # --vfs-cache-mode writes 标志:启用 VFS 缓存模式,以提高性能和兼容性。 rclone mount alioss: ~/mount/aliyun-oss-rclone --vfs-cache-mode writes --links --log-level INFO --log-file ~/.rclone/logs/rclone.log & # --allow-other 标志:允许其他用户访问挂载的文件系统。请注意,这需要在 Linux 上使用 FUSE 时设置相应的权限。 rclone mount alioss: ~/mount/aliyun-oss-rclone --vfs-cache-mode writes --allow-other --links --log-level INFO --log-file ~/.rclone/logs/rclone.log & # 2. 启用符号链接支持 # 如果你需要保留并访问 OSS 存储桶中的符号链接,可以在挂载时添加 --links 标志。这将允许 rclone 处理符号链接,但需要注意以下几点: # 性能影响:处理符号链接可能会增加文件系统的开销,尤其是在大量符号链接存在的情况下。 # 安全性:确保符号链接不会导致安全漏洞,特别是在多用户环境中。 ``` ```bash # 使用 --daemon 标志:在后台运行挂载进程 rclone mount alioss: ~/mount/aliyun-oss-rclone --vfs-cache-mode writes --daemon --allow-other --links --log-level INFO --log-file ~/.rclone/logs/rclone.log & # --checkers 8 --transfers 16:增加并发检查器和传输数量,以提高性能。(这个配置跟CPU和带宽有关, 1 Gbps 及以上建议8 到 16, 然后 CPU8核建议8到16, 不超过16, 最后, 通常,--checkers 可以设置为 --transfers 的一半左右,以避免检查过程成为瓶颈。) rclone mount alioss: ~/mount/aliyun-oss-rclone --daemon --allow-other --links --vfs-cache-mode writes --checkers 8 --transfers 16 --log-level INFO --log-file ~/.rclone/logs/rclone.log & ``` # SSHFS 多云端磁盘自动挂载 ## 生产级目录设计 [Section titled “生产级目录设计”](#生产级目录设计) 只保留一个 launchd 服务:`com.fa.cloud-disks`。`_bin/bootstrap.sh` 会按当前 `cloud-disks` 目录生成路径稳定的 `~/Library/LaunchAgents/com.fa.cloud-disks.plist`;该服务周期执行 `_bin/mount_all.sh`,每次扫描所有 `cloud-disks/*/cloud-disk.conf`,所以新增云盘只需要新增一个目录和配置文件,下一轮自动生效,不需要再新增服务。 ```text cloud-disks/ ├── _bin/ │ ├── bootstrap.sh # 生成并加载 ~/Library/LaunchAgents/com.fa.cloud-disks.plist │ ├── mount_all.sh # 扫描所有云盘配置 │ └── sshfs_mount.sh # 单盘 one-shot runner └── fa.intranet.company/ └── cloud-disk.conf # 单盘配置;新增云盘只复制这一类目录 ``` * `cloud-disk.conf` 只需要配置 `REMOTE`;磁盘 ID、默认挂载点、默认日志名都从 SSH host 自动推导。 * `mount_all.sh` 每 60 秒扫描一次 `cloud-disks/*/cloud-disk.conf`。 * 新增云盘目录后无需新增 plist;下一轮扫描自动尝试挂载。 ## 配置字段 [Section titled “配置字段”](#配置字段) 最小配置: ```bash REMOTE="fa.intranet.company:/data/nfs_share/dev" ``` 可选覆盖项: ```bash SSH_PORT="22" IDENTITY_FILE="/Users/fa/.ssh/id_ed25519_sshfs_fa" LOG_DIR="/Users/fa/Library/Logs/cloud-disks" MOUNT_TIMEOUT="30" PROBE_TIMEOUT="5" UNMOUNT_TIMEOUT="10" EXTRA_SSHFS_OPTS="" ``` 配置由 runner 按严格 `KEY="VALUE"` 文本解析,不会被 `source` 执行;`DISK_ID` 从 `REMOTE` 的 SSH host 自动推导;默认挂载点为 `/Users/fa/mount/cloud-disks/${host}`,默认日志为 `/Users/fa/Library/Logs/cloud-disks/${host}.log`。 ## 首次准备 [Section titled “首次准备”](#首次准备) ```bash # 1. 安装能提供 sshfs 命令的 macOS 实现 brew install macos-fuse-t/homebrew-cask/sshfs-fuse-t # 2. 确认 sshfs 位于 runner 允许的绝对路径之一 ls /opt/homebrew/bin/sshfs /usr/local/bin/sshfs # 3. 准备非交互 SSH key mkdir -p ~/.ssh chmod 700 ~/.ssh ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_sshfs_fa -C "cloud-disk-fa.intranet.company" -N "" chmod 600 ~/.ssh/id_ed25519_sshfs_fa # 4. 首次交互连接,接受并固定 host key;如果提示认证失败,先把公钥加入远端 authorized_keys ssh -i ~/.ssh/id_ed25519_sshfs_fa -p 22 fa.intranet.company true # 5. 最终认证检查:不得出现密码、passphrase、host key 交互提示 ssh -i ~/.ssh/id_ed25519_sshfs_fa -o BatchMode=yes -o NumberOfPasswordPrompts=0 -p 22 fa.intranet.company true ``` ## 启用自动挂载 [Section titled “启用自动挂载”](#启用自动挂载) ```bash find ./cloud-disks -name cloud-disk.conf -exec chmod 600 {} \; mkdir -p /Users/fa/mount/cloud-disks /Users/fa/Library/Logs/cloud-disks chmod 700 /Users/fa/Library/Logs/cloud-disks # 本地验证,不会挂载 /bin/zsh ./cloud-disks/_bin/sshfs_mount.sh ./cloud-disks/fa.intranet.company/cloud-disk.conf --self-test # 只需要 bootstrap 一次;脚本会生成路径稳定的 ~/Library/LaunchAgents/com.fa.cloud-disks.plist /bin/zsh ./cloud-disks/_bin/bootstrap.sh ./cloud-disks launchctl print gui/$(id -u)/com.fa.cloud-disks ``` ## 新增云盘 [Section titled “新增云盘”](#新增云盘) ```bash NEW_HOST="aliyun.example.com" mkdir -p "./cloud-disks/${NEW_HOST}" nano "./cloud-disks/${NEW_HOST}/cloud-disk.conf" chmod 600 "./cloud-disks/${NEW_HOST}/cloud-disk.conf" ``` `cloud-disk.conf` 最少只写: ```bash REMOTE="aliyun.example.com:/data" ``` 保存后不需要再 bootstrap;`com.fa.cloud-disks` 下一轮运行时会自动扫描到它。 ## 运维与调试 [Section titled “运维与调试”](#运维与调试) ```bash # 查看全局扫描服务是否已加载,以及上次退出状态 launchctl print gui/$(id -u)/com.fa.cloud-disks # 立即触发一次扫描;新云盘无需重新 bootstrap,用这个命令加速下一轮 launchctl kickstart -k gui/$(id -u)/com.fa.cloud-disks # 卸载全局服务 launchctl bootout gui/$(id -u)/com.fa.cloud-disks # 查看扫描器本身输出;如果没有任何单盘日志,先看这里 mkdir -p /Users/fa/Library/Logs/cloud-disks tail -f /Users/fa/Library/Logs/cloud-disks/scanner.log # 查看单盘日志;文件名默认等于 REMOTE 的 SSH host tail -f /Users/fa/Library/Logs/cloud-disks/fa.intranet.company.log # 手动跑一次扫描,直接看 stderr;适合排查 plist 路径、配置权限、runner 不可读 /bin/zsh ./cloud-disks/_bin/mount_all.sh ./cloud-disks # 手动跑单盘,适合排查 REMOTE、SSH key、sshfs、挂载点和权限问题 /bin/zsh ./cloud-disks/_bin/sshfs_mount.sh ./cloud-disks/fa.intranet.company/cloud-disk.conf # 查看挂载状态 mount | grep cloud-disks ``` 如果 `kickstart` 后没有挂载也没有单盘日志,按顺序查:`launchctl print` 是否显示服务存在、`scanner.log` 是否有 launchd/stdout/stderr 输出、`mount_all.sh` 手动扫描是否能读到配置、`cloud-disk.conf` 是否为当前用户所有且权限不超过 `600`。 ## 手动卸载 [Section titled “手动卸载”](#手动卸载) ```bash # 普通卸载 /usr/sbin/diskutil unmount /Users/fa/mount/cloud-disks/fa.intranet.company # 仍然失败时再手动强制卸载;自动 runner 不会执行强制卸载,避免数据丢失 /usr/sbin/diskutil unmount force /Users/fa/mount/cloud-disks/fa.intranet.company /sbin/umount -f /Users/fa/mount/cloud-disks/fa.intranet.company ``` ## 设计要点 [Section titled “设计要点”](#设计要点) * 只有一个 launchd 服务:`com.fa.cloud-disks`。 * 新增云盘只新增 `cloud-disks/${ssh-host}/cloud-disk.conf`。 * 目录名、挂载点、日志名默认由 `REMOTE` 的 SSH host 推导,不让用户再自定义 `DISK_ID`。 * `mount_all.sh` 负责扫描所有云盘配置;`sshfs_mount.sh` 负责单盘挂载。 * runner 是 one-shot:已挂载且远端来源匹配才退出;未挂载才尝试挂载一次。 * 自动路径只执行普通卸载;普通卸载失败时记录占用进程,不自动强制卸载。 * 日志目录权限为 `700`,日志文件权限为 `600`,且日志目录、日志文件和挂载点路径中不允许出现软链接。 * `allow_other` 不在默认自动路径里;只有明确需要本机其他用户访问挂载目录时才在 `EXTRA_SSHFS_OPTS` 中显式追加。 # fuse-t 用于替代macfuse [官方GitHub地址](https://github.com/macos-fuse-t/fuse-t) ```bash brew install macos-fuse-t/homebrew-cask/fuse-t brew install macos-fuse-t/homebrew-cask/sshfs-fuse-t ``` # Syncthing使用记录 [官网](https://syncthing.net/downloads/) ## 1. 安装 [Section titled “1. 安装”](#1-安装) ```bash # 下载安装(macOS) https://github.com/syncthing/syncthing/releases/download/v1.29.3/syncthing-macos-universal-v1.29.3.zip # linux wget https://github.com/syncthing/syncthing/releases/download/v1.29.3/syncthing-linux-amd64-v1.29.3.tar.gz -O syncthing-linux-amd64-v1.29.3.tar.gz tar -zxf syncthing-linux-amd64-v1.29.3.tar.gz # 启动 cd syncthing-linux-amd64-v1.29.3 ./syncthing ``` # ciphey(一个强大的全自动解密/解码/破解工具,只需输入加密文本就能解密,Star 18K+!) [github地址](https://github.com/ciphey/Ciphey) ## docker使用方式 [Section titled “docker使用方式”](#docker使用方式) ```shell docker run -it --rm registry.cn-hangzhou.aliyuncs.com/iuin/ciphey ``` # 两台主机之间直连 [gitee仓库](https://gitee.com/konyshe/goodlink) ## docker启动 [Section titled “docker启动”](#docker启动) ```bash docker rm goodlink -f # remote docker run -d --name=goodlink --net=host --restart=always registry.cn-shanghai.aliyuncs.com/kony/goodlink --key=nas_202412140928 # local docker run -d --name=goodlink --net=host --restart=always registry.cn-shanghai.aliyuncs.com/kony/goodlink --local=127.0.0.1:18080 --key=nas_202412140928 # 以上两个命令执行后, 如果联通了的话, 那就是通过clash等代理软件可以访问remote端的所有端口 # 目标: 在家里电脑(或出差电脑)浏览器上配置代理: socks5://127.0.0.1:18080, 访问公司所有内网 WEB, 和在公司无异 # 由于remote和local两端默认使用的算法不一样, 如果出现超过10分钟无法连接的情况, 可能是其中一端和默认的算法不兼容, 此时可在local端增加 "--conn=1" 选项, 以调换两端的算法, 就能连接了 ``` ## 命令方式 [Section titled “命令方式”](#命令方式) ```bash chmod +x ./goodlink-linux-amd64 ./goodlink-linux-amd64 --key=nas_202412140928 ./goodlink-linux-arm64 --local=127.0.0.1:18080 --key=nas_202412140928 # 后台执行, 收集日志到文件中(PS: 2>&1 作用为将标准错误重定向到标准输出, 即写入goodlink.log日志文件) nohup ./goodlink-linux-amd64 --key=nas_202412140928 > ./goodlink.log 2>&1 & ``` * 异常 * [参考文章](https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes) ```bash sysctl -w net.core.rmem_max=7500000 sysctl -w net.core.wmem_max=7500000 ``` # goodlink使用记录(v2.1.8) [下载地址](https://gitee.com/konyshe/goodlink/releases/download/v2.1.8/goodlink-linux-amd64-cmd.zip) ```bash # 下载 wget https://gitee.com/konyshe/goodlink/releases/download/v2.1.8/goodlink-linux-amd64-cmd.zip # 添加执行权限 chmod +x ./goodlink-linux-amd64-cmd # local ./goodlink-linux-amd64-cmd --key=AIabJpEIYHMDIA6NBgOBboYJ1 --local # remote ./goodlink-linux-amd64-cmd --key=AIabJpEIYHMDIA6NBgOBboYJ1 --remote # remote(docker) docker rm goodlink -f; docker run -d --name=goodlink --net=host --restart=always registry.cn-shanghai.aliyuncs.com/kony/goodlink --key=AIabJpEIYHMDIA6NBgOBboYJ1 --remote ``` ```bash services: dev-jumpbox: image: registry.cn-shanghai.aliyuncs.com/kony/goodlink container_name: goodlink # network_mode: host command: ./goodlink --key=AIabJpEIYHMDIA6NBgOBboYJ1 --remote environment: TZ: "Asia/Shanghai" extra_hosts: - "me.host:host-gateway" restart: unless-stopped ``` # git使用记录 ## git-lfs使用 [Section titled “git-lfs使用”](#git-lfs使用) [install](https://packagecloud.io/github/git-lfs/install) [如何使用 Git LFS](https://help.aliyun.com/document_detail/206889.html) ```shell # quick install curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash sudo apt-get install git-lfs # 让仓库支持LFS git lfs install # 为了将以示例.bigfile后缀结尾的文件使用Git LFS进行存储,需要执行track命令建立追踪: git lfs track "*.bigfile" # 将普通提交中的大文件迁移到lfs中去(非必须) git lfs migrate import --include="*.bigfile" # 你可以取消继续跟踪某类文件,并将其从cache中清理: git lfs untrack "*.bigfile" git rm --cached "*.bigfile" ``` # gradle相关配置 ## 使用wrapper时 [Section titled “使用wrapper时”](#使用wrapper时) ```bash vim ~/.gradle/wrapper/dists/gradle-8.13-bin/eiq4n3sh1vxscrgcjqudhxaw8/gradle-8.13/init.d/init.gradle ``` # gradle使用 * 文章 * [如何使注解处理器在自定义库中是可传递的?](https://www.volcengine.com/theme/5197725-R-7-1) # interpreter [官方文档](https://docs.openinterpreter.com/getting-started/introduction) ## 安装 [Section titled “安装”](#安装) ```bash pip install open-interpreter ``` ## 使用 [Section titled “使用”](#使用) ```bash interpreter # 使用本地模型 interpreter --model ollama/ # 示例 interpreter --model ollama/qwen2.5-coder ``` # jmap的使用 * 方式一 [java hprof文件如何导出](https://github.com/183461750/doc-record/blob/9ebb07355231f4ae916fdfec741c7e0d044c35ab/materiel/ai/java/java%E4%B8%ADhprof%E6%96%87%E4%BB%B6%E5%A6%82%E4%BD%95%E5%AF%BC%E5%87%BA.md) ```shell # 找pid ps -ef | grep xxl-job-admin # [root@10-0-1-94 data]# jmap -dump:format=b,file=/data/temp/xxl-job-admin.hprof 24663 # 24663: Unable to open socket file: target process not responding or HotSpot VM not loaded # The -F option can be used when the target process is not responding # 示例(PS: AI提供的命令执行失败的话, 加上-F参数) jmap -F -dump:format=b,file=/data/temp/xxl-job-admin.hprof 24663 ``` * 方式二 在启动jar包时候添加参数 [参考文章](https://mp.weixin.qq.com/s/3xCxRxfrz_Y41z7PO-d82g) ```bash -Xms128M -Xmx128M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=../xfg-dev-tech-dump/docs/dump # HeapDumpPath 为你的工程完成路径,到出到 dump 文件夹下。 # 运行方法后,就可以在 docs/dump 就可以看到产生的日志了。 ``` # 远程交互(idea使用gradle与远程服务器间的交互--发布服务与连接arthas) > **v1版本更新内容** Date: 2025-10-13 > > * 操作简单, 一键双击即可 > > * 双击发布指定服务到指定服务器并实时显示日志 > > * idea与日志打印能联动, 点击日志中的类能跳到具体的代码行 > * 异常分组功能, 目前idea只能检测以`Caused by:`开头的异常才进行分组 > > * 双击实时显示指定服务器中的指定服务的日志 > * 日志行为idea控制台能容纳的最大行, 后续有新增日志实时滚动显示 > > * 双击连接指定服务器中的指定服务的arthas ## 后续优化 [Section titled “后续优化”](#后续优化) * arthas的交互体验, 目前只能一次性交互, 需要重新连接 * 如何让远程服务器识别到我在idea中的gradle task console中输入的`^c`的mac快捷键 * 增加远程服务器连接功能 * 自动生成任务, 根据gradle环境属性文件生成对应环境的任务, 这样就只需要添加环境属性文件即可了 * 看看如何把这完整的功能打成插件包, 放到阿里制品库中, 实现通过gradle依赖引入即可拥有这些功能 [相关配置文件地址](https://github.com/183461750/doc-record/blob/main/docs/tools/terminal/publishScript/remote_interaction/v1) ## 使用说明 [Section titled “使用说明”](#使用说明) ```bash vi ~/.ssh/config # 开发环境 Host xxx.dev.iuin HostName 1.0.1.1 User root IdentityFile ~/.ssh/id_ed25519_iu ``` ```bash # 根据项目更新`base.sh`文件中的环境变量 项目目录: LOCAL_BASE_DIR="/Users/fa/dev/projects/IdeaProjects/company/iuin/mall/private-deploy/xxx-sbbc" 远程服务地址: REMOTE_SERVER="xxx.dev.iuin" 远程服务目录前缀: REMOTE_BASE_DIR="/data/xxx" ``` ### 结合gradle使用 [Section titled “结合gradle使用”](#结合gradle使用) 项目根目录的`build.gradle`文件添加相关任务(配置已在上面提供的地址中了) ```bash # 项目根目录执行 mkdir script # 将上面提到的文件夹中的文件添加进去(配置已在上面提供的地址中了) # 并在项目根目录中添加对应的配置文件与引用代码 ``` ```bash # bash ./gradlew :pay-service:publishToTest --info bash ./gradlew :pay-service:publishToTest ``` ![gradle task示例](https://github.com/183461750/doc-record/blob/main/docs/tools/terminal/publishScript/remote_interaction/imgs/gradle_task.png?raw=true) ### 结合arthas命令查看sql, Redis, es命令 [Section titled “结合arthas命令查看sql, Redis, es命令”](#结合arthas命令查看sql-redis-es命令) [参考查看sql命令地址](https://github.com/183461750/doc-record/blob/main/docs/materiel/article/arthas%E6%9F%A5%E7%9C%8Bsql.md) [参考查看sql\_redis\_es命令地址](https://github.com/183461750/doc-record/blob/main/docs/materiel/draft/arthas%E6%9F%A5%E7%9C%8Bsql_redis_es.md) # 远程交互(idea使用gradle与远程服务器间的交互--发布服务与连接arthas) > **v2版本更新内容** Date: 2025-10-20 > > * 自动生成任务, 根据gradle环境属性文件生成对应环境的任务, 这样就只需要添加环境属性文件即可了 ## 后续优化 [Section titled “后续优化”](#后续优化) * arthas的交互体验, 目前只能一次性交互, 需要重新连接 * 如何让远程服务器识别到我在idea中的gradle task console中输入的`^c`的mac快捷键 * 看看如何把这完整的功能打成插件包, 放到阿里制品库中, 实现通过gradle依赖引入即可拥有这些功能 [所有版本功能文档](https://github.com/183461750/doc-record/blob/main/docs/tools/terminal/publishScript/remote_interaction/version.md) ## 使用说明 [Section titled “使用说明”](#使用说明) ```bash vi ~/.ssh/config # 开发环境 Host xxx.dev.iuin HostName 1.0.1.1 User root IdentityFile ~/.ssh/id_ed25519_iu ``` ```bash # 根据项目更新`base.sh`文件中的环境变量 项目目录: LOCAL_BASE_DIR="/Users/fa/dev/projects/IdeaProjects/company/iuin/mall/private-deploy/xxx-sbbc" 远程服务地址: REMOTE_SERVER="xxx.dev.iuin" 远程服务目录前缀: REMOTE_BASE_DIR="/data/xxx" ``` ### 结合gradle使用 [Section titled “结合gradle使用”](#结合gradle使用) [文档GitHub地址](https://github.com/183461750/doc-record/blob/main/docs/tools/terminal/publishScript/remote_interaction/v2/doc.md) 将GitHub中这个文档同级目录中的所有文件及文件夹都复制到项目根目录后刷新gradle即可(点击上面的链接可以直接跳转到对应目录) ```bash # bash ./gradlew :pay-service:publishToTest --info bash ./gradlew :pay-service:publishToTest ``` ![gradle task示例](https://github.com/183461750/doc-record/blob/main/docs/tools/terminal/publishScript/remote_interaction/imgs/gradle_task.png?raw=true) ### 结合arthas命令查看sql, Redis, es命令 [Section titled “结合arthas命令查看sql, Redis, es命令”](#结合arthas命令查看sql-redis-es命令) [参考查看sql命令地址](https://github.com/183461750/doc-record/blob/main/docs/materiel/article/arthas%E6%9F%A5%E7%9C%8Bsql.md) [参考查看sql\_redis\_es命令地址](https://github.com/183461750/doc-record/blob/main/docs/materiel/draft/arthas%E6%9F%A5%E7%9C%8Bsql_redis_es.md) # 版本日志--远程交互(idea使用gradle与远程服务器间的交互--发布服务与连接arthas) ## v1 [Section titled “v1”](#v1) > **v1版本更新内容** Date: 2025-10-13 > > * 操作简单, 一键双击即可 > * 双击发布指定服务到指定服务器并实时显示日志 > * 双击实时显示指定服务器中的指定服务的日志 > * 日志行为idea控制台能容纳的最大行, 后续有新增日志实时滚动显示 > * 双击连接指定服务器中的指定服务的arthas ## v2 [Section titled “v2”](#v2) > **v1版本更新内容** Date: 2025-10-20 > > * 自动生成任务, 根据gradle环境属性文件生成对应环境的任务, 这样就只需要添加环境属性文件即可了 # 远程交互插件(idea使用gradle与远程服务器间的交互--发布服务,查看日志,连接arthas等) ## 使用说明 [Section titled “使用说明”](#使用说明) ```bash vi ~/.ssh/config # 开发环境 Host xxx.dev.iuin HostName 1.0.1.1 User root Port 2222 IdentityFile ~/.ssh/id_ed25519_iu ``` ```bash ssh-copy-id -i ~/.ssh/id_ed25519_iu xxx.dev.iuin ``` ### 结合gradle使用 [Section titled “结合gradle使用”](#结合gradle使用) * 项目根目录下的build.gradle文件中添加以下内容 ```groovy // 项目根目录下的build.gradle文件中添加以下内容 plugins { id 'io.github.iuin8.remote' version '0.1.36' } group = 'com.xxx.xxx' version = '3.0.0' ``` * 项目根目录下的settings.gradle文件中添加以下内容 ```groovy // 项目根目录下的settings.gradle文件中添加以下内容 //gradle插件仓库 pluginManagement { repositories { //本地 mavenLocal() //私服 maven { url 'http://10.11.11.11:1111/repository/maven-public/' allowInsecureProtocol = true } //国内镜像 maven { url 'https://maven.aliyun.com/repository/public' } //gradle官方门户 gradlePluginPortal() //备用 mavenCentral() } } ``` * 配置文件: <项目根目录>/remote-plugin/remote.yml ```yml # 配置文件: {项目根目录}/remote-plugin/remote.yml # Remote plugin configuration example # Supported placeholders: # - ${service} : current Gradle project name # - ${REMOTE_BASE_DIR} : value of remote.base.dir # - ${remote.base.dir} : same as above # Environment configurations # Each environment can have its own settings environments: # Development environment configuration (from gradle-dev.properties) dev: remote: server: xxx.dev.iuin base: dir: /data/xxx # 其他环境, 例如: 测试环境, 生产环境等 test: remote: server: xxx.test.iuin base: dir: /data/xxx # Service ports configuration (previously in service-ports.json) service: ports: order-service: 1111 start: command: $REMOTE_BASE_DIR/$SERVICE_NAME/$SERVICE_NAME-start.sh # command: sudo systemctl restart $SERVICE_NAME env: JAVA_TOOL_OPTIONS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:3$SERVICE_PORT # Configure log file pattern for logTask (logTo) # Default resolves to: ${REMOTE_BASE_DIR}/../logs/${service}.log log: filePattern: ${REMOTE_BASE_DIR}/../logs/${service}.log ``` * 发布服务示例 ```bash # bash ./gradlew :order-service:publish\(dev\) --info bash ./gradlew :order-service:publish\(dev\) # 执行这个命令, 或者直接在idea中双击这个gradle任务, 都可以发布服务到远程服务器 ``` ![gradle task示例](https://github.com/iuin8/doc-record/blob/main/docs/tools/terminal/publishScript/remote_plugin/imgs/gradle_task.png?raw=true) ### 结合arthas命令查看sql, Redis, es命令 [Section titled “结合arthas命令查看sql, Redis, es命令”](#结合arthas命令查看sql-redis-es命令) * [参考查看sql命令地址](https://github.com/iuin8/doc-record/blob/main/docs/materiel/article/arthas%E6%9F%A5%E7%9C%8Bsql.md) * [参考查看sql\_redis\_es命令地址](https://github.com/iuin8/doc-record/blob/main/docs/materiel/draft/arthas%E6%9F%A5%E7%9C%8Bsql_redis_es.md) # 一键快速发布服务 * 支持指定服务的更新 * 支持更新所有服务 * 处理服务的JAR文件上传和远程启动 * 支持配合idea于gradle使用 * 双击即可发布服务到测试环境 [相关配置文件地址](https://github.com/183461750/doc-record/blob/main/docs/tools/terminal/publishScript/update-service) ## 使用说明 [Section titled “使用说明”](#使用说明) ```bash vi ~/.ssh/config # 开发环境 Host xxx.dev.iuin HostName 1.0.1.1 User root IdentityFile ~/.ssh/id_ed25519_iu ``` ```bash # 根据项目更新`base.sh`文件中的环境变量 项目目录: LOCAL_BASE_DIR="/Users/fa/dev/projects/IdeaProjects/company/iuin/mall/private-deploy/xxx-sbbc" 远程服务地址: REMOTE_SERVER="xxx.dev.iuin" 远程服务目录前缀: REMOTE_BASE_DIR="/data/xxx" ``` ```bash chmod +x base.sh bash base.sh ``` ### 结合gradle使用 [Section titled “结合gradle使用”](#结合gradle使用) 项目根目录的`build.gradle`文件添加相关任务(配置已在上面提供的地址中了) ```bash # 项目根目录执行 mkdir script # 将`base.sh`和`update-service.sh`文件添加进去(配置已在上面提供的地址中了) ``` ```bash # bash ./gradlew :pay-service:publishToTest --info bash ./gradlew :pay-service:publishToTest ``` ![gradle示例](https://github.com/183461750/doc-record/blob/main/docs/tools/terminal/publishScript/update-service/imgs/gradle-demo.png?raw=true) # 一键快速发布服务:配合idea与gradle使用 > **v2版本更新** Date: 2025-09-19 > > * 当存在bootJar任务时, 优先使用bootJar打包的jar文件 > * 配合gradle使用时, 不再需要配置`LOCAL_BASE_DIR`环境变量, 改为了自动获取 > * 启动服务命令改为了systemctl(因为新版jar服务被systemctl管理了, 并且systemctl启动配置中指定了www用户启动) * 支持指定服务的更新 * 支持更新所有服务 * 处理服务的JAR文件上传和远程启动 * 支持配合idea与gradle使用 * 双击即可发布服务到测试环境 [相关配置文件地址](https://github.com/183461750/doc-record/blob/main/docs/tools/terminal/publishScript/update-service/v2) ## 使用说明 [Section titled “使用说明”](#使用说明) ```bash vi ~/.ssh/config # 开发环境 Host xxx.dev.iuin HostName 1.0.1.1 User root IdentityFile ~/.ssh/id_ed25519 ``` ```bash # 上传公钥, 开启免密登录(其实就是将公钥`~/.ssh/id_ed25519.pub`内容上传到服务器的`~/.ssh/authorized_keys`文件中, 手动复制进去也行的) ssh-copy-id xxx.dev.iuin -i ~/.ssh/id_ed25519 # 然后, 通过ssh免密登录 ssh xxx.dev.iuin ``` ```bash # 根据项目更新`base.sh`文件中的环境变量 远程服务地址: REMOTE_SERVER="xxx.dev.iuin" 远程服务目录前缀: REMOTE_BASE_DIR="/data/xxx" ``` ```bash chmod +x base.sh bash base.sh ``` ### 结合gradle使用 [Section titled “结合gradle使用”](#结合gradle使用) 项目根目录的`build.gradle`文件添加相关任务(配置已在上面提供的地址中了) ```bash # 项目根目录执行 mkdir script # 将`base.sh`和`update-service.sh`文件添加进去(配置已在上面提供的地址中了) ``` ```bash # bash ./gradlew :pay-service:publishToTest --info bash ./gradlew :pay-service:publishToTest # 或者直接在idea中直接双击这个任务即可 ``` ![gradle示例](https://github.com/183461750/doc-record/blob/main/docs/tools/terminal/publishScript/update-service/imgs/gradle-demo.png?raw=true) # 一键快速发布服务:配合idea与gradle使用(自定义多环境版) > **v3版本更新** Date: 2025-09-28 > > * 简化脚本逻辑 > * 支持配置文件化 > * 支持多环境配置 > * 支持idea与gradle结合使用 [相关配置文件地址](https://github.com/183461750/doc-record/blob/main/docs/tools/terminal/publishScript/update-service/v3) ## 使用说明 [Section titled “使用说明”](#使用说明) [部分说明可参考v2版本](https://github.com/183461750/doc-record/blob/main/docs/tools/terminal/publishScript/update-service/v2/doc.md) ### 添加自定义任务 [Section titled “添加自定义任务”](#添加自定义任务) 修改以下配置去添加自定义任务即可实现多环境发布 * [发布服务任务gradle配置](https://github.com/183461750/doc-record/blob/main/docs/tools/terminal/publishScript/update-service/v3/project/script/publishServerTask.gradle) * [添加对应环境的gradle属性](https://github.com/183461750/doc-record/blob/main/docs/tools/terminal/publishScript/update-service/v3/project/gradle-demo.properties) # 一键快速发布服务:配合idea与gradle使用(自定义多环境版) > **v4版本更新** Date: 2025-09-30 > > * 支持查看实时日志 > * 利用idea的原生功能, 自动区分error日志(独立tab窗口查看), 快速感知都有哪些报错, 方便排查问题 ![service-logs-to-idea-console](https://github.com/183461750/doc-record/blob/main/docs/tools/terminal/publishScript/update-service/imgs/service-logs-to-idea-console-1.png?raw=true) ![service-logs-to-idea-console](https://github.com/183461750/doc-record/blob/main/docs/tools/terminal/publishScript/update-service/imgs/service-logs-to-idea-console-2.png?raw=true) 可惜idea的error日志分组功能, 只内置了以`Caused by:`为前缀去判断, 貌似没有开放自定义配置功能 [全版本更新日志](https://github.com/183461750/doc-record/blob/main/docs/tools/terminal/publishScript/update-service/version.md) [相关配置文件地址](https://github.com/183461750/doc-record/blob/main/docs/tools/terminal/publishScript/update-service/v4) ## 使用说明 [Section titled “使用说明”](#使用说明) [部分说明可参考v2版本](https://github.com/183461750/doc-record/blob/main/docs/tools/terminal/publishScript/update-service/v2/doc.md) ### 添加自定义任务 [Section titled “添加自定义任务”](#添加自定义任务) 修改以下配置去添加自定义任务即可实现多环境发布 * [发布服务任务gradle配置](https://github.com/183461750/doc-record/blob/main/docs/tools/terminal/publishScript/update-service/v4/project/script/publishServerTask.gradle) * [添加对应环境的gradle属性](https://github.com/183461750/doc-record/blob/main/docs/tools/terminal/publishScript/update-service/v4/project/gradle-demo.properties) # 版本更新内容 ## v4版本更新 [Section titled “v4版本更新”](#v4版本更新) > **v4版本更新** Date: 2025-09-30 > > * 支持查看实时日志 > * 利用idea的原生功能, 自动区分error日志(独立tab窗口查看), 快速感知都有哪些报错, 方便排查问题 ## v3版本更新 [Section titled “v3版本更新”](#v3版本更新) > **v3版本更新** Date: 2025-09-28 > > * 简化脚本逻辑 > * 支持配置文件化 > * 支持多环境配置 > * 支持idea与gradle结合使用 ## v2版本更新 [Section titled “v2版本更新”](#v2版本更新) > **v2版本更新** Date: 2025-09-19 > > * 当存在bootJar任务时, 优先使用bootJar打包的jar文件 > * 配合gradle使用时, 不再需要配置`LOCAL_BASE_DIR`环境变量, 改为了自动获取 > * 启动服务命令改为了systemctl(因为新版jar服务被systemctl管理了, 并且systemctl启动配置中指定了www用户启动) ## v1版本更新 [Section titled “v1版本更新”](#v1版本更新) * 支持指定服务的更新 * 支持更新所有服务 * 处理服务的JAR文件上传和远程启动 * 支持配合idea于gradle使用 * 双击即可发布服务到测试环境 # ssh使用记录 ## SSH X11转发使用指南 [Section titled “SSH X11转发使用指南”](#ssh-x11转发使用指南) ```bash # 服务器端配置(远程主机) # 编辑SSH配置文件 sudo nano /etc/ssh/sshd_config # 确保以下参数设置为yes(取消注释并修改) X11Forwarding yes X11DisplayOffset 10 # 开启这个配置就只能通过localhost连接, 其他IP连接会失败 X11UseLocalhost no # 这个看情况是否需要配置 AddressFamily inet # 强制使用IPv4(避免IPv6冲突) # 重启SSH服务使配置生效 sudo systemctl restart sshd ``` ```bash # 客户端连接(本地计算机) # 基础命令(-X:安全模式,-Y:信任模式) ssh -Y username@远程服务器IP # 示例:连接名为"server"的主机 ssh -Y alice@192.168.1.100 ``` ```bash # 连接成功后,直接在远程终端输入图形程序名称即可: # 测试命令(需服务器安装x11-apps) xclock # 显示简单时钟窗口(验证X11是否正常工作) xeyes # 显示跟随鼠标的眼睛动画 gedit # 启动文本编辑器 firefox # 运行浏览器(远程渲染,本地显示) ``` ```bash # 必备条件与故障排查 # 服务器端依赖 # 安装X11相关工具( Ubuntu/Debian ) sudo apt install xauth x11-apps # 高级技巧 # 压缩传输:慢网络环境下启用压缩(-C参数): ssh -YC username@远程IP # -Y信任模式 + -C压缩 # 多窗口管理:结合screen或tmux保持程序后台运行,断开SSH后重连仍可恢复窗口。 ``` ```bash # Mac客户端配置(关键步骤) # 1. 安装XQuartz(Mac必备X服务器) brew install --cask xquartz # 2. 启动XQuartz并配置 open -a XQuartz # 在XQuartz偏好设置→安全性中勾选"允许从网络客户端的连接" # 3. 重启终端后重新连接 ssh -Y pdd.intranet.company # 4. 验证DISPLAY变量 echo $DISPLAY # 应显示类似 localhost:10.0 ``` ```bash # Firefox打不开窗口的问题 # 方式一: 允许Snap访问X11(推荐) # 给Firefox snap添加X11权限 sudo snap connect firefox:x11 # 然后重新启动Firefox firefox # 方式二: 使用非Snap Firefox # 先停止当前的snap firefox sudo snap remove firefox # 安装deb版本的firefox sudo apt update sudo apt install firefox # 测试 firefox # 方法3:临时绕过Snap限制 # 使用--no-sandbox参数启动 firefox --no-sandbox # 或者设置环境变量 export MOZ_DISABLE_CONTENT_SANDBOX=1 firefox # 方法4:使用其他浏览器测试 # 安装并测试Chromium sudo apt install chromium-browser chromium-browser ``` ```bash # chromium-browser打不开窗口的问题 # 修复缺失的共享库 # 安装X11基础依赖库(覆盖libpxbackend相关组件) sudo apt update && sudo apt install -y \ libx11-dev libxext-dev libxrender-dev \ libxtst-dev libxi-dev libxrandr-dev \ libgl1-mesa-glx libglu1-mesa # 检查库文件是否存在 sudo find /usr/lib -name "libpxbackend*" # 为Chromium添加X11权限 sudo snap connect chromium:x11 # 验证权限是否生效 snap interfaces | grep chromium:x11 # 方法5:检查DISPLAY和XAUTHORITY变量 echo $DISPLAY $XAUTHORITY export DISPLAY=localhost:10.0 chromium-browser --no-sandbox --disable-setuid-sandbox # 方法6:完全绕过Snap限制 # 方法A:安装Firefox ESR(非Snap) sudo apt update sudo apt install firefox-esr firefox-esr # 方法B:安装Chromium deb版本 sudo apt install chromium-browser # 方法C:安装其他轻量级浏览器 sudo apt install epiphany-browser # GNOME Web sudo apt install midori # 完全绕过Snap限制 # 临时禁用Snap安全特性 sudo snap set core experimental.xdg-desktop-portal=false # 或者使用--no-sandbox chromium-browser --no-sandbox --disable-setuid-sandbox sudo apt install libgtk-3-0 # 确保GTK库完整 ``` ```bash # 移除 Snap 版 Firefox: sudo snap remove firefox # 添加 Mozilla 官方 PPA 源: sudo add-apt-repository ppa:mozillateam/ppa # 设置优先级(防止系统自动装回 Snap): 执行以下命令创建一个配置文件: echo ' Package: * Pin: release o=LP-PPA-mozillateam Pin-Priority: 1001 ' | sudo tee /etc/apt/preferences.d/mozilla-firefox # 安装原生 Firefox: sudo apt update sudo apt install firefox # 使用独立模式启动 (推荐) firefox --no-remote --new-instance # 或者,如果还是报错,可以尝试指定一个新的 Profile: firefox -P # 重启 Firefox 确保 Profile 生效 sudo killall -9 firefox firefox --no-remote # 创建新配置文件 firefox -CreateProfile "newprofile" # 使用新配置文件启动 firefox -P "newprofile" ``` ```bash # 赋予 Snap 特权权限(不一定成功) sudo snap refresh firefox --channel=stable/pkg-testing # 注意:即便如此,Snap 在处理 X11 转发路径(如 /tmp/.X11-unix)时依然经常出错。 ``` ```bash # 处理OpenGL/图形警告(可选) # 安装OpenGL和Mesa图形库 sudo apt update sudo apt install -y mesa-utils libgl1-mesa-dri libglx-mesa0 # 验证图形配置(非必需,仅用于确认) glxinfo | grep "direct rendering" # 输出"direct rendering: Yes"表示正常 ``` ```bash # 安装原生 Google Chrome (非 Snap 版) wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb sudo apt install ./google-chrome-stable_current_amd64.deb google-chrome --no-sandbox # 强制新实例: (这会给 Chrome 指定一个临时文件夹存放数据,避开所有权限冲突。) google-chrome --user-data-dir=/tmp/chrome-remote --no-sandbox # --disable-gpu: 在远程 SSH 环境下,禁用硬件加速能大幅提高稳定性,减少闪退。 google-chrome --no-sandbox --user-data-dir=/tmp/chrome_test --disable-gpu ``` ```bash # 方法4:使用VNC # 启动VNC服务器 vncserver :1 -geometry 1920x1080 -depth 24 # 从Mac连接 open vnc://master1:5901 ``` # sshuttle [github地址](https://github.com/sshuttle/sshuttle) ```bash # 本地安装 brew install sshuttle # 本地执行命令, 将10.0.1.0/24流量代理到服务器中去 sshuttle --sudoers-user fa -r jump.local.container2222-sshuttle.fa.intranet.company 10.0.1.0/24 ``` * 其他高级自动配置参数 ```bash # --dns 捕获本地 DNS 请求并转发到远程 DNS 服务器 sshuttle --sudoers-user fa -r mac.intranet.company 10.0.10.0/24 --dns --method auto # --auto-hosts 持续扫描远程主机名并在发现时更新本地 /etc/hosts 文件。 # --auto-nets 自动确定路由子网 sshuttle --sudoers-user fa -r mac.intranet.company 10.0.10.0/24 --dns --method auto --auto-hosts --auto-nets # -D后台运行 sshuttle --sudoers-user fa -r mac.intranet.company 10.0.10.0/24 --dns --method auto --auto-hosts --auto-nets -D ``` * 最佳实践 ```bash # 只添加必要配置, 其他均用默认值就好 sshuttle --dns --auto-hosts --auto-nets -D -r mac.intranet.company 10.0.10.0/24 # 多网段, 空格隔开, 一般连接k8s的时候, 是需要将k8s命名空间内部的网段也给代理下, 这样才能正确解析并访问k8s内部域名`svc.cluster.local`(不然就算解析了, IP没有代理, 也访问不了(PS: 这个很重要, 容器网段需要被代理)) sshuttle --dns --auto-hosts --auto-nets -D -r mac.intranet.company 10.0.10.0/24 100.20.0.0/16 100.19.0.0/16 ``` # sshuttle [github地址](https://github.com/sshuttle/sshuttle) ```bash # 安装 brew install sshuttle # 配置本地mac免密 sshuttle --sudoers-no-modify # 执行后会打印配置内容 # 执行以下命令, 将配置内容写入到以下文件中 visudo /etc/sudoers.d/sshuttle_auto # 给指定用户添加配置(指定用户john)(好像指定用户sshuttle的免密才能生效) sudo visudo /etc/sudoers.d/sshuttle_auto_john # 免密使用(fa为免密用户, 需指定)(配合ssh config使用) # PS: 貌似并没有免密 sshuttle --sudoers-user fa -r jump.local.container2222-sshuttle.fa.intranet.company 10.0.1.0/24 ``` ```bash # 其他使用方式示例 sshuttle -r root@10.0.1.90 --python $(which python3) 0.0.0.0/0 # 成功命令(--python指定的是服务端的python命令, 在服务端安装了python3) sshuttle -r root@container2222.fa.intranet.company --python /usr/bin/python3 0.0.0.0/0 # 简化版 sshuttle -r container2222.fa.intranet.company 0.0.0.0/0 # 通过内部mac服务器访问网络, mac中连接了其他公司内部VPN, 一下命令实现让本机也能访问受VPN限制的网络 sshuttle -r mac.intranet.company 0.0.0.0/0 # 可以指定代理的域名 sshuttle -r mac.intranet.company baidu.com ``` ## 高级操作(客户端零配置功能测试失败) [Section titled “高级操作(客户端零配置功能测试失败)”](#高级操作客户端零配置功能测试失败) ### 一、服务器端配置(一次性操作) [Section titled “一、服务器端配置(一次性操作)”](#一服务器端配置一次性操作) #### 1. 创建专用 VPN 用户 [Section titled “1. 创建专用 VPN 用户”](#1-创建专用-vpn-用户) ```bash sudo useradd -r -s /usr/sbin/nologin vpn-tunnel # 创建无登录权限的系统用户 sudo mkdir -p /home/vpn-tunnel/.ssh ``` #### 2. 生成服务器专用密钥对 [Section titled “2. 生成服务器专用密钥对”](#2-生成服务器专用密钥对) ```bash # 在服务器上生成密钥(仅需执行一次) sudo ssh-keygen -t ed25519 -f /etc/ssh/vpn-server-key -N "" -C "vpn-server@company" # 设置权限 sudo chmod 600 /etc/ssh/vpn-server-key* ``` #### 3. 配置自动授权 [Section titled “3. 配置自动授权”](#3-配置自动授权) ```bash # 将公钥设为 VPN 用户的唯一授权方式 sudo cp /etc/ssh/vpn-server-key.pub /home/vpn-tunnel/.ssh/authorized_keys sudo chown -R vpn-tunnel:vpn-tunnel /home/vpn-tunnel/.ssh ``` #### 4. 加固 SSH 配置 (`/etc/ssh/sshd_config`) [Section titled “4. 加固 SSH 配置 (/etc/ssh/sshd\_config)”](#4-加固-ssh-配置-etcsshsshd_config) ```bash # 限制 VPN 用户权限 Match User vpn-tunnel AllowTcpForwarding no # 禁用端口转发 PermitTunnel yes # 允许创建隧道 ForceCommand /bin/false # 禁止执行任何命令 AuthenticationMethods publickey PermitRootLogin no X11Forwarding no AllowAgentForwarding no IdentityFile /etc/ssh/vpn-server-key ``` #### 5. 应用配置 [Section titled “5. 应用配置”](#5-应用配置) ```bash # 重启sshd sudo systemctl restart sshd # 如果没有上面的命令, 则使用下面的方案 # 测试 sshd 配置文件的语法是否正确 /usr/sbin/sshd -t # 发送 HUP 信号, 促使 sshd 进程重新加载配置。 /usr/sbin/sshd -k HUP ``` ### 二、客户端零配置连接方案 [Section titled “二、客户端零配置连接方案”](#二客户端零配置连接方案) #### 方案 B:证书认证(更安全,适合生产环境) [Section titled “方案 B:证书认证(更安全,适合生产环境)”](#方案-b证书认证更安全适合生产环境) ```bash # 在服务器上生成 CA 证书 sudo ssh-keygen -t ed25519 -f /etc/ssh/ca_key -N "" # 签署 VPN 用户证书(有效期 30 天) sudo ssh-keygen -s /etc/ssh/ca_key -I "vpn-cert" -n vpn-tunnel -V +30d /home/vpn-tunnel/.ssh/authorized_keys # 客户端只需信任 CA 公钥即可连接 ``` # 命令行使用记录文档 ## asdf工具(The Multiple Runtime Version Manager多运行时版本管理器) [Section titled “asdf工具(The Multiple Runtime Version Manager多运行时版本管理器)”](#asdf工具the-multiple-runtime-version-manager多运行时版本管理器) asdf 确保团队使用完全相同版本的工具,通过插件系统支持许多工具,并且作为包含在 Shell 配置中的单个 Shell 脚本的简单性和熟悉性。 asdf 不打算成为系统包管理器。它是一个工具版本管理器。仅仅因为您可以为任何工具创建插件并使用 asdf 管理其版本,并不意味着这是该特定工具的最佳行动方案。 [官网地址](https://asdf-vm.com/) ```bash # 安装 git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.14.0 # 配置环境变量 code ~/.zshrc . "$HOME/.asdf/asdf.sh" . "$HOME/.asdf/completions/asdf.bash" # 查询插件 asdf plugin list all | grep python # 安装插件 asdf plugin add python https://github.com/danhper/asdf-python.git # 安装python asdf install python latest # 设置版本 asdf global python latest ``` ## Nix工具 [Section titled “Nix工具”](#nix工具) Nix,纯粹的函数式包管理器 Nix 是一个强大的包管理器,适用于 Linux 和其他 Unix 系统,它使包管理可靠且可重现。 [官网地址](https://nixos.org/nix/) # Algolia DocSearch 配置指南 > 如何为Docusaurus网站配置Algolia搜索功能 ## 简介 [Section titled “简介”](#简介) Algolia DocSearch 是一个强大的文档搜索服务,可以为技术文档网站提供高质量的搜索体验。本指南将帮助你为 Docusaurus 网站配置 Algolia 搜索功能。 ## 步骤 1: 注册 Algolia 账号 [Section titled “步骤 1: 注册 Algolia 账号”](#步骤-1-注册-algolia-账号) 1. 访问 [Algolia 官网](https://www.algolia.com/) 并注册一个账号 2. 登录后,创建一个新的应用程序(Application) 3. 记下你的应用程序 ID(Application ID) ## 步骤 2: 申请 DocSearch 爬虫或设置自己的爬虫 [Section titled “步骤 2: 申请 DocSearch 爬虫或设置自己的爬虫”](#步骤-2-申请-docsearch-爬虫或设置自己的爬虫) ### 选项 A: 申请官方 DocSearch 爬虫(推荐) [Section titled “选项 A: 申请官方 DocSearch 爬虫(推荐)”](#选项-a-申请官方-docsearch-爬虫推荐) 1. 访问 [DocSearch 申请页面](https://docsearch.algolia.com/apply/) 2. 填写表单,提供你的网站 URL 和其他必要信息 3. 提交申请后,Algolia 团队会审核你的申请 4. 如果申请被接受,你将收到一封包含配置信息的电子邮件 ### 选项 B: 设置自己的爬虫 [Section titled “选项 B: 设置自己的爬虫”](#选项-b-设置自己的爬虫) 如果你想自己管理爬虫,可以按照以下步骤操作: 1. 安装 DocSearch 爬虫: ```bash npm install @docsearch/scraper ``` 2. 创建配置文件 `docsearch.config.json`: ```json { "index_name": "你的索引名称", "start_urls": ["https://你的网站域名/"], "sitemap_urls": ["https://你的网站域名/sitemap.xml"], "sitemap_alternate_links": true, "stop_urls": [], "selectors": { "lvl0": { "selector": ".menu__link--sublist.menu__link--active", "global": true, "default_value": "Documentation" }, "lvl1": "article h1", "lvl2": "article h2", "lvl3": "article h3", "lvl4": "article h4", "lvl5": "article h5, article td:first-child", "text": "article p, article li, article td:last-child" }, "strip_chars": " .,;:#", "custom_settings": { "separatorsToIndex": "_", "attributesForFaceting": ["language", "version", "type", "docusaurus_tag"], "attributesToRetrieve": ["hierarchy", "content", "anchor", "url", "url_without_anchor", "type"] } } ``` 3. 在 Algolia 控制面板中创建 API 密钥: * 导航到 API Keys 页面 * 创建一个新的 API 密钥,具有以下权限: * search * addObject * deleteObject * deleteIndex * settings * editSettings 4. 运行爬虫: ```bash docker run -it --env-file=.env -e "CONFIG=$(cat docsearch.config.json | jq -r tostring)" algolia/docsearch-scraper ``` 其中 `.env` 文件包含: ```plaintext APPLICATION_ID=你的应用ID API_KEY=你的管理API密钥 ``` ## 步骤 3: 配置 Docusaurus [Section titled “步骤 3: 配置 Docusaurus”](#步骤-3-配置-docusaurus) 1. 安装 Algolia 搜索主题: ```bash npm install --save @docusaurus/theme-search-algolia ``` 2. 在 `docusaurus.config.ts` 中配置 Algolia: docusaurus.config.ts ```typescript export default { // ... themeConfig: { // ... algolia: { appId: '你的应用ID', // 你的 Algolia 应用 ID apiKey: '你的搜索API密钥', // 你的搜索 API 密钥(非管理 API 密钥) indexName: '你的索引名称', // 你的索引名称 contextualSearch: true, // 启用上下文搜索 // 可选配置 searchParameters: {}, // 附加搜索参数 searchPagePath: 'search', // 搜索页面路径 }, // 注意:启用 Algolia 后,应注释或删除本地搜索配置 // search: { // provider: require.resolve('@easyops-cn/docusaurus-search-local'), // // ... // }, }, }; ``` 3. 重启开发服务器: ```bash npm run start ``` ## 步骤 4: 验证搜索功能 [Section titled “步骤 4: 验证搜索功能”](#步骤-4-验证搜索功能) 1. 访问你的网站 2. 点击导航栏中的搜索图标 3. 输入一些关键词进行搜索 4. 验证搜索结果是否正确显示 ## 常见问题 [Section titled “常见问题”](#常见问题) ### 搜索结果为空 [Section titled “搜索结果为空”](#搜索结果为空) * 确保爬虫已成功运行并索引了你的网站 * 检查 Algolia 控制面板中的索引是否包含数据 * 验证 `apiKey` 是否为搜索 API 密钥(非管理 API 密钥) ### 依赖冲突 [Section titled “依赖冲突”](#依赖冲突) 如果安装 `@docusaurus/theme-search-algolia` 时出现依赖冲突,可以尝试: ```bash # 使用 --legacy-peer-deps 选项 npm install --save @docusaurus/theme-search-algolia --legacy-peer-deps # 或使用 --force 选项 npm install --save @docusaurus/theme-search-algolia --force ``` ### 本地搜索与 Algolia 搜索共存 [Section titled “本地搜索与 Algolia 搜索共存”](#本地搜索与-algolia-搜索共存) 不建议同时启用两种搜索方式,应该选择其中一种: * 如果你希望使用 Algolia,请注释或删除本地搜索配置 * 如果你希望使用本地搜索,请注释或删除 Algolia 配置 ## 资源链接 [Section titled “资源链接”](#资源链接) * [Algolia DocSearch 官方文档](https://docsearch.algolia.com/docs/what-is-docsearch) * [Docusaurus Algolia 搜索文档](https://docusaurus.io/docs/search#using-algolia-docsearch) * [Algolia 控制面板](https://www.algolia.com/dashboard) # filepizza使用记录 [GitHub地址](https://github.com/kern/filepizza) ## 安装 [Section titled “安装”](#安装) ```bash # 直接使用 git clone https://github.com/kern/filepizza.git pnpm install pnpm dev pnpm build pnpm start # docker方式 pnpm docker:build pnpm docker:up pnpm docker:down ``` # GitHub ## gist [Section titled “gist”](#gist) 简单来说,GitHub Gist 是 GitHub 提供的一个“代码片段(Snippet)寄存站”。Gist 就像是一个便签本,专门用来随手记录和分享单份文件、代码片段或小工具配置。 ```bash # 指定版本(每修改一次就有一个版本) https://gist.githubusercontent.com/用户名/GistID/raw/版本号/文件名 # 最新版 https://gist.githubusercontent.com/用户名/GistID/raw/文件名 ``` 刚更新的内容会有CDN 缓存延迟 (GitHub 的 Raw 内容缓存刷新时间通常在 5 分钟 左右。但在某些极端情况下或特定地区,可能会有更久的延迟。) 如果你急需立即生效,可以在 URL 后面加一个随机参数(Cache Buster)来骗过缓存,例如: ```bash https://gist.githubusercontent.com/.../raw/config.yaml?v=20260416 ```