[{"data":1,"prerenderedAt":370},["ShallowReactive",2],{"home-articles":3},[4,18,28,36,47,56,67,78,87,96,110,118,129,140,149,159,169,177,186,195,204,215,225,233,240,244,252,259,267,274,282,289,297,304,314,322,330,337,345,353,361],{"_path":5,"slug":6,"title":7,"description":8,"excerpt":8,"date":9,"tags":10,"type":15,"cover":16,"content":17},"\u002Fknowledge\u002F个人网站icp备案全流程","个人网站icp备案全流程","个人网站 ICP 备案全流程：从买服务器到公安备案的一次性指南","把 ICP 备案到公安备案的所有步骤拆成 6 章，每章带具体命令、配置示例、踩坑记录。 读者能照着走完全流程。","2026-08-26",[11,12,13,14],"建站","ICP 备案","Nginx","HTTPS","article","\u002Fknowledge-assets\u002F个人网站icp备案全流程\u002F公安联网备案网站信息.png","\r\n# 个人网站 ICP 备案全流程：从买服务器到公安备案的一次性指南\r\n\r\n> 写在前面：本文记录了作者 2026 年 7-8 月的一次完整实战。\r\n> 适用对象：个人开发者 \u002F 独立站长，已具备基础 Linux 与命令行能力。\r\n> 不适用：企业备案、境外服务器备案、阿里云备案（流程类似但细节不同）。\r\n\r\n## 目录\r\n\r\n- 第 1 章 · 为什么个人站长必须做 ICP 备案\r\n- 第 2 章 · 准备阶段：三件套\r\n- 第 3 章 · ICP 备案实战（核心章节）\r\n- 第 4 章 · 域名解析\r\n- 第 5 章 · SSL 证书与 Nginx HTTPS（踩坑重灾区）\r\n- 第 6 章 · 公安联网备案（30 日时限）\r\n- 附录 A · 速查命令表\r\n- 附录 B · 名词解释\r\n- 附录 C · 腾讯云控制台链接合集\r\n\r\n## 第 1 章 · 为什么个人站长必须做 ICP 备案\r\n\r\n很多个人开发者的第一步是「写代码 → 部署 → 让别人能访问」。\r\n但你用国内服务器，**域名指向公网 IP 的那一刻起，工信部就要求你完成 ICP 备案**，\r\n否则：\r\n\r\n- **被运营商屏蔽**：域名解析到国内服务器 IP 后，运营商定期核查，未备案域名会被直接 reset 到 127.0.0.1，访问者看到「该网站暂时无法访问」。\r\n- **无法接入 CDN**：阿里云、腾讯云的 CDN 都要求 ICP 备案号作为准入条件，没备案意味着你只能裸跑源站，抗不住流量。\r\n- **被罚款**：根据《非经营性互联网信息服务备案管理办法》，未备案擅自提供服务的，由通信管理局责令限期改正，最高可处 5000 元罚款。个人站点很少真被罚，但被请喝茶、约谈的情况并不罕见。\r\n- **微信生态完全失联**：公众号文章里的外链、微信支付商户、小程序后端域名，都强校验 ICP 备案号。没备案，这些功能用不了。\r\n\r\n> 注：备案只针对「解析到中国大陆境内服务器」的域名。\r\n> 如果你的服务器在境外（香港、台湾、海外），暂不需要 ICP 备案，但访问速度和稳定性会受影响；若站点仍面向中国大陆用户提供服务，建议根据当地规定评估是否完成公安联网备案（见第 6 章）。\r\n\r\nICP 备案号是工信部发放的，公安备案号是公安部发放的——**两个号都要展示在页脚**，缺一不可。流程是：\r\n\r\n```\r\n域名注册 → 实名认证 → 提交 ICP 备案 → 管局审核（7-20 个工作日）\r\n → 拿到 ICP 号 → 30 天内完成公安联网备案 → 拿到公安号 → 页脚展示\r\n```\r\n\r\n> **踩坑提示**：腾讯云备案系统里会显示两个编号，用途不同，不要混淆：\r\n> - **主体备案号**：`粤ICP备2026XXXXXX号`（不带序号后缀，标识备案主体）\r\n> - **网站备案号**：`粤ICP备2026XXXXXX号-N`（带序号后缀，如 `-1`、`-2`…，标识具体网站）\r\n>\r\n> **页脚挂哪个号，按备案地管局要求来，各省并不统一**：\r\n> - **广东省**（本文作者所在地）：管局要求页脚挂**主体备案号**（不带序号后缀）。\r\n> - **其他省份**：管局一般要求挂**网站备案号**（带序号后缀，如 `-1`、`-2`），且不能只挂主体号。\r\n\r\n## 第 2 章 · 准备阶段：三件套\r\n\r\n备案前你需要准备三样东西：**一台国内服务器、一个域名、一个人的实名身份**。少一样都不行。\r\n\r\n### 2.1 选服务器：腾讯云轻量 vs CVM\r\n\r\n对个人开发者，**腾讯云轻量应用服务器** 是首选。理由：\r\n\r\n| 维度 | 轻量应用服务器 | 云服务器 CVM |\r\n|------|---------------|-------------|\r\n| 价格 | 2 核 2G 1年 ≈ 99 元 | 同配置一年 ≈ 484 元 |\r\n| 带宽 | 300GB月流量 4M带宽（够个人站用） | 按流量计费，容易超支 |\r\n| 控制台 | 面向新手，开箱即用 | 专业向，参数多 |\r\n| 备案支持 | 一致 | 一致 |\r\n\r\n实操建议：选 **轻量应用服务器 · 标准型 · 2 核 2G · 4M 带宽 · 系统盘 50G SSD · OpenCloudOS 8.8**。\r\n\r\n> 服务器买完后请立即在腾讯云控制台「实例」页**找到并记录公网 IPv4 地址**\r\n> （形如 `124.221.xx.xx`），后续所有备案填表都要用。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002F个人网站icp备案全流程\u002F轻量服务器购买.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n### 2.2 域名注册与实名认证\r\n\r\n国内注册商必须用已工信部批准的（腾讯云 \u002F 阿里云 \u002F 华为云 \u002F 新网等），境外注册商（Namecheap \u002F GoDaddy）也支持转入后备案，但流程更绕。\r\n\r\n**关键点**：\r\n\r\n- 后缀限制：`.cn` \u002F `.com.cn` \u002F `.中国` 等必须做**域名实名认证**后才能备案；`.com` \u002F `.net` 注册后做 ICP 备案时也会被要求上传实名认证截图。\r\n- 域名所有人必须与备案主体一致：你是个人备案，域名所有者就必须是你本人姓名，不能是公司、不能是别人的身份证。\r\n- 域名有效期至少 3 个月：备案审核期间域名不能过期，否则直接驳回。\r\n\r\n**操作路径**：腾讯云 DNS 解析控制台 → 域名注册 → 搜索想要的域名 →加入清单 → 填写所有者信息（身份证号 + 手机号 + 邮箱）→ 付款。\r\n付款成功后立即在「域名管理」页提交实名认证，上传身份证正反面，1-3 个工作日通过。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002F个人网站icp备案全流程\u002F域名购买查询.png\" alt=\"域名查询\" style=\"zoom:50%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002F个人网站icp备案全流程\u002F我的域名.png\" alt=\"我的域名\" style=\"zoom:50%;\" \u002F>\r\n\r\n## 第 3 章 · ICP 备案实战（核心章节）\r\n\r\n### 3.1 个人备案 5 条红线\r\n\r\n个人 ICP 备案审核严格，以下 5 条为硬性约束，违反任一项均可能被驳回：\r\n\r\n1. **禁止 UGC**：网站不得提供用户注册、评论、投稿、论坛、留言板等用户可自主发布内容的功能。\r\n2. **禁止商业化表述**：网站名称、简介、内容中不得出现「平台」「商城」「交易」「接单」「付费服务」「广告投放」等经营性词汇。\r\n3. **禁止新闻资讯**：不得发布时事新闻、行业资讯、聚合报道等具有新闻属性的内容。\r\n4. **必须展示 ICP 号**：备案号获取后，必须在网站底部显著位置展示，并链接至工信部备案查询页。\r\n5. **内容必须与备案描述一致**：实际网站内容、网站名称、网站简介必须与备案填报信息保持一致。\r\n\r\n### 3.2 站点合规改造的判断方法\r\n\r\n红线知道了，但**怎么快速判断自己的站点有没有违反**？三步走：\r\n\r\n**第一步：跑敏感词扫描**。在你的项目根目录执行：\r\n\r\n```bash\r\n# 以下以 Nuxt\u002FVue 项目为例，其他框架请换对应目录和扩展名\r\ngrep -rn -E '社区|平台|商城|交易|投稿|合作|广告|会员|付费|教育|培训' \\\r\n  --include='*.vue' --include='*.ts' \\\r\n  pages\u002F components\u002F layouts\u002F\r\n```\r\n\r\n期望：没有任何匹配输出。如果有，逐个判断是不是真的违规（\"合作开发\"作为代码注释通常无害，\"广告位招租\"作为页面文案就违规）。\r\n\r\n**第二步：审查 UGC 功能**。检查你的站点有没有：\r\n\r\n- 评论表单 \u002F 留言板 \u002F 论坛 \u002F 投稿入口\r\n- 第三方评论组件（Disqus \u002F Gitalk \u002F Twikoo 等）\r\n- 用户个人主页 \u002F 关注功能\r\n\r\n如果有，**关掉它们**（代码层面 `v-if=\"false\"` 或开关配置）。\r\n\r\n**第三步：核对外链**。检查页脚的备案号链接是否指向 `https:\u002F\u002Fbeian.miit.gov.cn\u002F`。错一个字符都不行。\r\n\r\n> 作为案例，作者把自己的站点做了如下改造（仅供参考）：\r\n> - 文章页评论功能用 `v-if=\"commentsEnabled\"` 关闭（开关置 `false`）\r\n> - About 页「合作 \u002F 投稿」改为「技术交流」\r\n> - 微信群标题从「加入微信交流群」改为「微信联系」\r\n> - 首页统计文案去除\"AI 问答采纳 + 次\"\r\n>\r\n> 你的站点不必照搬这些动作，按上面三步自查即可。\r\n\r\n### 3.3 腾讯云备案系统填报\r\n\r\n入口：https:\u002F\u002Fconsole.cloud.tencent.com\u002Fbeian\r\n\r\n按系统指引依次填：\r\n\r\n1. **主体信息**：备案人姓名、身份证号、手机号、邮箱、应急电话\r\n2. **网站信息**：网站名称、网站首页 URL（`https:\u002F\u002F你的域名`）、服务类型（选\"非交互式\"）\r\n3. **主办者信息**：同主体信息（个人备案）\r\n4. **接入信息**：腾讯云服务器实例\r\n5. **上传资料**：身份证正反面、域名证书、人脸核验视频\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002F个人网站icp备案全流程\u002FICP备案互联网信息.png\" alt=\"腾讯云备案系统&quot;网站信息&quot;页，含网站名称输入框\" style=\"zoom:50%;\" \u002F>\r\n\r\n### 3.4 资料上传 + 人脸核验 + 电话核验 + 短信核验\r\n\r\n**身份证照片**：正反面分别拍，**四角完整、字迹清晰、不能反光**。系统会自动 OCR 识别，所以**不能太歪**。\r\n\r\n**人脸核验**：腾讯云会要求你用手机扫码进入小程序，按提示做几个动作（眨眼、点头）。**不要戴帽子、不要戴口罩、背景干净**。\r\n\r\n**电话核验**：腾讯云会电话核验，询问相关备案信息。**不要拦截骚扰或广告电话，否则会驳回**。\r\n\r\n**短信核验**：管局审核员会发短信到你的手机号，短信里有一个 6 位验证码，需要在 24 小时内回填到工信部系统。**不要拦截备案短信**。\r\n\r\n### 3.5 管局审核：等待周期与驳回 TOP5\r\n\r\n**等待周期**：\r\n\r\n- 腾讯云初审：1-3 个工作日\r\n- 管局终审：7-20 个工作日（广东管局通常较快，7-10 天）\r\n- 整体：最快 7 天拿到号，最慢 20 天\r\n\r\n**驳回原因 TOP5**（按出现频率）：\r\n\r\n| 排名 | 原因 | 解决 |\r\n|------|------|------|\r\n| 1 | 域名实名认证未通过 | 去域名注册商提交实名认证 |\r\n| 2 | 应急电话与负责人手机号相同 | 换一个不同的号码 |\r\n| 3 | 网站内容含敏感词 | 重新跑 grep 扫描 |\r\n| 4 | 身份证照片模糊 | 重拍，确保四角完整 |\r\n| 5 | 腾讯云核验电话被拦截 | 不要拦截骚扰或广告电话 |\r\n\r\n> 驳回后系统会发短信告诉你原因，按提示修改后**不需要重新提交**，直接在原申请上改完重新走流程即可。\r\n\r\n### 3.6 拿到备案号后第一件事\r\n\r\n审核通过后，你会收到一条短信 + 站内信，包含 ICP 备案号。\r\n\r\n**重要：分清主体备案号和网站备案号**。腾讯云备案系统会给你两个号：\r\n\r\n- **主体备案号**：`粤ICP备2026XXXXXX号`（不带序号后缀，标识备案主体）\r\n- **网站备案号**：`粤ICP备2026XXXXXX号-N`（带序号后缀，如 `-1`、`-2`，标识这个具体网站）\r\n\r\n**页脚挂哪个号，取决于备案地管局要求，各省并不统一**：\r\n\r\n- **广东省**：管局要求页脚挂**主体备案号**（不带序号后缀），如 `粤ICP备2026XXXXXX号`。\r\n- **其他省份**：管局要求挂**网站备案号**（带序号后缀），如 `京ICP备2026XXXXXX号-1`，且通常不能只挂主体号。\r\n\r\n本文作者在广东，所以页脚用的是**主体备案号**。如果你不在广东，请先确认你所在省份管局的具体规定，再决定页脚写哪个号。参考：腾讯云《备案号悬挂说明》（https:\u002F\u002Fcloud.tencent.cn\u002Fdocument\u002Fproduct\u002F243\u002F61412）。\r\n\r\n**无论哪个省份，还有两个硬性要求**：\r\n\r\n- **备案号必须可点击**：用 `\u003Ca>` 超链接包裹备案号，链接到工信部备案管理系统 `https:\u002F\u002Fbeian.miit.gov.cn\u002F`。\r\n- **链接必须有效**：确保点击后能正常打开工信部备案查询页，供公众核对。\r\n\r\n> 未按规定悬挂备案号，可能被责令改正并处以五千元以上一万元以下罚款。常见的不合规原因就是\"备案号只是个纯文本、点不了\"，或链接指向错误。\r\n\r\n**为什么只有广东特殊**：广东依据《广东省通信管理局关于网站备案号悬挂及链接有关事项的通知》要求挂**主体备案号**，目的是方便公众通过一个主体号查到该主体名下所有已备案网站的整体情况；其他省份执行的是工信部通用规定，要求挂**当前这个网站**的网站备案号。因此，如果一个主体下备案了多个网站，非广东的每个网站都要在页脚标明自己对应的、带序号的网站备案号。\r\n\r\n拿到备案号后，接下来按顺序做：\r\n1. 第 4 章：把域名解析到服务器公网 IP\r\n2. 第 5 章：配置 HTTPS（SSL 证书 + Nginx）\r\n3. 第 6 章：30 天内完成公安联网备案\r\n4. 把 ICP 备案号和公安备案号一起展示在页脚\r\n\r\n> **踩坑提示**：管局要求备案号必须展示在网站首页底部。但不用急着现在写死代码——\r\n> 等域名解析、HTTPS、公安备案都完成后，一次性把两个号写进页脚更稳妥。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002F个人网站icp备案全流程\u002FICP审核通过短信.jpg\" alt=\"备案审核通过后的短信 \u002F 站内信截图\" style=\"zoom:33%;\" \u002F>\r\n\r\n## 第 4 章 · 域名解析\r\n\r\n拿到 ICP 备案号后，第一步是把域名解析到服务器公网 IP。\r\n\r\n### 4.1 A 记录 vs CNAME 的选择\r\n\r\n| 类型 | 用途 |\r\n|------|------|\r\n| A 记录 | 域名 → IPv4 地址（裸域 `datayte.com` 用这个） |\r\n| CNAME | 域名 → 另一个域名（子域名 `www.datayte.com` 偶尔用） |\r\n\r\n**首次部署建议全用 A 记录**，简单粗暴，便于排查。等要接 CDN 时再切 CNAME。\r\n\r\n### 4.2 腾讯云 DNSPod 配置\r\n\r\n入口：https:\u002F\u002Fconsole.cloud.tencent.com\u002Fcns\r\n\r\n添加两条记录：\r\n\r\n| 主机记录 | 记录类型 | 记录值 |\r\n|---------|---------|--------|\r\n| @ | A | `你的服务器公网 IP` |\r\n| www | A | `你的服务器公网 IP` |\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002F个人网站icp备案全流程\u002FDNS域名解析.png\" alt=\"TODO 图片：DNSPod 解析记录配置页\" style=\"zoom:50%;\" \u002F>\r\n\r\n### 4.3 验证解析生效\r\n\r\n在本地终端跑：\r\n\r\n```bash\r\nnslookup 你的域名\r\nnslookup www.你的域名\r\n```\r\n\r\n两条都应返回你服务器的公网 IP。如果返回的是 CDN 节点 IP，说明你之前用过 CDN，缓存还在；\r\n等几小时再试，或在 DNSPod 控制台临时把 TTL 调到 60 秒。\r\n\r\n> **踩坑提示**：DNS 解析有缓存。修改记录后，全球生效可能要 5-30 分钟。\r\n> 不要刚改完就刷新浏览器看到旧结果就以为是配置错了。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002F个人网站icp备案全流程\u002Fnslookup.png\" alt=\"验证解析生效\" style=\"zoom:50%;\" \u002F>\r\n\r\n## 第 5 章 · SSL 证书与 Nginx HTTPS（踩坑重灾区）\r\n\r\n### 5.1 为什么必须 HTTPS\r\n\r\n- **SEO**：百度 \u002F Google 都明确表示 HTTPS 站点排名优先\r\n- **微信生态**：公众号文章外链、小程序后端域名强制 HTTPS\r\n- **现代浏览器**：Chrome 80+ 把 HTTP 站点明确标记\"不安全\"\r\n\r\n### 5.2 腾讯云免费 DV 证书申请流程\r\n\r\n入口：https:\u002F\u002Fconsole.cloud.tencent.com\u002Fssl\r\n\r\n1. 点击「申请免费证书」\r\n2. 域名绑定：填 `你的域名`（可同时勾选 `www.你的域名`）\r\n3. 验证方式：选「DNS 验证」（最简单）\r\n4. 系统会给你一条 TXT 记录，到 DNSPod 控制台添加\r\n5. 提交申请，等待腾讯云审核\r\n\r\n> 注意：这里只是提交证书申请。审核通过、能下载证书之后，才是第 5.4 节的下载与上传。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002F个人网站icp备案全流程\u002FSSL证书申请.png\" alt=\"TODO 图片：SSL 证书申请页，域名绑定表单\" style=\"zoom:50%;\" \u002F>\r\n\r\n### 5.3 DNS 验证不需要服务器提前开放 443 端口\r\n\r\n> 前置条件：本节需要你已经在 DNSPod 完成第 4 章的 A 记录解析。如果还没解析，先回第 4 章做完。\r\n\r\n腾讯云的免费 DV 证书支持多种验证方式，**个人站长推荐选 DNS 验证**，流程如下：\r\n\r\n1. 在 SSL 证书控制台申请时，验证方式选「DNS 验证」\r\n2. 系统会生成一条 TXT 记录（含主机记录和记录值）\r\n3. 到 DNSPod 控制台添加这条 TXT 记录\r\n4. 等待 DNS 生效，腾讯云会自动检测\r\n\r\n**重要：DNS 验证只检查 DNS 记录，不要求你的服务器提前开放 80 或 443 端口**。也就是说，你完全可以在 Nginx 还没配 HTTPS 之前就申请并通过证书验证。等证书签发后，再按 5.4 节下载并配置到 Nginx 即可。\r\n\r\n如果你选择的是「HTTP 验证」，才需要服务器 80 端口可达，并按要求放置验证文件。\r\n\r\n```bash\r\n# 检查 TXT 记录是否已全球生效（可选）\r\n# 主机记录以腾讯云申请页显示的那条为准（不一定是 _acme-challenge）\r\nnslookup -type=TXT 主机记录.你的域名\r\n```\r\n\r\n> **踩坑提示**：腾讯云的 DNS 验证超时一般是 24 小时。如果反复失败，先检查 DNSPod 里的 TXT 记录主机记录、记录值是否填对，以及是否已全球生效，不要急着重试。\r\n\r\n### 5.4 证书下载与上传\r\n\r\nDNS 验证通过后，在 SSL 证书控制台点击「下载」，选择「Nginx」格式，会得到一个 zip 包，解压后得到两个文件：\r\n\r\n| 文件 | 用途 |\r\n|------|------|\r\n| `你的域名_bundle.crt` | 证书（含域名证书 + 中间证书，**不要拆开**） |\r\n| `你的域名.key` | 私钥 |\r\n\r\n将这两个文件上传到服务器 `\u002Fetc\u002Fnginx\u002Fssl\u002F` 目录：\r\n\r\n```bash\r\n# 在本地执行（把文件上传到服务器）\r\nscp 你的域名_bundle.crt root@你的服务器IP:\u002Fetc\u002Fnginx\u002Fssl\u002F\r\nscp 你的域名.key root@你的服务器IP:\u002Fetc\u002Fnginx\u002Fssl\u002F\r\n\r\n# 在服务器上收紧私钥权限（防止被其他用户读取）\r\nchmod 600 \u002Fetc\u002Fnginx\u002Fssl\u002F你的域名.key\r\n```\r\n\r\n> **踩坑提示**：腾讯云下载的 `.crt` 文件里已经包含了完整证书链（域名证书 + 中间证书合并在一起），直接用这个 `_bundle.crt` 即可，**不要再拆开成单独的根证书和中间证书**。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002F个人网站icp备案全流程\u002FSSL证书下载.png\" alt=\"TODO 图片：腾讯云 SSL 证书下载页，Nginx 格式\" style=\"zoom:50%;\" \u002F>\r\n\r\n### 5.5 完整 server block\r\n\r\n推荐把配置放在 `\u002Fetc\u002Fnginx\u002Fconf.d\u002F你的域名.conf`：\r\n\r\n```nginx\r\n# HTTP → HTTPS 跳转\r\nserver {\r\n    listen 80;\r\n    server_name 你的域名 www.你的域名;\r\n    return 301 https:\u002F\u002F$host$request_uri;\r\n}\r\n\r\n# HTTPS 主站\r\nserver {\r\n    listen 443 ssl;\r\n    server_name 你的域名 www.你的域名;\r\n\r\n    root \u002Fusr\u002Fshare\u002Fnginx\u002Fhtml;\r\n    index index.html;\r\n\r\n    ssl_certificate     \u002Fetc\u002Fnginx\u002Fssl\u002F你的域名_bundle.crt;\r\n    ssl_certificate_key \u002Fetc\u002Fnginx\u002Fssl\u002F你的域名.key;\r\n    ssl_protocols       TLSv1.2 TLSv1.3;\r\n\r\n    access_log \u002Fvar\u002Flog\u002Fnginx\u002F你的域名.access.log;\r\n    error_log  \u002Fvar\u002Flog\u002Fnginx\u002F你的域名.error.log;\r\n\r\n    # 静态文件\r\n    location \u002F {\r\n        try_files $uri $uri\u002F \u002Findex.html;\r\n    }\r\n\r\n    # 后端 API 反向代理，如果没有后台服务可不配\r\n    location \u002Fapi\u002F {\r\n        proxy_pass http:\u002F\u002F127.0.0.1:8080\u002F;\r\n        proxy_set_header Host $host;\r\n        proxy_set_header X-Real-IP $remote_addr;\r\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\r\n        proxy_set_header X-Forwarded-Proto $scheme;\r\n        proxy_buffering off;       # SSE 流式必须\r\n        proxy_read_timeout 300s;\r\n    }\r\n}\r\n```\r\n\r\n> **踩坑提示**：80 跳转必须用 `301`（永久）而不是 `302`（临时）。\r\n> 301 会被浏览器缓存，下次访问直接走 HTTPS；\r\n> 302 每次都要去服务器跳转一次，对 SEO 也不友好。\r\n\r\n### 5.6 Nginx 调试常用命令\r\n\r\n```bash\r\n# 1. 测试配置语法（关键！）\r\nnginx -t\r\n\r\n# 2. 重载配置（不中断服务）\r\nnginx -s reload\r\n\r\n# 3. 看错误日志（启动失败时第一件事）\r\ntail -f \u002Fvar\u002Flog\u002Fnginx\u002F你的域名.error.log\r\n\r\n# 4. 直接检查证书文件\r\nls -la \u002Fetc\u002Fnginx\u002Fssl\u002F\r\n```\r\n\r\n> **踩坑提示**：`nginx -t` 是救命命令。**每次改完配置都先跑它**，\r\n> 确认语法 OK 再 reload，否则一个括号错了整个 Nginx 起不来。\r\n\r\n### 5.7 Chrome 显示\"不安全\"的排查法\r\n\r\n正式证书替换完成后，用浏览器访问 `https:\u002F\u002F你的域名\u002F`，如果仍然显示\"不安全\"，按以下顺序排查：\r\n\r\n**第一步：先清浏览器缓存（最容易被忽略）**\r\n\r\n浏览器会缓存旧证书，即使服务端已换成正式证书，浏览器可能仍在用缓存中的自签证书。\r\n\r\n1. **彻底清理浏览器缓存**（不只是历史记录）\r\n   - Chrome 地址栏输入 `chrome:\u002F\u002Fsettings\u002FclearBrowserData`\r\n   - Edge 地址栏输入 `edge:\u002F\u002Fsettings\u002FclearBrowserData`\r\n   - 勾选「缓存的图片和文件」→ 「全部时间」→ 清除\r\n   - 或者用快捷键 `Ctrl+Shift+Del`\r\n2. **完全退出并重新打开浏览器**（不是关标签页，是整个进程退出）\r\n   - 任务栏右键 Chrome 图标 → \"关闭\" 或 `Ctrl+Shift+Q`（部分版本）\r\n   - 重新启动 Chrome 再访问\r\n\r\n> 作者本人就是在替换正式证书后，Chrome 一直显示\"不安全\"，**清缓存 + 关浏览器重开后才解决**。\r\n> 走了 1 小时冤枉路才发现是缓存问题。先做这步，能省掉 90% 的排查时间。\r\n\r\n如果清缓存重开后仍然\"不安全\"，再走下面两步。\r\n\r\n**第二步：验证证书本身**（看证书内容对不对）\r\n\r\n```bash\r\nopenssl x509 -in \u002Fpath\u002Fto\u002F你的域名_bundle.crt -noout -subject -issuer -dates\r\n```\r\n\r\n期望：\r\n- subject 含 `CN = 你的域名`\r\n- issuer 含 `TrustAsia`\r\n- notBefore \u003C 今天 \u003C notAfter\r\n\r\n如果 issuer 是你域名自己，**说明还是自签证书**，文件没替换对。\r\n\r\n**第三步：再看握手时的链路**（看服务器实际发的链）\r\n\r\n```bash\r\necho | openssl s_client -connect 你的域名:443 -servername 你的域名 2>\u002Fdev\u002Fnull   | grep -E \"Verify return code\"\r\n```\r\n\r\n期望：`Verify return code: 0 (ok)`\r\n\r\n如果返回 `unable to verify the first certificate`，**证书链不完整**，检查 bundle 里是不是少了中间证书。\r\n\r\n**第四步：最后看客户端**（看 Chrome 实际报错）\r\n\r\n无痕窗口打开 `https:\u002F\u002F你的域名\u002F`，按 F12 → Console，看具体错误码：\r\n\r\n- `NET::ERR_CERT_AUTHORITY_INVALID` → 自签或不受信任 CA\r\n- `NET::ERR_CERT_DATE_INVALID` → 时间不在证书有效期内\r\n- `NET::ERR_CERT_COMMON_NAME_INVALID` → 域名不匹配\r\n\r\n## 第 6 章 · 公安联网备案（30 日时限）\r\n\r\n**重要时限**：拿到 ICP 备案号后，**30 日内必须完成公安联网备案**，否则管局可能注销你的 ICP 备案号。\r\n\r\n### 6.1 准备资料\r\n\r\n开始公安联网备案前，先把以下资料准备好，避免填到一半到处找：\r\n\r\n| 资料 | 说明 |\r\n|------|------|\r\n| 域名证书 | 域名注册商后台下载，证明域名属于你 |\r\n| 身份证正反面 | 四角完整、字迹清晰，与 ICP 备案一致 |\r\n| 手持身份证照 | 部分情况会要求上传 |\r\n| ICP 备案号 | 备案成功后拿到的备案号（广东用主体号，其他省份用网站号，与页脚展示一致） |\r\n| 服务器公网 IP | 备案域名指向的服务器 IPv4 地址 |\r\n| 应急联系电话 | 能联系到你的手机号 |\r\n\r\n### 6.2 入口与流程概览\r\n\r\n入口：https:\u002F\u002Fbeian.mps.gov.cn\u002F\r\n\r\n首次访问要先注册账号（用手机号 + 邮箱），然后按顺序走：\r\n\r\n1. 填写开办者主体信息（姓名、身份证号）\r\n2. 添加网站信息（域名、ICP 备案号、服务器 IP 等）\r\n3. 提交审核（一般 3-7 个工作日）\r\n4. **审核通过后**拿到公安备案号（`粤公网安备44XXXXXXXXXXXX号`）\r\n5. 从系统下载公安备案图标\r\n6. 把备案号和图标一起展示在网站页脚\r\n\r\n> 注：腾讯云支持将 ICP 备案信息同步到公安部备案系统，能少填一部分字段。但公安备案仍需单独提交审核，不能直接替代。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002F个人网站icp备案全流程\u002F公安联网备案网站信息.png\" alt=\"TODO 图片：公安部备案系统网站信息填报页\" style=\"zoom:50%;\" \u002F>\r\n\r\n### 6.3 审核通过与公安备案号查询\r\n\r\n提交后约 3-7 个工作日，公安部备案系统会：\r\n\r\n- 发短信通知\r\n- 在系统首页显示你的公安备案号\r\n\r\n查询入口：https:\u002F\u002Fbeian.mps.gov.cn\u002F\r\n\r\n**拿到公安备案号后，才能继续下一步：下载图标并展示到页脚。**\r\n\r\n> **踩坑提示**：公安备案号和 ICP 备案号是**两套独立的号**，分别由公安部、工信部发放。\r\n> 两个号**都要展示在页脚**，缺一不可。\r\n\r\n### 6.4 页脚展示：图标 + 编号\r\n\r\n审核通过后，公安部备案系统会提供备案图标下载链接。下载后得到一个 `.png` 文件，建议改名为 `beian-icon.png`，放到网站静态资源目录（如 Nuxt 的 `public\u002F` 目录），确保能通过 `https:\u002F\u002F你的域名\u002Fbeian-icon.png` 访问到。\r\n\r\n**ICP 备案号也要放页脚**，做成可点击链接指向工信部备案系统（广东用主体号，其他省份用网站号，见 3.6 节）：\r\n\r\n```html\r\n\u003Ca href=\"https:\u002F\u002Fbeian.miit.gov.cn\u002F\">粤ICP备2026XXXXXX号\u003C\u002Fa>\r\n```\r\n\r\n公安备案号在页脚的写法见下。\r\n\r\n**格式硬要求：图标在前，编号在后**。\r\n\r\n正确效果：\r\n\r\n```\r\n[图标] 粤公网安备44XXXXXXXXXXXX号\r\n```\r\n\r\n即：\u003Cimg src=\"\u002Fknowledge-assets\u002F个人网站icp备案全流程\u002F备案图标.png\" alt=\"公安备案图标\" style=\"zoom:50%;\" \u002F> [粤公网安备44XXXXXXXXXXXX号](https:\u002F\u002Fbeian.mps.gov.cn\u002F#\u002Fquery\u002FwebSearch?code=44XXXXXXXXXXXX)\r\n\r\n> 注：`44XXXXXXXXXXXX` 为示例编号，请替换为你从公安部备案系统获得的实际编号。\r\n\r\n正确写法：\r\n\r\n```html\r\n\u003Ca href=\"https:\u002F\u002Fbeian.mps.gov.cn\u002F#\u002Fquery\u002FwebSearch?code=44XXXXXXXXXXXX\">\r\n  \u003Cimg src=\"\u002Fbeian-icon.png\" alt=\"\" width=\"16\" height=\"16\" \u002F>\r\n  粤公网安备44XXXXXXXXXXXX号\r\n\u003C\u002Fa>\r\n```\r\n\r\n> **踩坑提示**：作者第一次提交时忘了加图标，被打回要求补图。\r\n> 建议：**公安备案审核通过后先下载图标，再写页脚代码**，避免来回修改。\r\n\r\n## 附录 A · 速查命令表\r\n\r\n**DNS 验证**\r\n\r\n```bash\r\nnslookup 你的域名\r\nnslookup www.你的域名\r\n```\r\n\r\n**证书查看**\r\n\r\n```bash\r\nopenssl x509 -in bundle.crt -noout -subject -issuer -dates\r\necho | openssl s_client -connect 你的域名:443 -servername 你的域名 2>\u002Fdev\u002Fnull | grep -E \"Verify return code\"\r\n```\r\n\r\n**Nginx 调试**\r\n\r\n```bash\r\nnginx -t\r\nnginx -s reload\r\ntail -f \u002Fvar\u002Flog\u002Fnginx\u002F你的域名.error.log\r\n```\r\n\r\n## 附录 B · 名词解释\r\n\r\n| 术语 | 含义 |\r\n|------|------|\r\n| DNS | 域名系统，把域名翻译成 IP |\r\n| A 记录 | 域名 → IPv4 地址 |\r\n| CNAME | 域名 → 另一个域名（别名） |\r\n| TTL | DNS 缓存时间（秒） |\r\n| TLS | 传输层安全协议（HTTPS 的 S） |\r\n| SSL | TLS 的旧称（现在混用） |\r\n| DV 证书 | 域名验证型 SSL 证书（最便宜、个人站长都用这个） |\r\n| OV \u002F EV 证书 | 组织 \u002F 扩展验证型证书（贵、需要企业资质） |\r\n| SNI | 服务器名称指示，让一个 IP 托管多个 HTTPS 站点 |\r\n| CAA | DNS 记录，指定哪些 CA 可以给你的域名发证书 |\r\n| ICP 备案 | 工信部要求的网站备案 |\r\n| 公安备案 | 公安部要求的联网备案（30 天内） |\r\n| SSG | Static Site Generation，静态站点生成 |\r\n| SSR | Server-Side Rendering，服务端渲染 |\r\n| CDN | Content Delivery Network，内容分发网络 |\r\n| SSE | Server-Sent Events，单向流式推送（聊天常用） |\r\n\r\n## 附录 C · 腾讯云控制台链接合集\r\n\r\n| 用途 | 链接 |\r\n|------|------|\r\n| ICP 备案 | https:\u002F\u002Fconsole.cloud.tencent.com\u002Fbeian |\r\n| 域名管理 | https:\u002F\u002Fconsole.cloud.tencent.com\u002Fdomain |\r\n| DNS 解析（DNSPod） | https:\u002F\u002Fconsole.cloud.tencent.com\u002Fcns |\r\n| SSL 证书 | https:\u002F\u002Fconsole.cloud.tencent.com\u002Fssl |\r\n| 轻量应用服务器 | https:\u002F\u002Fconsole.cloud.tencent.com\u002Flighthouse |\r\n| CVM 云服务器 | https:\u002F\u002Fconsole.cloud.tencent.com\u002Fcvm |\r\n| 工信部备案查询 | https:\u002F\u002Fbeian.miit.gov.cn\u002F |\r\n| 公安部联网备案 | https:\u002F\u002Fbeian.mps.gov.cn\u002F |\r\n",{"_path":19,"slug":20,"title":21,"description":22,"excerpt":22,"date":23,"tags":24,"type":15,"cover":26,"content":27},"\u002Fknowledge\u002Fclaude-code","claude-code","Chrome DevTools MCP 插件安装指南","Chrome DevTools MCP 插件安装指南 插件用途 chrome-devtools-mcp 是 Chrome 官方团队提供的 MCP（Model Context Protocol）插件。它相当于给 Claude Code 装了一个\"浏览器\"，让 AI 可以直接操控 Chrome。 为什么需要它？ 默认情况下","2026-06-15",[25],"Claude",null,"# Chrome DevTools MCP 插件安装指南\n\n## 插件用途\n\nchrome-devtools-mcp 是 Chrome 官方团队提供的 MCP（Model Context Protocol）插件。它相当于给 Claude Code 装了一个\"浏览器\"，让 AI 可以直接操控 Chrome。\n\n### 为什么需要它？\n\n默认情况下，Claude 只能读代码、跑命令，**看不到网页也无法操作网页**。安装这个插件后，Claude 能够：\n\n- 打开网页并\"看到\"页面内容（文本快照）\n- 点击按钮、填写表单、滚动页面\n- 对网页截图\n- 查看网络请求和控制台日志\n- 录制性能分析（Core Web Vitals）\n- 运行 Lighthouse 审计（SEO、可访问性）\n\n### 典型使用场景\n\n| 场景 | 例子 |\n|------|------|\n| 查看网页 | \"打开 xxx 页面，看看上面有什么\" |\n| 截图 | \"打开这个页面并截图\" |\n| 自动化操作 | \"登录这个网站，填写表单并提交\" |\n| 前端调试 | \"查看这个页面的网络请求，为什么加载慢\" |\n| 性能分析 | \"分析首页的 LCP 性能瓶颈\" |\n| 可访问性审计 | \"检查这个页面的无障碍支持情况\" |\n\n---\n\n## 连接模式\n\n插件有两种核心工作方式：\n\n### 模式一：自动启动新浏览器（默认）\n\n**不需要预先打开 Chrome。** 插件自动启动一个新的 Chrome 实例，使用独立的用户数据目录。\n\n- ✅ 简单，开箱即用\n- ✅ 不影响你日常使用的 Chrome\n- ✅ 登录状态、Cookie 等会持久化保留\n- ❌ 与日常 Chrome 的登录状态不共享\n\n### 模式二：连接已有 Chrome\n\n**复用你已经打开的 Chrome。** 需要先以远程调试模式启动 Chrome。\n\n- ✅ 共享你日常 Chrome 的登录状态、Cookie、扩展\n- ✅ 不需要重新登录各种网站\n- ❌ 需要手动启动 Chrome 远程调试端口\n\n在 Windows 上启动带调试端口的 Chrome：\n\n```bash\n\"C:\\Users\\\u003C用户名>\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe\" --remote-debugging-port=9222 --user-data-dir=\"%TEMP%\\chrome-profile\"\n```\n\n> 注意：必须指定 `--user-data-dir` 为非默认目录，否则 Chrome 出于安全策略会拒绝启动远程调试。\n\n---\n\n## 可选配置\n\n以下是常用 CLI 参数，可根据需要配置：\n\n### 基础启动参数\n\n| 参数 | 默认值 | 说明 |\n|------|--------|------|\n| `--headless` | `false` | 无头模式，不显示浏览器窗口（适合 CI\u002F无桌面环境） |\n| `--channel` | `stable` | Chrome 版本：`stable`、`canary`、`beta`、`dev` |\n| `--executablePath` | — | 自定义 Chrome 可执行文件路径 |\n| `--userDataDir` | 自动 | Chrome 用户数据目录（持久化登录状态等） |\n| `--isolated` | `false` | 使用临时用户数据目录，关闭后自动清理（适合 CI） |\n| `--viewport` | — | 初始视口大小，如 `1280x720` |\n\n### 连接已有浏览器\n\n| 参数 | 说明 |\n|------|------|\n| `--browserUrl` \u002F `-u` | 通过 HTTP 连接调试端口，如 `http:\u002F\u002F127.0.0.1:9222` |\n| `--wsEndpoint` \u002F `-w` | 通过 WebSocket 直连，如 `ws:\u002F\u002F127.0.0.1:9222\u002Fdevtools\u002Fbrowser\u002F\u003Cid>` |\n| `--autoConnect` | （Chrome 144+）自动读取 Chrome 用户数据目录中的调试端口 |\n\n### 功能开关\n\n| 参数 | 说明 |\n|------|------|\n| `--slim` | 精简模式，仅加载核心工具集 |\n| `--categoryEmulation` | 设备\u002F网络模拟工具（默认开启） |\n| `--categoryPerformance` | 性能追踪工具（默认开启） |\n| `--categoryNetwork` | 网络检查工具（默认开启） |\n| `--categoryExtensions` | 启用扩展调试能力 |\n\n### 配置示例\n\n**默认模式（启动新 Chrome，有界面，持久化状态）**：无需任何配置，插件已默认此行为。\n\n**无头 + 隔离模式（CI\u002FCD）**：\n\n```json\n{\n  \"mcpServers\": {\n    \"chrome-devtools\": {\n      \"command\": \"npx\",\n      \"args\": [\"chrome-devtools-mcp@latest\", \"--headless=true\", \"--isolated=true\"]\n    }\n  }\n}\n```\n\n**连接已有 Chrome**：\n\n```json\n{\n  \"mcpServers\": {\n    \"chrome-devtools\": {\n      \"command\": \"npx\",\n      \"args\": [\"chrome-devtools-mcp@latest\", \"--browserUrl=http:\u002F\u002F127.0.0.1:9222\"]\n    }\n  }\n}\n```\n\n---\n\n## 安装\n\nClaude Code 内置了插件市场，通过 `\u002Fplugin` 命令即可安装，无需手动 clone 仓库或编写 MCP 配置。\n\n在 Claude Code 中输入：\n\n```\n\u002Fplugin\n```\n\n在弹出的插件列表中搜索 **chrome-devtools-mcp**，点击 Install。\n\n或者用命令行：\n\n```bash\nclaude plugins install chrome-devtools-mcp@claude-plugins-official\n```\n\n安装完成后重启 Claude Code 即可生效。\n\n## 自定义参数配置\n\n`\u002Fplugin` 安装使用默认参数，适合大多数场景。如果需要自定义参数（如无头模式、连接已有 Chrome 等），需要在设置文件中手动添加 `mcpServers` 配置。\n\n### 配置文件位置\n\nClaude Code 有两个级别的设置文件：\n\n| 文件 | 路径 | 作用范围 |\n|------|------|----------|\n| **用户级** | `~\u002F.claude\u002Fsettings.json` | 对所有项目生效 |\n| **项目级** | `\u003C项目根目录>\u002F.claude\u002Fsettings.json` | 仅对当前项目生效 |\n| **用户本地** | `~\u002F.claude\u002Fsettings.local.json` | 本地覆盖，不提交 Git |\n\n> 优先级：项目级 > 用户本地 > 用户级。推荐将 `mcpServers` 配置写在**用户级** `~\u002F.claude\u002Fsettings.json` 中，一次配置到处可用。\n\n### 配置示例\n\n**无头 + 隔离模式（CI\u002FCD）**：\n\n在 `~\u002F.claude\u002Fsettings.json` 中添加：\n\n```json\n{\n  \"mcpServers\": {\n    \"chrome-devtools\": {\n      \"command\": \"npx\",\n      \"args\": [\"chrome-devtools-mcp@latest\", \"--headless=true\", \"--isolated=true\"]\n    }\n  }\n}\n```\n\n**连接已有 Chrome（共享 Cookie 和登录状态）**：\n\n```json\n{\n  \"mcpServers\": {\n    \"chrome-devtools\": {\n      \"command\": \"npx\",\n      \"args\": [\"chrome-devtools-mcp@latest\", \"--browserUrl=http:\u002F\u002F127.0.0.1:9222\"]\n    }\n  }\n}\n```\n\n**自定义 Chrome 路径**：\n\n```json\n{\n  \"mcpServers\": {\n    \"chrome-devtools\": {\n      \"command\": \"npx\",\n      \"args\": [\"chrome-devtools-mcp@latest\", \"--executablePath=C:\\\\你的Chrome路径\\\\chrome.exe\"]\n    }\n  }\n}\n```\n\n### 与 `\u002Fplugin` 安装的关系\n\n| 方式 | 说明 |\n|------|------|\n| `\u002Fplugin` 安装（推荐） | Claude Code 统一管理，默认参数开箱即用 |\n| `\u002Fplugin` + `mcpServers` 配置 | 插件管理安装和更新，配置文件覆盖默认参数 |\n| 纯手动 `mcpServers` 配置 | 自己管理 npx 版本，可能与插件系统冲突 |\n\n> 如果之前启用了 `\u002Fplugin` 中的 chrome-devtools-mcp，同时又在 `settings.json` 中手动配置了同名的 `mcpServers`，两者会冲突。建议只保留一种方式。\n\n### 让 Claude 帮你配置\n\n如果你不确定该怎么写配置，或者不想手动编辑 JSON，可以直接对 Claude 说：\n\n> **\"帮我配置 chrome-devtools-mcp 使用已有 Chrome（已开启 9222 端口）\"**\n\n> **\"帮我配置 chrome-devtools-mcp 为无头模式\"**\n\n> **\"帮我配置 chrome-devtools-mcp，使用指定的 Chrome 路径\"**\n\nClaude 会自动读取当前设置文件，合并配置，避免冲突。\n\n## 验证安装\n\n在 Claude Code 中输入 `\u002Fplugin`，确认 `chrome-devtools-mcp` 显示为绿色 ✓ 已启用状态。\n\n安装后首次调用任意浏览器工具时，插件会自动启动 Chrome。\n\n## 可用工具\n\n| 工具 | 说明 |\n|------|------|\n| `navigate_page` | 导航到 URL、前进后退、刷新 |\n| `take_screenshot` | 全页或元素截图 |\n| `take_snapshot` | 获取页面无障碍树文本快照 |\n| `click` \u002F `fill` \u002F `hover` \u002F `drag` | 元素交互 |\n| `press_key` \u002F `type_text` | 键盘操作 |\n| `evaluate_script` | 执行 JavaScript |\n| `list_network_requests` | 查看网络请求 |\n| `get_network_request` | 获取请求\u002F响应详情 |\n| `list_console_messages` | 查看控制台日志 |\n| `performance_start_trace` \u002F `stop_trace` | 性能录制 |\n| `performance_analyze_insight` | 分析性能洞见 |\n| `lighthouse_audit` | Lighthouse 审计 |\n| `emulate` | 设备\u002F网络模拟 |\n\n## 卸载\n\n```bash\nclaude plugins uninstall chrome-devtools-mcp@claude-plugins-official\n```\n",{"_path":29,"slug":30,"title":31,"description":32,"excerpt":32,"date":23,"tags":33,"type":15,"cover":34,"content":35},"\u002Fknowledge\u002Fclaudecode模式选择指南","claudecode模式选择指南","Claude Code 模式选择指南：Brainstorming 与 Systematic Debugging","Claude Code 模式选择指南：Brainstorming 与 Systematic Debugging 一、Claude Code 四种模式概览 | 模式 | 显示标识 | 核心特征 | 适合场景 | | :------------------ | :------------------- | :-------",[25],"\u002Fknowledge-assets\u002Fclaudecode模式选择指南\u002Fclaude.png","# Claude Code 模式选择指南：Brainstorming 与 Systematic Debugging\r\n\r\n## 一、Claude Code 四种模式概览\r\n\r\n| 模式                | 显示标识             | 核心特征                                   | 适合场景                       |\r\n| :------------------ | :------------------- | :----------------------------------------- | :----------------------------- |\r\n| **默认模式**        | `? for shortcuts`    | 自由对话，AI 提出改动需用户确认            | 通用场景，探索性对话，诊断调试 |\r\n| **Accept Edits On** | `⏵⏵ accept edits on` | AI 可直接应用代码改动，无需逐条确认        | 信任度高的编码任务，追求效率   |\r\n| **Plan Mode**       | `⏸ plan mode on`     | 只读分析，生成计划，不修改代码             | 架构设计、代码审查、风险评估   |\r\n| **Auto Mode**       | `⏵⏵ auto mode on`    | 自动判断：简单任务直接执行，复杂任务先询问 | 效率与安全平衡，适合熟练用户   |\r\n\r\n> 按 `Shift+Tab` 循环切换四种模式。\r\n\r\n------\r\n\r\n## 二、Brainstorming（头脑风暴）模式选择\r\n\r\n### 推荐：**默认模式** (`? for shortcuts`) 或 **Auto Mode**\r\n\r\n| 模式               | 是否适合 | 理由                                                         |\r\n| :----------------- | :------- | :----------------------------------------------------------- |\r\n| ✅ **默认模式**     | 最适合   | 自由对话，AI 通过提问引导思路探索问题，不会急于产出最终代码。这是需求探索和思想碰撞的理想环境。 |\r\n| ✅ **Auto Mode**    | 也适合   | AI 会将头脑风暴判断为“探索性对话”，自动保持谨慎，不会擅自修改代码。适合在探索过程中兼顾一些快速验证。 |\r\n| ⚠️ **Plan Mode**    | 部分可用 | 适合在已有设计草案时用只读方式分析架构，但无法执行任何验证性操作（如运行原型代码）。 |\r\n| ❌ **Accept Edits** | 不适合   | AI 可能过早直接写代码，跳过真正的问题定义和需求澄清阶段，导致方向偏差。 |\r\n\r\n### 为什么 Brainstorming 不适合 Plan Mode？\r\n\r\nPlan Mode 是**只读模式**，其设计目标是“在修改代码前生成执行计划”。而 Brainstorming 的本质是：\r\n\r\n- **对话探索**：需要自由地让 AI 提问、反问、追问\r\n- **需求澄清**：可能需要快速写草稿、画原型（虽然最终不保留）\r\n- **灵活迭代**：思路随时调整，不需要严格的结构化输出\r\n\r\nPlan Mode 的只读约束会限制这种探索性对话的深度。\r\n\r\n### 为什么 Brainstorming 不适合 Accept Edits Mode？\r\n\r\nAccept Edits Mode 的默认行为是“AI 可以直接改代码”。这在头脑风暴阶段是危险的：\r\n\r\n- AI 可能过早跳到“写代码”阶段\r\n- 用户的模糊需求可能被 AI 过度具体化\r\n- 失去了“先想清楚再做”的关键环节\r\n\r\n------\r\n\r\n## 三、Systematic Debugging（系统性调试）模式选择\r\n\r\n### 推荐：**默认模式** (`? for shortcuts`) 或 **Auto Mode**\r\n\r\nSystematic Debugging 的四阶段流程：\r\n\r\n1. **Phase 1: 根因调查** — 复现问题、添加日志、追踪数据流\r\n2. **Phase 2: 模式分析** — 寻找正常工作的对比案例\r\n3. **Phase 3: 假设验证** — 提出单一假设，最小化测试\r\n4. **Phase 4: 实施修复** — 写失败测试，实施修复，验证\r\n\r\n| 模式               | 是否适合 | 理由                                                         |\r\n| :----------------- | :------- | :----------------------------------------------------------- |\r\n| ✅ **默认模式**     | 最适合   | 四阶段调试需要自由对话、执行诊断命令、添加日志、运行测试、验证假设——这些都需要写入和执行权限。 |\r\n| ✅ **Auto Mode**    | 也适合   | AI 可自动判断何时直接加日志\u002F运行测试（Phase 1-3），何时需要汇报。平衡效率与安全。 |\r\n| ⚠️ **Accept Edits** | 谨慎使用 | 仅适合 Phase 4（实施修复）阶段，且根因已完全明确。调试早期绝不可用。 |\r\n| ❌ **Plan Mode**    | 不适合   | 只读模式无法运行测试、添加诊断日志、执行验证命令——这些都是调试的核心动作。 |\r\n\r\n### 为什么 Systematic Debugging 不适合 Plan Mode？\r\n\r\nPlan Mode 的核心约束是**只读**，而 Systematic Debugging 强制要求的动作包括：\r\n\r\n- 添加 `console.log` \u002F 诊断日志\r\n- 运行测试用例\r\n- 执行 `git bisect` 等诊断命令\r\n- 创建最小复现示例\r\n\r\n这些操作在 Plan Mode 下完全被禁止。调试和规划是不同性质的活动：\r\n\r\n- **规划**：在看清楚之前，不动手\r\n- **调试**：在动手过程中，才能看清楚\r\n\r\n### 为什么 Phase 4 可以谨慎使用 Accept Edits？\r\n\r\n当调试进入 Phase 4 时，根因已经完全明确：\r\n\r\n- 你知道要改什么\r\n- 你知道怎么改\r\n- 你有测试用例验证\r\n\r\n此时 Accept Edits Mode 可以加速修复过程。但前提是**根因已确认**，否则风险极大。\r\n\r\n------\r\n\r\n## 四、快速决策指南\r\n\r\n### 按场景选择\r\n\r\ntext\r\n\r\n```\r\n开始任务\r\n    │\r\n    ├─ 需求模糊，需要探索和讨论？\r\n    │   └─ 默认模式 (? for shortcuts)\r\n    │       例：Brainstorming、需求分析、Systematic Debugging Phase 1-3\r\n    │\r\n    ├─ 任务明确，但希望保留控制权？\r\n    │   └─ 默认模式（AI 提出改动需你确认）\r\n    │       例：常规编码、代码审查、学习新代码库\r\n    │\r\n    ├─ 信任 AI，追求效率最大化？\r\n    │   └─ Accept Edits On (⏵⏵)\r\n    │       例：批量重构、脚手架生成、熟悉的领域\r\n    │\r\n    ├─ 只读分析，不想有任何风险？\r\n    │   └─ Plan Mode (⏸)\r\n    │       例：架构评审、安全审计、生成迁移计划\r\n    │\r\n    └─ 想要平衡，让 AI 自己判断？\r\n        └─ Auto Mode (⏵⏵)\r\n            例：日常开发，AI 判断简单改动直接做，复杂改动先请示\r\n```\r\n\r\n\r\n\r\n### 按方法论选择\r\n\r\n| 方法论                   | 首选模式      | 次选模式 | 禁用模式     |\r\n| :----------------------- | :------------ | :------- | :----------- |\r\n| **Brainstorming**        | Default (`?`) | Auto     | Accept Edits |\r\n| **Systematic Debugging** | Default (`?`) | Auto     | Plan Mode    |\r\n\r\n------\r\n\r\n## 五、核心原则总结\r\n\r\n1. **方法论 vs 执行模式是两个维度**\r\n   - Brainstorming 和 Systematic Debugging 是**思维框架**（how to think）\r\n   - Default\u002FPlan\u002FAuto\u002FAccept Edits 是**操作权限模式**（what AI can do）\r\n2. **默认模式是最安全、最通用的起点**\r\n   - 探索性工作：默认模式\r\n   - 诊断性工作：默认模式\r\n   - 不确定用什么模式：默认模式\r\n3. **Plan Mode 只适合“纯规划”场景**\r\n   - 架构评审、迁移计划、风险评估\r\n   - 任何需要“动手”的工作（包括加日志、运行测试）都不适合\r\n4. **Auto Mode 是熟练用户的效率之选**\r\n   - AI 会根据任务复杂度自动判断是否需要确认\r\n   - 探索性对话会自动保持谨慎，简单任务会直接执行\r\n5. **Accept Edits Mode 需要充分信任**\r\n   - 仅适合根因明确、方案清晰、风险可控的场景\r\n   - 绝不要在调试早期或需求模糊时使用\r\n\r\n------\r\n\r\n## 六、实际操作示例\r\n\r\n### 示例 1：Brainstorming 新功能\r\n\r\nbash\r\n\r\n```\r\n$ claude\r\n# 左下角显示: ? for shortcuts\r\n\r\n> 我想给电商网站加一个“猜你喜欢”功能，帮我 brainstorm 一下\r\n# AI 会通过提问引导你思考：数据来源、算法选择、展示位置、冷启动问题等\r\n```\r\n\r\n\r\n\r\n### 示例 2：Systematic Debugging 完整流程\r\n\r\nbash\r\n\r\n```\r\n$ claude\r\n# 左下角显示: ? for shortcuts\r\n\r\n> 运行 npm run build 报错 TypeError: Cannot read properties of undefined...\r\n# AI 自动激活 Systematic Debugging 技能，按 Phase 1→2→3→4 执行\r\n\r\n# Phase 4 时可临时切换提高效率\r\nShift+Tab   # 切换到 Auto Mode 或 Accept Edits\r\n```\r\n\r\n\r\n\r\n### 示例 3：需要只读评审时切换到 Plan Mode\r\n\r\nbash\r\n\r\n```\r\n# 调试到 Phase 3，发现需要重构核心模块\r\nShift+Tab   # 切换到 ⏸ plan mode on\r\n\r\n> 帮我生成一个 ProductList 组件的重构计划，先不要改代码\r\n# AI 生成只读计划，风险评估，依赖分析\r\n\r\nShift+Tab   # 切回默认模式开始执行\r\n```\r\n\r\n\r\n\r\n------\r\n\r\n## 七、常见误区\r\n\r\n| 误区                                  | 正确理解                                                     |\r\n| :------------------------------------ | :----------------------------------------------------------- |\r\n| “Brainstorming 应该在 Plan Mode 下做” | ❌ Plan Mode 是只读规划，不能执行探索性对话所需的快速原型验证 |\r\n| “调试时用 Plan Mode 更安全”           | ❌ 调试需要加日志、跑测试、执行命令，Plan Mode 的只读约束反而阻碍调试 |\r\n| “Auto Mode 会自动选择最优模式”        | ⚠️ Auto Mode 只在“是否确认”上做判断，不会自动切换四种模式     |\r\n| “Accept Edits 适用于所有编码任务”     | ❌ 仅适合根因明确、风险可控的场景，调试早期绝对禁用           |\r\n\r\n------\r\n\r\n",{"_path":37,"slug":38,"title":39,"description":40,"excerpt":40,"date":41,"tags":42,"type":15,"cover":26,"content":46},"\u002Fknowledge\u002Foracle-to-kingbase","oracle-to-kingbase","Oracle 迁移到达梦数据库实践","针对电力行业核心系统的 Oracle 迁移实践, 分享类型映射、SQL 改写和验证经验。","2026-06-05",[43,44,45],"迁移","达梦","信创","\n# Oracle 迁移到达梦数据库实践\n\n电力行业核心系统对数据库稳定性要求极高。本文分享一次 Oracle 迁移到达梦数据库的实战经验。\n\n## 背景\n\n- 源库: Oracle 11g\n- 目标库: 达梦 DM8\n- 数据量: 约 5 TB\n- 停机窗口: 4 小时\n\n## 类型映射\n\n| Oracle | 达梦 |\n|--------|------|\n| NUMBER | NUMBER |\n| VARCHAR2 | VARCHAR |\n| CLOB | TEXT |\n| DATE | TIMESTAMP |\n\n## SQL 改写注意点\n\n- `ROWNUM` 需要改写为 `LIMIT`\n- `NVL` 对应 `IFNULL`\n- `SYSDATE` 对应 `CURRENT_TIMESTAMP`\n\n```sql\n-- Oracle\nSELECT * FROM users WHERE ROWNUM \u003C= 10;\n\n-- 达梦\nSELECT * FROM users LIMIT 10;\n```\n\n## 验证\n\n迁移完成后, 使用 DB-Compare 生成差异报告, 确认无 schema 遗漏。\n",{"_path":48,"slug":49,"title":50,"description":51,"excerpt":51,"date":52,"tags":53,"type":15,"cover":26,"content":55},"\u002Fknowledge\u002Fintro","intro","数据库迁移入门","介绍企业数据库迁移的常见挑战与应对策略, 适合初次接触迁移项目的读者。","2026-06-01",[43,54],"入门","\n# 数据库迁移入门\n\n企业数据库迁移是高风险、高复杂度的工程活动。本文介绍常见挑战与应对策略。\n\n## 常见挑战\n\n- 数据量大, 停机窗口短\n- 异构数据库之间的类型映射差异\n- 应用层 SQL 方言不兼容\n- 回滚方案设计不足\n\n## 应对策略\n\n1. **充分评估**: 使用结构对比工具梳理 schema 差异。\n2. **分批迁移**: 先迁移非核心表, 验证链路稳定后再切核心表。\n3. **双写并行**: 迁移期间新旧库双写, 便于回滚。\n4. **自动化校验**: 迁移结束后做行数、关键字段 checksum 校验。\n\n```java\npublic class MigrationChecker {\n    public boolean checksum(String table) {\n        \u002F\u002F 计算源库和目标库 checksum\n        return true;\n    }\n}\n```\n\n更多实战内容请关注后续专栏。\n",{"_path":57,"slug":58,"title":59,"description":60,"excerpt":60,"date":61,"tags":62,"type":15,"cover":65,"content":66},"\u002Fknowledge\u002Fopenclaw","openclaw","OpenClaw入门使用教程","OpenClaw入门使用教程 1 简介 ​ OpenClaw官网：https:\u002F\u002Fopenclaw.ai\u002F 2 安装 2.1 安装环境准备 - Node环境准备 - 2.2 一键安装 2.3 手动安装","2026-03-28",[63,64],"Node.js","OpenClaw","\u002Fknowledge-assets\u002Fopenclaw\u002Fpowershell-set.png","# OpenClaw入门使用教程\r\n\r\n# 1\t简介\r\n\r\n​\t\t[OpenClaw官网](https:\u002F\u002Fopenclaw.ai\u002F)：https:\u002F\u002Fopenclaw.ai\u002F\r\n\r\n\r\n\r\n# 2\t安装\r\n\r\n## 2.1\t安装环境准备\r\n\r\n- Node环境准备\r\n- \r\n\r\n```shell\r\n# 以管理员身份打开 PowerShell 窗口\r\n# 允许当前用户运行本地和下载脚本\r\nSet-ExecutionPolicy RemoteSigned -Scope CurrentUser\r\n\r\n# 临时跳过当前窗口的脚本执行限制\r\nSet-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Fpowershell-set.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n\r\n\r\n## 2.2\t一键安装\r\n\r\n```SHELL\r\npowershell -c \"irm https:\u002F\u002Fopenclaw.ai\u002Finstall.ps1 | iex\"\r\n```\r\n\r\n\r\n\r\n## 2.3\t手动安装\r\n\r\n```shell\r\n# 安装 openClaw\r\nnpm install -g openclaw\r\n# 初始化配置\r\nopenclaw onboard\r\n# 初始化配置——设置为守护进程，开机自启，则添加 --install-daemon\r\nopenclaw onboard --install-daemon\r\n\r\n\r\n# 启动服务-启动网关 (Gateway) 默认端口：18789\r\nopenclaw gateway start\r\n\r\n# 打开管理页面 (Dashboard) —— http:\u002F\u002F127.0.0.1:18789\r\nopenclaw dashboard\r\n\r\n# 检查网关运行状态\r\nopenclaw gateway status\r\n```\r\n\r\n\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Finstall-1.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n等待安装步骤完成。\r\n\r\n安装完成后，进入配置页面。\r\n\r\n风险告知选择 YES，引导模式选择`QuickStart`(快速启动)\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Finstall-2.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n### 配置 AI 模型 API Key\r\n\r\nOpenClaw 需要连接到大语言模型才能工作。Openclaw 比较费token，国外模型成本高，门槛也高，这里我选择国内的智谱。\r\n\r\n> 如果没有智谱的API Key，点击官方地址自己注册账号获取API key：https:\u002F\u002Fwww.bigmodel.cn\u002Flogin\r\n\r\n选择模型：我这里选择智普模型（新用户注册免费赠送2000万token体验包）\r\n\r\n[智普官网](https:\u002F\u002Fwww.bigmodel.cn\u002Flogin)，模型注册参考另外：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Fmodel-1.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Fmodel-2.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Finstall-3.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Finstall-model.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Finstall-model-2.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n### 选择 AI 模型\r\n\r\n因为我是新用户，领的是【新用户专享】1200万GLM-4.5-Air资源包，这里就选择了对应的。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Finstall-model-3.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n\r\n\r\n连接即时通讯平台\r\n\r\n我这里选择先跳过，后面在安装。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Finstall-channel.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\r\n\r\n搜索引擎\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Finstall-search.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\r\n\r\n\r\n\r\n### 选择Skills\r\n\r\n这里也选择：No，暂不配置，后面通过UI界面进行配置：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Finstall-skills.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n接下来，设置会话的保持方式。（用空格键选择）\r\n\r\n操作步骤：先敲**空格**，表示选中当前项，再敲回车键\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Finstall-hooks.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n### 启动服务并打开UI界面\r\n\r\n此时它会自动再打开一个命令窗口来启动服务:\r\n\r\n\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Fopenclaw-gateway.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Finstall-open.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n浏览器自动打开Web UI界面：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Foepnclaw-chat.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n测试\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Foepnclaw-chat-1.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\r\n\r\n\r\n\r\n# QQ接入openClaw流程\r\n\r\n1\t登陆QQ平台\r\n\r\n[qqbot](https:\u002F\u002Fq.qq.com\u002Fqqbot\u002Fopenclaw\u002Flogin.html): https:\u002F\u002Fq.qq.com\u002Fqqbot\u002Fopenclaw\u002Flogin.html\r\n\r\n2\t手机扫码登陆，在手机QQ扫码后选择同意，即完成注册，进入QQ机器人配置页。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Fqq-0.png\" style=\"zoom:30%;\" \u002F>\r\n\r\n3\t创建机器人，在QQ开放平台的QQ机器人页面，可以单击**创建机器人**，即可直接新建一个QQ机器人。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Fqq-1.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n机器人创建完成后，在页面中找到 “AppID” 和 “AppSecret” 两个参数，分别点击右侧 “复制” 按钮，将其保存到个人记事本或备忘录中（请妥善保存勿泄露，注意数据安全），后续步骤中需要使用。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Fqq-2.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n回到QQ软件，可以看到新建的QQ机器人已经被添加至您的消息列表中，并将会发送第一条消息。\r\n\r\n\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Fqq-3.jpg\" style=\"zoom:50%;\" \u002F>\r\n\r\n此时您还不能与该机器人正常进行对话，会提示“该机器人去火星了，稍后再试吧”，因为QQ机器人此时尚未与之前部署的OpenClaw应用打通。您需要继续后面的步骤，为OpenClaw应用配置QQ机器人的AppID和AppSecret。\r\n\r\n接下来需要为已经完成部署的OpenClaw配置模型和通道（即Channel，如QQ）。\r\n\r\n\r\n\r\n配置QQ插件\r\n创建好机器人以后，我们就可以安装QQ插件了。目前OpenClaw官方暂时不支持QQ，所以需要先安装插件才行。\r\n\r\n用管理员权限打开PowerShell终端，输入如下命令：\r\n\r\nopenClaw原生接入流程：\r\n\r\n```shell\r\n1.安装OpenClaw开源社区QQBot插件\r\nopenclaw plugins install @tencent-connect\u002Fopenclaw-qqbot@latest\r\n2.配置绑定当前QQ机器人\r\nopenclaw channels add --channel qqbot --token \"1903703697:gIivugEYeXCdrvlO\"\r\n3.重启本地OpenClaw服务\r\nopenclaw gateway restart\r\n```\r\n\r\n\r\n\r\n注意：\r\n\r\n```shell\r\n# 如果安装报下面的错误，等几分钟后再重试。\r\nPS C:\\Windows\\system32> openclaw plugins install @tencent-connect\u002Fopenclaw-qqbot@latest\r\n\r\n🦞 OpenClaw 2026.3.24 (cff6dc9) — The only open-source project where the mascot could eat the competition.\r\n\r\nResolving clawhub:@tencent-connect\u002Fopenclaw-qqbot@latest…\r\nClawHub \u002Fapi\u002Fv1\u002Fpackages\u002F%40tencent-connect%2Fopenclaw-qqbot failed (429): Rate limit exceeded\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Fopenclaw-qqbot.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n\r\n\r\n\r\n\r\n# 3\t配置\r\n\r\n```shell\r\n# 打开openclaw配置\r\nOpenClaw configure\r\n```\r\n\r\n\r\n\r\n# 4\t安装skill\r\n\r\n```shell\r\n# 使用 npm 全局安装 ClawHub CLI\r\nnpm install -g clawhub@latest\r\n# 验证安装结果\r\nclawhub -V\r\n\r\n# 登录 ClawHub（可选，但推荐）\r\n# 登录后可以访问更多高级技能，提升请求频率限制：\r\n# 使用 CLI Token 登录（从 ClawHub 官网获取）\r\nclawhub login --token 你的CLI_TOKEN\r\n# 验证登录状态\r\nclawhub whoami\r\n\r\n# 搜索技能\r\nclawhub search sonoscli\r\n# 安装技能\r\nclawhub install sonoscli\r\n# 列出已安装的技能\r\nclawhub list\r\n# 更新技能\r\nclawhub update sonoscli\r\n# 卸载技能\r\nclawhub uninstall sonoscli\r\n\r\n```\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n# 5\t心跳任务\r\n\r\n在实际使⽤中，Heartbeat的应⽤远超以上⽰例，你可以通过合理设计⼼跳规则，让OpenClaw持续在后台完成各种重复性⼯作。\r\n\r\n例如，定期整理⾏业资讯就是⼀个⾮常典型的应⽤场景。你可以设置⼼跳规则，让OpenClaw在每次⼼跳触发时检查指定的信息源，如果发现新的重要信息，就⾃动⽣成摘要并发送到⻜书。这样⼀来，你每天打开⻜书时，就能看到整理好的⾏业动态。\r\n\r\nHeartbeat还可以⽤于⾃动化资料积累。例如，你可以让OpenClaw在每次⼼跳时搜索某个主题的最新⽂章，并把有价值的内容保存到本地。随着时间推移，系统就会逐渐积累⼀份持续更新的资料库。\r\n\r\n在内容创作领域，Heartbeat也⾮常实⽤。例如，可以设置规则，让OpenClaw定期整理热点话题、提取潜在选题，或者⽣成内容灵感清单。这样，当你需要写作时，系统已经提前帮你准备好⼀批素材。\r\n\r\n可以说，当Heartbeat被合理利⽤之后，OpenClaw就不再只是⼀个被动响应的⼯具，而变成了⼀个在后台持续运⾏的⾃动化系统。它会不断巡视环境、检查信息、整理数据，并在必要时主动提醒⽤⼾。随着规则逐渐完善，这种⾃动化能⼒也会越来越强。\r\n\r\n# 6\t设置定时任务\r\n\r\n怎么让它每天⾃动给你发早报\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n# 7\t多agent配置\r\n\r\n为每个智能体创建 workspace\r\n\r\n使用向导，或手动创建 workspace：\r\n\r\n```\r\nopenclaw agents add coding\r\nopenclaw agents add social\r\n```\r\n\r\n每个智能体都会获得自己的 workspace，其中包含 `SOUL.md`、`AGENTS.md` 和可选的 `USER.md`，以及位于 `~\u002F.openclaw\u002Fagents\u002F\u003CagentId>` 下的专用 `agentDir` 和会话存储。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Fagents-1.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n配置模型\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Fagents-2.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fopenclaw\u002Fagents-3.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n配置通道\r\n\r\n```shell\r\n◇  Channel status ───────────────────────────────╮\r\n│                                                │\r\n│  Feishu: connected as OpenClaw                 │\r\n│  Google Chat: not configured                   │\r\n│  Nostr: not configured                         │\r\n│  Microsoft Teams: not configured               │\r\n│  Mattermost: not configured                    │\r\n│  Nextcloud Talk: not configured                │\r\n│  .......\r\n│  Slack: installed                              │\r\n│  Telegram: installed                           │\r\n│  Twitch: installed                             │\r\n│  WhatsApp: installed                           │\r\n│                                                │\r\n├────────────────────────────────────────────────╯\r\n◇  Configure chat channels now?\r\n│  Yes\r\n│\r\n◇  How channels work \r\n│\r\n◇  Select a channel\r\n│  Feishu\u002FLark (飞书)\r\n◇  Feishu already configured. What do you want to do?\r\n│  Modify settings\r\n│\r\n◇  We found an existing bot (App ID: cli_a9551cf4f34a5bb4). Use it for this setup?\r\n│  No\r\n│\r\n◇  Feishu scan-to-create ───────────────────────╮\r\n│                                               │\r\n│  Scan the QR with Lark\u002FFeishu on your phone.  │\r\n│                                               │\r\n├───────────────────────────────────────────────╯\r\n扫描二维码 快速创建机器人\r\n\r\n│\r\n◇  Scan completed.\r\n│\r\n◇  Group chat policy\r\n│  Allowlist - only respond in specific groups\r\n│\r\n◇  Bot configured.\r\n[info]: [ 'client ready' ]\r\n│\r\n◇  Select a channel\r\n│  Finished\r\n│\r\n◇  Selected channels ──────────────────────────────────────────╮\r\n│                                                              │\r\n│  Feishu — 飞书\u002FLark enterprise messaging. Docs:              │\r\n│  feishu  │\r\n│                                                              │\r\n├──────────────────────────────────────────────────────────────╯\r\n│\r\n◇  Configure DM access policies now? (default: pairing)\r\n│  Yes\r\n│\r\n◇  Feishu DM access ─────────────────────────────────────────────────────────────────────────╮\r\n│                                                                                            │\r\n│  Default: pairing (unknown DMs get a pairing code).                                        │\r\n│  Approve: openclaw pairing approve feishu \u003Ccode>                                           │\r\n│  Allowlist DMs: channels.feishu.dmPolicy=\"allowlist\" + channels.feishu.allowFrom entries.  │\r\n│  Public DMs: channels.feishu.dmPolicy=\"open\" + channels.feishu.allowFrom includes \"*\".     │\r\n│  Multi-user DMs: run: openclaw config set session.dmScope \"per-channel-peer\" (or           │\r\n│  \"per-account-channel-peer\" for multi-account channels) to isolate sessions.               │\r\n│  Docs: channels\u002Fpairing               │\r\n│                                                                                            │\r\n├────────────────────────────────────────────────────────────────────────────────────────────╯\r\n│\r\n◇  Feishu DM policy\r\n│  Pairing (recommended)\r\n│\r\n◇  Route selected channels to this agent now? (bindings)\r\n│  Yes\r\nConfig overwrite: \u002Froot\u002F.openclaw\u002Fopenclaw.json (sha256 7f17c571753d8df0b5e05e9fbe146f6b6c2e76b7f0160de185edfbacd8e072f0 -> 60d68e4017a5a27c115e4a38b2c452cb128de48dccb700dc8fda2df2ce3df61b, backup=\u002Froot\u002F.openclaw\u002Fopenclaw.json.bak)\r\nUpdated ~\u002F.openclaw\u002Fopenclaw.json\r\nWorkspace OK: ~\u002F.openclaw\u002Fworkspace\u002Fcoding\r\nSessions OK: ~\u002F.openclaw\u002Fagents\u002Fcoding\u002Fsessions\r\n│\r\n└  Agent \"coding\" ready.\r\n```\r\n\r\n",{"_path":68,"slug":69,"title":70,"description":71,"excerpt":71,"date":72,"tags":73,"type":15,"cover":76,"content":77},"\u002Fknowledge\u002Fantlr4入门","antlr4入门","Antlr4入门","Antlr4入门 1 简介 ​ ANTLR4是一个用于构建语言解析器的强大工具，它可以根据你定义的语法规则，自动生成对应的词法分析器和语法分析器，广泛应用于构建DSL、配置文件解析器、静态代码分析工具等场景。 ​ 官网 https:\u002F\u002Fwww.antlr.org\u002F ​ GitHub https:\u002F\u002Fgithub.com","2026-01-20",[74,44,75],"Java","ANTLR","\u002Fknowledge-assets\u002Fantlr4入门\u002Fhello.png","\r\n\r\n# Antlr4入门\r\n\r\n# 1\t简介\r\n\r\n​\t\tANTLR4是一个用于构建语言解析器的强大工具，它可以根据你定义的语法规则，自动生成对应的词法分析器和语法分析器，广泛应用于构建DSL、配置文件解析器、静态代码分析工具等场景。\r\n\r\n​\t\t[官网](https:\u002F\u002Fwww.antlr.org\u002F) https:\u002F\u002Fwww.antlr.org\u002F\r\n\r\n​\t\t[GitHub](https:\u002F\u002Fgithub.com\u002Fantlr\u002Fantlr4) https:\u002F\u002Fgithub.com\u002Fantlr\u002Fantlr4\r\n\r\n\r\n\r\n# 2\tAntlr4语法\r\n\r\nANTLR4的核心是编写语法规则文件。该文件同时定义了**词法规则**（标记单词，如关键字、标识符）和**语法规则**（定义句子结构）。\r\n\r\n- **词法规则**：以大写字母开头，使用正则表达式定义词汇（如 `ID: [a-z]+;`）。\r\n- **语法规则**：以小写字母开头，定义如何组合词汇（如 `prog: 'hello' ID ;`）。\r\n\r\n## 2.1\t结构\r\n\r\n```antlr\r\n\u002F** Optional javadoc style comment *\u002F\r\ngrammar Name; \r\noptions {...}\r\nimport ... ;\r\n\r\ntokens {...}\r\nchannels {...} \u002F\u002F lexer only\r\n@actionName {...}\r\n\r\nrule1 \u002F\u002F parser and lexer rules, possibly intermingled\r\n...\r\nruleN\r\n```\r\n\r\n- [**grammar**](https:\u002F\u002Fgithub.com\u002Fantlr\u002Fantlr4\u002Fblob\u002Fmaster\u002Fdoc\u002Fgrammars.md)：语法文件定义，`Name`需要和文件名一致，如：`grammar Hello`，文件名为`Hello.g4`；在语法头中没有前缀的语法是可以同时包含词法规则和解析器规则的组合语法。\r\n  - **lexer**：纯词法规则，只能编写词法，如：```lexer grammar Name```；\r\n  - **parser **：纯解析器规则，如：``` parser grammar Name```；\r\n\r\n- [**options**](https:\u002F\u002Fgithub.com\u002Fantlr\u002Fantlr4\u002Fblob\u002Fmaster\u002Fdoc\u002Foptions.md)：选项，如语言选项，输出选项，回溯选项，记忆选项等等，options { name1=value1; ... nameN=valueN; }\r\n\r\n  - **superClass**：设置生成的解析器或词法分析器的父类；\r\n\r\n  - **language**：指定生成的语言，java、c等；\r\n\r\n  - **tokenVocab**：导入指定文件内所有已定义的词法符号；\r\n\r\n  - **caseInsensitive**：是否忽略大小写匹配；\r\n\r\n    ```\r\n    options {\r\n        tokenVocab=DmSqlLexer;\t\t\t\u002F\u002F 导入词法符号\r\n        superClass=DmSqlParserBase;\t\t\u002F\u002F 继承父类\r\n        caseInsensitive=true;  \t\t\t\u002F\u002F 忽略大小写匹配\r\n    }\r\n    ```\r\n\r\n- [**import**](https:\u002F\u002Fgithub.com\u002Fantlr\u002Fantlr4\u002Fblob\u002Fmaster\u002Fdoc\u002Fgrammars.md#grammar-imports)：与 `tokenVocab` 不同，`import` 用于将一个语法文件的**全部规则**（词法和语法）导入到当前语法中，进行组合和复用；\r\n\r\n- [**tokens**](https:\u002F\u002Fgithub.com\u002Fantlr\u002Fantlr4\u002Fblob\u002Fmaster\u002Fdoc\u002Fgrammars.md#tokens-section)\r\n\r\n- [**actionName**](https:\u002F\u002Fgithub.com\u002Fantlr\u002Fantlr4\u002Fblob\u002Fmaster\u002Fdoc\u002Fgrammars.md#actions-at-the-grammar-level)  动作（Actions）实际上是用目标语言写成的、嵌入到规则中的代码（以花括号包裹）\r\n\r\n  ```\r\n  @header {\r\n  \u002F\u002F 生成目标文件，头部携带的信息，自动带上这个包路径，避免了手动加入的麻烦\r\n  package cn.mh.antlr4.demo.generated.count;\r\n  }\r\n  ```\r\n  \r\n- **rule** 表示规则，以“:”开始，以分号“;”结束，多个规则以“|”分隔。\r\n\r\n\r\n\r\n## 2.2\tHelloWorld\r\n\r\n​\t\t匹配hello前缀的字符串：\r\n\r\n```antlr\r\ngrammar Hello;\r\n\r\nr  : 'hello' ID;          \u002F\u002F match keyword hello followed by an identifier\r\n\r\nID : [a-z]+ ;             \u002F\u002F match lower-case identifiers\r\n\r\nWS : [ \\t\\r\\n]+ -> skip ; \u002F\u002F 全局跳过，skip spaces, tabs, newlines\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fantlr4入门\u002Fhello.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n\r\n\r\n# 3\tIDEA配置\r\n\r\n## 3.1\tidea插件安装\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fantlr4入门\u002Fidea插件安装.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n## 3.2\t运行\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fantlr4入门\u002Fantlr运行.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fantlr4入门\u002Fhello语法树.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\r\n\r\n\r\n\r\n# 4\t词法规则\r\n\r\n​\t\t[词法文档](https:\u002F\u002Fgithub.com\u002Fantlr\u002Fantlr4\u002Fblob\u002Fmaster\u002Fdoc\u002Flexer-rules.md)，文件使用`lexer grammar Name` 声明。\r\n\r\n| 特性               | 说明                                                         |\r\n| :----------------- | :----------------------------------------------------------- |\r\n| **书写格式**       | 规则名**大写字母开头**，后跟冒号和定义，以分号结束。如 `ID : [a-zA-Z]+ ;` |\r\n| **核心任务**       | 使用正则表达式定义各类“单词”，如标识符、数字、关键字、运算符、空白符。 |\r\n| **工作原理**       | ANTLR按规则顺序**从最长匹配原则**尝试匹配。匹配成功的规则会成为Token，供语法分析器使用。 |\r\n| **与语法规则关系** | 词法分析在前，语法分析在后。语法规则**调用**词法规则名来构建句子结构。 |\r\n\r\n## 4.1\t基础标记规则\r\n\r\n```antlr\r\n\u002F\u002F 标识符：由字母、数字、下划线组成，首字符不能是数字\r\nID : [a-zA-Z_] [a-zA-Z_0-9]* ;\r\n\r\n\u002F\u002F 整数：一个或多个数字\r\nINT : [0-9]+ ;\r\n\r\n\u002F\u002F 浮点数：包含小数点的数字\r\nFLOAT : [0-9]+ '.' [0-9]* \r\n      | '.' [0-9]+ \r\n      ;\r\n\r\n\u002F\u002F 字符串：双引号内的任意字符序列（简易版，使用转义）\r\nSTRING : '\"' ( ~[\"\\r\\n] | '\\\\\"' )* '\"' ;\r\n```\r\n\r\n## 4.2\t关键字与运算符\r\n\r\n```\r\n\u002F\u002F 关键字（顺序在ID之前，确保精确匹配）\r\nIF : 'if' ;\r\nWHILE : 'while' ;\r\nRETURN : 'return' ;\r\n\r\n\u002F\u002F 运算符和标点\r\nPLUS : '+' ;\r\nASSIGN : '=' ;\r\nSEMI : ';' ;\r\nLPAREN : '(' ;\r\nRPAREN : ')' ;\r\n```\r\n\r\n## 4.3\t特殊处理规则\r\n\r\n```\r\n\u002F\u002F 1. 跳过规则：匹配但不生成Token，直接丢弃\r\nWS : [ \\t\\r\\n]+ -> skip ;        \u002F\u002F 空白字符\r\nCOMMENT : '\u002F\u002F' ~[\\r\\n]* -> skip ; \u002F\u002F 单行注释\r\n\r\n\u002F\u002F 2. 通道规则：匹配后送入“隐藏通道”，不干扰语法分析但可被需要时访问\r\n\u002F\u002F 例如保留注释内容供后续工具（如语法高亮、格式化）使用\r\nCHANNEL_COMMENT : '\u002F*' .*? '*\u002F' -> channel(HIDDEN) ;\r\n\r\n\u002F\u002F 3. 片段规则：辅助性规则，本身不生成Token，供其他词法规则引用\r\nfragment DIGIT : [0-9] ;\r\nfragment LETTER : [a-zA-Z] ;\r\n\u002F\u002F 引用片段规则\r\nNUMBER : DIGIT+ ( '.' DIGIT+ )? ;\r\n```\r\n\r\n## 4.4\t词法模式\r\n\r\n​\t\t用于处理**上下文相关**的词法，如模板语言、字符串插值。最经典场景是**识别字符串内部的特殊语法**。\r\n\r\n```\r\n\u002F\u002F === 主模式（默认）===\r\nSTRING_START : '\"' -> pushMode(STRING_MODE), more ;\r\n\u002F\u002F 其他主模式规则...\r\n\r\nmode STRING_MODE; \u002F\u002F 进入字符串模式\r\n    STRING_TEXT : ~[\"\\\\]+ ; \u002F\u002F 普通字符串内容\r\n    ESCAPE : '\\\\' [\"\\\\\u002Fbfnrt] ; \u002F\u002F 转义序列\r\n    STRING_END : '\"' -> popMode ; \u002F\u002F 结束字符串，返回主模式\r\n```\r\n\r\n## 4.5\t计算案例\r\n\r\n```antlr\r\nlexer grammar CalcExprLexer;  \u002F\u002F 声明这是一个词法语法文件\r\n\r\n\u002F\u002F 1. 关键字（必须在ID之前定义）\r\nIF     : 'if';\r\nELSE   : 'else';\r\nWHILE  : 'while';\r\nRETURN : 'return';\r\nLET    : 'let';      \u002F\u002F 可能用于变量声明\r\n\r\n\u002F\u002F 2. 运算符和标点\r\nASSIGN : '=';       \u002F\u002F 赋值\r\nPLUS   : '+';\r\nMINUS  : '-';\r\nMUL    : '*';\r\nDIV    : '\u002F';\r\nMOD    : '%';       \u002F\u002F 取模\r\n\r\nEQ     : '==';      \u002F\u002F 相等\r\nNEQ    : '!=';      \u002F\u002F 不等\r\nLT     : '\u003C';\r\nLTE    : '\u003C=';\r\nGT     : '>';\r\nGTE    : '>=';\r\n\r\nLPAREN : '(';\r\nRPAREN : ')';\r\nLBRACE : '{';\r\nRBRACE : '}';\r\nCOMMA  : ',';\r\nSEMI   : ';';       \u002F\u002F 语句结束\r\n\r\n\u002F\u002F 3. 字面量\r\nINT    : [0-9]+;\r\nFLOAT  : [0-9]+ '.' [0-9]*    \u002F\u002F 如 3.14\r\n       | '.' [0-9]+           \u002F\u002F 如 .5\r\n       ;\r\n\r\n\u002F\u002F 字符串字面量（支持简单转义）\r\nSTRING : '\"' ( ESC | ~[\"\\\\] )* '\"';\r\nfragment ESC : '\\\\' [\"\\\\tnr];  \u002F\u002F 支持转义：\\\", \\\\, \\t, \\n, \\r\r\n\r\n\u002F\u002F 布尔字面量\r\nTRUE   : 'true';\r\nFALSE  : 'false';\r\n\r\n\u002F\u002F 4. 标识符（必须在所有关键字之后！）\r\nID     : [a-zA-Z_][a-zA-Z_0-9]*;\r\n\r\n\u002F\u002F 5. 空白符和注释（跳过规则）\r\nWS     : [ \\t\\r\\n]+ -> skip;      \u002F\u002F 跳过空格、制表符、回车、换行\r\n\r\n\u002F\u002F 单行注释\r\nLINE_COMMENT : '\u002F\u002F' ~[\\r\\n]* -> skip;\r\n\r\n\u002F\u002F 多行注释（支持嵌套）\r\nBLOCK_COMMENT: '\u002F*' ( BLOCK_COMMENT | . )*? '*\u002F' -> skip;\r\n\r\n\u002F\u002F 6. 错误字符处理（可选）\r\n\u002F\u002F 定义非法字符规则，帮助调试\r\n\u002F\u002F ERRCHAR : . ; \u002F\u002F 任何未匹配的字符，通常不需要，因为ANTLR会报错\r\n```\r\n\r\n\r\n\r\n# 5\t解析规则\r\n\r\n​\t\t[解析文档](https:\u002F\u002Fgithub.com\u002Fantlr\u002Fantlr4\u002Fblob\u002Fmaster\u002Fdoc\u002Fparser-rules.md)\r\n\r\n​\t\t文件使用`parser grammar Name` 声明，在ANTLR4中，**解析规则**（或语法规则）负责定义语言的结构。它接收由词法分析器产生的**词法符号流**，并按照你定义的规则，构建出一棵**语法分析树**。\r\n\r\n​\t\t简单来说，词法规则定义了“单词”，而语法规则定义了将这些单词组合成合法“句子”的语法。\r\n\r\n​\t\t一个 `.g4` 文件中的 `parser grammar` 部分包含了所有解析规则。其基本结构如下：\r\n\r\n| 组成部分   | 说明与示例                                                   |\r\n| :--------- | :----------------------------------------------------------- |\r\n| **规则名** | 以小写字母开头，例如 `expr`、`statement`。                   |\r\n| **规则体** | 由**备选分支**组成，用竖线 `|` 分隔。每个分支是词法符号和\u002F或其他规则名的序列。 |\r\n| **终止符** | 规则以分号 `;` 结束。                                        |\r\n\r\n\r\n\r\n```\r\nparser grammar CalcExprParser; \u002F\u002F 可独立存在的解析器语法\r\n\r\noptions {\r\n    tokenVocab=CalcExprLexer;  \u002F\u002F 导入词法符号，这是词法语法分离的关键\r\n}\r\n\r\n\u002F\u002F 语法规则的起点，通常名为 prog（program）、file 或计算器中的 calc\r\nprog: stat+ ; \u002F\u002F 一个程序由一条或多条语句组成\r\n\r\n\u002F\u002F 语句规则\r\nstat: assignstat ';'   # AssignStat   \u002F\u002F 标签：#AssignStat\r\n     | expr ';'        # ExprStat     \u002F\u002F 标签：#ExprStat\r\n     ;\r\n\r\n\u002F\u002F 赋值语句规则\r\nassignstat: ID '=' expr ;\r\n\r\n\u002F\u002F 表达式规则：处理加法和乘法，体现优先级\r\nexpr: expr ('*' | '\u002F') expr # MulDivExpr  \u002F\u002F 乘除优先级高，在规则中位置更低\r\n    | expr ('+' | '-') expr # AddSubExpr  \u002F\u002F 加减优先级低，在规则中位置更高\r\n    | INT                   # IntExpr\r\n    | ID                    # IdExpr\r\n    | '(' expr ')'          # ParensExpr\r\n    ;\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fantlr4入门\u002Fcalc.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n# 6\t达梦ddl解析案例\r\n\r\n词法规则：\r\n\r\n```antlr\r\n\r\n```\r\n\r\n解析规则：\r\n\r\n```antlr\r\n\r\n```\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n",{"_path":79,"slug":80,"title":81,"description":82,"excerpt":82,"date":83,"tags":84,"type":15,"cover":26,"content":86},"\u002Fknowledge\u002Fdmx512灯光控制流程设计","dmx512灯光控制流程设计","DMX512灯光控制流程设计","DMX512灯光控制流程设计 1 简介 DMX512协议是一种用于舞台灯光和控制系统的标准通信协议。它使用RS-485物理层，采用异步串行通信，数据格式为1个起始位、8个数据位、2个停止位，无奇偶校验，波特率为250kbps。","2026-01-18",[44,85],"DMX512","# DMX512灯光控制流程设计\r\n\r\n# 1\t简介\r\n\r\nDMX512协议是一种用于舞台灯光和控制系统的标准通信协议。它使用RS-485物理层，采用异步串行通信，数据格式为1个起始位、8个数据位、2个停止位，无奇偶校验，波特率为250kbps。\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n",{"_path":88,"slug":89,"title":90,"description":91,"excerpt":91,"date":83,"tags":92,"type":15,"cover":94,"content":95},"\u002Fknowledge\u002Fpcb硬件电路","pcb硬件电路","PCB硬件电路设计","PCB硬件电路设计 1、布电源线时需要计算线宽、载流 网址：https:\u002F\u002Feda365.com\u002Farticle-12-1.html 2、布电源过孔时，需要考虑过孔载流大小，需要考虑孔径大小 嘉立创的孔壁铜厚是不能修改的，一般是18um，PCB厂家会在官网声明自己支持的壁厚。 外直径跟内直径相差一般要大于10mil，孔",[93],"PCB","\u002Fknowledge-assets\u002Fpcb硬件电路\u002Fpcb过孔载流.png","# PCB硬件电路设计\r\n\r\n\r\n\r\n1、布电源线时需要计算线宽、载流\r\n网址：https:\u002F\u002Feda365.com\u002Farticle-12-1.html\r\n2、布电源过孔时，需要考虑过孔载流大小，需要考虑孔径大小\r\n嘉立创的孔壁铜厚是不能修改的，一般是18um，PCB厂家会在官网声明自己支持的壁厚。\r\n外直径跟内直径相差一般要大于10mil，孔径一般过1.5安电流，孔径大小一般是20mil\r\n网址：https:\u002F\u002Feda365.com\u002Farticle-11-1.html\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fpcb硬件电路\u002Fpcb过孔载流.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fpcb硬件电路\u002Fpcb过孔载流-1.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\r\n\r\n\r\n\r\n",{"_path":97,"slug":98,"title":99,"description":100,"excerpt":100,"date":101,"tags":102,"type":15,"cover":108,"content":109},"\u002Fknowledge\u002Falg轻量级日志收集框架","alg轻量级日志收集框架","ALG轻量级日志收集框架","ALG轻量级日志收集框架 **日志系统：**GLA、ELK、数仓 - **Agent**：代理或客户端，例如Alloy或 Promtail ，随Loki⼀起分发。代理抓取⽇志，通过添加标签将⽇志转换为流，并通过HTTP API将流推送到Loki。 - **Loki**：Loki 是⼀个可⽔平扩展、⾼可⽤性、多租户⽇志聚","2025-10-22",[103,104,105,106,107],"Docker","Spring Boot","Prometheus","ELK","Loki","\u002Fknowledge-assets\u002Falg轻量级日志收集框架\u002Floki.png","# ALG轻量级日志收集框架\r\n\r\n**日志系统：**GLA、ELK、数仓\r\n\r\n\r\n\r\n- **Agent**：代理或客户端，例如Alloy或 Promtail ，随Loki⼀起分发。代理抓取⽇志，通过添加标签将⽇志转换为流，并通过HTTP API将流推送到Loki。\r\n\r\n- **Loki**：Loki 是⼀个可⽔平扩展、⾼可⽤性、多租户⽇志聚合系统，其灵感来⾃Prometheus。Loki 与 Prometheus 的不同之处在于，它专注于⽇志⽽不是指标，并通过推送⽽不是拉取来收集⽇志。\r\n\r\n- **Grafana**：⽤于查询和显示⽇志数据。您还可以使⽤LogCLI或直接使⽤Loki API从命令⾏ 查询⽇志。\r\n\r\n\r\n\r\n# 1\t架构\r\n\r\n## 1.1\t架构1\r\n\r\n\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Falg轻量级日志收集框架\u002Floki.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n## 1.2\t架构2\r\n\r\n\r\n\r\n\r\n\r\n# 2\t环境搭建\r\n\r\n## 2.1\t安装Loki\r\n\r\n```yml\r\n# 官网下载\r\n```\r\n\r\n\r\n\r\n## 2.2\t安装alloy\r\n\r\n```shell\r\ndocker run -d \\\r\n  --name=alloy-tmp \\\r\n  --network=dp \\\r\n  -v \u002Fhome\u002Fsmartsync_v3\u002Falloy\u002Fconfig.alloy:\u002Fetc\u002Falloy\u002Fconfig.alloy \\\r\n  -v \u002Fhome\u002Fsmartsync_v3\u002Flogs:\u002Ftmp\u002Flogs \\\r\n  -p 12345:12345 \\\r\n  grafana\u002Falloy:v1.8.1 \\\r\n  run --server.http.listen-addr=0.0.0.0:12345 --storage.path=\u002Fvar\u002Flib\u002Falloy\u002Fdata \\\r\n  \u002Fetc\u002Falloy\u002Fconfig.alloy\r\n```\r\n\r\n\r\n\r\n安装成功后，打开浏览器，访问：http:\u002F\u002Flocalhost:12345，出现类似下面的界面表名安装成功。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Falg轻量级日志收集框架\u002Falloy.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n`config.alloy`配置文件，精确指定文件名称：\r\n\r\n```shell\r\n\u002F\u002F 定义日志的接收端，这里使用 Loki 的接收器, 自定义名称：tmpfiles\r\nloki.source.file \"tmpfiles\" {\r\n  \u002F\u002F 目标：指定 Spring Boot 日志文件的位置\r\n  targets = [\r\n    { __path__ = \"\u002Ftmp\u002Flogs\u002Fsmartsync-api\u002Fsmartsync.log\" },\r\n    { __path__ = \"\u002Ftmp\u002Flogs\u002Fsmartsync-flow\u002Fsmartsync.log\" },\r\n  ]\r\n  \u002F\u002F 转发到目标地址，定义的名称local需要跟后面的 loki.write定义的名称一致\r\n  forward_to = [loki.write.local.receiver]\r\n}\r\n\r\n\u002F\u002F 定义日志的写入端，即发送到哪个 Loki 服务\r\nloki.write \"local\" {\r\n  endpoint {\r\n    url = \"http:\u002F\u002F192.168.3.198:3100\u002Floki\u002Fapi\u002Fv1\u002Fpush\" \u002F\u002F 使用 Docker 容器名通信\r\n  }\r\n}\r\n```\r\n\r\n`config.alloy`配置文件，正则匹配文件名称：\r\n\r\n```shell\r\n\u002F\u002F 捕捉哪些文件\r\nlocal.file_match \"logs\" {\r\n  path_targets = [\r\n    { __path__ = \"\u002Ftmp\u002Flogs\u002Fsmartsync-api\u002F*.log\", \"application\" = \"smartsync-api\" },\r\n    { __path__ = \"\u002Ftmp\u002Flogs\u002Fsmartsync-web\u002F*.log\", \"application\" = \"smartsync-web\" },\r\n    { __path__ = \"\u002Ftmp\u002Flogs\u002Fsmartsync-flow\u002F*.log\", \"application\" = \"smartsync-flow\" },\r\n    { __path__ = \"\u002Ftmp\u002Flogs\u002Fsmartsync-support\u002F*.log\", \"application\" = \"smartsync-support\" },\r\n  ]\r\n}\r\n\r\n\u002F\u002F 定义日志的接收端，这里使用 Loki 的接收器\r\nloki.source.file \"tmpfiles\" {\r\n  \u002F\u002F 调用上面正则匹配的日志文件\r\n  targets    = local.file_match.logs.targets\r\n  forward_to = [loki.write.local.receiver]\r\n}\r\n\r\n\u002F\u002F 定义日志的写入端，即发送到哪个 Loki 服务\r\nloki.write \"local\" {\r\n  endpoint {\r\n    url = \"http:\u002F\u002F192.168.3.198:3100\u002Floki\u002Fapi\u002Fv1\u002Fpush\" \u002F\u002F 使用 Docker 容器名通信\r\n  }\r\n}\r\n```\r\n\r\n`config.alloy`配置文件，正则匹配日志内容，扩展提取标签：\r\n\r\n```shell\r\n\u002F\u002F 捕捉日志文件\r\nlocal.file_match \"logs\" {\r\n  path_targets = [\r\n    { __path__ = \"\u002Ftmp\u002Flogs\u002Fsmartsync-api\u002F*.log\", \"application\" = \"smartsync-api\" },\r\n    { __path__ = \"\u002Ftmp\u002Flogs\u002Fsmartsync-web\u002F*.log\", \"application\" = \"smartsync-web\" },\r\n    { __path__ = \"\u002Ftmp\u002Flogs\u002Fsmartsync-flow\u002F*.log\", \"application\" = \"smartsync-flow\" },\r\n    { __path__ = \"\u002Ftmp\u002Flogs\u002Fsmartsync-support\u002F*.log\", \"application\" = \"smartsync-support\" },\r\n  ]\r\n}\r\n\r\n\u002F\u002F 定义日志的接收端，这里使用 Loki 的接收器\r\nloki.source.file \"tmpfiles\" {\r\n  \u002F\u002F 调用上面正则匹配的日志文件\r\n  targets    = local.file_match.logs.targets\r\n  forward_to = [loki.process.extract_custom_fields.receiver]\r\n}\r\n\r\n\u002F\u002F 扩展字段处理，添加标签\r\nloki.process \"extract_custom_fields\" {\r\n  forward_to = [loki.write.local.receiver]\r\n\r\n  stage.match {\r\n    selector = \"{application=\\\"smartsync-flow\\\"}\"\r\n\r\n    \u002F\u002F 正则提取日志内容\r\n    stage.regex {\r\n      \u002F\u002F expression = \"\\\\[(?P\u003CflowCode>|[0-9a-f]{32})\\\\]\\\\s*\\\\[(?P\u003CrequestId>|[0-9a-f]{32})\\\\]\"\r\n      expression = \"^(?P\u003Ctimestamp>\\\\d{4}-\\\\d{2}-\\\\d{2}[\\\\s|T]\\\\d{2}:\\\\d{2}:\\\\d{2}\\\\.\\\\d{3})\\\\s+(?P\u003Clevel>\\\\w+)\\\\s+(?P\u003Cprocess_id>\\\\d+)\\\\s+---\\\\s+\\\\[(?P\u003Capplication>[^\\\\]]+)\\\\]\\\\s+\\\\[(?P\u003Cthread_name>[^\\\\]]+)\\\\]\\\\s+(\\\\[(?:(?P\u003CflowCode>[a-f0-9]{32})|\\\\s{32})\\\\]\\\\s+)?\\\\[(?:(?P\u003CrequestId>[a-f0-9]{32})|\\\\s{32})\\\\]\\\\s+(?P\u003Clogger>[^\\\\s]+)\\\\s+:\\\\s+(?P\u003Cmessage>[\\\\s\\\\S]+)$\"\r\n    }\r\n    \r\n    \u002F\u002F 生成标签\r\n    stage.labels {\r\n      values = {\r\n        level = \"\",\r\n        flowCode = \"\",\r\n        requestId = \"\",\r\n      }\r\n    }\r\n  }\r\n}\r\n\r\n\u002F\u002F 定义日志的写入端，即发送到哪个 Loki 服务\r\nloki.write \"local\" {\r\n  endpoint {\r\n    url = \"http:\u002F\u002F192.168.3.198:3100\u002Floki\u002Fapi\u002Fv1\u002Fpush\" \u002F\u002F 使用 Docker 容器名通信\r\n  }\r\n}\r\n```\r\n\r\n打开浏览器，访问：http:\u002F\u002Flocalhost:12345，收集步骤如下：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Falg轻量级日志收集框架\u002Floki-file.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n点击任意流程，进入明细，想查看特别语法，可以选择` Documentation`进入官网查看案例说明。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Falg轻量级日志收集框架\u002Falloy-link.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Falg轻量级日志收集框架\u002Falloy-1.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Falg轻量级日志收集框架\u002Falloy-2.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n## 2.3\t安装Grafana\r\n\r\n（1）首页：\r\n\r\n\r\n\r\n（2）添加Loki连接，直接在搜索框搜索Loki，然后安装。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Falg轻量级日志收集框架\u002Fgrafana-2.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n（3）配置Loki连接信息，这里Loki和Grafana在同一个网络里，可以直接用容器名称。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Falg轻量级日志收集框架\u002Fgrafana-3.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n配置完后，点击连接测试，看能否连接。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Falg轻量级日志收集框架\u002Fgrafana-4.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n（4）选择Explore，在这里可以查询日志，好比navicat查询数据库表信息。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Falg轻量级日志收集框架\u002Fgrafana-5.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n（5）查询日志\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Falg轻量级日志收集框架\u002Fgrafana-query.png\" style=\"zoom:80%;\" \u002F>\r\n",{"_path":111,"slug":112,"title":113,"description":114,"excerpt":114,"date":101,"tags":115,"type":15,"cover":116,"content":117},"\u002Fknowledge\u002Fprometheus指标监控","prometheus指标监控","Prometheus指标监控","Prometheus指标监控 1 架构 1.1 架构 2 环境搭建 2.1 安装Prometheus prometheus.yml配置文件 访问：http:\u002F\u002Flocalhost:9090",[103,104,105],"\u002Fknowledge-assets\u002Fprometheus指标监控\u002Fprometheus.svg","# Prometheus指标监控\r\n\r\n\r\n\r\n\r\n\r\n# 1\t架构\r\n\r\n## 1.1\t架构\r\n\r\n\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fprometheus指标监控\u002Fprometheus.svg\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n\r\n\r\n# 2\t环境搭建\r\n\r\n## 2.1\t安装Prometheus\r\n\r\n```shell\r\ndocker run -d \\\r\n  --name=prometheus-dev \\\r\n  --network=dp \\\r\n  -p 9090:9090 \\\r\n  -v \u002Fhome\u002Fsmartsync_v3\u002Fprometheus\u002Fprometheus.yml:\u002Fetc\u002Fprometheus\u002Fprometheus.yml \\\r\n  prom\u002Fprometheus:v3.7.1\r\n```\r\n\r\nprometheus.yml配置文件\r\n\r\n```shell\r\nglobal:\r\n  scrape_interval: 15s\r\n\r\nscrape_configs:\r\n  - job_name: 'prometheus'\r\n    static_configs:\r\n      - targets: [ 'localhost:9090' ]\r\n```\r\n\r\n\r\n\r\n访问：http:\u002F\u002Flocalhost:9090\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fprometheus指标监控\u002Fprometheus.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\r\n\r\n## 2.2\tSpringBoot集成Prometheus\r\n\r\npom.xml\r\n\r\n```xml\r\n\u003Cdependencies>\r\n    \u003Cdependency>\r\n        \u003CgroupId>org.springframework.boot\u003C\u002FgroupId>\r\n        \u003CartifactId>spring-boot-starter-web\u003C\u002FartifactId>\r\n    \u003C\u002Fdependency>\r\n\t\u003C!-- springboot自身的监控依赖 -->\r\n    \u003Cdependency>\r\n        \u003CgroupId>org.springframework.boot\u003C\u002FgroupId>\r\n        \u003CartifactId>spring-boot-starter-actuator\u003C\u002FartifactId>\r\n    \u003C\u002Fdependency>\r\n\r\n    \u003C!-- prometheus 依赖 -->\r\n    \u003Cdependency>\r\n        \u003CgroupId>io.micrometer\u003C\u002FgroupId>\r\n        \u003CartifactId>micrometer-registry-prometheus\u003C\u002FartifactId>\r\n        \u003Cversion>1.5.9\u003C\u002Fversion>\r\n    \u003C\u002Fdependency>\r\n\u003C\u002Fdependencies>\r\n```\r\n\r\n在 application.yml 中配置如下\r\n\r\n```yml\r\nspring:\r\n  application:\r\n    name: PrometheusApp\r\n\r\n#springboot监控配置\r\nmanagement:\r\n  endpoints:\r\n    web:\r\n      \u002F\u002F 暴露所有信息,prometheus才能拿到这些数据\r\n      exposure:\r\n        include: '*'\r\n  metrics:\r\n    export:\r\n      prometheus:\r\n        enabled: true\r\n    tags:\r\n      application: ${spring.application.name} # 暴露的数据中添加application label\r\n```\r\n\r\nprometheus.yml配置文件\r\n\r\n```shell\r\nglobal:\r\n  scrape_interval: 15s\r\n\r\nscrape_configs:\r\n  - job_name: 'prometheus'\r\n    static_configs:\r\n      - targets: [ 'localhost:9090' ]\r\n  \u002F\u002F 添加springboot监控信息\r\n  - job_name: 'smartsync-web'\r\n    metrics_path: '\u002Fdp-web\u002Factuator\u002Fprometheus'\r\n    static_configs:\r\n      - targets: [ '192.168.3.198:9000' ]\r\n  - job_name: 'smartsync-flow'\r\n    metrics_path: '\u002Fdp-flow\u002Factuator\u002Fprometheus'\r\n    static_configs:\r\n      - targets: [ '192.168.3.198:9500' ]\r\n  - job_name: 'smartsync-api'\r\n    metrics_path: '\u002Fdp-query\u002Factuator\u002Fprometheus'\r\n    static_configs:\r\n      - targets: [ '192.168.3.198:9600' ]\r\n  - job_name: 'smartsync-support'\r\n    metrics_path: '\u002Fdp-support\u002Factuator\u002Fprometheus'\r\n    static_configs:\r\n      - targets: [ '192.168.3.198:9700' ]\r\n```\r\n\r\n\r\n\r\n打开浏览器访问：http:\u002F\u002Flocalhost:9090即可看到如下：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fprometheus指标监控\u002Fprometheus.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\r\n\r\n## 2.3\t安装Grafana\r\n\r\n（1）首页：\r\n\r\n\r\n\r\n（2）添加Prometheus连接，直接在搜索框搜索Loki。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fprometheus指标监控\u002Fgrafana-1.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n（3）配置Prometheus连接信息，这里Prometheus和Grafana在同一个网络里，可以直接用容器名称。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fprometheus指标监控\u002Fgrafana-2.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fprometheus指标监控\u002Fgrafana-3.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n配置完后，点击连接测试，看能否连接。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fprometheus指标监控\u002Fgrafana-4.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n（4）选择Explore，在这里可以查询指标，好比navicat查询数据库表信息。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fprometheus指标监控\u002Fgrafana-5.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n（5）添加监控大屏\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fprometheus指标监控\u002Fgrafana-6.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fprometheus指标监控\u002Fgrafana-7.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fprometheus指标监控\u002Fgrafana-8.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fprometheus指标监控\u002Fgrafana-9.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fprometheus指标监控\u002Fgrafana-10.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fprometheus指标监控\u002Fgrafana-11.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n这里就可以看到大屏监控指标了：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fprometheus指标监控\u002Fgrafana-12.png\" style=\"zoom:60%;\" \u002F>\n",{"_path":119,"slug":120,"title":120,"description":121,"excerpt":121,"date":122,"tags":123,"type":15,"cover":127,"content":128},"\u002Fknowledge\u002Fmongodb安装教程","mongodb安装教程","mongodb安装教程 1 概述 1.1 简介 ​ MongoDB 是一种 NoSQL 数据库，属于文档数据库类别。其核心特性包括： - ‌**文档存储模型**‌：数据以 BSON（二进制 JSON）格式的文档形式存储，每个文档相当于关系数据库中的一行数据，但字段结构更灵活，无需预定义统一模式。‌‌ - ‌**分布式架","2025-09-17",[124,125,44,126],"Linux","MongoDB","数据同步","\u002Fknowledge-assets\u002Fmongodb安装教程\u002Fdownload.png","# mongodb安装教程\r\n\r\n# 1\t概述\r\n\r\n## 1.1\t简介\r\n\r\n​\tMongoDB 是一种 NoSQL 数据库，属于文档数据库类别。其核心特性包括：\r\n\r\n- ‌**文档存储模型**‌：数据以 BSON（二进制 JSON）格式的文档形式存储，每个文档相当于关系数据库中的一行数据，但字段结构更灵活，无需预定义统一模式。‌‌\r\n\r\n- ‌**分布式架构**‌：基于分布式文件存储设计，支持数据分片（跨服务器分布）和副本集（自动同步冗余），确保高可用性和可扩展性。‌‌\r\n\r\n- ‌**开源与跨平台**‌：由 C++ 编写，提供社区版和企业版，可在本地或云端（如 MongoDB Atlas）部署。‌‌\r\n\r\n  \r\n\r\n## 1.2\t官网下载安装包\r\n\r\n​\t[下载](https:\u002F\u002Fwww.mongodb.com\u002Ftry\u002Fdownload\u002Fcommunity)：https:\u002F\u002Fwww.mongodb.com\u002Ftry\u002Fdownload\u002Fcommunity\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmongodb安装教程\u002Fdownload.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n# 2\tLinux离线安装-CentOS7\r\n\r\n## 2.1\t安装配置\r\n\r\n```shell\r\n# 解压\r\ntar -zxvf mongodb-linux-x86_64-rhel70-4.2.24.tgz\r\n# 重命名\r\nmv mongodb-linux-x86_64-rhel70-4.2.24 mongodb\r\n# 进入mongodb根目录\r\ncd mongodb\u002F\r\n\r\n# 添加配置文件\r\nvi mongodb.conf\r\n```\r\n\r\n​\t以下为配置文件mongodb.conf中的内容：\r\n\r\n```shell\r\n#数据文件存放目录\r\ndbpath = \u002Fusr\u002Flocal\u002Fmongodb\u002Fdata\u002Fdb\r\n#日志文件存放目录\r\nlogpath = \u002Fusr\u002Flocal\u002Fmongodb\u002Flogs\u002Fmongodb.log\r\n#默认端口27017\r\nport = 27017\r\n#以守护程序的方式启用，即在后台运行\r\nfork = true\r\n#允许远程连接,127.0.0.1只允许本地连接\r\nbind_ip=0.0.0.0\r\n#是否需要认证，如果启用，则需要创建mongodb账号密码，使用账号密码才可以远程访问\r\n#auth = true\r\n```\r\n\r\n​\t然后创建mongodb.conf配置文件中配置的数据文件目录和日志文件：\r\n\r\n```shell\r\nmkdir -p \u002Fusr\u002Flocal\u002Fmongodb\u002Fdata\u002Fdb\r\nmkdir -p \u002Fusr\u002Flocal\u002Fmongodb\u002Flogs\r\ntouch \u002Fusr\u002Flocal\u002Fmongodb\u002Flogs\u002Fmongodb.log\r\n```\r\n\r\n## 2.2\t配置环境变量\r\n\r\n```shell\r\n# 编辑profile文件\r\nvi \u002Fetc\u002Fprofile \r\n# 添加到mongodb到PATH\r\nexport PATH=$PATH:\u002Fusr\u002Flocal\u002Fmongodb\u002Fbin\r\n# 刷新环境变量\r\nsource \u002Fetc\u002Fprofile\r\n```\r\n\r\n## 2.3\t启动mongo服务\r\n\r\n```shell\r\n# 指定配置文件启动\r\nmongod -f \u002Fusr\u002Flocal\u002Fmongodb\u002Fmongodb.conf\r\n```\r\n\r\n​\t启动成功如下：\r\n\r\n```shell\r\n[root@localhost mongodb]# mongod -f \u002Fusr\u002Flocal\u002Fmongodb\u002Fmongodb.conf\r\nabout to fork child process, waiting until server is ready for connections.\r\nforked process: 32591\r\nchild process started successfully, parent exiting\r\n```\r\n\r\n​\t也可以通过`ps -ef | grep mongo`查看进程是否启动。\r\n\r\n## 2.4\t连接mongo客户端\r\n\r\n```shell\r\n# 未开启认证\r\nmongo\r\n\r\n# 开启认证使用账号密码连接\r\nmongo -u admin -p admin\r\n\r\n# 客户端连接格式为：\r\n# --authenticationDatabase 数据库名 选填\r\nmongo -u 账号 --authenticationDatabase 数据库名 -p 密码 \r\n```\r\n\r\n连接成功如下：\r\n\r\n```shell\r\n[root@localhost mongodb-4.2]# bin\u002Fmongo\r\nMongoDB shell version v4.2.24\r\nconnecting to: mongodb:\u002F\u002F127.0.0.1:27017\u002F?compressors=disabled&gssapiServiceName=mongodb\r\nImplicit session: session { \"id\" : UUID(\"c45bcccb-cb60-4118-9145-5129895363b8\") }\r\nMongoDB server version: 4.2.24\r\nWelcome to the MongoDB shell.\r\nFor interactive help, type \"help\".\r\nFor more comprehensive documentation, see\r\n        https:\u002F\u002Fdocs.mongodb.com\u002F\r\nQuestions? Try the MongoDB Developer Community Forums\r\n        https:\u002F\u002Fcommunity.mongodb.com\r\nServer has startup warnings:\r\n2025-09-17T10:21:53.450+0800 I  CONTROL  [initandlisten]\r\n2025-09-17T10:21:53.451+0800 I  CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.\r\n---\r\nEnable MongoDB's free cloud-based monitoring service, which will then receive and display\r\nmetrics about your deployment (disk utilization, CPU, operation statistics, etc).\r\n\r\nThe monitoring data will be available on a MongoDB website with a unique URL accessible to you\r\nand anyone you share the URL with. MongoDB may use this information to make product\r\nimprovements and to suggest MongoDB products and deployment options to you.\r\n\r\nTo enable free monitoring, run the following command: db.enableFreeMonitoring()\r\nTo permanently disable this reminder, run the following command: db.disableFreeMonitoring()\r\n---\r\n\r\n> \r\n> exit\r\nbye\r\n[root@localhost mongodb]# \r\n```\r\n\r\n## 2.5\t创建用户\r\n\r\n```shell\r\n# 切换到admin数据库\r\nuse admin\r\n# 使用db.createUser() 创建一个管理员用户admin,角色为root，指定具体数据库\r\ndb.createUser({user:'admin',pwd:'admin',roles:[{role:'root',db:'admin'}]})\r\n# db.auth()认证一下获取权限，认证通过后可以操作数据库，成功则会输出1\r\ndb.auth(\"admin\",\"admin\")\r\n\r\n\r\n# use 命令也可以是创建数据库，当指定数据库不存在时即为创建，切换到一个新的数据库xtest\r\nuse xtest\r\n# 创建用户xtest dbOwner权限\r\ndb.createUser({user:'xtest',pwd:'xtest',roles:['dbOwner']})\r\n\r\n# 查看有哪儿些用户\r\nshow users\r\n# 删除用户\r\ndb.dropUser(\"user_name\")\r\n```\r\n\r\n​\t必须要创建一个`管理员账号`，创建完账号后，需要在配置文件`mongodb.conf`中开启auth认证，然后重启`mongo`服务。\r\n\r\n重启后需要通过刚刚创建的管理员账号密码登录连接客户端，否则`show dbs`命令无法查看到任何数据库，因为没有权限。\r\n\r\nrole角色：\r\n\r\n```shell\r\nread    \t允许用户读取指定数据库\r\nreadWrite    \t允许用户读写指定数据库\r\ndbAdmin    \t允许用户在指定数据库中执行管理函数，如索引创建、删除，查看统计或访问system.profile\r\ndbOwner\t\t数据库拥有者，包含readWrite、dbAdmin、userAdmin\r\nuserAdmin    \t允许用户向system.users集合写入，可以找指定数据库里创建、删除和管理用户\r\nclusterAdmin    \t只能切换在admin数据库中可用，赋予用户所有分片和复制集相关函数的管理权限。\r\nreadAnyDatabase    \t只能切换在admin数据库中可用，赋予用户所有数据库的读权限\r\nreadWriteAnyDatabase    \t只能切换在admin数据库中可用，赋予用户所有数据库的读写权限\r\nuserAdminAnyDatabase    \t只能切换在admin数据库中可用，赋予用户所有数据库的userAdmin权限\r\ndbAdminAnyDatabase    \t只能切换在admin数据库中可用，赋予用户所有数据库的dbAdmin权限。\r\nroot    \t只能切换在admin数据库中可用。超级账号，超级权限\r\n```\r\n\r\n## 2.6\t关闭mongo服务\r\n\r\n```shell\r\nmongod --dbpath \u002Fusr\u002Flocal\u002Fmongodb\u002Fdata\u002Fdb --logpath \u002Fusr\u002Flocal\u002Fmongodb\u002Flogs\u002Fmongodb.log --shutdown\r\n```\r\n\r\n或\r\n\r\n```shell\r\nrs:PRIMARY> use admin\r\nrs:PRIMARY> db.shutdownServer()\r\n#退出后即关闭\r\n```\r\n\r\n## 2.7\t可视化工具\r\n\r\n​\t通过navicat工具连接到mongodb数据库。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmongodb安装教程\u002Fconnect-1.png\" style=\"zoom:60%;\" \u002F>\n",{"_path":130,"slug":131,"title":132,"description":133,"excerpt":133,"date":134,"tags":135,"type":15,"cover":138,"content":139},"\u002Fknowledge\u002Fjenkins自动化部署","jenkins自动化部署","Jenkins自动化部署","Jenkins自动化部署 1 简介 2 Jenkins安装 2.1 docker安装 2.2 访问 ​ 打开浏览器，访问：http:\u002F\u002F192.168.3.10:8080 （1）","2025-09-05",[103,136,137,63],"Maven","Jenkins","\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fjenkins-token.png","# Jenkins自动化部署\r\n\r\n# 1\t简介\r\n\r\n\r\n\r\n# 2\tJenkins安装\r\n\r\n## 2.1\tdocker安装\r\n\r\n```shell\r\n# 下拉镜像\r\ndocker pull jenkins\u002Fjenkins:2.525\r\n\r\n# 创建挂着目录\r\nmkdir \u002Fusr\u002Flocal\u002Fsoftware\u002Fjenkins\r\n\r\n# 安装\r\ndocker run --name jenkins \\\r\n  --privileged=true \\\r\n  --restart=always \\\r\n  -u root \\\r\n  -p 8080:8080 \\\r\n  -p 50000:50000 \\\r\n  -v \u002Fusr\u002Flocal\u002Fsoftware\u002Fjenkins:\u002Fvar\u002Fjenkins_home \\\r\n  -d jenkins\u002Fjenkins:2.525\r\n\r\n```\r\n\r\n## 2.2\t访问\r\n\r\n```shell\r\n# 查看初始化密码\r\ndocker logs -f jenkins\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fjenkins-token.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n​\t打开浏览器，访问：http:\u002F\u002F192.168.3.10:8080\r\n\r\n（1）\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fjenkins-token2.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n（2）\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fjenkins-custom.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n（3）\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fjenkins-custom1.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n## 2.3\t插件安装\r\n\r\n### 2.3.1\tssh插件安装\r\n\r\n安装ssh插件：[Publish Over SSHVersion](https:\u002F\u002Fplugins.jenkins.io\u002Fpublish-over-ssh)\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fssh-server-1.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n配置ssh远程连接：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fssh-server.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fssh-server-config.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fssh-server-connect.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\r\n\r\n### 2.3.2\tgit插件安装\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002FgitLab-plugin.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\r\n\r\n## 2.4\t全局工具配置\r\n\r\n（1）配置jdk\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fjenkins-jdk.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n（2）配置maven，这里可以将 maven复制到jenkins的home目录中。注意指定的是容器中的路径。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fjenkins-maven.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n（3）配置git，这里master节点上并没有用到git，随便写个路径。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fjenkins-git.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\r\n\r\n## 2.5\tmaster-slave模式\r\n\r\n​\t\t项目比较多时，单个master负载较大，构建会出现长时间等待，可以采用master-slave架构来提升构建性能。而这里使用docker-slave方式来构建项目。docker部署jenkins master，而通过slave来构建项目。\r\n\r\n### 2.5.1\tslave安装\r\n\r\n（1）节点列表\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fadd-node.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n（2）创建节点\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fadd-node1.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fadd-node2.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fadd-node3.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n（3）安装从节点\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fslave-install.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fslave-install2.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n在linux上执行如下命令，启动从节点：\r\n\r\n```shell\r\n# 创建节点目录\r\nmkdir \u002Fhome\u002Ftools\u002Fjenkins-slave\r\n# 下载agent.jar\r\ncurl -sO http:\u002F\u002F192.168.13.1:8080\u002FjnlpJars\u002Fagent.jar\r\n# 编辑启动脚本\r\necho 'nohup java -jar agent.jar -url http:\u002F\u002F192.168.13.1:8080\u002F -secret 8d5eaea56e419a05ad96dea6335adc164353b66f52e3eeca9456f80b51b9fb2c -name \"slave-node\" -webSocket -workDir \"\u002Fhome\u002Ftools\u002Fjenkins-slave\" &' > slave-start.sh\r\n\r\n# 授权\r\nchmod +x slave-start.sh\r\n# 启动从节点\r\n.\u002Fslave-start.sh\r\n```\r\n\r\n​\t\t查看当前节点状态：可以看到已经正常。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fslave-install3.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n### 2.5.2\t从节点工具配置\r\n\r\n​\t\t要配置从节点工具，必须先配置全局工具，到从节点才能选择工具。\r\n\r\n​\t\t（1）配置jdk\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fslave-jdk.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t\t（2）配置maven\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fslave-maven.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t\t（3）配置git，这里必须写到git 脚本命令\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fslave-git.png\" style=\"zoom:70%;\" \u002F>\r\n\r\n### 2.5.3\t从节点安装Node.js\r\n\r\n​\t\t当前系统是：Rocky Linux 9.7，安装完成后在流水线中可以直接使用`npm`，不需要做其他配置。\r\n\r\n```shell\r\n# 1 清理旧版本与更新系统：如果你的系统之前有安装过 Node.js，建议先移除旧包\r\nsudo dnf remove -y nodejs npm\r\nsudo dnf update -y\r\n\r\n# 2 添加 NodeSource 仓库并安装\r\n# 安装最新的长期支持版 (LTS，推荐)\r\ncurl -fsSL https:\u002F\u002Frpm.nodesource.com\u002Fsetup_lts.x | sudo bash -\r\nsudo dnf install -y nodejs\r\n\r\n# 安装最新的当前版 (Current)：\r\ncurl -fsSL https:\u002F\u002Frpm.nodesource.com\u002Fsetup_current.x | sudo bash -\r\nsudo dnf install -y nodejs\r\n\r\n# 3 验证安装：安装完成后，运行以下命令检查版本\r\nnode -v\r\nnpm -v\r\n```\r\n\r\n\r\n\r\n## 2.6\t系统配置\r\n\r\n### 2.6.1\t全局凭据配置\r\n\r\n（1）gitLab账号密码配置\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fgitlab-pass.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fgitlab-config.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\r\n\r\n## 2.7\t流水线配置\r\n\r\n### 2.7.1\t查看流水线语法\r\n\r\n​\t\t新建一个流水线任务，点击查看流水线语法：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fjenkins-flow.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n（1）查看git下拉代码语法，选择使用之前配置的凭证。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fgitlab-flow.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\r\n\r\n### 2.7.1\t流水线ssh部署脚本\r\n\r\n```shell\r\npipeline {\r\n    agent{\r\n        \u002F\u002F 指定从节点标签，即用从节点构建\r\n        label 'slave'\r\n    }\r\n    options {\r\n        disableConcurrentBuilds()\r\n    }\r\n    tools {\r\n        jdk 'jdk-21'\r\n        maven 'maven3'\r\n        git 'git'\r\n    }\r\n    stages {\r\n        stage('Clean Workspace') {\r\n            steps {\r\n                deleteDir()  \u002F\u002F 删除当前目录\r\n            }\r\n        }\r\n        stage('git pull') {\r\n            steps {\r\n                sh 'pwd'\r\n                sh 'git -v'\r\n                git credentialsId: 'gitlab-mh', url: 'http:\u002F\u002F192.168.3.138\u002Fsmartsync3.5\u002Fsmartsync.git'\r\n            }\r\n        }\r\n        stage('maven deploy') {\r\n            steps {\r\n                sh \"mvn clean deploy -DskipTests=true -Dmaven.javadoc.skip=true -Dmaven.install.skip=true\"\r\n            }\r\n        }\r\n        stage('copy jar') {\r\n            steps {\r\n                sh \"cp smartsync-admin\u002Fsmartsync-center\u002Ftarget\u002Fsmartsync-admin.jar \u002Fhome\u002Fsmartsync\u002Fservice\u002Fadmin\u002F\"\r\n            }\r\n        }\r\n        \u002F\u002F  ssh远程启动\r\n        stage('ssh deploy') {\r\n        \tsteps {\r\n        \t    echo \"Deploy To pro 13.1 Begin\" \r\n        \t    sshPublisher(\r\n        \t        publishers: [\r\n        \t                sshPublisherDesc(\r\n        \t                configName: '13_1_CICDServer',\r\n        \t                transfers: [\r\n        \t                    sshTransfer(\r\n    \t                            execCommand: \"\"\"\r\n                                        pwd & ls\r\n                                        cd \u002Fhome\u002Fsmartsync\u002Fservice\u002Fadmin\r\n                                        sh boot_admin.sh restart\r\n                                        cd \u002Fhome\u002Fsmartsync\u002Fservice\u002Fexecutor\r\n                                        sh boot_executor.sh restart\r\n    \t                            \"\"\"\r\n        \t                    )\r\n        \t                ],\r\n        \t                verbose: true\r\n        \t            )\r\n        \t        ]\r\n        \t    )\r\n        \t    echo 'Deploy To pro 13.1 End'  \r\n        \t}\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n### 2.7.2\t流水线ssh前端部署脚本\r\n\r\n（1）本地服务器部署\r\n\r\n```shell\r\npipeline {\r\n    agent{\r\n        \u002F\u002F 指定从节点标签，即用从节点构建\r\n        label 'slave'\r\n    }\r\n    options {\r\n        disableConcurrentBuilds()\r\n    }\r\n    tools {\r\n        git 'git'\r\n    }\r\n    stages {\r\n        stage('Clean Workspace') {\r\n            steps {\r\n                deleteDir()  \u002F\u002F 删除当前目录\r\n            }\r\n        }\r\n        stage('git pull') {\r\n            steps {\r\n                sh \"pwd\"\r\n                git credentialsId: 'gitlab-mh', url: 'http:\u002F\u002F192.168.3.138\u002Fsmartsync3.5\u002Fsmartsync_ui.git'\r\n            }\r\n        }\r\n        stage('npm install'){\r\n            steps{\r\n                sh 'npm install'\r\n            }\r\n        }\r\n        stage('npm build'){\r\n            steps {\r\n                sh 'npm run build'\r\n            }\r\n        }\r\n        stage('deploy ui'){\r\n            steps {\r\n                sh 'rm -rf \u002Fhome\u002Fsmartsync\u002Fservice\u002Fweb-ui'\r\n                sh 'cp -r dist\u002F \u002Fhome\u002Fsmartsync\u002Fservice\u002Fweb-ui'\r\n            }\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n（2）上传远程服务器部署\r\n\r\n```shell\r\npipeline {\r\n    agent{\r\n        \u002F\u002F 指定从节点标签，即用从节点构建\r\n        label 'slave'\r\n    }\r\n    options {\r\n        disableConcurrentBuilds()\r\n    }\r\n    tools {\r\n        git 'git'\r\n    }\r\n    stages {\r\n        stage('Clean Workspace') {\r\n            steps {\r\n                deleteDir()  \u002F\u002F 删除当前目录\r\n            }\r\n        }\r\n        stage('git pull') {\r\n            steps {\r\n                sh \"pwd\"\r\n                git credentialsId: 'gitlab-mh', url: 'http:\u002F\u002F192.168.3.138\u002Fsmartsync3.5\u002Fsmartsync_ui.git'\r\n            }\r\n        }\r\n        stage('npm install'){\r\n            steps{\r\n                sh 'npm install'\r\n            }\r\n        }\r\n        stage('npm build'){\r\n            steps {\r\n                sh 'npm run build'\r\n            }\r\n        }\r\n        stage('deploy ui'){\r\n            steps {\r\n                sh 'tar -zcvf dist.rar dist'\r\n            }\r\n        }\r\n        stage('ssh upload') {\r\n        \tsteps {\r\n        \t    echo \"upload To pro 13.4 Begin\" \r\n        \t    sshPublisher(\r\n        \t        publishers: [\r\n        \t                sshPublisherDesc(\r\n        \t                configName: '13_4_CICDServer',\r\n        \t                transfers: [\r\n        \t                    sshTransfer(\r\n        \t                        sourceFiles: 'dist.rar',\r\n                                    remoteDirectory: '\u002Fhome\u002Fsmartsync\u002Fservice\u002F',\r\n                                    removePrefix: '', \r\n    \t                            execCommand: \"\"\"\r\n    \t                                echo \"文件上传成功！\"\r\n                                        cd \u002Fhome\u002Fsmartsync\u002Fservice\u002F\r\n                                        pwd & ls\r\n                                        tar -zxvf dist.rar\r\n                                        rm -rf web-ui\r\n                                        mv dist web-ui\r\n    \t                            \"\"\"\r\n        \t                    )\r\n        \t                ],\r\n        \t                verbose: true\r\n        \t            )\r\n        \t        ]\r\n        \t    )\r\n        \t    echo 'upload To pro 13.4 End'  \r\n        \t}\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n\r\n\r\n\r\n\r\n### 2.7.3\t流水线ssh上传文件脚本\r\n\r\n```shell\r\npipeline {\r\n    agent{\r\n        \u002F\u002F 指定从节点标签，即用从节点构建\r\n        label 'slave'\r\n    }\r\n    options {\r\n        disableConcurrentBuilds()\r\n    }\r\n    tools {\r\n        jdk 'jdk21'\r\n        maven 'maven3'\r\n        git 'git'\r\n    }\r\n    stages {\r\n        stage('git checkout') {\r\n            steps {\r\n                sh 'pwd'\r\n                git credentialsId: '1001', url: 'http:\u002F\u002F192.168.3.138\u002Fsmartsync3.5\u002Fsmartsync.git'\r\n            }\r\n        }\r\n        stage('maven deploy') {\r\n            steps {\r\n                sh \"mvn clean deploy -DskipTests=true -Dmaven.javadoc.skip=true -Dmaven.install.skip=true\"\r\n            }\r\n        }\r\n        \u002F\u002F  ssh上传jar，有的jenkins版本直接在上传jar后，直接sh启动部署脚本会报错，因此这里上传和启动分开\r\n        stage('ssh upload') {\r\n        \tsteps {\r\n        \t    echo \"upload To pro 13.4 Begin\" \r\n        \t    sshPublisher(\r\n        \t        publishers: [\r\n        \t                sshPublisherDesc(\r\n        \t                configName: '13_4_CICDServer',\r\n        \t                transfers: [\r\n        \t                    sshTransfer(\r\n        \t                        sourceFiles: 'smartsync-admin\u002Fsmartsync-center\u002Ftarget\u002Fsmartsync-admin.jar,smartsync-executor\u002Fsmartsync-executor-engine\u002Ftarget\u002Fsmartsync-executor-engine.jar',\r\n                                    remoteDirectory: '\u002Fhome\u002Fsmartsync\u002Fservice\u002F',\r\n                                    removePrefix: '', \u002F\u002F 如果只有一个jar时可以在这里直接移除前缀smartsync-admin\u002Fsmartsync-center\u002Ftarget\u002F，但这里是两个不同前缀没法直接移除，只能在sh命令中mv修改\r\n    \t                            execCommand: \"\"\"\r\n    \t                                echo \"文件上传成功！\"\r\n                                        cd \u002Fhome\u002Fsmartsync\u002Fservice\u002F\r\n                                        pwd & ls\r\n                                        mv smartsync-admin\u002Fsmartsync-center\u002Ftarget\u002Fsmartsync-admin.jar admin\u002F\r\n                                        rm -rf smartsync-admin\r\n                                        mv smartsync-executor\u002Fsmartsync-executor-engine\u002Ftarget\u002Fsmartsync-executor-engine.jar executor\u002F\r\n                                        rm -rf smartsync-executor\r\n                                        pwd & ls\r\n    \t                            \"\"\"\r\n        \t                    )\r\n        \t                ],\r\n        \t                verbose: true\r\n        \t            )\r\n        \t        ]\r\n        \t    )\r\n        \t    echo 'upload To pro 13.4 End'  \r\n        \t}\r\n        }\r\n        \u002F\u002F  ssh远程启动\r\n        stage('ssh deploy') {\r\n        \tsteps {\r\n        \t    echo \"Deploy To pro 13.4 Begin\" \r\n        \t    sshPublisher(\r\n        \t        publishers: [\r\n        \t                sshPublisherDesc(\r\n        \t                configName: '13_4_CICDServer',\r\n        \t                transfers: [\r\n        \t                    sshTransfer(\r\n    \t                            execCommand: \"\"\"\r\n                                        pwd & ls\r\n                                        cd \u002Fhome\u002Fsmartsync\u002Fservice\u002Fadmin\r\n                                        sh boot_admin.sh restart\r\n                                        cd \u002Fhome\u002Fsmartsync\u002Fservice\u002Fexecutor\r\n                                        sh boot_executor.sh restart\r\n    \t                            \"\"\"\r\n        \t                    )\r\n        \t                ],\r\n        \t                verbose: true\r\n        \t            )\r\n        \t        ]\r\n        \t    )\r\n        \t    echo 'Deploy To pro 13.4 End'  \r\n        \t}\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n\r\n\r\n\r\n\r\n# 3\tNexus私服\r\n\r\n## 3.1\t镜像安装\r\n\r\n```shell\r\n# 下拉镜像\r\ndocker pull sonatype\u002Fnexus3:3.71.0\r\n\r\n# 创建挂载目录\r\nmkdir \u002Fusr\u002Flocal\u002Fsoftware\u002Fnexus\u002Fnexus-data\r\n\r\n# 运行脚本\r\ndocker run --name nexus \\\r\n-p 8081:8081 \\\r\n--privileged=true \\\r\n-e INSTALL4J_ADD_VM_PARAMS=\"-Xms1024m -Xmx1024m -XX:MaxDirectMemorySize=1024m\" \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fnexus\u002Fnexus-data:\u002Fnexus-data \\\r\n-d sonatype\u002Fnexus3:3.71.0\r\n\r\n# 如果报错，权限不够，则给挂载目录权限\r\nchmod 777 \u002Fusr\u002Flocal\u002Fsoftware\u002Fnexus\u002Fnexus-data\r\n```\r\n\r\n\r\n\r\n## 3.2\t配置\r\n\r\n（1）打开浏览器访问：http:\u002F\u002Flocalhost:8081\u002F\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fnexus-1.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n（2）进入挂载目录，获取登录密码，默认账号为：`admin`\r\n\r\n```shell\r\ncd \u002Fusr\u002Flocal\u002Fsoftware\u002Fnexus\u002Fnexus-data\r\ncat admin.password\r\n```\r\n\r\n\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fnexus-2.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n（3）点击下一步，修改密码，然后进入如下：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fnexus-3.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n## 3.3\t创建代理库\r\n\r\n​\t\t配置代理到阿里云仓库，用于代理从阿里云下载的所有内容，下次下载相同的依赖项时，它将被缓存在您的Sonatype Nexus中。您可以根据需要创建多个仓库（例如设置多个代理到其他公共仓库），然后将它们全部分组到组仓库中。\r\n\r\n创建一个新的Maven（代理）仓库并按以下方式配置它：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fnexus-proxy.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\r\n\r\n​\t\t添加到仓库组中，并设置`maven-proxy`优先级最高，这样我们maven连接`maven-public`仓库即可，没有的依赖会自动去代理库下载，然后缓存到我们创建的`maven-proxy`代理库中。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fnexus-proxy2.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n\r\n\r\n## 3.4\t配置仓库\r\n\r\n​\t\t将上传的仓库修改为允许相同版本自动覆盖，否则无法上传相同的版本jar。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjenkins自动化部署\u002Fnexus-release.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\r\n\r\n\r\n\r\n## 3.5\t批量上传本地依赖\r\n\r\n创建`mavenimport.sh` 文件，内容如下：\r\n\r\n```shell\r\n#!\u002Fbin\u002Fbash\r\n# git 执行命令\r\n# $ ! .\u002Fmavenimport.sh -u admin -p 123456 -r http:\u002F\u002F106.53.110.52:8081\u002Frepository\u002Fmh\u002F\r\nwhile getopts \":r:u:p:\" opt;do\r\n    case $opt in\r\n        r) REPO_URL=\"$OPTARG\"\r\n        ;;\r\n        u) USERNAME=\"$OPTARG\"\r\n        ;;\r\n        p) PASSWORD=\"$OPTARG\"\r\n        ;;\r\n    esac\r\ndone\r\nfind . -type f -not -path '.\u002Fmavenimport\\.sh*' -not -path '*\u002F\\.*' -not -path '*\u002F\\^archetype\\-catalog\\.xml*' -not -path '*\u002F\\^maven\\-metadata\\-local*\\.xml' -not -path '*\u002F\\^maven\\-metadata\\-deployment*\\.xml' | sed \"s|^\\.\u002F||\" | xargs -I '{}' curl -u \"$USERNAME:$PASSWORD\" -X PUT -v -T {} ${REPO_URL}\u002F{}\r\n```\r\n\r\n执行脚本：\r\n\r\n```shell\r\n# 复制脚本到maven本地依赖的目录，然后执行\r\nsh mavenimport.sh -u admin -p 123456 -r http:\u002F\u002F106.53.110.52:8081\u002Frepository\u002Fmh\u002F\r\n```\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n# 4\tmaven配置\r\n\r\nsetting.xml内容：\r\n\r\n```xml\r\n\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n\u003Csettings xmlns=\"http:\u002F\u002Fmaven.apache.org\u002FSETTINGS\u002F1.2.0\"\r\n          xmlns:xsi=\"http:\u002F\u002Fwww.w3.org\u002F2001\u002FXMLSchema-instance\"\r\n          xsi:schemaLocation=\"http:\u002F\u002Fmaven.apache.org\u002FSETTINGS\u002F1.2.0 https:\u002F\u002Fmaven.apache.org\u002Fxsd\u002Fsettings-1.2.0.xsd\">\r\n  \u003ClocalRepository>\u002Fhome\u002Fgreat\u002Ftools\u002Fmaven-3.9.8\u002Frepository\u003C\u002FlocalRepository>\r\n\r\n  \u003Cproxies>\r\n  \u003C\u002Fproxies>\r\n\r\n  \u003Cservers>\r\n    \u003C!-- 上传jar到私有nexus服务密码  -->\r\n    \u003Cserver>\r\n      \u003Cid>GreatDeploy\u003C\u002Fid>\r\n      \u003Cusername>admin\u003C\u002Fusername>\r\n      \u003Cpassword>Great@2025\u003C\u002Fpassword>\r\n    \u003C\u002Fserver>\r\n  \u003C\u002Fservers>\r\n\r\n  \u003C!-- 依赖下载地址，指向私有nexus仓库 -->\r\n  \u003Cmirrors>\r\n    \u003Cmirror>\r\n      \u003Cid>nexus\u003C\u002Fid>\r\n      \u003CmirrorOf>*\u003C\u002FmirrorOf>\r\n      \u003Cname>nexus-maven\u003C\u002Fname>\r\n      \u003Curl>http:\u002F\u002F192.168.13.1:8081\u002Frepository\u002Fmaven-public\u002F\u003C\u002Furl>\r\n    \u003C\u002Fmirror>\r\n  \u003C\u002Fmirrors>\r\n\r\n  \u003Cprofiles>\r\n    \u003C!-- deploy jar到私有nexus地址,统一在此配置，不用在工程pom.xml中再配置 -->\r\n    \u003Cprofile>\r\n      \u003Cid>nexus-deploy\u003C\u002Fid>\r\n      \u003Cproperties>\r\n        \u003C!-- 格式：repositoryId::layout::url，其中 repositoryId 必须与 \u003Cservers> 中配置的 \u003Cid> 一致。 -->\r\n        \u003CaltReleaseDeploymentRepository>\r\n           GreatDeploy::default::http:\u002F\u002F192.168.13.1:8081\u002Frepository\u002Fmaven-releases\u002F\r\n        \u003C\u002FaltReleaseDeploymentRepository>\r\n      \u003C\u002Fproperties>\r\n    \u003C\u002Fprofile>\r\n  \u003C\u002Fprofiles>\r\n\r\n  \u003C!-- 激活环境  -->\r\n  \u003CactiveProfiles>\r\n    \u003CactiveProfile>nexus-deploy\u003C\u002FactiveProfile>\r\n  \u003C\u002FactiveProfiles>\r\n\u003C\u002Fsettings>\r\n```\r\n\r\n\r\n\r\n\r\n\r\n",{"_path":141,"slug":142,"title":143,"description":144,"excerpt":144,"date":145,"tags":146,"type":15,"cover":26,"content":148},"\u002Fknowledge\u002Foracle数据库操作文档","oracle数据库操作文档","Oracle数据库操作文档","Oracle数据库操作文档 1 启动数据库实例 **步骤：** 1.1 登录SQLPlus（使用操作系统认证或密码认证） 或 登录成功显示如下： 登录失败显示如下： 如果磁盘空间爆满无法启动，开源使用`df -h`查看哪个路径资源使用了100%，可以先清除log日志，然后启动成功了，再清理归档文件。 1.2 执行启动命","2025-08-04",[124,147],"Oracle","# Oracle数据库操作文档\r\n\r\n# 1\t启动数据库实例\r\n\r\n**步骤：**\r\n\r\n## 1.1\t登录SQLPlus（使用操作系统认证或密码认证）\r\n\r\n```bash\r\nsqlplus \u002F as sysdba  # 使用操作系统认证（需当前用户有dba权限）\r\n```\r\n\r\n或\r\n\r\n```shell\r\nsqlplus sys\u002F你的密码 as sysdba  # 使用密码认证\r\n```\r\n\r\n登录成功显示如下：\r\n\r\n```sql\r\n[oracle@zhu oracle]$ sqlplus \u002F as sysdba\r\nSQL*Plus: Release 19.0.0.0.0 - Production on Mon Aug 4 14:22:24 2025\r\nVersion 19.3.0.0.0\r\nCopyright (c) 1982, 2019, Oracle.  All rights reserved.\r\nConnected to an idle instance.\r\nSQL> \r\n```\r\n\r\n登录失败显示如下：\r\n\r\n```shell\r\n[oracle@localhost ~]$ sqlplus \u002F as sysdba\r\nSQL*Plus: Release 19.0.0.0.0 - Production on Mon Aug 4 19:45:11 2025\r\nVersion 19.3.0.0.0\r\nCopyright (c) 1982, 2019, Oracle.  All rights reserved.\r\nERROR:\r\nORA-09925: Unable to create audit trail file\r\nLinux-x86_64 Error: 28: No space left on device\r\nAdditional information: 9925\r\nORA-09925: Unable to create audit trail file\r\nLinux-x86_64 Error: 28: No space left on device\r\nAdditional information: 9925\r\n\r\nEnter user-name: \r\n```\r\n\r\n如果磁盘空间爆满无法启动，开源使用`df -h`查看哪个路径资源使用了100%，可以先清除log日志，然后启动成功了，再清理归档文件。\r\n\r\n\r\n\r\n## 1.2\t执行启动命令\r\n\r\n```\r\nSTARTUP;\r\n```\r\n\r\n启动成功显示：\r\n\r\n```sql\r\nSQL> STARTUP;\r\nORACLE instance started.\r\nTotal System Global Area 1.0100E+10 bytes\r\nFixed Size                 12684816 bytes\r\nVariable Size            4227858432 bytes\r\nDatabase Buffers         5838471168 bytes\r\nRedo Buffers               20869120 bytes\r\nDatabase mounted.\r\nDatabase opened.\r\n```\r\n\r\n\r\n\r\n## 1.3\t查看pdbs\r\n\r\n```shell\r\nshow pdbs;\r\n```\r\n\r\n执行后显示：\r\n\r\n```shell\r\nSQL> show pdbs;\r\n    CON_ID CON_NAME                       OPEN MODE  RESTRICTED\r\n---------- ------------------------------ ---------- ----------\r\n         2 PDB$SEED                       READ ONLY  NO\r\n         3 ORCLPDB1                       MOUNTED\r\n         4 PDB1                           MOUNTED\r\n```\r\n\r\n**开启对应的pdb，修改RESTRICTED为空的pdb：**\r\n\r\n```shell\r\nalter pluggable database pdb名称 open;\r\n```\r\n\r\n\r\n\r\n## 1.4\t查看实例状态\r\n\r\n```shell\r\nSELECT status FROM v$instance;  -- 状态应为 `OPEN`\r\nSELECT open_mode FROM v$database; -- 确认打开模式\r\n```\r\n\r\n结果显示：\r\n\r\n```shell\r\nSQL> select status from v$instance;\r\n\r\nSTATUS\r\n------------\r\nOPEN\r\n```\r\n\r\n执行完以上步骤后`exit`退出。\r\n\r\n\r\n\r\n## 1.5\t开启监听\r\n\r\n开启了监听器，外部才能够连接数据库。\r\n\r\n```shell\r\nlsnrctl start  # 启动监听器\r\nlsnrctl status # 检查状态\r\n```\r\n\r\n成功信息如下：\r\n\r\n```shell\r\n[oracle@zhu oracle]$ lsnrctl start\r\nLSNRCTL for Linux: Version 19.0.0.0.0 - Production on 04-AUG-2025 14:26:55\r\nCopyright (c) 1991, 2019, Oracle.  All rights reserved.\r\nStarting \u002Fopt\u002Foracle\u002Fproduct\u002F19c\u002Fdbhome_1\u002Fbin\u002Ftnslsnr: please wait...\r\nTNSLSNR for Linux: Version 19.0.0.0.0 - Production\r\nSystem parameter file is \u002Fopt\u002Foracle\u002Fproduct\u002F19c\u002Fdbhome_1\u002Fnetwork\u002Fadmin\u002Flistener.ora\r\nLog messages written to \u002Fopt\u002Foracle\u002Fdiag\u002Ftnslsnr\u002Fzhu\u002Flistener\u002Falert\u002Flog.xml\r\n.................\r\nThe command completed successfully\r\n```\r\n\r\n\r\n\r\n## 1.6\t关闭数据库\r\n\r\n```\r\nSHUTDOWN IMMEDIATE;  -- 安全关闭（回滚活动事务）\r\nSHUTDOWN NORMAL;     -- 等待所有会话退出（可能阻塞）\r\nSHUTDOWN ABORT;      -- 强制关闭（仅用于故障场景）\r\n```\r\n\r\n\r\n\r\n## 1.7\t常见问题排查\r\n\r\n（1）**监听器未启动** → 客户端无法连接。\r\n\r\n（2）**权限不足** → 确保用户属于`dba`组或使用`sysdba`登录。\r\n\r\n（3）**参数文件错误** → 检查`spfile`或`pfile`路径：\r\n\r\n```\r\nCREATE SPFILE FROM PFILE='\u002Fpath\u002Fto\u002Finit.ora';  -- 重建参数文件\r\n```\r\n\r\n（4）**存储空间不足** → 检查数据库log日志、归档日志和表空间。\r\n\r\n\r\n\r\n# 2\tOracle19c清理归档日志\r\n\r\n## 2.1\t增加归档空间设置\r\n\r\n### 2.1.1\t使用sys登录数据库\r\n\r\n```shell\r\nsqlplus \u002F as sysdba;\r\n```\r\n\r\n### 2.1.2\t查看flash recovery area的使用情况\r\n\r\n```sql\r\nselect * from V$FLASH_RECOVERY_AREA_USAGE;\r\n```\r\n\r\n### 2.1.3 查看recovery目录\r\n\r\n```sql\r\nshow parameter recovery;\r\n```\r\n\r\n### 2.1.4 增加归档空间设置\r\n\r\n```sql\r\nalter system set db_recovery_file_dest_size=500G scope=spfile(需要重启DB生效)\r\n```\r\n\r\n\r\n\r\n## 2.2 使用rman清理归档日志\r\n\r\n### 2.2.1\t登录rman\r\n\r\n```shell\r\nrman target \u002F\r\n```\r\n\r\n### 2.2.2\t检查控制文件和实际物理文件的差别\r\n\r\n```shell\r\ncrosscheck archivelog all;\r\n```\r\n\r\n执行crosscheck命令，检查控制文件和实际物理文件的差别，如果物理文件不存在于介质上，将标记为expired（失效\u002F不可用），crosscheck之后，就可以删除这些失效的归档日志了(执行脚本后，删除的归档日志状态会变为“失效”)\r\n\r\n### 2.2.3\t同步检查控制文件和实际物理文件的信息\r\n\r\n删除状态为expired（失效\u002F不可用）的归档日志\r\n\r\n```shell\r\nRMAN> delete expired archivelog all;\r\n```\r\n\r\n### 2.2.4\t显示全部的归档日志\r\n\r\n```shell\r\nlist archivelog all;\r\n```\r\n\r\n### 2.2.5\t手工删除归档日志文件\r\n\r\n**删除 3 天前的归档日志：**\r\n\r\n```shell\r\nRMAN> delete archivelog all completed before 'sysdate-3';\r\n```\r\n\r\n**删除 1 天前：**\r\n\r\n```shell\r\nRMAN> delete archivelog until time 'sysdate-1'\r\nRMAN> delete archivelog until time 'sysdate-1\u002F12'\r\n```\r\n\r\n\r\n\r\n------\r\n\r\n区别：第一条带complete的语句，主要是删除已备份过的归档，不会删除闪回区有效的归档日志。而第二个语句， 则会删除掉归档，无论是不是闪回区有效的归档日志。\r\n\r\n\r\n\r\n## 2.3\t离线删除归档\r\n\r\n除非磁盘占满，数据库无法启动，否则不建议。\r\n\r\n归档路径如：\r\n\r\n```shell\r\n\u002Fopt\u002Foracle\u002Fproduct\u002F19c\u002Fdbhome_1\u002Fdbs\u002F1_2203_1117811974.dbf\r\n\u002Fopt\u002Foracle\u002Fproduct\u002F19c\u002Fdbhome_1\u002Fdbs\u002F1_2204_1117811974.dbf\r\n```\r\n\r\n\r\n\r\n```shell\r\n\u002Fopt\u002Foracle\u002Fproduct\u002F19c\u002Fdbhome_1\u002Flog\u002F\r\n```\r\n\r\n",{"_path":150,"slug":151,"title":152,"description":153,"excerpt":153,"date":154,"tags":155,"type":15,"cover":157,"content":158},"\u002Fknowledge\u002Fflink入门","flink入门","Flink 快速入门","Flink 快速入门 1 简介 2 Flink 部署 2.1 官网下载 下载地址：https:\u002F\u002Fflink.apache.org\u002Fdownloads\u002F#apache-flink-downloads","2025-06-26",[124,156],"Flink","\u002Fknowledge-assets\u002Fflink入门\u002Fflink-download.png","# Flink 快速入门\r\n\r\n# 1\t简介\r\n\r\n\r\n\r\n# 2\tFlink 部署\r\n\r\n## 2.1\t官网下载\r\n\r\n[下载地址](https:\u002F\u002Fflink.apache.org\u002Fdownloads\u002F#apache-flink-downloads)：https:\u002F\u002Fflink.apache.org\u002Fdownloads\u002F#apache-flink-downloads\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fflink入门\u002Fflink-download.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n## 2.2\t上传并解压\r\n\r\n```shell\r\ncd \u002Fhome\u002Fflink\r\ntar -zxvf flink-1.20.1-bin-scala_2.12.tgz\r\n```\r\n\r\n\r\n\r\n## 2.3\t修改集群配置\r\n\r\n\r\n\r\n\r\n\r\nnetcat网络连接工具\r\n\r\n​\t\t在Linux系统中，`netcat`（nc）是一个非常有用的网络工具，用于读写TCP和UDP协议的网络连接。\r\n\r\n```\r\n# 安装，对于CentOS 7及更早版本\r\nsudo yum install nc  \r\n\r\nnc -lk 7777\r\n```\r\n\r\n​\t\t\r\n\r\n\r\n\r\n\r\n\r\n",{"_path":160,"slug":161,"title":162,"description":163,"excerpt":163,"date":164,"tags":165,"type":15,"cover":167,"content":168},"\u002Fknowledge\u002Fgradle安装与使用","gradle安装与使用","Gradle安装与使用","Gradle安装与使用 1 Gradle入门 ​ **Java项目构建**是软件开发中至关重要的一个环节，涵盖了**依赖管理、编译、测试和打包等**多个步骤。 1.1 Gradle简介 ​ Gradle 是一款Google 推出的**基于 JVM、**通用灵活的**项目构建工具，**它使用一种基于Groovy的特定领域","2025-06-12",[74,104,166,136],"Gradle","\u002Fknowledge-assets\u002Fgradle安装与使用\u002Fimage.png","# Gradle安装与使用\r\n\r\n# 1\tGradle入门\r\n\r\n​\t**Java项目构建**是[软件开发](https:\u002F\u002Fso.csdn.net\u002Fso\u002Fsearch?q=软件开发&spm=1001.2101.3001.7020)中至关重要的一个环节，涵盖了**依赖管理、编译、测试和打包等**多个步骤。\r\n\r\n## 1.1\tGradle简介\r\n\r\n​\tGradle 是一款Google 推出的**基于 JVM、**通用灵活的**项目构建工具，**它使用一种基于[Groovy](https:\u002F\u002Fbaike.baidu.com\u002Fitem\u002FGroovy\u002F180590?fromModule=lemma_inlink)的特定领域语言([DSL](https:\u002F\u002Fbaike.baidu.com\u002Fitem\u002FDSL\u002F60963557?fromModule=lemma_inlink))来声明项目设置，也增加了基于[Kotlin](https:\u002F\u002Fbaike.baidu.com\u002Fitem\u002FKotlin\u002F1133714?fromModule=lemma_inlink)语言的kotlin-based DSL，抛弃了基于[XML](https:\u002F\u002Fbaike.baidu.com\u002Fitem\u002FXML\u002F86251?fromModule=lemma_inlink)的各种烦琐配置。\r\n\r\n​\tGradle配置灵活，可以用来构建native的C\u002FC++程序，甚至扩展到任何语言的构建。现在一些主流的项目也是使用了Gradle来管理项目，spring家族源码已经使用Gradle作为项目管理。\r\n\r\n​\t如果你的项目没有太多自定义构建需求的话还是推荐使用Maven，但是如果有自定义的构建需求，那么还是投入Gradle的怀抱吧。\r\n\r\n​\t[官网](https:\u002F\u002Fgradle.org\u002F)：https:\u002F\u002Fgradle.org\r\n\r\n## 1.2\t常见的项目构建工具\r\n\r\n- **Ant**: 2000 年 Apache 推出的纯Java 编写构建工具，通过 xml[build.xml]文件管理项目。\r\n\r\n  优点：使用灵活，速度快(快于 gradle 和 maven)。\r\n\r\n​\t缺点：Ant 没有强加任何编码约定的项目目录结构，开发人员需编写繁杂XML 文件构建指令，对开发人员是一个挑战。\r\n\r\n- **Maven**: 2004 年Apache 组织推出的再次使用xml 文件[pom.xml]管理项目的构建工具。\r\n\r\n​\t优点: 遵循一套约定大于配置的项目目录结构，使用统一的GAV 坐标进行依赖管理，**侧重于包管理**。\r\n\r\n​\t缺点：项目构建过程僵化，配置文件编写不够灵活、不方便自定义组件，构建速度慢于 gradle。\r\n\r\n- **Gradle**: 2012 年Google 推出的基于**Groovy** 语言的全新项目构建工具，集合了Ant 和 Maven 各自的优势。\r\n\r\n​\t优点：集 Ant 脚本的灵活性+Maven 约定大于配置的项目目录优势，支持多种远程仓库和插件，侧重于**大项目构建**。\r\n\r\n​\t缺点：学习成本高、资料少、脚本灵活、版本兼容性差等。\r\n\r\n（1）三者比较\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002Fimage.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n（2）使用gradle和maven构建小项目（10个模块，每个模块50个源文件和50个测试文件）的比较：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002Fe233142aa92ab3006ec050c0dbdba106.png\" style=\"zoom:40%;\" \u002F>\r\n\r\n（3）使用gradle和maven构建大项目（500个模块，每个模块100个源文件和100个测试文件）的比较：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002Ff157313271f4c210482a4c7d271abe93.png\" style=\"zoom:40%;\" \u002F>\r\n\r\n## 1.3\tGradle 安装\r\n\r\n### 1.3.1\tGradle 安装说明\r\n\r\n（1）SpringBoot 与Gradle 存在版本兼容问题。SpringBoot 官方文档明确指出，目前SpringBoot 3.x的 Gradle 插件需要Gradle7.x 版本及以上。[springboot官方文档](https:\u002F\u002Fdocs.spring.io\u002Fspring-boot\u002Finstalling.html)：https:\u002F\u002Fdocs.spring.io\u002Fspring-boot\u002Finstalling.html\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002FSnipaste_2025-05-11_19-01-02.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n（2）Gradle 与Idea 也存在兼容问题。在idea安装根目录下，可以查看当前idea版本兼容的Gradle版本。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002FSnipaste_2025-05-11_19-05-02.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n### 1.3.2\t安装jdk\r\n\r\n​\t要求Jdk 为 1.8 或者 1.8 版本以上。\r\n\r\n### 1.3.3\t下载Gradle\r\n\r\n​\t[下载](https:\u002F\u002Fgradle.org\u002Freleases\u002F)：https:\u002F\u002Fgradle.org\u002Freleases\u002F\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002FSnipaste_2025-05-11_19-13-28.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n​\t和maven一样，解压即可使用，不需要安装，这里解压到D:\\openSource\\gradle-8.10.2目录。\r\n\r\n### 1.3.4\t配置环境变量\r\n\r\n- **GRADLE_HOME**：D:\\openSource\\gradle-8.10.2\r\n  - 再配置PATH环境变量：%GRADLE_HOME%\\bin\r\n- **GRADLE_USER_HOME**： D:\\openSource\\gradle-repository\r\n  - 相当于配置Gradle 本地仓库位置和 Gradle Wrapper 缓存目录。\r\n  - Gradle本地仓库可以和Maven本地仓库目录一致\r\n- **M2_HOME**：D:\\openSource\\gradle-repository\r\n  - 指向本地仓库\r\n\r\n### 1.3.5\t检测是否安装成功\r\n\r\n```cmd\r\ngradle -v \r\n# 或者\r\ngradle --version\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002FSnipaste_2025-05-11_19-25-12.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n### 1.3.6\t配置国内镜像源\r\n\r\n​\tGradle 自带的Maven 源地址是国外的，该Maven 源在国内的访问速度是很慢的，除非使用了特别的手段。一般情况下，我们建议使用国内的第三方开放的Maven 源或企业内部自建Maven 源。\r\n\r\n​\t在Gradle安装根目录下的init.d文件夹，创建一个后缀为`.gradle`的文件，如：`init.gradle`文件。并添加以下内容：\r\n\r\n```properties\r\nallprojects {\r\n    repositories {\r\n\t\t\u002F\u002F 当去找依赖的时候，按顺序从上到下查找\r\n\t\t\u002F\u002F本地仓库，但需要配置环境变量 M2_HOME 指向本地库\r\n\t\tmavenLocal()\r\n        \u002F\u002F 阿里云镜像\r\n        maven { name \"aliyun\"; url 'https:\u002F\u002Fmaven.aliyun.com\u002Frepository\u002Fpublic\u002F' }\r\n\t\tmaven { name \"Bstek\"; url 'https:\u002F\u002Fmaven.aliyun.com\u002Frepository\u002Fgradle-plugin\u002F' }\r\n        \r\n        \u002F\u002F 备用镜像源\r\n        maven { name \"huawei\"; url 'https:\u002F\u002Fmirrors.huaweicloud.com\u002Frepository\u002Fmaven\u002F' }\r\n\t\t\u002F\u002F 上面都找不到的话，去maven中央仓库找\r\n        mavenCentral()\r\n    }\r\n    \r\n    buildscript {\r\n        repositories {\r\n            maven { name \"aliyun\"; url 'https:\u002F\u002Fmaven.aliyun.com\u002Frepository\u002Fpublic\u002F' }\r\n            maven { name \"Bstek\"; url 'https:\u002F\u002Fmaven.aliyun.com\u002Frepository\u002Fgradle-plugin\u002F' }\r\n\t\t\tmaven { name \"M2\"; url 'https:\u002F\u002Fmaven.aliyun.com\u002Frepository\u002Fgradle-plugin\u002F' }\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n\r\n\r\n**拓展 一**：启用init.gradle 文件的方法有\r\n\r\n1. 在命令行指定文件，例如：`gradle --init-script yourdir\u002Finit.gradle -q taskName`。可以多次输入此命令来指定多个init文件\r\n2. 把init.gradle文件放到 `USER_HOME\u002F.gradle\u002F` 目录下\r\n3. 把以.gradle结尾的文件放到 `USER_HOME\u002F.gradle\u002Finit.d\u002F` 目录下\r\n4. 把以.gradle结尾的文件放到 `GRADLE_HOME\u002Finit.d\u002F` 目录下\r\n\r\n​\t如果存在上面的4种方式的2种以上，gradle会按上面的1-4序号依次执行这些文件，如果给定目录下存在多个init脚本，会按拼音a-z顺序执行这些脚本，每个init脚本都存在一个对应的gradle实例，你在这个文件中调用的所有方法和属性，都会委托给这个gradle实例，每个init脚本都实现了Script接口。\r\n\r\n**拓展** 二：仓库地址说明\r\n\r\n- mavenLocal()：指定使用maven本地仓库，而本地仓库在配置maven时settings文件指定的仓库位置。如E:\u002Frepository，gradle 查找jar包顺序如下：USER_HOME\u002F.m2\u002Fsettings.xml >> M2_HOME\u002Fconf\u002Fsettings.xml >> USER_HOME\u002F.m2\u002Frepository\r\n\r\n- maven { url 地址}：指定maven仓库，一般用私有仓库地址或其它的第三方库【比如阿里镜像仓库地址】。\r\n\r\n- mavenCentral()：这是Maven的中央仓库，无需配置，直接声明就可以使用。\r\n\r\n- jcenter()：JCenter中央仓库，实际也是是用的maven搭建的，但相比Maven仓库更友好，通过CDN分发，并且支持https访问，在新版本中已经废弃了，替换为了mavenCentral()。\r\n\r\n​\t总之，gradle可以通过指定仓库地址为本地maven仓库地址和远程仓库地址相结合的方式，避免每次都会去远程仓库下载依赖库。这种方式也有一定的问题，如果本地maven仓库有这个依赖，就会从直接加载本地依赖，如果本地仓库没有该依赖，那么还是会从远程下载。但是下载的jar不是存储在本地maven仓库中，而是放在自己的缓存目录中，默认在USER_HOME\u002F.gradle\u002Fcaches目录，当然如果我们配置过GRADLE_USER_HOME环境变量，则会放在GRADLE_USER_HOME\u002Fcaches目录，那么可不可以将gradle caches指向maven repository。我们说这是不行的，caches下载文件不是按照maven仓库中存放的方式。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002FSnipaste_2025-05-11_20-42-26.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n**拓展** 三：阿里云仓库地址请参考：https:\u002F\u002Fdeveloper.aliyun.com\u002Fmvn\u002Fguide\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002FSnipaste_2025-05-11_20-47-38.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n在gradle 中的使用说明：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002FSnipaste_2025-05-11_20-49-19.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\r\n\r\n1.4\tGradle项目目录\r\n\r\n​\tGradle 项目**默认目录结构和Maven 项目的目录结构一致**，都是基于**约定大于配置**【Convention Over Configuration】。其完整项目目录结构如下所示：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002Fgradle项目目录.jpeg\" style=\"zoom:50%;\" \u002F>\r\n\r\n> 1. 只有war工程才有webapp目录，对于普通的jar工程并没有webapp目录；\r\n> 2. gradlew与gradlew.bat执行指定wrapper版本中的gradle指令，不是本地安装的gradle指令；\r\n> 3. wrapper中的gradle版本不一定会跟安装的gradle版本一致。\r\n\r\n### 1.3.7\tGradle 创建第一个项目\r\n\r\n**借助于 spring 脚手架创建gradle 第一个项目**：https:\u002F\u002Fstart.spring.io\u002F\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002FSnipaste_2025-05-11_20-06-57.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n查看生成的gradle 项目目录结构如下所示:\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002FSnipaste_2025-05-11_20-11-23.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n在build.gradle文件中，引入的依赖配置如下：\r\n\r\n```properties\r\nplugins {\r\n\tid 'java'\r\n\tid 'org.springframework.boot' version '3.4.5'\r\n\tid 'io.spring.dependency-management' version '1.1.7'\r\n}\r\n\r\ngroup = 'com.mh'\r\nversion = '0.0.1-SNAPSHOT'\r\n\r\njava {\r\n\ttoolchain {\r\n\t\tlanguageVersion = JavaLanguageVersion.of(17)\r\n\t}\r\n}\r\n\r\nrepositories {\r\n\tmavenCentral()\r\n}\r\n\r\n# 依赖信息，格式：implementation '[GROUP_ID]:[ARTIFACT_ID]:[VERSION]'\r\n# 这是Groovy语法，也可以使用括号()或者单独引号\r\ndependencies {\r\n\timplementation 'org.springframework.boot:spring-boot-starter'\r\n\ttestImplementation 'org.springframework.boot:spring-boot-starter-test'\r\n\ttestRuntimeOnly 'org.junit.platform:junit-platform-launcher'\r\n\timplementation(\"com.baomidou:mybatis-plus-boot-starter:3.5.11\")\r\n}\r\n\r\ntasks.named('test') {\r\n\tuseJUnitPlatform()\r\n}\r\n```\r\n\r\n\r\n\r\n### 1.3.8\tGradle 中的常用指令\r\n\r\nGradle 常用命令说明:\r\n\r\n| Gradle常用命令       | 说明                         |\r\n| -------------------- | ---------------------------- |\r\n| gradle clean         | 清空build目录                |\r\n| gradle classes       | 编译业务代码和配置文件       |\r\n| gradle test          | 编译测试代码，并生成测试报告 |\r\n| gradle build         | 构建项目                     |\r\n| gradle build -x test | 跳过测试构建项目             |\r\n\r\n> **gradle 的指令要在含有build.gradle 的目录执行**。\r\n\r\n### 1.3.9\tWrapper 包装器\r\n\r\n​\tGradle Wrapper 实际上就是对 Gradle 的一层包装，用于解决实际开发中可能会遇到的不同的项目需要不同版本的 Gradle问题。\r\n\r\n​\t例如：把自己的代码共享给其他人使用，可能出现如下情况:\r\n\r\n- 对方电脑没有安装 gradle\r\n- 对方电脑安装过 gradle，但是版本太旧了\r\n\r\n​\t这时候，我们就可以考虑使用 Gradle Wrapper 了。这也是官方建议使用 Gradle Wrapper 的原因。实际上有了 Gradle Wrapper 之后，我们本地是可以不配置 Gradle 的，下载Gradle 项目后，使用 gradle 项目自带的wrapper 操作也是可以的。\r\n\r\n​\t那如何使用Gradle Wrapper 呢？\r\n\r\n​\t项目中的gradlew、gradlew.cmd脚本用的就是wrapper中规定的gradle版本。而我们上面提到的gradle指令用的是本地gradle，所以gradle指令和gradlew指令所使用的gradle版本**有可能是不一样的**。\r\n\r\n​\tgradlew、gradlew.cmd的使用方式与gradle使用方式完全一致，只不过把gradle指令换成了gradlew指令。\r\n\r\n​\t当然，我们也可在终端执行 gradlew 指令时，指定指定一些参数，来控制 Wrapper 的生成，比如依赖的版本等，如下：\r\n\r\n| 参数名                    | 说明                              |\r\n| ------------------------- | --------------------------------- |\r\n| --gradle-version          | 用于指定使用的gradle版本          |\r\n| --gradle-distribution-url | 用于指定下载Gradle发行版的url地址 |\r\n\r\n具体操作如下所示 ：\r\n\r\n```shell\r\n# 升级wrapper版本号，只是修改gradle.properties中wrapper版本，未实际下载，等到更新依赖或者构建时才会下载\r\ngradle wrapper --gradle-version=4.4\r\n\r\n# 关联源码用\r\ngradle wrapper --gradle-version 5.2.1 --distribution-type all\r\n```\r\n\r\n\r\n\r\nGradleWrapper 的执行流程\r\n\r\n1. 当我们第一次执行 `.\u002Fgradlew build`命令的时候，gradlew 会读取 gradle-wrapper.properties 文件的配置信息\r\n2. 准确的将指定版本的 gradle 下载并解压到指定的位置(GRADLE_USER_HOME目录下的wrapper\u002Fdists目录中)\r\n3. 并构建本地缓存(GRADLE_USER_HOME目录下的caches目录中)，下载再使用相同版本的gradle就不用下载了\r\n4. 之后执行的 .\u002Fgradlew 所有命令都是使用指定的 gradle 版本。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002Fgradlew.jpeg\" style=\"zoom:50%;\" \u002F>\r\n\r\ngradle-wrapper.properties 文件解读:\r\n\r\n```properties\r\n#下载的Gradle压缩包解压后存储的主目录\r\ndistributionBase=GRADLE_USER_HOME\r\n#解压后的Gradle压缩包的子路径\r\ndistributionPath=wrapper\u002Fdists\r\n#Gradle发行版压缩包的下载地址\r\ndistributionUrl=https\\:\u002F\u002Fservices.gradle.org\u002Fdistributions\u002Fgradle-8.13-bin.zip\r\n#网络超时时间\r\nnetworkTimeout=10000\r\nvalidateDistributionUrl=true\r\n# 存放zip压缩包的主目录\r\nzipStoreBase=GRADLE_USER_HOME\r\n# 存放zip压缩包的子目录\r\nzipStorePath=wrapper\u002Fdists\r\n```\r\n\r\n> 注意：\r\n>\r\n> ​\t前面提到的 **GRALE_USER_HOME 环境变量**用于这里的Gradle Wrapper 下载的特定版本的gradle 存储目录。如果我们**没有配置过GRALE_USER_HOME 环境变量，默认在当前用户家目录下的.gradle 文件夹中。**\r\n\r\n\r\n\r\n- 那什么时候选择使用 gradle wrapper、什么时候选择使用本地gradle?\r\n\r\n​\t下载别人的项目或者使用操作以前自己写的不同版本的gradle项目时：用Gradle wrapper，也即:gradlew\r\n\r\n- 什么时候使用本地gradle?\r\n\r\n  新建一个项目时: 使用gradle指令即可。\r\n\r\n  \r\n\r\n# 2\tGroovy\r\n\r\n## 2.1\tGroovy简介\r\n\r\n​\t在某种程度上，Groovy 可以被视为Java 的一种脚本化改良版，Groovy 也是运行在 JVM 上，它可以很好地与 Java 代码及其相关库进行交互操作。它是一种成熟的面向对象编程语言，既可以面向对象编程，又可以用作纯粹的脚本语言。大多数有效的 Java 代码也可以转换为有效的 Groovy 代码，Groovy 和 Java 语言的主要区别是：完成同样的任务所需的Groovy 代码比 Java 代码更少。\r\n\r\n​\t其特点为：\r\n\r\n- 功能强大，例如提供了动态类型转换、**闭包**和元编程（metaprogramming）支持\r\n- 支持函数式编程，不需要main 函数\r\n- 默认导入常用的包\r\n- 类不支持 default 作用域，且默认作用域为public。\r\n- Groovy 中基本类型也是对象，可以直接调用对象的方法。\r\n- 支持DSL（Domain Specific Languages 领域特定语言）和其它简洁的语法，让代码变得易于阅读和维护。\r\n- Groovy 是基于Java 语言的，所以完全兼容Java 语法，所以对于java 程序员学习成本较低。\r\n\r\n\r\n\r\n# 3\tGradle与Idea整合\r\n\r\n## 3.1\tIdea安装Gradle插件\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002FSnipaste_2025-05-11_22-48-59.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n## 3.2\t创建普通java工程\r\n\r\n### 3.2.1\t创建由Gradle 管理的项目\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002FSnipaste_2025-05-11_22-44-27.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n### 3.2.2\t修改使用本地Gradle\r\n\r\n​\t修改当前项目使用本地安装的gradle，可以加快下载项目依赖jar 包的速度【配置了私服地址】。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002FSnipaste_2025-05-11_22-55-01.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n### 3.3\t项目结构\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002FSnipaste_2025-05-11_23-05-21.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n# 4\tGredle进阶\r\n\r\n## Dependencies\r\n\r\n### 依赖的方式\r\n\r\n```groovy\r\ndependencies {\r\n\t\u002F\u002F①.依赖当前项目下的某个模块[子工程]\r\n\timplementation project(':subject01')\r\n\t\u002F\u002F②.直接依赖本地的某个jar文件\r\n\timplementation files('libs\u002Ffoo.jar'， 'libs\u002Fbar.jar')\r\n\t\u002F\u002F②.配置某文件夹作为依赖项\r\n\timplementation fileTree(dir: 'libs'， include: ['*.jar'])\r\n\t\u002F\u002F③.直接依赖\r\n\timplementation 'org.apache.logging.log4j:log4j:2.17.2'\r\n}\r\n```\r\n\r\n​\t\t**直接依赖**：在项目中直接导入的依赖，就是直接依赖：`implementation 'org.apache.logging.log4j:log4j:2.17.2' `上面是简写法，完整版写法如下：\r\n\r\n```groovy\r\ndependencies {\r\n\timplementation group: 'org.apache.logging.log4j'， name: 'log4j'， version: '2.17.2'\r\n}\r\n```\r\n\r\n​\t\tgroup\u002Fname\u002Fversion 共同定位一个远程仓库，version 最好写一个固定的版本号，以防构建出问题，implementation 类似maven 中的依赖的scope，对比 maven 中的依赖:\r\n\r\n```xml\r\n\u003Cdependencies>\r\n    \u003Cdependency>\r\n        \u003CgroupId>log4j\u003C\u002FgroupId>\r\n        \u003CartifactId>log4j\u003C\u002FartifactId>\r\n        \u003Cversion>1.2.12\u003C\u002Fversion>\r\n        \u003Cscope>compile\u003C\u002Fscope>\r\n    \u003C\u002Fdependency>\r\n\u003C\u002Fdependencies>\r\n```\r\n\r\n### 依赖的下载\r\n\r\n​\t\t当执行 build 命令时，gradle 就会去配置的依赖仓库中下载对应的 Jar，并应用到项目中。\r\n\r\n### 依赖的类型\r\n\r\n​\t\t类似于 Maven 的 scope 标签，gradle 也提供了依赖的类型，具体如下所示：\r\n\r\n| 类型               | 描述                                                         |\r\n| ------------------ | ------------------------------------------------------------ |\r\n| compileOnly        | 由java插件提供，适用于编译期需要而不需要打包的情况。         |\r\n| runtimeOnly        | 由 java 插件提供，只在运行期有效，编译时不需要，比如mysql 驱动包。取代老版本中被移除的 runtime |\r\n| implementation     | 由 java 插件提供，针对源码[src\u002Fmain 目录] ，在编译、运行时都有效，取代老版本中被移除的 compile |\r\n| testCompileOnly    | 由 java 插件提供，用于编译测试的依赖项，运行时不需要         |\r\n| testRuntimeOnly    | 由 java 插件提供，只在测试运行时需要，而不是在测试编译时需要，取代老版本中被移除的testRuntime |\r\n| testImplementation | 由 java 插件提供，针对测试代码[src\u002Ftest 目录] 取代老版本中被移除的testCompile |\r\n| providedCompile    | war 插件提供支持，编译、测试阶段代码需要依赖此类jar 包，而运行阶段容器已经提供了相应的支持，所以无需将这些文件打入到war 包中了;例如servlet-api.jar、jsp-api.jar |\r\n| api                | java-library 插件提供支持，这些依赖项可以传递性地导出给使用者，用于编译时和运行时。取代老版本中被移除的 compile |\r\n| compileOnlyApi     | java-library 插件提供支持，在声明模块和使用者在编译时需要的依赖项，但在运行时不需要。 |\r\n\r\n**官方文档参考：**\r\n\r\n-  [执行java命令时都使用了哪些依赖范围的依赖](https:\u002F\u002Fdocs.gradle.org\u002Fcurrent\u002Fuserguide\u002Fjava_plugin.html)：https:\u002F\u002Fdocs.gradle.org\u002Fcurrent\u002Fuserguide\u002Fjava_plugin.html\r\n- [各个依赖范围的关系和说明](https:\u002F\u002Fdocs.gradle.org\u002Fcurrent\u002Fuserguide\u002Fjava_library_plugin.html)：https:\u002F\u002Fdocs.gradle.org\u002Fcurrent\u002Fuserguide\u002Fjava_library_plugin.html\r\n- [API 和implemention 区别](https:\u002F\u002Fdocs.gradle.org\u002Fcurrent\u002Fuserguide\u002Fjava_library_plugin.html#java_library_plugin)：https:\u002F\u002Fdocs.gradle.org\u002Fcurrent\u002Fuserguide\u002Fjava_library_plugin.html#java_library_plugin\r\n- [依赖范围升级和移除](https:\u002F\u002Fdocs.gradle.org\u002Fcurrent\u002Fuserguide\u002Fupgrading_version_8.html)：https:\u002F\u002Fdocs.gradle.org\u002Fcurrent\u002Fuserguide\u002Fupgrading_version_8.html\r\n\r\n\r\n\r\n\r\n\r\n## Gradle 插件\r\n\r\n### 插件的作用\r\n\r\n​\t\t在项目构建过程中做很多事情，把插件应用到项目中，通常可以完成:\r\n\r\n1. 可以添加任务【task】到项目中，从而帮助完成测试、编译、打包等。\r\n2. 可以添加依赖配置到项目中。\r\n3. 可以向项目中拓展新的扩展属性、方法等。\r\n4. 可以对项目进行一些约定，如应用 Java 插件后，约定src\u002Fmain\u002Fjava 目录是我们的源代码存在位置，编译时编译这个目录下的Java 源代码文件。\r\n\r\n### 插件的分类和使用\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002Fgradle插件分类.jpeg\" style=\"zoom:80%;\" \u002F>\r\n\r\n#### 第一种：脚本插件\r\n\r\n​\t\t脚本插件的本质就是一个脚本文件，使用脚本插件时通过apply from:将脚本加载进来就可以了，后面的脚本文件可以是本地的也可以是网络上的脚本文件。\r\n\r\n#### 第二种：对象插件之内部插件[核心插件]\r\n\r\n​\t\t二进制插件[对象插件]就是实现了 org.gradle.api.Plugin  接口的插件，每个 Java Gradle 插件都有一个 plugin id。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002F对象插件.jpeg\" style=\"zoom:80%;\" \u002F>\r\n\r\n​\t\t待补充。。。\r\n\r\n#### 第二种：对象插件之第三方插件\r\n\r\n直接使用 plugins DSL 的方式引用：\r\n\r\n```groovy\r\nplugins {\r\n    id 'java'\r\n    id 'org.springframework.boot' version '3.5.0'\r\n    id 'io.spring.dependency-management' version '1.1.7'\r\n}\r\n```\r\n\r\n#### 第二种：对象插件之用户自定义插件\r\n\r\n待补充。。。\r\n\r\n\r\n\r\n## buildSrc 项目\r\n\r\n​\t\tbuildSrc 是Gradle 默认的插件目录，编译 Gradle 的时候会自动识别这个目录，将其中的代码编译为插件。\r\n\r\n\r\n\r\n## build.gradle 文件\r\n\r\n- build.gradle 是一个gradle 的构建脚本文件,支持java、groovy 等语言。\r\n- 每个project 都会有一个build.gradle 文件,该文件是项目构建的入口,可配置版本、插件、依赖库等信息。\r\n- 每个build 文件都有一个对应的 Project 实例,对build.gradle 文件配置，本质就是设置Project 实例的属性和方法。\r\n- 由于每个 project 都会有一个build 文件,那么Root Project 也不列外.Root Project 可以获取到所有 Child Project,所以在Root Project 的 build 文件中我们可以对Child Project 统一配置,比如应用的插件、依赖的maven 中心仓库等。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fgradle安装与使用\u002Fbuild-gradle.jpeg\" style=\"zoom:80%;\" \u002F>\r\n\r\n### 常见属性代码\r\n\r\n```shell\r\ngroup = 'com.mh'\r\nversion = '0.0.1-SNAPSHOT'\r\n\r\nsourceCompatibility = 17\r\ntargetCompatibility = 17\r\ncompileJava.options.encoding \"UTF-8\"\r\ncompileTestJava.options.encoding \"UTF-8\"\r\n```\r\n\r\n### Repositories\r\n\r\n​\t\tGradle 没有自己的远程仓库，而是使用 Maven、jcenter、jvy、google 这些远程仓库。\r\n\r\n```groovy\r\nrepositories {\r\n    \u002F\u002Fgradle中会按着仓库配置的顺序，从上往下依次去对应的仓库中找所需要的jar包:\r\n    \u002F\u002F如果找到，则停止向下搜索，如果找不到，继续在下面的仓库中查找\r\n    \u002F\u002F指定去本地某个磁盘目录中查找:使用本地file文件协议:一般不用这种方式\r\n    maven { url 'file:\u002F\u002F\u002FD:\u002Frepos\u002Fmavenrepos3.5.4'}\r\n    maven { url \"$rootDir\u002Flib\u002Frelease\" }\r\n    \u002F\u002F指定去maven的本地仓库查找\r\n    mavenLocal()\r\n    \u002F\u002F指定去maven的私服或者第三方镜像仓库查找\r\n    maven { name \"Alibaba\" ; url \"https:\u002F\u002Fmaven.aliyun.com\u002Frepository\u002Fpublic\" }\r\n    maven { name \"Bstek\" ; url \"https:\u002F\u002Fnexus.bsdn.org\u002Fcontent\u002Fgroups\u002Fpublic\u002F\" }\r\n    \u002F\u002F指定去maven的远程仓库查找:即 https:\u002F\u002Frepo.maven.apache.org\u002Fmaven2\u002F\r\n    mavenCentral()\r\n    \u002F\u002F去google仓库查找\r\n    google()\r\n}\r\n```\r\n\r\n### Subprojects 与 Allprojects\r\n\r\n​\t\tallprojects 是对所有project**(包括Root Project+ child Project[当前工程和所有子工程])**的进行统一配置，而subprojects\r\n\r\n是对**所有Child Project 的进行统一配置**。\r\n\r\n\r\n\r\n\r\n\r\n### ext 用户自定义属性\r\n\r\n​\t\tProject 和 Task 都允许用户添加额外的自定义属性，要添加额外的属性，通过应用所属对象的ext 属性即可实现。添加之后可以通过 ext 属性对自定义属性读取和设置。\r\n\r\n```groovy\r\n\u002F\u002F自定义一个Project的属性\r\next.age = 18\r\n\u002F\u002F通过代码块同时自定义多个属性\r\next {\r\n    phone = 18292883833\r\n    address=\"广州天河区\"\r\n}\r\ntask extCustomProperty {\r\n    \u002F\u002F在task中自定义属性\r\n    ext {\r\n        desc = \"奥利给\"\r\n    }\r\n    doLast {\r\n        println \" 年 龄 是 ：${age}\"\r\n        println \"电话是：${phone}\"\r\n        println \"地址是：${address}\"\r\n        println \"羊城：${desc}\"\r\n    }\r\n}\r\n```\r\n\r\n执行结果：`gradle extCustomProperty`\r\n\r\n> Task :extCustomProperty\r\n>  年 龄 是 ：18\r\n> 电话是：18292883833\r\n> 地址是：广州天河区\r\n> 羊城：奥利给\r\n\r\n\r\n\r\n## gradle.properties文件\r\n\r\n​\t\text 配置的是用户自定义属性，而gradle.properties 中一般定义 系统属性、环境变量、项目属性、JVM 相关配置信息。\r\n\r\n​\t\tgradle.properties 文件中的属性会自动在项目运行时加载。\r\n\r\n```properties\r\n## 设置此参数主要是编译下载包会占用大量的内存，可能会内存溢出\r\norg.gradle.jvmargs=-Xms4096m -Xmx8192m ## 开启gradle缓存\r\norg.gradle.caching=true #开启并行编译org.gradle.parallel=true #启用新的孵化模式\r\norg.gradle.configureondemand=true #开启守护进程org.gradle.daemon=true\r\n```\r\n\r\n[详细参考](https:\u002F\u002Fdocs.gradle.org\u002Fcurrent\u002Fuserguide\u002Fbuild_environment.html#sec%3Agradle_configuration_properties)：https:\u002F\u002Fdocs.gradle.org\u002Fcurrent\u002Fuserguide\u002Fbuild_environment.html#sec%3Agradle_configuration_properties\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n**参考资料：**\r\n\r\n​\t[尚硅谷](https:\u002F\u002Fwww.yuque.com\u002Fyouyi-ai1ik\u002Femphm9\u002Fkyhenl)：https:\u002F\u002Fwww.yuque.com\u002Fyouyi-ai1ik\u002Femphm9\u002Fkyhenl\n",{"_path":170,"slug":171,"title":171,"description":172,"excerpt":172,"date":173,"tags":174,"type":15,"cover":175,"content":176},"\u002Fknowledge\u002Fnvm管理多版本node教程","nvm管理多版本node教程","nvm管理多版本node教程 1 nvm介绍 **nvm** 全称 `Node Version Manager`，是Mac 下管理多版本 Node.js 工具，nvm 默认只支持 Linux 和 OS X，不支持 Windows；如果需要管理 Windows 下的 node，官方推荐使用 nvmw 或 nvm-wind","2025-05-06",[124,63],"\u002Fknowledge-assets\u002Fnvm管理多版本node教程\u002Fnvm下载.png","# nvm管理多版本node教程\r\n\r\n# 1\tnvm介绍\r\n\r\n**nvm** 全称 `Node Version Manager`，是Mac 下管理多版本 Node.js 工具，nvm 默认只支持 Linux 和 OS X，不支持 Windows；如果需要管理 Windows 下的 node，官方推荐使用 nvmw 或 nvm-windows，不过，nvm-windows 并不是 nvm 的简单移植，他们也没有任何关系。\r\n\r\n大部分情况下，Windows 下的 nvm 和 mac 里的 nvm 使用都没有大的差异，基本上是一致的，会有个别命令不太相同。\r\n\r\n# 2\tnvm下载安装\r\n\r\n## 2.1\t官网下载\r\n\r\n网址：https:\u002F\u002Fgithub.com\u002Fcoreybutler\u002Fnvm-windows\r\n\r\n- `nvm-noinstall.zip`： 绿色免安装版本，但是使用之前需要配置；\r\n- `nvm-setup.zip`：这是自动配置安装包，下载之后点击安装，无需配置就可以使用，方便。下载`nvm-setup.exe`或`nvm-setup.zip`包。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fnvm管理多版本node教程\u002Fnvm下载.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n## 2.2\t安装\r\n\r\n在指定的文件下新建两个文件夹。分别是`node`和`nvm`。\r\n\r\n- `nvm`文件夹存放`nvm`的安装文件；\r\n- `node`文件夹用来存放node的文件。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fnvm管理多版本node教程\u002Fnvm安装目录.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n（1）双击`nvm-setup.exe`进行安装，选择nvm安装路径：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fnvm管理多版本node教程\u002Fnvm安装1.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n（2）选择node.js路径：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fnvm管理多版本node教程\u002Fnvm安装2.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n（3）点击 `Install`——>点击 `Finish`，安装完成。\r\n\r\n> 安装完成，node文件夹会消失；\r\n\r\n安装成功后：\r\n\r\n- 环境变量中的**用户变量** 、**系统变量**都自动添加了`NVM_HOME` 和 `NVM_SYMLINK`两个变量；\r\n- **用户变量**中的`path`变量自动添加了`NVM_HOME`和 `NVM_SYMLINK`变量值。\r\n\r\n## 2.3\t查看版本\r\n\r\n```shell\r\n# 打开cmd终端工具，执行 nvm。注意：使用powershell会报错\r\nnvm -v\r\n```\r\n\r\n# 3\t配置国内镜像源\r\n\r\n## 3.1\t配置文件方式\r\n\r\n打开`nvm`安装路径下的`settings.txt`文件，在`settings.txt`文件的最后添加以下代码：\r\n\r\n```shell\r\nnode_mirror: https:\u002F\u002Fnpmmirror.com\u002Fmirrors\u002Fnode\u002F\r\nnpm_mirror: https:\u002F\u002Fnpmmirror.com\u002Fmirrors\u002Fnpm\u002F\r\n```\r\n\r\n添加完之后文件内部：\r\n\r\n```shell\r\nroot: D:\\devTools\\nvm\\nvm\r\npath: D:\\devTools\\nvm\\node\r\n\r\nnode_mirror: https:\u002F\u002Fnpmmirror.com\u002Fmirrors\u002Fnode\u002F\r\nnpm_mirror: https:\u002F\u002Fnpmmirror.com\u002Fmirrors\u002Fnpm\u002F\r\n```\r\n\r\n\r\n\r\n> root：nvm安装路径\r\n>\r\n> path：node.js快捷方式路径\r\n\r\n## 3.2\t命令配置方式\r\n\r\n```shell\r\n nvm node_mirror [url]  # 设置节点镜像。默认为https:\u002F\u002Fnodejs.org\u002Fdist\u002F。保留[url]为空，使用默认url。\r\n nvm npm_mirror [url]   # 设置npm镜像。默认为https:\u002F\u002Fgithub.com\u002Fnpm\u002Fcli\u002Farchive\u002F。保留[url]为空，默认url。\r\n```\r\n\r\n\r\n\r\n# 4\tnvm常用命令\r\n\r\n## 4.1\t命令列表\r\n\r\n```shell\r\nnvm arch                     # 显示节点是否运行在32位或64位模式。\r\nnvm current                  # 显示激活版本。\r\nnvm install \u003Cversion> [arch] # 版本可以是一个特定的版本，“latest”表示最新的当前版本，“lts”表示最新的lts版本。可选地指定是否安装32位或64位版本(默认为system arch)。设置[arch]为\"all\"安装32位和64位版本。在此命令的末尾添加——insecure以绕过远程下载服务器的SSL验证。\r\nnvm list [available]         #  列出node.js的安装。在最后输入“available”，看看可以安装什么。别名为ls。\r\nnvm on                       # 启用node.js版本管理。\r\nnvm off                      # 禁用node.js版本管理。\r\nnvm proxy [url]              # 设置下载要使用的代理。将[url]留空以查看当前代理。将[url]设置为“none”以删除代理。\r\n\r\nnvm uninstall \u003Cversion>      # 卸载指定版本node 版本必须是指定的版本号。\r\nnvm use [version] [arch]     # 切换到使用指定的版本。可选使用“latest”，“lts”或“latest”。“latest”是最新安装的版本。可选地指定32\u002F64位架构。 nvm use \u003Carch>将继续使用所选版本，但切换到32\u002F64位模式。                               \r\nnvm root [path]              # 设置nvm存储不同版本node.js的目录。未设置path时，将显示当前根。\r\nnvm [--]version              # 显示当前运行的Windows nvm版本。别名为v。\r\n```\r\n\r\n## 4.2\t查看node\r\n\r\n```shell\r\n# 查看可在线安装的node.js版本\r\nnvm list available\r\n# 查看已安装的node.js版本\r\nnvm ls\r\n#或者\r\nnvm list\r\n```\r\n\r\n## 4.3\t安装\u002F卸载node\r\n\r\n安装成功后，会在安装目录下出现一个`\u003Cversion>` 文件夹。安装了多个版本就会有多个对应版本的文件夹。\r\n\r\n```shell\r\n# 命令格式\r\nnvm install \u003Cversion>\r\n# 如：\r\nnvm install v14.21.3\r\n\r\n# 卸载指定版本的node.js\r\nnvm uninstall [version]\r\n# 如：\r\nnvm uninstall v14.21.3\r\n```\r\n\r\n\r\n\r\n注安装报错解决：\r\n\r\n```shell\r\nC:\\Users\\mh>nvm install 24.14.1\r\nerror installing 24.14.1: Node.js v24.14.1 is not yet released or is not available for download yet.\r\n# 如果遇到这种错误，直接取消【国内镜像源】配置即可解决。\r\n```\r\n\r\n\r\n\r\n## 4.4\t使用\u002F切换node版本\r\n\r\n```shell\r\n# 切换node.js版本，切换node时，会自动将和其关联的npm也切换了。\r\nnvm use v14.21.3\r\n\r\n# 可以使用node -v命令检查是否切换成功\r\nnode -v\r\n\r\n# 显示当前正在使用的node.js版本\r\nnvm current\r\n```\r\n\r\n\r\n\r\n# 5\t关于npm\r\n\r\n安装`node`的时候，`npm`其实也已经一起安装了。\r\n\r\n```shel\r\n# 查看npm版本\r\nnpm -v\r\n# 查看npm配置信息（基本包含了仓储和缓存路径的配置）\r\nnpm config ls\r\n```\r\n\r\n\r\n\r\n# 6\t安装yarn\r\n\r\n## 6.1\tyarn命令\r\n\r\n除了使用npm安装管理依赖，也可以使用yarn。只在nvm使用的当前node版本下安装，若切换了其他node版本是不存在yarn的，需要重新安装。\r\n\r\n```shell\r\n# 安装 yarn\r\nnpm install -g yarn\r\nnpm install -g yarn@[版本号]\r\n \r\n# 查看版本\r\nyarn --version\r\n\r\n# 配置淘宝镜像源\r\nyarn config set registry https:\u002F\u002Fregistry.npmmirror.com\r\n# 配置node-sass镜像源\r\nyarn config set sass_binary_site https:\u002F\u002Fnpmmirror.com\u002Fmirrors\u002Fnode-sass -g\r\n\r\n# 初始化项目\r\nyarn init \u002F\u002F 同npm init，执行输入信息后，会生成package.json文件\r\n# 安装项目依赖\r\nyarn install\r\n```\r\n\r\n\r\n\r\n## 6.2\tnpm与yarn命令比较\r\n\r\n比如说你的项目模块依赖是@1.2.1版本。在你安装A的时候需要安装依赖C和D，很多依赖不会指定版本号，默认会安装最新的版本，这样就会出现问题：比如今天安装模块的时候C和D是某一个版本，而当以后C、D更新的时候，再次安装模块就会安装C和D的最新版本，如果新的版本无法兼容你的项目，你的程序可能就会出BUG，甚至无法运行。这就是npm的弊端，而yarn为了解决这个问题推出了yarn.lock的机制。\r\n\r\n\r\n\r\n参考来源：https:\u002F\u002Fblog.csdn.net\u002Fweixin_51623642\u002Farticle\u002Fdetails\u002F130170646\n",{"_path":178,"slug":179,"title":180,"description":181,"excerpt":181,"date":173,"tags":182,"type":15,"cover":184,"content":185},"\u002Fknowledge\u002Fspringboot源码","springboot源码","手写模拟SpringBoot核心流程","手写模拟SpringBoot核心流程 springboot 并不是重新开发，只是对现有的技术进行整合。 代码地址：码云：https:\u002F\u002Fgitee.com\u002Fmeng_hui\u002Fmh-springboot 1 创建工程 首先，SpringBoot是基于Spring，所以我们要依赖Spring，然后希望我们模拟出来的Spri",[74,104,136,183],"Tomcat","\u002Fknowledge-assets\u002Fspringboot源码\u002F精简版sprngboot源码.png","# 手写模拟SpringBoot核心流程\r\n\r\nspringboot 并不是重新开发，只是对现有的技术进行整合。\r\n\r\n代码地址：[码云](https:\u002F\u002Fgitee.com\u002Fmeng_hui\u002Fmh-springboot)：https:\u002F\u002Fgitee.com\u002Fmeng_hui\u002Fmh-springboot\r\n\r\n# 1\t创建工程\r\n\r\n首先，SpringBoot是基于Spring，所以我们要依赖Spring，然后希望我们模拟出来的SpringBoot也支持Spring MVC的那一套功能，所以也要依赖Spring MVC，包括Tomcat等，所以在SpringBoot模块中要添加以下依赖。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fspringboot源码\u002F精简版sprngboot源码.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n## 1.1\tspringboot模块\r\n\r\n### 1.1.1\tpom.xml文件\r\n\r\n```xml\r\n\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n\u003Cproject xmlns=\"http:\u002F\u002Fmaven.apache.org\u002FPOM\u002F4.0.0\" xmlns:xsi=\"http:\u002F\u002Fwww.w3.org\u002F2001\u002FXMLSchema-instance\"\r\n         xsi:schemaLocation=\"http:\u002F\u002Fmaven.apache.org\u002FPOM\u002F4.0.0 https:\u002F\u002Fmaven.apache.org\u002Fxsd\u002Fmaven-4.0.0.xsd\">\r\n    \u003CmodelVersion>4.0.0\u003C\u002FmodelVersion>\r\n    \u003Cparent>\r\n        \u003CgroupId>com.mh\u003C\u002FgroupId>\r\n        \u003CartifactId>mh-springboot\u003C\u002FartifactId>\r\n        \u003Cversion>1.0\u003C\u002Fversion>\r\n    \u003C\u002Fparent>\r\n\r\n    \u003CartifactId>springboot\u003C\u002FartifactId>\r\n    \u003Cversion>1.0\u003C\u002Fversion>\r\n\r\n    \u003Cdependencies>\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.springframework\u003C\u002FgroupId>\r\n            \u003CartifactId>spring-context\u003C\u002FartifactId>\r\n            \u003Cversion>6.2.6\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.springframework\u003C\u002FgroupId>\r\n            \u003CartifactId>spring-web\u003C\u002FartifactId>\r\n            \u003Cversion>6.2.6\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.springframework\u003C\u002FgroupId>\r\n            \u003CartifactId>spring-webmvc\u003C\u002FartifactId>\r\n            \u003Cversion>6.2.6\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n\r\n        \u003Cdependency>\r\n            \u003CgroupId>javax.servlet\u003C\u002FgroupId>\r\n            \u003CartifactId>javax.servlet-api\u003C\u002FartifactId>\r\n            \u003Cversion>4.0.1\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.apache.tomcat.embed\u003C\u002FgroupId>\r\n            \u003CartifactId>tomcat-embed-core\u003C\u002FartifactId>\r\n            \u003Cversion>10.1.40\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n    \u003C\u002Fdependencies>\r\n\u003C\u002Fproject>\r\n\r\n```\r\n\r\n### 1.1.2\t@SpringBootApplication核心注解\r\n\r\n```java\r\npackage com.mh.springboot;\r\n\r\nimport org.springframework.context.annotation.ComponentScan;\r\nimport org.springframework.context.annotation.Configuration;\r\nimport java.lang.annotation.ElementType;\r\nimport java.lang.annotation.Retention;\r\nimport java.lang.annotation.RetentionPolicy;\r\nimport java.lang.annotation.Target;\r\n\r\n\u002F**\r\n * springboot核心注解\r\n *\r\n * 贴在springboot应用的启动类上\r\n *\u002F\r\n@Target(ElementType.TYPE)\r\n@Retention(RetentionPolicy.RUNTIME)\r\n@Configuration  \u002F\u002F 表明该类是一个配置类\r\n@ComponentScan  \u002F\u002F spring 扫描bean范围\r\npublic @interface MhSpringBootApplication {\r\n\r\n}\r\n```\r\n\r\n### 1.1.3\tSpringApplication核心类\r\n\r\n```java\r\npackage com.mh.springboot;\r\n\r\nimport org.apache.catalina.*;\r\nimport org.apache.catalina.connector.Connector;\r\nimport org.apache.catalina.core.StandardContext;\r\nimport org.apache.catalina.core.StandardEngine;\r\nimport org.apache.catalina.core.StandardHost;\r\nimport org.apache.catalina.startup.Tomcat;\r\nimport org.springframework.web.context.WebApplicationContext;\r\nimport org.springframework.web.context.support.AnnotationConfigWebApplicationContext;\r\nimport org.springframework.web.servlet.DispatcherServlet;\r\n\r\n\u002F**\r\n * springboot 核心类\r\n * springboot 并不是重新开发，只是对现有的技术进行整合\r\n *\u002F\r\npublic class MhSpringApplication {\r\n\r\n    \u002F**\r\n     * 1.创建一个Spring容器\r\n     * 2.创建Tomcat对象\r\n     * 3.生成DispatcherServlet对象，并且和前面创建出来的Spring容器进行绑定\r\n     * 4.将DispatcherServlet添加到Tomcat中\r\n     * 5.启动Tomcat\r\n     *\u002F\r\n    public static void run(Class clazz) {\r\n        \u002F\u002F 创建一个spring容器，spring中扫描到的bean存放到applicationContext这个容器里\r\n        AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();\r\n        applicationContext.register(clazz);\r\n        applicationContext.refresh();\r\n\r\n        \u002F\u002F 启动tomcat，才能够监听http请求\r\n        startTomcat(applicationContext);\r\n    }\r\n\r\n    \u002F\u002F 启动tomcat\r\n    public static void startTomcat(WebApplicationContext applicationContext){\r\n\r\n        Tomcat tomcat = new Tomcat();\r\n\r\n        Server server = tomcat.getServer();\r\n        Service service = server.findService(\"Tomcat\");\r\n\r\n        Connector connector = new Connector();\r\n        connector.setPort(8081);\r\n\r\n        Engine engine = new StandardEngine();\r\n        engine.setDefaultHost(\"localhost\");\r\n\r\n        Host host = new StandardHost();\r\n        host.setName(\"localhost\");\r\n\r\n        String contextPath = \"\";\r\n        Context context = new StandardContext();\r\n        context.setPath(contextPath);\r\n        context.addLifecycleListener(new Tomcat.FixContextListener());\r\n\r\n        host.addChild(context);\r\n        engine.addChild(host);\r\n\r\n        service.setContainer(engine);\r\n        service.addConnector(connector);\r\n\r\n        \u002F\u002F 配置一个dispatcher前端过滤器，统一处理controller的请求\r\n        \u002F\u002F 需要传入spring容器对象，这样才能够知道我们的应用中有哪些Controller（即接口）\r\n        tomcat.addServlet(contextPath, \"dispatcher\", new DispatcherServlet(applicationContext));\r\n        context.addServletMappingDecoded(\"\u002F*\", \"dispatcher\");\r\n\r\n        try {\r\n            tomcat.start();\r\n        } catch (LifecycleException e) {\r\n            e.printStackTrace();\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n\r\n\r\n## 1.2\tuser模块\r\n\r\n### 1.2.1\tpom.xml文件\r\n\r\n```xml\r\n\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n\u003Cproject xmlns=\"http:\u002F\u002Fmaven.apache.org\u002FPOM\u002F4.0.0\" xmlns:xsi=\"http:\u002F\u002Fwww.w3.org\u002F2001\u002FXMLSchema-instance\"\r\n         xsi:schemaLocation=\"http:\u002F\u002Fmaven.apache.org\u002FPOM\u002F4.0.0 https:\u002F\u002Fmaven.apache.org\u002Fxsd\u002Fmaven-4.0.0.xsd\">\r\n\r\n    \u003Cparent>\r\n        \u003CgroupId>com.mh\u003C\u002FgroupId>\r\n        \u003CartifactId>mh-springboot\u003C\u002FartifactId>\r\n        \u003Cversion>1.0\u003C\u002Fversion>\r\n    \u003C\u002Fparent>\r\n\r\n    \u003CmodelVersion>4.0.0\u003C\u002FmodelVersion>\r\n    \u003CartifactId>user\u003C\u002FartifactId>\r\n    \u003Cversion>1.0\u003C\u002Fversion>\r\n\r\n    \u003Cdependencies>\r\n        \u003Cdependency>\r\n            \u003CgroupId>com.mh\u003C\u002FgroupId>\r\n            \u003CartifactId>springboot\u003C\u002FartifactId>\r\n            \u003Cversion>1.0\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n    \u003C\u002Fdependencies>\r\n\u003C\u002Fproject>\r\n```\r\n\r\n### 1.2.2\t启动类\r\n\r\n```java\r\npackage com.mh.user;\r\nimport com.mh.springboot.MhSpringApplication;\r\nimport com.mh.springboot.MhSpringBootApplication;\r\nimport org.springframework.context.annotation.ComponentScan;\r\nimport org.springframework.context.annotation.Configuration;\r\n\r\n\u002F**\r\n * user应用启动类\r\n *\u002F\r\n\r\n@MhSpringBootApplication\r\n\u002F* 相当于下面这两个注解\r\n@Configuration\r\n@ComponentScan*\u002F\r\npublic class UserApplication {\r\n    public static void main(String[] args) {\r\n        \u002F\u002F 传入启动类或核心配置类，就是贴@MhSpringBootApplication注解的类\r\n        MhSpringApplication.run(UserApplication.class);\r\n    }\r\n}\r\n```\r\n\r\n### 1.2.3\tcontroller\r\n\r\n```java\r\npackage com.mh.user.controller;\r\n\r\nimport com.mh.user.service.UserService;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.RestController;\r\n\r\n@RestController\r\npublic class UserController {\r\n\r\n    @Autowired\r\n    private UserService userService;\r\n\r\n    @GetMapping(\"\u002Ftest\")\r\n    public String test(){\r\n        return userService.test();\r\n    }\r\n}\r\n```\r\n\r\n### 1.2.4\tservice\r\n\r\n```java\r\npackage com.mh.user.service;\r\n\r\nimport org.springframework.stereotype.Service;\r\n\r\n@Service\r\npublic class UserService {\r\n\r\n    public String test() {\r\n        return \"hello mh\";\r\n    }\r\n}\r\n```\r\n\r\n## 1.3\t访问\r\n\r\n实际上代码写到这，一个极度精简版的SpringBoot就写出来了，比如现在运行UserApplication，就能正常的启动项目，并能接收请求。\r\n\r\n浏览器访问：http:\u002F\u002Flocalhost:8081\u002Ftest\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fspringboot源码\u002F访问.png\" style=\"zoom:70%;\" \u002F>\r\n\r\n# 2\t实现Tomcat和Jetty的切换\r\n\r\n虽然我们前面已经实现了一个比较简单的SpringBoot，不过我们可以继续来扩充它的功能，比如现在我有这么一个需求，这个需求就是我现在不想使用Tomcat了，而是想要用Jetty，那该怎么办？\r\n\r\n这个逻辑希望SpringBoot自动帮我实现，对于程序员用户而言，只要在Pom文件中添加相关依赖就可以了，想用Tomcat就加Tomcat依赖，想用Jetty就加Jetty依赖。\r\n\r\n我们前面代码中默认启动的是Tomcat，那我现在想改成这样子：\r\n\r\n1. 如果项目中有Tomcat的依赖，那就启动Tomcat\r\n2. 如果项目中有Jetty的依赖就启动Jetty\r\n3. 如果两者都没有则报错\r\n4. 如果两者都有也报错\r\n\r\n## 2.1\tspringboot模块\r\n\r\n### 2.1.1\t添加依赖\r\n\r\n在springboot模块pom中添加jetty依赖：\r\n\r\n```xml\r\n\u003Cdependency>\r\n    \u003CgroupId>org.eclipse.jetty\u003C\u002FgroupId>\r\n    \u003CartifactId>jetty-server\u003C\u002FartifactId>\r\n    \u003Cversion>11.0.24\u003C\u002Fversion>\r\n\u003C\u002Fdependency>\r\n```\r\n\r\n### 2.1.2\t创建WebServer\r\n\r\n我们知道，不管是Tomcat还是Jetty，它们都是应用服务器，或者是Servlet容器，所以我们可以定义接口来表示它们，这个接口叫做WebServer（别问我为什么叫这个，因为真正的SpringBoot源码中也叫这个）。\r\n\r\n（1）创建WebServer接口\r\n\r\n```java\r\npackage com.mh.springboot;\r\n\r\npublic interface WebServer {\r\n    void start();\r\n}\r\n```\r\n\r\n（2）创建tomcat实现类\r\n\r\n```java\r\npackage com.mh.springboot;\r\n\r\npublic class TomcatWebServer implements WebServer {\r\n    @Override\r\n    public void start() {\r\n        System.out.println(\"启动tomcat\");\r\n    }\r\n}\r\n```\r\n\r\n（3）创建jetty实现类\r\n\r\n```java\r\npackage com.mh.springboot;\r\n\r\npublic class JettyWebServer implements WebServer {\r\n    @Override\r\n    public void start() {\r\n        System.out.println(\"启动jetty\");\r\n    }\r\n}\r\n```\r\n\r\n### 2.1.3\t修改SpringApplication核心类\r\n\r\n而在MhSpringApplication中的run方法中，我们就要去获取对应的WebServer，然后启动对应的webServer，代码为：\r\n\r\n```java\r\npublic class MhSpringApplication {\r\n\r\n    public static void run(Class clazz) {\r\n        \u002F\u002F 创建一个spring容器，spring中扫描到的bean存放到applicationContext这个容器里\r\n        AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();\r\n        applicationContext.register(clazz);\r\n        applicationContext.refresh();\r\n\r\n        \u002F\u002F 这样，我们就只需要在getWebServer方法中去判断到底该返回TomcatWebServer还是JettyWebServer。\r\n        WebServer webServer = getWebServer(applicationContext);\r\n        webServer.start();\r\n    }\r\n\r\n    \u002F\u002F 获取web服务, 根据添加的tomcat或者jetty依赖，自动选择对应的web服务来启动\r\n    public static WebServer getWebServer(WebApplicationContext applicationContext){\r\n        \u002F\u002F 从spring容器中获取tomcat或者jetty的bean对象\r\n        \u002F\u002F key为beanName, value为Bean对象， 通过接口去获取，拿到的可能是多个实现类对象\r\n        Map\u003CString, WebServer> webServers = applicationContext.getBeansOfType(WebServer.class);\r\n\r\n        if (webServers.isEmpty()) {\r\n            throw new NullPointerException();\r\n        }\r\n        if (webServers.size() > 1) {\r\n            throw new IllegalStateException();\r\n        }\r\n\r\n        \u002F\u002F 返回唯一的一个\r\n        return webServers.values().stream().findFirst().get();\r\n    }\r\n}\r\n```\r\n\r\n这样，我们就只需要在getWebServer方法中去判断到底该返回TomcatWebServer还是JettyWebServer。\r\n\r\n现在我们希望是通过pom中是否添加tomcat或jetty依赖，来启动对应的tomcat或jetty服务，所以我们还需要进行判断。\r\n\r\n### 2.1.4\t创建WebServiceAutoConfiguration自动配置类\r\n\r\n模拟创建一个**WebServiceAutoConfiguration**自动配置类，在这个类中根据我们添加的pom依赖来判断创建tomcat对象或者jetty对象。\r\n\r\n通过一个WebServiceAutoConfiguration的spring配置类，在里面定义了两个bean，一个是TomcatWebServer，一个是JettyWebServer，不过这两个类要生效，必须符合条件：\r\n\r\n- 只有存在核心类“org.apache.catalina.startup.Tomcat”，那么才创建TomcatWebServer这个bean\r\n- 只有存在核心类“org.eclipse.jetty.server.Server”，那么才会创建JettyWebServer这个bean\r\n\r\n（1）创建WebServiceAutoConfiguration配置类\r\n\r\n```java\r\npackage com.mh.springboot;\r\n\r\nimport org.springframework.context.annotation.Bean;\r\nimport org.springframework.context.annotation.Conditional;\r\nimport org.springframework.context.annotation.Configuration;\r\n\r\n\u002F**\r\n * 创建web服务自动配置类\r\n *\u002F\r\n\r\npublic class WebServiceAutoConfiguration {\r\n\r\n    @Bean\r\n    \u002F\u002F spring条件判断注解\r\n    \u002F\u002F 条件配置，如果pom添加了tomcat依赖，则自动创建tomcat服务\r\n    @Conditional(TomcatConditional.class)\r\n    public TomcatWebServer tomcatWebServer(){\r\n        return new TomcatWebServer();\r\n    }\r\n\r\n    @Bean\r\n    \u002F\u002F 条件配置，如果pom添加了jetty依赖，则自动创建jetty服务\r\n    @Conditional(JettyConditional.class)\r\n    public JettyWebServer jettyWebServer(){\r\n        return new JettyWebServer();\r\n    }\r\n}\r\n```\r\n\r\n（2）创建tomcat判断条件类\r\n\r\n```java\r\npackage com.mh.springboot;\r\n\r\nimport org.springframework.context.annotation.Condition;\r\nimport org.springframework.context.annotation.ConditionContext;\r\nimport org.springframework.core.type.AnnotatedTypeMetadata;\r\n\r\n\u002F**\r\n * tomcat pom是否添加依赖判断\r\n *\u002F\r\npublic class TomcatConditional implements Condition {\r\n\r\n    \u002F**\r\n     * 返回 true 则符合条件，返回 false 不符合条件\r\n     *\u002F\r\n    @Override\r\n    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {\r\n        \u002F\u002F 项目依赖有tomcat就返回true，没有就返回false\r\n        try {\r\n            \u002F\u002F 加载tomcat里一个非常核心的类，如果存在就说明已经添加了依赖\r\n            \u002F\u002F 如果报错，那就说明pom没有添加tomcat依赖\r\n            context.getClassLoader().loadClass(\"org.apache.catalina.startup.Tomcat\");\r\n            return true;\r\n        } catch (ClassNotFoundException e) {\r\n            return false;\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n（3）创建jetty判断条件类\r\n\r\n```java\r\npackage com.mh.springboot;\r\n\r\nimport org.springframework.context.annotation.Condition;\r\nimport org.springframework.context.annotation.ConditionContext;\r\nimport org.springframework.core.type.AnnotatedTypeMetadata;\r\n\r\n\u002F**\r\n * jetty pom是否添加依赖判断\r\n *\u002F\r\npublic class JettyConditional implements Condition {\r\n    @Override\r\n    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {\r\n        \u002F\u002F 通过类加载器去获取 jetty中的核心类，如果存在说明pom添加了jetty依赖，报错则说明没添加\r\n        try {\r\n            context.getClassLoader().loadClass(\"org.eclipse.jetty.server.Server\");\r\n            return true;\r\n        } catch (ClassNotFoundException e) {\r\n            return false;\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n如果现在就启动user模块的话，会报空指针异常，因为在getWebServer()中，获取不到tomcat或者jetty的bean对象，user模块上配置的注解@MhSpringBootApplication只扫描user当前模块所在的包路径，并不会扫描到springboot模块的代码，因此WebServiceAutoConfiguration并没有生效。\r\n\r\n所以我们在@MhSpringBootApplication注解中，需要导入WebServiceAutoConfiguration这个类。\r\n\r\n### 2.1.5\t修改@SpringBootApplication核心注解\r\n\r\n通过在@MhSpringBootApplication注解上添加一个@Import注解，使spring在扫描时，一同扫描@Import导入的类，这样WebServiceAutoConfiguration类才会生效。\r\n\r\n> 但是这样会存在一个问题，就是我们每写一个自动配置类，都需要@Import导入，代码耦合度会很高，那如果处理呢？在下一章自动导入配置会提供处理方式，现在暂时这样用，功能达到就可以了。\r\n\r\n```java\r\n@Target(ElementType.TYPE)\r\n@Retention(RetentionPolicy.RUNTIME)\r\n@Configuration  \u002F\u002F 表明该类是一个配置类\r\n@ComponentScan  \u002F\u002F spring 扫描bean范围\r\n@Import(WebServiceAutoConfiguration.class) \u002F\u002F web服务自动配置\r\npublic @interface MhSpringBootApplication {\r\n\r\n}\r\n```\r\n\r\n此时我们启动UserApplication服务，会报IllegalStateException异常，因为同时存在tomcat依赖和jetty依赖。但是我们又不能在springboot模块中去除jetty依赖，因为编写jetty启动服务时需要用到，同理tomcat也不能去除。\r\n\r\n那我们可以在在springboot模块的pom中将jetty依赖设置为不传递，这样其user或他模块引用时都不会携带jetty这个依赖：\r\n\r\n```xml\r\n\u003Cdependency>\r\n    \u003CgroupId>org.eclipse.jetty\u003C\u002FgroupId>\r\n    \u003CartifactId>jetty-server\u003C\u002FartifactId>\r\n    \u003Cversion>11.0.24\u003C\u002Fversion>\r\n    \u003C!-- 禁止依赖传递，即其他模块引入这个模块，不会传递这个依赖 -->\r\n    \u003Coptional>true\u003C\u002Foptional>\r\n\u003C\u002Fdependency>\r\n```\r\n\r\n## 2.2\tuser模块\r\n\r\n启动userApplication服务时，默认使用了tomcat服务。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fspringboot源码\u002Ftomcat-start.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n如果我们需要使用jetty服务，则需要在pom文件中排除tomcat依赖，在添加jetty依赖即可。\r\n\r\npom文件：\r\n\r\n```xml\r\n\u003Cdependencies>\r\n    \u003Cdependency>\r\n        \u003CgroupId>com.mh\u003C\u002FgroupId>\r\n        \u003CartifactId>springboot\u003C\u002FartifactId>\r\n        \u003Cversion>1.0\u003C\u002Fversion>\r\n        \u003C!-- 排除tomcat依赖 -->\r\n        \u003Cexclusions>\r\n            \u003Cexclusion>\r\n                \u003CgroupId>org.apache.tomcat.embed\u003C\u002FgroupId>\r\n                \u003CartifactId>tomcat-embed-core\u003C\u002FartifactId>\r\n            \u003C\u002Fexclusion>\r\n        \u003C\u002Fexclusions>\r\n    \u003C\u002Fdependency>\r\n\r\n    \u003C!-- 引入jetty依赖 -->\r\n    \u003Cdependency>\r\n        \u003CgroupId>org.eclipse.jetty\u003C\u002FgroupId>\r\n        \u003CartifactId>jetty-server\u003C\u002FartifactId>\r\n        \u003Cversion>11.0.24\u003C\u002Fversion>\r\n    \u003C\u002Fdependency>\r\n\u003C\u002Fdependencies>\r\n```\r\n\r\n这样我们启动user服务时，就使用了jetty服务。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fspringboot源码\u002Fjetty-start.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n## 2.3\t代码优化\r\n\r\n### 2.3.1\tspringboot模块\r\n\r\n（1）pom文件\r\n\r\n```xml\r\n\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n\u003Cproject xmlns=\"http:\u002F\u002Fmaven.apache.org\u002FPOM\u002F4.0.0\" xmlns:xsi=\"http:\u002F\u002Fwww.w3.org\u002F2001\u002FXMLSchema-instance\"\r\n         xsi:schemaLocation=\"http:\u002F\u002Fmaven.apache.org\u002FPOM\u002F4.0.0 https:\u002F\u002Fmaven.apache.org\u002Fxsd\u002Fmaven-4.0.0.xsd\">\r\n    \u003CmodelVersion>4.0.0\u003C\u002FmodelVersion>\r\n    \u003Cparent>\r\n        \u003CgroupId>com.mh\u003C\u002FgroupId>\r\n        \u003CartifactId>mh-springboot\u003C\u002FartifactId>\r\n        \u003Cversion>1.0\u003C\u002Fversion>\r\n    \u003C\u002Fparent>\r\n\r\n    \u003CartifactId>springboot\u003C\u002FartifactId>\r\n    \u003Cversion>1.0\u003C\u002Fversion>\r\n\r\n    \u003Cdependencies>\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.springframework\u003C\u002FgroupId>\r\n            \u003CartifactId>spring-context\u003C\u002FartifactId>\r\n            \u003Cversion>6.2.6\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.springframework\u003C\u002FgroupId>\r\n            \u003CartifactId>spring-web\u003C\u002FartifactId>\r\n            \u003Cversion>6.2.6\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.springframework\u003C\u002FgroupId>\r\n            \u003CartifactId>spring-webmvc\u003C\u002FartifactId>\r\n            \u003Cversion>6.2.6\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n\r\n        \u003Cdependency>\r\n            \u003CgroupId>javax.servlet\u003C\u002FgroupId>\r\n            \u003CartifactId>javax.servlet-api\u003C\u002FartifactId>\r\n            \u003Cversion>4.0.1\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.apache.tomcat.embed\u003C\u002FgroupId>\r\n            \u003CartifactId>tomcat-embed-core\u003C\u002FartifactId>\r\n            \u003Cversion>10.1.40\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.eclipse.jetty\u003C\u002FgroupId>\r\n            \u003CartifactId>jetty-server\u003C\u002FartifactId>\r\n            \u003Cversion>11.0.24\u003C\u002Fversion>\r\n            \u003C!-- 禁止依赖传递，即其他模块引入这个模块，不会传递这个依赖 -->\r\n            \u003Coptional>true\u003C\u002Foptional>\r\n        \u003C\u002Fdependency>\r\n    \u003C\u002Fdependencies>\r\n\u003C\u002Fproject>\r\n```\r\n\r\n\r\n\r\n（2）**MhSpringBootApplication**核心注解：\r\n\r\n```java\r\npackage com.mh.springboot;\r\n\r\n\r\nimport org.springframework.context.annotation.ComponentScan;\r\nimport org.springframework.context.annotation.Configuration;\r\nimport org.springframework.context.annotation.Import;\r\n\r\nimport java.lang.annotation.ElementType;\r\nimport java.lang.annotation.Retention;\r\nimport java.lang.annotation.RetentionPolicy;\r\nimport java.lang.annotation.Target;\r\n\r\n\u002F**\r\n * springboot核心注解\r\n * 贴在springboot应用的启动类上\r\n *\u002F\r\n\r\n@Target(ElementType.TYPE)\r\n@Retention(RetentionPolicy.RUNTIME)\r\n@Configuration  \u002F\u002F 表明该类是一个配置类\r\n@ComponentScan  \u002F\u002F spring 扫描bean范围\r\n@Import(WebServiceAutoConfiguration.class) \u002F\u002F web服务自动配置\r\npublic @interface MhSpringBootApplication {\r\n\r\n}\r\n```\r\n\r\n\r\n\r\n（3）**MhSpringApplication**核心类：\r\n\r\n```java\r\npackage com.mh.springboot;\r\n\r\nimport org.springframework.web.context.WebApplicationContext;\r\nimport org.springframework.web.context.support.AnnotationConfigWebApplicationContext;\r\n\r\nimport java.util.Map;\r\n\r\n\u002F**\r\n * springboot 启动类型运行的方法\r\n *\u002F\r\n\r\npublic class MhSpringApplication {\r\n\r\n    \u002F**\r\n     * 1.创建一个Spring容器\r\n     * 2.调用webserver，获取tomcat或jetty对象，并启动\r\n     *\u002F\r\n    public static void run(Class clazz) {\r\n        \u002F\u002F 创建一个spring容器，spring中扫描到的bean存放到applicationContext这个容器里\r\n        AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();\r\n        applicationContext.register(clazz);\r\n        applicationContext.refresh();\r\n\r\n        \u002F\u002F 这样，我们就只需要在getWebServer方法中去判断到底该返回TomcatWebServer还是JettyWebServer。\r\n        WebServer webServer = getWebServer(applicationContext);\r\n        webServer.start();\r\n    }\r\n\r\n    \u002F\u002F 获取web服务, 根据添加的tomcat或者jetty依赖，自动选择对应的web服务来启动\r\n    public static WebServer getWebServer(WebApplicationContext applicationContext){\r\n        \u002F\u002F 从spring容器中获取tomcat或者jetty的bean对象\r\n        \u002F\u002F key为beanName, value为Bean对象， 通过接口去获取，拿到的可能是多个实现类对象\r\n        Map\u003CString, WebServer> webServers = applicationContext.getBeansOfType(WebServer.class);\r\n\r\n        if (webServers.isEmpty()) {\r\n            throw new NullPointerException();\r\n        }\r\n        if (webServers.size() > 1) { \u002F\u002F 只允许存在一个，要么tomcat，要么jetty\r\n            throw new IllegalStateException();\r\n        }\r\n        \u002F\u002F 返回唯一的一个\r\n        return webServers.values().stream().findFirst().get();\r\n    }\r\n}\r\n```\r\n\r\n（4）WebServer 接口\r\n\r\n```java\r\npackage com.mh.springboot;\r\n\r\npublic interface WebServer {\r\n    void start();\r\n}\r\n```\r\n\r\n（5）tomcat服务\r\n\r\n```java\r\npackage com.mh.springboot;\r\n\r\npublic class TomcatWebServer implements WebServer {\r\n    @Override\r\n    public void start() {\r\n        System.out.println(\"启动tomcat\");\r\n    }\r\n}\r\n```\r\n\r\n（6）jetty服务\r\n\r\n```java\r\npackage com.mh.springboot;\r\n\r\npublic class JettyWebServer implements WebServer {\r\n    @Override\r\n    public void start() {\r\n        System.out.println(\"启动jetty\");\r\n    }\r\n}\r\n```\r\n\r\n（7）WebServiceAutoConfiguration自动配置类\r\n\r\n```java\r\npackage com.mh.springboot;\r\n\r\nimport org.springframework.context.annotation.Bean;\r\nimport org.springframework.context.annotation.Configuration;\r\n\r\n\u002F**\r\n * 创建web服务自动配置类\r\n *\u002F\r\n\r\npublic class WebServiceAutoConfiguration {\r\n\r\n    @Bean\r\n    \u002F\u002F 条件注解\r\n    \u002F\u002F 条件配置，如果pom添加了tomcat依赖，则自动创建tomcat服务\r\n    @MhConditionOnClass(\"org.apache.catalina.startup.Tomcat\")\r\n    public TomcatWebServer tomcatWebServer(){\r\n        return new TomcatWebServer();\r\n    }\r\n\r\n    @Bean\r\n    \u002F\u002F 条件配置，如果pom添加了jetty依赖，则自动创建jetty服务\r\n    @MhConditionOnClass(\"org.eclipse.jetty.server.Server\")\r\n    public JettyWebServer jettyWebServer(){\r\n        return new JettyWebServer();\r\n    }\r\n}\r\n```\r\n\r\n（8）模拟实现条件注解，创建专门用于判断指定类是否存在的注解@MhConditionOnClass\r\n\r\n```java\r\npackage com.mh.springboot;\r\n\r\nimport org.springframework.context.annotation.Conditional;\r\n\r\nimport java.lang.annotation.ElementType;\r\nimport java.lang.annotation.Retention;\r\nimport java.lang.annotation.RetentionPolicy;\r\nimport java.lang.annotation.Target;\r\n\r\n\u002F**\r\n * 模拟实现条件注解，判断指定类是否存在\r\n * 其中核心为@Conditional(OnClassConditional.class)，因为它才是真正的判断逻辑\r\n *\u002F\r\n\r\n@Target({ElementType.TYPE, ElementType.METHOD})\r\n@Retention(RetentionPolicy.RUNTIME)\r\n@Conditional(OnClassConditional.class)\r\npublic @interface MhConditionOnClass {\r\n    String value();\r\n}\r\n```\r\n\r\n（9）实现真正的判断逻辑\r\n\r\n```java\r\npackage com.mh.springboot;\r\n\r\nimport org.springframework.context.annotation.Condition;\r\nimport org.springframework.context.annotation.ConditionContext;\r\nimport org.springframework.core.type.AnnotatedTypeMetadata;\r\n\r\nimport java.util.Map;\r\n\r\n\u002F**\r\n * 根据条件判断是否属于指定类\r\n *\u002F\r\npublic class OnClassConditional implements Condition {\r\n\r\n    \u002F**\r\n     * 返回 true 则符合条件，返回 false 不符合条件\r\n     *\u002F\r\n    @Override\r\n    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {\r\n        \u002F\u002F 通过元数据，获取所贴注解的传入信息，即@MhConditionOnClass注解的value属性值\r\n        Map\u003CString, Object> map = metadata.getAnnotationAttributes(MhConditionOnClass.class.getName());\r\n        String className = (String) map.get(\"value\");\r\n        try {\r\n            \u002F\u002F 加载指定的类名，如果报错，那就说明该类不存在\r\n            context.getClassLoader().loadClass(className);\r\n            return true;\r\n        } catch (ClassNotFoundException e) {\r\n            return false;\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n\r\n\r\n### 2.3.2\tuser模块\r\n\r\n（1）pom文件\r\n\r\n```xml\r\n\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n\u003Cproject xmlns=\"http:\u002F\u002Fmaven.apache.org\u002FPOM\u002F4.0.0\" xmlns:xsi=\"http:\u002F\u002Fwww.w3.org\u002F2001\u002FXMLSchema-instance\"\r\n         xsi:schemaLocation=\"http:\u002F\u002Fmaven.apache.org\u002FPOM\u002F4.0.0 https:\u002F\u002Fmaven.apache.org\u002Fxsd\u002Fmaven-4.0.0.xsd\">\r\n\r\n    \u003Cparent>\r\n        \u003CgroupId>com.mh\u003C\u002FgroupId>\r\n        \u003CartifactId>mh-springboot\u003C\u002FartifactId>\r\n        \u003Cversion>1.0\u003C\u002Fversion>\r\n    \u003C\u002Fparent>\r\n\r\n    \u003CmodelVersion>4.0.0\u003C\u002FmodelVersion>\r\n    \u003CartifactId>user\u003C\u002FartifactId>\r\n    \u003Cversion>1.0\u003C\u002Fversion>\r\n\r\n    \u003Cdependencies>\r\n        \u003Cdependency>\r\n            \u003CgroupId>com.mh\u003C\u002FgroupId>\r\n            \u003CartifactId>springboot\u003C\u002FartifactId>\r\n            \u003Cversion>1.0\u003C\u002Fversion>\r\n            \u003Cexclusions>\r\n                \u003Cexclusion>\r\n                    \u003CgroupId>org.apache.tomcat.embed\u003C\u002FgroupId>\r\n                    \u003CartifactId>tomcat-embed-core\u003C\u002FartifactId>\r\n                \u003C\u002Fexclusion>\r\n            \u003C\u002Fexclusions>\r\n        \u003C\u002Fdependency>\r\n\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.eclipse.jetty\u003C\u002FgroupId>\r\n            \u003CartifactId>jetty-server\u003C\u002FartifactId>\r\n            \u003Cversion>11.0.24\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n    \u003C\u002Fdependencies>\r\n\r\n\u003C\u002Fproject>\r\n```\r\n\r\n\r\n\r\n（2）controller\r\n\r\n```java\r\npackage com.mh.user.controller;\r\n\r\nimport com.mh.user.service.UserService;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.RestController;\r\n\r\n@RestController\r\npublic class UserController {\r\n\r\n    @Autowired\r\n    private UserService userService;\r\n\r\n    @GetMapping(\"\u002Ftest\")\r\n    public String test(){\r\n        return userService.test();\r\n    }\r\n}\r\n```\r\n\r\n（3）service\r\n\r\n```java\r\npackage com.mh.user.service;\r\n\r\nimport org.springframework.stereotype.Service;\r\n\r\n@Service\r\npublic class UserService {\r\n\r\n    public String test() {\r\n        return \"hello mh\";\r\n    }\r\n}\r\n```\r\n\r\n（4）启动类\r\n\r\n```java\r\npackage com.mh.user;\r\n\r\nimport com.mh.springboot.MhSpringApplication;\r\nimport com.mh.springboot.MhSpringBootApplication;\r\nimport org.springframework.context.annotation.ComponentScan;\r\nimport org.springframework.context.annotation.Configuration;\r\n\r\n\u002F**\r\n * user应用启动类\r\n * springboot 并不是重新开发，只是对现有的技术进行整合\r\n *\u002F\r\n\r\n@MhSpringBootApplication\r\n\u002F* 相当于下面这两个注解\r\n@Configuration\r\n@ComponentScan*\u002F\r\npublic class UserApplication {\r\n\r\n    public static void main(String[] args) {\r\n        MhSpringApplication.run(UserApplication.class);\r\n    }\r\n}\r\n```\r\n\r\n\r\n\r\n# 3\t发现自动配置类\r\n\r\n在上面的配置中，我们通过手动`@Import(WebServiceAutoConfiguration.class)`导入实现自动配置功能，但是springboot中存在很多个需要自动配置的功能，每个都在`@SpringBootApplication`核心注解上`@Import`导入显然不现实的。\r\n\r\n接下来我们就通过spring自带功能来实现发现自动配置类功能。\r\n\r\n## 3.1\t创建AutoConfiguration接口\r\n\r\n创建一个AutoConfiguration接口，其他需要实现自动配置功能的类，只需要实现这个接口即可。\r\n\r\n```java\r\npackage com.mh.springboot;\r\n\r\n\u002F**\r\n * 声明一个自动配置类接口，所有需要自动配置的类只需要实现这个接口即可\r\n * 在导入选择器中只需要根据这个接口来获取所有自动配置类\r\n *\u002F\r\npublic interface AutoConfiguration {\r\n}\r\n```\r\n\r\n## 3.2\t修改WebServiceAutoConfiguration自动配置类\r\n\r\n实现AutoConfiguration接口，并贴上`@Configuration`注解。\r\n\r\n```java\r\npackage com.mh.springboot;\r\n\r\nimport org.springframework.context.annotation.Bean;\r\nimport org.springframework.context.annotation.Configuration;\r\n\r\n\u002F**\r\n * 创建web服务自动配置类\r\n *\u002F\r\n\r\n@Configuration\r\npublic class WebServiceAutoConfiguration implements AutoConfiguration {\r\n\r\n    @Bean\r\n    \u002F\u002F 条件注解\r\n    \u002F\u002F 条件配置，如果pom添加了tomcat依赖，则自动创建tomcat服务\r\n    @MhConditionOnClass(\"org.apache.catalina.startup.Tomcat\")\r\n    public TomcatWebServer tomcatWebServer(){\r\n        return new TomcatWebServer();\r\n    }\r\n\r\n    @Bean\r\n    \u002F\u002F 条件配置，如果pom添加了jetty依赖，则自动创建jetty服务\r\n    @MhConditionOnClass(\"org.eclipse.jetty.server.Server\")\r\n    public JettyWebServer jettyWebServer(){\r\n        return new JettyWebServer();\r\n    }\r\n}\r\n```\r\n\r\n## 3.3\t创建配置文件\r\n\r\n现在我们需要在springboot模块的`resources`目录下创建`META-INF\u002Fservices`目录和文件。\r\n\r\n文件的名称就是我们上面写的AutoConfiguration接口全类限定名称，即`com.mh.springboot.AutoConfiguration`。并写入内容`com.mh.springboot.WebServiceAutoConfiguration`，就是我们的WebServiceAutoConfiguration自动配置类名字。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fspringboot源码\u002Fconfig-file.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n## 3.4\t创建ImportSelect导入选择器\r\n\r\n创建ImportSelect导入选择器，通过spring工具获取`META-INF\u002Fservices` 路径下对应AutoConfiguration文件里的自动配置类信息。\r\n\r\n```java\r\npackage com.mh.springboot;\r\n\r\nimport org.springframework.context.annotation.DeferredImportSelector;\r\nimport org.springframework.core.type.AnnotationMetadata;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport java.util.ServiceLoader;\r\n\r\n\u002F**\r\n * 配置类导入选择器\r\n *\u002F\r\n\r\npublic class MhImportSelect implements DeferredImportSelector {\r\n\r\n    @Override\r\n    public String[] selectImports(AnnotationMetadata importingClassMetadata) {\r\n        \u002F\u002F 读取 META-INF\u002Fservices 路径下 对应AutoConfiguration文件存放的自动配置类信息\r\n        ServiceLoader\u003CAutoConfiguration> serviceLoader = ServiceLoader.load(AutoConfiguration.class);\r\n\r\n        List\u003CString> list = new ArrayList\u003C>();\r\n\r\n        serviceLoader.forEach(service -> {\r\n            list.add(service.getClass().getName());\r\n        });\r\n\r\n        return list.toArray(new String[list.size()]);\r\n    }\r\n}\r\n```\r\n\r\n## 3.5\t修改@SpringBootApplication核心注解\r\n\r\n添加`@Import(MhImportSelect.class)`注解，导入选择器类。\r\n\r\n```java\r\npackage com.mh.springboot;\r\n\r\nimport org.springframework.context.annotation.ComponentScan;\r\nimport org.springframework.context.annotation.Configuration;\r\nimport org.springframework.context.annotation.Import;\r\n\r\nimport java.lang.annotation.ElementType;\r\nimport java.lang.annotation.Retention;\r\nimport java.lang.annotation.RetentionPolicy;\r\nimport java.lang.annotation.Target;\r\n\r\n\u002F**\r\n * springboot核心注解\r\n * 贴在springboot应用的启动类上\r\n *\u002F\r\n\r\n@Target(ElementType.TYPE)\r\n@Retention(RetentionPolicy.RUNTIME)\r\n@Configuration  \u002F\u002F 表明该类是一个配置类\r\n@ComponentScan  \u002F\u002F spring 扫描bean范围\r\n@Import(MhImportSelect.class)  \u002F\u002F 导入一个公共类，所有自动配置类通过这个类选择导入\r\npublic @interface MhSpringBootApplication {\r\n\r\n}\r\n```\r\n\r\n## 3.6\t总结\r\n\r\nuser模块什么都不需要改动，直接启动即可完成发现自动配置类功能。\r\n\r\n后续需要发现自动配置功能：\r\n\r\n- 只需要实现AutoConfiguration接口\r\n- 在`META-INF\u002Fservices\u002Fcom.mh.springboot.AutoConfiguration`文件中添加实现类名称\n",{"_path":187,"slug":188,"title":189,"description":190,"excerpt":190,"date":191,"tags":192,"type":15,"cover":193,"content":194},"\u002Fknowledge\u002Flinux系统基础操作","linux系统基础操作","Linux系统基础操作","Linux系统基础操作 1 基础命令 ‌Linux系统主要分为**Redhat**系和**Debian**系，这两个类别涵盖了绝大部分常用的Linux系统‌。‌ - **Redhat**系 Redhat系主要包括**Redhat、CentOS、Fedora**等。CentOS是很多服务器用户选择的系统，因为它与RHEL","2025-04-21",[124,13,63],"\u002Fknowledge-assets\u002Flinux系统基础操作\u002F网络配置文件.png","# Linux系统基础操作\r\n\r\n# 1\t基础命令\r\n\r\n‌Linux系统主要分为**Redhat**系和**Debian**系，这两个类别涵盖了绝大部分常用的Linux系统‌。‌\r\n\r\n- **Redhat**系\r\n  Redhat系主要包括**Redhat、CentOS、Fedora**等。CentOS是很多服务器用户选择的系统，因为它与RHEL（Red Hat Enterprise Linux）高度兼容，且开源免费。\r\n\r\n- **Debian**系\r\n  Debian系主要包括**Debian、Ubuntu、Mint**等。这个系列还有其他一些衍生版本的系统。\r\n\r\n- 其他系统\r\n  此外，还有一些其他系统，例如Gentoo、Arch Linux、LFS（Linux From Scratch）等。\r\n\r\n  \r\n\r\n发行版特点：\r\n\r\n​\tLinux发行版是基于Linux内核的一系列软件产品，包括应用程序和工具。每个发行版都有自己的包管理器、桌面环境和一些特定的工具，提供了更加便捷和高效的使用体验。常见的发行版有Ubuntu、RedHat、CentOS、Debian、Fedora等。\r\n\r\n不同的派系，使用上会有一些区别，如Debian系用apt包管理器，Redhat系用rpm、yum包管理器。\r\n\r\n## 1.1\trpm 安装与卸载软件\r\n\r\n### 1.1.1\t安装一个rpm软件包\r\n\r\n```shell\r\nrpm -ivh 软件包名.rpm\r\n# 强制安装，忽略依赖\r\nrpm -ivh --nodeps 软件包名.rpm\r\n\r\n这里的选项含义如下：\r\n-i：表示安装（install）操作。\r\n-v：表示详细信息输出（verbose），可以看到安装过程的详细信息。\r\n-h：表示以散列（hash）标记显示安装进度\r\n--nodeps 表示强制操作，忽略相关依赖\r\n```\r\n\r\n### 1.1.2\t卸载一个软件包\r\n\r\n```shell\r\nrpm -e 包名\r\n# 如卸载nginx\r\nrpm -e nginx\r\n# 强制卸载\r\nsudo rpm -e --nodeps 包名\r\n\r\n这里的选项:\r\n-e 表示卸载（erase）操作。\r\n--nodeps 表示强制操作\r\n\r\n```\r\n\r\n### 1.1.3\t升级一个 RPM 软件包\r\n\r\n```shell\r\nrpm -Uvh 包名.rpm\r\n# 或\r\nrpm -Fvh 包名.rpm\r\n\r\n这里的选项含义如下：\r\n-U：表示升级（upgrade）或安装软件包。\r\n-F：表示只升级（freshen）已安装的软件包，如果软件包未安装，则不会安装它。\r\n```\r\n\r\n### 1.1.4\t查询已安装的软件包\r\n\r\n```shell\r\n# 查询已经安装的软件包\r\nrpm -q 包名\r\n# 查询所有已安装的软件包\r\nrpm -qa 包名\r\n\r\n# 如：查询是否安装了nginx\r\nrpm -qa | grep nginx\r\n\r\n# 查询软件包文件列表\r\nrpm -ql 包名\r\n\r\n# 查询软件包的详细信息\r\nrpm -qi 包名\r\n\r\n# 查询某个文件属于哪个 RPM 软件包\r\nrpm -qf 文件路径\r\n\r\n这里的选项的含义如下：\r\n-q：查询（query）操作。\r\n-a：所有。\r\n-l：列表。\r\n-i：详细信息；\r\n-f：指定查询的文件（file）。例如，如果您想查询 \u002Fusr\u002Flib64\u002Ffirefox\u002Fplatform.ini文件属于哪个软件包\r\n```\r\n\r\n### 1.1.5\t验证软件包\r\n\r\n```shell\r\nrpm -V 包名\r\n```\r\n\r\n\r\n\r\n## 1.2\tyum安装与卸载软件\r\n\r\nyum是一个基于RPM的包管理器，主要用于在Red Hat系列的Linux发行版中管理软件包。它能够自动处理软件包的依赖关系，并且可以从配置的软件仓库中下载和安装软件包。\r\n\r\n### 1.2.1\t升级系统\r\n\r\n```shell\r\n# 升级所有包同时，也升级软件和系统内核\r\nyum -y update\t\r\n# 只升级所有软件包文件，不升级软件和系统内核，软件和内核保持原样\r\nyum -y upgarde\t\r\n```\r\n\r\n### 1.2.2\t查看所有软件包\r\n\r\n```shell\r\n# 查看所有可安装的软件包\r\nyum list\r\n\r\n# 查看已经安装的软件包\r\nyum list installed\r\n\r\n# 显示软件包的名称、版本、大小、仓库等信息\r\nyum info 软件包名\r\n```\r\n\r\n### 1.2.6\t模糊搜索软件包\r\n\r\n```shell\r\nyum search 软件包名\r\n```\r\n\r\n### 1.2.3\t安装软件包\r\n\r\n```shell\r\n# yum会自动解决依赖关系，并下载安装所需的软件包。\r\nyum install 软件包名\r\n# 如安装 nginx\r\nyum -y install nginx\r\n\r\n这里的选项的含义如下：\r\n-y：安装过程遇到yes\u002Fno询问，可省略输入Y确认\r\n```\r\n\r\n### 1.2.4\t卸载\u002F删除\r\n\r\n```shell\r\n# 这个命令会删除指定的软件包，同时也会删除不再需要的依赖包\r\nyum remove 软件包名\r\n```\r\n\r\n### 1.2.5\t软件更新\r\n\r\n```shell\r\nyum -y update 软件包名\r\n```\r\n\r\n### 1.2.7\t清除缓存中老旧的头文件和软件包\r\n\r\n```shell\r\nyum clean all\r\n```\r\n\r\n### 1.2.8\t列出启用的仓库\r\n\r\n要查看当前系统中启用了哪些仓库，可以使用repolist命令：\r\n\r\n```shell\r\n# 列出所有启用的仓库及其状态\r\nyum repolist\r\n```\r\n\r\n### 1.2.9\t启用或禁用仓库\r\n\r\n通过编辑仓库配置文件来启用或禁用某个仓库。仓库配置文件通常位于\u002Fetc\u002Fyum.repos.d\u002F目录下。例如，禁用epel仓库：\r\n\r\n```shell\r\nvi \u002Fetc\u002Fyum.repos.d\u002Fepel.repo\r\n```\r\n\r\n在文件中找到enabled=1，将其改为enabled=0，然后保存退出。\r\n\r\n### 1.2.10\t添加新的仓库\r\n\r\n如果你需要从其他仓库中安装软件包，可以手动添加新的仓库。首先，创建一个新的.repo文件：\r\n\r\n```shell\r\nvi \u002Fetc\u002Fyum.repos.d\u002Fmyrepo.repo\r\n```\r\n\r\n然后，在文件中添加以下内容：\r\n\r\n```properties\r\n[myrepo]\r\nname=My Custom Repository\r\nbaseurl=http:\u002F\u002Fexample.com\u002Fmyrepo\r\nenabled=1\r\ngpgcheck=0\r\n```\r\n\r\n保存退出后，`yum`就会从这个新的仓库中下载软件包。\r\n\r\n## 1.3\t检查操作系统信息\r\n\r\n### 1.3.1\tlscpu\r\n\r\n```shell\r\nlscpu\r\n\r\n[root@localhost home]# lscpu\r\nArchitecture:          x86_64\r\nCPU op-mode(s):        32-bit, 64-bit\r\nByte Order:            Little Endian\r\nCPU(s):                8\r\nOn-line CPU(s) list:   0-7\r\nThread(s) per core:    1\r\nCore(s) per socket:    1\r\nSocket(s):             8\r\nNUMA node(s):          1\r\nVendor ID:             GenuineIntel\r\nCPU family:            6\r\nModel:                 85\r\nModel name:            Intel(R) Xeon(R) Silver 4210R CPU @ 2.40GHz\r\nStepping:              7\r\nCPU MHz:               2394.375\r\nBogoMIPS:              4788.75\r\nHypervisor vendor:     VMware\r\nVirtualization type:   full\r\nL1d cache:             32K\r\nL1i cache:             32K\r\nL2 cache:              1024K\r\nL3 cache:              14080K\r\nNUMA node0 CPU(s):     0-7\r\n```\r\n\r\n\r\n\r\n### 1.3.2\t\u002Fetc\u002Fos-release\r\n\r\n```shell\r\ncat \u002Fetc\u002F*release\r\ncat \u002Fetc\u002Fos-release\r\n```\r\n\r\n信息如下：\r\n\r\n```shell\r\n[root@localhost ~]# cat \u002Fetc\u002F*release\r\nCentOS Linux release 7.9.2009 (Core)\r\nNAME=\"CentOS Linux\"\r\nVERSION=\"7 (Core)\"\r\nID=\"centos\"\r\nID_LIKE=\"rhel fedora\"\r\nVERSION_ID=\"7\"\r\nPRETTY_NAME=\"CentOS Linux 7 (Core)\"\r\nANSI_COLOR=\"0;31\"\r\nCPE_NAME=\"cpe:\u002Fo:centos:centos:7\"\r\nHOME_URL=\"https:\u002F\u002Fwww.centos.org\u002F\"\r\nBUG_REPORT_URL=\"https:\u002F\u002Fbugs.centos.org\u002F\"\r\n\r\nCENTOS_MANTISBT_PROJECT=\"CentOS-7\"\r\nCENTOS_MANTISBT_PROJECT_VERSION=\"7\"\r\nREDHAT_SUPPORT_PRODUCT=\"centos\"\r\nREDHAT_SUPPORT_PRODUCT_VERSION=\"7\"\r\n\r\nCentOS Linux release 7.9.2009 (Core)\r\nCentOS Linux release 7.9.2009 (Core)\r\n```\r\n\r\n\r\n\r\n麒麟操作系统\r\n\r\n```shell\r\nNAME=\"Kylin Linux Advanced Server\"\r\nVERSION=\"V10 (Halberd)\"\r\nID=\"kylin\"\r\nVERSION_ID=\"V10\"\r\nPRETTY_NAME=\"Kylin Linux Advanced Server V10 (Halberd)\"\r\nANSI_COLOR=\"0;31\"\r\n```\r\n\r\n\r\n\r\n## 1.4\t检查系统内存与存储空间\r\n\r\n### 1.4.1\tfree -lh\r\n\r\n查看内存信息（以GB单位显示）：\r\n\r\n```shell\r\nfree -lh\r\n\r\n[root@localhost home]# free -lh\r\n              total        used        free      shared  buff\u002Fcache   available\r\nMem:            15G        9.4G        2.7G         16M        3.4G        5.7G\r\nLow:            15G         12G        2.7G\r\nHigh:            0B          0B          0B\r\nSwap:          7.9G         33M        7.8G\r\n```\r\n\r\n### 1.4.2\tdf -lh\r\n\r\n查看磁盘存储信息（以GB单位显示）：\r\n\r\n```shell\r\ndf -lh\r\n\r\n[root@localhost ~]# df -lh\r\nFilesystem               Size  Used Avail Use% Mounted on\r\ndevtmpfs                 7.8G     0  7.8G   0% \u002Fdev\r\ntmpfs                    7.8G     0  7.8G   0% \u002Fdev\u002Fshm\r\ntmpfs                    7.8G   18M  7.8G   1% \u002Frun\r\ntmpfs                    7.8G     0  7.8G   0% \u002Fsys\u002Ffs\u002Fcgroup\r\n\u002Fdev\u002Fmapper\u002Fcentos-root   50G   14G   37G  27% \u002F\r\n\u002Fdev\u002Fsda1               1014M  194M  821M  20% \u002Fboot\r\n\u002Fdev\u002Fmapper\u002Fcentos-home  241G   12G  230G   5% \u002Fhome\r\ntmpfs                    1.6G     0  1.6G   0% \u002Frun\u002Fuser\u002F0\r\n```\r\n\r\n### 1.4.3\tdu -sh *\r\n\r\n查看当前目录及文件大小：\r\n\r\n```shell\r\n# 查看所有文件\r\ndu -sh *\r\n# 查看当前目录\r\ndu -sh .\r\n\r\n[root@localhost home]# du -sh *\r\n1.5G    chenyun\r\n269M    dbswitch-release-2.0.1\r\n214M    dbswitch-release-2.0.1.tar.gz\r\n2.9G    docker\r\n6.7G    smartsync\r\n[root@localhost home]# du -sh .\r\n12G     .\r\n```\r\n\r\n## 1.5\t删除命令\r\n\r\n### 1.5.1\trm\r\n\r\n```shell\r\nrm 文件\u002F目录名称\r\n```\r\n\r\n### 1.5.2\tfind . -delete\r\n\r\n```shell\r\n# 当系统不能使用rm命令十，可以使用find命令删除\r\n# 使用find 命令删除（只能删除空目录或文件）\r\nfind . -name text.log -delete\r\n# 删除当前目录下的文件及空目录\r\nfind . -delete\r\n```\r\n\r\n\r\n\r\n## 1.6\txargs\r\n\r\n​\t\t`xargs` 的核心功能是将输入数据转换为命令行参数。它通常与其他命令（如 `find`、`grep` 等）结合使用，以处理大量数据或文件。\r\n\r\n### 1.6.1. 基本语法\r\n\r\n```shell\r\nxargs [选项] [命令]\r\n```\r\n\r\n- **输入**：`xargs` 从标准输入（stdin）读取数据。\r\n- **输出**：将输入数据作为参数传递给指定的命令并执行。\r\n\r\n**常用选项**\r\n\r\n| 选项          | 说明                                   |\r\n| ------------- | -------------------------------------- |\r\n| `-n`          | 指定每次执行命令时使用的参数个数。     |\r\n| `-I`          | 用输入项替换占位符（通常为 `{}`）。    |\r\n| `-p`          | 交互式模式，执行前提示用户确认。       |\r\n| `-t`          | 打印执行的命令。                       |\r\n| `-r`          | 如果输入为空，则不执行命令。           |\r\n| `-d`          | 指定输入的分隔符（默认是空格和换行）。 |\r\n| `-a`          | 从文件读取输入，而不是标准输入。       |\r\n| `-L`          | 指定每次执行命令时使用的行数。         |\r\n| `-s`          | 设置命令行的最大长度。                 |\r\n| `--max-procs` | 并行执行命令，指定最大进程数。         |\r\n\r\n### 1.6.2\t使用示例\r\n\r\n（1）**将输入参数传递给echo**\r\n\r\n```shell\r\necho \"file1 file2 file3\" | xargs echo\r\n\r\n[root@localhost home]# echo \"file1 file2 file3\" | xargs echo\r\nfile1 file2 file3\r\n```\r\n\r\n（2）**结合find使用**\r\n\r\n```shell\r\n# 查找当前目录下的 .txt 文件并删除：\r\nfind . -name \"*.txt\" | xargs rm\r\n```\r\n\r\n（3）**使用占位符（`-I`）**\r\n\r\n```shell\r\n# 复制当前目录下的文件或目录到\u002Fhome目录\r\nls | xargs -I {} cp \u002Fhome\r\n\r\n# 批量加载docker镜像\r\nfind . -name \"*.rar\" | xargs -I {} docker load -i {}\r\n```\r\n\r\n[参考](https:\u002F\u002Fwww.cnblogs.com\u002Fydswin\u002Fp\u002F18639288)：https:\u002F\u002Fwww.cnblogs.com\u002Fydswin\u002Fp\u002F18639288\r\n\r\n\r\n\r\n## 1.7\tsed\r\n\r\n​\t\t**sed（Stream Editor）是Linux\u002FUnix系统中强大的流式文本编辑器**‌，主要用于非交互式地逐行处理文本数据，支持查找、替换、删除、插入等操作，常与正则表达式结合使用。‌‌\r\n\r\n### 1.7.1\t基本语法\r\n\r\n```shell\r\nsed [选项] '命令' 文件名\r\n```\r\n\r\n常用选项：\r\n\r\n- `-n`：抑制默认输出。\r\n- `-e`：多命令串联。\r\n- `-f`：从脚本文件读取命令。\r\n- `-i`：直接修改文件（危险操作需谨慎）\r\n\r\n\r\n\r\n### 1.7.2\t使用示例\r\n\r\n（1）替换文本\r\n\r\n```shell\r\nsed 's\u002Fold\u002Fnew\u002Fgi' file\r\n\r\n# s代表文本替换\r\n# old表示被替换的旧文本\r\n# new表示替换的新文本\r\n# g表示全局替换，不加g只替换匹配的一次\r\n# i表示不区分大小写\r\n# 使用\u002F区分新文本和旧文本，也可以使用其他符号，如：sed 's#old#new#g' file\r\n```\r\n\r\n（2）删除文本行\r\n\r\n```shell\r\nsed '\u003Cn>d' file\r\n\r\n# n代表第几行\r\n\r\n# 删除第2行文本\r\nsed '2d' file\r\n\r\n```\r\n\r\n[参考](https:\u002F\u002Fwww.cnblogs.com\u002FTangQF\u002Farticles\u002F18555649)：https:\u002F\u002Fwww.cnblogs.com\u002FTangQF\u002Farticles\u002F18555649\r\n\r\n\r\n\r\n## 1.8\t管理用户\r\n\r\n（1）创建用户\r\n\r\n```shell\r\n# 创建用户\r\nsudo useradd [选项] 用户名\r\n\r\n常用选项：\r\n  -m：创建用户家目录（默认位置 \u002Fhome\u002F用户名）\r\n  -s \u002Fbin\u002Fbash：指定默认Shell（如bash）\r\n  -G 组名：附加用户到其他组（多个组用逗号分隔）\r\n  -c \"注释\"：添加用户描述（如全名）\r\n\r\n# 示例：\r\nsudo useradd -m -s \u002Fbin\u002Fbash -c \"测试用户\" appuser\r\n```\r\n\r\n（2）设置密码\r\n\r\n```shell\r\nsudo passwd 用户名  # 按提示输入密码\r\n```\r\n\r\n（3）回收（删除）用户\r\n\r\n```shell\r\nsudo userdel [选项] 用户名\r\n\r\n常用选项：\r\n-r：同时删除用户家目录和邮件目录（重要！）\r\n-f：强制删除（即使用户已登录） ，不会关闭已经启动的进程\r\n\r\n# 示例：\r\nsudo userdel -r appuser  # 彻底删除用户及其家目录\r\n```\r\n\r\n彻底删除用户\r\n\r\n```shell\r\nsudo pkill -u john       # 结束用户所有进程\r\nsudo userdel -r john     # 删除用户及家目录\r\n```\r\n\r\n\r\n\r\n\r\n\r\n# 2\t常见配置\r\n\r\n## 2.1\tssh服务器间免密登录\r\n\r\n​\t实现Linux系统A服务器免密登录B服务器。首先在A服务器上生成ssh密钥对。\r\n\r\n（1）创建密钥对\r\n\r\n​\t\t在A服务器上创建密钥对，执行成功后会在用户目录的`~\u002F.ssh`下生成`id_rsa`私钥和`id_rsa.pub`公钥两个文件。\r\n\r\n```shell\r\nssh-keygen\r\n```\r\n\r\n​\t\t执行以上命令，一路回车即可。\r\n\r\n（2）将公钥复制到服务器端\r\n\r\n​\t\t创建密钥对成功后，在A服务器上执行以下命令，将公钥文件远程拷贝到B服务器。\r\n\r\n```shell\r\nssh-copy-id root@192.168.x.x\r\n```\r\n\r\n​\t\t如果服务器没有`ssh-copy-id`命令，需要手把`id_rsa.pub`中的内容拷贝到B服务器的`~\u002F.ssh\u002Fauthorized_keys`文件中。\r\n\r\n（3）验证登录\r\n\r\n```shell\r\nssh root@192.168.x.x\r\n```\r\n\r\n​\t\t执行命令后，如果不需要密码就登录成功，说明ssh免密登录配置成功了。\r\n\r\n​\t\t如果需要两台互相免密登录，将上面的操作在B服务器执行一遍即可。\r\n\r\n\r\n\r\n# 3\tIP修改\r\n\r\n## 3.1\t静态IP修改—文件方式\r\n\r\n### 3.1.1\t进入网络配置目录\r\n\r\n```java\r\ncd \u002Fetc\u002Fsysconfig\u002Fnetwork-scripts\u002F\r\n```\r\n\r\n输入 ls，查看文件名是ens-32  还是ens-33，我这里是 ifcfg-ens33\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Flinux系统基础操作\u002F网络配置文件.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n### 3.1.2\t修改配置文件\r\n\r\n```java\r\nvi ifcfg-ens33\r\n```\r\n\r\n可以删除全部内容，粘贴下面的内容到文件中。\r\n\r\n```java\r\n输入999dd 删除所有内容\r\n```\r\n\r\n文件内容修改如下：\r\n\r\n```shell\r\nTYPE=\"Ethernet\"\r\nPROXY_METHOD=\"none\"\r\nBROWSER_ONLY=\"no\"\r\nBOOTPROTO=\"static\"       #需要修改为static\r\nDEFROUTE=\"yes\"\r\nIPADDR=192.168.2.128     #ip地址修改\r\nGATEWAY=192.168.2.2      #网关地址修改，不可任意修改，必须参照下面的要求修改\r\nDNS1=8.8.8.8             # Google dns域名服务\r\nDNS2=114.114.114.114     # 114 DNS域名解析\r\nDNS3=223.5.5.5           # 阿里公共 DNS域名解析\r\nNAME=\"ens33\"\r\nUUID=\"ba52ece4-f2e7-44a4-a126-1e76d95a1bf2\"\r\nDEVICE=\"ens33\"\r\nONBOOT=\"yes\"\r\nZONE=public\r\n```\r\n\r\n修改完成后，保存，重启网络：\r\n\r\n```java\r\nsystemctl restart network\r\n```\r\n\r\n### 3.1.3\t检查是否能联网\r\n\r\n```java\r\nping www.baidu.com\r\n```\r\n\r\n​\t连网成功。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Flinux系统基础操作\u002F联网检查.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n```shell\r\n# 查看dns解析\r\ncat \u002Fetc\u002Fresolv.conf\r\n```\r\n\r\n\r\n\r\n### 3.1.4\t虚拟机网关地址修改\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Flinux系统基础操作\u002F查看网关地址.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n​\t\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Flinux系统基础操作\u002F查看网关地址1.png\" style=\"zoom:70%;\" \u002F>\r\n\r\n​\t\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Flinux系统基础操作\u002F查看网关地址2.png\" style=\"zoom:70%;\" \u002F>\r\n\r\n\r\n\r\n## 3.2\t静态IP修改—nmtui命令\r\n\r\n### 3.2.1\t打开网络配置\r\n\r\n（1）打开网络管理界面\r\n\r\n```shell\r\n# 输入命令，进入图形化界面\r\nnmtui\r\n```\r\n\r\n（2）编辑网络连接\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Flinux系统基础操作\u002F1-nmtui配置ip.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n（3）选择`ens192`网卡进入\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Flinux系统基础操作\u002F2-edit.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n（4）配置IP、网关等信息。比如配置ip为：192.168.4.105，网关为：192.168.4.1，DNS服务配置两个为：114.114.114.114，192.168.4.1，修改完成后，点击[OK]保存退出。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Flinux系统基础操作\u002F3-edit-connection.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n> 中文含义参考如下：\r\n>\r\n> \u003Cimg src=\"\u002Fknowledge-assets\u002Flinux系统基础操作\u002F3-edit-connection-1.png\" style=\"zoom:57%;\" \u002F>\r\n\r\n\r\n\r\n### 3.2.2\t重启网络\r\n\r\n```shell\r\n# 重载网卡，这里输入上面的网卡名称\r\nnmcli connection reload ens192\r\n# 启动\r\nnmcli connection up ens192\r\n\r\n# 检查能否联网\r\nping www.baidu.com\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Flinux系统基础操作\u002F4-reload-connection.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\r\n\r\n# 4\tLinux设置服务开机自启\r\n\r\n当系统启动时，用户经常需要让某些服务自动运行，以便无需手动介入即可提供服务。这就是Linux服务开机自启动的主要目的，它通过一系列机制确保系统在启动时按照预定的顺序和规则加载服务。\r\n\r\nLinux系统中设置服务开机自启动有多种方法，包括使用 init.d 脚本、 rc.local 脚本、使用 chkconfig 命令以及对于使用Systemd的现代Linux发行版的 systemctl 命令。\r\n\r\n在Linux系统中，添加服务以在开机启动时自动运行通常涉及到使用systemd（在较新的系统如CentOS 7及以上、Fedora、RHEL 7及以上、Ubuntu 16.04及以上等系统中），或者传统的init.d脚本（在较旧的系统或某些特定环境中）。\r\n\r\n参考：[Linux系统 init程序和systemd管理器](https:\u002F\u002Fblog.csdn.net\u002Fyuelai_217\u002Farticle\u002Fdetails\u002F130949299)\r\n\r\n## 4.1\t使用systemd\r\n\r\nSystemd 作为 Linux 系统的服务管理器，已经在大部分现代 Linux 发行版中取代了传统的 init 系统。systemctl 命令是与 Systemd 交互的主要方式，提供了启动、停止、重启、管理服务和系统守护进程的强大能力。\r\n\r\nSystemctl 是一个用于与 Systemd 系统和服务管理器进行交互的命令行工具。它不仅可以用来启动、停止、重启和启用服务，还能查看服务状态，设置服务开机自启动，以及管理 Systemd 的目标（target）。\r\n\r\n### 4.1.1\tsystemctl常用命令\r\n\r\n```shell\r\n# 启动服务\r\nsystemctl start nginx\r\n\r\n# 停止服务\r\nsystemctl stop nginx\r\n\r\n# 重启服务\r\nsystemctl restart nginx\r\n\r\n# 查看服务状态\r\nsystemctl status nginx\r\n\r\n# 开机自启\r\nsystemctl enable nginx\r\n\r\n# 取消开机自启\r\nsystemctl disable nginx\r\n```\r\n\r\n### 4.1.2\t配置服务开机自启动\r\n\r\n配置服务开机自启动是 systemctl 的一个常用功能。Systemd 使用单元文件（unit files）来定义如何启动服务，这些单元文件通常位于 \u002Fetc\u002Fsystemd\u002Fsystem\u002F 目录下。\r\n\r\n（1）创建一个service文件\r\n\r\n```shell\r\nvi \u002Fetc\u002Fsystemd\u002Fsystem\u002Fdocker.service\r\n```\r\n\r\n文件内容：\r\n\r\n```properties\r\n[Unit]\r\nDescription=Docker Application Container Engine\r\nDocumentation=https:\u002F\u002Fdocs.docker.com\r\n\r\n[Service]\r\nType=notify\r\nExecStart=\u002Fusr\u002Fbin\u002Fdockerd\r\nExecReload=\u002Fbin\u002Fkill -s HUP $MAINPID\r\nRestart=always\r\nStartLimitBurst=3\r\nStartLimitInterval=60s\r\n\r\n[Install]\r\nWantedBy=multi-user.target\r\n```\r\n\r\n参数描述：\r\n\r\n- Unit 段：描述服务信息，可以不写\r\n  - Description：服务描述信息\r\n  - Documentation：文档链接\r\n- Service 段：\r\n  - type：定义进程的行为\r\n    - Type=simple：默认值，执行ExecStart指定的命令，启动主进程\r\n    - Type=notify：当前服务启动完毕，会通知Systemd，再继续往下执行\r\n  - ExecStart：启动当前服务的命令\r\n  - ExecStartPre：启动当前服务之前执行的命令\r\n  - ExecStartPost：启动当前服务之后执行的命令\r\n  - ExecReload：重启当前服务时执行的命令\r\n  - ExecStop：停止当前服务时执行的命令\r\n  - ExecStopPost：停止当其服务之后执行的命令\r\n  - Restart：定义何种情况 Systemd 会自动重启当前服务，可能的值包括 always（总是重启）、on-success、on-failure、on-abnormal、on-abort、on-watchdog\r\n  - TimeoutStartSec：启动服务时等待的秒数，这一配置对于使用 Docker 容器而言显得尤为重要，因其第一次运行时可能需要下载镜像，严重延时会容易被 Systemd 误判为启动失败杀死。通常，对于这种服务，将此值指定为 0，从而关闭超时检测\r\n  - TimeoutStopSec：停止服务时的等待秒数，如果超过这个时间仍然没有停止，Systemd 会使用 SIGKILL 信号强行杀死服务的进程\r\n- Install 段：指定运行目标的 target\r\n  - WantedBy：\r\n    - multi-user.target：多用户模式\r\n\r\n（2）重新加载`systemd`，使更改生效\r\n\r\n```shell\r\nsystemctl daemon-reload\r\n```\r\n\r\n（3）启用服务，使其在Linux启动后自动运行\r\n\r\n```shell\r\nsystemctl enable docker.service\r\n```\r\n\r\n（4）启动服务\r\n\r\n```shell\r\nsystemctl start docker.service\r\n```\r\n\r\n\r\n\r\n\r\n\r\n## 4.1\t使用init.d\r\n\r\n\r\n\r\n\r\n\r\n# 5\t哈哈\r\n\r\n\r\n\r\n\r\n\r\n# 6\t定时管理\r\n\r\n\r\n\r\n# 7\t常见异常\r\n\r\n## 7.1\t无法解析主机 Could not retrieve mirrorlist.centos.org\r\n\r\n当使用`yum install`等等操作的似乎，如果报错Could not resolve host: mirrorlist.centos.org；Name or service not known时。\r\n\r\n```shell\r\nCould not retrieve mirrorlist http:\u002F\u002Fmirrorlist.centos.org\u002F?release=7&arch=x86_64&repo=os&infra=stock error was\r\n14: curl#6 - \"Could not resolve host: mirrorlist.centos.org; Name or service not known\"\r\n One of the configured repositories failed (Unknown),\r\n and yum doesn't have enough cached data to continue. At this point the only\r\n ........\r\nCannot find a valid baseurl for repo: base\u002F7\u002Fx86_64\r\n```\r\n\r\n（1）下载CentOS 7的对应的repo文件，[地址](http:\u002F\u002Fmirrors.aliyun.com\u002Frepo\u002FCentos-7.repo)：http:\u002F\u002Fmirrors.aliyun.com\u002Frepo\u002FCentos-7.repo\r\n\r\n（2）上传到服务器；\r\n\r\n（3）然后将其传到`\u002Fetc\u002Fyum.repos.d`目录下，重命名为`CentOS-Base.repo`；\r\n\r\n```shell\r\n# 移动\r\nmv Centos-7.repo \u002Fetc\u002Fyum.repos.d\r\ncd \u002Fetc\u002Fyum.repos.d\r\n# 覆盖旧的CentOS-Base.repo文件\r\nmv Centos-7.repo CentOS-Base.repo\r\n```\r\n\r\n（4）清除&更新缓存\r\n\r\n```shell\r\n# 清理系统中的缓存和临时文件\r\nyum clean all\r\n# 创建和更新yum缓存\r\nyum makecache\r\n```\r\n\r\n## 7.2\tThere are no enabled repos 或 Loaded plugins: fastestmirror\r\n\r\n在安装Centos7后，刚进入系统什么都没做，yum直接报错：\r\n\r\n```shell\r\n[root@localhost ~]# yum install -y yum-utils\r\nLoaded plugins: fastestmirror\r\nThere are no enabled repos.\r\n Run \"yum repolist all\" to see the repos you have.\r\n To enable Red Hat Subscription Management repositories:\r\n     subscription-manager repos --enable \u003Crepo>\r\n To enable custom repositories:\r\n     yum-config-manager --enable \u003Crepo>\r\n```\r\n\r\n按照`7.1 `章节步骤处理即可。\n",{"_path":196,"slug":197,"title":198,"description":199,"excerpt":199,"date":200,"tags":201,"type":15,"cover":202,"content":203},"\u002Fknowledge\u002Felk日志收集框架","elk日志收集框架","ELK日志收集框架","ELK日志收集框架 - **Logstash**：用于收集并处理日志，将日志信息存储到Elasticsearch里面 - **Elasticsearch**：用于存储收集到的日志信息 - **Kibana**：通过Web端的可视化界面来查看日志（数据可视化） Logstash 是免费且开放的服务器端数据处理管道，能够从","2025-02-21",[103,106,63],"\u002Fknowledge-assets\u002Felk日志收集框架\u002Felk-3.png","# ELK日志收集框架\r\n\r\n- **Logstash**：用于收集并处理日志，将日志信息存储到Elasticsearch里面\r\n\r\n- **Elasticsearch**：用于存储收集到的日志信息\r\n\r\n- **Kibana**：通过Web端的可视化界面来查看日志（数据可视化）\r\n\r\n\r\n\r\nLogstash 是免费且开放的服务器端数据处理管道，能够从多个来源采集数据，转换数据，然后将数据发送到您最喜欢的存储库中。\r\n\r\n[ELK版本兼容](https:\u002F\u002Fwww.elastic.co\u002Fcn\u002Fsupport\u002Fmatrix#matrix_compatibility)：https:\u002F\u002Fwww.elastic.co\u002Fcn\u002Fsupport\u002Fmatrix#matrix_compatibility\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Felk日志收集框架\u002Felk-3.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n# 1\t架构设计\r\n\r\n## 1.1\t架构1\r\n\r\n微服务跟logstash部署在同一台服务器。\r\n\r\n优点：性能高；缺点：占用资源高（logstash非常耗资源）\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Felk日志收集框架\u002Felk-1.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n## 1.2\t架构2\r\n\r\nlogstash独立部署，微服务节点通过TCP向logstash发送日志。\r\n\r\n优点：节省资源；缺点：性能受限于网络。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Felk日志收集框架\u002Felk-2.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n# 2\t环境搭建\r\n\r\n## 2.1\t安装Elasticsearch\r\n\r\n```shell\r\n# 运行es\r\ndocker run --name es -e 'discovery.type=single-node' -p 9200:9200 -d elasticsearch:8.4.0\r\n\r\n# 关闭密码认证\r\n# 1 修改elasticsearch.yml文件，关闭安全认证；\r\n# 2 复制文件到es容器中，并重启容器\r\ndocker cp elasticsearch.yml  es:\u002Fusr\u002Fshare\u002Felasticsearch\u002Fconfig\r\ndocker restart es\r\n```\r\n\r\nelasticsearch.yml配置，关闭安全认证。\r\n\r\n```yml\r\ncluster.name: \"docker-cluster\"\r\nnetwork.host: 0.0.0.0\r\n\r\n# Enable security features\r\nxpack.security.enabled: false\r\n\r\nxpack.security.enrollment.enabled: false\r\n\r\n# Enable encryption for HTTP API client connections, such as Kibana, Logstash, and Agents\r\nxpack.security.http.ssl:\r\n  enabled: false\r\n  keystore.path: certs\u002Fhttp.p12\r\n\r\n# Enable encryption and mutual authentication between cluster nodes\r\nxpack.security.transport.ssl:\r\n  enabled: false\r\n  verification_mode: certificate\r\n  keystore.path: certs\u002Ftransport.p12\r\n  truststore.path: certs\u002Ftransport.p12\r\n```\r\n\r\n\r\n\r\n## 2.2\t安装Kibana\r\n\r\n```shell\r\ndocker run --name kibana -p 5601:5601 -d kibana:8.4.0\r\n```\r\n\r\n打开浏览器，访问：http:\u002F\u002Flocalhost:5601\r\n\r\n配置es连接信息即可。\r\n\r\n\r\n\r\n## 2.3\t安装Logstash\r\n\r\n编辑logstash.conf配置文件内容如下：\r\n\r\n```shell\r\ninput {\r\n    tcp {\r\n        mode => \"server\"\r\n        host => \"0.0.0.0\"\r\n        port => 4567\r\n        codec => json{\r\n            charset => \"UTF-8\"\r\n        }\r\n    }\r\n}\r\n\r\noutput {\r\n    elasticsearch  {\r\n        hosts => \"http:\u002F\u002F192.168.3.72:9200\"\r\n        index =>  \"%{[appName]}-%{+YYYY.MM.dd}\"\r\n    }\r\n}\r\n```\r\n\r\n编辑logstash.yml内容如下：\r\n\r\n```shell\r\nhttp.host: \"0.0.0.0\"\r\nxpack.monitoring.elasticsearch.hosts: [ \"http:\u002F\u002F192.168.3.72:9200\" ]\r\n```\r\n\r\n创建logstash容器：\r\n\r\n```shell\r\ndocker run --name logstash \\\r\n-v \u002Froot\u002Flogstash\u002Flogstash.conf:\u002Fusr\u002Fshare\u002Flogstash\u002Fpipeline\u002Flogstash.conf \\\r\n-v \u002Froot\u002Flogstash\u002Flogstash.yml:\u002Fusr\u002Fshare\u002Flogstash\u002Fconfig\u002Flogstash.yml \\\r\n-p 4567:4567 -d logstash:7.17.18\r\n```\r\n\r\n\r\n\r\n# 3\tspringboot项目集成\r\n\r\n## 3.1\t添加依赖\r\n\r\n```xml\r\n\t\t\u003Cdependency>\r\n            \u003CgroupId>net.logstash.logback\u003C\u002FgroupId>\r\n            \u003CartifactId>logstash-logback-encoder\u003C\u002FartifactId>\r\n            \u003Cversion>7.2\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n```\r\n\r\n\r\n\r\n## 3.2\t指定logstash的连接信息\r\n\r\n本demo项目使用的是sl4f + logback日志框架，因此在日志配置文件logback.xml中，添加logstash的连接信息如下，如果使用其他日志框架，请在对应的xml配置文件中添加即可。\r\n\r\n```xml\r\n\u003C?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n\u003Cconfiguration debug=\"false\">\r\n\r\n    \u003CspringProperty scope=\"context\" name=\"appName\" source=\"spring.application.name\"\u002F>\r\n\r\n    \u003C!-- 控制台输出 -->\r\n    \u003Cappender name=\"console\" class=\"ch.qos.logback.core.ConsoleAppender\">\r\n        \u003Cencoder>\r\n            \u003Cpattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n\u003C\u002Fpattern>\r\n            \u003Ccharset>UTF-8\u003C\u002Fcharset>\r\n        \u003C\u002Fencoder>\r\n    \u003C\u002Fappender>\r\n\r\n\r\n    \u003C!--LOGSTASH 的日志输出格式 -->\r\n    \u003Cappender name = \"LOGSTASH\" class =\"net.logstash.logback.appender.LogstashAccessTcpSocketAppender\">\r\n        \u003C!-- LOGSTASH 服务ip和监听的端口号 -->\r\n        \u003Cdestination>192.168.3.72:4567\u003C\u002Fdestination>\r\n        \u003Cencoder charset =\"UTF-8\" class =\"net.logstash.logback.encoder.LogstashEncoder\">\r\n            \u003CcustomFields>\r\n                {\r\n                \"appName\": \"${appName}\",\r\n                \"pid\": \"-\"\r\n                }\r\n            \u003C\u002FcustomFields>\r\n        \u003C\u002Fencoder>\r\n    \u003C\u002Fappender>\r\n\r\n    \u003Croot level=\"info\">\r\n        \u003Cappender-ref ref=\"console\"\u002F>\r\n        \u003Cappender-ref ref=\"LOGSTASH\"\u002F>\r\n    \u003C\u002Froot>\r\n\u003C\u002Fconfiguration>\r\n```\r\n\r\n\r\n\r\n## 3.3\t启动类\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Felk日志收集框架\u002Fspringboot-1.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n# 4\tkibana 界面配置\r\n\r\n（1）进入kibana首页, http:\u002F\u002Flocalhost:5601，展开首页左侧工具栏，点击【Analytics】。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Felk日志收集框架\u002Fkibana-2.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n（2）点击【Discover】\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Felk日志收集框架\u002Fkibana-3.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n（3）查看数据视图，点击【Create a data view】创建数据视图。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Felk日志收集框架\u002Fkibana-4.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n（4）创建数据视图。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Felk日志收集框架\u002Fkibana-5.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n右上角检测出的索引名称，其实就是我们springboot的应用名称。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Felk日志收集框架\u002Fkibana-6.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n# 5\tkibana 日志报表\r\n\r\n（1）大屏显示日志，可以根据多条件筛选日志信息。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Felk日志收集框架\u002Fkibana-7.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n（2）通过调用es api查看日志。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Felk日志收集框架\u002Fkibana-1.png\" style=\"zoom:80%;\" \u002F>\n",{"_path":205,"slug":206,"title":207,"description":208,"excerpt":208,"date":209,"tags":210,"type":15,"cover":213,"content":214},"\u002Fknowledge\u002Fkubesphere容器平台","kubesphere容器平台","1\t简介","KubeSphere容器平台 1 简介 ​ 官网 ：https:\u002F\u002Fstaging.kubesphere.com.cn\u002F ​ KubeSphere 是基于 Kubernetes 内核的**分布式**、**多租户**商用云原生操作系统。在开源能力的基础上，在多云集群管理、微服务治理、应用管理等多个核心业务场景进行功能延伸","2024-11-25",[103,124,211,63,212],"Kubernetes","KubeSphere","\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fmetrics-server.png","KubeSphere容器平台\r\n\r\n# 1\t简介\r\n\r\n​\t[官网](https:\u002F\u002Fstaging.kubesphere.com.cn\u002F) ：https:\u002F\u002Fstaging.kubesphere.com.cn\u002F\r\n\r\n​\tKubeSphere 是基于 Kubernetes 内核的**分布式**、**多租户**商用云原生操作系统。在开源能力的基础上，在多云集群管理、微服务治理、应用管理等多个核心业务场景进行功能延伸。KubeSphere 集成了众多企业级功能，如多租户管理，多集群管理，DevOps，GitOps，服务网格，微服务，可观测（包括监控、告警、日志、审计、事件、通知等），应用商店，边缘计算，网络与存储管理等。\r\n\r\n\r\n\r\n# 2\tKubeSphere 集群搭建\r\n\r\n​\t准备三台4核8G的虚拟机(内存至少8G以上)，操作系统选择用centos 7以上版本。\r\n\r\n| 主机         | 说明       |\r\n| ------------ | ---------- |\r\n| 192.168.3.71 | k8s-master |\r\n| 192.168.3.72 | k8s-node1  |\r\n| 192.168.3.73 | k8s-node2  |\r\n\r\n\r\n\r\n## 2.1\t安装Docker\r\n\r\n1）配置yum源\r\n\r\n```shell\r\nsudo yum install -y yum-utils\r\nsudo yum-config-manager \\\r\n--add-repo \\\r\nhttp:\u002F\u002Fmirrors.aliyun.com\u002Fdocker-ce\u002Flinux\u002Fcentos\u002Fdocker-ce.repo\r\n```\r\n\r\n> 注意：\r\n>\r\n> ```shell\r\n> # 使用 yum install -y xxx 或者 yum makecache时，如果报错 Could not resolve host: mirrorlist.centos.org\r\n> # 1.下载CentOS 7的对应的repo文件\r\n> # 直接在浏览器通过http:\u002F\u002Fmirrors.aliyun.com\u002Frepo\u002FCentos-7.repo 下载Centos-7.repo，然后将其传到\u002Fetc\u002Fyum.repos.d目录下，重命名为CentOS-Base.repo\r\n> mv Centos-7.repo \u002Fetc\u002Fyum.repos.d\r\n> cd \u002Fetc\u002Fyum.repos.d\r\n> mv Centos-7.repo CentOS-Base.repo\r\n> \r\n> # 2.更新镜像源\r\n> yum clean all\r\n> yum makecache\r\n> yum -y update\r\n> ```\r\n\r\n（2）安装docker\r\n\r\n```shell\r\nyum install -y docker-ce-20.10.7 docker-ce-cli-20.10.7  containerd.io-1.4.6\r\n```\r\n\r\n（3）启动docker\r\n\r\n```shell\r\n# 启动Docker服务\r\nsystemctl start docker\r\n# 设置Docker服务开机自启\r\nsystemctl enable docker\r\n\r\n# 或一步到位，设置开启自启，并启动docker\r\nsystemctl enable docker --now\r\n```\r\n\r\n（3）配置加速及cgroup\r\n\r\nkubelet的cgroup和docker的不一致，“kubelet cgroup驱动为systemd，而docker的为“cgroupfs”，因此**修改docker的cgroup为systemd**，否则kubelet无法启动。\r\n\r\n```shell\r\n# 创建目录\r\nmkdir -p \u002Fetc\u002Fdocker\r\n# 配置加速器\r\ntee \u002Fetc\u002Fdocker\u002Fdaemon.json \u003C\u003C-'EOF'\r\n{\r\n  \"registry-mirrors\": [\"https:\u002F\u002Fjsj9yxoq.mirror.aliyuncs.com\"],\r\n  \"exec-opts\": [\"native.cgroupdriver=systemd\"],\r\n  \"log-driver\": \"json-file\",\r\n  \"log-opts\": {\r\n    \"max-size\": \"100m\"\r\n  },\r\n  \"storage-driver\": \"overlay2\"\r\n}\r\nEOF\r\n\r\n# 重启\r\nsystemctl daemon-reload\r\nsystemctl restart docker\r\n```\r\n\r\n\r\n\r\n如需要，可配置多个镜像加速：\r\n\r\n```json\r\n{\r\n    \"registry-mirrors\": [\r\n    \"https:\u002F\u002Fjsj9yxoq.mirror.aliyuncs.com\",\r\n    \"https:\u002F\u002Fdocker.registry.cyou\",\r\n    \"https:\u002F\u002Fdocker-cf.registry.cyou\",\r\n    \"https:\u002F\u002Fdockercf.jsdelivr.fyi\",\r\n    \"https:\u002F\u002Fdocker.jsdelivr.fyi\",\r\n    \"https:\u002F\u002Fdockertest.jsdelivr.fyi\",\r\n    \"https:\u002F\u002Fmirror.aliyuncs.com\",\r\n    \"https:\u002F\u002Fdockerproxy.com\",\r\n    \"https:\u002F\u002Fmirror.baidubce.com\",\r\n    \"https:\u002F\u002Fdocker.m.daocloud.io\",\r\n    \"https:\u002F\u002Fdocker.nju.edu.cn\",\r\n    \"https:\u002F\u002Fdocker.mirrors.sjtug.sjtu.edu.cn\",\r\n    \"https:\u002F\u002Fdocker.mirrors.ustc.edu.cn\",\r\n    \"https:\u002F\u002Fmirror.iscas.ac.cn\",\r\n    \"https:\u002F\u002Fdocker.rainbond.cc\"],\r\n  \"exec-opts\": [\"native.cgroupdriver=systemd\"],\r\n  \"log-driver\": \"json-file\",\r\n  \"log-opts\": {\r\n    \"max-size\": \"100m\"\r\n  },\r\n  \"storage-driver\": \"overlay2\"\r\n}\r\n```\r\n\r\n\r\n\r\n## 2.2\t安装Kubernetes \r\n\r\n### 2.2.1\t基础环境\r\n\r\n在所有集群主机上执行以下操作：\r\n\r\n（1）各个机器设置自己的主机名\r\n\r\n```shell\r\nhostnamectl set-hostname k8s-master\r\nhostnamectl set-hostname k8s-node1\r\nhostnamectl set-hostname k8s-node2\r\n```\r\n\r\n（2）关闭防火墙\r\n\r\n```shell\r\n# 停止firewalld服务\r\nsystemctl stop firewalld\r\n# 禁用firewalld服务，使其不会开机自启\r\nsystemctl disable firewalld\r\n```\r\n\r\n（3）将 SELinux 设置为 permissive 模式（相当于将其禁用）\r\n\r\n```shell\r\nsetenforce 0\r\nsed -i 's\u002F^SELINUX=enforcing$\u002FSELINUX=permissive\u002F' \u002Fetc\u002Fselinux\u002Fconfig\r\n```\r\n\r\n（4）关闭交互区\r\n\r\n```shell\r\n# 关闭swap\r\nswapoff -a  \r\nsed -ri 's\u002F.*swap.*\u002F#&\u002F' \u002Fetc\u002Ffstab\r\n\r\nsystemctl reboot  #重启生效\r\n```\r\n\r\n（5）添加hosts\r\n\r\n```shell\r\n#添加hosts，执行如下命令，ip需要修改成自己机器的ip\r\ncat >> \u002Fetc\u002Fhosts \u003C\u003C EOF\r\n192.168.3.71 k8s-master\r\n192.168.3.72 k8s-node1\r\n192.168.3.73 k8s-node2\r\nEOF\r\n```\r\n\r\n（6）允许 iptables 检查桥接流量\r\n\r\n```shell\r\ncat \u003C\u003CEOF | tee \u002Fetc\u002Fmodules-load.d\u002Fk8s.conf\r\nbr_netfilter\r\nEOF\r\n\r\ncat \u003C\u003CEOF | tee \u002Fetc\u002Fsysctl.d\u002Fk8s.conf\r\nnet.bridge.bridge-nf-call-ip6tables = 1\r\nnet.bridge.bridge-nf-call-iptables = 1\r\nEOF\r\n\r\nsysctl --system\r\n```\r\n\r\n（7）设置时间同步\r\n\r\n```shell\r\n# 安装ntpdate\r\nyum install ntpdate -y\r\n# 同步时间\r\nntpdate time.windows.com\r\n```\r\n\r\n### 2.2.2\t安装kubelet、kubeadm、kubectl\r\n\r\n在所有集群主机上执行以下操作：\r\n\r\n```shell\r\n# 配置k8s的yum源地址\r\ncat \u003C\u003CEOF | tee \u002Fetc\u002Fyum.repos.d\u002Fkubernetes.repo\r\n[kubernetes]\r\nname=Kubernetes\r\nbaseurl=http:\u002F\u002Fmirrors.aliyun.com\u002Fkubernetes\u002Fyum\u002Frepos\u002Fkubernetes-el7-x86_64\r\nenabled=1\r\ngpgcheck=0\r\nrepo_gpgcheck=0\r\ngpgkey=http:\u002F\u002Fmirrors.aliyun.com\u002Fkubernetes\u002Fyum\u002Fdoc\u002Fyum-key.gpg\r\n   http:\u002F\u002Fmirrors.aliyun.com\u002Fkubernetes\u002Fyum\u002Fdoc\u002Frpm-package-key.gpg\r\nexclude=kubelet kubeadm kubectl\r\nEOF\r\n\r\n# 安装kubelet、kubeadm、kubectl\r\nyum install -y kubelet-1.20.9 kubeadm-1.20.9 kubectl-1.20.9 --disableexcludes=kubernetes\r\n\r\n# --disableexcludes=kubernetes  禁掉除了这个之外的别的仓库 \r\n\r\n# 启动kubelet，并设置开机自启\r\nsystemctl enable --now kubelet\r\n```\r\n\r\n\r\n\r\n### 2.2.3\t使用kubeadm引导集群\r\n\r\n在所有集群主机上执行以下操作：\r\n\r\n```shell\r\n# 提前下载各个机器需要的镜像，后续安装pod时不用再下载\r\ntee .\u002Fimages.sh \u003C\u003C-'EOF'\r\n#!\u002Fbin\u002Fbash\r\nimages=(\r\nkube-apiserver:v1.20.9\r\nkube-proxy:v1.20.9\r\nkube-controller-manager:v1.20.9\r\nkube-scheduler:v1.20.9\r\ncoredns:1.7.0\r\netcd:3.4.13-0\r\npause:3.2\r\n)\r\nfor imageName in ${images[@]} ; do\r\ndocker pull registry.cn-guangzhou.aliyuncs.com\u002Fmhui\u002F$imageName\r\ndone\r\nEOF\r\n\r\n# 执行镜像下载脚本\r\nchmod +x .\u002Fimages.sh && .\u002Fimages.sh\r\n```\r\n\r\n\r\n\r\n### 2.2.4\t初始化主节点\r\n\r\n（1）在master节点执行\r\n\r\n```shell\r\n#主节点初始化\r\nkubeadm init \\\r\n--apiserver-advertise-address=192.168.3.71 \\\r\n--control-plane-endpoint=k8s-master \\\r\n--image-repository registry.cn-guangzhou.aliyuncs.com\u002Fmhui \\\r\n--kubernetes-version v1.20.9 \\\r\n--service-cidr=10.96.0.0\u002F16 \\\r\n--pod-network-cidr=10.244.0.0\u002F16\r\n\r\n# 这3个ip地址不能配在同一网段，所有网络范围不重叠\r\n# --apiserver-advertise-address: 指定的当前master节点ip\r\n# --service-cidr：\r\n# --pod-network-cidr：配置pod ip地址\r\n```\r\n\r\n初始化成功后，会在控制台上输出如下内容：\r\n\r\n```shell\r\n################################################################\r\nYour Kubernetes control-plane has initialized successfully!\r\n\r\nTo start using your cluster, you need to run the following as a regular user:\r\n\r\n  mkdir -p $HOME\u002F.kube\r\n  sudo cp -i \u002Fetc\u002Fkubernetes\u002Fadmin.conf $HOME\u002F.kube\u002Fconfig\r\n  sudo chown $(id -u):$(id -g) $HOME\u002F.kube\u002Fconfig\r\n\r\nAlternatively, if you are the root user, you can run:\r\n\r\n  export KUBECONFIG=\u002Fetc\u002Fkubernetes\u002Fadmin.conf\r\n\r\nYou should now deploy a pod network to the cluster.\r\nRun \"kubectl apply -f [podnetwork].yaml\" with one of the options listed at:\r\n  https:\u002F\u002Fkubernetes.io\u002Fdocs\u002Fconcepts\u002Fcluster-administration\u002Faddons\u002F\r\n\r\nYou can now join any number of control-plane nodes by copying certificate authorities\r\nand service account keys on each node and then running the following as root:\r\n\r\n  kubeadm join k8s-master:6443 --token tgy6n0.xmbgqwek8kjhwx6b \\\r\n    --discovery-token-ca-cert-hash sha256:b8d1bd430967528118d74af2a88d20461f39015e3b0df8f2fde620c31d3c9bc3 \\\r\n    --control-plane\r\n\r\nThen you can join any number of worker nodes by running the following on each as root:\r\n\r\nkubeadm join k8s-master:6443 --token tgy6n0.xmbgqwek8kjhwx6b \\\r\n    --discovery-token-ca-cert-hash sha256:b8d1bd430967528118d74af2a88d20461f39015e3b0df8f2fde620c31d3c9bc3\r\n\r\n################################################################\r\n```\r\n\r\n\r\n\r\n（2）配置环境变量\r\n\r\n```shell\r\n# 检查有没有环境变量\r\necho $KUBECONFIG\r\n# 如果当前用户是root，则配置\r\nexport KUBECONFIG=\u002Fetc\u002Fkubernetes\u002Fadmin.conf  # 重启后会失效，得重新配置\r\n# 如果你想让这个变量永久生效，可以将上述命令添加到 ~\u002F.bash_profile 文件的末尾，然后执行source ~\u002F.bash_profile 来应用更改\r\n\r\n# 其他登录用户，不是root用户，则执行执行，控制台输出的内容：\r\nmkdir -p $HOME\u002F.kube\r\nsudo cp -i \u002Fetc\u002Fkubernetes\u002Fadmin.conf $HOME\u002F.kube\u002Fconfig\r\nsudo chown $(id -u):$(id -g) $HOME\u002F.kube\u002Fconfig\r\n```\r\n\r\n\r\n\r\n（3）安装网络插件\r\n\r\n```shell\r\n# master节点 下载网络插件配置\r\ncurl https:\u002F\u002Fdocs.projectcalico.org\u002Fv3.20\u002Fmanifests\u002Fcalico.yaml -O\r\n\r\n# 个别镜像下载太慢或无法下载，\r\n# 将calico.yaml中所有镜像地址前缀修改为：registry.cn-guangzhou.aliyuncs.com\u002Fmhui\r\n\r\n# master节点 安装网络\r\nkubectl apply -f calico.yaml\r\n\r\n# 如果虚拟机配置多网卡，出现下面的错误：calico\u002Fnode is not ready: BIRD is not ready: BGP not established with xxx\r\n# 修改calico.yaml的内容,指定网卡，添加下面两行\r\n# 配置网卡，在这calico.yaml文件下，添加网卡IP_AUTODETECTION_METHOD信息\r\n            # Auto-detect the BGP IP address.\r\n            - name: IP\r\n              value: \"autodetect\"\r\n            ##########################\r\n            # 添加网卡\r\n            - name: IP_AUTODETECTION_METHOD\r\n              value: \"interface=ens33\"\r\n            ##########################\r\n            # Enable IPIP\r\n\r\n# 查看运行信息\r\nkubectl get pods -A\r\n# 查看安装过程信息\r\nkubectl describe pod pod名称 -n kube-system\r\n\r\n# 如果创建失败，删除pod，再创建\r\nkubectl delete -f calico.yaml\r\n```\r\n\r\n\r\n\r\n（4）查看node节点状态\r\n\r\n```shell\r\nkubectl get nodes\r\n```\r\n\r\n\r\n\r\n### 2.2.5\t加入node节点\r\n\r\n在集群node节点上执行以下操作：\r\n\r\n```shell\r\n# 在node 节点执行\r\nkubeadm join k8s-master:6443 --token grzsle.0up1mbojuva9zv37 \\\r\n    --discovery-token-ca-cert-hash sha256:a32bbb2e9f7534e1fd9fe8818db52551da1f43fddf21357413e378d3ced6313f\r\n\r\n# 如果token过期，可以通过下面的命令重新生成令牌\r\nkubeadm token create --print-join-command\r\n\r\n# node节点执行kubectl命令kubectl get nodes出现下面的错误：\r\n# The connection to the server localhost:8080 was refused - did you specify the right host or port?\r\n# 解决方案： 在node节点配置KUBECONFIG环境变量即可\r\necho \"export KUBECONFIG=\u002Fetc\u002Fkubernetes\u002Fkubelet.conf\" >> \u002Fetc\u002Fprofile\r\nsource \u002Fetc\u002Fprofile\r\n```\r\n\r\n\r\n\r\n### 2.2.6\t查看kubelet信息\r\n\r\n```shell\r\n# 启动 kubelet\r\nsystemctl start kubelet\r\n# 重启 kubelet\r\nsystemctl restart kubelet\r\n# 停止 kubelet\r\nsystemctl stop kubelet\r\n# 查看 kubelet状态\r\nsystemctl status kubelet\r\n\r\n# 查看 kubelet日志\r\njournalctl -f -u kubelet\r\n\r\n```\r\n\r\n\r\n\r\n## 2.3\t安装KubeSphere前置环境\r\n\r\n### 2.3.1\tNFS文件系统\r\n\r\n#### 2.3.1.1\t安装NFS\r\n\r\n```shell\r\n# k8s集群在每个机器下安装nfs\r\nyum install -y nfs-utils\r\n\r\n# 在k8s集群节点中选择一个节点作为NFS master节点\r\n# 在master 执行以下命令，暴露nfs集群共享目录\r\necho \"\u002Fnfs\u002Fdata\u002F *(insecure,rw,sync,no_root_squash)\" > \u002Fetc\u002Fexports\r\n\r\n# 执行以下命令，启动 nfs 服务;创建共享目录\r\nmkdir -p \u002Fnfs\u002Fdata\r\n\r\n# 在master执行\r\nsystemctl enable rpcbind\r\nsystemctl enable nfs-server\r\nsystemctl start rpcbind\r\nsystemctl start nfs-server\r\n\r\n# 使配置生效\r\nexportfs -r\r\n\r\n#检查配置是否生效\r\nexportfs\r\n```\r\n\r\n\r\n\r\n#### 2.3.1.2\t配置nfs-client（选做）\r\n\r\n```shell\r\n# 查看 nfs master 暴露的共享目录\r\nshowmount -e 192.168.3.71\r\n\r\nmkdir -p \u002Fnfs\u002Fdata\r\n\r\nmount -t nfs 192.168.3.71:\u002Fnfs\u002Fdata \u002Fnfs\u002Fdata\r\n```\r\n\r\n\r\n\r\n#### 2.3.1.3\t配置pv动态存储卷\r\n\r\n```yaml\r\n## 创建了一个存储类\r\napiVersion: storage.k8s.io\u002Fv1\r\nkind: StorageClass\r\nmetadata:\r\n  name: nfs-storage\r\n  annotations:\r\n    storageclass.kubernetes.io\u002Fis-default-class: \"true\"\r\nprovisioner: k8s-sigs.io\u002Fnfs-subdir-external-provisioner\r\nparameters:\r\n  archiveOnDelete: \"true\"  ## 删除pv的时候，pv的内容是否要备份\r\n\r\n---\r\napiVersion: apps\u002Fv1\r\nkind: Deployment\r\nmetadata:\r\n  name: nfs-client-provisioner\r\n  labels:\r\n    app: nfs-client-provisioner\r\n  # replace with namespace where provisioner is deployed\r\n  namespace: default\r\nspec:\r\n  replicas: 1\r\n  strategy:\r\n    type: Recreate\r\n  selector:\r\n    matchLabels:\r\n      app: nfs-client-provisioner\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: nfs-client-provisioner\r\n    spec:\r\n      serviceAccountName: nfs-client-provisioner\r\n      containers:\r\n        - name: nfs-client-provisioner\r\n          image: registry.cn-guangzhou.aliyuncs.com\u002Fmhui\u002Fnfs-subdir-external-provisioner:v4.0.2\r\n          # resources:\r\n          #    limits:\r\n          #      cpu: 10m\r\n          #    requests:\r\n          #      cpu: 10m\r\n          volumeMounts:\r\n            - name: nfs-client-root\r\n              mountPath: \u002Fpersistentvolumes\r\n          env:\r\n            - name: PROVISIONER_NAME\r\n              value: k8s-sigs.io\u002Fnfs-subdir-external-provisioner\r\n            - name: NFS_SERVER\r\n              value: 192.168.3.71 ## 指定自己nfs服务器地址\r\n            - name: NFS_PATH  \r\n              value: \u002Fnfs\u002Fdata  ## nfs服务器共享的目录\r\n      volumes:\r\n        - name: nfs-client-root\r\n          nfs:\r\n            server: 192.168.3.71\r\n            path: \u002Fnfs\u002Fdata\r\n---\r\napiVersion: v1\r\nkind: ServiceAccount\r\nmetadata:\r\n  name: nfs-client-provisioner\r\n  # replace with namespace where provisioner is deployed\r\n  namespace: default\r\n---\r\nkind: ClusterRole\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nmetadata:\r\n  name: nfs-client-provisioner-runner\r\nrules:\r\n  - apiGroups: [\"\"]\r\n    resources: [\"nodes\"]\r\n    verbs: [\"get\", \"list\", \"watch\"]\r\n  - apiGroups: [\"\"]\r\n    resources: [\"persistentvolumes\"]\r\n    verbs: [\"get\", \"list\", \"watch\", \"create\", \"delete\"]\r\n  - apiGroups: [\"\"]\r\n    resources: [\"persistentvolumeclaims\"]\r\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\r\n  - apiGroups: [\"storage.k8s.io\"]\r\n    resources: [\"storageclasses\"]\r\n    verbs: [\"get\", \"list\", \"watch\"]\r\n  - apiGroups: [\"\"]\r\n    resources: [\"events\"]\r\n    verbs: [\"create\", \"update\", \"patch\"]\r\n---\r\nkind: ClusterRoleBinding\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nmetadata:\r\n  name: run-nfs-client-provisioner\r\nsubjects:\r\n  - kind: ServiceAccount\r\n    name: nfs-client-provisioner\r\n    # replace with namespace where provisioner is deployed\r\n    namespace: default\r\nroleRef:\r\n  kind: ClusterRole\r\n  name: nfs-client-provisioner-runner\r\n  apiGroup: rbac.authorization.k8s.io\r\n---\r\nkind: Role\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nmetadata:\r\n  name: leader-locking-nfs-client-provisioner\r\n  # replace with namespace where provisioner is deployed\r\n  namespace: default\r\nrules:\r\n  - apiGroups: [\"\"]\r\n    resources: [\"endpoints\"]\r\n    verbs: [\"get\", \"list\", \"watch\", \"create\", \"update\", \"patch\"]\r\n---\r\nkind: RoleBinding\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nmetadata:\r\n  name: leader-locking-nfs-client-provisioner\r\n  # replace with namespace where provisioner is deployed\r\n  namespace: default\r\nsubjects:\r\n  - kind: ServiceAccount\r\n    name: nfs-client-provisioner\r\n    # replace with namespace where provisioner is deployed\r\n    namespace: default\r\nroleRef:\r\n  kind: Role\r\n  name: leader-locking-nfs-client-provisioner\r\n  apiGroup: rbac.authorization.k8s.io\r\n```\r\n\r\n​\t（1）检查配置是否生效\r\n\r\n```shell\r\nkubectl get sc\r\n```\r\n\r\n\r\n\r\n​\t（2）测试创建pvc时，能否自动创建pv：\r\n\r\n```yaml\r\nkind: PersistentVolumeClaim\r\napiVersion: v1\r\nmetadata:\r\n  name: pvc-test\r\n  annotations: # 指定 storage，自动创建pv\r\n    volume.beta.kubernetes.io\u002Fstorage-class: \"nfs-storage\"\r\nspec:\r\n  accessModes:\r\n    - ReadWriteMany\r\n  resources:\r\n    requests:\r\n      storage: 1Mi\r\n```\r\n\r\n​\t\r\n\r\n```shell\r\n# 创建pvc\r\nkubectl apply -f pvc-test.yaml\r\n\r\n# 查看是否创建pv\r\nkubectl get pvc,pv\r\n```\r\n\r\n\r\n\r\n### 2.3.2\tmetrics-server\r\n\r\n​\t集群监控指标组件，如监控内存、cpu等信息。\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: ServiceAccount\r\nmetadata:\r\n  labels:\r\n    k8s-app: metrics-server\r\n  name: metrics-server\r\n  namespace: kube-system\r\n---\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nkind: ClusterRole\r\nmetadata:\r\n  labels:\r\n    k8s-app: metrics-server\r\n    rbac.authorization.k8s.io\u002Faggregate-to-admin: \"true\"\r\n    rbac.authorization.k8s.io\u002Faggregate-to-edit: \"true\"\r\n    rbac.authorization.k8s.io\u002Faggregate-to-view: \"true\"\r\n  name: system:aggregated-metrics-reader\r\nrules:\r\n- apiGroups:\r\n  - metrics.k8s.io\r\n  resources:\r\n  - pods\r\n  - nodes\r\n  verbs:\r\n  - get\r\n  - list\r\n  - watch\r\n---\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nkind: ClusterRole\r\nmetadata:\r\n  labels:\r\n    k8s-app: metrics-server\r\n  name: system:metrics-server\r\nrules:\r\n- apiGroups:\r\n  - \"\"\r\n  resources:\r\n  - pods\r\n  - nodes\r\n  - nodes\u002Fstats\r\n  - namespaces\r\n  - configmaps\r\n  verbs:\r\n  - get\r\n  - list\r\n  - watch\r\n---\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nkind: RoleBinding\r\nmetadata:\r\n  labels:\r\n    k8s-app: metrics-server\r\n  name: metrics-server-auth-reader\r\n  namespace: kube-system\r\nroleRef:\r\n  apiGroup: rbac.authorization.k8s.io\r\n  kind: Role\r\n  name: extension-apiserver-authentication-reader\r\nsubjects:\r\n- kind: ServiceAccount\r\n  name: metrics-server\r\n  namespace: kube-system\r\n---\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nkind: ClusterRoleBinding\r\nmetadata:\r\n  labels:\r\n    k8s-app: metrics-server\r\n  name: metrics-server:system:auth-delegator\r\nroleRef:\r\n  apiGroup: rbac.authorization.k8s.io\r\n  kind: ClusterRole\r\n  name: system:auth-delegator\r\nsubjects:\r\n- kind: ServiceAccount\r\n  name: metrics-server\r\n  namespace: kube-system\r\n---\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nkind: ClusterRoleBinding\r\nmetadata:\r\n  labels:\r\n    k8s-app: metrics-server\r\n  name: system:metrics-server\r\nroleRef:\r\n  apiGroup: rbac.authorization.k8s.io\r\n  kind: ClusterRole\r\n  name: system:metrics-server\r\nsubjects:\r\n- kind: ServiceAccount\r\n  name: metrics-server\r\n  namespace: kube-system\r\n---\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  labels:\r\n    k8s-app: metrics-server\r\n  name: metrics-server\r\n  namespace: kube-system\r\nspec:\r\n  ports:\r\n  - name: https\r\n    port: 443\r\n    protocol: TCP\r\n    targetPort: https\r\n  selector:\r\n    k8s-app: metrics-server\r\n---\r\napiVersion: apps\u002Fv1\r\nkind: Deployment\r\nmetadata:\r\n  labels:\r\n    k8s-app: metrics-server\r\n  name: metrics-server\r\n  namespace: kube-system\r\nspec:\r\n  selector:\r\n    matchLabels:\r\n      k8s-app: metrics-server\r\n  strategy:\r\n    rollingUpdate:\r\n      maxUnavailable: 0\r\n  template:\r\n    metadata:\r\n      labels:\r\n        k8s-app: metrics-server\r\n    spec:\r\n      containers:\r\n      - args:\r\n        - --cert-dir=\u002Ftmp\r\n        - --kubelet-insecure-tls\r\n        - --secure-port=4443\r\n        - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname\r\n        - --kubelet-use-node-status-port\r\n        image: registry.cn-guangzhou.aliyuncs.com\u002Fmhui\u002Fmetrics-server:v0.4.3\r\n        imagePullPolicy: IfNotPresent\r\n        livenessProbe:\r\n          failureThreshold: 3\r\n          httpGet:\r\n            path: \u002Flivez\r\n            port: https\r\n            scheme: HTTPS\r\n          periodSeconds: 10\r\n        name: metrics-server\r\n        ports:\r\n        - containerPort: 4443\r\n          name: https\r\n          protocol: TCP\r\n        readinessProbe:\r\n          failureThreshold: 3\r\n          httpGet:\r\n            path: \u002Freadyz\r\n            port: https\r\n            scheme: HTTPS\r\n          periodSeconds: 10\r\n        securityContext:\r\n          readOnlyRootFilesystem: true\r\n          runAsNonRoot: true\r\n          runAsUser: 1000\r\n        volumeMounts:\r\n        - mountPath: \u002Ftmp\r\n          name: tmp-dir\r\n      nodeSelector:\r\n        kubernetes.io\u002Fos: linux\r\n      priorityClassName: system-cluster-critical\r\n      serviceAccountName: metrics-server\r\n      volumes:\r\n      - emptyDir: {}\r\n        name: tmp-dir\r\n---\r\napiVersion: apiregistration.k8s.io\u002Fv1\r\nkind: APIService\r\nmetadata:\r\n  labels:\r\n    k8s-app: metrics-server\r\n  name: v1beta1.metrics.k8s.io\r\nspec:\r\n  group: metrics.k8s.io\r\n  groupPriorityMinimum: 100\r\n  insecureSkipTLSVerify: true\r\n  service:\r\n    name: metrics-server\r\n    namespace: kube-system\r\n  version: v1beta1\r\n  versionPriority: 100\r\n```\r\n\r\n\r\n\r\n​\t查看集群各节点内存占用信息：\r\n\r\n```shell\r\nkubectl top nodes\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fmetrics-server.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n## 2.4\tKubeSphere平台安装\r\n\r\n[KubeSphere官网](https:\u002F\u002Fkubesphere.com.cn\u002F)：https:\u002F\u002Fkubesphere.com.cn\u002F\r\n\r\n### 2.4.1\tk8s上安装KubeSphere\r\n\r\n#### 2.4.1.1\t下载核心文件\r\n\r\n```shell\r\nwget https:\u002F\u002Fgithub.com\u002Fkubesphere\u002Fks-installer\u002Freleases\u002Fdownload\u002Fv3.1.1\u002Fkubesphere-installer.yaml\r\n\r\nwget https:\u002F\u002Fgithub.com\u002Fkubesphere\u002Fks-installer\u002Freleases\u002Fdownload\u002Fv3.1.1\u002Fcluster-configuration.yaml\r\n```\r\n\r\n\r\n\r\n`kubesphere-installer.yaml` 文件内容：\r\n\r\n```yaml\r\n---\r\napiVersion: apiextensions.k8s.io\u002Fv1beta1\r\nkind: CustomResourceDefinition\r\nmetadata:\r\n  name: clusterconfigurations.installer.kubesphere.io\r\nspec:\r\n  group: installer.kubesphere.io\r\n  versions:\r\n  - name: v1alpha1\r\n    served: true\r\n    storage: true\r\n  scope: Namespaced\r\n  names:\r\n    plural: clusterconfigurations\r\n    singular: clusterconfiguration\r\n    kind: ClusterConfiguration\r\n    shortNames:\r\n    - cc\r\n\r\n---\r\napiVersion: v1\r\nkind: Namespace\r\nmetadata:\r\n  name: kubesphere-system\r\n\r\n---\r\napiVersion: v1\r\nkind: ServiceAccount\r\nmetadata:\r\n  name: ks-installer\r\n  namespace: kubesphere-system\r\n\r\n---\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nkind: ClusterRole\r\nmetadata:\r\n  name: ks-installer\r\nrules:\r\n- apiGroups:\r\n  - \"\"\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - apps\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - extensions\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - batch\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - rbac.authorization.k8s.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - apiregistration.k8s.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - apiextensions.k8s.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - tenant.kubesphere.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - certificates.k8s.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - devops.kubesphere.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - monitoring.coreos.com\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - logging.kubesphere.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - jaegertracing.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - storage.k8s.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - admissionregistration.k8s.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - policy\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - autoscaling\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - networking.istio.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - config.istio.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - iam.kubesphere.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - notification.kubesphere.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - auditing.kubesphere.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - events.kubesphere.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - core.kubefed.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - installer.kubesphere.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - storage.kubesphere.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - security.istio.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - monitoring.kiali.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - kiali.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - networking.k8s.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - kubeedge.kubesphere.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n- apiGroups:\r\n  - types.kubefed.io\r\n  resources:\r\n  - '*'\r\n  verbs:\r\n  - '*'\r\n\r\n---\r\nkind: ClusterRoleBinding\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nmetadata:\r\n  name: ks-installer\r\nsubjects:\r\n- kind: ServiceAccount\r\n  name: ks-installer\r\n  namespace: kubesphere-system\r\nroleRef:\r\n  kind: ClusterRole\r\n  name: ks-installer\r\n  apiGroup: rbac.authorization.k8s.io\r\n\r\n---\r\napiVersion: apps\u002Fv1\r\nkind: Deployment\r\nmetadata:\r\n  name: ks-installer\r\n  namespace: kubesphere-system\r\n  labels:\r\n    app: ks-install\r\nspec:\r\n  replicas: 1\r\n  selector:\r\n    matchLabels:\r\n      app: ks-install\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: ks-install\r\n    spec:\r\n      serviceAccountName: ks-installer\r\n      containers:\r\n      - name: installer\r\n        image: kubesphere\u002Fks-installer:v3.1.1\r\n        imagePullPolicy: \"Always\"\r\n        resources:\r\n          limits:\r\n            cpu: \"1\"\r\n            memory: 1Gi\r\n          requests:\r\n            cpu: 20m\r\n            memory: 100Mi\r\n        volumeMounts:\r\n        - mountPath: \u002Fetc\u002Flocaltime\r\n          name: host-time\r\n      volumes:\r\n      - hostPath:\r\n          path: \u002Fetc\u002Flocaltime\r\n          type: \"\"\r\n        name: host-time\r\n\r\n```\r\n\r\n\r\n\r\n`cluster-configuration.yaml`文件内容：\r\n\r\n```yaml\r\n---\r\napiVersion: installer.kubesphere.io\u002Fv1alpha1\r\nkind: ClusterConfiguration\r\nmetadata:\r\n  name: ks-installer\r\n  namespace: kubesphere-system\r\n  labels:\r\n    version: v3.1.1\r\nspec:\r\n  persistence:\r\n    storageClass: \"\"        # If there is no default StorageClass in your cluster, you need to specify an existing StorageClass here.\r\n  authentication:\r\n    jwtSecret: \"\"           # Keep the jwtSecret consistent with the Host Cluster. Retrieve the jwtSecret by executing \"kubectl -n kubesphere-system get cm kubesphere-config -o yaml | grep -v \"apiVersion\" | grep jwtSecret\" on the Host Cluster.\r\n  local_registry: \"\"        # Add your private registry address if it is needed.\r\n  etcd:\r\n    monitoring: false       # Enable or disable etcd monitoring dashboard installation. You have to create a Secret for etcd before you enable it.\r\n    endpointIps: localhost  # etcd cluster EndpointIps. It can be a bunch of IPs here.\r\n    port: 2379              # etcd port.\r\n    tlsEnable: true\r\n  common:\r\n    redis:\r\n      enabled: false\r\n    openldap:\r\n      enabled: false\r\n    minioVolumeSize: 20Gi # Minio PVC size.\r\n    openldapVolumeSize: 2Gi   # openldap PVC size.\r\n    redisVolumSize: 2Gi # Redis PVC size.\r\n    monitoring:\r\n      # type: external   # Whether to specify the external prometheus stack, and need to modify the endpoint at the next line.\r\n      endpoint: http:\u002F\u002Fprometheus-operated.kubesphere-monitoring-system.svc:9090 # Prometheus endpoint to get metrics data.\r\n    es:   # Storage backend for logging, events and auditing.\r\n      # elasticsearchMasterReplicas: 1   # The total number of master nodes. Even numbers are not allowed.\r\n      # elasticsearchDataReplicas: 1     # The total number of data nodes.\r\n      elasticsearchMasterVolumeSize: 4Gi   # The volume size of Elasticsearch master nodes.\r\n      elasticsearchDataVolumeSize: 20Gi    # The volume size of Elasticsearch data nodes.\r\n      logMaxAge: 7                     # Log retention time in built-in Elasticsearch. It is 7 days by default.\r\n      elkPrefix: logstash              # The string making up index names. The index name will be formatted as ks-\u003Celk_prefix>-log.\r\n      basicAuth:\r\n        enabled: false\r\n        username: \"\"\r\n        password: \"\"\r\n      externalElasticsearchUrl: \"\"\r\n      externalElasticsearchPort: \"\"\r\n  console:\r\n    enableMultiLogin: true  # Enable or disable simultaneous logins. It allows different users to log in with the same account at the same time.\r\n    port: 30880\r\n  alerting:                # (CPU: 0.1 Core, Memory: 100 MiB) It enables users to customize alerting policies to send messages to receivers in time with different time intervals and alerting levels to choose from.\r\n    enabled: false         # Enable or disable the KubeSphere Alerting System.\r\n    # thanosruler:\r\n    #   replicas: 1\r\n    #   resources: {}\r\n  auditing:                # Provide a security-relevant chronological set of records，recording the sequence of activities happening on the platform, initiated by different tenants.\r\n    enabled: false         # Enable or disable the KubeSphere Auditing Log System. \r\n  devops:                  # (CPU: 0.47 Core, Memory: 8.6 G) Provide an out-of-the-box CI\u002FCD system based on Jenkins, and automated workflow tools including Source-to-Image & Binary-to-Image.\r\n    enabled: false             # Enable or disable the KubeSphere DevOps System.\r\n    jenkinsMemoryLim: 2Gi      # Jenkins memory limit.\r\n    jenkinsMemoryReq: 1500Mi   # Jenkins memory request.\r\n    jenkinsVolumeSize: 8Gi     # Jenkins volume size.\r\n    jenkinsJavaOpts_Xms: 512m  # The following three fields are JVM parameters.\r\n    jenkinsJavaOpts_Xmx: 512m\r\n    jenkinsJavaOpts_MaxRAM: 2g\r\n  events:                  # Provide a graphical web console for Kubernetes Events exporting, filtering and alerting in multi-tenant Kubernetes clusters.\r\n    enabled: false         # Enable or disable the KubeSphere Events System.\r\n    ruler:\r\n      enabled: true\r\n      replicas: 2\r\n  logging:                 # (CPU: 57 m, Memory: 2.76 G) Flexible logging functions are provided for log query, collection and management in a unified console. Additional log collectors can be added, such as Elasticsearch, Kafka and Fluentd.\r\n    enabled: false         # Enable or disable the KubeSphere Logging System.\r\n    logsidecar:\r\n      enabled: true\r\n      replicas: 2\r\n  metrics_server:                    # (CPU: 56 m, Memory: 44.35 MiB) It enables HPA (Horizontal Pod Autoscaler).\r\n    enabled: false                   # Enable or disable metrics-server.\r\n  monitoring:\r\n    storageClass: \"\"                 # If there is an independent StorageClass you need for Prometheus, you can specify it here. The default StorageClass is used by default.\r\n    # prometheusReplicas: 1          # Prometheus replicas are responsible for monitoring different segments of data source and providing high availability.\r\n    prometheusMemoryRequest: 400Mi   # Prometheus request memory.\r\n    prometheusVolumeSize: 20Gi       # Prometheus PVC size.\r\n    # alertmanagerReplicas: 1          # AlertManager Replicas.\r\n  multicluster:\r\n    clusterRole: none  # host | member | none  # You can install a solo cluster, or specify it as the Host or Member Cluster.\r\n  network:\r\n    networkpolicy: # Network policies allow network isolation within the same cluster, which means firewalls can be set up between certain instances (Pods).\r\n      # Make sure that the CNI network plugin used by the cluster supports NetworkPolicy. There are a number of CNI network plugins that support NetworkPolicy, including Calico, Cilium, Kube-router, Romana and Weave Net.\r\n      enabled: false # Enable or disable network policies.\r\n    ippool: # Use Pod IP Pools to manage the Pod network address space. Pods to be created can be assigned IP addresses from a Pod IP Pool.\r\n      type: none # Specify \"calico\" for this field if Calico is used as your CNI plugin. \"none\" means that Pod IP Pools are disabled.\r\n    topology: # Use Service Topology to view Service-to-Service communication based on Weave Scope.\r\n      type: none # Specify \"weave-scope\" for this field to enable Service Topology. \"none\" means that Service Topology is disabled.\r\n  openpitrix: # An App Store that is accessible to all platform tenants. You can use it to manage apps across their entire lifecycle.\r\n    store:\r\n      enabled: false # Enable or disable the KubeSphere App Store.\r\n  servicemesh:         # (0.3 Core, 300 MiB) Provide fine-grained traffic management, observability and tracing, and visualized traffic topology.\r\n    enabled: false     # Base component (pilot). Enable or disable KubeSphere Service Mesh (Istio-based).\r\n  kubeedge:          # Add edge nodes to your cluster and deploy workloads on edge nodes.\r\n    enabled: false   # Enable or disable KubeEdge.\r\n    cloudCore:\r\n      nodeSelector: {\"node-role.kubernetes.io\u002Fworker\": \"\"}\r\n      tolerations: []\r\n      cloudhubPort: \"10000\"\r\n      cloudhubQuicPort: \"10001\"\r\n      cloudhubHttpsPort: \"10002\"\r\n      cloudstreamPort: \"10003\"\r\n      tunnelPort: \"10004\"\r\n      cloudHub:\r\n        advertiseAddress: # At least a public IP address or an IP address which can be accessed by edge nodes must be provided.\r\n          - \"\"            # Note that once KubeEdge is enabled, CloudCore will malfunction if the address is not provided.\r\n        nodeLimit: \"100\"\r\n      service:\r\n        cloudhubNodePort: \"30000\"\r\n        cloudhubQuicNodePort: \"30001\"\r\n        cloudhubHttpsNodePort: \"30002\"\r\n        cloudstreamNodePort: \"30003\"\r\n        tunnelNodePort: \"30004\"\r\n    edgeWatcher:\r\n      nodeSelector: {\"node-role.kubernetes.io\u002Fworker\": \"\"}\r\n      tolerations: []\r\n      edgeWatcherAgent:\r\n        nodeSelector: {\"node-role.kubernetes.io\u002Fworker\": \"\"}\r\n        tolerations: []\r\n```\r\n\r\n\r\n\r\n#### 2.4.1.2\t修改cluster-configuration\r\n\r\n在 cluster-configuration.yaml中指定我们需要开启的功能\r\n\r\n参照官网“启用可插拔组件” ：https:\u002F\u002Fkubesphere.com.cn\u002Fdocs\u002Fpluggable-components\u002Foverview\u002F\r\n\r\n\r\n\r\n`cluster-configuration.yaml`文件开启相关组件后，内容如下：\r\n\r\n```yaml\r\n---\r\napiVersion: installer.kubesphere.io\u002Fv1alpha1\r\nkind: ClusterConfiguration\r\nmetadata:\r\n  name: ks-installer\r\n  namespace: kubesphere-system\r\n  labels:\r\n    version: v3.1.1\r\nspec:\r\n  persistence:\r\n    storageClass: \"\"        # 如果k8s集群没有默认的StorageClass，这里需要配置\r\n  authentication:\r\n    jwtSecret: \"\"           # Keep the jwtSecret consistent with the Host Cluster. Retrieve the jwtSecret by executing \"kubectl -n kubesphere-system get cm kubesphere-config -o yaml | grep -v \"apiVersion\" | grep jwtSecret\" on the Host Cluster.\r\n  local_registry: \"\"        # Add your private registry address if it is needed.\r\n  etcd:\r\n    monitoring: true        # 开启etcd监控\r\n    endpointIps: 192.168.3.71  # etcd cluster EndpointIps. It can be a bunch of IPs here.\r\n    port: 2379              # etcd port.\r\n    tlsEnable: true\r\n  common:\r\n    redis:\r\n      enabled: true         # 开启redis功能\r\n    openldap:\r\n      enabled: false\r\n    minioVolumeSize: 10Gi # Minio PVC size.\r\n    openldapVolumeSize: 2Gi   # openldap PVC size.\r\n    redisVolumSize: 2Gi # Redis PVC size.\r\n    monitoring:\r\n      # type: external   # Whether to specify the external prometheus stack, and need to modify the endpoint at the next line.\r\n      endpoint: http:\u002F\u002Fprometheus-operated.kubesphere-monitoring-system.svc:9090 # Prometheus endpoint to get metrics data.\r\n    es:   # Storage backend for logging, events and auditing.\r\n      # elasticsearchMasterReplicas: 1   # The total number of master nodes. Even numbers are not allowed.\r\n      # elasticsearchDataReplicas: 1     # The total number of data nodes.\r\n      elasticsearchMasterVolumeSize: 4Gi   # The volume size of Elasticsearch master nodes.\r\n      elasticsearchDataVolumeSize: 20Gi    # The volume size of Elasticsearch data nodes.\r\n      logMaxAge: 7                     # Log retention time in built-in Elasticsearch. It is 7 days by default.\r\n      elkPrefix: logstash              # The string making up index names. The index name will be formatted as ks-\u003Celk_prefix>-log.\r\n      basicAuth:\r\n        enabled: false\r\n        username: \"\"\r\n        password: \"\"\r\n      externalElasticsearchUrl: \"\"\r\n      externalElasticsearchPort: \"\"\r\n  console:\r\n    enableMultiLogin: true  # Enable or disable simultaneous logins. It allows different users to log in with the same account at the same time.\r\n    port: 30880\r\n  alerting:                # (CPU: 0.1 Core, Memory: 100 MiB) It enables users to customize alerting policies to send messages to receivers in time with different time intervals and alerting levels to choose from.\r\n    enabled: true         # 开启系统告警功能\r\n    # thanosruler:\r\n    #   replicas: 1\r\n    #   resources: {}\r\n  auditing:                # Provide a security-relevant chronological set of records，recording the sequence of activities happening on the platform, initiated by different tenants.\r\n    enabled: false         # 开启审计功能 \r\n  devops:                  # (CPU: 0.47 Core, Memory: 8.6 G) Provide an out-of-the-box CI\u002FCD system based on Jenkins, and automated workflow tools including Source-to-Image & Binary-to-Image.\r\n    enabled: true             # 开启devops功能\r\n    jenkinsMemoryLim: 2Gi      # Jenkins memory limit.\r\n    jenkinsMemoryReq: 1500Mi   # Jenkins memory request.\r\n    jenkinsVolumeSize: 8Gi     # Jenkins volume size.\r\n    jenkinsJavaOpts_Xms: 512m  # The following three fields are JVM parameters.\r\n    jenkinsJavaOpts_Xmx: 512m\r\n    jenkinsJavaOpts_MaxRAM: 2g\r\n  events:                  # Provide a graphical web console for Kubernetes Events exporting, filtering and alerting in multi-tenant Kubernetes clusters.\r\n    enabled: false         # Enable or disable the KubeSphere Events System.\r\n    ruler:\r\n      enabled: true\r\n      replicas: 2\r\n  logging:                 # (CPU: 57 m, Memory: 2.76 G) Flexible logging functions are provided for log query, collection and management in a unified console. Additional log collectors can be added, such as Elasticsearch, Kafka and Fluentd.\r\n    enabled: false         # Enable or disable the KubeSphere Logging System.\r\n    logsidecar:\r\n      enabled: true\r\n      replicas: 2\r\n  metrics_server:                    # (CPU: 56 m, Memory: 44.35 MiB) It enables HPA (Horizontal Pod Autoscaler).\r\n    enabled: false                   # Enable or disable metrics-server.\r\n  monitoring:\r\n    storageClass: \"\"                 # If there is an independent StorageClass you need for Prometheus, you can specify it here. The default StorageClass is used by default.\r\n    # prometheusReplicas: 1          # Prometheus replicas are responsible for monitoring different segments of data source and providing high availability.\r\n    prometheusMemoryRequest: 400Mi   # Prometheus request memory.\r\n    prometheusVolumeSize: 20Gi       # Prometheus PVC size.\r\n    # alertmanagerReplicas: 1          # AlertManager Replicas.\r\n  multicluster:\r\n    clusterRole: none  # host | member | none  # You can install a solo cluster, or specify it as the Host or Member Cluster.\r\n  network:\r\n    networkpolicy: # Network policies allow network isolation within the same cluster, which means firewalls can be set up between certain instances (Pods).\r\n      # Make sure that the CNI network plugin used by the cluster supports NetworkPolicy. There are a number of CNI network plugins that support NetworkPolicy, including Calico, Cilium, Kube-router, Romana and Weave Net.\r\n      enabled: false # Enable or disable network policies.\r\n    ippool: # Use Pod IP Pools to manage the Pod network address space. Pods to be created can be assigned IP addresses from a Pod IP Pool.\r\n      type: none # Specify \"calico\" for this field if Calico is used as your CNI plugin. \"none\" means that Pod IP Pools are disabled.\r\n    topology: # Use Service Topology to view Service-to-Service communication based on Weave Scope.\r\n      type: none # Specify \"weave-scope\" for this field to enable Service Topology. \"none\" means that Service Topology is disabled.\r\n  openpitrix: # An App Store that is accessible to all platform tenants. You can use it to manage apps across their entire lifecycle.\r\n    store:\r\n      enabled: false # Enable or disable the KubeSphere App Store.\r\n  servicemesh:         # (0.3 Core, 300 MiB) Provide fine-grained traffic management, observability and tracing, and visualized traffic topology.\r\n    enabled: false     # Base component (pilot). Enable or disable KubeSphere Service Mesh (Istio-based).\r\n  kubeedge:          # Add edge nodes to your cluster and deploy workloads on edge nodes.\r\n    enabled: false   # Enable or disable KubeEdge.\r\n    cloudCore:\r\n      nodeSelector: {\"node-role.kubernetes.io\u002Fworker\": \"\"}\r\n      tolerations: []\r\n      cloudhubPort: \"10000\"\r\n      cloudhubQuicPort: \"10001\"\r\n      cloudhubHttpsPort: \"10002\"\r\n      cloudstreamPort: \"10003\"\r\n      tunnelPort: \"10004\"\r\n      cloudHub:\r\n        advertiseAddress: # At least a public IP address or an IP address which can be accessed by edge nodes must be provided.\r\n          - \"\"            # Note that once KubeEdge is enabled, CloudCore will malfunction if the address is not provided.\r\n        nodeLimit: \"100\"\r\n      service:\r\n        cloudhubNodePort: \"30000\"\r\n        cloudhubQuicNodePort: \"30001\"\r\n        cloudhubHttpsNodePort: \"30002\"\r\n        cloudstreamNodePort: \"30003\"\r\n        tunnelNodePort: \"30004\"\r\n    edgeWatcher:\r\n      nodeSelector: {\"node-role.kubernetes.io\u002Fworker\": \"\"}\r\n      tolerations: []\r\n      edgeWatcherAgent:\r\n        nodeSelector: {\"node-role.kubernetes.io\u002Fworker\": \"\"}\r\n        tolerations: []\r\n```\r\n\r\n\r\n\r\n#### 2.4.1.3\t执行安装\r\n\r\n```shell\r\nkubectl apply -f kubesphere-installer.yaml\r\nkubectl apply -f cluster-configuration.yaml\r\n```\r\n\r\n\r\n\r\n#### 2.4.1.4\tKubeSphere平台访问\r\n\r\n（1）查看安装进度\r\n\r\n```shell\r\nkubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l app=ks-install -o jsonpath='{.items[0].metadata.name}') -f\r\n```\r\n\r\n​\t安装成功后，控制台会输出默认密码：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002FkubeSphere-init.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n\r\n\r\n查看pod安装过程是否会报错\r\n\r\n```shell\r\nkubectl get pod -A\r\n```\r\n\r\n> 解决etcd监控证书找不到问题？\r\n>\r\n> ​\t直接运行如下命令，创建 secret\r\n>\r\n> ```shell\r\n> kubectl -n kubesphere-monitoring-system create secret generic kube-etcd-client-certs  --from-file=etcd-client-ca.crt=\u002Fetc\u002Fkubernetes\u002Fpki\u002Fetcd\u002Fca.crt  --from-file=etcd-client.crt=\u002Fetc\u002Fkubernetes\u002Fpki\u002Fapiserver-etcd-client.crt  --from-file=etcd-client.key=\u002Fetc\u002Fkubernetes\u002Fpki\u002Fapiserver-etcd-client.key\r\n> ```\r\n\r\n\r\n\r\n\r\n\r\n（2）访问\r\n\r\n​\t访问集群任意机器的 30880端口\r\n\r\n​\t账号 ： admin\r\n\r\n​\t密码 ： 控制台会输出默认密码\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002FkubeSphere-login.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n### 2.4.2\t官方安装方式\r\n\r\n\r\n\r\n\r\n\r\n# 3\tKubeSphere 实战\r\n\r\n## 3.1\t多租户系统使用\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fkubesphere-saas.png\" style=\"zoom:80%;\" \u002F>\r\n\r\nkubeSphere角色描述信息：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fkubesphere-role.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n\r\n\r\n- **platform-admin**：平台管理员，可以管理平台内所有资源，如admin账号。admin平台管理员首次先创建`users-manager`账号，然后再由该账号去创建其他账号，当然也可以用admin直接创建，但一般都是由`users-manager`管理员创建。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fkubesphere-user.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n- **platform-regular**：平台普通用户，在被邀请加入企业空间或集群之前，没有任何资源操作权限；\r\n- **users-manager**：平台用户管理员，管理平台所有用户；\r\n\r\n- **workerspaces-manager**：平台企业空间管理员，管理平台所有企业空间。但是不能创建用户。\r\n\r\n\r\n\r\n（1）创建 users-manager 角色账号：hr-zhang\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fhr-zhang.png\" style=\"zoom:57%;\" \u002F>\r\n\r\n（2）使用hr-zhang登录，创建**workerspaces-manager**企业老板：boss-li。boss-li 是集团最大的boss，管理集团的所有分部或子公司。需要创建多少个子公司（企业空间）由boss-li创建。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fboss-li.png\" style=\"zoom:57%;\" \u002F>\r\n\r\n（3）使用boss-li登录，创建武汉分公司、深圳分公司。\r\n\r\n> 注意：**workerspaces-manager**角色只能创建企业空间，不能创建用户。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fwuhan.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fworkspace-manager.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n\r\n\r\n（4）再登陆hr-zhang，创建武汉分公司wuhan-boss，深圳分公司shenzhen-boss。\r\n\r\n> 注意：除了workerspaces-manager集团最大老板boss-li，其他都是平台普通用户。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fwuhan-boss.png\" style=\"zoom:57%;\" \u002F>\r\n\r\n​\t同时让更多人入职，创建了pm-wang，dev-zhao，big-li等用户。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fusers.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n\r\n\r\n（5）登录boss-li，给武汉、深圳分公司分配boss。\r\n\r\n​\t企业公司角色列表：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fwuhan-role.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n​\t邀请wuhan-boss为武汉分公司老板：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fkubesphere-space.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fwuhan-admin.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fwuhan-fen.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t同时邀请shenzhen-boss 为深圳分公司老板。\r\n\r\n（6）使用wuhan-boss登录，分配自己分公司的成员，打造自己分公司的项目。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fbig-sun.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n除了项目管理pm-wang具备创建项目、DevOps等资源权限，其他人员仅是普通成员是没法创建的，如果有销售人员，可以设置为观察者角色。\r\n\r\npm-wang可以创建项目，也可以邀请人到项目中。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fwuhan-users.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n（7）登录pm-wang，王总监创建自己管理的项目，并邀请成员。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fpm-wang.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n给his项目邀请成员，big-sun能管理项目任何资源，包括项目成员删除、邀请，权限仅次于pm-wang，只是不能创建项目而已。\r\n\r\n其他成员则只能创建和部署项目，比如创建DevOps，部署项目等。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fproject-role.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fpm-wang-his.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\r\n\r\n## 3.2\t中间件部署\r\n\r\n> 应用部署需要关注的信息【应用部署三要素】\r\n>\r\n> 1、应用的部署方式\r\n>\r\n> 2、应用的数据挂载（数据，配置文件）\r\n>\r\n> 3、应用的可访问性\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fkubesphere-deploy.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\r\n\r\n不论是以哪种方式部署，最终都是pod（容器组）。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fproject-deploy.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\r\n\r\n### 3.2.1\t配置Secret（镜像仓库）\r\n\r\n​\t配置镜像仓库地址，以及镜像登录账号密码。\r\n\r\n选择【配置中心】下的【密钥】，创建Secret。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fdocker-secret.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t点击【编辑模式】可以看到yaml内容如下：\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Secret\r\nmetadata:\r\n  namespace: his\r\n  labels: {}\r\n  name: aliyun-docker\r\n  annotations:\r\n    kubesphere.io\u002Fdescription: 阿里云镜像仓库\r\ntype: kubernetes.io\u002Fdockerconfigjson\r\nspec:\r\n  template:\r\n    metadata:\r\n      labels: {}\r\ndata:\r\n  .dockerconfigjson: >-\r\n    eyJhdXRocyI6eyJodHRwczovL3JlZ2lzdHJ5LmNuLWd1YW5nemhvdS5hbGl5dW5jcy5jb20iOnsidXNlcm5hbWUiOiJtX2h1aSIsInBhc3N3b3JkIjoiQ2hpbmFAMTk0OTEwMSIsImVtYWlsIjoiIiwiYXV0aCI6ImJWOW9kV2s2UTJocGJtRkFNVGswT1RFd01RPT0ifX19\r\n```\r\n\r\n\r\n\r\n### 3.2.2\t部署MySQL\r\n\r\n#### \t3.2.2.1\t容器部署方式\r\n\r\n```shell\r\ndocker run -p 3306:3306 --name mysql --restart=always --privileged=true \\\r\n-v \u002Fhome\u002Fhis\u002Fmysql\u002Flog:\u002Fvar\u002Flog\u002Fmysql \\\r\n-v \u002Fhome\u002Fhis\u002Fmysql\u002Fdata:\u002Fvar\u002Flib\u002Fmysql \\\r\n-v \u002Fhome\u002Fhis\u002Fmysql\u002Fconf:\u002Fetc\u002Fmysql\u002Fconf.d \\\r\n-v \u002Fetc\u002Flocaltime:\u002Fetc\u002Flocaltime:ro \\\r\n-e MYSQL_ROOT_PASSWORD=admin -d mysql:8.4.0\r\n```\r\n\r\n`my.cnf`配置文件：\r\n\r\n```shell\r\n[client]\r\ndefault-character-set=utf8mb4\r\n\r\n[mysql]\r\ndefault-character-set=utf8mb4\r\n\r\n[mysqld]\r\n# 设置东八区时区\r\ndefault-time_zone = '+8:00'\r\n\r\n# 设置密码验证规则，default_authentication_plugin参数已被废弃\r\n# 改为authentication_policy\r\n# default_authentication_plugin=mysql_native_password\r\nauthentication_policy=mysql_native_password\r\n\r\n# 限制导入和导出的数据目录\r\n# 为空，不限制导入导出的数据目录；\r\n# 指定目录，必须从该目录导入导处，且MySQL不会自动创建该目录；\r\n# 为NULL，禁止导入与导出功能\r\n#secure_file_priv=\u002Fvar\u002Flib\u002Fmysql\r\nsecure_file_priv=\r\n\r\ninit_connect='SET collation_connection = utf8mb4_0900_ai_ci'\r\ninit_connect='SET NAMES utf8mb4'\r\n\r\ncharacter-set-server=utf8mb4\r\ncollation-server=utf8mb4_0900_ai_ci\r\n\r\nskip-character-set-client-handshake\r\nskip-name-resolve\r\n```\r\n\r\n\r\n\r\n#### 3.2.2.2\tMySQL部署分析\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fmysql.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\tmysql部署需考虑数据挂载、配置文件挂载，环境变量（密码）配置。\r\n\r\n- 容器内的数据目录：\u002Fvar\u002Flib\u002Fmysql\r\n\r\n- 容器内的配置目录：\u002Fetc\u002Fmysql\u002Fconf.d ，主要是：my.cnf\r\n- 容器内的日志目录：\u002Fvar\u002Flog\u002Fmysql\r\n- 环境变量参数为：MYSQL_ROOT_PASSWORD（登录密码）\r\n- my.cnf配置文件内容，可直接使用 `3.2.2.1 容器部署方式`章的配置文件。\r\n\r\n\r\n\r\n#### 3.2.2.3\t创建ConfigMap配置\r\n\r\n（1）点击【配置中心】下的【配置】，创建一个名为mysql-conf的配置。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fkubesphere-mysql-conf.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n（2）复制上面的配置文件内容：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fmysql-cnf.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n（3）yaml内容如下：\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: ConfigMap\r\nmetadata:\r\n  namespace: his\r\n  labels: {}\r\n  name: mysql-conf\r\n  annotations:\r\n    kubesphere.io\u002Falias-name: mysql-conf\r\n    kubesphere.io\u002Fdescription: mysql配置\r\nspec:\r\n  template:\r\n    metadata:\r\n      labels: {}\r\ndata:\r\n  my.conf: |-\r\n    [client]\r\n    default-character-set=utf8mb4\r\n\r\n    [mysql]\r\n    default-character-set=utf8mb4\r\n\r\n    [mysqld]\r\n    # 设置东八区时区\r\n    default-time_zone = '+8:00'\r\n\r\n    # 设置密码验证规则，default_authentication_plugin参数已被废弃\r\n    # 改为authentication_policy\r\n    #default_authentication_plugin=mysql_native_password\r\n    authentication_policy=mysql_native_password\r\n\r\n    # 限制导入和导出的数据目录\r\n    # 为空，不限制导入导出的数据目录；\r\n    # 指定目录，必须从该目录导入导处，且MySQL不会自动创建该目录；\r\n    # 为NULL，禁止导入与导出功能\r\n    #secure_file_priv=\u002Fvar\u002Flib\u002Fmysql\r\n    secure_file_priv=\r\n\r\n    init_connect='SET collation_connection = utf8mb4_0900_ai_ci'\r\n    init_connect='SET NAMES utf8mb4'\r\n\r\n    character-set-server=utf8mb4\r\n    collation-server=utf8mb4_0900_ai_ci\r\n\r\n    skip-character-set-client-handshake\r\n    skip-name-resolve\r\n```\r\n\r\n\r\n\r\n#### 3.2.2.4\t创建存储卷\r\n\r\n> ​       有状态应用不建议先创建存储卷，应该是在创建应用部署的时候再配置。如果先创建pvc卷，那么后续增加副本的时候不会自动创建新的pvc卷，这就违背了有状态应用部署原则。有状态应用部署的存储卷，一个pvc绑定一个pod，并不是多个pod共享一个pvc卷。因此不能使用下面这种方式创建。\r\n\r\n​\t点击【存储管理】下的【存储卷】创建mysql-pvc存储卷。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fmysql-pvc.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t点击【下一步】，选择`StorageClass`【存储类型】和【存储卷容量】，然后【下一步】，直至创建。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fmysql-pvc2.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n点击右上角的【编辑模式】，可看到创建pvc卷yaml内容如下：\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: PersistentVolumeClaim\r\nmetadata:\r\n  namespace: his\r\n  name: mysql-pvc\r\n  labels: {}\r\n  annotations:\r\n    kubesphere.io\u002Fdescription: mysql pvc存储卷\r\nspec:\r\n  accessModes:\r\n    - ReadWriteOnce\r\n  resources:\r\n    requests:\r\n      storage: 5Gi\r\n  storageClassName: nfs-storage\r\n```\r\n\r\n\r\n\r\n#### 3.2.2.5\t创建应用部署\r\n\r\n​\t部署有状态应用的时候，会自动帮我们也创建了service服务，默认创建的是None模式的，只能集群内通过域名访问。当然等部署成功了之后，手动删除默认的service服务，然后根据自己需求再创建新的service。\r\n\r\n（1）点击【应用负载】下的【工作负载】，选择【有状态副本集】，创建mysql应用。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fmysql-sts.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t（2）点击【下一步】,输入镜像名称，网络不好可能加载不出来。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fmysql-sts2.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t可以对容器资源做一些限制，然后配置容器端口，service服务端口\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fmysql-sts3.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t配置环境变量，登录密码`MYSQL_ROOT_PASSWORD`，并设置同步宿主机时间。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fmysql-sts4.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t（3）点击【下一步】，添加数据挂载和配置挂载。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fmysql-sts6.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t选择【添加存储卷】，添加刚刚创建的pvc存储卷，挂载容器内的路径：`\u002Fvar\u002Flib\u002Fmysql `\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fmysql-sts7.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t然后再选择【挂载配置文件或密钥】，挂载刚刚创建的ConfigMap配置，挂载容器的路径：`\u002Fetc\u002Fmysql\u002Fconf.d`\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fmysql-sts8.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t挂载完成后，显示如下：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fmysql-sts-conf.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t（4）点击【下一步】，然后创建。\r\n\r\n​\t（5）点击【编辑模式】可看到yaml配置如下：\r\n\r\n```yaml\r\napiVersion: apps\u002Fv1\r\nkind: StatefulSet\r\nmetadata:\r\n  namespace: his\r\n  labels:\r\n    app: mysql-sts\r\n  name: mysql-sts\r\n  annotations:\r\n    kubesphere.io\u002Fdescription: mysql数据库\r\nspec:\r\n  replicas: 1\r\n  selector:\r\n    matchLabels:\r\n      app: mysql-sts\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: mysql-sts\r\n      annotations:\r\n        logging.kubesphere.io\u002Flogsidecar-config: '{}'\r\n    spec:\r\n      containers:\r\n        - name: mysql-dxsumn\r\n          imagePullPolicy: IfNotPresent\r\n          image: 'mysql:8.4.0'\r\n          resources:\r\n            limits:\r\n              memory: 2048Mi\r\n          ports:\r\n            - name: tcp-3306\r\n              protocol: TCP\r\n              containerPort: 3306\r\n              servicePort: 3306\r\n          volumeMounts:\r\n            - name: host-time\r\n              mountPath: \u002Fetc\u002Flocaltime\r\n              readOnly: true\r\n            - name: volume-lu805i\r\n              readOnly: false\r\n              mountPath: \u002Fvar\u002Flib\u002Fmysql\r\n            - name: volume-nrwp8i\r\n              readOnly: true\r\n              mountPath: \u002Fetc\u002Fmysql\u002Fconf.d\r\n          env:\r\n            - name: MYSQL_ROOT_PASSWORD\r\n              value: admin\r\n      serviceAccount: default\r\n      affinity: {}\r\n      initContainers: []\r\n      volumes:\r\n        - hostPath:\r\n            path: \u002Fetc\u002Flocaltime\r\n            type: ''\r\n          name: host-time\r\n        - name: volume-lu805i\r\n          persistentVolumeClaim:\r\n            claimName: mysql-pvc\r\n        - name: volume-nrwp8i\r\n          configMap:\r\n            name: mysql-conf\r\n            items:\r\n              - key: my.conf\r\n                path: my.conf\r\n      imagePullSecrets: null\r\n  updateStrategy:\r\n    type: RollingUpdate\r\n    rollingUpdate:\r\n      partition: 0\r\n  serviceName: mysql-sts-7ds6\r\n---\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  namespace: his\r\n  labels:\r\n    app: mysql-sts\r\n  name: mysql-sts-7ds6\r\n  annotations:\r\n    kubesphere.io\u002Falias-name: mysql-sts\r\n    kubesphere.io\u002FserviceType: statefulservice\r\nspec:\r\n  sessionAffinity: None\r\n  selector:\r\n    app: mysql-sts\r\n  ports:\r\n    - name: tcp-3306\r\n      protocol: TCP\r\n      port: 3306\r\n      targetPort: 3306\r\n  clusterIP: None\r\n\r\n```\r\n\r\n\r\n\r\n#### 3.2.2.6\t访问\r\n\r\n​\t创建有状态应用部署时，会自动帮我们也创建了service，默认是None，只能在集群内部通过域名访问，如：`mysql-sts-7ds6.his`。\r\n\r\n```shell\r\n# mysql 使用远程主机的方式登录\r\nmysql -uroot -hmysql-sts-7ds6 -p\r\n```\r\n\r\n​\t如果想要集群外部访问，可以重新创建类型为NodeIP的服务，或者创建Ingress的方式来供外部访问。\r\n\r\n​\t（1）选择【应用负载】下的【服务】，点击【创建】，然后选择【指定工作负载】\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fkubesphere-svc.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t（2）选择对应的访问类型，访问类型有两种，第二种Headless（None）是无法暴露外界访问的。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fsvc-3.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t选择对应的访问类型，工作负载，然后配置端口：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fsvc-2.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n（3）选择是否暴露外界访问\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fsvc-node.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t点击【编辑模式】可以看到yaml内容如下，有更多需求可以直接在【编辑模式】下直接修改yaml。\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  namespace: his\r\n  labels:\r\n    app: mysql-svc\r\n  name: mysql-svc\r\nspec:\r\n  sessionAffinity: None\r\n  selector:\r\n    app: mysql-sts\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: mysql-svc\r\n  ports:\r\n    - name: http-3306\r\n      protocol: TCP\r\n      targetPort: 3306\r\n      port: 3306\r\n  type: NodePort\r\n\r\n```\r\n\r\n\r\n\r\n（4）访问\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fsvc-4.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\r\n\r\n### 3.2.3\t部署PostgreSQL\r\n\r\n```yaml\r\napiVersion: apps\u002Fv1\r\nkind: StatefulSet\r\nmetadata:\r\n  namespace: dhyy\r\n  labels:\r\n    app: postgres-sts\r\n  name: postgres-sts\r\n  annotations:\r\n    kubesphere.io\u002Fdescription: postgres数据库\r\nspec:\r\n  replicas: 1\r\n  selector:\r\n    matchLabels:\r\n      app: postgres-sts\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: postgres-sts\r\n      annotations:\r\n        logging.kubesphere.io\u002Flogsidecar-config: '{}'\r\n    spec:\r\n      containers:\r\n        - name: postgres\r\n          imagePullPolicy: IfNotPresent\r\n          image: 'postgres:16'\r\n          ports:\r\n            - name: http-5432\r\n              protocol: TCP\r\n              containerPort: 5432\r\n              servicePort: 5432\r\n          volumeMounts:\r\n            - name: host-time\r\n              mountPath: \u002Fetc\u002Flocaltime\r\n              readOnly: false\r\n            - readOnly: false\r\n              mountPath: \u002Fvar\u002Flib\u002Fpostgresql\u002Fdata\r\n              name: postgres-pvc\r\n          env:\r\n            - name: POSTGRES_USER\r\n              value: postgres\r\n            - name: POSTGRES_PASSWORD\r\n              value: postgres\r\n      serviceAccount: default\r\n      affinity: {}\r\n      initContainers: []\r\n      volumes:\r\n        - hostPath:\r\n            path: \u002Fetc\u002Flocaltime\r\n            type: ''\r\n          name: host-time\r\n      imagePullSecrets: null\r\n  updateStrategy:\r\n    type: RollingUpdate\r\n    rollingUpdate:\r\n      partition: 0\r\n  serviceName: postgres-sts-9bsp\r\n  volumeClaimTemplates:\r\n    - spec:\r\n        accessModes:\r\n          - ReadWriteOnce\r\n        resources:\r\n          requests:\r\n            storage: 5Gi\r\n        storageClassName: nfs-storage\r\n      metadata:\r\n        name: postgres-pvc\r\n        namespace: dhyy\r\n---\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  namespace: dhyy\r\n  labels:\r\n    app: postgres-sts\r\n  name: postgres-sts-9bsp\r\n  annotations:\r\n    kubesphere.io\u002Falias-name: postgres-sts\r\n    kubesphere.io\u002FserviceType: statefulservice\r\nspec:\r\n  sessionAffinity: None\r\n  selector:\r\n    app: postgres-sts\r\n  ports:\r\n    - name: http-5432\r\n      protocol: TCP\r\n      port: 5432\r\n      targetPort: 5432\r\n  clusterIP: None\r\n\r\n```\r\n\r\n\r\n\r\n\r\n\r\n### 3.2.4\t部署Redis\r\n\r\n#### 3.2.4.1\t容器部署方式\r\n\r\n```shell\r\n#创建配置文件\r\n## 1、准备redis配置文件内容\r\nmkdir -p \u002Fhome\u002Fredis\u002Fconf\r\n\r\n## 2、编辑配置文件\r\nvi \u002Fmydata\u002Fredis\u002Fconf\u002Fredis.conf\r\n## redis.conf配置示例：\r\nappendonly yes\r\nport 6379\r\nbind 0.0.0.0\r\nrequirepass 123456\r\n\r\n\r\n\r\n#docker启动redis\r\ndocker run -d -p 6379:6379 --restart=always \\\r\n-v \u002Fhome\u002Fredis\u002Fconf\u002Fredis.conf:\u002Fetc\u002Fredis\u002Fredis.conf \\\r\n-v  \u002Fhome\u002Fredis\u002Fdata:\u002Fdata \\\r\n--name redis redis:7.4 \\\r\nredis-server \u002Fetc\u002Fredis\u002Fredis.conf\r\n\r\n# 指定配置文件启动\r\n# redis-server \u002Fetc\u002Fredis\u002Fredis.conf\r\n```\r\n\r\n\r\n\r\n#### 3.2.4.2\tRedis部署分析\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fredis-sts.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\r\n\r\n#### 3.2.4.2\t创建ConfigMap配置\r\n\r\n​\t\t点击【配置中心】下的【配置】，创建redis配置。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fredis-conf.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t\t`redis.conf`配置文件内容为：\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: ConfigMap\r\nmetadata:\r\n  namespace: his\r\n  labels: {}\r\n  name: redis-conf\r\n  annotations:\r\n    kubesphere.io\u002Fdescription: redis配置文件\r\nspec:\r\n  template:\r\n    metadata:\r\n      labels: {}\r\ndata:\r\n  redis.conf: |-\r\n    appendonly yes\r\n    port 6379\r\n    bind 0.0.0.0\r\n\r\n```\r\n\r\n\r\n\r\n#### 3.2.4.3\t创建应用部署\r\n\r\n​\t\t（1）点击【应用负载】下的【工作负载】，创建有状态副本集。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fredis-sts1.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t\t配置启动命令，指定配置文件启动：`redis-server \u002Fetc\u002Fredis\u002Fredis.conf`\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fredis-sts2.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n（2）点击【下一步】，创建数据挂载，创建配置文件。\r\n\r\n​\t\t选择【添加存储卷模板】，创建pvc卷，并配置数据挂载目录：\u002Fdata\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fredis-sts3.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t\t\t\t选择【挂载配置文件或密钥】，配置redis.conf文件。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fredis-sts4.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t\t（3）点击【下一步】，直至创建完成，yaml内容如下：\r\n\r\n```yaml\r\nkind: StatefulSet\r\napiVersion: apps\u002Fv1\r\nmetadata:\r\n  name: redis-sts\r\n  namespace: his\r\n  labels:\r\n    app: redis-sts\r\n  annotations:\r\n    kubesphere.io\u002Fcreator: dev-zhao\r\n    kubesphere.io\u002Fdescription: redis缓存\r\nspec:\r\n  replicas: 1\r\n  selector:\r\n    matchLabels:\r\n      app: redis-sts\r\n  template:\r\n    metadata:\r\n      creationTimestamp: null\r\n      labels:\r\n        app: redis-sts\r\n      annotations:\r\n        logging.kubesphere.io\u002Flogsidecar-config: '{}'\r\n    spec:\r\n      volumes:\r\n        - name: host-time\r\n          hostPath:\r\n            path: \u002Fetc\u002Flocaltime\r\n            type: ''\r\n        - name: volume-t359ym\r\n          configMap:\r\n            name: redis-conf\r\n            items:\r\n              - key: redis.conf\r\n                path: redis.conf\r\n            defaultMode: 420\r\n      containers:\r\n        - name: redis-9132ey\r\n          image: 'redis:7.4'\r\n          command:\r\n            - redis-server\r\n          args:\r\n            - \u002Fetc\u002Fredis\u002Fredis.conf\r\n          ports:\r\n            - name: http-6379\r\n              containerPort: 6379\r\n              protocol: TCP\r\n          resources:\r\n            limits:\r\n              memory: 1Gi\r\n          volumeMounts:\r\n            - name: host-time\r\n              mountPath: \u002Fetc\u002Flocaltime\r\n            - name: redis-pvc\r\n              mountPath: \u002Fdata\r\n            - name: volume-t359ym\r\n              readOnly: true\r\n              mountPath: \u002Fetc\u002Fredis\u002Fredis.conf\r\n              subPath: redis.conf\r\n          terminationMessagePath: \u002Fdev\u002Ftermination-log\r\n          terminationMessagePolicy: File\r\n          imagePullPolicy: IfNotPresent\r\n      restartPolicy: Always\r\n      terminationGracePeriodSeconds: 30\r\n      dnsPolicy: ClusterFirst\r\n      serviceAccountName: default\r\n      serviceAccount: default\r\n      securityContext: {}\r\n      affinity: {}\r\n      schedulerName: default-scheduler\r\n  volumeClaimTemplates:\r\n    - kind: PersistentVolumeClaim\r\n      apiVersion: v1\r\n      metadata:\r\n        name: redis-pvc\r\n        namespace: his\r\n        creationTimestamp: null\r\n      spec:\r\n        accessModes:\r\n          - ReadWriteOnce\r\n        resources:\r\n          requests:\r\n            storage: 2Gi\r\n        storageClassName: nfs-storage\r\n        volumeMode: Filesystem\r\n      status:\r\n        phase: Pending\r\n  serviceName: redis-sts-je3w\r\n  podManagementPolicy: OrderedReady\r\n  updateStrategy:\r\n    type: RollingUpdate\r\n    rollingUpdate:\r\n      partition: 0\r\n  revisionHistoryLimit: 10\r\n\r\n```\r\n\r\n\r\n\r\n### 3.2.5\t部署ElasticSearch\r\n\r\n#### 3.2.5.1\t容器部署方式\r\n\r\n```shell\r\n# 创建数据目录\r\nmkdir -p \u002Fhome\u002Fes\u002Fdata\r\n# 创建插件目录\r\nmkdir -p \u002Fhome\u002Fes\u002Fplugs\r\nchmod 777 -R \u002Fhome\u002Fes\r\n\r\ndocker run --name es -p 9200:9200  -p 9300:9300 \\\r\n--privileged=true \\\r\n--restart=always \\\r\n-v \u002Fhome\u002Fes\u002Fdata:\u002Fusr\u002Fshare\u002Felasticsearch\u002Fdata \\\r\n-v \u002Fhome\u002Fes\u002Fplugs:\u002Fusr\u002Fshare\u002Felasticsearch\u002Fplugs \\\r\n-e \"discovery.type=single-node\" \\\r\n-e \"cluster.name=es-cluster\" \\\r\n-e ELASTIC_USERNAME=elastic \\\r\n-e ELASTIC_PASSWORD='admin' \\\r\n-e ES_JAVA_OPTS=\"-Xms64m -Xmx128m\" \\\r\n-d elasticsearch:8.4.0\r\n```\r\n\r\n\r\n\r\n#### 3.2.5.2\tEs部署分析\r\n\r\n- 配置文件路径：\u002Fusr\u002Fshare\u002Felasticsearch\u002Fconfig，主要是elasticsearch.yml\r\n- 数据路径：\u002Fusr\u002Fshare\u002Felasticsearch\u002Fdata\r\n- 插件存放路径：\u002Fusr\u002Fshare\u002Felasticsearch\u002Fplugins\r\n\r\n\r\n\r\n#### 3.2.5.3\t创建应用部署\r\n\r\n（1）配置端口、环境变量。\r\n\r\n- 单机模式：discovery.type=single-node\r\n\r\n- 集群名称（选配）：cluster.name=es-cluster\r\n\r\n- 登录名称：ELASTIC_USERNAME=elastic\r\n\r\n- 登录密码：ELASTIC_PASSWORD=elastic\r\n\r\n- jvm参数：ES_JAVA_OPTS=-Xms64m -Xmx128m\r\n\r\n\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fes-sts.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t\t环境变量配置：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fes-sts-env.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t（2）挂载数据存储、插件：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fes-conf.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t\t\r\n\r\n​\t\t（3）点击【下一步】，直至创建，yaml内容如下：\r\n\r\n```yaml\r\napiVersion: apps\u002Fv1\r\nkind: StatefulSet\r\nmetadata:\r\n  namespace: his\r\n  labels:\r\n    app: es-sts\r\n  name: es-sts\r\nspec:\r\n  replicas: 1\r\n  selector:\r\n    matchLabels:\r\n      app: es-sts\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: es-sts\r\n      annotations:\r\n        logging.kubesphere.io\u002Flogsidecar-config: '{}'\r\n    spec:\r\n      containers:\r\n        - name: elasticsearch\r\n          imagePullPolicy: IfNotPresent\r\n          image: 'elasticsearch:8.4.0'\r\n          volumeMounts:\r\n            - name: host-time\r\n              mountPath: \u002Fetc\u002Flocaltime\r\n              readOnly: false\r\n            - readOnly: false\r\n              mountPath: \u002Fusr\u002Fshare\u002Felasticsearch\u002Fdata\r\n              name: es-pvc-data\r\n            - readOnly: false\r\n              mountPath: \u002Fusr\u002Fshare\u002Felasticsearch\u002Fplugs\r\n              name: es-pvc-plugs\r\n          ports:\r\n            - name: http-9200\r\n              protocol: TCP\r\n              containerPort: 9200\r\n              servicePort: 9200\r\n            - name: http-9300\r\n              protocol: TCP\r\n              containerPort: 9300\r\n              servicePort: 9300\r\n          resources:\r\n            limits:\r\n              memory: 2048Mi\r\n          env:\r\n            - name: discovery.type\r\n              value: single-node\r\n            - name: cluster.name\r\n              value: es-cluster\r\n            - name: ELASTIC_USERNAME\r\n              value: elastic\r\n            - name: ELASTIC_PASSWORD\r\n              value: elastic\r\n            - name: ES_JAVA_OPTS\r\n              value: '-Xms64m -Xmx128m'\r\n      serviceAccount: default\r\n      affinity: {}\r\n      initContainers: []\r\n      volumes:\r\n        - hostPath:\r\n            path: \u002Fetc\u002Flocaltime\r\n            type: ''\r\n          name: host-time\r\n      imagePullSecrets: null\r\n  updateStrategy:\r\n    type: RollingUpdate\r\n    rollingUpdate:\r\n      partition: 0\r\n  serviceName: es-sts-n14u\r\n  volumeClaimTemplates:\r\n    - spec:\r\n        accessModes:\r\n          - ReadWriteOnce\r\n        resources:\r\n          requests:\r\n            storage: 2Gi\r\n        storageClassName: nfs-storage\r\n      metadata:\r\n        name: es-pvc-data\r\n        namespace: his\r\n    - spec:\r\n        accessModes:\r\n          - ReadWriteOnce\r\n        resources:\r\n          requests:\r\n            storage: 2Gi\r\n        storageClassName: nfs-storage\r\n      metadata:\r\n        name: es-pvc-plugs\r\n        namespace: his\r\n---\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  namespace: his\r\n  labels:\r\n    app: es-sts\r\n  name: es-sts-n14u\r\n  annotations:\r\n    kubesphere.io\u002Falias-name: es-sts\r\n    kubesphere.io\u002FserviceType: statefulservice\r\nspec:\r\n  sessionAffinity: None\r\n  selector:\r\n    app: es-sts\r\n  ports:\r\n    - name: http-9200\r\n      protocol: TCP\r\n      port: 9200\r\n      targetPort: 9200\r\n    - name: http-9300\r\n      protocol: TCP\r\n      port: 9300\r\n      targetPort: 9300\r\n  clusterIP: None\r\n\r\n```\r\n\r\n\r\n\r\n（4）访问\r\n\r\n```shell\r\n# 如果没开启密码，则使用http访问\r\nhttp:\u002F\u002Fip:9200\r\n# 开启密码，则使用https\r\nhttps:\u002F\u002Fip:9200\r\n```\r\n\r\n\r\n\r\n结果如下，如果开启了密码登录，则不会有响应。\r\n\r\n```shell\r\n{\r\n  \"name\" : \"es-sts-0\",\r\n  \"cluster_name\" : \"es-cluster\",\r\n  \"cluster_uuid\" : \"fJOwh5-gR2mqG_Nkwi1z0A\",\r\n  \"version\" : {\r\n    \"number\" : \"8.4.0\",\r\n    \"build_flavor\" : \"default\",\r\n    \"build_type\" : \"docker\",\r\n    \"build_hash\" : \"f56126089ca4db89b631901ad7cce0a8e10e2fe5\",\r\n    \"build_date\" : \"2022-08-19T19:23:42.954591481Z\",\r\n    \"build_snapshot\" : false,\r\n    \"lucene_version\" : \"9.3.0\",\r\n    \"minimum_wire_compatibility_version\" : \"7.17.0\",\r\n    \"minimum_index_compatibility_version\" : \"7.0.0\"\r\n  },\r\n  \"tagline\" : \"You Know, for Search\"\r\n}\r\n```\r\n\r\n\r\n\r\n### 3.2.6\t部署es可视化界面kibana\r\n\r\n[官网](https:\u002F\u002Fwww.elastic.co\u002Fguide\u002Fen\u002Fkibana\u002F8.4\u002Fdocker.html)：https:\u002F\u002Fwww.elastic.co\u002Fguide\u002Fen\u002Fkibana\u002F8.4\u002Fdocker.html\r\n\r\n#### 3.2.6.1\t容器部署方式\r\n\r\n```shell\r\ndocker run --name kibana -p 5601:5601 kibana:8.4.0\r\n```\r\n\r\n#### 3.2.6.2\tkibana部署\r\n\r\n创建一个无状态部署应用：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fkibana-deploy.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\tyaml内容如下：\r\n\r\n```yaml\r\napiVersion: apps\u002Fv1\r\nkind: Deployment\r\nmetadata:\r\n  namespace: his\r\n  labels:\r\n    app: kibana-deploy\r\n  name: kibana-deploy\r\n  annotations:\r\n    kubesphere.io\u002Fdescription: es可视化界面\r\nspec:\r\n  replicas: 1\r\n  selector:\r\n    matchLabels:\r\n      app: kibana-deploy\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: kibana-deploy\r\n    spec:\r\n      containers:\r\n        - name: container-b7iaam\r\n          imagePullPolicy: IfNotPresent\r\n          image: 'kibana:8.4.0'\r\n          ports:\r\n            - name: http-5601\r\n              protocol: TCP\r\n              containerPort: 5601\r\n          volumeMounts:\r\n            - name: host-time\r\n              mountPath: \u002Fetc\u002Flocaltime\r\n              readOnly: true\r\n      serviceAccount: default\r\n      affinity: {}\r\n      initContainers: []\r\n      volumes:\r\n        - hostPath:\r\n            path: \u002Fetc\u002Flocaltime\r\n            type: ''\r\n          name: host-time\r\n      imagePullSecrets: null\r\n  strategy:\r\n    type: RollingUpdate\r\n    rollingUpdate:\r\n      maxUnavailable: 25%\r\n      maxSurge: 25%\r\n\r\n```\r\n\r\n\r\n\r\n#### 3.2.6.3\t创建服务\r\n\r\n（1）指定负载，配置端口\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fkibana-svc.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t\t（2）开启外网访问\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fkibana-svc-node.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t\t（2）点击【编辑模式】，指定NodePort端口\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  namespace: his\r\n  labels:\r\n    app: kibana-svc\r\n  name: kibana-svc\r\n  annotations:\r\n    kubesphere.io\u002Fdescription: es可视化界面\r\nspec:\r\n  sessionAffinity: None\r\n  selector:\r\n    app: kibana-deploy\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: kibana-svc\r\n  ports:\r\n    - name: http-5601\r\n      protocol: TCP\r\n      targetPort: 5601\r\n      port: 5601\r\n      nodePort: 30001\r\n  type: NodePort\r\n\r\n```\r\n\r\n\r\n\r\n#### 3.2.6.4\t配置\r\n\r\n访问地址：http:\u002F\u002F192.168.3.71:30001\u002F\r\n\r\n**（1）es不开启密码认证**\r\n\r\n​\t\t进入ip配置界面：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fkibana-config0.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t\t输如ip地址，无密码认证，需要使用http协议，往下一路点击确认即可：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fkibana-config1.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\r\n\r\n**（2）es开启密码认证情况下**\r\n\r\n```shell\r\n# 进入es容器内部\r\nkubectl exec -it -n his es-sts-0 \u002Fbin\u002Fbash\r\n\r\n# 生成  kibane token\r\nbin\u002Felasticsearch-create-enrollment-token -s kibana\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fes-kibana-token.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\r\n\r\n按照如下配置token，如果配置一直超时，则删掉es、kibana容器后再启动重试即可。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fkibana8.x-config.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n如果时间过长，弹出如下界面：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fkibana8.x-config2.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n则根据kibana终端显示的校验码输入即可，终端显示如下：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fkibana8.x-config3.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\r\n\r\n#### 3.2.6.5\t访问\r\n\r\n从首页进入数据操作界面：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fdev-tools.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n进入命令操作界面：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fkubesphere容器平台\u002Fkibana.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n创建索引，查看索引：\r\n\r\n```shell\r\n# 创建索引\r\nPUT \u002Fmy_index\r\n{\r\n  \"settings\": {\r\n    \"number_of_shards\": 5,  \u002F\u002F设置5个片区\r\n    \"number_of_replicas\": 1 \u002F\u002F复制集。设置1个备份\r\n  }\r\n}\r\n# 查看索引\r\nGET \u002Fmy_index\r\n# 删除索引\r\nDELETE \u002Fmy_index\r\n```\r\n\r\n\r\n\r\n## 3.3\t微服务部署\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n# 4\t云原生DevOps实战\r\n\r\n\r\n\r\n# 5\t微服务基础与实战\r\n\r\n",{"_path":216,"slug":217,"title":218,"description":219,"excerpt":219,"date":220,"tags":221,"type":15,"cover":223,"content":224},"\u002Fknowledge\u002Ffrp内网穿透","frp内网穿透","搭建的小主机服务器，如何被互联网访问？","搭建的小主机服务器，如何被互联网访问？ - 使用 Frp 搭建内网穿透 - 使用 Ngrok 免费隧道 - 申请公网IP - 使用 WireGuard、ZeroTier 组网 下面，将会讲解如何让我们搭建的小主机能通过公网进行访问。 因为公网IP不好申请，我们先介绍的是对小白相对友好的一些方案。其中有些方法需要自己有一","2024-11-09",[103,44,222],"frp","\u002Fknowledge-assets\u002Ffrp内网穿透\u002Ffrp-login.png","# 搭建的小主机服务器，如何被互联网访问？\r\n\r\n- 使用 Frp 搭建内网穿透\r\n\r\n- 使用 Ngrok 免费隧道\r\n\r\n- 申请公网IP\r\n\r\n- 使用 WireGuard、ZeroTier 组网\r\n\r\n下面，将会讲解如何让我们搭建的小主机能通过公网进行访问。\r\n\r\n因为公网IP不好申请，我们先介绍的是对小白相对友好的一些方案。其中有些方法需要自己有一台云服务器，用于提供公网IP和流量转发。并且对配置要求也不高，只需要带宽不是小水管就行。\r\n\r\n\r\n\r\n# 使用FRP搭建内网穿透\r\n\r\n## FRP简介\r\n\r\n首先，我们使用**Frp**来搭建我们的内网穿透服务。**Frp**是一款在 **Github** 上非常热门的项目，使用 **Golang** 语言开发，目前已经有 **82k** 的 **star**数，社区也很活跃。\r\n\r\n> Github地址：https:\u002F\u002Fgithub.com\u002Ffatedier\u002Ffrp 文档地址：https:\u002F\u002Fgofrp.org\u002Fzh-cn\u002Fdocs\u002F\r\n\r\n**Frp** 是一个专注于内网穿透的高性能的反向代理应用，支持 **TCP** 、**UDP**、**HTTP**、**HTTPS** 等多种协议，且支持 **P2P** 通信。可以将内网服务以安全、便捷的方式通过具有 **公网IP** 节点的中转暴露到公网。\r\n\r\n通过在具有公网 **IP** 的节点上部署 **Frp** 服务端，您可以轻松地将内网服务穿透到公网，并享受以下专业特性：\r\n\r\n- 多种协议支持：客户端服务端通信支持 **TCP**、**QUIC**、**KCP** 和 **Websocket** 等多种协议。\r\n- **TCP** 连接流式复用：在单个连接上承载多个请求，减少连接建立时间，降低请求延迟。\r\n- 代理组间的负载均衡。\r\n- 端口复用：多个服务可以通过同一个服务端端口暴露。\r\n- **P2P** 通信：流量不必经过服务器中转，充分利用带宽资源。\r\n- 客户端插件：提供多个原生支持的客户端插件，如静态文件查看、**HTTPS\u002FHTTP** 协议转换、**HTTP**、**SOCKS5** 代理等，以便满足各种需求。\r\n- 服务端插件系统：高度可扩展的服务端插件系统，便于根据自身需求进行功能扩展。\r\n- 用户友好的 UI 页面：提供服务端和客户端的用户界面，使配置和监控变得更加方便。\r\n\r\n**frp** 主要由两个组件组成：客户端( **frpc** ) 和 服务端( **frps** )。通常情况下，服务端部署在具有公网 IP 地址的机器上，而客户端部署在需要穿透的内网服务所在的机器上。\r\n\r\n由于内网服务缺乏公网 **IP** 地址，因此无法直接被非局域网内的用户访问。用户通过访问服务端的 **frps**，**frp** 负责根据请求的端口或其他信息将请求路由到相应的内网机器，从而实现通信。\r\n\r\n## 搭建Frp\r\n\r\n首先就需要准备好一台云服务器，用于提供**公网IP**和流量转发。至于购买哪家的云服务产品，本着能省则省的原则，这个当然是哪家便宜用哪家呢。\r\n\r\n\r\n\r\n### 安装服务端\r\n\r\n首先来安装服务端，服务端需要在具有公网IP的设备上进行安装，演示环境预装了 **CentOS 7.x** 系统。这里需要使用到 **docker** 来进行安装。\r\n\r\n**(1) 创建 frp 的服务端配置文件：**\r\n\r\n```shell\r\nvi \u002Froot\u002Ffrp\u002Ffrps.ini\r\n```\r\n\r\n然后填写配置信息，这里会启动两个端口号：**7000**：用于和内网设备数据交互；**7500**：提供 **frp** 图形化界面，同时需要配置面板访问的账号和密码，以及 **token**是内网设备和 **frp** 服务端建立连接时的密码。\r\n\r\n```shell\r\n[common]\r\n# 监听端口\r\nbind_port = 7000\r\n# 面板端口\r\ndashboard_port = 7500\r\n# 登录面板账号设置\r\ndashboard_user = admin\r\n# 登录面板的密码\r\ndashboard_pwd = QWEasd@123\r\n\r\n# 身份验证\r\ntoken = !QAZ2wsx#EDC\r\n```\r\n\r\n\r\n\r\n**(2) 启动容器**\r\n\r\n```shell\r\ndocker run --name frps \\\r\n--restart=always --network host \\\r\n-v \u002Froot\u002Ffrp\u002Ffrps.ini:\u002Fetc\u002Ffrp\u002Ffrps.ini \\\r\n-d registry.cn-shenzhen.aliyuncs.com\u002Fmogublog_business\u002Ffrps\r\n```\r\n\r\n细心的小伙伴，可能会发现：命令行中使用了 **--network host** 定网络模式为host模式。\r\n\r\n众所周知，**Docker** 使用了Linux的Namespaces技术来进行资源隔离，如`PID Namespace`隔离进程，`Mount Namespace`隔离文件系统，`Network Namespace`隔离网络等。一个`Network Namespace`提供了一份独立的网络环境，包括网卡、路由、**Iptable** 规则等都与其他的 **Network Namespace** 隔离。\r\n\r\n如果使用 **host** 模式时，容器中的应用都直接绑定在宿主机的端口上，没有经过 **NAT** 转换，但容器的其他如文件系统等还是隔离的。\r\n\r\n```shell\r\n# NAT网络模式，必须提前将监听映射的端口暴露\r\ndocker run --name frps \\\r\n--restart=always \\\r\n-p 7000:7000 -p 7500:7500 \\\r\n-p 9000:9000 -p 9001:9001 -p 9002:9002 \\\r\n-v \u002Froot\u002Ffrp\u002Ffrps.ini:\u002Fetc\u002Ffrp\u002Ffrps.ini \\\r\n-d registry.cn-shenzhen.aliyuncs.com\u002Fmogublog_business\u002Ffrps\r\n```\r\n\r\n\r\n\r\n**frp** 还提供了图形化的界面，我们使用 http:\u002F\u002Fip:7500 即可打开对应的图形化界面。输入上面配置文件中，配置的账号和密码登录即可。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Ffrp内网穿透\u002Ffrp-login.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n如果能看到下面的页面，说明就我们的服务端就安装成功了\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Ffrp内网穿透\u002Ffrp-server.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n### 安装客户端\r\n\r\n客户端需要在我们的内网的机器上进行安装，演示环境为CentOS7.x。\r\n\r\n**(1) 创建 frp 的客户端配置文件：**\r\n\r\n首先，需要在这台机器上，创建 **frp** 的客户端配置文件：\r\n\r\n```shell\r\nvi \u002Froot\u002Ffrp\u002Ffrpc.ini\r\n```\r\n\r\n然后填写下面的配置，这里需要注意的是 **server_addr** 填写的是服务器端的地址，然后 **token** 是服务端配置的token令牌，用于客户端和服务端建立连接。\r\n\r\n```shell\r\n[common]\r\n# server_addr为云服务器IP地址\r\nserver_addr = 106.53.110.52\r\n# server_port为服务端监听端口，bind_port\r\nserver_port = 7000\r\n# 服务端设置的token\r\ntoken = !QAZ2wsx#EDC\r\n\r\n# 配置挂公网的本地服务端口\r\n[vue_web]\r\ntype = tcp\r\nlocal_ip = 127.0.0.1\r\n# 本地端口\r\nlocal_port = 8000\r\n# 映射到远程服务的端口\r\nremote_port = 9000\r\n\r\n[vue_admin]\r\ntype = tcp\r\nlocal_ip = 127.0.0.1\r\nlocal_port = 8001\r\nremote_port = 8001\r\n\r\n[gateway]\r\ntype = tcp\r\nlocal_ip = 127.0.0.1\r\nlocal_port = 8002\r\nremote_port = 8002\r\n```\r\n\r\n上面配置是将这台机器中的3个端口，映射到服务端的3个端口上。\r\n\r\n\r\n\r\n**(2) 启动容器**\r\n\r\n```shell\r\n# 使用 host网络模式\r\ndocker run --name frpc --restart=always \\\r\n--network host \\\r\n-v \u002Froot\u002Ffrp\u002Ffrpc.ini:\u002Fetc\u002Ffrp\u002Ffrpc.ini \\\r\n-d registry.cn-shenzhen.aliyuncs.com\u002Fmogublog_business\u002Ffrpc\r\n\r\n# 使用NAT映射网络模式，配置文件中的local_ip 必须写成宿主机的IP\r\ndocker run --name frpc --restart=always \\\r\n-p 7000:7000 \\\r\n-p 9000:9000 -p 8001:8001 -p 8002:8002 \\\r\n-v \u002Froot\u002Ffrp\u002Ffrpc.ini:\u002Fetc\u002Ffrp\u002Ffrpc.ini \\\r\n-d registry.cn-shenzhen.aliyuncs.com\u002Fmogublog_business\u002Ffrpc\r\n```\r\n\r\n我们再打开 **frp** 的图形化界面，选中：**Proxies → TCP**，可以看到这几个端口都已经注册上来了。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Ffrp内网穿透\u002Ffrp-client.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n**(3) 测试**\r\n\r\n```\r\n# 创建一个nginx测试容器\r\ndocker run --name nginx -p 8000:80 -d nginx:1.27.0\r\n```\r\n\r\n访问公网IP：`http:\u002F\u002F106.53.110.52:9000`，即可看到本地虚拟机部署的页面。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Ffrp内网穿透\u002Ffrp-nginx.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n到这里，使用frp进行内网穿透小主机就完毕了，关于frp的更多玩法，小伙伴们也可以参考frp的官方文档进行体验~\n",{"_path":226,"slug":227,"title":227,"description":228,"excerpt":228,"date":229,"tags":230,"type":15,"cover":231,"content":232},"\u002Fknowledge\u002Fdm数据库安装使用","dm数据库安装使用","一、达梦数据安装使用 1、官网下载安装 达梦数据库安装包 https:\u002F\u002Feco.dameng.com\u002Fdownload\u002F 2、默认安装，直至完成。 3、打开 DM管理工具 就可以直接连接达梦数据库，作用类似navicat软件。 4、如果要创建达梦数据库（本地库），则打开 DM数据库配置助手，在这里面创建数据库实例。在","2024-11-05",[44],"\u002Fknowledge-assets\u002Fdm数据库安装使用\u002Fdm_service.png","一、达梦数据安装使用\r\n\r\n1、官网下载安装 达梦数据库安装包 https:\u002F\u002Feco.dameng.com\u002Fdownload\u002F\r\n\r\n2、默认安装，直至完成。\r\n\r\n3、打开 DM管理工具 就可以直接连接达梦数据库，作用类似navicat软件。\r\n\r\n4、如果要创建达梦数据库（本地库），则打开 DM数据库配置助手，在这里面创建数据库实例。在该助手中可以创建、删除数据库实例。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdm数据库安装使用\u002Fdm_service.png\" style=\"zoom:90%;\" \u002F>\r\n\r\n二、创建数据库实例\r\n\r\n1、打开 DM数据库配置助手，点击创建数据库实例，根据需要自己配置参数，这里要注意的是：**字符串比较大小写敏感**。勾选该选项时，数据库用户名、模式名、表名会严格区分大小写，建议不要勾选。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdm数据库安装使用\u002Fdm_service1.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n2、口令管理中的两个账号需要设置口令（密码），不然使用dm管理工具客户端连接的时候不知道使用什么密码连接，需要先连接这两个其中的账号\u002F密码才能创建另外的用户账号。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdm数据库安装使用\u002Fdm_service2.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n3、达梦数据库创建新用户，可参考该博客：https:\u002F\u002Fblog.csdn.net\u002Fqq_37358909\u002Farticle\u002Fdetails\u002F109609250?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-109609250-blog-121059824.pc_relevant_multi_platform_whitelistv3&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-109609250-blog-121059824.pc_relevant_multi_platform_whitelistv3&utm_relevant_index=1\r\n\r\n简单步骤可按如下：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdm数据库安装使用\u002Fdm_service3.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n\r\n\r\n在达梦数据库中，我们每创建一个用户，就会自动创建一个与用户名相同的模式出来，在模式中是具体的数据库对象，比如视图、表、函数等等。其次，达梦数据库每一个用户支持创建多个模式的，也就是说我创建一个TEST用户，那么它会自动创建一个TEST的模式，我用这个用户连接数据库，那么默认的数据库对象都会在TEST模式，默认的模式在指定对象名时可以忽略模式名的前缀，比如TEST模式的A表，我们查询可以写为select * from TEST.A，或者可以忽略模式名写为select * from A。但如果TEST用户再创建一个TEST1的模式，那我们查TEST1模式中的表B的时候，就必须待模式名，比如：select * from TEST1.B，因为TEST1不是TEST用户的默认模式，所以必须加模式名前缀。\r\n\r\n如果数据库区分大小写，那么连接模式名、表名也必须区分，否则会显示无效的视图或表。\r\n\r\n注意大小写敏感问题，在大小写敏感的数据库实例里面，如果模式名、表名是小写，那么查询的时候模式名、表名需要加双引号，否则默认转成大写；如：ROOT.\"persion\"，不加双引号，会自动将 persion转换成大写。\r\n\r\n检查数据库是否大小写敏感：SELECT CASE_SENSITIVE();    结果1：敏感，结果0：不敏感。达梦数据库大小写敏感初始化实例设置后，不可再修改，网上找不到直接修改的案例，因此只能删除了实例，再创建后设置。\n",{"_path":234,"slug":235,"title":236,"description":237,"excerpt":237,"date":229,"tags":238,"type":15,"cover":26,"content":239},"\u002Fknowledge\u002Fdocker-容器操作教程","docker-容器操作教程","Docker 容器操作教程","Docker 容器操作教程 1 Docker容器 1.1 Docker容器基本操作 1.1.1 创建并启动容器 ​ run 命令解释: ​ (1)命令会检测当前要运行的镜像(centos)在本地存不存在,若不存在他会自动 pull 下来再运行; ​ (2)运行后会启动一个容器, 并且开启一个文件系统, 你可以直接在容器",[103],"# Docker 容器操作教程\r\n\r\n## 1\tDocker容器\r\n\r\n### 1.1\tDocker容器基本操作\r\n\r\n#### 1.1.1\t创建并启动容器\r\n\r\n```shell\r\ndocker run IMAGE [COMMAND] [ARGS...]\r\n示例: docker run centos echo 'hello docker'\r\n```\r\n\r\n​\trun 命令解释:\r\n\r\n​\t(1)命令会检测当前要运行的镜像(centos)在本地存不存在,若不存在他会自动 pull 下来再运行;\r\n\r\n​\t(2)运行后会启动一个容器, 并且开启一个文件系统, 你可以直接在容器内创建文件夹. 运行一个指定的程序, 当程序运行完退出后, 容器也就退出了;\r\n\r\n​\t(3)运行时的容器无法删除, 只能停止后删除, 或者加上 -f 参数强制删除;\r\n\r\n#### 1.1.2\t创建并启动守护式容器\r\n\r\n```shell\r\ndocker run -i -t IMAGE \u002Fbin\u002Fbash\r\n    -i --interactive=true|false 默认是false:允许你对容器内的标准输入 (STDIN) 进行交互\r\n    -t --tty=true|false 默认是false:在新容器内指定一个伪终端或终端\r\n示例: docker run -i -t centos \u002Fbin\u002Fbash\r\n```\r\n\r\n​\t使用` exit `命令退出会关闭守护式容器；退出但不关闭容器按: Ctrl+P和Ctrl+Q\r\n\r\n​\t`\u002Fbin\u002Fbash` 是命令解析器\r\n\r\n#### 1.1.3\t创建并启动自定义名字的容器\r\n\r\n```shell\r\ndocker run --name=自定义名 -it IMAGE \u002Fbin\u002Fbash\r\n示例：docker run --name=demo -it centos \u002Fbin\u002Fbash\r\n```\r\n\r\n#### 1.1.4\t容器和宿主机目录映射\r\n\r\n即共享目录，创建共享关系后，在宿主机可CRUD共享目录的内容，在容器中也可以看到相应的变化，两者实际上操作的是同一个目录文件。\r\n\r\n```shell\r\ndocker run --name=自定义名 -it -v 宿主机路径:容器路径 IMAGE \u002Fbin\u002Fbash\r\n示例： 将宿主机的目录\u002Froot\u002Ftest和容器的目录\u002Fusr\u002Flocal\u002Ftest关联\r\ndocker run --name=demo -it -v \u002Froot\u002Ftest:\u002Fusr\u002Flocal\u002Ftest centos \u002Fbin\u002Fbash\r\n```\r\n\r\n#### 1.1.5\t使容器具有真正的root权限\r\n\r\n默认创建的容器并不会拥有真正的root权限，当进行一些特殊操作时无法进行，创建容器时可指定`--privileged=true`参数，让其具备真正的root权限。进入容器时，可通过root方式进入：`docker exec -it --user root 容器名 bash`\r\n\r\n```shell\r\ndocker run --name=自定义名 -it --privileged=true IMAGE \u002Fbin\u002Fbash\r\n示例：docker run --name=demo -it --privileged=true centos \u002Fbin\u002Fbash\r\n```\r\n\r\n#### 1.1.6\t重新启动停止的容器\r\n\r\n```shell\r\ndocker start [-i] 容器名\r\n```\r\n\r\n注： 创建容器的时候，如果不指定 -i -t（即进入容器），那么使用 docker start 命令启动容器，将一闪而过，容器不会一直在后台运行。\r\n\r\n```shell\r\n示例：docker run --name=c1 centos #创建并启动容器且命名为c1\r\n​\t docker start c1             #启动c1容器\r\n​\t docker ps                   #c1并没有在后台运行\r\n-------------------------------------------------------\r\n示例：docker run --name=c2 -i -t centos #创建并启动容器且命名为c2。然后再exit退出\r\n​\t docker start c2\t\t\t\t   #重新启动c2容器\r\n​\t docker ps\t\t\t\t\t\t   #可以看到后台在运行的c2容器\r\n```\r\n\r\n**docker start 启动容器 跟创建容器时指定的参数有关联**。\r\n\r\n#### 1.1.7\t删除停止的容器\r\n\r\n```shell\r\ndocker rm 容器名\u002F容器唯一标识\r\n```\r\n\r\n只能删除停止的容器,不能删除正在运行中的容器.\r\n\r\n#### 1.1.8\t查看容器\r\n\r\n```shell\r\ndocker ps [-a] [-l]\r\n    -a:表示列举所有的容器\r\n    -l :表示列举最近创建的容器\r\n```\r\n\r\n默认情况,容器在运行之后就停止了,docker ps不跟任何参数，只是显示正在运行的容器。\r\n\r\n#### 1.1.9\t查看容器详细信息\r\n\r\n```shell\r\ndocker inspect [容器名字|容器唯一标识]\r\n```\r\n\r\n#### 1.1.10\t从Docker中拷贝文件到宿主机\r\n\r\n```shell\r\n#将mysql8.0容器中的\u002Fvar\u002Flib\u002Fmysql 目录拷贝到宿主机的当前目录.\r\ndocker cp mysql8.0:\u002Fvar\u002Flib\u002Fmysql .\r\n```\r\n\r\n#### 1.1.11\t从宿主机拷贝文件到docker\r\n\r\n```shell\r\n# 拷贝宿主机 \u002Fdata\u002Fmysql\u002Fbinlog 目录到 mysql8.0 容器的 \u002Fdata\u002Flog 目录中\r\ndocker cp \u002Fdata\u002Fmysql\u002Fbinlog mysql8.0: \u002Fdata\u002Flog\r\n```\r\n\r\n### 1.2\t守护式容器\r\n\r\n上面大多是容器都是在创建好之后就关闭了.在真实的案例中,我们需要长期运行的容器提供服务.这就是docker的守护式容器.\r\n\r\n特点: 能长期运行， 没有交互式会话，适合运行应用程序和服务.\r\n\r\n#### 1.2.1\t以守护形式创建容器\r\n\r\n```shell\r\ndocker run -i -t IMAGE \u002Fbin\u002Fbash\r\n示例: docker run -i -t centos \u002Fbin\u002Fbash\r\n```\r\n\r\n退出但不关闭容器:Ctrl+P和Ctrl+Q。使用 exit 命令退出会关闭守护式容器。\r\n\r\n#### 1.2.2\t进入到运行中的容器\r\n\r\n**方式一**：\r\n\r\n```shell\r\ndocker attach 容器名\u002F容器唯一标识\r\n```\r\n\r\n使用exit退出，会关闭该容器，包括启动该容器的所有进程。\r\n\r\n**方式二**（**推荐**）：\r\n\r\n```shell\r\ndocker exec -it 容器名\u002F容器唯一标识 bash\r\n```\r\n\r\n使用`exit`退出，不会关闭容器。\r\n\r\n#### 1.2.3\t使用root用户进入容器\r\n\r\n有一些操作需要拥有root权限才能进行，可以使用如下方式进入：\r\n\r\n```shell\r\ndocker exec -it --user root 容器名\u002F容器唯一标识 bash\r\n```\r\n\r\n#### 1.2.4\t查看容器日志\r\n\r\n```shell\r\ndocker logs [-f] [-t] [--tail] 容器名\r\n\t-f --follow=true|false 默认为false 一直跟踪日志的变化,并返回结果\r\n\t-t --timestamps=true|false 默认为false 在返回的结果上加上时间戳\r\n\t--tail = “all” 返回后几行的日志数据.\r\n示例：docker logs -f -t --tail=\"all\" demo\r\n```\r\n\r\n#### 1.2.5\t查看容器内进程\r\n\r\n```shell\r\ndocker top 容器名\u002F容器唯一标识\r\n```\r\n\r\n#### 1.2.6\t在运行中的容器内启动新进程进入 (推荐进入容器的方式)\r\n\r\n```shell\r\ndocker exec [-d] [-i] [-t] 容器名 [COMMAND] [ARG...]\r\n示例:docker exec -i -t dc1 \u002Fbin\u002Fbash\r\n```\r\n\r\nps：(1) 该容器此前必须启动了，才能使用该命令开启新进程进入；\r\n\r\n​\t\t(2) 退出时使用`exit`，只会关闭当前的进程，不会关闭该容器。使用 Ctrl+P和Ctrl+Q不会关闭该进程，也就是该容器多开启一个进程。\r\n\r\n#### 1.2.7\t停止守护式容器\r\n\r\n```shell\r\ndocker stop 容器名\u002F容器唯一标识  #发送一个信号给容器,等待容器的关闭.\r\ndocker kill 容器名\u002F容器唯一标识  #直接停止容器.\r\n```\r\n\r\n## 2\t部署静态网站\r\n\r\n### 2.1\t设置容器的端口映射\r\n\r\n```shell\r\ndocker run [-P] [-p] [...] IMAGE \u002Fbin\u002Fbash\r\n\t-P , --publish-all=true|false 默认为false :将为容器所有暴露的端口进行映射.\r\n      示例:docker run -P -i -t centos \u002Fbin\u002Fbash\r\n\r\n    -p, --publish=[] :给指定的端口进行映射\r\n       方式一:containerPort\r\n          示例:docker run -p 80 -i -t centos \u002Fbin\u002Fbash\r\n          这种映射方式，停止该容器，当再次启动的时候，对应的宿主机端口会发生变化\r\n       方式二:hostPort:containerPort\r\n          示例:docker run -p 8080:80 -i -t centos \u002Fbin\u002Fbash\r\n          绑定宿主机的8080端口映射到容器的80端口。停止容器，再启动容器时端口不会发生改变\r\n```\r\n\r\n### 2.2\tNginx部署流程\r\n\r\n(1)创建映射80端口的交互式容器\r\n\r\n(2)安装Nginx\r\n\r\n(3)安装文本编辑器vim\r\n\r\n(4)创建静态页面\r\n\r\n(5)修改Nginx配置文件\r\n\r\n(6)运行Nginx\r\n\r\n(7)验证网站访问\r\n\r\n#### 2.2.1 Nginx部署步骤\r\n\r\n(1)创建一个守护式容器,并绑定宿主机的8080端口，映射到容器的80端口.\r\n\r\n```shell\r\ndocker run -p 8080:80 --name=webnew -it centos \u002Fbin\u002Fbash\r\n```\r\n\r\n(2)进入容器后,需要安装nginx和vim,执行如下命令:\r\n\r\n```shell\r\nyum install -y epel-release\r\nyum install -y nginx\r\n```\r\n\r\n(3)在容器内部,进入到\u002Fusr\u002Fshare\u002Fnginx\u002Fhtml 目录,修改index.html文件\r\n\r\n```shell\r\nvim index.html\r\n```\r\n\r\n(4)运行nginx命令,启动服务\r\n\r\n```shell\r\n\u002Fusr\u002Fsbin\u002Fnginx #启动nginx服务\r\n```\r\n\r\n(5)Ctrl+P和Ctrl+Q退出容器\r\n\r\n(6)在宿主机上使用curl命令查看是否能访问\r\n\r\n```shell\r\ncurl http:\u002F\u002F127.0.0.1:8080\u002Findex.html\r\n```\r\n\r\n**外网访问**：`宿主机ip:8080\u002Findex.html`\r\n\r\n\r\n\r\n#### 2.2.2 其他问题\r\n\r\n(1)使用`docker inspect 容器名`可以查看容器的ip地址.\r\n\r\n(2)使用容器的ip也是能访问到该静态页面的.\r\n\r\n(3)使用`docker stop 容器名` 关闭容器.\r\n\r\n(4)使用`docker start 容器名` 启动容器.\r\n\r\n(5)使用`docker top 容器名` 发现重新启动容器后,nginx服务并没有重新启动.\r\n\r\n(6)我们可以使用`docker exec 容器名 nginx `来启动容器中的nginx服务. \r\n\r\n```shell\r\n示例：docker exec -it web \u002Fusr\u002Fsbin\u002Fnginx\r\n```\r\n\r\n\r\n\r\n## 3\tDocker的镜像和仓库\r\n\r\n镜像是容器的基石\r\n\r\n### 3.1 列出镜像\r\n\r\n```shell\r\ndocker images [OPTIONS] [REPOSITORY]\r\n    \r\n  OPTIONS:\r\n    -a, --all=false :表示列举出所有的镜像.默认并不显示中间层的镜像.\r\n\t-f, --filter=[] :表示添加过滤条件.\r\n\t--no-trunc=false:表示对信息进行截断.默认情况是会截断镜像的唯一id的.\r\n\t-q, --quiet=false:表示值显示镜像的唯一id\r\n  REPOSITORY 仓库: 是一切镜像的集合.\r\n  REGISTRY 注册仓库:包含REPOSITORY 的仓库.\r\n  TAG 标签:我们之前运行的centos默认使用的是lastest的标签.仓库名+镜像名就能唯一确定一个镜像.\r\n如果使用docker images -a 看到没有仓库名和标签名的其实是中间层镜像.\r\n```\r\n\r\n### 3.2 查看镜像\r\n\r\n```shell\r\ndocker inspect [OPTIONS] CONTAINER|IMAGE [CONTAINER|IMAGE...]\r\n示例:docker inspect \r\n```\r\n\r\n### 3.3 删除镜像\r\n\r\n```shell\r\ndocker rmi [OPTIONS] IMAGE [IMAGE...]\r\n    \r\n  OPTIONS:\r\n\t-f, --force=false :表示强制删除镜像.\r\n\t--no-proune=false :会保留未被打标签的父镜像.\r\n```\r\n\r\n### 3.4 删除对应仓库所有的镜像\r\n\r\n```shell\r\ndocker rmi  $(docker images -q centos)\r\n```\r\n\r\n\r\n\r\n## 4\t安装mysql\r\n\r\n### 4.1 下载mysql 镜像\r\n\r\n进入docker hub官网：https:\u002F\u002Fhub.docker.com\u002F\r\n\r\n```shell\r\n#下载mysql镜像\r\ndocker pull mysql  #默认下载最新的版本\r\ndocker pull mysql:8.0.31  #指定版本下载\r\n```\r\n\r\n### 4.2 创建并启动容器\r\n\r\n```shell\r\ndocker run -p 3306:3306 --name mysql \\\r\n-v \u002Fdata\u002Fmysql\u002Flog:\u002Fvar\u002Flog\u002Fmysql \\\r\n-v \u002Fdata\u002Fmysql\u002Fdata:\u002Fvar\u002Flib\u002Fmysql \\\r\n-v \u002Fdata\u002Fmysql\u002Fconf:\u002Fetc\u002Fmysql \\\r\n-e MYSQL_ROOT_PASSWORD=root \\\r\n-d mysql:5.7\r\n\r\n#参数说明：\r\n#\tp 3306:3306 :将主机3306端口映射到容器的3306端口\r\n#    -v \u002Fmydata\u002Fmysql\u002Flog:\u002Fvar\u002Flog\u002Fmysql ：将日志文件挂载到主机\r\n#    -v \u002Fmydata\u002Fmysql\u002Fdata:\u002Fvar\u002Flib\u002Fmysql ：将配置文件挂载到主机\r\n#    -v \u002Fmydata\u002Fmysql\u002Fconf:\u002Fetc\u002Fmysql : 将配置文件挂载到主机\r\n#    -e MYSQL_ROOT_PASSWORD=root : 初始化root用户的密码\r\n#    -d ：指定容器后台启动\r\n#\t mysql:5.7   ：指定镜像\r\n\r\n# --restart=always 当Docker 重启时，容器会自动启动\r\ndocker run --restart=always --name mysql \\\r\n-v \u002Fdata\u002Fmysql\u002Fcnf:\u002Fetc\u002Fmysql \\\r\n-v \u002Fdata\u002Fmysql\u002Fdata:\u002Fvar\u002Flib\u002Fmysql \\\r\n-v \u002Fdata\u002Fmysql\u002Flog:\u002Fvar\u002Flog \\\r\n-v \u002Fdata\u002Fmysql\u002Fmysql-files:\u002Fvar\u002Flib\u002Fmysql-files \\\r\n-p 3306:3306 \\\r\n-e MYSQL_ROOT_PASSWORD='root' \\\r\n-d mysql:5.7\r\n\r\n#上面的挂载启动只有5.7版本成功，8.0版本挂载失败，暂时找不到原因\r\ndocker run -itd --restart=always --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root mysql:8.0.31\r\ndocker run -itd --restart=always --name mysql -p 3307:3306 -e MYSQL_ROOT_PASSWORD='root' mysql:5.7\r\n```\r\n\r\n启动后，查看容器运行状态\r\n\r\n```shell\r\ndocker ps\r\n```\r\n\r\n### 4.3\t配置mysql远程连接\r\n\r\n#### 4.3.1\t进入镜像\r\n\r\n```shell\r\ndocker exec -it mysql8.0 bash\r\n```\r\n\r\n#### 4.3.2\t登录mysql\r\n\r\n```shell\r\nmysql -uroot -p\r\n```\r\n\r\n#### 4.3.3\t切换数据库\r\n\r\n```sql\r\nuse mysql;\r\n```\r\n\r\n#### 4.3.4\t设置远程访问\r\n\r\n```sql\r\n#用户对应的 host 字段为%，表示任意ip地址可访问(即远程访问)\r\n#查看远程连接用户信息\r\nselect host,user,plugin from user;\r\n#删除多余的信息\r\ndelete from user where user ='root' and host='%';\r\n#设置所有root都可以远程访问\r\nupdate user set host='%' where user ='root';\r\n#刷新设置，使之生效\r\nFLUSH PRIVILEGES;\r\n\r\n#mysql8.0更新密码，密码太简单容易被黑客攻击，如果在创建容器时没有设置复杂密码，\r\n#可以按照以下方式更新密码\r\n#首先清除旧密码\r\nupdate user set authentication_string='' where user='root';\r\n#查看是否已经清除密码\r\nselect host,user,plugin,authentication_string from user;\r\n#设置新的密码\r\nALTER USER \"root\"@\"%\" IDENTIFIED BY \"!QAZ2wsx#EDC\";\r\n#退出，重启容器即可\r\n```\r\n\r\n## 5\t安装redis\r\n\r\n### 5.1\t下载redis镜像\r\n\r\n```shell\r\ndocker pull redis\r\n```\r\n\r\n### 5.2\t创建实例并启动\r\n\r\n```shell\r\nmkdir -p \u002Fdata\u002Fredis\u002Fconf\r\n#redis镜像默认是没有redis配置文件的，配置挂载目录的时候需要先\r\n#创建一个redis.conf文件，否则会默认把最后一级目录当成配置文件\r\ntouch \u002Fdata\u002Fredis\u002Fconf\u002Fredis.conf\r\n\r\ndocker run -p 6379:6379 --name redis \\\r\n-v \u002Fdata\u002Fredis\u002Fdata:\u002Fdata \\\r\n-v \u002Fdata\u002Fredis\u002Fconf\u002Fredis.conf:\u002Fetc\u002Fredis\u002Fredis.conf \\\r\n-d redis redis-server \u002Fetc\u002Fredis\u002Fredis.conf\r\n\r\n#参数说明：\r\n#\t-v \u002Fdata\u002Fredis\u002Fdata:\u002Fdata  ：配置挂载目录\r\n#\t-v \u002Fdata\u002Fredis\u002Fconf\u002Fredis.conf:\u002Fetc\u002Fredis\u002Fredis.conf \\  ：配置文件挂载目录\r\n#\t-d ：指定容器后台启动\r\n#\tredis  ：指定镜像名\r\n#\tredis-server \u002Fetc\u002Fredis\u002Fredis.conf  ：指定redis配置文件启动\r\n```\r\n\r\n### 5.3\t测试redis\r\n\r\n```shell\r\n#先进入redis容器\r\ndocker exec -it redis bash\r\n#进入redis客户端 测试\r\nredis-cli\r\n#退出\r\nexit\r\n#直接进入redis客户端\r\ndocker exec -it redis redis-cli\r\n```\r\n\r\n### 5.4\t修改配置redis.conf文件\r\n\r\n```shell\r\nvi redis.conf\r\n#因为镜像中的redis默认配置文件是空的，因此redis的值都只存储在内存中，每次重启容器数据都会丢失，因此需要配置持久化方式，在redis.conf配置文件中写入：appendonly yes，然后重启容器即可。\r\nappendonly yes\r\n```\r\n\r\n\r\n\r\n\r\n",{"_path":241,"slug":242,"title":236,"description":237,"excerpt":237,"date":229,"tags":243,"type":15,"cover":26,"content":239},"\u002Fknowledge\u002Fdocker容器操作教程","docker容器操作教程",[103],{"_path":245,"slug":246,"title":247,"description":248,"excerpt":248,"date":229,"tags":249,"type":15,"cover":250,"content":251},"\u002Fknowledge\u002Fdocker环境部署","docker环境部署","Docker环境部署","Docker环境部署 [TOC] 1 Docker环境安装 1.1 Docker环境安装 — 基于CentOS Docker官方要求 CentOS 操作系统内核必须在 3.10 以上。可以使用以下命令来查看当前系统的内核版本： 1.1.1 Docker在线安装 （1）更新 yum 仓库，确保 yum 包都是最新版本 （",[103,124],"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fwsl-install.png","# Docker环境部署\r\n\r\n[TOC]\r\n\r\n# 1\tDocker环境安装\r\n\r\n## 1.1\tDocker环境安装 — 基于CentOS\r\n\r\nDocker官方要求 CentOS 操作系统内核必须在 3.10 以上。可以使用以下命令来查看当前系统的内核版本： ```uname -r```\r\n\r\n### 1.1.1\tDocker在线安装\r\n\r\n（1）更新 yum 仓库，确保 yum 包都是最新版本\r\n\r\n```shell\r\nyum update\r\n```\r\n\r\n（2）查看是否有安装 docker，若有则将其删除\r\n\r\n```shell\r\nyum list installed | grep docker\r\nyum remove docker...  #如果有的话则删除对应的包\r\n```\r\n\r\n（3）安装需要的软件依赖包，yum-util 提供 yum-config-manager 功能，另外两个是 devicemapper 驱动依赖\r\n\r\n```shell\r\nyum install -y yum-utils device-mapper-persistent-data lvm2\r\n```\r\n\r\n（4）设置 yum 源\r\n\r\n```shell\r\nyum-config-manager --add-repo http:\u002F\u002Fmirrors.aliyun.com\u002Fdocker-ce\u002Flinux\u002Fcentos\u002Fdocker-ce.repo\r\n```\r\n\r\n（5）查看仓库中所有 docker 版本，选择你需要的版本安装\r\n\r\n```shell\r\nyum list docker-ce --showduplicates | sort -r\r\n```\r\n\r\n（6）安装 docker\r\n\r\n```shell\r\nyum install -y docker-ce\r\n```\r\n\r\n（7）设置 docker 开机自动启动\r\n\r\n```shell\r\nsystemctl start docker # 启动 docker 服务端\r\nsystemctl enable docker # 启用 docker 服务开机自启\r\n```\r\n\r\n（8）校验 docker 是否启动成功\r\n\r\n```shell\r\ndocker version\r\ndocker -v\r\n```\r\n\r\n\r\n\r\n### 1.1.2\t离线安装Docker\r\n\r\n（1）官网下载安装包，[下载地址](https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fstatic\u002Fstable\u002Fx86_64\u002F)：https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fstatic\u002Fstable\u002Fx86_64\u002F\r\n\r\n（2）上传压缩包到服务器上，如```\u002Fusr\u002Flocal\u002Fsoftware```目录，```docker-26.1.0.tgz```，并解压: \r\n\r\n```shell\r\ntar -zxvf docker-26.1.0.tgz\r\n```\r\n\r\n（3）进入到刚才解压的docer目录\r\n\r\n```shell\r\ncd docker\r\n\r\n# 给整个docker目录授权\r\nchown -R root:root ..\u002Fdocker\r\n```\r\n\r\n（4）移动到```\u002Fusr\u002Fbin```目录下，或者也可以设置环境变量或软链接\r\n\r\n```shell\r\nmv .\u002F* \u002Fusr\u002Fbin\u002F\r\n# 或\r\nexport DOCKER_HOME=\u002Fusr\u002Flocal\u002Fsoftware\u002Fdocker\r\nexport PATH=$PATH:$DOCKER_HOME\r\n```\r\n\r\n（5）创建server服务文件，控制docker的启停\r\n\r\n```shell\r\nvi \u002Fetc\u002Fsystemd\u002Fsystem\u002Fdocker.service\r\n```\r\n\r\n文件内容：\r\n\r\n```shell\r\n[Unit]\r\nDescription=Docker Application Container Engine\r\nDocumentation=https:\u002F\u002Fdocs.docker.com\r\n\r\n[Service]\r\nType=notify\r\nExecStart=\u002Fusr\u002Fbin\u002Fdockerd\r\n# 高版本如28版本，需要关闭 --userland-proxy=false，否则可能会报错\r\n# ExecStart=\u002Fusr\u002Fbin\u002Fdockerd --userland-proxy=false\r\nExecReload=\u002Fbin\u002Fkill -s HUP $MAINPID\r\nRestart=always\r\nStartLimitBurst=3\r\nStartLimitInterval=60s\r\n\r\n[Install]\r\nWantedBy=multi-user.target\r\n```\r\n\r\n（6）重载配置\r\n\r\n```shell\r\nsystemctl daemon-reload\r\n```\r\n\r\n（6）设置开机自启动\r\n\r\n```shell\r\nsystemctl enable docker.service\r\n```\r\n\r\n（6）查看版本\r\n\r\n```shell\r\ndocker version\r\ndocker -v\r\n```\r\n\r\n\r\n\r\n### 1.1.3\tDocker Compose在线安装\r\n\r\n（1）下载\r\n\r\n方式一：从阿里云下载\r\n\r\n```shell\r\nsudo curl -L \"http:\u002F\u002Fmirrors.aliyun.com\u002Fdocker-toolbox\u002Flinux\u002Fcompose\u002F1.9.0\u002Fdocker-compose-$(uname -s)-$(uname -m)\" -o \u002Fusr\u002Flocal\u002Fbin\u002Fdocker-compose\r\n```\r\n\r\n方式二：从compose官网，即github下载\r\n\r\n```shell\r\ncurl -SL https:\u002F\u002Fgithub.com\u002Fdocker\u002Fcompose\u002Freleases\u002Fdownload\u002Fv2.18.0\u002Fdocker-compose-linux-x86_64 -o \u002Fusr\u002Flocal\u002Fbin\u002Fdocker-compose\r\n```\r\n\r\n（2）赋予执行权限\r\n\r\n```shell\r\nsudo chmod +x \u002Fusr\u002Flocal\u002Fbin\u002Fdocker-compose\r\n```\r\n\r\n（3）创建软链接，可以不建\r\n\r\n```shell\r\nsudo ln -s \u002Fusr\u002Flocal\u002Fbin\u002Fdocker-compose \u002Fusr\u002Fbin\u002Fdocker-compose\r\n```\r\n\r\n（4）查看版本\r\n\r\n```shell\r\ndocker-compose -v\r\ndocker-compose version\r\n```\r\n\r\n**注意**： 对于 alpine，需要以下依赖包： py-pip，python-dev，libffi-dev，openssl-dev，gcc，libc-dev，和 make。\r\n\r\n\r\n\r\n### 1.1.4\tDocker Compose离线安装\r\n\r\n（1）官网下载：https:\u002F\u002Fgithub.com\u002Fdocker\u002Fcompose\u002Freleases\r\n\r\n（2）上传到服务器，并移动\r\n\r\n```shell\r\nmv docker-compose-linux-x86_64 \u002Fusr\u002Flocal\u002Fbin\u002Fdocker-compose\r\n```\r\n\r\n（3）赋予执行权限\r\n\r\n```shell\r\nchmod +x \u002Fusr\u002Flocal\u002Fbin\u002Fdocker-compose\r\n```\r\n\r\n（4）查看版本\r\n\r\n```shell\r\ndocker-compose -v\r\ndocker-compose version\r\n```\r\n\r\n\r\n\r\n## 1.2\t配置Docker国内镜像源\r\n\r\n创建目录\r\n\r\n```shell\r\nsudo mkdir -p \u002Fetc\u002Fdocker\r\n```\r\n\r\n指定阿里镜像源：\r\n\r\n```shell\r\nsudo tee \u002Fetc\u002Fdocker\u002Fdaemon.json \u003C\u003C-'EOF'\r\n{\r\n  \"registry-mirrors\": [\"https:\u002F\u002Fjsj9yxoq.mirror.aliyuncs.com\"]\r\n}\r\nEOF\r\n```\r\n\r\n配置多个镜像源：\r\n\r\n```shell\r\nsudo tee \u002Fetc\u002Fdocker\u002Fdaemon.json \u003C\u003C-'EOF'\r\n{\r\n  \"registry-mirrors\": [\r\n  \t\"https:\u002F\u002Fjsj9yxoq.mirror.aliyuncs.com\",\r\n    \"https:\u002F\u002Fdocker.registry.cyou\",\r\n    \"https:\u002F\u002Fdocker-cf.registry.cyou\",\r\n    \"https:\u002F\u002Fdockercf.jsdelivr.fyi\",\r\n    \"https:\u002F\u002Fdocker.jsdelivr.fyi\",\r\n    \"https:\u002F\u002Fdockertest.jsdelivr.fyi\",\r\n    \"https:\u002F\u002Fmirror.aliyuncs.com\",\r\n    \"https:\u002F\u002Fdockerproxy.com\",\r\n    \"https:\u002F\u002Fmirror.baidubce.com\",\r\n    \"https:\u002F\u002Fdocker.m.daocloud.io\",\r\n    \"https:\u002F\u002Fdocker.nju.edu.cn\",\r\n    \"https:\u002F\u002Fdocker.mirrors.sjtug.sjtu.edu.cn\",\r\n    \"https:\u002F\u002Fdocker.mirrors.ustc.edu.cn\",\r\n    \"https:\u002F\u002Fmirror.iscas.ac.cn\",\r\n    \"https:\u002F\u002Fdocker.rainbond.cc\"\r\n  ]\r\n}\r\nEOF\r\n```\r\n\r\n重新加载，并重启Docker\r\n\r\n```shell\r\nsudo systemctl daemon-reload\r\nsudo systemctl restart docker\r\n```\r\n\r\n\r\n\r\n## 1.3\tDocker环境离线安装—Rocky Linux\r\n\r\n（1）官网下载安装包，[下载地址](https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fstatic\u002Fstable\u002Fx86_64\u002F)：https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fstatic\u002Fstable\u002Fx86_64\u002F\r\n\r\n（2）上传压缩包到服务器上，如```\u002Fusr\u002Flocal\u002Fsoftware```目录，```docker-29.1.5.tgz```，并解压: \r\n\r\n```shell\r\ntar -zxvf docker-29.1.5.tgz\r\n```\r\n\r\n（3）进入到刚才解压的docer目录\r\n\r\n```shell\r\n# 给整个docker目录授权\r\nchown -R root:root docker\r\n\r\ncd docker\r\n```\r\n\r\n（4）移动到```\u002Fusr\u002Fbin```目录下，或者也可以设置环境变量或软链接\r\n\r\n```shell\r\nmv .\u002F* \u002Fusr\u002Fbin\u002F\r\n# 或\r\nvi \u002Fetc\u002Fprofile\r\n# 添加如下\r\nexport DOCKER_HOME=\u002Fhome\u002Ftools\u002Fdocker\r\nexport PATH=$PATH:$DOCKER_HOME\r\n```\r\n\r\n（5）创建server服务文件，控制docker的启停\r\n\r\n```shell\r\nvi \u002Fetc\u002Fsystemd\u002Fsystem\u002Fdocker.service\r\n```\r\n\r\n文件内容：\r\n\r\n```shell\r\n[Unit]\r\nDescription=Docker Application Container Engine\r\nDocumentation=https:\u002F\u002Fdocs.docker.com\r\n\r\n[Service]\r\nType=notify\r\nEnvironment=\"PATH=\u002Fhome\u002Ftools\u002Fdocker:\u002Fusr\u002Flocal\u002Fsbin:\u002Fusr\u002Flocal\u002Fbin:\u002Fusr\u002Fsbin:\u002Fusr\u002Fbin:\u002Fsbin:\u002Fbin\"\r\n# 高版本如28版本，需要关闭 --userland-proxy=false，否则可能会报错\r\nExecStart=\u002Fhome\u002Ftools\u002Fdocker\u002Fdockerd --userland-proxy=false\r\nExecReload=\u002Fbin\u002Fkill -s HUP $MAINPID\r\nRestart=always\r\nStartLimitBurst=3\r\nStartLimitInterval=60s\r\n\r\n[Install]\r\nWantedBy=multi-user.target\r\n```\r\n\r\n（6）重载配置\r\n\r\n```shell\r\nsystemctl daemon-reload\r\n```\r\n\r\n（7）设置SELinux\r\n\r\n永久解决SELinux问题：\r\n\r\n- 选项A：将SELinux设置为permissive模式（推荐测试环境）\r\n\r\n  ```shell\r\n  # 编辑SELinux配置文件\r\n  sudo vi \u002Fetc\u002Fselinux\u002Fconfig\r\n  # 修改为：\r\n  SELINUX=permissive\r\n  # 重启系统或执行\r\n  sudo setenforce 0\r\n  ```\r\n\r\n- 选项B：创建SELinux策略\r\n\r\n  ```shell\r\n  # 查看SELinux拒绝日志\r\n  sudo ausearch -m avc -ts recent | grep dockerd\r\n  # 如果有拒绝记录，创建策略\r\n  sudo grep dockerd \u002Fvar\u002Flog\u002Faudit\u002Faudit.log | sudo audit2allow -M mydocker\r\n  # 查看生成的.te文件，确认没问题后安装\r\n  sudo semodule -i mydocker.pp\r\n  ```\r\n\r\n```shell\r\n# 查看SELinux当前状态\r\ngetenforce\r\n# 如果是Enforcing，临时禁用测试\r\nsudo setenforce 0\r\n# 重新启用SELinux\r\nsudo setenforce 1\r\n```\r\n\r\n（8）启动\r\n\r\n```shell\r\n# 启动\r\nsystemctl start docker\r\n# 重启\r\nsystemctl restart docker\r\n# 设置开机启动\r\nsystemctl enable docker.service\r\n```\r\n\r\n（9）查看版本\r\n\r\n```shell\r\ndocker version\r\ndocker -v\r\n```\r\n\r\n## 1.4\tDocker环境在线安装—Rocky Linux\r\n\r\n步骤一：安装必要依赖并添加 Docker 官方源\r\n\r\n首先，需要安装 `yum-utils` 工具集并添加 Docker 的官方软件仓库。\r\n\r\n1. 更新系统软件包并安装 `yum-utils`：\r\n\r\n   ```shell\r\n   sudo dnf update -y\r\n   sudo dnf install -y yum-utils\r\n   ```\r\n\r\n2. 添加 Docker 官方仓库。Rocky Linux 与 CentOS 高度兼容，因此使用 CentOS 的仓库即可。\r\n\r\n   ```shell\r\n   sudo yum-config-manager --add-repo https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fcentos\u002Fdocker-ce.repo\r\n   ```\r\n\r\n3. *(可选但推荐)* 如果你在中国大陆地区，使用国内镜像源可以大幅提升下载速度。你可以选择使用阿里云镜像源：\r\n\r\n   ```shell\r\n   sudo dnf config-manager --add-repo https:\u002F\u002Fmirrors.aliyun.com\u002Fdocker-ce\u002Flinux\u002Fcentos\u002Fdocker-ce.repo\r\n   ```\r\n\r\n   或者使用由 `linuxmirrors.cn` 提供的一键脚本自动配置。\r\n\r\n步骤二：安装 Docker Engine\r\n\r\n依赖和仓库都准备好后，就可以安装 Docker 及其核心组件了。建议安装所有官方推荐的插件，以获得最佳体验。\r\n\r\n1. 安装最新版本的 Docker Engine、CLI 和 containerd：\r\n\r\n   ```shell\r\n   sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin\r\n   ```\r\n\r\n步骤三：启动并验证 Docker 服务\r\n\r\n安装完成后，需要启动 Docker 守护进程，并设置其开机自启。\r\n\r\n1. 启动 Docker 服务并设置开机自启：\r\n\r\n   ```shell\r\n   sudo systemctl enable docker --now\r\n   ```\r\n\r\n2. 验证 Docker 是否正确安装且状态为 `active (running)`。\r\n\r\n   ```shell\r\n   sudo systemctl status docker\r\n   ```\r\n\r\n3. 通过运行一个简单的 `hello-world` 容器来最终验证：\r\n\r\n   ```shell\r\n   sudo docker run hello-world\r\n   ```\r\n\r\n   如果看到 \"Hello from Docker!\" 的提示信息，则说明安装成功。\r\n\r\n\r\n\r\n## 1.5\tWindow系统安装\r\n\r\n安装步骤\r\n\r\n### 1.5.1\t启用 WSL2\r\n\r\n  以管理员身份打开 PowerShell，执行：\r\n\r\n```shell\r\nwsl --install\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fwsl-install.png\" style=\"zoom:67%;\" \u002F> \r\n\r\n 重启电脑。重启后 Ubuntu 会自动继续安装，设置用户名密码即可。\r\n\r\n  如果已经安装过 WSL，更新到 WSL2：\r\n\r\n ```shell\r\n wsl --update\r\n ```\r\n\r\n### 1.5.2\t安装 Docker Desktop\r\n\r\n  下载地址：\r\n  https:\u002F\u002Fwww.docker.com\u002Fproducts\u002Fdocker-desktop\u002F\r\n\r\n要下载适合自己架构的版本。如果实在不知道自己系统架构的话，直接用命令行安装：\r\n\r\n```shell\r\nwinget install Docker.DockerDesktop\r\n```\r\n\r\n报错：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fwsl-install-2.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n电脑打开控制面板：然后勾选Hype-V，然后重启电脑即可。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fwsl-install-3.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n\r\n\r\n### 1.5.3\t验证 Docker\r\n\r\n  打开 PowerShell 或 Git Bash：\r\n\r\n```shell\r\ndocker --version\r\ndocker compose version\r\n```\r\n\r\n  看到版本号就说明装好了。\r\n\r\n### 1.5.4\t配置国内镜像源\r\n\r\n```shell\r\n{\r\n\t\"builder\": {\r\n\t\t\"gc\": {\r\n\t\t\t\"defaultKeepStorage\": \"20GB\",\r\n\t\t\t\"enabled\": true\r\n\t\t}\r\n\t},\r\n\t\"experimental\": false,\r\n\t\"fixed-cidr-v6\": \"\",\r\n\t\"ipv6\": false,\r\n\t\"registry-mirrors\": [\r\n\t\t\"https:\u002F\u002Fjsj9yxoq.mirror.aliyuncs.com\",\r\n\t\t\"https:\u002F\u002Fdocker.registry.cyou\",\r\n\t\t\"https:\u002F\u002Fdocker-cf.registry.cyou\",\r\n\t\t\"https:\u002F\u002Fdockercf.jsdelivr.fyi\",\r\n\t\t\"https:\u002F\u002Fdocker.jsdelivr.fyi\",\r\n\t\t\"https:\u002F\u002Fdockertest.jsdelivr.fyi\",\r\n\t\t\"https:\u002F\u002Fmirror.aliyuncs.com\",\r\n\t\t\"https:\u002F\u002Fdockerproxy.com\",\r\n\t\t\"https:\u002F\u002Fmirror.baidubce.com\",\r\n\t\t\"https:\u002F\u002Fdocker.m.daocloud.io\",\r\n\t\t\"https:\u002F\u002Fdocker.nju.edu.cn\",\r\n\t\t\"https:\u002F\u002Fdocker.mirrors.sjtug.sjtu.edu.cn\",\r\n\t\t\"https:\u002F\u002Fdocker.mirrors.ustc.edu.cn\",\r\n\t\t\"https:\u002F\u002Fmirror.iscas.ac.cn\",\r\n\t\t\"https:\u002F\u002Fdocker.rainbond.cc\"\r\n\t]\r\n}\r\n```\r\n\r\n\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fdocker-engine.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n# 2\t安装MySQL\r\n\r\n### 2.1\t拉取镜像\r\n\r\n```shell\r\n# 拉取镜像\r\ndocker pull mysql\r\n# 或者\r\ndocker pull mysql:8.0.37\r\n\r\n# 以上两个命令是一致的，默认拉取的就是 latest 版本的\r\n# 我们还可以用下面的命令来查看可用版本：\r\ndocker search mysql\r\n```\r\n\r\n\r\n\r\n### 2.2\t配置文件\r\n\r\n```shell\r\n# 进入到上面映射的配置目录，如果没有该目录则创建\r\ncd \u002Fusr\u002Flocal\u002Fmysql\u002Fconf\r\n# 打开并创建一个my.cnf文件\r\nvi my.cnf\r\n```\r\n\r\n（1）8.0.x配置文件\r\n\r\n```properties\r\n[client]\r\ndefault-character-set=utf8mb4\r\n\r\n[mysql]\r\ndefault-character-set=utf8mb4\r\n\r\n[mysqld]\r\n# 设置东八区时区\r\ndefault-time_zone = '+8:00'\r\n\r\n# 设置密码验证规则，default_authentication_plugin参数已被废弃\r\n# 改为authentication_policy\r\n#default_authentication_plugin=mysql_native_password\r\nauthentication_policy=mysql_native_password\r\n\r\n# 限制导入和导出的数据目录\r\n# 为空，不限制导入导出的数据目录；\r\n# 指定目录，必须从该目录导入导处，且MySQL不会自动创建该目录；\r\n# 为NULL，禁止导入与导出功能\r\n#secure_file_priv=\u002Fvar\u002Flib\u002Fmysql\r\nsecure_file_priv=\r\n\r\ninit_connect='SET collation_connection = utf8mb4_0900_ai_ci'\r\ninit_connect='SET NAMES utf8mb4'\r\n\r\ncharacter-set-server=utf8mb4\r\ncollation-server=utf8mb4_0900_ai_ci\r\n\r\nskip-character-set-client-handshake\r\nskip-name-resolve\r\n```\r\n\r\n默认的鉴权方式，我们修改为```mysql_native_password```，不然的话连接会报错。因为在mysql8以后的默认加密方式改变了，由``` mysql_native_password```改为了```caching_sha2_password```。这种加密凡是在客户端无法访问，客户端支持的是```mysql_native_password``` 。\r\n\r\n（2）8.4.x配置文件\r\n\r\n```properties\r\n# For advice on how to change settings please see\r\n# http:\u002F\u002Fdev.mysql.com\u002Fdoc\u002Frefman\u002F8.4\u002Fen\u002Fserver-configuration-defaults.html\r\n\r\n[mysqld]\r\n#\r\n# Remove leading # and set to the amount of RAM for the most important data\r\n# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.\r\n# innodb_buffer_pool_size = 128M\r\n#\r\n# Remove leading # to turn on a very important data integrity option: logging\r\n# changes to the binary log between backups.\r\n# log_bin\r\n#\r\n# Remove leading # to set options mainly useful for reporting servers.\r\n# The server defaults are faster for transactions and fast SELECTs.\r\n# Adjust sizes as needed, experiment to find the optimal values.\r\n# join_buffer_size = 128M\r\n# sort_buffer_size = 2M\r\n# read_rnd_buffer_size = 2M\r\n\r\n# 区分大小写\r\nlower_case_table_names=0\r\n\r\nhost-cache-size=0\r\nskip-name-resolve\r\ndatadir=\u002Fvar\u002Flib\u002Fmysql\r\nsocket=\u002Fvar\u002Frun\u002Fmysqld\u002Fmysqld.sock\r\nsecure-file-priv=\u002Fvar\u002Flib\u002Fmysql-files\r\nuser=mysql\r\n\r\npid-file=\u002Fvar\u002Frun\u002Fmysqld\u002Fmysqld.pid\r\n[client]\r\nsocket=\u002Fvar\u002Frun\u002Fmysqld\u002Fmysqld.sock\r\n\r\n!includedir \u002Fetc\u002Fmysql\u002Fconf.d\u002F\r\n```\r\n\r\n\r\n\r\n### 2.3\t运行容器\r\n\r\n（1）**8.0.x版本**\r\n\r\n```shell\r\ndocker run -p 3306:3306 --name mysql --restart=always --privileged=true \\\r\n-v \u002Fusr\u002Flocal\u002Fmysql\u002Flog:\u002Fvar\u002Flog\u002Fmysql \\\r\n-v \u002Fusr\u002Flocal\u002Fmysql\u002Fdata:\u002Fvar\u002Flib\u002Fmysql \\\r\n-v \u002Fusr\u002Flocal\u002Fmysql\u002Fconf:\u002Fetc\u002Fmysql \\\r\n-v \u002Fetc\u002Flocaltime:\u002Fetc\u002Flocaltime:ro \\\r\n-e MYSQL_ROOT_PASSWORD=123456 -d mysql:8.0.22\r\n\r\n#忽略大小写，8.0 之后只能在初始化时指定\r\ndocker run -p 3306:3306 --name mysql  --privileged=true -e MYSQL_ROOT_PASSWORD=Great@2024 -d mysql:8.0.22 --lower_case_table_names=1\r\n```\r\n\r\n（2）**8.4.x版本**\r\n\r\n高版本还需要指定：conf.d目录，由于mysql的配置目录\u002Fetc\u002Fmysql下有两个空目录， 上面的执行命令仅挂载了当前目录，导致里面的两个目录没有权限挂载到宿主机内， 应该将挂载目录指定到具体的目录下：\r\n\r\n```shell\r\ndocker run -p 3306:3306 --name mysql --restart=always --privileged=true \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fmysql\u002Flog:\u002Fvar\u002Flog\u002Fmysql \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fmysql\u002Fdata:\u002Fvar\u002Flib\u002Fmysql \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fmysql\u002Fconf:\u002Fetc\u002Fmysql \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fmysql\u002Fconf:\u002Fetc\u002Fmysql\u002Fconf.d \\\r\n-v \u002Fetc\u002Flocaltime:\u002Fetc\u002Flocaltime:ro \\\r\n-e MYSQL_ROOT_PASSWORD=!QAZ2wsx#EDC -d mysql:8.0.37\r\n```\r\n\r\n### 2.4\t授权远程访问\r\n\r\n#### 2.4.1\t登录mysql\r\n\r\n```shell\r\ndocker exec -it mysql \u002Fbin\u002Fbash\r\nmysql -u root -p\r\n```\r\n\r\n#### 2.4.2\t选择数据库\r\n\r\n```mysql\r\n# 查看数据库\r\nmysql> show databases;\r\n# 选择数据库\r\nmysql> use mysql;\r\n\r\n# 查看大小写是否敏感，1：不区分，0：区分大小写\r\nmysql> show VARIABLES like '%lower%';\r\n```\r\n\r\n#### 2.4.3\t查看用户信息\r\n\r\n```mysql\r\n# 查看root用户是否具有权限，和host主机地址是否为%，如果host为%，则已具备远程访问权限\r\nmysql> select host,user,plugin from user;\r\n+-----------+------------------+-----------------------+\r\n| host      | user             | plugin                |\r\n+-----------+------------------+-----------------------+\r\n| %         | root             | mysql_native_password |\r\n| localhost | mysql.infoschema | caching_sha2_password |\r\n| localhost | mysql.session    | caching_sha2_password |\r\n| localhost | mysql.sys        | caching_sha2_password |\r\n| localhost | root             | mysql_native_password |\r\n+-----------+------------------+-----------------------+\r\n5 rows in set (0.00 sec)\r\n```\r\n\r\n#### 2.4.4\t两个root用户的存在\r\n\r\n在mysql用户表中出现两个“root”用户是因为mysql允许在不同的主机上使用相同的用户名创建用户。这是因为mysql使用“用户名@主机”的形式来标识一个用户，其中“用户名”是用户的名称，“主机”是用户所连接的主机名或者IP地址。\r\n\r\n```mysql\r\n# 如果存在两个账号，本地登录则自动使用host为本地的账号登录，远程登录则自动使用%的，\r\n# 注意这是两个不同的账号，密码也不一定相同（可以只修改为不一样的密码），权限也是不同的，增加了运维管理负担\r\n# 查询对比两者的权限差异\r\nmysql> show grants for 'root'@'localhost';\r\nmysql> show grants for 'root'@'%';\r\n\r\n# 可以删除其中一个，这里删除host为%的账号\r\nmysql> drop user 'root'@'%';\r\n```\r\n\r\n#### 2.4.5\t授予远程访问权限\r\n\r\n```mysql\r\n# 修改root用户host为%，即开放远程访问权限\r\nmysql> update user set host='%' where user='root';\r\n\r\n# 授权所有权限给root@'%'账号，如果不是新建的root账号，可以不用设置\r\nmysql> grant all on *.* to root@'%';\r\n\r\n# 刷新权限（授权，或者开放远程访问才生效）\r\nmysql> FLUSH PRIVILEGES;\r\n```\r\n\r\n#### 2.4.6\t修改密码\r\n\r\n```mysql\r\n# 如修改密码为!QAZzaq1\r\nmysql> ALTER USER 'root'@'%' IDENTIFIED BY '!QAZzaq1';\r\nQuery OK, 0 rows affected (0.03 sec)\r\n\r\nmysql> exit\r\n```\r\n\r\n\r\n\r\n# 3\t安装redis\r\n\r\n### 3.1\t拉取镜像\r\n\r\n```shell\r\n# laster版本\r\ndocker pull redis\r\n# 指定版本\r\ndocker pull redis:7.2.4\r\n```\r\n\r\n\r\n\r\n### 3.2\t创建redis配置文件\r\n\r\n```shell\r\n# redis镜像默认是没有redis配置文件的，配置挂载目录的时候需要先\r\n# 创建一个redis.conf文件，否则会默认把最后一级目录当成配置文件\r\n# 创建目录\r\nmkdir -p \u002Fusr\u002Flocal\u002Fsoftware\u002Fredis\u002Fconf\r\n\r\n# 创建文件\r\ntouch \u002Fusr\u002Flocal\u002Fsoftware\u002Fredis\u002Fconf\u002Fredis.conf\r\n\r\n# 可以从官网下载redis配置文件,记得下载对应版本的配置文件，否则可能会报错,也可以不用下载,自己编写redis.conf配置文件\r\n#地址：https:\u002F\u002Fgithub.com\u002Fredis\u002Fredis\u002Fblob\u002F7.2.4\u002Fredis.conf\r\n\r\n# 编辑文件\r\nvi redis.conf\r\n```\r\n\r\nredis默认配置文件是空的，因此redis的值都只存储在内存中，每次重启容器数据都会丢失，因此需要配置持久化方式。编写```redis.conf```文件内容如下：\r\n\r\n```shell\r\n# 启动进程端口号，默认6379，可以改\r\nport 6379\r\n\r\n# 配置密码登录\r\nrequirepass !QAZ2wsx#EDC\r\n\r\n# 配置持久化方式：开启aof\r\nappendonly yes\r\n```\r\n\r\n\r\n\r\n### 3.3\t运行容器\r\n\r\n```shell\r\ndocker run -p 6379:6379 --name redis --restart=always --privileged \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fredis\u002Fdata:\u002Fdata \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fredis\u002Fconf\u002Fredis.conf:\u002Fetc\u002Fredis\u002Fredis.conf \\\r\n-v \u002Fetc\u002Flocaltime:\u002Fetc\u002Flocaltime:ro \\\r\n-d redis redis-server \u002Fetc\u002Fredis\u002Fredis.conf\r\n\r\n# 指定密码运行\r\ndocker run -p 6379:6379 --name redis --privileged \\\r\n-d redis:7.4.0 \\\r\n--requirepass 'Great@2024' --appendonly yes\r\n```\r\n\r\n参数说明：\r\n\r\n```shell\r\n-p 6379:6379：指定宿主机和容器端口映射\r\n--name redis：指定容器名称\r\n--restart=always：总是跟随docker启动\r\n--privileged：获取宿主机root权限\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fredis\u002Fdata:\u002Fdata  ：配置redis数据挂载目录\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fredis\u002Fconf\u002Fredis.conf:\u002Fetc\u002Fredis\u002Fredis.conf  ：配置redis配置文件挂载目录\r\n-d ：指定容器后台启动\r\nredis-server \u002Fetc\u002Fredis\u002Fredis.conf  ：指定redis配置文件启动\r\n```\r\n\r\n\r\n\r\n### 3.4\t连接测试\r\n\r\n```shell\r\n# 进入redis容器\r\ndocker exec -it redis \u002Fbin\u002Fbash\r\n\r\n# 使用redis自带工具连接\r\nredis-cli\r\n\r\n# 如果redis配置了密码，则使用-a\r\nredis-cli -a '!QAZ2wsx#EDC'\r\nredis-cli -h localhost -a '!QAZ2wsx#EDC'\r\n\r\n# 退出\r\nexit\r\n\r\n# 直接进入redis客户端\r\ndocker exec -it redis redis-cli\r\ndocker exec -it redis redis-cli -a '!QAZ2wsx#EDC'\r\n```\r\n\r\n\r\n\r\n# 4\t安装nacos\r\n\r\n### 4.1\t拉取镜像\r\n\r\n```shell\r\n# 拉取最新版本，不加版本好默认最新版本\r\ndocker pull nacos\u002Fnacos-server\r\n\r\n# 拉取2.3.2版本\r\ndocker pull nacos\u002Fnacos-server:v2.3.2\r\n```\r\n\r\n\r\n\r\n### 4.2\t启动方式一内置数据库持久化\r\n\r\n```shell\r\n# 最新版本\r\ndocker run --env MODE=standalone --name nacos -d -p 8848:8848 -p 9848:9848 -p 9849:9849 nacos\u002Fnacos-server\r\n# 指定版本\r\ndocker run --env MODE=standalone --name nacos -d -p 8848:8848 -p 9848:9848 -p 9849:9849 nacos\u002Fnacos-server:v2.3.2\r\n\r\n# 开启认证登录\r\ndocker run --name nacos \\\r\n-p 8848:8848 -p 9848:9848 -p 9849:9849 \\\r\n--privileged=true \\\r\n-e MODE=standalone \\\r\n-e NACOS_AUTH_ENABLE=true \\\r\n-e NACOS_AUTH_TOKEN=SecretKey012345678901234567890123453456789999876549012345678901232389742349889 \\\r\n-e NACOS_AUTH_IDENTITY_KEY=nacos \\\r\n-e NACOS_AUTH_IDENTITY_VALUE='Great@2024' \\\r\n-d nacos\u002Fnacos-server:v2.4.0\r\n```\r\n\r\n\r\n\r\n### 4.3\t启动方式—Mysql持久化\r\n\r\n#### 4.3.1\t创建映射目录\r\n\r\n```shell\r\nmkdir -p \u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Flogs\u002F\r\nmkdir -p \u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Fdata\u002F\r\n```\r\n\r\n\r\n\r\n#### 4.3.2\t运行容器\r\n\r\n2.2.2版本之前的Nacos默认控制台，无论服务端是否开启鉴权，都会存在一个登录页；这导致很多用户被**误导**认为Nacos默认是存在鉴权的。在社区安全工程师的建议下，Nacos自**2.2.2**版本开始，在未开启鉴权时，默认控制台将不需要登录即可访问，同时在控制台中给予提示，提醒用户当前集群未开启鉴权。\r\n\r\n在用户开启鉴权后，控制台才需要进行登录访问。这里没有开启鉴权，不需要登录。\r\n\r\n```shell\r\ndocker run --name nacos \\\r\n-p 8848:8848 -p 9848:9848 -p 9849:9849 \\\r\n--privileged=true \\\r\n--restart=always \\\r\n-e JVM_XMS=256m \\\r\n-e JVM_XMX=256m \\\r\n-e MODE=standalone \\\r\n-e SPRING_DATASOURCE_PLATFORM=mysql \\\r\n-e MYSQL_SERVICE_HOST=106.53.110.52 \\\r\n-e MYSQL_SERVICE_PORT=3306 \\\r\n-e MYSQL_SERVICE_DB_NAME=nacos \\\r\n-e MYSQL_SERVICE_USER=root \\\r\n-e MYSQL_SERVICE_PASSWORD='!QAZ2wsx#EDC' \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Flogs\u002F:\u002Fhome\u002Fnacos\u002Flogs\u002F \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Fdata\u002F:\u002Fhome\u002Fnacos\u002Fdata\u002F \\\r\n-d nacos\u002Fnacos-server:v2.3.2\r\n```\r\n\r\n\r\n\r\n#### 4.3.3\t运行容器（高版本开启鉴权）\r\n\r\n```shell\r\ndocker run --name nacos \\\r\n-p 8848:8848 -p 9848:9848 -p 9849:9849 \\\r\n--privileged=true \\\r\n--restart=always \\\r\n-e JVM_XMS=256m \\\r\n-e JVM_XMX=256m \\\r\n-e MODE=standalone \\\r\n-e SPRING_DATASOURCE_PLATFORM=mysql \\\r\n-e MYSQL_SERVICE_HOST=106.53.110.52 \\\r\n-e MYSQL_SERVICE_PORT=3306 \\\r\n-e MYSQL_SERVICE_DB_NAME=nacos \\\r\n-e MYSQL_SERVICE_USER=root \\\r\n-e MYSQL_SERVICE_PASSWORD='!QAZ2wsx#EDC' \\\r\n-e NACOS_AUTH_ENABLE=true \\\r\n-e NACOS_AUTH_TOKEN=SecretKey012345678901234567890123453456789999876549012345678901232389742349889 \\\r\n-e NACOS_AUTH_IDENTITY_KEY=nacos \\\r\n-e NACOS_AUTH_IDENTITY_VALUE=nacos \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Flogs\u002F:\u002Fhome\u002Fnacos\u002Flogs\u002F \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Fdata\u002F:\u002Fhome\u002Fnacos\u002Fdata\u002F \\\r\n-d nacos\u002Fnacos-server:v2.3.2\r\n```\r\n\r\n参数说明：\r\n\r\n```shell\r\n--name ： 容器名称\r\n-p 8848:8848 ：nacos默认端口8848 映射到外部端口8848\r\n-p 9848:9848 ：naocs 2.0版本后新增了gRPC通信，用于gRPC客户端向服务端通信\r\n-p 9849:9849 ：naocs 2.0版本后新增了gRPC通信，用于gRPC服务间同步\r\n--privileged ：获取宿主机root权限\r\n--restart=always ：总是跟随docker启动\r\n\r\n-e 配置 启动参数\r\n-e JVM_XMS=256m -e JVM_XMX=256m ：配置 jvm\r\n-e MODE=standalone ：单机模式\r\n-e SPRING_DATASOURCE_PLATFORM=mysql ：指定mysql数据库\r\n-e MYSQL_SERVICE_HOST=106.53.110.52 ：mysql连接地址\r\n-e MYSQL_SERVICE_PORT=3306 ：mysql连接端口\r\n-e MYSQL_SERVICE_DB_NAME=nacos ：mysql连接数据库\r\n-e MYSQL_SERVICE_USER=root ：mysql连接账号\r\n# mysql连接密码，含有特殊字符得用单引号引起来（window系统则不用,否则会当成密码的一部分）\r\n-e MYSQL_SERVICE_PASSWORD='!QAZ2wsx#EDC'\r\n\r\n-e NACOS_AUTH_ENABLE=true ：开启鉴权\r\n-e NACOS_AUTH_TOKEN=XXX ：指定生成jwt令牌的密钥\r\n-e NACOS_AUTH_IDENTITY_KEY=nacos ：鉴权账号\r\n-e NACOS_AUTH_IDENTITY_VALUE=nacos ：鉴权密码，如果连接了数据库，以数据库的密码为准，一般为nacos\r\n\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Flogs\u002F:\u002Fhome\u002Fnacos\u002Flogs\u002F ：配置日志挂载目录到宿主机\u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Flogs\u002F\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Fconf\u002F:\u002Fhome\u002Fnacos\u002Fconf\u002F ：配置挂载宿主机目录\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Fdata\u002F:\u002Fhome\u002Fnacos\u002Fdata\u002F ：数据挂载宿主机目录\r\n-d ：指定容器后台启动\r\nnacos\u002Fnacos-server:v2.3.2 ：镜像名称\r\n```\r\n\r\n\r\n\r\n### 4.4\t启动方式—Mysql持久化（properties配置）\r\n\r\n#### 4.4.1\t创建映射目录\r\n\r\n```shell\r\nmkdir -p \u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Flogs\u002F\r\nmkdir -p \u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Fconf\u002F\r\nmkdir -p \u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Fdata\u002F\r\n```\r\n\r\n\r\n\r\n#### 4.4.2\t启动容器\r\n\r\n```shell\r\ndocker run --env MODE=standalone --name nacos -d -p 8848:8848 -p 9848:9848 -p 9849:9849 nacos\u002Fnacos-server:v2.3.2\r\n```\r\n\r\n\r\n\r\n#### 4.4.3\t拷贝容器中的配置文件\r\n\r\n```shell\r\n# 拷贝配置文件\r\ndocker cp nacos:\u002Fhome\u002Fnacos\u002Fconf \u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\r\n# 拷贝完之后，停止容器\r\ndocker stop nacos\r\n# 删除容器\r\ndocker rm nacos\r\n```\r\n\r\n\r\n\r\n#### 4.4.4\tconf 配置目录文件\r\n\r\n```shell\r\ncd \u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Fconf\r\nls\r\n# conf目录文件如下\r\n1.4.0-ipv6_support-update.sql\r\nannouncement_zh-CN.conf\r\nconsole-guide.conf\r\nmysql-schema.sql\r\nannouncement_en-US.conf\r\napplication.properties\r\nderby-schema.sql\r\nnacos-logback.xml\r\n```\r\n\r\n\r\n\r\n#### 4.4.5\tMysql数据库创建配置表\r\n\r\n在MySQL数据库上，新建nacos[数据库](https:\u002F\u002Fso.csdn.net\u002Fso\u002Fsearch?q=数据库&spm=1001.2101.3001.7020)，并执行```mysql-schema.sql```中的sql，也可以从官网下载：https:\u002F\u002Fgithub.com\u002Falibaba\u002Fnacos\u002Fblob\u002F2.3.2\u002Fconfig\u002Fsrc\u002Fmain\u002Fresources\u002FMETA-INF\u002Fmysql-schema.sql 。\r\n\r\nsql语句如下：\r\n\r\n```mysql\r\n# 创建nacos数据库\r\nmysql> CREATE DATABASE nacos;\r\n# 进入nacos数据库\r\nmysql> use nacos;\r\n```\r\n\r\n```mysql-schema.sql```中建表语句如下：\r\n\r\n```mysql\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = config_info                  *\u002F\r\n\u002F******************************************\u002F\r\nCREATE TABLE `config_info` (\r\n  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',\r\n  `data_id` varchar(255) NOT NULL COMMENT 'data_id',\r\n  `group_id` varchar(128) DEFAULT NULL COMMENT 'group_id',\r\n  `content` longtext NOT NULL COMMENT 'content',\r\n  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',\r\n  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\r\n  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',\r\n  `src_user` text COMMENT 'source user',\r\n  `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',\r\n  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',\r\n  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',\r\n  `c_desc` varchar(256) DEFAULT NULL COMMENT 'configuration description',\r\n  `c_use` varchar(64) DEFAULT NULL COMMENT 'configuration usage',\r\n  `effect` varchar(64) DEFAULT NULL COMMENT '配置生效的描述',\r\n  `type` varchar(64) DEFAULT NULL COMMENT '配置的类型',\r\n  `c_schema` text COMMENT '配置的模式',\r\n  `encrypted_data_key` text NOT NULL COMMENT '密钥',\r\n  PRIMARY KEY (`id`),\r\n  UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = config_info_aggr             *\u002F\r\n\u002F******************************************\u002F\r\nCREATE TABLE `config_info_aggr` (\r\n  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',\r\n  `data_id` varchar(255) NOT NULL COMMENT 'data_id',\r\n  `group_id` varchar(128) NOT NULL COMMENT 'group_id',\r\n  `datum_id` varchar(255) NOT NULL COMMENT 'datum_id',\r\n  `content` longtext NOT NULL COMMENT '内容',\r\n  `gmt_modified` datetime NOT NULL COMMENT '修改时间',\r\n  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',\r\n  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',\r\n  PRIMARY KEY (`id`),\r\n  UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段';\r\n\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = config_info_beta             *\u002F\r\n\u002F******************************************\u002F\r\nCREATE TABLE `config_info_beta` (\r\n  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',\r\n  `data_id` varchar(255) NOT NULL COMMENT 'data_id',\r\n  `group_id` varchar(128) NOT NULL COMMENT 'group_id',\r\n  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',\r\n  `content` longtext NOT NULL COMMENT 'content',\r\n  `beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps',\r\n  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',\r\n  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\r\n  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',\r\n  `src_user` text COMMENT 'source user',\r\n  `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',\r\n  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',\r\n  `encrypted_data_key` text NOT NULL COMMENT '密钥',\r\n  PRIMARY KEY (`id`),\r\n  UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta';\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = config_info_tag              *\u002F\r\n\u002F******************************************\u002F\r\nCREATE TABLE `config_info_tag` (\r\n  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',\r\n  `data_id` varchar(255) NOT NULL COMMENT 'data_id',\r\n  `group_id` varchar(128) NOT NULL COMMENT 'group_id',\r\n  `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',\r\n  `tag_id` varchar(128) NOT NULL COMMENT 'tag_id',\r\n  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',\r\n  `content` longtext NOT NULL COMMENT 'content',\r\n  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',\r\n  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\r\n  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',\r\n  `src_user` text COMMENT 'source user',\r\n  `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',\r\n  PRIMARY KEY (`id`),\r\n  UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag';\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = config_tags_relation         *\u002F\r\n\u002F******************************************\u002F\r\nCREATE TABLE `config_tags_relation` (\r\n  `id` bigint(20) NOT NULL COMMENT 'id',\r\n  `tag_name` varchar(128) NOT NULL COMMENT 'tag_name',\r\n  `tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',\r\n  `data_id` varchar(255) NOT NULL COMMENT 'data_id',\r\n  `group_id` varchar(128) NOT NULL COMMENT 'group_id',\r\n  `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',\r\n  `nid` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'nid, 自增长标识',\r\n  PRIMARY KEY (`nid`),\r\n  UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),\r\n  KEY `idx_tenant_id` (`tenant_id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation';\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = group_capacity               *\u002F\r\n\u002F******************************************\u002F\r\nCREATE TABLE `group_capacity` (\r\n  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',\r\n  `group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID，空字符表示整个集群',\r\n  `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额，0表示使用默认值',\r\n  `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',\r\n  `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限，单位为字节，0表示使用默认值',\r\n  `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数，，0表示使用默认值',\r\n  `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限，单位为字节，0表示使用默认值',\r\n  `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',\r\n  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\r\n  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',\r\n  PRIMARY KEY (`id`),\r\n  UNIQUE KEY `uk_group_id` (`group_id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表';\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = his_config_info              *\u002F\r\n\u002F******************************************\u002F\r\nCREATE TABLE `his_config_info` (\r\n  `id` bigint(20) unsigned NOT NULL COMMENT 'id',\r\n  `nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'nid, 自增标识',\r\n  `data_id` varchar(255) NOT NULL COMMENT 'data_id',\r\n  `group_id` varchar(128) NOT NULL COMMENT 'group_id',\r\n  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',\r\n  `content` longtext NOT NULL COMMENT 'content',\r\n  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',\r\n  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\r\n  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',\r\n  `src_user` text COMMENT 'source user',\r\n  `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',\r\n  `op_type` char(10) DEFAULT NULL COMMENT 'operation type',\r\n  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',\r\n  `encrypted_data_key` text NOT NULL COMMENT '密钥',\r\n  PRIMARY KEY (`nid`),\r\n  KEY `idx_gmt_create` (`gmt_create`),\r\n  KEY `idx_gmt_modified` (`gmt_modified`),\r\n  KEY `idx_did` (`data_id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造';\r\n\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = tenant_capacity              *\u002F\r\n\u002F******************************************\u002F\r\nCREATE TABLE `tenant_capacity` (\r\n  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',\r\n  `tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',\r\n  `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额，0表示使用默认值',\r\n  `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',\r\n  `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限，单位为字节，0表示使用默认值',\r\n  `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数',\r\n  `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限，单位为字节，0表示使用默认值',\r\n  `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',\r\n  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\r\n  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',\r\n  PRIMARY KEY (`id`),\r\n  UNIQUE KEY `uk_tenant_id` (`tenant_id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表';\r\n\r\n\r\nCREATE TABLE `tenant_info` (\r\n  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',\r\n  `kp` varchar(128) NOT NULL COMMENT 'kp',\r\n  `tenant_id` varchar(128) default '' COMMENT 'tenant_id',\r\n  `tenant_name` varchar(128) default '' COMMENT 'tenant_name',\r\n  `tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',\r\n  `create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',\r\n  `gmt_create` bigint(20) NOT NULL COMMENT '创建时间',\r\n  `gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',\r\n  PRIMARY KEY (`id`),\r\n  UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),\r\n  KEY `idx_tenant_id` (`tenant_id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';\r\n\r\nCREATE TABLE `users` (\r\n\t`username` varchar(50) NOT NULL PRIMARY KEY COMMENT 'username',\r\n\t`password` varchar(500) NOT NULL COMMENT 'password',\r\n\t`enabled` boolean NOT NULL COMMENT 'enabled'\r\n);\r\n\r\nCREATE TABLE `roles` (\r\n\t`username` varchar(50) NOT NULL COMMENT 'username',\r\n\t`role` varchar(50) NOT NULL COMMENT 'role',\r\n\tUNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE\r\n);\r\n\r\nCREATE TABLE `permissions` (\r\n    `role` varchar(50) NOT NULL COMMENT 'role',\r\n    `resource` varchar(128) NOT NULL COMMENT 'resource',\r\n    `action` varchar(8) NOT NULL COMMENT 'action',\r\n    UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE\r\n);\r\n\r\nINSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);\r\n\r\nINSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');\r\n```\r\n\r\n\r\n\r\n#### 4.4.6\t修改 application.properties 配置文件\r\n\r\n```properties\r\n# spring\r\nserver.servlet.contextPath=${SERVER_SERVLET_CONTEXTPATH:\u002Fnacos}\r\nserver.contextPath=\u002Fnacos\r\nserver.port=${NACOS_APPLICATION_PORT:8848}\r\nserver.tomcat.accesslog.max-days=30\r\nserver.tomcat.accesslog.pattern=%h %l %u %t \"%r\" %s %b %D %{User-Agent}i %{Request-Source}i\r\nserver.tomcat.accesslog.enabled=${TOMCAT_ACCESSLOG_ENABLED:false}\r\nserver.error.include-message=ALWAYS\r\n# default current work dir\r\nserver.tomcat.basedir=file:.\r\n#*************** Config Module Related Configurations ***************#\r\n### Deprecated configuration property, it is recommended to use `spring.sql.init.platform` replaced.\r\n# 添加使用mysql数据库\r\nspring.datasource.platform=${SPRING_DATASOURCE_PLATFORM:mysql}\r\nspring.sql.init.platform=${SPRING_DATASOURCE_PLATFORM}\r\nnacos.cmdb.dumpTaskInterval=3600\r\nnacos.cmdb.eventTaskInterval=10\r\nnacos.cmdb.labelTaskInterval=300\r\nnacos.cmdb.loadDataAtStart=false\r\ndb.num=${MYSQL_DATABASE_NUM:1}\r\n# 添加mysql ip，连接的数据库名\r\ndb.url.0=jdbc:mysql:\u002F\u002F${MYSQL_SERVICE_HOST:127.0.0.1}:${MYSQL_SERVICE_PORT:3306}\u002F${MYSQL_SERVICE_DB_NAME:nacos}?${MYSQL_SERVICE_DB_PARAM:characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false}\r\n# 添加登录用户\r\ndb.user.0=${MYSQL_SERVICE_USER:root}\r\n# 添加登录密码\r\ndb.password.0=${MYSQL_SERVICE_PASSWORD:!QAZ2wsx#EDC}\r\n## DB connection pool settings\r\ndb.pool.config.connectionTimeout=${DB_POOL_CONNECTION_TIMEOUT:30000}\r\ndb.pool.config.validationTimeout=10000\r\ndb.pool.config.maximumPoolSize=20\r\ndb.pool.config.minimumIdle=2\r\n### The auth system to use, currently only 'nacos' and 'ldap' is supported:\r\nnacos.core.auth.system.type=${NACOS_AUTH_SYSTEM_TYPE:nacos}\r\n### worked when nacos.core.auth.system.type=nacos\r\n### The token expiration in seconds:\r\nnacos.core.auth.plugin.nacos.token.expire.seconds=${NACOS_AUTH_TOKEN_EXPIRE_SECONDS:18000}\r\n### The default token:\r\nnacos.core.auth.plugin.nacos.token.secret.key=${NACOS_AUTH_TOKEN:}\r\n### Turn on\u002Foff caching of auth information. By turning on this switch, the update of auth information would have a 15 seconds delay.\r\nnacos.core.auth.caching.enabled=${NACOS_AUTH_CACHE_ENABLE:false}\r\nnacos.core.auth.enable.userAgentAuthWhite=${NACOS_AUTH_USER_AGENT_AUTH_WHITE_ENABLE:false}\r\nnacos.core.auth.server.identity.key=${NACOS_AUTH_IDENTITY_KEY:}\r\nnacos.core.auth.server.identity.value=${NACOS_AUTH_IDENTITY_VALUE:}\r\n## spring security config\r\n### turn off security\r\nnacos.security.ignore.urls=${NACOS_SECURITY_IGNORE_URLS:\u002F,\u002Ferror,\u002F**\u002F*.css,\u002F**\u002F*.js,\u002F**\u002F*.html,\u002F**\u002F*.map,\u002F**\u002F*.svg,\u002F**\u002F*.png,\u002F**\u002F*.ico,\u002Fconsole-fe\u002Fpublic\u002F**,\u002Fv1\u002Fauth\u002F**,\u002Fv1\u002Fconsole\u002Fhealth\u002F**,\u002Factuator\u002F**,\u002Fv1\u002Fconsole\u002Fserver\u002F**}\r\n# metrics for elastic search\r\nmanagement.metrics.export.elastic.enabled=false\r\nmanagement.metrics.export.influx.enabled=false\r\nnacos.naming.distro.taskDispatchThreadCount=10\r\nnacos.naming.distro.taskDispatchPeriod=200\r\nnacos.naming.distro.batchSyncKeyCount=1000\r\nnacos.naming.distro.initDataRatio=0.9\r\nnacos.naming.distro.syncRetryDelay=5000\r\nnacos.naming.data.warmup=true\r\nnacos.console.ui.enabled=true\r\nnacos.core.param.check.enabled=true\r\n```\r\n\r\n\r\n\r\n#### 4.4.7\t配置 nacos 登录授权\r\n\r\n出于安全考虑，nacos 2.2.3版本后，登录账号和密码默认不用输入，登录不用鉴权（为了避免默认的密钥被带到生产环境）。如果需要使用登录的账号和密码，参考这个文档进行配置：https:\u002F\u002Fnacos.io\u002Fzh-cn\u002Fdocs\u002Fv2\u002Fguide\u002Fuser\u002Fauth.html\r\n\r\n开启鉴权，application.properties中的配置信息修改为：\r\n\r\n```properties\r\nnacos.core.auth.system.type=nacos\r\nnacos.core.auth.enabled=true\r\n```\r\n\r\n自定义密钥：\r\n\r\n```properties\r\n# 自定义用于生成JWT令牌的密钥\r\nnacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123453456789999876549012345678901232389742349889\r\n# 自定义密钥时，推荐将配置项设置为Base64编码的字符串，且原始密钥长度不得低于32字符\r\nnacos.core.auth.plugin.nacos.token.secret.key=VGhpc0lzTXlDdXN0b21TZWNyZXRLZXkwMTIzNDU2Nzg=\r\n```\r\n\r\n修改后的最终文档：\r\n\r\n```properties\r\n# spring\r\nserver.servlet.contextPath=${SERVER_SERVLET_CONTEXTPATH:\u002Fnacos}\r\nserver.contextPath=\u002Fnacos\r\nserver.port=${NACOS_APPLICATION_PORT:8848}\r\nserver.tomcat.accesslog.max-days=30\r\nserver.tomcat.accesslog.pattern=%h %l %u %t \"%r\" %s %b %D %{User-Agent}i %{Request-Source}i\r\nserver.tomcat.accesslog.enabled=${TOMCAT_ACCESSLOG_ENABLED:false}\r\nserver.error.include-message=ALWAYS\r\n# default current work dir\r\nserver.tomcat.basedir=file:.\r\n#*************** Config Module Related Configurations ***************#\r\n### Deprecated configuration property, it is recommended to use `spring.sql.init.platform` replaced.\r\n# 添加使用mysql数据库\r\nspring.datasource.platform=${SPRING_DATASOURCE_PLATFORM:mysql}\r\nspring.sql.init.platform=${SPRING_DATASOURCE_PLATFORM}\r\nnacos.cmdb.dumpTaskInterval=3600\r\nnacos.cmdb.eventTaskInterval=10\r\nnacos.cmdb.labelTaskInterval=300\r\nnacos.cmdb.loadDataAtStart=false\r\ndb.num=${MYSQL_DATABASE_NUM:1}\r\n# 添加mysql ip，连接的数据库名\r\ndb.url.0=jdbc:mysql:\u002F\u002F${MYSQL_SERVICE_HOST:127.0.0.1}:${MYSQL_SERVICE_PORT:3306}\u002F${MYSQL_SERVICE_DB_NAME:nacos}?${MYSQL_SERVICE_DB_PARAM:characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false}\r\n# 添加登录用户\r\ndb.user.0=${MYSQL_SERVICE_USER:root}\r\n# 添加登录密码\r\ndb.password.0=${MYSQL_SERVICE_PASSWORD:!QAZ2wsx#EDC}\r\n## DB connection pool settings\r\ndb.pool.config.connectionTimeout=${DB_POOL_CONNECTION_TIMEOUT:30000}\r\ndb.pool.config.validationTimeout=10000\r\ndb.pool.config.maximumPoolSize=20\r\ndb.pool.config.minimumIdle=2\r\n### The auth system to use, currently only 'nacos' and 'ldap' is supported:\r\nnacos.core.auth.system.type=${NACOS_AUTH_SYSTEM_TYPE:nacos}\r\n# 开启鉴权\r\nnacos.core.auth.enabled=true\r\n### worked when nacos.core.auth.system.type=nacos\r\n### The token expiration in seconds:\r\nnacos.core.auth.plugin.nacos.token.expire.seconds=${NACOS_AUTH_TOKEN_EXPIRE_SECONDS:18000}\r\n# 添加生成jwt令牌的密钥\r\nnacos.core.auth.plugin.nacos.token.secret.key=${NACOS_AUTH_TOKEN:SecretKey012345678901234567890123453456789999876549012345678901232389742349889}\r\n### Turn on\u002Foff caching of auth information. By turning on this switch, the update of auth information would have a 15 seconds delay.\r\nnacos.core.auth.caching.enabled=${NACOS_AUTH_CACHE_ENABLE:false}\r\nnacos.core.auth.enable.userAgentAuthWhite=${NACOS_AUTH_USER_AGENT_AUTH_WHITE_ENABLE:false}\r\n# 添加登录账号密码，如果配置了数据库，在这里配置相当于无效\r\nnacos.core.auth.server.identity.key=${NACOS_AUTH_IDENTITY_KEY:nacos}\r\nnacos.core.auth.server.identity.value=${NACOS_AUTH_IDENTITY_VALUE:nacos}\r\n## spring security config\r\n### turn off security\r\nnacos.security.ignore.urls=${NACOS_SECURITY_IGNORE_URLS:\u002F,\u002Ferror,\u002F**\u002F*.css,\u002F**\u002F*.js,\u002F**\u002F*.html,\u002F**\u002F*.map,\u002F**\u002F*.svg,\u002F**\u002F*.png,\u002F**\u002F*.ico,\u002Fconsole-fe\u002Fpublic\u002F**,\u002Fv1\u002Fauth\u002F**,\u002Fv1\u002Fconsole\u002Fhealth\u002F**,\u002Factuator\u002F**,\u002Fv1\u002Fconsole\u002Fserver\u002F**}\r\n# metrics for elastic search\r\nmanagement.metrics.export.elastic.enabled=false\r\nmanagement.metrics.export.influx.enabled=false\r\nnacos.naming.distro.taskDispatchThreadCount=10\r\nnacos.naming.distro.taskDispatchPeriod=200\r\nnacos.naming.distro.batchSyncKeyCount=1000\r\nnacos.naming.distro.initDataRatio=0.9\r\nnacos.naming.distro.syncRetryDelay=5000\r\nnacos.naming.data.warmup=true\r\nnacos.console.ui.enabled=true\r\nnacos.core.param.check.enabled=true\r\n```\r\n\r\n\r\n\r\n#### 4.4.8\t运行容器\r\n\r\n```shell\r\ndocker run --name nacos \\\r\n-p 8848:8848 -p 9848:9848 -p 9849:9849 \\\r\n-e MODE=standalone \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Flogs\u002F:\u002Fhome\u002Fnacos\u002Flogs\u002F \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Fconf\u002F:\u002Fhome\u002Fnacos\u002Fconf\u002F \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Fdata\u002F:\u002Fhome\u002Fnacos\u002Fdata\u002F \\\r\n--restart=always \\\r\n--privileged=true \\\r\n-d nacos\u002Fnacos-server:v2.3.2\r\n```\r\n\r\n参数说明：\r\n\r\n```shell\r\n--name ： 容器名称\r\n-p 8848:8848 ：nacos默认端口8848 映射到外部端口8848\r\n-p 9848:9848 ：naocs 应该是2.0版本以后就需要一下的两个端口 所以也需要开放\r\n-p 9849:9849 ：naocs 应该是2.0版本以后就需要一下的两个端口 所以也需要开放\r\n-e MODE=standalone ：单机模式\r\n--restart=always ：总是跟随docker启动\r\n--privileged ：获取宿主机root权限\r\n-d ：指定容器后台启动\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Flogs\u002F:\u002Fhome\u002Fnacos\u002Flogs\u002F ：配置日志挂载目录到宿主机\u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Flogs\u002F\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Fconf\u002F:\u002Fhome\u002Fnacos\u002Fconf\u002F ：配置挂载宿主机目录\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fnacos\u002Fdata\u002F:\u002Fhome\u002Fnacos\u002Fdata\u002F ：数据挂载宿主机目录\r\nnacos\u002Fnacos-server:v2.3.2 ：镜像名称\r\n```\r\n\r\n\r\n\r\n### 4.5\t可视化访问\r\n\r\n打开浏览器访问：http:\u002F\u002Fip:8848\u002Fnacos\u002F  首次访问会跳转到登录页，账号\u002F密码都是nacos\r\n\r\n\r\n\r\n# 5\t安装RabbitMQ\r\n\r\n### 5.1\t拉取镜像\r\n\r\n```shell\r\ndocker pull rabbitmq\r\n```\r\n\r\n\r\n\r\n### 5.2\t运行容器\r\n\r\n```shell\r\n# 运行容器\r\ndocker run --name rabbitmq -p 5672:5672 -p 15672:15672 -d rabbitmq\r\n\r\n# 指定账号、密码\r\ndocker run --name rabbitmq -p 5672:5672 -p 15672:15672 \\\r\n--hostname rabbitmq \\\r\n-e RABBITMQ_DEFAULT_VHOST=my_vhost \\\r\n-e RABBITMQ_DEFAULT_USER=guest \\\r\n-e RABBITMQ_DEFAULT_PASS='!QAZ2wsx#EDC' \\\r\n-d rabbitmq\r\n```\r\n\r\n参数说明：\r\n\r\n```shell\r\n-p 指定服务运行的端口（5672：应用访问端口；15672：控制台Web端口号）；\r\n--hostname 主机名（RabbitMQ的一个重要注意事项是它根据所谓的 “节点名称” 存储数据，默认为主机名）\r\n-e 指定环境变量；（RABBITMQ_DEFAULT_VHOST：默认虚拟机名；RABBITMQ_DEFAULT_USER：默认的用户名；RABBITMQ_DEFAULT_PASS：默认用户名的密码）\r\n```\r\n\r\n\r\n\r\n### 5.3\t访问\r\n\r\n```shell\r\n# 查看运行的容器\r\ndocker ps\r\n\r\n# 进入rabbitmq\r\ndocker exec -it rabbitmq \u002Fbin\u002Fbash\r\n# 启动web管理\r\nrabbitmq-plugins enable rabbitmq_management\r\n```\r\n\r\n浏览器打开web管理端：[http:\u002F\u002Fip:15672](http:\u002F\u002Fip:15672\u002F)  ，默认账号\u002F密码：guest\u002Fguest\r\n\r\n\r\n\r\n# 6\t安装 Elasticsearch\r\n\r\n### 6.1\t安装Elasticsearch\r\n\r\ngithub网址：https:\u002F\u002Fgithub.com\u002Felastic\u002Felasticsearch\u002Freleases\r\n\r\n#### 6.1.1\t安装7.x 版本\r\n\r\n##### 6.1.1.1\t直接运行\r\n\r\n###### 6.1.1.1.1\t拉取镜像\r\n\r\n```shell\r\ndocker pull elasticsearch:7.17.21\r\n```\r\n\r\n###### 6.1.1.1.2\t创建并启动容器\r\n\r\n```shell\r\ndocker run --name es -p 9200:9200 -p 9300:9300 \\\r\n--privileged=true \\\r\n--restart=always \\\r\n-e \"discovery.type=single-node\" \\\r\n-e \"http.host=0.0.0.0\" \\\r\n-e \"xpack.security.enabled=true\" \\\r\n-e \"xpack.security.transport.ssl.enabled=true\" \\\r\n-e ES_JAVA_OPTS=\"-Xms64m -Xmx128m\" \\\r\n-e ELASTIC_USERNAME=elastic \\\r\n-e ELASTIC_PASSWORD=!QAZ2wsx#EDC \\\r\n-d elasticsearch:7.17.21\r\n```\r\n\r\n\r\n\r\n##### 6.1.1.2\t挂载目录方式\r\n\r\n###### 6.1.1.2.1\t拉取镜像\r\n\r\n```shell\r\ndocker pull elasticsearch:7.17.21\r\n```\r\n\r\n\r\n\r\n###### 6.1.1.2.2\t创建挂载目录\r\n\r\n```shell\r\n#1、创建Elasticsearch配置文件夹\r\nmkdir -p \u002Fusr\u002Flocal\u002Fsoftware\u002Felasticsearch\u002Fconfig\r\n#2、创建Elasticsearch数据文件夹\r\nmkdir -p \u002Fusr\u002Flocal\u002Fsoftware\u002Felasticsearch\u002Fdata\r\n#3、创建Elasticsearch插件文件夹（如：ik）\r\nmkdir -p \u002Fusr\u002Flocal\u002Fsoftware\u002Felasticsearch\u002Fplugins\r\n```\r\n\r\n创建并写入```elasticsearch.yml```配置：\r\n\r\n```shell\r\nvi \u002Fusr\u002Flocal\u002Fsoftware\u002Felasticsearch\u002Fconfig\u002Felasticsearch.yml\r\n```\r\n\r\n输入内容：\r\n\r\n```shell\r\n# 配置监听的地址，0.0.0.0任意访问\r\nhttp.host: 0.0.0.0\r\n\r\n# 如果要开启账号密码登录，则加入下面的配置\r\n# 开启xpack认证机制，使用账号密码登录\r\nxpack.security.enabled: true\r\nxpack.security.transport.ssl.enabled: true\r\n```\r\n\r\n赋予文件夹权限，不授权可能无法访问：\r\n\r\n```shell\r\nchmod -R 777 \u002Fusr\u002Flocal\u002Fsoftware\u002Felasticsearch\u002F\r\n```\r\n\r\n\r\n\r\n###### 6.1.1.2.3\t运行容器\r\n\r\n配置账号密码方式，```elasticsearch.yml```文件中必需开启鉴权：\r\n\r\n```shell\r\ndocker run --name es -p 9200:9200 -p 9300:9300 \\\r\n--privileged=true \\\r\n--restart=always \\\r\n-e \"discovery.type=single-node\" \\\r\n-e ES_JAVA_OPTS=\"-Xms128m -Xmx256m\" \\\r\n-e ELASTIC_USERNAME=elastic \\\r\n-e ELASTIC_PASSWORD='!QAZ2wsx#EDC' \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Felasticsearch\u002Fconfig\u002Felasticsearch.yml:\u002Fusr\u002Fshare\u002Felasticsearch\u002Fconfig\u002Felasticsearch.yml \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Felasticsearch\u002Fdata:\u002Fusr\u002Fshare\u002Felasticsearch\u002Fdata\u002F \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Felasticsearch\u002Fplugins:\u002Fusr\u002Fshare\u002Felasticsearch\u002Fplugins\u002F \\\r\n-d elasticsearch:7.17.21\r\n```\r\n\r\n参数说明：\r\n\r\n```shell\r\n--name ： 容器名称\r\n-p 9200:9200 ：将容器的9200端口映射到宿主机9200端口\r\n-p 9300:9300 ：将容器的9300端口映射到宿主机9300端口，目的是集群互相通信\r\n--privileged ：获取宿主机root权限\r\n--restart=always ：总是跟随docker启动\r\n\r\n-e \"discovery.type=single-node\"：单例模式\r\n-e ES_JAVA_OPTS=\"-Xms64m -Xmx128m\" ：配置jvm内存大小\r\n\r\n# 将配置文件\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Felasticsearch\u002Fconfig\u002Felasticsearch.yml:\u002Fusr\u002Fshare\u002Felasticsearch\u002Fconfig\u002Felasticsearch.yml \r\n# 挂载数据目录\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Felasticsearch\u002Fdata:\u002Fusr\u002Fshare\u002Felasticsearch\u002Fdata \r\n# 挂载es插件目录\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Felasticsearch\u002Fplugins:\u002Fusr\u002Fshare\u002Felasticsearch\u002Fplugins \r\n\r\n-d ：指定容器后台启动\r\nelasticsearch:7.17.21 ：镜像名称\r\n```\r\n\r\n\r\n\r\n###### 6.1.1.2.4\t设置密码\r\n\r\n如果不在```docker run```启动的时候配置密码，可以在这里配置，前提必须开启`xpack.security.enabled: true`鉴权，否则无法访问，操作步骤如下：\r\n\r\n```shell\r\n# 进入容器\r\ndocker exec -it es \u002Fbin\u002Fbash\r\n# 切换目录\r\ncd \u002Fusr\u002Fshare\u002Felasticsearch\u002Fbin\u002F\r\n# 配置密码\r\n.\u002Felasticsearch-setup-passwords interactive\r\n```\r\n\r\n账号为：```elastic```，会弹出需要输入一连串的密码，内容如下：\r\n\r\n```shell\r\nroot@756575de7887:\u002Fusr\u002Fshare\u002Felasticsearch\u002Fbin# .\u002Felasticsearch-setup-passwords interactive\r\nInitiating the setup of passwords for reserved users elastic,apm_system,kibana,kibana_system,logstash_system,beats_system,remote_monitoring_user.\r\nYou will be prompted to enter passwords as the process progresses.\r\nPlease confirm that you would like to continue [y\u002FN]y\r\n\r\nEnter password for [elastic]:\r\nReenter password for [elastic]:\r\nEnter password for [apm_system]:\r\nReenter password for [apm_system]:\r\nEnter password for [kibana_system]:\r\nReenter password for [kibana_system]:\r\nEnter password for [logstash_system]:\r\nReenter password for [logstash_system]:\r\nEnter password for [beats_system]:\r\nReenter password for [beats_system]:\r\nEnter password for [remote_monitoring_user]:\r\nReenter password for [remote_monitoring_user]:\r\nChanged password for user [apm_system]\r\nChanged password for user [kibana_system]\r\nChanged password for user [kibana]\r\nChanged password for user [logstash_system]\r\nChanged password for user [beats_system]\r\nChanged password for user [remote_monitoring_user]\r\nChanged password for user [elastic]\r\n```\r\n\r\n\r\n\r\n###### 6.1.1.2.5\t验证\r\n\r\n```shell\r\ncurl http:\u002F\u002Flocalhost:9200\r\n```\r\n\r\n返回如下结果表示Docker安装和运行ElasticSearch服务成功：\r\n\r\n```shell\r\n{\r\n  \"name\" : \"UltKQt-\",\r\n  \"cluster_name\" : \"elasticsearch\",\r\n  \"cluster_uuid\" : \"DR-i6GrxQbKE70_ZJhwDLQ\",\r\n  \"version\" : {\r\n    \"number\" : \"5.6.12\",\r\n    \"build_hash\" : \"cfe3d9f\",\r\n    \"build_date\" : \"2018-09-10T20:12:43.732Z\",\r\n    \"build_snapshot\" : false,\r\n    \"lucene_version\" : \"6.6.1\"\r\n  },\r\n  \"tagline\" : \"You Know, for Search\"\r\n}\r\n```\r\n\r\n\r\n\r\n#### 6.1.2\t安装8.x 版本\r\n\r\n官方安装文档：https:\u002F\u002Fwww.elastic.co\u002Fguide\u002Fen\u002Felasticsearch\u002Freference\u002F8.4\u002Fdocker.html\r\n\r\n##### 6.1.2.1\t直接运行\r\n\r\n###### 6.1.2.1.1\t拉取镜像\r\n\r\n```shell\r\ndocker pull elasticsearch:8.4.0\r\n```\r\n\r\n###### 6.1.2.1.2\t启动容器—终端显示随机密码\r\n\r\n第一次运行启动Elasticsearch，会生成用户密码并输出到终端，再加上用于注册Kibana的注册令牌。不能添加jvm参数。\r\n\r\n```shell\r\ndocker run --name es -p 9200:9200 -p 9300:9300 \\\r\n--privileged=true \\\r\n--restart=always \\\r\n-e \"discovery.type=single-node\" \\\r\n-e \"cluster.name=es-cluster\" \\\r\n-it elasticsearch:8.4.0\r\n```\r\n\r\n命令参数：\r\n\r\n```shell\r\n--name ： 容器名称\r\n-p 9200:9200 ：将容器的9200端口映射到宿主机9200端口\r\n-p 9300:9300 ：将容器的9300端口映射到宿主机9300端口，目的是集群互相通信，单例模式可以不用开启映射\r\n--privileged ：获取宿主机root权限\r\n--restart=always ：总是跟随docker启动\r\n-e \"discovery.type=single-node\"：单例模式\r\n-e \"cluster.name=es-cluster\" ：集群名称\r\n-it :终端输入输出显示\r\n```\r\n\r\n\r\n\r\n终端输出信息如下，包含密码，kibana令牌，集群token：\r\n\r\n```shell\r\n-----------------------------------------------------------------------------------------------\r\n-> Elasticsearch security features have been automatically configured!\r\n-> Authentication is enabled and cluster connections are encrypted.\r\n\r\n->  Password for the elastic user (reset with `bin\u002Felasticsearch-reset-password -u elastic`):\r\n  1SG*7Akq+dDRcQNq_VY-\r\n\r\n->  HTTP CA certificate SHA-256 fingerprint:\r\n  f395bf570c8823b67027babcba2faf6c5fbae11521b172d566436013468e766c\r\n\r\n->  Configure Kibana to use this cluster:\r\n* Run Kibana and click the configuration link in the terminal when Kibana starts.\r\n* Copy the following enrollment token and paste it into Kibana in your browser (valid for the next 30 minutes):\r\n  eyJ2ZXIiOiI4LjQuMCIsImFkciI6WyIxNzIuMTcuMC4yOjkyMDAiXSwiZmdyIjoiZjM5NWJmNTcwYzg4MjNiNjcwMjdiYWJjYmEyZmFmNmM1ZmJhZTExNTIxYjE3MmQ1NjY0MzYwMTM0NjhlNzY2YyIsImtleSI6InNyZzR5bzhCWEpxSUhvRzBrdUctOmNVdmRBeGVDU1Ytbk1VQkFHcFZneHcifQ==\r\n\r\n-> Configure other nodes to join this cluster:\r\n* Copy the following enrollment token and start new Elasticsearch nodes with `bin\u002Felasticsearch --enrollment-token \u003Ctoken>` (valid for the next 30 minutes):\r\n  eyJ2ZXIiOiI4LjQuMCIsImFkciI6WyIxNzIuMTcuMC4yOjkyMDAiXSwiZmdyIjoiZjM5NWJmNTcwYzg4MjNiNjcwMjdiYWJjYmEyZmFmNmM1ZmJhZTExNTIxYjE3MmQ1NjY0MzYwMTM0NjhlNzY2YyIsImtleSI6InNiZzR5bzhCWEpxSUhvRzBrdUctOm1HeTNNYmgxUVhHYXJPbF9MQUh1VVEifQ==\r\n\r\n  If you're running in Docker, copy the enrollment token and run:\r\n  `docker run -e \"ENROLLMENT_TOKEN=\u003Ctoken>\" docker.elastic.co\u002Felasticsearch\u002Felasticsearch:8.4.0`\r\n-----------------------------------------------------------------------------------------------\r\n```\r\n\r\n退出终端界面：`Ctrl + c` ，退出终端后，容器可能会停止，这时候重新启动容器即可。\r\n\r\n\r\n\r\n###### 6.1.2.1.3\t启动容器—自定义密码\r\n\r\n```shell\r\ndocker run --name es -p 9200:9200 \\\r\n--privileged=true \\\r\n--restart=always \\\r\n-e \"discovery.type=single-node\" \\\r\n-e \"cluster.name=es-cluster\" \\\r\n-e ELASTIC_USERNAME=elastic \\\r\n-e ELASTIC_PASSWORD='!QAZ2wsx#EDC' \\\r\n-e ES_JAVA_OPTS=\"-Xms64m -Xmx128m\" \\\r\n-d elasticsearch:8.4.0\r\n```\r\n\r\n命令参数：\r\n\r\n```shell\r\n--name ： 容器名称\r\n-p 9200:9200 ：将容器的9200端口映射到宿主机9200端口\r\n-p 9300:9300 ：将容器的9300端口映射到宿主机9300端口，目的是集群互相通信，单例模式可以不用开启映射\r\n--privileged ：获取宿主机root权限\r\n--restart=always ：总是跟随docker启动\r\n-e \"discovery.type=single-node\"：单例模式\r\n-e \"cluster.name=es-cluster\" ：集群名称\r\n-e ELASTIC_USERNAME=elastic ：账号\r\n-e ELASTIC_PASSWORD='!QAZ2wsx#EDC' ：密码\r\n-e ES_JAVA_OPTS=\"-Xms64m -Xmx128m\" ：jvm参数\r\n-d ：后台运行\r\n```\r\n\r\n\r\n\r\n###### 6.1.2.1.4\t修改密码及生成Kibana Token\r\n\r\n```shell\r\n# 进入容器，在容器的~目录下，绝对路径即：\u002Fusr\u002Fshare\u002Felasticsearch\r\ndocker exec -it es \u002Fbin\u002Fbash\r\n# 重新生成一个随机密码\r\nbin\u002Felasticsearch-reset-password -u elastic\r\n# 设置自定义密码\r\nbin\u002Felasticsearch-reset-password -u elastic -i\r\n\r\n# 修改账号密码后，需要重新生成 kibane token\r\nbin\u002Felasticsearch-create-enrollment-token -s kibana\r\n```\r\n\r\n###### 6.1.2.1.5\t关闭密码认证\r\n\r\n```shell\r\n# 将容器中的elasticsearch.yml复制到本地，然后关闭密码认证，再拷贝到容器中，再重启容器即可；\r\ndocker cp es:\u002Fusr\u002Fshare\u002Felasticsearch\u002Fconfig\u002Felasticsearch.yml .\r\n# 关闭yml中的密码认证，修改成false\r\nxpack.security.enabled: false\r\nxpack.security.enrollment.enabled: false\r\n\r\n# 在复制到容器中\r\ndocker cp elasticsearch.yml es:\u002Fusr\u002Fshare\u002Felasticsearch\u002Fconfig\u002Felasticsearch.yml\r\n# 重启容器\r\ndocker restart es\r\n```\r\n\r\n\r\n\r\n###### 6.1.2.1.6\t验证\r\n\r\n```shell\r\n# 如果没开启密码，则使用http访问\r\nhttp:\u002F\u002Flocalhost:9200\r\n# 开启密码，则使用https\r\nhttps:\u002F\u002Flocalhost:9200\r\n```\r\n\r\n###### 6.1.2.1.7\t常见异常\r\n\r\n（1）启动过程报操作系统虚拟内存不够的问题？\r\n\r\n**报错信息：**`bootstrap check failure [1] of [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144] `\r\n\r\n**解决方法**:\r\n\r\n（a）临时修改（不会在重启后保留）：执行以下命令来临时提高`vm.max_map_count`的值:\r\n\r\n```shell\r\nsudo sysctl -w vm.max_map_count=262144\r\n```\r\n\r\n（b）永久修改：编辑`\u002Fetc\u002Fsysctl.conf`文件，添加以下行:\r\n\r\n```shell\r\nvm.max_map_count=262144\r\n```\r\n\r\n执行以下命令来使其立即生效：\r\n\r\n```shell\r\nsudo sysctl -p\r\n```\r\n\r\n\r\n\r\n#### 6.1.3\t安装ik分词器\r\n\r\nes默认分词器对中文并不友好，中文只是简单的被分成了一个个汉字，如“手机”，仅仅是被分成“手”和“机”，这并不是我们想要的结果，我们想要的是包含有”手机“二字的内容，因此默认分词器无法满足。\r\n\r\nik分词器版本号必须和es版本号一致，如果官网没有对应的版本，请参考下一章节：```es和ik分词器版本一致问题```\r\n\r\n##### 6.1.3.1\t在线安装\r\n\r\n```shell\r\n# 进入容器内部\r\ndocker exec -it es \u002Fbin\u002Fbash\r\n# 进入bin目录\r\ncd \u002Fusr\u002Fshare\u002Felasticsearch\u002Fbin\r\n\r\n# 在线下载并安装\r\n.\u002Felasticsearch-plugin  install https:\u002F\u002Fgithub.com\u002Finfinilabs\u002Fanalysis-ik\u002Freleases\u002Fdownload\u002Fv7.17.18\u002Felasticsearch-analysis-ik-7.17.18.zip\r\n\r\n# 重启es，或者直接重启容器\r\ndocker restart es\r\n# 查看日志，如果没报错则表明安装成功\r\ndocker logs -f es\r\n```\r\n\r\n\r\n\r\n##### 6.1.3.2\t离线安装\r\n\r\n官网下载ik压缩包，地址：https:\u002F\u002Fgithub.com\u002Finfinilabs\u002Fanalysis-ik\r\n\r\n```shell\r\n# 这里直接下载，也可以本地下载在上传服务器\r\nwget https:\u002F\u002Fgithub.com\u002Finfinilabs\u002Fanalysis-ik\u002Freleases\u002Fdownload\u002Fv7.17.18\u002Felasticsearch-analysis-ik-7.17.18.zip\r\n\r\n# 解压到指定目录，没有目录自动创建\r\nunzip elasticsearch-analysis-ik-7.17.18.zip -d ik\r\n\r\n# 将文件移动至elasticsearch安装目录下的plugins文件夹下\r\ndocker cp ik es:\u002Fusr\u002Fshare\u002Felasticsearch\u002Fplugins\r\n\r\n# 重启es，或者直接重启容器\r\ndocker restart es\r\n# 查看日志，如果没报错则表明安装成功\r\ndocker logs -f es\r\n```\r\n\r\n\r\n\r\n##### 6.1.3.3\t通过kibana测试ik分词器\r\n\r\nkibana安装步骤参考下一章，这里打开浏览器：http:\u002F\u002FIP:5601\u002Fapp\u002Fdev_tools#\u002Fconsole\r\n\r\n**（1）ik分词器**\r\n\r\n```json\r\nGET _analyze\r\n{\r\n  \"analyzer\": \"ik_smart\",\r\n  \"text\": \"程序员青年2024年发表的文章集合\"\r\n}\r\n```\r\n\r\n得到的响应结果如下：\r\n\r\n```json\r\n{\r\n  \"tokens\" : [\r\n    {\r\n      \"token\" : \"程序员\",\r\n      \"start_offset\" : 0,\r\n      \"end_offset\" : 3,\r\n      \"type\" : \"CN_WORD\",\r\n      \"position\" : 0\r\n    },\r\n    {\r\n      \"token\" : \"青年\",\r\n      \"start_offset\" : 3,\r\n      \"end_offset\" : 5,\r\n      \"type\" : \"CN_WORD\",\r\n      \"position\" : 1\r\n    },\r\n    \u002F\u002F省略.......\r\n  ]\r\n}\r\n\r\n```\r\n\r\n（2）es默认分词器\r\n\r\n```shell\r\nGET _analyze\r\n{\r\n  \"analyzer\": \"standard\",\r\n  \"text\": \"程序员学习java太棒了！\"\r\n}\r\n```\r\n\r\n结果：如果是中文，只是\r\n\r\n```shell\r\n{\r\n  \"tokens\" : [\r\n    {\r\n      \"token\" : \"程\",\r\n      \"start_offset\" : 0,\r\n      \"end_offset\" : 1,\r\n      \"type\" : \"\u003CIDEOGRAPHIC>\",\r\n      \"position\" : 0\r\n    },\r\n    {\r\n      \"token\" : \"序\",\r\n      \"start_offset\" : 1,\r\n      \"end_offset\" : 2,\r\n      \"type\" : \"\u003CIDEOGRAPHIC>\",\r\n      \"position\" : 1\r\n    },\r\n    {\r\n      \"token\" : \"员\",\r\n      \"start_offset\" : 2,\r\n      \"end_offset\" : 3,\r\n      \"type\" : \"\u003CIDEOGRAPHIC>\",\r\n      \"position\" : 2\r\n    },\r\n    {\r\n      \"token\" : \"学\",\r\n      \"start_offset\" : 3,\r\n      \"end_offset\" : 4,\r\n      \"type\" : \"\u003CIDEOGRAPHIC>\",\r\n      \"position\" : 3\r\n    },\r\n    {\r\n      \"token\" : \"习\",\r\n      \"start_offset\" : 4,\r\n      \"end_offset\" : 5,\r\n      \"type\" : \"\u003CIDEOGRAPHIC>\",\r\n      \"position\" : 4\r\n    },\r\n    {\r\n      \"token\" : \"java\",\r\n      \"start_offset\" : 5,\r\n      \"end_offset\" : 9,\r\n      \"type\" : \"\u003CALPHANUM>\",\r\n      \"position\" : 5\r\n    },\r\n    {\r\n      \"token\" : \"太\",\r\n      \"start_offset\" : 9,\r\n      \"end_offset\" : 10,\r\n      \"type\" : \"\u003CIDEOGRAPHIC>\",\r\n      \"position\" : 6\r\n    },\r\n    {\r\n      \"token\" : \"棒\",\r\n      \"start_offset\" : 10,\r\n      \"end_offset\" : 11,\r\n      \"type\" : \"\u003CIDEOGRAPHIC>\",\r\n      \"position\" : 7\r\n    },\r\n    {\r\n      \"token\" : \"了\",\r\n      \"start_offset\" : 11,\r\n      \"end_offset\" : 12,\r\n      \"type\" : \"\u003CIDEOGRAPHIC>\",\r\n      \"position\" : 8\r\n    }\r\n  ]\r\n}\r\n```\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n#### 6.1.4\tes和ik分词器版本一致问题\r\n\r\n**问题**：IK分词器版本和ES版本不一致，无法找到和自己ES版本匹配的分词器问题。\r\n\r\nIK分词器，提供的插件版本，远赶不上ES的更新版本，在使用过程中，不一定能顺利的找到与自己使用的ES版本相对应。在ES使用与当前版本不同版本的Ik分词器，在启动的过程中，会校验版本，无法通过则停止运行。ik分词器地址：https:\u002F\u002Fgithub.com\u002Finfinilabs\u002Fanalysis-ik\u002Freleases\r\n\r\n**解决方案**\r\n\r\n最简单的方式就是，选一个最接近的版本下载，然后修改一个配置即可。操作步骤如下：\r\n\r\n（1）官网下载ik分词器，并解压。如：```elasticsearch-analysis-ik-7.17.18.zip```\r\n\r\n（2）解压到指定目录，如：ik\r\n\r\n```shell\r\n# 解压到指定目录，没有目录自动创建\r\nunzip elasticsearch-analysis-ik-7.17.18.zip -d ik\r\n```\r\n\r\n（3）进入到解压目录下，修改```plugin-descriptor.properties```文件中的版本号，修改跟es版本号一致即可，主要有version和elasticsearch.version这两处，如：将```version=7.17.18``` 修改为```version=7.17.21```，将```elasticsearch.version=7.17.18```修改为```elasticsearch.version=7.17.21```。操作如下：\r\n\r\n```shell\r\n# 进入解压目录\r\ncd ik\r\n# 打开plugin-descriptor.properties文件\r\nvi plugin-descriptor.properties\r\n```\r\n\r\n修改文件中的版本内容如下：\r\n\r\n```shell\r\n# 'version': plugin's version\r\n# 修改版本跟es版本号一致\r\nversion=7.17.21\r\n\r\n# plugins with the incorrect elasticsearch.version.\r\n# 修改版本号和es版本号一致\r\nelasticsearch.version=7.17.21\r\n```\r\n\r\n（4）将ik分词器复制到es容器中，并重启容器\r\n\r\n```shell\r\n# 将文件移动至elasticsearch安装目录下的plugins文件夹下\r\ndocker cp ik es:\u002Fusr\u002Fshare\u002Felasticsearch\u002Fplugins\r\n# 重启es，或者直接重启容器\r\ndocker restart es\r\n```\r\n\r\n\r\n\r\n### 6.2\t安装可视化管理界面\r\n\r\nelasticsearch 客户端为什么要安装两个？\r\n\r\n​\t**es-head**：观察数据非常好，但是操作命令却不怎么友好，没办法做对应提示。本地浏览器插件的方式安装。\r\n\r\n​\t**kibana**：恰好跟 es-head 相反，操作命令很好，提示非常智能，但是观察数据相对麻烦，查看数据不怎么好。服务器上安装。\r\n\r\n​\t因此，可以的话，两个客户端都安装。\r\n\r\n\r\n\r\n#### 6.2.1\t安装kibana 7.x版本\r\n\r\n官网：https:\u002F\u002Fwww.elastic.co\u002Fguide\u002Fen\u002Fkibana\u002Fcurrent\u002Fdocker.html\r\n\r\n下载：https:\u002F\u002Fwww.elastic.co\u002Fcn\u002Fdownloads\u002Fpast-releases#kibana\r\n\r\n##### 6.2.1.1\t拉取镜像\r\n\r\n```shell\r\n# 版本必须跟es一致\r\ndocker pull kibana:7.17.21\r\n```\r\n\r\n##### 6.2.1.2\t运行容器\r\n\r\n```shell\r\n# 需要创建网络桥接器，容器都加入这个局域网中，容器之间才能互相访问\r\ndocker run --name kibana \\\r\n-e ELASTICSEARCH_HOSTS=http:\u002F\u002Fes:9200 \\\r\n--network=es-net \\\r\n-p 5601:5601 \\\r\n-d kibana:7.17.21\r\n```\r\n\r\n如果es配置了登录账号密码，则指定账号密码运行：\r\n\r\n```shell\r\ndocker run --name kibana \\\r\n-e ELASTICSEARCH_HOSTS=http:\u002F\u002F106.53.110.52:9200 \\\r\n-e ELASTICSEARCH_USERNAME=\"elastic\" \\\r\n-e ELASTICSEARCH_PASSWORD=\"!QAZ2wsx#EDC\" \\\r\n-p 5601:5601 \\\r\n-d kibana:7.17.21\r\n```\r\n\r\n参数说明：\r\n\r\n```shell\r\n--network es-net ：加入一个名为es-net的网络中，与elasticsearch在同一个网络中\r\n-e ELASTICSEARCH_HOSTS=http:\u002F\u002Fes:9200 设置elasticsearch的地址，因为kibana已经与elasticsearch在一个网络，因此可以用容器名直接访问elasticsearch\r\n-p 5601:5601：端口映射配置\r\n```\r\n\r\n\r\n\r\n##### 6.2.1.3\t访问\r\n\r\n kibana启动一般比较慢，需要多等待一会，可以通过命令：\r\n\r\n```shell\r\ndocker logs -f kibana\r\n```\r\n\r\n浏览器访问：http:\u002F\u002Flocalhost:5601\u002Fapp\u002Fhome#\u002F\r\n\r\n从首页进入数据操作界面：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fdev-tools.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n进入命令操作界面：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fkibana.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n创建索引，查看索引：\r\n\r\n```shell\r\n# 创建索引\r\nPUT \u002Fmy_index\r\n{\r\n  \"settings\": {\r\n    \"number_of_shards\": 5,  \u002F\u002F设置5个片区\r\n    \"number_of_replicas\": 1 \u002F\u002F复制集。设置1个备份\r\n  }\r\n}\r\n# 查看索引\r\nGET \u002Fmy_index\r\n# 删除索引\r\nDELETE \u002Fmy_index\r\n```\r\n\r\n\r\n\r\n#### 6.2.2\t安装kibana 8.x版本\r\n\r\n官方安装文档：https:\u002F\u002Fwww.elastic.co\u002Fguide\u002Fen\u002Fkibana\u002F8.4\u002Fdocker.html\r\n\r\n##### 6.2.2.1\t拉取镜像\r\n\r\n```shell\r\ndocker pull kibana:8.4.0\r\n```\r\n\r\n##### 6.2.2.2\t运行\r\n\r\n```shell\r\n# 想连接到elasticsearch，必须在同一网络中\r\n# 创建网络\r\ndocker network create elastic\r\n# 将es容器接入到网络中\r\ndocker network connect elastic es\r\n# 创建kibane，并接入网络\r\ndocker run --name kibana --net elastic -p 5601:5601 kibana:8.4.0\r\n```\r\n\r\n##### 6.2.2.3\t配置\r\n\r\n容器运行后，终端显示如下：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fkibana8.x.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n复制控制台输出地址，将```0.0.0.0```修改成自己的IP，如：http:\u002F\u002Flocalhost:5601\u002F?code=708523 到浏览器访问。\r\n\r\n**（1）es不开启密码认证**\r\n\r\n​\t\t进入ip配置界面：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fkibana-config0.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t\t输如ip地址，无密码认证，需要使用http协议，往下一路点击确认即可：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fkibana-config1.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n\r\n\r\n**（2）es开启密码认证情况下**\r\n\r\n按照如下配置token，如果配置一直超时，则删掉es、kibana容器后再启动重试即可。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fkibana8.x-config.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n如果时间过长，弹出如下界面：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fkibana8.x-config2.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n则根据kibana终端显示的校验码输入即可，终端显示如下：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fkibana8.x-config3.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n退出终端界面：`Ctrl + c` ，退出终端后，容器可能会停止，这时候重新启动容器即可。\r\n\r\n\r\n\r\n##### 6.2.2.4\t访问\r\n\r\n参考：`6.2.1.3访问` 章节\r\n\r\n\r\n\r\n#### 6.2.3\t安装es-head\r\n\r\nElasticsearch默认的客户端工具是命令行形式的，操作起来不方便，也不能直观看到数据的展示，所以我们需要去安装一个可视化插件，但是这些插件都是基于H5开发的，在谷歌的应用商店中找到**elasticsearch-head**插件，然后安装，使用该插件能比较直观的展示服务器中的数据。\r\n\r\nes-head有两种安装方式：独立插件和浏览器插件（只能用谷歌浏览器）；\r\n\r\n独立插件方式：需要用到Node.js环境，这个属于前端的，我们后端一般不用这种方式；\r\n\r\n浏览器插件方式：\r\n\r\n​\t步骤1：将es-head压缩包，解压到如D:\\devTools\\es-head目录下；\r\n\r\n​\t\t官网下载：https:\u002F\u002Fgithub.com\u002Fmobz\u002Felasticsearch-head\r\n\r\n​\t步骤2：打开浏览器（必须是谷歌浏览器）\r\n\r\n​\t\t进入谷歌浏览器的”扩展程序“界面；\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002F进入拓展程序.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n​\t\t加载已经解压的es-head插件。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fes-head插件.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n​\t\t进入es-head客户端界面。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002F进入es-head客户端界面.png\" style=\"zoom:50%;\" \u002F>\r\n\r\n​\t\t观察ES数据\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fes-head界面.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n\r\n\r\n# 7 docker安装 PostgreSQL\r\n\r\n```shell\r\n# 下拉镜像\r\ndocker pull postgres:16\r\n# 运行\r\ndocker run --name postgres -p 5432:5432 -e POSTGRES_PASSWORD='!QAZ2wsx#EDC' --restart=always -d postgres:16\r\n\r\ndocker run --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=postgres --restart=always -d postgres:16\r\n\r\n# 默认账号：postgres\r\n```\r\n\r\n\r\n\r\n# 8\t容器间相互通信—网络\r\n\r\n在Docker中，您可以使用`docker network connect`命令将一个或多个容器连接到现有的网络，将容器都加入这个局域网中，容器间才能互相访问。以下是如何使用此命令的示例：\r\n\r\n首先，创建一个网络（如果还没有的话）：\r\n\r\n```shell\r\n# 创建网络\r\ndocker network create my_network\r\n\r\n# 查看docker网络列表\r\ndocker network ls\r\n```\r\n\r\n然后，启动一个容器并将其加入到网络中：\r\n\r\n```shell\r\ndocker run -d --name my_container --network my_network my_image\r\n```\r\n\r\n如果您已经有一个运行中的容器，并希望将其加入到同一个网络中，您可以使用`docker network connect`命令：\r\n\r\n```shell\r\ndocker network connect my_network existing_container\r\n```\r\n\r\n这里`my_network`是您想要加入的网络的名称，`existing_container`是您想要加入网络的容器的名称或ID。\r\n\r\n确保容器和网络的名称或ID是唯一的，否则您需要使用完整的ID来指定容器或网络。\r\n\r\n\r\n\r\n# 9\t安装nexus\r\n\r\n## 9.1\t镜像安装\r\n\r\n```shell\r\n# 下拉镜像\r\ndocker pull sonatype\u002Fnexus3:3.71.0\r\n\r\n# 创建挂载目录\r\nmkdir \u002Fusr\u002Flocal\u002Fsoftware\u002Fnexus\u002Fnexus-data\r\n\r\n# 运行脚本\r\ndocker run --name nexus \\\r\n-p 8081:8081 \\\r\n--privileged=true \\\r\n-e INSTALL4J_ADD_VM_PARAMS=\"-Xms1024m -Xmx1024m -XX:MaxDirectMemorySize=1024m\" \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fnexus\u002Fnexus-data:\u002Fnexus-data \\\r\n-d sonatype\u002Fnexus3:3.71.0\r\n\r\n# 如果报错，权限不够，则给挂载目录权限\r\nchmod 777 \u002Fusr\u002Flocal\u002Fsoftware\u002Fnexus\u002Fnexus-data\r\n```\r\n\r\n\r\n\r\n## 9.2\t配置\r\n\r\n（1）打开浏览器访问：http:\u002F\u002Flocalhost:8081\u002F\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fnexus-1.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n（2）进入挂载目录，获取登录密码，默认账号为：`admin`\r\n\r\n```shell\r\ncd \u002Fusr\u002Flocal\u002Fsoftware\u002Fnexus\u002Fnexus-data\r\ncat admin.password\r\n```\r\n\r\n\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fnexus-2.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n（3）点击下一步，修改密码，然后进入如下：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fnexus-3.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n## 9.3\t创建代理库\r\n\r\n​\t\t配置代理到阿里云仓库，用于代理从阿里云下载的所有内容，下次下载相同的依赖项时，它将被缓存在您的Sonatype Nexus中。您可以根据需要创建多个仓库（例如设置多个代理到其他公共仓库），然后将它们全部分组到组仓库中。\r\n\r\n​\t\t创建一个新的Maven（代理）仓库并按以下方式配置它：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fnexus-proxy.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\r\n\r\n​\t\t添加到仓库组中，并设置`maven-proxy`优先级最高，这样我们maven连接`maven-public`仓库即可，没有的依赖会自动去代理库下载，然后缓存到我们创建的`maven-proxy`代理库中。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fnexus-proxy2.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n\r\n\r\n## 9.4\t配置仓库\r\n\r\n​\t\t将上传的仓库修改为允许相同版本自动覆盖，否则无法上传相同的版本jar。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fnexus-release.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\r\n\r\n## 9.5\t批量上传本地依赖\r\n\r\n创建`mavenimport.sh` 文件，内容如下：\r\n\r\n```shell\r\n#!\u002Fbin\u002Fbash\r\n# git 执行命令\r\n# $ ! .\u002Fmavenimport.sh -u admin -p 123456 -r http:\u002F\u002F106.53.110.52:8081\u002Frepository\u002Fmh\u002F\r\nwhile getopts \":r:u:p:\" opt;do\r\n    case $opt in\r\n        r) REPO_URL=\"$OPTARG\"\r\n        ;;\r\n        u) USERNAME=\"$OPTARG\"\r\n        ;;\r\n        p) PASSWORD=\"$OPTARG\"\r\n        ;;\r\n    esac\r\ndone\r\nfind . -type f -not -path '.\u002Fmavenimport\\.sh*' -not -path '*\u002F\\.*' -not -path '*\u002F\\^archetype\\-catalog\\.xml*' -not -path '*\u002F\\^maven\\-metadata\\-local*\\.xml' -not -path '*\u002F\\^maven\\-metadata\\-deployment*\\.xml' | sed \"s|^\\.\u002F||\" | xargs -I '{}' curl -u \"$USERNAME:$PASSWORD\" -X PUT -v -T {} ${REPO_URL}\u002F{}\r\n```\r\n\r\n执行脚本：\r\n\r\n```shell\r\n# 复制脚本到maven本地依赖的目录，然后执行\r\nsh mavenimport.sh -u admin -p 123456 -r http:\u002F\u002F106.53.110.52:8081\u002Frepository\u002Fmh\u002F\r\n```\r\n\r\n\r\n\r\n# 10\t安装Kafka\r\n\r\n### 10.1\t低版本（4.0版本以前）\r\n\r\n\r\n\r\n\r\n\r\n### 10.2\t高版本\r\n\r\nkafka4.0版本之后，抛弃了zookeeper和java8，使用了jdk21版本，因此不在需要安装zookeeper。\r\n\r\n```shell\r\ndocker pull apache\u002Fkafka:4.0.0\r\n```\r\n\r\n\r\n\r\n# 11\t安装Jenkins\r\n\r\n## 11.1\tjenkins:2.525安装\r\n\r\n### 11.1.1\t镜像安装\r\n\r\n```shell\r\n# 下拉镜像\r\ndocker pull jenkins\u002Fjenkins:2.525\r\n\r\n# 创建挂着目录\r\nmkdir \u002Fusr\u002Flocal\u002Fsoftware\u002Fjenkins\r\n\r\n# 安装\r\ndocker run --name jenkins \\\r\n  --privileged=true \\\r\n  --restart=always \\\r\n  -u root \\\r\n  -p 8080:8080 \\\r\n  -p 50000:50000 \\\r\n  -v \u002Fusr\u002Flocal\u002Fsoftware\u002Fjenkins:\u002Fvar\u002Fjenkins_home \\\r\n  -d jenkins\u002Fjenkins:2.525\r\n\r\n```\r\n\r\n### 11.1.2\t访问\r\n\r\n```shell\r\n# 查看初始化密码\r\ndocker logs -f jenkins\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fjenkins-token.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n​\t打开浏览器，访问：http:\u002F\u002F192.168.3.10:8080\r\n\r\n（1）使用控制台密码登录\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fjenkins-token2.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n（2）选择插件安装\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fjenkins-custom.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n（3）安装插件\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fdocker环境部署\u002Fjenkins-custom1.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\r\n\r\n\r\n\r\n",{"_path":253,"slug":254,"title":255,"description":256,"excerpt":256,"date":229,"tags":257,"type":15,"cover":26,"content":258},"\u002Fknowledge\u002Fjava8新特性","java8新特性","Java8新特性","消费型接口Consumer\u003CT> void accept(T t) 有参数 无返回 供给型接口Supplier\u003CT> T get() 无参数 有返回 函数型接口Function\u003CT,R> R apply(T t) 有参数 有返回 断定型接口Predicate\u003CT> boolean test(T t) 有参数 返回Boo",[74],"\r\n\r\n\r\n\r\n消费型接口Consumer\u003CT>  void accept(T t)   有参数 无返回\r\n供给型接口Supplier\u003CT>  T  get()           无参数  有返回\r\n函数型接口Function\u003CT,R>  R apply(T t)     有参数  有返回\r\n断定型接口Predicate\u003CT>  boolean  test(T t)  有参数  返回Boolean值\r\n\r\n\r\n\r\n| 函数式接口                               | 方法                  | 参数类型 | 返回类型 | 作用                                          |\r\n| :--------------------------------------- | :-------------------- | :------- | :------- | :-------------------------------------------- |\r\n| BiFunction\u003CT , U, R >                    | R apply(T t, U u)     | T, U     | R        | 对 T, U 类型的参数进行操作，并返回R类型的结果 |\r\n| UnaryOperator\u003CT> (Function 子接口)       | T apply(T t)          | T        | T        | 对 T类型的参数进行一元运算，并返回R对象的结果 |\r\n| BinaryOperato\u003CT,R> (BiFunction 子接口) ) | T apply(T t1, T t2    | T, T     | T        | 对T类型的参数进行二元运算，并返回T类型的结果  |\r\n| BiConsumer\u003CT, U>                         | void accept(T t, U u) | T, U     | void     | 对T,作                                        |\r\n|                                          |                       |          |          |                                               |\n",{"_path":260,"slug":261,"title":262,"description":263,"excerpt":263,"date":229,"tags":264,"type":15,"cover":265,"content":266},"\u002Fknowledge\u002Fjava日志框架","java日志框架","Java日志框架使用","Java日志框架使用 1 日志文件 &emsp;&emsp;日志文件是用于记录系统操作事件的集合，可分为事件日志和消息日志。日志文件主要记录系统行为的时间、地点、状态等相关信息，能够帮助我们了解并监控系统状态，在发生错误或者接近某种危险状态时能够及时提醒我们处理，同时在系统产生问题时，能够帮助我们快速的定位、诊断并解决",[74,104],"\u002Fknowledge-assets\u002Fjava日志框架\u002Fconcrete-bindings.png","# Java日志框架使用\r\n\r\n# 1\t日志文件\r\n\r\n&emsp;&emsp;日志文件是用于记录系统操作事件的集合，可分为事件日志和消息日志。日志文件主要记录系统行为的时间、地点、状态等相关信息，能够帮助我们了解并监控系统状态，在发生错误或者接近某种危险状态时能够及时提醒我们处理，同时在系统产生问题时，能够帮助我们快速的定位、诊断并解决问题。\r\n\r\n# 2\tJava常用日志框架\r\n\r\n&emsp;&emsp;JUL（java.util.logging）、JCL（Apache Commons Logging）、Logback、Log4j、Log4j2、Slf4j、Jboss-logging 等。\r\n\r\n## 2.1\t日志门面\r\n\r\n&emsp;&emsp;主要有：JCL、Slf4j、Log4j2、Jboss-logging等。日志门面即日志的一个抽象层，提供了使用各种日志实现的统一接口，它只是一个接口，并没有实现类。在项目中使用日志门面提供的接口输出日志，当我们更换日志框架的时候，不需要去修改项目代码，只需要配置使用哪种日志实现框架，项目运行时就会自动调用具体日志框架输出（面向接口编程）。日志门面最流行的是使用Slf4j。项目日志文件的内容格式、保存路径等配置，需要符合具体配置的日志框架语法，因为底层真正使用的是你配置的日志框架。\r\n\r\n## 2.2\t日志实现\r\n\r\n&emsp;&emsp;主要有：JUL、Logback、Log4j、Log4j2等。日志实现是能够直接单独使用的日志框架，但当项目更换不同的日志框架时，因为每种框架的使用的方法不同，因此需要修改项目中日志输出的代码。如果使用日志门面，就能够避免修改代码这个问题。\r\n\r\n&emsp;&emsp;在项目中，一般选择一个日志门面（抽象层）+ 一个日志实现。\r\n\r\n&emsp;&emsp;Spring 框架默认使用 **JCL** 日志框架，SpringBoot 使用：**Slf4j 日志门面+ Logback 日志框架** 。\r\n\r\n# 3\tSlf4j日志门面\r\n\r\n&emsp;&emsp;官网：https:\u002F\u002Fwww.slf4j.org\u002F\r\n\r\n&emsp;&emsp;目前市面上最流行的日志门面，现在的项目中，基本上都是使用Slf4j作为我们的日志系统。\r\n\r\n## 3.1\tSlf4j 日志绑定\r\n\r\n&emsp;&emsp;开发的时，日志方法的调用，不应该直接调用日志框架具体实现，而是调用日志门面（抽象层）里的方法，即面向接口编程。\r\n\r\n&emsp;&emsp;日志绑定：**Slf4j日志门面依赖 + 日志实现依赖**。\r\n\r\n&emsp;&emsp;**日志绑定流程**：\r\n\r\n&emsp;&emsp;&emsp;（1）添加 slf4j-api 的依赖\r\n\r\n&emsp;&emsp;&emsp;（2）绑定具体的日志实现框架\r\n\r\n&emsp;&emsp;&emsp;&emsp;a 绑定已经实现了 slf4j的日志框架，直接添加对应的依赖\r\n\r\n&emsp;&emsp;&emsp;&emsp;b 绑定没有实现 slf4j的日志框架，先添加该日志框架的适配器依赖，再添加日志实现的依赖\r\n\r\n&emsp;&emsp;&emsp;（3）项目中使用 slf4j的api进行统一的日志记录\r\n\r\n&emsp;&emsp;&emsp;（4）slf4j有且仅有一个日志实现框架的绑定，如果出现多个日志实现框架，默认使用排在第一个依赖的实现\r\n\r\n&emsp;&emsp;项目中先导入 **Slf4j** 依赖，再导入**日志实现**的依赖，如果需要适配器的日志实现，只需导入适配器依赖即可，因为在适配器中已经导入了对应的日志实现依赖，当然也可以继续导入日志实现的依赖。Slf4j绑定日志实现配置图如下：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjava日志框架\u002Fconcrete-bindings.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n&emsp;&emsp;**注意**：每一个日志框架都有自己的配置文件。使用Slf4j以后，配置文件还是需要使用所选择的日志实现的配置文件。比如使用 **Slf4j** + **Logback** ，那么配置文件使用的配置需要符合 **logback** 配置要求。\r\n\r\n## 3.2\tSlf4j 的使用\r\n\r\n&emsp;&emsp;根据3.1 Slf4j日志绑定图，添加绑定依赖如下，添加依赖后，idea工具可在pom.xml文件中鼠标右键点击**Diagrams**选项，查看依赖结构图表，展开结构图表后，你会发现有的日志实现其实不用导入 **Slf4j**日志门面的依赖，如：**reload4j**日志实现，在适配器已经导入了**Slf4j**的api依赖，当然也可以导入Slf4j日志门面的依赖，不会有影响。\r\n\r\n```xml\r\n\t\u003Cdependencies>\r\n        \u003C!-- Slf4j日志门面 -->\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.slf4j\u003C\u002FgroupId>\r\n            \u003CartifactId>slf4j-api\u003C\u002FartifactId>\r\n            \u003Cversion>1.7.36\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n\r\n        \u003C!-- 使用Slf4j内置的简单日志实现 -->\r\n        \u003C!--\u003Cdependency>\r\n            \u003CgroupId>org.slf4j\u003C\u002FgroupId>\r\n            \u003CartifactId>slf4j-simple\u003C\u002FartifactId>\r\n            \u003Cversion>1.7.36\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>-->\r\n        \u003C!-- 使用logback日志实现 -->\r\n        \u003C!-- \u003Cdependency>\r\n            \u003CgroupId>ch.qos.logback\u003C\u002FgroupId>\r\n            \u003CartifactId>logback-classic\u003C\u002FartifactId>\r\n            \u003Cversion>1.2.11\u003C\u002Fversion>\r\n        \u003C\u002Fdependency> -->\r\n        \u003C!-- slf4j-nop日志开关（该日志没有不会有输出） -->\r\n        \u003C!--\u003Cdependency>\r\n            \u003CgroupId>org.slf4j\u003C\u002FgroupId>\r\n            \u003CartifactId>slf4j-nop\u003C\u002FartifactId>\r\n            \u003Cversion>1.7.36\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>-->\r\n        \r\n        \u003C!-- 使用reload4j日志实现 则只需要导入适配器，\r\n\t\t不需要在导入reload4j.jar包本身，因为在适配器依赖里已经导入了，\r\n\t\t使用reload4j日志实需要添加log4j.properties配置文件才能输出日志 -->\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.slf4j\u003C\u002FgroupId>\r\n            \u003CartifactId>slf4j-reload4j\u003C\u002FartifactId>\r\n            \u003Cversion>1.7.36\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n        \u003C!--\u003Cdependency> 不需要在导入本身jar\r\n            \u003CgroupId>ch.qos.reload4j\u003C\u002FgroupId>\r\n            \u003CartifactId>reload4j\u003C\u002FartifactId>\r\n            \u003Cversion>1.2.20\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>-->\r\n        \r\n        \u003C!-- 使用jdk的logging日志实现 -->\r\n        \u003C!--\u003Cdependency>\r\n            \u003CgroupId>org.slf4j\u003C\u002FgroupId>\r\n            \u003CartifactId>slf4j-jdk14\u003C\u002FartifactId>\r\n            \u003Cversion>1.7.25\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>-->\r\n\r\n        \u003C!-- junit单元测试 -->\r\n        \u003Cdependency>\r\n            \u003CgroupId>junit\u003C\u002FgroupId>\r\n            \u003CartifactId>junit\u003C\u002FartifactId>\r\n            \u003Cversion>4.12\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n    \u003C\u002Fdependencies>\r\n```\r\n\r\n&emsp;&emsp;测试类：\r\n\r\n```java\r\nimport org.junit.Test;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\npublic class Slf4jTest {\r\n    private static Logger log = LoggerFactory.getLogger(Slf4jTest.class);\r\n\r\n    @Test\r\n    public void test() {\r\n        \u002F\u002F使用slf4j日志门面的api，底层会自动调用具体日志实现\r\n        log.trace(\"这是 trace 日志。。。\");\r\n        log.debug(\"这是 debug 日志。。。\");\r\n        log.info(\"这是 info 日志。。。\");\r\n        log.warn(\"这是 warn 日志。。。\");\r\n        log.error(\"这是 error 日志。。。\");\r\n    }\r\n}\r\n```\r\n\r\n&emsp;&emsp;**reload4j**日志实现需要的配置 log4j.properties 文件。\r\n\r\n```properties\r\nlog4j.rootLogger=debug, stdout, R\r\n\r\nlog4j.appender.stdout=org.apache.log4j.ConsoleAppender\r\nlog4j.appender.stdout.layout=org.apache.log4j.PatternLayout\r\n\r\nlog4j.appender.stdout.layout.ConversionPattern=%5p - %m%n\r\n\r\nlog4j.appender.R=org.apache.log4j.RollingFileAppender\r\nlog4j.appender.R.File=firestorm.log\r\n\r\nlog4j.appender.R.MaxFileSize=100KB\r\nlog4j.appender.R.MaxBackupIndex=1\r\n\r\nlog4j.appender.R.layout=org.apache.log4j.PatternLayout\r\nlog4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n\r\n\r\nlog4j.logger.com.codefutures=DEBUG\r\n```\r\n\r\n\r\n\r\n## 3.3\t桥接器\u002F统一日志框架\r\n\r\n&emsp;&emsp;不同的框架，往往都有自己默认的日志框架，如：Spring（JCL），Hibernate（jboss-logging）、MyBatis等等。统一日志框架，就是将别的日志框架，也一起统一使用slf4j进行日志输出。桥接器能够解决项目中日志的遗留问题，比如以前项目中使用log4j做日志记录，现在需要切换使用logback日志框架，没有桥接器以前需要去修改项目代码，有了slf4j桥接器后，可以通过桥接器直接切换到slf4j日志门面，再使用logback日志实现输出，并不需要去修改项目代码。统一日志框架也是一样，先将框架默认的日志框架排除，再使用桥接器，最后就可以做到统一日志输出。\r\n\r\n**桥接器的使用步骤**：\r\n\r\n​\t\t（1）先去除之前的日志框架的依赖\r\n\r\n​\t\t（2）添加对应的slf4j提供的桥接器依赖（其实就是将桥接器替换掉原有的日志框架jar包）\r\n\r\n​\t\t（3）添加slf4j的具体日志实现\r\n\r\n​\t\t\t\ta 绑定已经实现了 slf4j的日志框架，直接添加对应的依赖\r\n\r\n​\t\t\t\tb 绑定没有实现 slf4j的日志框架，先添加该日志框架的适配器依赖，再添加日志实现的依赖\r\n\r\n桥接器使用示意图：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjava日志框架\u002Flegacy.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n桥接器的原理：\r\n\r\n&emsp;&emsp;其实就是偷天换日，创建一个跟框架默认使用的日志框架一样的jar包（桥接器），然后将框架默认使用的日志jar去掉，桥接器跟原来的日志框架包路径相同，具有同样方法，只是在这些方法是空的，并在这些方法中做一层跳转，跳转到slf4j日志门面，当各框架调用自己日志方法输出的时候，最终就会调用slf4j输出。\r\n\r\n```xml\r\n    \u003Cdependencies>\r\n        \u003C!-- Slf4j日志门面依赖 -->\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.slf4j\u003C\u002FgroupId>\r\n            \u003CartifactId>slf4j-api\u003C\u002FartifactId>\r\n            \u003Cversion>1.7.36\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n\r\n        \u003C!-- 使用log4j日志实现，测试类中使用log4j日志实现的方法 -->\r\n        \u003C!--\u003Cdependency>\r\n            \u003CgroupId>org.slf4j\u003C\u002FgroupId>\r\n            \u003CartifactId>slf4j-reload4j\u003C\u002FartifactId>\r\n            \u003Cversion>1.7.36\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>-->\r\n\r\n        \u003C!-- 使用slf4j桥接器（其实就是替换掉log4j的依赖） -->\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.slf4j\u003C\u002FgroupId>\r\n            \u003CartifactId>log4j-over-slf4j\u003C\u002FartifactId>\r\n            \u003Cversion>1.7.36\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n\r\n        \u003C!-- 使用logback日志实现 -->\r\n        \u003Cdependency>\r\n            \u003CgroupId>ch.qos.logback\u003C\u002FgroupId>\r\n            \u003CartifactId>logback-classic\u003C\u002FartifactId>\r\n            \u003Cversion>1.2.11\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n\r\n        \u003C!-- junit单元测试 -->\r\n        \u003Cdependency>\r\n            \u003CgroupId>junit\u003C\u002FgroupId>\r\n            \u003CartifactId>junit\u003C\u002FartifactId>\r\n            \u003Cversion>4.12\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n    \u003C\u002Fdependencies>\r\n```\r\n\r\n测试类：使用桥接器后，测试类中的代码都不需要修改（包路径不需要修改，日志输出方法也不需要修改），经过桥接器跳转后，最终会调用logback输出。\r\n\r\n```java\r\n\u002F\u002F这里使用的是log4j的对象(包路径)\r\nimport org.apache.log4j.Logger;\r\nimport org.junit.Test;\r\n\r\npublic class Slf4jBridgingTest {\r\n    \u002F\u002F 定义log4j日志对象\r\n    private static final Logger log4j = Logger.getLogger(Slf4jBridgingTest.class);\r\n    \u002F\u002F 测试桥接器\r\n    @Test\r\n    public void test() {\r\n        log4j.trace(\"这是 trace 日志。。。\");\r\n        log4j.debug(\"这是 debug 日志。。。\");\r\n        log4j.info(\"这是 info 日志。。。\");\r\n        log4j.warn(\"这是 warn 日志。。。\");\r\n        log4j.error(\"这是 error 日志。。。\");\r\n    }\r\n}\r\n\r\n```\r\n\r\n使用log4j输出日志：\r\n\r\n```java\r\nDEBUG - 这是 debug 日志。。。\r\n INFO - 这是 info 日志。。。\r\n WARN - 这是 warn 日志。。。\r\nERROR - 这是 error 日志。。。\r\n```\r\n\r\n桥接后，日志门面为logback输出日志：\r\n\r\n```java\r\n00:48:31.671 [main] DEBUG top.mengh.Slf4jBridgingTest - 这是 debug 日志。。。\r\n00:48:31.681 [main] INFO top.mengh.Slf4jBridgingTest - 这是 info 日志。。。\r\n00:48:31.681 [main] WARN top.mengh.Slf4jBridgingTest - 这是 warn 日志。。。\r\n00:48:31.681 [main] ERROR top.mengh.Slf4jBridgingTest - 这是 error 日志。。。\r\n```\r\n\r\n\r\n\r\n# 4\tlogback 日志实现的使用\r\n\r\n&emsp;&emsp;官网：https:\u002F\u002Flogback.qos.ch\u002F\r\n\r\n&emsp;&emsp;logback是由log4j创始人设计的另外一个开源日志组件，性能比log4j要好。\r\n\r\n&emsp;&emsp;logback主要分为三个模块：\r\n\r\n&emsp;&emsp;&emsp;&emsp;logback-core：其他两个模块的基础模块\r\n\r\n&emsp;&emsp;&emsp;&emsp;logback-classic：是log4j的一个改良版本，同时完整实现了slf4j的api\r\n\r\n&emsp;&emsp;&emsp;&emsp;logback-access：访问模块与servlet容器集成，提供通过http来访问日志的功能\r\n\r\n## 4.1\tlogback配置文件\r\n\r\n&emsp;&emsp;logback启动时，会依次读取以下类型的配置文件，如果均不采用，会采用默认配置。\r\n\r\n&emsp;&emsp;&emsp;&emsp;logback.groovy\r\n\r\n&emsp;&emsp;&emsp;&emsp;logback-test.xml\r\n\r\n&emsp;&emsp;&emsp;&emsp;logback.xml\r\n\r\n\r\n\r\nlogback组件之间的关系：\r\n\r\n&emsp;&emsp;Logger：日志对象，记录器。把它关联到对应的context上后，主要用于存放日志对象，也可以定义日志类型、级别。\r\n\r\n&emsp;&emsp;Appender：用于指定日志输出的目的地，目的地可以时控制台、文件、数据库等。\r\n\r\n&emsp;&emsp;Layout：负责把事件转换成字符串，格式化的日志信息输出。在logback中，Layout对象被封装在encoder中。\r\n\r\n\r\n\r\nlogback.xml文件基本配置信息：\r\n\r\n```xml\r\n\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n\u003Cconfiguration>\r\n    \u003C!-- 配置集中管理属性 -->\r\n    \u003Cproperty name=\"pattern\" value=\"[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n\"\u002F>\r\n    \u003Cproperty name=\"htmlPattern\" value=\"%-5level %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L %thread %m%n\"\u002F>\r\n    \u003C!--\r\n    日志输出格式：\r\n        %-5level\r\n        %d{yyyy-MM-dd HH:mm:ss.SSS}日期\r\n        %c类的全限定名\r\n        %M为method\r\n        %L为行号\r\n        %thread线程名称\r\n        %m或者%msg为信息\r\n        %n换行\r\n    -->\r\n\r\n    \u003C!-- 定义日志文件保存路径属性 -->\r\n    \u003Cproperty name=\"log_dir\" value=\".\u002Flogs\"\u002F>\r\n\r\n    \u003C!-- 控制台输出 appender 输出位置指定-->\r\n    \u003Cappender name=\"console\" class=\"ch.qos.logback.core.ConsoleAppender\">\r\n        \u003C!-- 控制输出流对象，默认System.out,改为System.err -->\r\n        \u003Ctarget>System.err\u003C\u002Ftarget>\r\n        \u003C!-- 日志消息格式配置 -->\r\n        \u003Cencoder class=\"ch.qos.logback.classic.encoder.PatternLayoutEncoder\">\r\n            \u003Cpattern>${pattern}\u003C\u002Fpattern>\r\n        \u003C\u002Fencoder>\r\n    \u003C\u002Fappender>\r\n\r\n    \u003C!-- 日志文件输出的 appender -->\r\n    \u003Cappender name=\"file\" class=\"ch.qos.logback.core.FileAppender\">\r\n        \u003C!-- 日志文件保持路径 -->\r\n        \u003Cfile>${log_dir}\u002Flogback.log\u003C\u002Ffile>\r\n        \u003C!-- 日志文件消息格式配置 -->\r\n        \u003Cencoder class=\"ch.qos.logback.classic.encoder.PatternLayoutEncoder\">\r\n            \u003Cpattern>${pattern}\u003C\u002Fpattern>\r\n        \u003C\u002Fencoder>\r\n        \u003C!-- 日志级别过滤器 -->\r\n        \u003Cfilter class=\"ch.qos.logback.classic.filter.LevelFilter\">\r\n            \u003C!-- 日志过滤器级别，只输出error级别的日志 -->\r\n            \u003Clevel>ERROR\u003C\u002Flevel>\r\n            \u003ConMatch>ACCEPT\u003C\u002FonMatch>\r\n            \u003ConMismatch>DENY\u003C\u002FonMismatch>\r\n        \u003C\u002Ffilter>\r\n    \u003C\u002Fappender>\r\n\r\n    \u003C!-- html格式日志文件输出 appender -->\r\n    \u003Cappender name=\"htmlFile\" class=\"ch.qos.logback.core.FileAppender\">\r\n        \u003C!-- 日志文件保存路径 -->\r\n        \u003Cfile>${log_dir}\u002Flogback.html\u003C\u002Ffile>\r\n        \u003C!-- html 消息格式配置 -->\r\n        \u003Cencoder class=\"ch.qos.logback.core.encoder.LayoutWrappingEncoder\">\r\n            \u003Clayout class=\"ch.qos.logback.classic.html.HTMLLayout\">\r\n                \u003Cpattern>${htmlPattern}\u003C\u002Fpattern>\r\n            \u003C\u002Flayout>\r\n        \u003C\u002Fencoder>\r\n    \u003C\u002Fappender>\r\n\r\n    \u003C!-- 日志文件拆分和归档压缩 的appender对象 -->\r\n    \u003Cappender name=\"rollFile\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\r\n        \u003C!-- 日志文件保持路径 -->\r\n        \u003Cfile>${log_dir}\u002Froll_logback.log\u003C\u002Ffile>\r\n        \u003C!-- 日志文件消息格式配置 -->\r\n        \u003Cencoder class=\"ch.qos.logback.classic.encoder.PatternLayoutEncoder\">\r\n            \u003Cpattern>${pattern}\u003C\u002Fpattern>\r\n        \u003C\u002Fencoder>\r\n        \u003C!-- 指定拆分规则 -->\r\n        \u003CrollingPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy\">\r\n            \u003C!-- 按照时间和压缩格式声明拆分的文件名 -->\r\n            \u003C!--\u003CfileNamePattern>${log_dir_window}\u002Frolling.%d{yyyy-MM-dd-HH-mm-ss}.%i.log.gz\u003C\u002FfileNamePattern>-->\r\n            \u003CfileNamePattern>${log_dir}\u002F%d{yyyy-MM-dd}\u002Frolling.%d{yyyy-MM-dd-HH}.%i.log.gz\u003C\u002FfileNamePattern>\r\n            \u003C!-- 以文件大小为节点 -->\r\n            \u003CmaxFileSize>1MB\u003C\u002FmaxFileSize>\r\n            \u003C!-- 以上的文件命名规则为：rolling.2022-05-01.0.log.gz，rolling.2022-05-01.1.log.gz\r\n            当文件大于1MB时，文件名后按1，2，3递增 -->\r\n        \u003C\u002FrollingPolicy>\r\n    \u003C\u002Fappender>\r\n\r\n    \u003C!-- 异步日志，提高性能，开启异步线程去执行日志输出，\r\n    不必等待日志输出完成后才执行我们的业务代码 -->\r\n    \u003Cappender name=\"async\" class=\"ch.qos.logback.classic.AsyncAppender\">\r\n        \u003C!-- 指定某个具体的 appender -->\r\n        \u003Cappender-ref ref=\"rollFile\"\u002F>\r\n    \u003C\u002Fappender>\r\n\r\n    \u003C!-- root logger配置 -->\r\n    \u003C!--\u003Croot level=\"All\">\r\n        \u003Cappender-ref ref=\"console\"\u002F>\r\n        \u003Cappender-ref ref=\"file\"\u002F>\r\n        \u003Cappender-ref ref=\"rollFile\"\u002F>\r\n        \u003Cappender-ref ref=\"htmlFile\"\u002F>\r\n       \u003Cappender-ref ref=\"async\"\u002F>\r\n    \u003C\u002Froot>-->\r\n\r\n    \u003C!-- 自定义logger对象，如果没有自定义 logger对象，默认使用root，\r\n        additivity默认为true，继承root，\r\n        自定义logger对象可以针对不同的包路径下输出不同的日志 -->\r\n    \u003Clogger name=\"top.mengh.LogbackTest\" additivity=\"false\">\r\n        \u003Cappender-ref ref=\"console\"\u002F>\r\n        \u003Cappender-ref ref=\"rollFile\"\u002F>\r\n    \u003C\u002Flogger>\r\n    \u003C!-- 自定义 logger对象 -->\r\n    \u003Clogger name=\"top.mengh.DemoTest\"  level=\"info\" additivity=\"false\">\r\n        \u003Cappender-ref ref=\"console\"\u002F>\r\n        \u003Cappender-ref ref=\"file\"\u002F>\r\n    \u003C\u002Flogger>\r\n\u003C\u002Fconfiguration>\r\n```\r\n\r\n\r\n\r\n# 5\tlog4j2的使用\r\n\r\n&emsp;&emsp;log4j2参考了logback的一些优秀设计，并修复了一些问题，因此带来了一些重大的提升，主要有：\r\n\r\n- 异常处理：在logback中，appender中的异常不会被应用感知到，但是在log4j2中，提供了一些异常处理机制；\r\n\r\n- 性能提升：log4j2相较于log4j和logback都具有很明显的性能提升；\r\n\r\n- 自动重载配置：参考了logback的设计，提供自动刷新参数配置，最实用的就是我们在生产上可以动态修改日志的级别而不需要重启应用；\r\n\r\n- 无垃圾机制：log4j2在大部分情况下，都可以使用其设计一套无垃圾机制，避免频繁的日志收集导致的jvm gc。\r\n\r\n  log4j2的性能主要体现在：异步日志，和无垃圾机制。\r\n\r\n## 5.1\tlog4j2入门\r\n\r\n&emsp;&emsp;目前市面上最主流的日志门面就是slf4j，虽然log4j2也是日志门面，但大部分人习惯了slf4j，所以一般还是将log4j2看做日志实现，slf4j + log4j2搭配使用。\r\n\r\n添加依赖\r\n\r\n```xml\r\n\t\t\u003C!-- log4j2日志门面 -->\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.apache.logging.log4j\u003C\u002FgroupId>\r\n            \u003CartifactId>log4j-api\u003C\u002FartifactId>\r\n            \u003Cversion>2.17.2\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n        \u003C!-- log4j2日志实现 -->\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.apache.logging.log4j\u003C\u002FgroupId>\r\n            \u003CartifactId>log4j-core\u003C\u002FartifactId>\r\n            \u003Cversion>2.17.2\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n```\r\n\r\njava代码\r\n\r\n```java\r\nimport org.apache.logging.log4j.LogManager;\r\nimport org.apache.logging.log4j.Logger;\r\nimport org.junit.Test;\r\n\r\npublic class Log4j2Test {\r\n    private static final Logger log = LogManager.getLogger(Log4j2Test.class);\r\n    @Test\r\n    public void test() {\r\n        log.fatal(\"这是 fatal 日志。。。\");\r\n        log.trace(\"这是 trace 日志。。。\");\r\n        log.debug(\"这是 debug 日志。。。\");\r\n        log.info(\"这是 info 日志。。。\");\r\n        log.warn(\"这是 warn 日志。。。\");\r\n        log.error(\"这是 error 日志。。。\");\r\n    }\r\n}\r\n```\r\n\r\n## 5.2\t使用slf4j作为日志门面\r\n\r\n添加依赖\r\n\r\n```xml\r\n\t\u003Cdependencies>\r\n        \u003C!-- 使用slf4j作为日志门面 -->\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.slf4j\u003C\u002FgroupId>\r\n            \u003CartifactId>slf4j-api\u003C\u002FartifactId>\r\n            \u003Cversion>1.7.36\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n        \u003C!-- 使用log4j的适配器进行绑定 -->\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.apache.logging.log4j\u003C\u002FgroupId>\r\n            \u003CartifactId>log4j-slf4j-impl\u003C\u002FartifactId>\r\n            \u003Cversion>2.17.2\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n\r\n        \u003C!-- log4j2日志门面 -->\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.apache.logging.log4j\u003C\u002FgroupId>\r\n            \u003CartifactId>log4j-api\u003C\u002FartifactId>\r\n            \u003Cversion>2.17.2\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n        \u003C!-- log4j2日志实现 -->\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.apache.logging.log4j\u003C\u002FgroupId>\r\n            \u003CartifactId>log4j-core\u003C\u002FartifactId>\r\n            \u003Cversion>2.17.2\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n\r\n        \u003Cdependency>\r\n            \u003CgroupId>junit\u003C\u002FgroupId>\r\n            \u003CartifactId>junit\u003C\u002FartifactId>\r\n            \u003Cversion>4.12\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n    \u003C\u002Fdependencies>\r\n```\r\n\r\njava代码\r\n\r\n```java\r\nimport org.junit.Test;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\npublic class Slf4jTest {\r\n    private static final Logger log = LoggerFactory.getLogger(Slf4jTest.class);\r\n\r\n    @Test\r\n    public void test() {\r\n        log.trace(\"这是 trace 日志。。。\");\r\n        log.debug(\"这是 debug 日志。。。\");\r\n        log.info(\"这是 info 日志。。。\");\r\n        log.warn(\"这是 warn 日志。。。\");\r\n        log.error(\"这是 error 日志。。。\");\r\n    }\r\n}\r\n\r\n```\r\n\r\n\r\n\r\n## 5.3\tlog4j2配置\r\n\r\n&emsp;&emsp;log4j2默认加载classpath下的 `log4j2.xml`文件中的配置。\r\n\r\n```xml\r\n\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n\u003C!--\r\nstatus=“warn” 日志框架本身的输出日志级别\r\nmonitorInterval=\"5\" 自动加载配置文件的间隔时间，不低于5秒\r\n-->\r\n\u003Cconfiguration status=\"warn\" monitorInterval=\"5\">\r\n    \u003C!-- 日志处理 -->\r\n    \u003Cappenders>\r\n        \u003C!-- 控制台输出 appender对象 -->\r\n        \u003CConsole name=\"Console\" target=\"SYSTEM_OUT\">\r\n            \u003C!-- 日志消息格式 -->\r\n            \u003CPatternLayout pattern=\"[%d{HH:mm:ss.SSS}] [%t] [%-5level] %c{36}:%L --- %m%n\"\u002F>\r\n        \u003C\u002FConsole>\r\n\r\n        \u003C!-- 日志文件输出 appender对象 -->\r\n        \u003CFile name=\"file\" fileName=\".\u002Flogs\u002Flog4j2.log\">\r\n            \u003C!-- 日志消息格式 -->\r\n            \u003CPatternLayout pattern=\"[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} --- %m%n\"\u002F>\r\n        \u003C\u002FFile>\r\n\r\n        \u003C!-- 使用随机读写流的日志文件输出，appender对象，性能提高 -->\r\n        \u003CRandomAccessFile name=\"accessFile\" fileName=\".\u002Flogs\u002Flog4j-access.log\">\r\n            \u003C!-- 日志消息格式 -->\r\n            \u003CPatternLayout pattern=\"[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%t] [%-5level] %l %c{36} --- %m%n\"\u002F>\r\n        \u003C\u002FRandomAccessFile>\r\n\r\n        \u003C!-- 按照一定规则拆分的日志文件，appender对象 -->\r\n        \u003CRollingFile name=\"rollingFile\" fileName=\".\u002Flogs\u002FrollingFile.log\"\r\n                     filePattern=\".\u002Flogs\u002F$${date:yyyy-MM-dd}\u002Frolling-%d{yyyy-MM-dd-HH}.%i.log\">\r\n            \u003C!--日志级别过滤，只接受程序中DEBUG级别的日志进行处理-->\r\n            \u003CThresholdFilter level=\"DEBUG\" onMatch=\"ACCEPT\" onMismatch=\"DENY\"\u002F>\r\n            \u003C!-- 日志消息格式 -->\r\n            \u003CPatternLayout pattern=\"[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%t] [%-5level] %l %c{36} --- %m%n\"\u002F>\r\n            \u003Cpolicies>\r\n                \u003C!-- 在系统启动时，触发拆分规则，生成一个新的日志文件 -->\r\n                \u003COnStartupTriggeringPolicy\u002F>\r\n                \u003C!-- 按照文件大小拆分，10MB -->\r\n                \u003CSizeBasedTriggeringPolicy size=\"10MB\"\u002F>\r\n                \u003C!-- 按照时间节点拆分，规则根据 filePattern 定义的-->\r\n                \u003CTemiBaseTriggeringPolicy\u002F>\r\n            \u003C\u002Fpolicies>\r\n            \u003C!-- 防止日志文件太大，造成服务器内存溢出的问题，\r\n                在同一个目录下（也就是每天），文件的个数限定为 30 个，超过就进行覆盖 -->\r\n            \u003CDefaultRolloverStrategy max=\"30\"\u002F>\r\n        \u003C\u002FRollingFile>\r\n    \u003C\u002Fappenders>\r\n    \r\n    \u003C!-- 定义logger，只有定义了logger并引入的appender，appender才会生效 -->\r\n    \u003Cloggers>\r\n        \u003C!--默认的root的logger，使用root配置日志级别-->\r\n        \u003C!--\u003Croot level=\"DEBUG\">\r\n            &lt;!&ndash; 指定日志处理器 &ndash;&gt;\r\n            \u003Cappender-ref ref=\"Console\"\u002F>\r\n            \u003Cappender-ref ref=\"file\"\u002F>\r\n        \u003C\u002Froot>-->\r\n\r\n        \u003C!-- 自定义logger对象 -->\r\n        \u003Clogger name=\"top.mengh\" additivity=\"false\">\r\n            \u003Cappender-ref ref=\"Console\"\u002F>\r\n            \u003C!--\u003Cappender-ref ref=\"file\"\u002F>\r\n            \u003Cappender-ref ref=\"accessFile\"\u002F>-->\r\n            \u003Cappender-ref ref=\"rollingFile\"\u002F>\r\n        \u003C\u002Flogger>\r\n    \u003C\u002Floggers>\r\n\u003C\u002Fconfiguration>\r\n```\r\n\r\n\r\n\r\n## 5.4\tlog4j异步日志\r\n\r\n&emsp;&emsp;log4j2的优越性能主要依靠log4j2的异步日志功能，log4j2提供了两种方式实现日志的方式，一个时通过`AsyncAppender`，一个是通过`AsyncLogger`，分别对应Appender组件和Logger组件。\r\n\r\n&emsp;&emsp;配置log4j2异步日志需要添加依赖\r\n\r\n```xml\r\n\t\t\u003C!-- log4j2异步日志依赖 -->\r\n        \u003Cdependency>\r\n            \u003CgroupId>com.lmax\u003C\u002FgroupId>\r\n            \u003CartifactId>disruptor\u003C\u002FartifactId>\r\n            \u003Cversion>3.4.4\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n```\r\n\r\n### 5.4.1\tAsyncAppender 方式\r\n\r\n​\t\t这种方式使用不多，因为它的性能跟`logback`相差无几。\r\n\r\n```xml\r\n\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n\u003Cconfiguration status=\"warn\" monitorInterval=\"5\">\r\n    \u003C!-- 日志处理 -->\r\n    \u003Cappenders>\r\n        \u003C!-- 日志文件输出 appender对象 -->\r\n        \u003CFile name=\"file\" fileName=\".\u002Flogs\u002Flog4j2.log\">\r\n            \u003C!-- 日志消息格式 -->\r\n            \u003CPatternLayout pattern=\"[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} --- %m%n\"\u002F>\r\n        \u003C\u002FFile>\r\n\r\n        \u003C!-- 使用异步日志 -->\r\n        \u003C!-- AsyncAppender 方式 -->\r\n        \u003CAsync name=\"Async\">\r\n            \u003CAppenderRef ref=\"file\"\u002F>\r\n        \u003C\u002FAsync>\r\n    \u003C\u002Fappenders>\r\n\r\n    \u003Cloggers>\r\n        \u003C!-- 自定义logger对象 -->\r\n        \u003Clogger name=\"top.mengh\" level=\"trace\" additivity=\"false\">\r\n            \u003Cappender-ref ref=\"Console\"\u002F>\r\n            \u003C!-- 使用异步日志 appender 对象 -->\r\n            \u003CAppenderRef ref=\"Async\"\u002F>\r\n        \u003C\u002Flogger>\r\n    \u003C\u002Floggers>\r\n\u003C\u002Fconfiguration>\r\n```\r\n\r\n### 5.4.2\tAsyncLogger 方式\r\n\r\n&emsp;&emsp;AsyncLogger 是官方推荐的异步方式，它可以使得调用`logger.log`返回的更快，有两种选择，可以使用全局异步和混合异步。\r\n\r\n**全局异步**：就是所有的日志都使用异步记录，在配置文件上不用做任何的改动，只需要添加一个`log4j2.component.properties`配置文件，并添加内容：\r\n\r\n```properties\r\nLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector\r\n```\r\n\r\n**混合异步（局部异步）**：就是你可以在应用中同时使用同步日志和异步日志，这使得日志的配置方式更加灵活。\r\n\r\n```xml\r\n\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n\u003Cconfiguration status=\"warn\" monitorInterval=\"5\">\r\n    \u003C!-- 日志处理 -->\r\n    \u003Cappenders>\r\n        \u003C!-- 控制台输出 appender对象 -->\r\n        \u003CConsole name=\"Console\" target=\"SYSTEM_OUT\">\r\n            \u003C!-- 日志消息格式 -->\r\n            \u003CPatternLayout pattern=\"[%d{HH:mm:ss.SSS}] [%t] [%-5level] %c{36}:%L --- %m%n\"\u002F>\r\n        \u003C\u002FConsole>\r\n\r\n        \u003C!-- 日志文件输出 appender对象 -->\r\n        \u003CFile name=\"file\" fileName=\".\u002Flogs\u002Flog4j2.log\">\r\n            \u003C!-- 日志消息格式 -->\r\n            \u003CPatternLayout pattern=\"[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} --- %m%n\"\u002F>\r\n        \u003C\u002FFile>\r\n    \u003C\u002Fappenders>\r\n\r\n    \u003Cloggers>\r\n        \u003C!-- 自定义logger对象,这里使用同步的方式 -->\r\n        \u003Clogger name=\"top.mengh.Log4j2Test\" level=\"trace\" additivity=\"false\">\r\n            \u003Cappender-ref ref=\"Console\"\u002F>\r\n        \u003C\u002Flogger>\r\n\r\n        \u003C!-- 自定义logger对象，使用异步日志 AsyncLogger 方式\r\n            includeLocation=\"false\" 关闭日志记录的行号信息，开启输出行号信息性能可能会比同步记录还差-->\r\n        \u003CAsyncLogger name=\"top.mengh.Slf4jTest\" level=\"trace\" includeLocation=\"false\" additivity=\"false\">\r\n            \u003CAppenderRef ref=\"Console\"\u002F>\r\n            \u003CAppenderRef ref=\"file\"\u002F>\r\n        \u003C\u002FAsyncLogger>\r\n    \u003C\u002Floggers>\r\n\u003C\u002Fconfiguration>\r\n```\r\n\r\n\r\n\r\n**使用异步日志需要注意的问题：**\r\n\r\n（1）如果使用异步日志，AsyncAppender 、AsyncLogger 和全局异步这三种方式不要同时出现，同时出现会造成所有日志性能跟最差的`AsyncAppender `方式一样。\r\n\r\n（2）设置`includeLocation=\"false\"`，打印行号位置信息会降低异步日志的性能，性能可能会比同步日志还差。\r\n\r\n\r\n\r\njava代码\r\n\r\n```java\r\nimport org.junit.Test;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\npublic class Slf4jTest {\r\n    private static final Logger log = LoggerFactory.getLogger(Slf4jTest.class);\r\n\r\n    @Test\r\n    public void test() {\r\n        System.out.println(\"======start======\");\r\n        System.out.println(\"======start======\");\r\n        for (int i = 0; i \u003C 10; i++) {\r\n            log.trace(\"这是 trace 日志。。。\");\r\n            log.debug(\"这是 debug 日志。。。\");\r\n            log.info(\"这是 info 日志。。。\");\r\n            log.warn(\"这是 warn 日志。。。\");\r\n            log.error(\"这是 error 日志。。。\");\r\n        }\r\n        System.out.println(\"======end======\");\r\n        System.out.println(\"======end======\");\r\n    }\r\n}\r\n```\r\n\r\n&emsp;&emsp;异步日志配置在控制台输出，会发现执行完了`System.out.println()`的代码，才会输出log日志。\r\n\r\n```java\r\n======start======\r\n======start======\r\n======end======\r\n======end======\r\n[00:07:13.172] [main] [DEBUG] top.mengh.Slf4jTest: --- 这是 debug 日志。。。\r\n[00:07:13.172] [main] [INFO ] top.mengh.Slf4jTest: --- 这是 info 日志。。。\r\n[00:07:13.172] [main] [WARN ] top.mengh.Slf4jTest: --- 这是 warn 日志。。。\r\n[00:07:13.172] [main] [ERROR] top.mengh.Slf4jTest: --- 这是 error 日志。。。\r\n```\r\n\r\n\r\n\r\n# 6\tSpringBoot默认日志框架\r\n\r\n## 6.1\tSpringBoot 默认日志框架\r\n\r\n**SpringBoot底层默认使用的日志依赖**：\r\n\r\n```xml\r\n\u003Cdependency>\r\n  \u003CgroupId>org.springframework.boot\u003C\u002FgroupId>\r\n  \u003CartifactId>spring-boot-starter-logging\u003C\u002FartifactId>\r\n  \u003Cscope>compile\u003C\u002Fscope>\r\n\u003C\u002Fdependency>\r\n```\r\n\r\n**底层依赖关系**：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjava日志框架\u002Fspringboot_slf4j.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n**总结**：\r\n\r\n&emsp;&emsp;（1）**SpringBoot** 底层默认使用 **Slf4j** + **Logback** 方式进行日志记录；\r\n\r\n&emsp;&emsp;（2）**SpringBoot**把其他的默认日志都替换成了**slf4j**；\r\n\r\n&emsp;&emsp;SpringBoot使用日志最核心的总结：**SpringBoot能自动适配所有的日志，而且底层使用slf4j+logback的方式记录日志，引入其他框架的时候，只需要把这个框架默认使用的日志框架排除掉**。\r\n\r\n\r\n\r\nSpringBoot使用日志的时候，只需要在类中获取Logger日志对象即可。\r\n\r\n```java\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\npublic class Demo{\r\n    private final Logger log = LoggerFactory.getLogger(Demo.class);\r\n\r\n    public void test(){\r\n        log.trace(\"这是 trace 日志。。。\");\r\n        log.debug(\"这是 debug 日志。。。\");\r\n        log.info(\"这是 info 日志。。。\");\r\n        log.warn(\"这是 warn 日志。。。\");\r\n        log.error(\"这是 error 日志。。。\");\r\n    }\r\n}\r\n```\r\n\r\n&emsp;&emsp;如果不想每次都使用LoggerFactory.getLogger()获取日志对象，则在 pom.xml文件中添加lombok依赖，再在使用的类上添加注解 **@Slf4j** 。添加lombok依赖，idea需要先安装lombok插件。\r\n\r\n```xml\r\n\u003Cdependency>\r\n\t\u003CgroupId>org.projectlombok\u003C\u002FgroupId>\r\n\t\u003CartifactId>lombok\u003C\u002FartifactId>\r\n\u003C\u002Fdependency>\r\n```\r\n\r\n&emsp;&emsp;在类的上方贴 **@Slf4j** 注解，即可使用，如：\r\n\r\n```java\r\n@Slf4j\r\npublic class Demo{\r\n    public void test(){\r\n        log.info(\"这是 info 日志。。。\");\r\n    }\r\n}\r\n```\r\n\r\n&emsp;&emsp;日志等级优先级： **trace \u003C debug \u003C info \u003C warn \u003C error**\r\n\r\n&emsp;&emsp;springBoot默认使用的级别是 info级别，所以只会输出含 info 以上级别的日志。\r\n\r\n## 6.2\t指定配置文件\r\n\r\n&emsp;&emsp;给类路径下放上每个日志框架自己的配置文件，那么springBoot就不会使用默认配置，在工程resource目录下放置。\r\n\r\n| 日志实现 | 配置文件                        |\r\n| -------- | ------------------------------- |\r\n| logback  | logback-spring.xml，logback.xml |\r\n| jul      | logging.properties              |\r\n\r\n&emsp;&emsp;也可以使用全局配置文件，如`application.yml` 配置logback日志输出，`application.yml`全局配置不能和日志实现配置文件同时存在(如：logback.xml)，否则会报错。\r\n\r\n```yml\r\nspring:\r\n  profiles:\r\n    active: dev\r\n# slf4j日志配置\r\nlogging:\r\n  level:\r\n    # 日志等级优先级 trace \u003C debug \u003C info \u003C warn \u003C error\r\n    # 使用trace级别, 分包配置级别，不同的包下可以使用不同的级别\r\n    top.mengh: trace\r\n  file:\r\n    # name是在当前项目下生成名为 test.log 日志文件\r\n    #name: test.log\r\n    # path是在指定目录下生成日志文件，默认名为spring.log，如下面的路径为项目根目录\u002Flogs\u002Fspring.log\r\n    #如果同时指定 name 和 path 时，只有 name 生效。\r\n    path: .\u002Flogs\r\n    #path和name可以配合使用，方式如下:\r\n#    name: ${logging.file.path}\u002Ftest.log\r\n    \r\n  pattern:\r\n    # 指定控制台日志输出格式\r\n    console: \"[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n\"\r\n    # 指定文件中日志格式\r\n    file: \"[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n\"\r\n```\r\n\r\n&emsp;&emsp;可以通过切换环境使用不同的日志格式化输出，如`logback.xml`：\r\n\r\n```xml\r\n\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n\u003Cconfiguration>\r\n    \u003Cproperty name=\"pattern\" value=\"[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n\"\u002F>\r\n    \u003C!-- 定义日志文件保存路径属性 -->\r\n    \u003Cproperty name=\"log_dir\" value=\".\u002Flogs\"\u002F>\r\n\r\n    \u003C!-- 控制台输出 appender 对象-->\r\n    \u003Cappender name=\"console\" class=\"ch.qos.logback.core.ConsoleAppender\">\r\n        \u003Cencoder class=\"ch.qos.logback.classic.encoder.PatternLayoutEncoder\">\r\n            \u003C!-- 开发环境的输出格式 -->\r\n            \u003CspringProfile name=\"dev\">\r\n                \u003Cpattern>${pattern}\u003C\u002Fpattern>\r\n            \u003C\u002FspringProfile>\r\n            \u003C!-- 生产环境的输出格式 -->\r\n            \u003CspringProfile name=\"pro\">\r\n                \u003Cpattern>[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] ===== %m%n\u003C\u002Fpattern>\r\n            \u003C\u002FspringProfile>\r\n        \u003C\u002Fencoder>\r\n    \u003C\u002Fappender>\r\n\r\n    \u003C!-- 日志文件输出的 appender -->\r\n    \u003Cappender name=\"file\" class=\"ch.qos.logback.core.FileAppender\">\r\n        \u003C!-- 日志文件保持路径 -->\r\n        \u003Cfile>${log_dir}\u002Flogback.log\u003C\u002Ffile>\r\n        \u003C!-- 日志文件消息格式配置 -->\r\n        \u003Cencoder class=\"ch.qos.logback.classic.encoder.PatternLayoutEncoder\">\r\n            \u003Cpattern>${pattern}\u003C\u002Fpattern>\r\n        \u003C\u002Fencoder>\r\n    \u003C\u002Fappender>\r\n\r\n    \u003C!-- 自定义 logger对象 -->\r\n    \u003Clogger name=\"top.mengh\"  level=\"trace\" additivity=\"false\">\r\n        \u003Cappender-ref ref=\"console\"\u002F>\r\n        \u003Cappender-ref ref=\"file\"\u002F>\r\n    \u003C\u002Flogger>\r\n\u003C\u002Fconfiguration>\r\n```\r\n\r\n\r\n\r\n## 6.3\t日志实现切换 log4j2\r\n\r\n添加依赖：先排除springboot默认的logback依赖，在添加log4j2的依赖。\r\n\r\n```xml\r\n\t\t\u003Cdependency>\r\n            \u003CgroupId>org.springframework.boot\u003C\u002FgroupId>\r\n            \u003CartifactId>spring-boot-starter-web\u003C\u002FartifactId>\r\n            \u003Cversion>2.4.3\u003C\u002Fversion>\r\n            \u003C!-- 排除springboot默认的logback依赖 -->\r\n            \u003Cexclusions>\r\n                \u003Cexclusion>\r\n                    \u003CartifactId>spring-boot-starter-logging\u003C\u002FartifactId>\r\n                    \u003CgroupId>org.springframework.boot\u003C\u002FgroupId>\r\n                \u003C\u002Fexclusion>\r\n            \u003C\u002Fexclusions>\r\n        \u003C\u002Fdependency>\r\n\r\n        \u003C!-- 添加log4j2依赖，该依赖底层日志门面还是使用slf4j -->\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.springframework.boot\u003C\u002FgroupId>\r\n            \u003CartifactId>spring-boot-starter-log4j2\u003C\u002FartifactId>\r\n        \u003C\u002Fdependency>\r\n```\r\n\r\n&emsp;&emsp;这时候工程使用的配置文件得是log4j2的配置文件。\r\n\r\n&emsp;&emsp;演示项目地址：https:\u002F\u002Fgitee.com\u002Fmeng_hui\u002Fslf4j\n",{"_path":268,"slug":269,"title":269,"description":270,"excerpt":270,"date":229,"tags":271,"type":15,"cover":272,"content":273},"\u002Fknowledge\u002Fjdk安装","jdk安装","Linux环境下安装java开发工具包 一 jdk下载 ​ jdk版本需要和系统镜像对应得上。如：系统版本如下： ​ 则下载对应得jdk版本如下：",[124,74],"\u002Fknowledge-assets\u002Fjdk安装\u002F系统镜像类型.png","### Linux环境下安装java开发工具包\r\n\r\n### 一\tjdk下载\r\n\r\n​\tjdk版本需要和系统镜像对应得上。如：系统版本如下：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjdk安装\u002F系统镜像类型.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n​\t则下载对应得jdk版本如下：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjdk安装\u002Fjdk下载.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n​\t我在这里使用的是华为云服务器，系统是 CentOS 7.6 64bit with ARM版本，下载的jdk为：jdk-8u301-linux-aarch64.tar.gz\r\n\r\n### 二\tJDK安装\r\n\r\n#### 2.1\t删除系统自带的jdk\r\n\r\n​\t查询已安装的jdk：\r\n\r\n```java\r\nyum list installed | grep jdk\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjdk安装\u002F删除自带jdk-1.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n​\t删除自带的jdk：\r\n\r\n```java\r\nyum remove java-1.8.0-openjdk.aarch64 java-1.8.0-openjdk-devel.aarch64 java-1.8.0-openjdk-headless.aarch64\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjdk安装\u002F删除自带jdk-2.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n​\t删除后，再次查询是否还存在：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjdk安装\u002F删除自带jdk-3.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n#### 2.2\t创建目录\r\n\r\n​\t创建一个专门用于存放我们安装软件的目录。\r\n\r\n```cmake\r\nmkdir \u002Fusr\u002Flocal\u002Fsoftware\r\n```\r\n\r\n#### 2.3\t上传本地jdk到远程Linux主机中\r\n\r\n​\t远程连接工具使用的是SecureCRTPortable.exe软件。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjdk安装\u002F复制jdk到linux系统.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n#### 2.4\t解压 jdk-8u301-linux-aarch64.tar.gz 文件\r\n\r\n​\t解压jdk压缩包到当前目录下：\r\n\r\n```java\r\ntar -zxvf jdk-8u301-linux-aarch64.tar.gz\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjdk安装\u002F解压jdk-1.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n#### 2.5\t移动解压后的jdk\r\n\r\n​\t移动解压后的jdk到 \u002Fusr\u002Flocal\u002F目录下，并重命名为jdk1.8。\r\n\r\n```java\r\nmv jdk1.8.0_301 ..\u002Fjdk1.8\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjdk安装\u002F移动jdk.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n#### 2.6\t配置环境变量 JAVA_HOME，PATH\r\n\r\n​\t编辑profile文件，配置环境变量：\r\n\r\n```java\r\nvi \u002Fetc\u002Fprofile\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjdk安装\u002F编辑环境变量.png\" style=\"zoom:100%;\" \u002F>\r\n\r\n​\t在文件最后添加内容如下：\r\n\r\n```java\r\nJAVA_HOME=\u002Fusr\u002Flocal\u002Fjdk1.8\r\nPATH=$JAVA_HOME\u002Fbin:$PATH\r\n\r\nexport JAVA_HOME PATH\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjdk安装\u002F配置环境变量.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n#### 2.7\t重写加载环境变量配置文件\r\n\r\n```java\r\nsource \u002Fetc\u002Fprofile\r\n```\r\n\r\n#### 2.8\t最后查看是否安装成功\r\n\r\n​\t查出版本号，表名安装成功。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fjdk安装\u002F加载环境配置文件.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n",{"_path":275,"slug":276,"title":277,"description":278,"excerpt":278,"date":229,"tags":279,"type":15,"cover":280,"content":281},"\u002Fknowledge\u002Fk8s入门操作教程","k8s入门操作教程","Kubernetes 入门操作教程","Kubernetes 入门操作教程 1 概述 1.1 简介 ​ Kubernetes 是一个开源的容器编排引擎，用来对容器化应用进行自动化部署、扩缩和管理。 官网：https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fhome\u002F Kubernetes 为你提供： - **服务发现和负载均衡** Kubern",[211],"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002FContainer_Evolution.svg","# Kubernetes 入门操作教程\r\n\r\n# 1\t概述\r\n\r\n## 1.1\t简介\r\n\r\n​\tKubernetes 是一个开源的容器编排引擎，用来对容器化应用进行自动化部署、扩缩和管理。\r\n\r\n[官网](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fhome\u002F)：https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fhome\u002F\r\n\r\nKubernetes 为你提供：\r\n\r\n- **服务发现和负载均衡**\r\n\r\n  Kubernetes 可以使用 DNS 名称或自己的 IP 地址来暴露容器。 如果进入容器的流量很大， Kubernetes 可以负载均衡并分配网络流量，从而使部署稳定。\r\n\r\n- **存储编排**\r\n\r\n  Kubernetes 允许你自动挂载你选择的存储系统，例如本地存储、公共云提供商等。\r\n\r\n- **自动部署和回滚**\r\n\r\n  你可以使用 Kubernetes 描述已部署容器的所需状态， 它可以以受控的速率将实际状态更改为期望状态。 例如，你可以自动化 Kubernetes 来为你的部署创建新容器， 删除现有容器并将它们的所有资源用于新容器。\r\n\r\n- **自动完成装箱计算**\r\n\r\n  你为 Kubernetes 提供许多节点组成的集群，在这个集群上运行容器化的任务。 你告诉 Kubernetes 每个容器需要多少 CPU 和内存 (RAM)。 Kubernetes 可以将这些容器按实际情况调度到你的节点上，以最佳方式利用你的资源。\r\n\r\n- **自我修复**\r\n\r\n  Kubernetes 将重新启动失败的容器、替换容器、杀死不响应用户定义的运行状况检查的容器， 并且在准备好服务之前不将其通告给客户端。\r\n\r\n- **密钥与配置管理**\r\n\r\n  Kubernetes 允许你存储和管理敏感信息，例如密码、OAuth 令牌和 SSH 密钥。 你可以在不重建容器镜像的情况下部署和更新密钥和应用程序配置，也无需在堆栈配置中暴露密钥。\r\n\r\n- **批处理执行** 除了服务外，Kubernetes 还可以管理你的批处理和 CI（持续集成）工作负载，如有需要，可以替换失败的容器。\r\n- **水平扩缩** 使用简单的命令、用户界面或根据 CPU 使用率自动对你的应用进行扩缩。\r\n- **IPv4\u002FIPv6 双栈** 为 Pod（容器组）和 Service（服务）分配 IPv4 和 IPv6 地址。\r\n- **为可扩展性设计** 在不改变上游源代码的情况下为你的 Kubernetes 集群添加功能。\r\n\r\n\r\n\r\n## 1.2\t历史背景\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002FContainer_Evolution.svg\" style=\"zoom:80%;\" \u002F>\r\n\r\n## 1.3\tKubernetes 组件\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fcomponents-of-kubernetes.svg\" style=\"zoom:80%;\" \u002F>\r\n\r\n**核心组件**：\r\n\r\n​\tKubernetes 集群由控制平面和一个或多个工作节点组成。以下是主要组件的简要概述：\r\n\r\n（1）**控制平面组件（Control Plane Components）**\r\n\r\n管理集群的整体状态：\r\n\r\n- [kube-apiserver](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Farchitecture\u002F#kube-apiserver) ：公开 Kubernetes HTTP API 的核心组件服务器，所有k8s操作命令都是通过api来发送；\r\n\r\n- [etcd](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Farchitecture\u002F#etcd)：数据档案，存储所有 API 服务器的数据，具备一致性和高可用性的键值存储；\r\n\r\n- [kube-scheduler](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Farchitecture\u002F#kube-scheduler)：调度器，查找尚未绑定到节点的 Pod，并将每个 Pod 分配给合适的节点；\r\n\r\n- [kube-controller-manager](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Farchitecture\u002F#kube-controller-manager)：控制器管理；\r\n\r\n- [cloud-controller-manager](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Farchitecture\u002F#cloud-controller-manager) (optional)：与底层云驱动集成。\r\n\r\n  \r\n\r\n（2）**Node 组件**\r\n\r\n在集群节点上运行，维护运行的 Pod， 并提供 Kubernetes 运行时环境：\r\n\r\n- [kubelet](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Farchitecture\u002F#kubelet)：确保 Pod 及其容器正常运行。\r\n\r\n- [kube-proxy](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Farchitecture\u002F#kube-proxy)：维护节点上的网络规则以实现 Service 的功能。\r\n\r\n- [容器运行时（Container runtime）](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Farchitecture\u002F#container-runtime)：负责运行容器的软件，阅读[容器运行时](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fsetup\u002Fproduction-environment\u002Fcontainer-runtimes\u002F)以了解更多信息。\r\n\r\n\r\n\r\n# 2\t集群环境搭建\r\n\r\n​\t搭建你自己的 Kubernetes 生产集群有许多方法和工具。例如：\r\n\r\n- [kubeadm](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fsetup\u002Fproduction-environment\u002Ftools\u002Fkubeadm\u002F)\r\n\r\n- [kops](https:\u002F\u002Fkops.sigs.k8s.io\u002F)：自动化集群制备工具。 有关教程、最佳实践、配置选项和社区联系信息，请查阅 [`kOps` 网站](https:\u002F\u002Fkops.sigs.k8s.io\u002F)。\r\n\r\n- [kubespray](https:\u002F\u002Fkubespray.io\u002F)： 提供了 [Ansible](https:\u002F\u002Fdocs.ansible.com\u002F) Playbook、 [清单（inventory）](https:\u002F\u002Fgithub.com\u002Fkubernetes-sigs\u002Fkubespray\u002Fblob\u002Fmaster\u002Fdocs\u002Fansible.md#inventory)、 制备工具和通用 OS\u002FKubernetes 集群配置管理任务领域的知识。 你可以通过 Slack 频道 [#kubespray](https:\u002F\u002Fkubernetes.slack.com\u002Fmessages\u002Fkubespray\u002F) 联系此社区。\r\n\r\n\r\n\r\n**官方文档**： https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fsetup\u002Fproduction-environment\u002Ftools\u002Fkubeadm\u002Finstall-kubeadm\u002F\r\n\r\n[参考尚硅谷学习笔记](https:\u002F\u002Fwww.yuque.com\u002Fleifengyang\u002Foncloud)：https:\u002F\u002Fwww.yuque.com\u002Fleifengyang\u002Foncloud\r\n\r\n[参考图灵学习笔记](https:\u002F\u002Fnote.youdao.com\u002Fynoteshare\u002Findex.html?id=b2d5991b16e43cef9ac5071fbc516026&type=note&_time=1724600810755)：https:\u002F\u002Fnote.youdao.com\u002Fynoteshare\u002Findex.html?id=b2d5991b16e43cef9ac5071fbc516026&type=note&_time=1724600810755\r\n\r\n\r\n\r\n**集群环境搭建参考**：\r\n\r\nk8s v1.20.1  https:\u002F\u002Fnote.youdao.com\u002Fs\u002FMignGqZj\r\n\r\nk8s v1.24.3 https:\u002F\u002Fdocs.qq.com\u002Fdoc\u002FDUWRRQmZpeE1Sd1dC\r\n\r\nk8s v1.27.1 https:\u002F\u002Fnote.youdao.com\u002Fs\u002FDxh3Qaaa\r\n\r\nsealos快速安装kubernetes集群: https:\u002F\u002Fnote.youdao.com\u002Fs\u002FM2z4OzsL\r\n\r\n\r\n\r\n## 2.1\t容器运行时\r\n\r\n​\tKubernetes运行需要容器虚拟化环境，比如 docker 环境。\r\n\r\n**说明：** 自Kubernetes 1.24 版起，Dockershim 已从 Kubernetes 项目中移除，即不再支持原生docker环境，如需要则自己适配。阅读 [Dockershim 移除的常见问题](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdockershim)了解更多详情。\r\n\r\n[官网](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fsetup\u002Fproduction-environment\u002Fcontainer-runtimes\u002F)：https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fsetup\u002Fproduction-environment\u002Fcontainer-runtimes\u002F\r\n\r\n\r\n\r\n## 2.2\tk8s v1.20.1 集群搭建\r\n\r\n​\t当前使用kubeadm方式大家k8s集群。\r\n\r\n**准备机器**\r\n\r\n​\t搭建K8S集群，准备三台2核4G的虚拟机(内存至少2G以上)，操作系统选择用centos 7以上版本。\r\n\r\n| 主机         | 说明       |\r\n| ------------ | ---------- |\r\n| 192.168.2.10 | k8s-master |\r\n| 192.168.2.30 | k8s-node1  |\r\n| 192.168.2.40 | k8s-node2  |\r\n\r\n### 2.2.1\t安装docker\r\n\r\n（1）配置yum源\r\n\r\n```shell\r\nsudo yum install -y yum-utils\r\nsudo yum-config-manager \\\r\n--add-repo \\\r\nhttp:\u002F\u002Fmirrors.aliyun.com\u002Fdocker-ce\u002Flinux\u002Fcentos\u002Fdocker-ce.repo\r\n```\r\n\r\n> 注意：\r\n>\r\n> ```shell\r\n> # 使用 yum install -y xxx 或者 yum makecache时，如果报错 Could not resolve host: mirrorlist.centos.org\r\n> # 1.下载CentOS 7的对应的repo文件\r\n> # 直接在浏览器通过http:\u002F\u002Fmirrors.aliyun.com\u002Frepo\u002FCentos-7.repo 下载Centos-7.repo，然后将其传到\u002Fetc\u002Fyum.repos.d目录下，重命名为CentOS-Base.repo\r\n> mv Centos-7.repo \u002Fetc\u002Fyum.repos.d\r\n> cd \u002Fetc\u002Fyum.repos.d\r\n> mv Centos-7.repo CentOS-Base.repo\r\n> \r\n> # 2.更新镜像源\r\n> yum clean all\r\n> yum makecache\r\n> yum -y update\r\n> ```\r\n\r\n（2）安装docker\r\n\r\n```shell\r\nyum install -y docker-ce-20.10.7 docker-ce-cli-20.10.7  containerd.io-1.4.6\r\n```\r\n\r\n（3）启动docker\r\n\r\n```shell\r\n# 启动Docker服务\r\nsystemctl start docker\r\n# 设置Docker服务开机自启\r\nsystemctl enable docker\r\n\r\n# 或一步到位，设置开启自启，并启动docker\r\nsystemctl enable docker --now\r\n```\r\n\r\n（3）配置加速及cgroup\r\n\r\nkubelet的cgroup和docker的不一致，“kubelet cgroup驱动为systemd，而docker的为“cgroupfs”，因此**修改docker的cgroup为systemd**，否则kubelet无法启动。\r\n\r\n```shell\r\n# 创建目录\r\nmkdir -p \u002Fetc\u002Fdocker\r\n# 配置加速器\r\ntee \u002Fetc\u002Fdocker\u002Fdaemon.json \u003C\u003C-'EOF'\r\n{\r\n  \"registry-mirrors\": [\"https:\u002F\u002Fjsj9yxoq.mirror.aliyuncs.com\"],\r\n  \"exec-opts\": [\"native.cgroupdriver=systemd\"],\r\n  \"log-driver\": \"json-file\",\r\n  \"log-opts\": {\r\n    \"max-size\": \"100m\"\r\n  },\r\n  \"storage-driver\": \"overlay2\"\r\n}\r\nEOF\r\n\r\n# 重启\r\nsystemctl daemon-reload\r\nsystemctl restart docker\r\n```\r\n\r\n\r\n\r\n如需要，可配置多个镜像加速：\r\n\r\n```json\r\n{\r\n    \"registry-mirrors\": [\r\n    \"https:\u002F\u002Fjsj9yxoq.mirror.aliyuncs.com\",\r\n    \"https:\u002F\u002Fdocker.registry.cyou\",\r\n    \"https:\u002F\u002Fdocker-cf.registry.cyou\",\r\n    \"https:\u002F\u002Fdockercf.jsdelivr.fyi\",\r\n    \"https:\u002F\u002Fdocker.jsdelivr.fyi\",\r\n    \"https:\u002F\u002Fdockertest.jsdelivr.fyi\",\r\n    \"https:\u002F\u002Fmirror.aliyuncs.com\",\r\n    \"https:\u002F\u002Fdockerproxy.com\",\r\n    \"https:\u002F\u002Fmirror.baidubce.com\",\r\n    \"https:\u002F\u002Fdocker.m.daocloud.io\",\r\n    \"https:\u002F\u002Fdocker.nju.edu.cn\",\r\n    \"https:\u002F\u002Fdocker.mirrors.sjtug.sjtu.edu.cn\",\r\n    \"https:\u002F\u002Fdocker.mirrors.ustc.edu.cn\",\r\n    \"https:\u002F\u002Fmirror.iscas.ac.cn\",\r\n    \"https:\u002F\u002Fdocker.rainbond.cc\"],\r\n  \"exec-opts\": [\"native.cgroupdriver=systemd\"],\r\n  \"log-driver\": \"json-file\",\r\n  \"log-opts\": {\r\n    \"max-size\": \"100m\"\r\n  },\r\n  \"storage-driver\": \"overlay2\"\r\n}\r\n```\r\n\r\n\r\n\r\n### 2.2.2\t安装k8s\r\n\r\n#### 2.2.2.1\t基础环境\r\n\r\n在所有集群主机上执行以下操作：\r\n\r\n（1）各个机器设置自己的主机名\r\n\r\n```shell\r\nhostnamectl set-hostname k8s-master\r\nhostnamectl set-hostname k8s-node1\r\nhostnamectl set-hostname k8s-node2\r\n```\r\n\r\n（2）关闭防火墙\r\n\r\n```shell\r\n# 停止firewalld服务\r\nsystemctl stop firewalld\r\n# 禁用firewalld服务，使其不会开机自启\r\nsystemctl disable firewalld\r\n```\r\n\r\n（3）将 SELinux 设置为 permissive 模式（相当于将其禁用）\r\n\r\n```shell\r\nsetenforce 0\r\nsed -i 's\u002F^SELINUX=enforcing$\u002FSELINUX=permissive\u002F' \u002Fetc\u002Fselinux\u002Fconfig\r\n```\r\n\r\n（4）关闭交互区\r\n\r\n```shell\r\n# 关闭swap\r\nswapoff -a  \r\nsed -ri 's\u002F.*swap.*\u002F#&\u002F' \u002Fetc\u002Ffstab\r\n\r\nsystemctl reboot  #重启生效\r\n```\r\n\r\n（5）添加hosts\r\n\r\n```shell\r\n#添加hosts，执行如下命令，ip需要修改成自己机器的ip\r\ncat >> \u002Fetc\u002Fhosts \u003C\u003C EOF\r\n192.168.2.20 k8s-master\r\n192.168.2.30 k8s-node1\r\n192.168.2.40 k8s-node2\r\nEOF\r\n```\r\n\r\n（6）允许 iptables 检查桥接流量\r\n\r\n```shell\r\ncat \u003C\u003CEOF | tee \u002Fetc\u002Fmodules-load.d\u002Fk8s.conf\r\nbr_netfilter\r\nEOF\r\n\r\ncat \u003C\u003CEOF | tee \u002Fetc\u002Fsysctl.d\u002Fk8s.conf\r\nnet.bridge.bridge-nf-call-ip6tables = 1\r\nnet.bridge.bridge-nf-call-iptables = 1\r\nEOF\r\n\r\nsysctl --system\r\n```\r\n\r\n（7）设置时间同步\r\n\r\n```shell\r\n# 安装ntpdate\r\nyum install ntpdate -y\r\n# 同步时间\r\nntpdate time.windows.com\r\n```\r\n\r\n#### 2.2.2.2\t安装kubelet、kubeadm、kubectl\r\n\r\n在所有集群主机上执行以下操作：\r\n\r\n```shell\r\n# 配置k8s的yum源地址\r\ncat \u003C\u003CEOF | tee \u002Fetc\u002Fyum.repos.d\u002Fkubernetes.repo\r\n[kubernetes]\r\nname=Kubernetes\r\nbaseurl=http:\u002F\u002Fmirrors.aliyun.com\u002Fkubernetes\u002Fyum\u002Frepos\u002Fkubernetes-el7-x86_64\r\nenabled=1\r\ngpgcheck=0\r\nrepo_gpgcheck=0\r\ngpgkey=http:\u002F\u002Fmirrors.aliyun.com\u002Fkubernetes\u002Fyum\u002Fdoc\u002Fyum-key.gpg\r\n   http:\u002F\u002Fmirrors.aliyun.com\u002Fkubernetes\u002Fyum\u002Fdoc\u002Frpm-package-key.gpg\r\nexclude=kubelet kubeadm kubectl\r\nEOF\r\n\r\n# 安装kubelet、kubeadm、kubectl\r\nyum install -y kubelet-1.20.9 kubeadm-1.20.9 kubectl-1.20.9 --disableexcludes=kubernetes\r\n\r\n# --disableexcludes=kubernetes  禁掉除了这个之外的别的仓库 \r\n\r\n# 启动kubelet，并设置开机自启\r\nsystemctl enable --now kubelet\r\n```\r\n\r\n\r\n\r\n#### 2.2.2.3\t使用kubeadm引导集群\r\n\r\n在所有集群主机上执行以下操作：\r\n\r\n```shell\r\n# 提前下载各个机器需要的镜像，后续安装pod时不用再下载\r\ntee .\u002Fimages.sh \u003C\u003C-'EOF'\r\n#!\u002Fbin\u002Fbash\r\nimages=(\r\nkube-apiserver:v1.20.9\r\nkube-proxy:v1.20.9\r\nkube-controller-manager:v1.20.9\r\nkube-scheduler:v1.20.9\r\ncoredns:1.7.0\r\netcd:3.4.13-0\r\npause:3.2\r\n)\r\nfor imageName in ${images[@]} ; do\r\ndocker pull registry.cn-hangzhou.aliyuncs.com\u002Flfy_k8s_images\u002F$imageName\r\ndone\r\nEOF\r\n\r\n# 执行镜像下载脚本\r\nchmod +x .\u002Fimages.sh && .\u002Fimages.sh\r\n```\r\n\r\n\r\n\r\n#### 2.2.2.4\t初始化主节点\r\n\r\n（1）在master节点执行\r\n\r\n```shell\r\n#主节点初始化\r\nkubeadm init \\\r\n--apiserver-advertise-address=192.168.2.20 \\\r\n--control-plane-endpoint=k8s-master \\\r\n--image-repository registry.cn-hangzhou.aliyuncs.com\u002Flfy_k8s_images \\\r\n--kubernetes-version v1.20.9 \\\r\n--service-cidr=10.96.0.0\u002F16 \\\r\n--pod-network-cidr=10.244.0.0\u002F16\r\n\r\n# 这3个ip地址不能配在同一网段，所有网络范围不重叠\r\n# --apiserver-advertise-address: 指定的当前master节点ip\r\n# --service-cidr：\r\n# --pod-network-cidr：配置pod ip地址\r\n```\r\n\r\n初始化成功后，会在控制台上输出如下内容：\r\n\r\n```shell\r\n################################################################\r\nYour Kubernetes control-plane has initialized successfully!\r\n\r\nTo start using your cluster, you need to run the following as a regular user:\r\n\r\n  mkdir -p $HOME\u002F.kube\r\n  sudo cp -i \u002Fetc\u002Fkubernetes\u002Fadmin.conf $HOME\u002F.kube\u002Fconfig\r\n  sudo chown $(id -u):$(id -g) $HOME\u002F.kube\u002Fconfig\r\n\r\nAlternatively, if you are the root user, you can run:\r\n\r\n  export KUBECONFIG=\u002Fetc\u002Fkubernetes\u002Fadmin.conf\r\n\r\nYou should now deploy a pod network to the cluster.\r\nRun \"kubectl apply -f [podnetwork].yaml\" with one of the options listed at:\r\n  https:\u002F\u002Fkubernetes.io\u002Fdocs\u002Fconcepts\u002Fcluster-administration\u002Faddons\u002F\r\n\r\nYou can now join any number of control-plane nodes by copying certificate authorities\r\nand service account keys on each node and then running the following as root:\r\n\r\n  kubeadm join k8s-master:6443 --token tgy6n0.xmbgqwek8kjhwx6b \\\r\n    --discovery-token-ca-cert-hash sha256:b8d1bd430967528118d74af2a88d20461f39015e3b0df8f2fde620c31d3c9bc3 \\\r\n    --control-plane\r\n\r\nThen you can join any number of worker nodes by running the following on each as root:\r\n\r\nkubeadm join k8s-master:6443 --token tgy6n0.xmbgqwek8kjhwx6b \\\r\n    --discovery-token-ca-cert-hash sha256:b8d1bd430967528118d74af2a88d20461f39015e3b0df8f2fde620c31d3c9bc3\r\n\r\n################################################################\r\n```\r\n\r\n\r\n\r\n（2）配置环境变量\r\n\r\n```shell\r\n# 检查有没有环境变量\r\necho $KUBECONFIG\r\n# 如果当前用户是root，则配置\r\nexport KUBECONFIG=\u002Fetc\u002Fkubernetes\u002Fadmin.conf  # 重启后会失效，得重新配置\r\n# 如果你想让这个变量永久生效，可以将上述命令添加到 ~\u002F.bash_profile 文件的末尾，然后执行source ~\u002F.bash_profile 来应用更改\r\n\r\n# 其他登录用户，不是root用户，则执行执行，控制台输出的内容：\r\nmkdir -p $HOME\u002F.kube\r\nsudo cp -i \u002Fetc\u002Fkubernetes\u002Fadmin.conf $HOME\u002F.kube\u002Fconfig\r\nsudo chown $(id -u):$(id -g) $HOME\u002F.kube\u002Fconfig\r\n```\r\n\r\n\r\n\r\n（3）安装网络插件\r\n\r\n```shell\r\n# master节点 下载网络插件配置\r\ncurl https:\u002F\u002Fdocs.projectcalico.org\u002Fv3.20\u002Fmanifests\u002Fcalico.yaml -O\r\n\r\n# 提前安装所需镜像，可能需要科学才能下拉（所有集群节点都需要）\r\ndocker pull docker.io\u002Fcalico\u002Fcni:v3.20.6\r\ndocker pull docker.io\u002Fcalico\u002Fpod2daemon-flexvol:v3.20.6\r\ndocker pull docker.io\u002Fcalico\u002Fnode:v3.20.6\r\ndocker pull docker.io\u002Fcalico\u002Fkube-controllers:v3.20.6\r\n\r\n# master节点 安装网络\r\nkubectl apply -f calico.yaml\r\n\r\n# 如果虚拟机配置多网卡，出现下面的错误：calico\u002Fnode is not ready: BIRD is not ready: BGP not established with xxx\r\n# 修改calico.yaml的内容,指定网卡，添加下面两行\r\n# 配置网卡，在这calico.yaml文件下，添加网卡IP_AUTODETECTION_METHOD信息\r\n            # Auto-detect the BGP IP address.\r\n            - name: IP\r\n              value: \"autodetect\"\r\n            ##########################\r\n            # 添加网卡\r\n            - name: IP_AUTODETECTION_METHOD\r\n              value: \"interface=ens33\"\r\n            ##########################\r\n            # Enable IPIP\r\n\r\n# 查看运行信息\r\nkubectl get pods -A\r\n# 查看安装过程信息\r\nkubectl describe pod pod名称 -n kube-system\r\n\r\n# 如果创建失败，删除pod，再创建\r\nkubectl delete -f calico.yaml\r\n```\r\n\r\n\r\n\r\n（4）查看node节点状态\r\n\r\n```shell\r\nkubectl get nodes\r\n```\r\n\r\n\r\n\r\n#### 2.2.2.5\t加入node节点\r\n\r\n在集群node节点上执行以下操作：\r\n\r\n```shell\r\n# 在node 节点执行\r\nkubeadm join k8s-master:6443 --token grzsle.0up1mbojuva9zv37 \\\r\n    --discovery-token-ca-cert-hash sha256:a32bbb2e9f7534e1fd9fe8818db52551da1f43fddf21357413e378d3ced6313f\r\n\r\n# 如果token过期，可以通过下面的命令重新生成令牌\r\nkubeadm token create --print-join-command\r\n\r\n# node节点执行kubectl命令kubectl get nodes出现下面的错误：\r\n# The connection to the server localhost:8080 was refused - did you specify the right host or port?\r\n# 解决方案： 在node节点配置KUBECONFIG环境变量即可\r\necho \"export KUBECONFIG=\u002Fetc\u002Fkubernetes\u002Fkubelet.conf\" >> \u002Fetc\u002Fprofile\r\nsource \u002Fetc\u002Fprofile\r\n```\r\n\r\n\r\n\r\n#### 2.2.2.6\t查看kubelet信息\r\n\r\n```shell\r\n# 启动 kubelet\r\nsystemctl start kubelet\r\n# 重启 kubelet\r\nsystemctl restart kubelet\r\n# 停止 kubelet\r\nsystemctl stop kubelet\r\n# 查看 kubelet状态\r\nsystemctl status kubelet\r\n\r\n# 查看 kubelet日志\r\njournalctl -f -u kubelet\r\n\r\n```\r\n\r\n\r\n\r\n# 3\t配置可视化界面\r\n\r\n\r\n\r\n\r\n\r\n# 4\tK8S 快速实战\r\n\r\n## 4.1\tNamespace\r\n\r\n​\tK8s 中，[**命名空间（Namespace）**](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Foverview\u002Fworking-with-objects\u002Fnamespaces\u002F) 提供一种机制，将同一集群中的资源划分为相互隔离的组。同一命名空间内的资源名称要唯一，命名空间是用来隔离资源的，并不隔离网络。\r\n\r\nKubernetes 启动时会创建四个初始命名空间：\r\n\r\n- **default**：Kubernetes 包含这个命名空间，以便于你无需创建新的命名空间即可开始使用新集群。\r\n\r\n- **kube-node-lease**：该命名空间包含用于与各个节点关联的 [Lease（租约）](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Farchitecture\u002Fleases\u002F)对象。 节点租约允许 kubelet 发送[心跳](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Farchitecture\u002Fnodes\u002F#heartbeats)， 由此控制面能够检测到节点故障。\r\n\r\n- **kube-public**：所有的客户端（包括未经身份验证的客户端）都可以读取该命名空间。 该命名空间主要预留为集群使用，以便某些资源需要在整个集群中可见可读。 该命名空间的公共属性只是一种约定而非要求。\r\n\r\n- **kube-system**：该命名空间用于 Kubernetes 系统创建的对象。\r\n\r\n\r\n\r\n### 4.1.1\t查看namespace\r\n\r\n```shell\r\n# 查看namespace\r\nkubectl get namespace\r\n# 简写\r\nkubectl get ns\r\n\r\n#查看指定命名空间下的信息，加 -n 参数，如看kube-system下的pod\r\nkubectl get pods -n kube-system\r\n#查看所有namespace下的pod\r\nkubectl get pods -A\r\n```\r\n\r\n\r\n\r\n### 4.1.2\t创建命名空间\r\n\r\n**命令行方式**：\r\n\r\n```shell\r\n# 创建名为 mh 的命名空间\r\nkubectl create namespace mh\r\n# 简写\r\nkubectl create ns mh\r\n# 删除\r\nkubectl delete namespace mh\r\n```\r\n\r\n**yaml方式**：\r\n\r\n​\t新建一个名为`my-namespace.yaml`文件，并写入以下内容：\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Namespace\r\nmetadata:\r\n  name: mh\r\n```\r\n\r\n然后运行：\r\n\r\n```shell\r\n# 创建\r\nkubectl apply -f my-namespace.yaml\r\n# 删除\r\nkubectl delete -f my-namespace.yaml\r\n```\r\n\r\n\r\n\r\n## 4.2\tPod\r\n\r\n​\t[**Pod**](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Fworkloads\u002Fpods\u002F) **是 Kubernetes 中应用的最小单位。**Pod**（就像在鲸鱼荚或者豌豆荚中）**是运行中的一组（一个或多个）容器； 这些容器共享IP、网络、存储等。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fpod.png\" style=\"zoom:70%;\" \u002F>\r\n\r\n\r\n\r\n**创建Pod示例**：运行一个NGINX容器\r\n\r\n- **命令行方式**\r\n\r\n```shell\r\n# 创建名为mynginx的pod，不指定-n ，则默认创建到default命名空间\r\nkubectl run mynginx --image=nginx:1.27.0\r\n\r\n# 查看运行的pod，不指定-n，则默认查询default命名空间\r\nkubectl get pod\r\n\r\n# 查询指定命名空间下的pod，-owide 表示更详细的显示信息，不指定-n，则默认查询default命名空间\r\nkubectl get pod -owide -n \u003Cnamespace-name>\r\n\r\n#查看pod的详情，不指定-n，则默认查询default命名空间\r\nkubectl describe pod \u003Cpod-name>\r\n\r\n# 查看Pod的运行日志，不指定-n，则默认查看default命名空间\r\nkubectl logs \u003Cpod-name>\r\n\r\n# 删除pod\r\nkubectl delete pod \u003Cpod-name>\r\n```\r\n\r\n\r\n\r\n- **yaml方式**\r\n\r\n```shell\r\n# 编写 nginx-pod.yaml 文件\r\nvi nginx-pod.yaml\r\n```\r\n\r\nyaml内容：\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Pod\r\nmetadata:\r\n  labels:\r\n    run: mynginx   # pod标签\r\n  name: mynginx    # pod名字\r\nspec:\r\n  containers:      # pod中要运行的容器，一个pod中可以运行多个容器\r\n    - name: nginx  # 容器名称  \r\n      image: nginx:1.18.0  # 镜像及版本\r\n      ports:\r\n      - containerPort: 80\r\n```\r\n\r\n执行命令\r\n\r\n```yaml\r\n# 运行pod命令\r\nkubectl apply -f  nginx-pod.yaml\r\n# 删除pod\r\nkubectl delete -f nginx-pod.yaml\r\n```\r\n\r\n\r\n\r\n一个pod中可以运行多个容器:\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Pod\r\nmetadata:\r\n  labels:\r\n    run: myapp\r\n  name: myapp\r\nspec:\r\n  containers:\r\n    - name: nginx\r\n      image: nginx:1.18.0\r\n    - name: tomcat\r\n      image: tomcat:9.0.55\r\n```\r\n\r\n\r\n\r\n## 4.3\t工作负载管理\r\n\r\n​\t在Kubernetes中，工作负载是运行应用程序的一种方式。如果直接管理单个pod的工作量非常繁琐，比如部署10个一模一样的pod，就得手动创建10次，如果后期不需要这么多pod，又得一个个去停。\r\n\r\n​\t使用工作负载部署，就省掉了这么多麻烦，可以任意扩大pod数量，也可以任意缩减pod，哪个pod异常挂了，k8s会自动再启动一个pod，保持pod的部署数量。\r\n\r\n​\tkubernetes使用工作负载部署应用，具备水平扩容，自愈和故障转移能力等。\t\r\n\r\n​\tKubernetes 提供了几种不同的工作负载资源，包括 Deployment、StatefulSet、DaemonSet、Job 和 CronJob。\r\n\r\n​\t**官网**：https:\u002F\u002Fkubernetes.io\u002Fzh\u002Fdocs\u002Fconcepts\u002Fworkloads\u002Fcontrollers\u002F\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002F工作负载.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n- **Deployment**：无状态应用部署，多用于业务服务，比如微服务等；\r\n- **ReplicaSet**：\r\n- **StatefulSet**：有状态应用部署，中间件，数据库等，如：MySQL集群、Zookeeper集群、Nacos集群等；\r\n- **DaemonSet**：守护型应用部署，比如日志收集组件，在每个机器都运行一份；\r\n- **Job\u002FCronJob**：定时任务部署，比如垃圾清理组件，可以在指定时间运行。\r\n\r\n\r\n\r\n有状态服务和无状态服务的区别？\r\n\r\n**无状态服务**：\r\n\r\n- 在k8s中，无状态无法通常以Deployment或ReplicaSet的方式进行部署和管理；\r\n- 无状态服务的实例可以随意扩展和收缩，因为他们之间是相互替换的，而且不需要关注特定实例的状态；\r\n- 无状态服务可以使用水平扩展来应对高负载，k8s可以根据实际负载自动添加或移除实例；\r\n- 开发的应用、微服务等。\r\n\r\n**有状态服务**：\r\n\r\n- 在k8s中，有状态服务通常以StatefulSet的方式进行部署和管理；\r\n- StatefulSet提供了稳定的网络标识和持久化存储的能力，确保每个实例都有唯一的标识且可以使用持久化的卷来保存状态数据；\r\n- 有状态服务的实例通常需要按照确定的顺序部署和扩展，因为他们的状态数据可能会影响到服务的行为；\r\n- redis、mysql、nacos、kafka、zookeeper等。\r\n\r\n\r\n\r\n## 4.4\tDeployment\r\n\r\n​\tDeployment负责创建和更新应用程序的实例，**使Pod拥有多副本，自愈，扩缩容等能力**。创建Deployment后，Kubernetes Master 将应用程序实例调度到集群中的各个节点上。如果托管实例的节点关闭或被删除，Deployment控制器会将该实例替换为群集中另一个节点上的实例。这提供了一种自我修复机制来解决机器故障维护问题。\r\n\r\n### 4.4.1\t基础操作\r\n\r\n- **命令行方式**\r\n\r\n```shell\r\n# 创建tomcat部署应用\r\nkubectl create deployment my-tomcat --image=tomcat:9.0.55\r\n\r\n# 查看部署应用的信息\r\nkubectl get deployment\r\n# 查看部署应用的明细信息\r\nkubectl get deployment -owide\r\n\r\n# 自愈能力，这样删除 my-tomcat-xxx pod后，会自动再启动一个新的pod\r\nkubectl delete pod my-tomcat-6f9cfddd5d-zcg4s\r\n\r\n# 删除deployment部署的应用，这样才能删除创建的deployment部署\r\nkubectl delete deployment my-tomcat\r\n\r\n# 进入Pod容器内部并执行bash命令，如果想退出容器可以使用exit命令\r\nkubectl exec -it my-tomcat-6f9cfddd5d-zcg4s bash\r\n#使用 env 命令查看环境变量\r\nkubectl exec my-tomcat-6d6b57c8c8-n5gm4 -- env\r\n # 查看容器的根目录下面内容\r\nkubectl exec my-tomcat-6d6b57c8c8-n5gm4 -- ls \u002F\r\n#进入Pod容器内部并执行bash命令，如果想退出容器可以使用exit命令\r\nkubectl exec -it my-tomcat-6d6b57c8c8-n5gm4 -- sh\r\n```\r\n\r\n\r\n\r\n### 4.4.2\t自愈&故障转移\r\n\r\n​\tdeployment具备自愈和故障转移能力，当worker节点发生停机、删除pod、pod容器崩溃等，k8s会自动在正常的worker节点重新创建一个pod，这就是k8s的服务**自愈功能**，不需要运维人员干预。\r\n\r\n```shell\r\n#查看pod信息，-w意思是一直等待观察pod信息的变动\r\nkubectl get pod -w\r\n\r\n# 开另外一个命令窗口执行如下删除命令\r\n# 删除 my-tomcat-xxx pod 后，观察自愈过程\r\nkubectl delete pod my-tomcat-6f9cfddd5d-zcg4s\r\n\r\n# 不能用 kubectl delete deployment 命令测试，该命令直接把当前my-tomcat部署删除了\r\n```\r\n\r\n​\t可以看到之前那个tomcat的pod被销毁，但是又重新启动了一个新的tomcat pod，自愈过程如下：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002F自愈pod2.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n### 4.4.3\t多副本\r\n\r\n- **命令行方式：**\r\n\r\n```shell\r\n# 创建3个副本，即3个一模一样的pod\r\nkubectl create deployment my-tomcat --image=tomcat:8.5.0 --replicas=3\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002F多副本.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n- **yaml方式：**\r\n\r\n```yaml\r\napiVersion: apps\u002Fv1\r\nkind: Deployment\r\nmetadata:\r\n  labels:\r\n    app: my-tomcat\r\n  name: my-tomcat\r\nspec:\r\n  replicas: 3  # 创建3个副本，即3个一模一样的pod\r\n  selector:\r\n    matchLabels:\r\n      app: my-tomcat\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: my-tomcat\r\n    spec:       \r\n      containers:  # pod 容器配置\r\n      - image: tomcat:8.5.0\r\n        name: tomcat\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002F多副本-yaml.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n### 4.4.4\t缩扩容\r\n\r\n- **命令行方式：**\r\n\r\n```shell\r\n# 扩容到5个pod\r\nkubectl scale --replicas=5 deployment my-tomcat\r\n# 缩到3个pod\r\nkubectl scale --replicas=3 deployment my-tomcat\r\n\r\n```\r\n\r\n- **yaml方式：**\r\n\r\n```shell\r\n#修改 replicas\r\nkubectl edit deployment my-tomcat\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002F多副本-editpng.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n### 4.4.5\t滚动升级与回滚\r\n\r\n​\t对my-tomcat这个deployment进行滚动升级和回滚，将tomcat版本由tomcat:8.5.0升级到tomcat:9.0.55，再回滚到tomcat:8.5.0 。\r\n\r\n- **镜像版本升级**\r\n\r\n```shell\r\n# 镜像升级\r\nkubectl set image deployment my-tomcat tomcat=tomcat:9.0.55 --record\r\n\r\n# 查看deployment信息、版本\r\nkubectl get deployment -owide\r\n# 查看pod信息、版本\r\nkubectl describe pod my-tomcat-6d6b57c8c8-8vdl2\r\n```\r\n\r\n​\t可以执行 kubectl get pod -w 观察pod的变动情况，可以看到有的pod在销毁，有的pod在创建。\r\n\r\n- **版本回滚**\r\n\r\n```shell\r\n# 查看历史版本\r\nkubectl rollout history deployment my-tomcat\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002F查看历史版本.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n```shell\r\n# 回滚到上一个版本\r\nkubectl rollout undo deployment my-tomcat\r\n\r\n#回到指定版本 (--to-revision 参数可以指定回退的版本)\r\nkubectl rollout undo deployment my-tomcat --to-revision=2\r\n```\r\n\r\n\r\n\r\n### 4.4.6\tpod 访问\r\n\r\n​\t通过pod IP只能在集群内访问（在集群里任一worker节点都可以访问），集群外无法访问。想集群外访问，需要通过创建`service`来访问，后面`service`章节有讲。\r\n\r\n**集群内访问 tomcat pod**：\r\n\r\n```shell\r\n# curl pod的Ip:端口\r\ncurl 10.244.169.165:8080\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002F集群内访问.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n**集群外访问：**\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002F集群外访问.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n\r\n\r\n## 4.5\tService\r\n\r\n**Service**：Pod的服务发现与负载均衡，将一组 [Pods](https:\u002F\u002Fkubernetes.io\u002Fdocs\u002Fconcepts\u002Fworkloads\u002Fpods\u002Fpod-overview\u002F) 公开为网络服务的抽象方法。好比如我们前端访问pod的时候，只需要访问service的地址，service会自动负载均衡到各个pod上。\r\n\r\n**Service** 的类型有两种，分为**ClusterIP** 和 **NodePort**类型，创建时不指定类型，默认是**ClusterIP** 类型。\r\n\r\n- **ClusterIP** ：只能在集群内访问，集群外无法访问，通过集群内生成的ClusterIP访问；\r\n- **NodePort**：暴露端口到宿主机上，集群内外都可以访问，端口范围必须在30000-32767之间，集群内可ClusterIP访问，集群外通过宿主机的IP及暴露的端口访问。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fservice.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n> 不能为Kind类型为Pod的创建service映射。\r\n>\r\n\r\n**操作示例**： 首先部署一个my-nginx应用，拥有3个副本，然后分别修改pod里的html内容为1111，2222，3333。nginx访问默认端口为80，`curl`访问时可以不用指定。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002FSnipaste_2024-10-20_22-36-13.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n- **命令行方式**\r\n\r\n```shell\r\n# 查看pod标签\r\nkubectl get pod --show-labels\r\n\r\n# 创建service命令\r\n# my-nginx 指定上面部署的deployment的标签\r\n# --port 指定暴露外界访问的端口\r\n# --target-port 指定pod中服务的端口（即pod中nginx的监听端口）\r\nkubectl expose deployment my-nginx --port=8000 --target-port=80\r\n\r\n# 查看service信息\r\nkubectl get service\r\nkubectl get service -owide\r\n\r\n# 删除service命令\r\nkubectl delete service my-nginx\r\n```\r\n\r\n（1）**使用service ip访问**，负载均衡效果如下：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002F负载均衡.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n（2）**使用域名访问**，域名规则：`服务名.所在命名空间.svc`   ，服务名是service的名称。域名方式只能在容器内访问，在容器外是无法识别的，这里创建时不指定命名空间，所以是`default`：\r\n\r\n```shell\r\n# 进入容器内部（集群内任意容器）\r\nkubectl exec -it my-tomcat-6f9cfddd5d-zv85t bash\r\n# 使用域名访问\r\ncurl my-nginx.default.svc:8000\r\n# 使用ip访问\r\ncurl 10.96.202.152:8000\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fservice-域名访问.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n- yaml方式\r\n\r\n```shell\r\nvi my-nginx-service.yaml\r\n```\r\n\r\nyaml内容：\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  labels:\r\n    app: my-nginx-serv #当前service的标签\r\n  name: my-nginx-serv  # 当前service的名称，任意\r\nspec:\r\n  selector:\r\n    app: my-nginx  # 指定部署的deployment的标签\r\n  ports:\r\n  - port: 8000     # 暴露外界访问的端口\r\n    protocol: TCP\r\n    targetPort: 80  # 指定pod中服务的端口（即pod中nginx的监听端口）\r\n```\r\n\r\n创建service\r\n\r\n```shell\r\nkubectl apply -f my-nginx-service.yaml\r\n```\r\n\r\n\r\n\r\n#### 4.5.1\tClusterIP\r\n\r\n我们部署的pod、deployment、service 只能在集群内访问（在集群里任一worker节点都可以访问），集群外部是无法访问。\r\n\r\nClusterIP是集群内访问IP，集群外无法访问，创建serivce时不指定`type`类型，默认就是`ClusterIP`类型。\r\n\r\n```shell\r\n# 创建service\r\nkubectl expose deployment my-nginx --port=8000 --target-port=80 --type=ClusterIP\r\n# 不加 --type，默认就是 ClusterIP 类型\r\nkubectl expose deployment my-nginx --port=8000 --target-port=80\r\n```\r\n\r\n（1）集群外访问service，类型为ClusterIP时，是无法访问的。\r\n\r\n- **集群内：**\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002F集群外访问pod-2.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n- **集群外：**\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002F集群外访问pod-3.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n（2）集群外直接访问pod也是无法访问的。\r\n\r\n- **集群内：**\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002F集群外访问pod.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n- **集群外：**\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002F集群外访问pod-1.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n#### 4.5.2\tNodePort\r\n\r\n将service 的端口映射到宿主机上的端口（范围必须在30000-32767之间，不指定则随机分配），这样外界就可以通过宿主机IP及暴露的端口，进行访问。集群内照样可以通过ClusterIP访问，拥有ClusterIP类型的功能，只是多了暴露端口到宿主机上的这个功能。\r\n\r\n集群外使用任意节点IP访问，同样具备负载均衡的能力。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fnodeport3.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n- **命令行方式**\r\n\r\n```shell\r\n# 指定 NodePort 类型，不指定暴露的NodePort端口，则随机随机分配，范围在30000-32767之间\r\nkubectl expose deployment my-nginx --port=8000 --target-port=80 --type=NodePort\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002FnodePort.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n集群外使用worker节点地址访问：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002FnodePort2.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n- **yaml方式**\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  labels:\r\n    app: my-nginx-serv #当前service的标签\r\n  name: my-nginx-serv  # 当前service的名称，任意\r\nspec:\r\n  selector:\r\n    app: my-nginx  # 指定部署的deployment的标签\r\n  ports:\r\n  - port: 8000      #  service访问的端口\r\n    protocol: TCP\r\n    targetPort: 80  # 指定pod中服务的端口（即pod中nginx的监听端口）\r\n    nodePort: 30001  # 指定暴露的节点端口，范围必须在30000-32767之间，不指定则随机分配\r\n  type: NodePort\r\n```\r\n\r\n\r\n\r\n## 4.6\tIngress\r\n\r\n[Ingress](https:\u002F\u002Fkubernetes.io\u002Fdocs\u002Freference\u002Fgenerated\u002Fkubernetes-api\u002Fv1.31\u002F#ingress-v1-networking-k8s-io) 提供从集群外部到集群内[服务](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Fservices-networking\u002Fservice\u002F)的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 资源所定义的规则来控制。Ingress作用好比Nginx，根据路由规则转发、代理。\r\n\r\n[官网](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Fservices-networking\u002Fingress\u002F)：https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Fservices-networking\u002Fingress\u002F\r\n\r\n根据url路径转发到不同的service：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002FingressFanOut.svg\" style=\"zoom:80%;\" \u002F>\r\n\r\n根据域名转发到不同的service：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002FingressNameBased.svg\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n### 4.6.1\t安装\r\n\r\n```shell\r\nwget https:\u002F\u002Fraw.githubusercontent.com\u002Fkubernetes\u002Fingress-nginx\u002Fcontroller-v0.47.0\u002Fdeploy\u002Fstatic\u002Fprovider\u002Fbaremetal\u002Fdeploy.yaml\r\n\r\n#修改镜像\r\nvi deploy.yaml\r\n#将image的值改为如下值：\r\nregistry.cn-hangzhou.aliyuncs.com\u002Flfy_k8s_images\u002Fingress-nginx-controller:v0.46.0\r\n\r\n# 检查安装的结果\r\nkubectl get pod,svc -n ingress-nginx\r\n```\r\n\r\n\r\n\r\n> 如果下载不到，用以下文件，直接粘贴到文件中，kubectl apply -f 运行即可：\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Namespace\r\nmetadata:\r\n  name: ingress-nginx\r\n  labels:\r\n    app.kubernetes.io\u002Fname: ingress-nginx\r\n    app.kubernetes.io\u002Finstance: ingress-nginx\r\n\r\n---\r\n# Source: ingress-nginx\u002Ftemplates\u002Fcontroller-serviceaccount.yaml\r\napiVersion: v1\r\nkind: ServiceAccount\r\nmetadata:\r\n  labels:\r\n    helm.sh\u002Fchart: ingress-nginx-3.33.0\r\n    app.kubernetes.io\u002Fname: ingress-nginx\r\n    app.kubernetes.io\u002Finstance: ingress-nginx\r\n    app.kubernetes.io\u002Fversion: 0.47.0\r\n    app.kubernetes.io\u002Fmanaged-by: Helm\r\n    app.kubernetes.io\u002Fcomponent: controller\r\n  name: ingress-nginx\r\n  namespace: ingress-nginx\r\nautomountServiceAccountToken: true\r\n---\r\n# Source: ingress-nginx\u002Ftemplates\u002Fcontroller-configmap.yaml\r\napiVersion: v1\r\nkind: ConfigMap\r\nmetadata:\r\n  labels:\r\n    helm.sh\u002Fchart: ingress-nginx-3.33.0\r\n    app.kubernetes.io\u002Fname: ingress-nginx\r\n    app.kubernetes.io\u002Finstance: ingress-nginx\r\n    app.kubernetes.io\u002Fversion: 0.47.0\r\n    app.kubernetes.io\u002Fmanaged-by: Helm\r\n    app.kubernetes.io\u002Fcomponent: controller\r\n  name: ingress-nginx-controller\r\n  namespace: ingress-nginx\r\ndata:\r\n---\r\n# Source: ingress-nginx\u002Ftemplates\u002Fclusterrole.yaml\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nkind: ClusterRole\r\nmetadata:\r\n  labels:\r\n    helm.sh\u002Fchart: ingress-nginx-3.33.0\r\n    app.kubernetes.io\u002Fname: ingress-nginx\r\n    app.kubernetes.io\u002Finstance: ingress-nginx\r\n    app.kubernetes.io\u002Fversion: 0.47.0\r\n    app.kubernetes.io\u002Fmanaged-by: Helm\r\n  name: ingress-nginx\r\nrules:\r\n  - apiGroups:\r\n      - ''\r\n    resources:\r\n      - configmaps\r\n      - endpoints\r\n      - nodes\r\n      - pods\r\n      - secrets\r\n    verbs:\r\n      - list\r\n      - watch\r\n  - apiGroups:\r\n      - ''\r\n    resources:\r\n      - nodes\r\n    verbs:\r\n      - get\r\n  - apiGroups:\r\n      - ''\r\n    resources:\r\n      - services\r\n    verbs:\r\n      - get\r\n      - list\r\n      - watch\r\n  - apiGroups:\r\n      - extensions\r\n      - networking.k8s.io   # k8s 1.14+\r\n    resources:\r\n      - ingresses\r\n    verbs:\r\n      - get\r\n      - list\r\n      - watch\r\n  - apiGroups:\r\n      - ''\r\n    resources:\r\n      - events\r\n    verbs:\r\n      - create\r\n      - patch\r\n  - apiGroups:\r\n      - extensions\r\n      - networking.k8s.io   # k8s 1.14+\r\n    resources:\r\n      - ingresses\u002Fstatus\r\n    verbs:\r\n      - update\r\n  - apiGroups:\r\n      - networking.k8s.io   # k8s 1.14+\r\n    resources:\r\n      - ingressclasses\r\n    verbs:\r\n      - get\r\n      - list\r\n      - watch\r\n---\r\n# Source: ingress-nginx\u002Ftemplates\u002Fclusterrolebinding.yaml\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nkind: ClusterRoleBinding\r\nmetadata:\r\n  labels:\r\n    helm.sh\u002Fchart: ingress-nginx-3.33.0\r\n    app.kubernetes.io\u002Fname: ingress-nginx\r\n    app.kubernetes.io\u002Finstance: ingress-nginx\r\n    app.kubernetes.io\u002Fversion: 0.47.0\r\n    app.kubernetes.io\u002Fmanaged-by: Helm\r\n  name: ingress-nginx\r\nroleRef:\r\n  apiGroup: rbac.authorization.k8s.io\r\n  kind: ClusterRole\r\n  name: ingress-nginx\r\nsubjects:\r\n  - kind: ServiceAccount\r\n    name: ingress-nginx\r\n    namespace: ingress-nginx\r\n---\r\n# Source: ingress-nginx\u002Ftemplates\u002Fcontroller-role.yaml\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nkind: Role\r\nmetadata:\r\n  labels:\r\n    helm.sh\u002Fchart: ingress-nginx-3.33.0\r\n    app.kubernetes.io\u002Fname: ingress-nginx\r\n    app.kubernetes.io\u002Finstance: ingress-nginx\r\n    app.kubernetes.io\u002Fversion: 0.47.0\r\n    app.kubernetes.io\u002Fmanaged-by: Helm\r\n    app.kubernetes.io\u002Fcomponent: controller\r\n  name: ingress-nginx\r\n  namespace: ingress-nginx\r\nrules:\r\n  - apiGroups:\r\n      - ''\r\n    resources:\r\n      - namespaces\r\n    verbs:\r\n      - get\r\n  - apiGroups:\r\n      - ''\r\n    resources:\r\n      - configmaps\r\n      - pods\r\n      - secrets\r\n      - endpoints\r\n    verbs:\r\n      - get\r\n      - list\r\n      - watch\r\n  - apiGroups:\r\n      - ''\r\n    resources:\r\n      - services\r\n    verbs:\r\n      - get\r\n      - list\r\n      - watch\r\n  - apiGroups:\r\n      - extensions\r\n      - networking.k8s.io   # k8s 1.14+\r\n    resources:\r\n      - ingresses\r\n    verbs:\r\n      - get\r\n      - list\r\n      - watch\r\n  - apiGroups:\r\n      - extensions\r\n      - networking.k8s.io   # k8s 1.14+\r\n    resources:\r\n      - ingresses\u002Fstatus\r\n    verbs:\r\n      - update\r\n  - apiGroups:\r\n      - networking.k8s.io   # k8s 1.14+\r\n    resources:\r\n      - ingressclasses\r\n    verbs:\r\n      - get\r\n      - list\r\n      - watch\r\n  - apiGroups:\r\n      - ''\r\n    resources:\r\n      - configmaps\r\n    resourceNames:\r\n      - ingress-controller-leader-nginx\r\n    verbs:\r\n      - get\r\n      - update\r\n  - apiGroups:\r\n      - ''\r\n    resources:\r\n      - configmaps\r\n    verbs:\r\n      - create\r\n  - apiGroups:\r\n      - ''\r\n    resources:\r\n      - events\r\n    verbs:\r\n      - create\r\n      - patch\r\n---\r\n# Source: ingress-nginx\u002Ftemplates\u002Fcontroller-rolebinding.yaml\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nkind: RoleBinding\r\nmetadata:\r\n  labels:\r\n    helm.sh\u002Fchart: ingress-nginx-3.33.0\r\n    app.kubernetes.io\u002Fname: ingress-nginx\r\n    app.kubernetes.io\u002Finstance: ingress-nginx\r\n    app.kubernetes.io\u002Fversion: 0.47.0\r\n    app.kubernetes.io\u002Fmanaged-by: Helm\r\n    app.kubernetes.io\u002Fcomponent: controller\r\n  name: ingress-nginx\r\n  namespace: ingress-nginx\r\nroleRef:\r\n  apiGroup: rbac.authorization.k8s.io\r\n  kind: Role\r\n  name: ingress-nginx\r\nsubjects:\r\n  - kind: ServiceAccount\r\n    name: ingress-nginx\r\n    namespace: ingress-nginx\r\n---\r\n# Source: ingress-nginx\u002Ftemplates\u002Fcontroller-service-webhook.yaml\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  labels:\r\n    helm.sh\u002Fchart: ingress-nginx-3.33.0\r\n    app.kubernetes.io\u002Fname: ingress-nginx\r\n    app.kubernetes.io\u002Finstance: ingress-nginx\r\n    app.kubernetes.io\u002Fversion: 0.47.0\r\n    app.kubernetes.io\u002Fmanaged-by: Helm\r\n    app.kubernetes.io\u002Fcomponent: controller\r\n  name: ingress-nginx-controller-admission\r\n  namespace: ingress-nginx\r\nspec:\r\n  type: ClusterIP\r\n  ports:\r\n    - name: https-webhook\r\n      port: 443\r\n      targetPort: webhook\r\n  selector:\r\n    app.kubernetes.io\u002Fname: ingress-nginx\r\n    app.kubernetes.io\u002Finstance: ingress-nginx\r\n    app.kubernetes.io\u002Fcomponent: controller\r\n---\r\n# Source: ingress-nginx\u002Ftemplates\u002Fcontroller-service.yaml\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  annotations:\r\n  labels:\r\n    helm.sh\u002Fchart: ingress-nginx-3.33.0\r\n    app.kubernetes.io\u002Fname: ingress-nginx\r\n    app.kubernetes.io\u002Finstance: ingress-nginx\r\n    app.kubernetes.io\u002Fversion: 0.47.0\r\n    app.kubernetes.io\u002Fmanaged-by: Helm\r\n    app.kubernetes.io\u002Fcomponent: controller\r\n  name: ingress-nginx-controller\r\n  namespace: ingress-nginx\r\nspec:\r\n  type: NodePort\r\n  ports:\r\n    - name: http\r\n      port: 80\r\n      protocol: TCP\r\n      targetPort: http\r\n    - name: https\r\n      port: 443\r\n      protocol: TCP\r\n      targetPort: https\r\n  selector:\r\n    app.kubernetes.io\u002Fname: ingress-nginx\r\n    app.kubernetes.io\u002Finstance: ingress-nginx\r\n    app.kubernetes.io\u002Fcomponent: controller\r\n---\r\n# Source: ingress-nginx\u002Ftemplates\u002Fcontroller-deployment.yaml\r\napiVersion: apps\u002Fv1\r\nkind: Deployment\r\nmetadata:\r\n  labels:\r\n    helm.sh\u002Fchart: ingress-nginx-3.33.0\r\n    app.kubernetes.io\u002Fname: ingress-nginx\r\n    app.kubernetes.io\u002Finstance: ingress-nginx\r\n    app.kubernetes.io\u002Fversion: 0.47.0\r\n    app.kubernetes.io\u002Fmanaged-by: Helm\r\n    app.kubernetes.io\u002Fcomponent: controller\r\n  name: ingress-nginx-controller\r\n  namespace: ingress-nginx\r\nspec:\r\n  selector:\r\n    matchLabels:\r\n      app.kubernetes.io\u002Fname: ingress-nginx\r\n      app.kubernetes.io\u002Finstance: ingress-nginx\r\n      app.kubernetes.io\u002Fcomponent: controller\r\n  revisionHistoryLimit: 10\r\n  minReadySeconds: 0\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app.kubernetes.io\u002Fname: ingress-nginx\r\n        app.kubernetes.io\u002Finstance: ingress-nginx\r\n        app.kubernetes.io\u002Fcomponent: controller\r\n    spec:\r\n      dnsPolicy: ClusterFirst\r\n      containers:\r\n        - name: controller\r\n          image: registry.cn-hangzhou.aliyuncs.com\u002Flfy_k8s_images\u002Fingress-nginx-controller:v0.46.0\r\n          imagePullPolicy: IfNotPresent\r\n          lifecycle:\r\n            preStop:\r\n              exec:\r\n                command:\r\n                  - \u002Fwait-shutdown\r\n          args:\r\n            - \u002Fnginx-ingress-controller\r\n            - --election-id=ingress-controller-leader\r\n            - --ingress-class=nginx\r\n            - --configmap=$(POD_NAMESPACE)\u002Fingress-nginx-controller\r\n            - --validating-webhook=:8443\r\n            - --validating-webhook-certificate=\u002Fusr\u002Flocal\u002Fcertificates\u002Fcert\r\n            - --validating-webhook-key=\u002Fusr\u002Flocal\u002Fcertificates\u002Fkey\r\n          securityContext:\r\n            capabilities:\r\n              drop:\r\n                - ALL\r\n              add:\r\n                - NET_BIND_SERVICE\r\n            runAsUser: 101\r\n            allowPrivilegeEscalation: true\r\n          env:\r\n            - name: POD_NAME\r\n              valueFrom:\r\n                fieldRef:\r\n                  fieldPath: metadata.name\r\n            - name: POD_NAMESPACE\r\n              valueFrom:\r\n                fieldRef:\r\n                  fieldPath: metadata.namespace\r\n            - name: LD_PRELOAD\r\n              value: \u002Fusr\u002Flocal\u002Flib\u002Flibmimalloc.so\r\n          livenessProbe:\r\n            failureThreshold: 5\r\n            httpGet:\r\n              path: \u002Fhealthz\r\n              port: 10254\r\n              scheme: HTTP\r\n            initialDelaySeconds: 10\r\n            periodSeconds: 10\r\n            successThreshold: 1\r\n            timeoutSeconds: 1\r\n          readinessProbe:\r\n            failureThreshold: 3\r\n            httpGet:\r\n              path: \u002Fhealthz\r\n              port: 10254\r\n              scheme: HTTP\r\n            initialDelaySeconds: 10\r\n            periodSeconds: 10\r\n            successThreshold: 1\r\n            timeoutSeconds: 1\r\n          ports:\r\n            - name: http\r\n              containerPort: 80\r\n              protocol: TCP\r\n            - name: https\r\n              containerPort: 443\r\n              protocol: TCP\r\n            - name: webhook\r\n              containerPort: 8443\r\n              protocol: TCP\r\n          volumeMounts:\r\n            - name: webhook-cert\r\n              mountPath: \u002Fusr\u002Flocal\u002Fcertificates\u002F\r\n              readOnly: true\r\n          resources:\r\n            requests:\r\n              cpu: 100m\r\n              memory: 90Mi\r\n      nodeSelector:\r\n        kubernetes.io\u002Fos: linux\r\n      serviceAccountName: ingress-nginx\r\n      terminationGracePeriodSeconds: 300\r\n      volumes:\r\n        - name: webhook-cert\r\n          secret:\r\n            secretName: ingress-nginx-admission\r\n---\r\n# Source: ingress-nginx\u002Ftemplates\u002Fadmission-webhooks\u002Fvalidating-webhook.yaml\r\n# before changing this value, check the required kubernetes version\r\n# https:\u002F\u002Fkubernetes.io\u002Fdocs\u002Freference\u002Faccess-authn-authz\u002Fextensible-admission-controllers\u002F#prerequisites\r\napiVersion: admissionregistration.k8s.io\u002Fv1\r\nkind: ValidatingWebhookConfiguration\r\nmetadata:\r\n  labels:\r\n    helm.sh\u002Fchart: ingress-nginx-3.33.0\r\n    app.kubernetes.io\u002Fname: ingress-nginx\r\n    app.kubernetes.io\u002Finstance: ingress-nginx\r\n    app.kubernetes.io\u002Fversion: 0.47.0\r\n    app.kubernetes.io\u002Fmanaged-by: Helm\r\n    app.kubernetes.io\u002Fcomponent: admission-webhook\r\n  name: ingress-nginx-admission\r\nwebhooks:\r\n  - name: validate.nginx.ingress.kubernetes.io\r\n    matchPolicy: Equivalent\r\n    rules:\r\n      - apiGroups:\r\n          - networking.k8s.io\r\n        apiVersions:\r\n          - v1beta1\r\n        operations:\r\n          - CREATE\r\n          - UPDATE\r\n        resources:\r\n          - ingresses\r\n    failurePolicy: Fail\r\n    sideEffects: None\r\n    admissionReviewVersions:\r\n      - v1\r\n      - v1beta1\r\n    clientConfig:\r\n      service:\r\n        namespace: ingress-nginx\r\n        name: ingress-nginx-controller-admission\r\n        path: \u002Fnetworking\u002Fv1beta1\u002Fingresses\r\n---\r\n# Source: ingress-nginx\u002Ftemplates\u002Fadmission-webhooks\u002Fjob-patch\u002Fserviceaccount.yaml\r\napiVersion: v1\r\nkind: ServiceAccount\r\nmetadata:\r\n  name: ingress-nginx-admission\r\n  annotations:\r\n    helm.sh\u002Fhook: pre-install,pre-upgrade,post-install,post-upgrade\r\n    helm.sh\u002Fhook-delete-policy: before-hook-creation,hook-succeeded\r\n  labels:\r\n    helm.sh\u002Fchart: ingress-nginx-3.33.0\r\n    app.kubernetes.io\u002Fname: ingress-nginx\r\n    app.kubernetes.io\u002Finstance: ingress-nginx\r\n    app.kubernetes.io\u002Fversion: 0.47.0\r\n    app.kubernetes.io\u002Fmanaged-by: Helm\r\n    app.kubernetes.io\u002Fcomponent: admission-webhook\r\n  namespace: ingress-nginx\r\n---\r\n# Source: ingress-nginx\u002Ftemplates\u002Fadmission-webhooks\u002Fjob-patch\u002Fclusterrole.yaml\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nkind: ClusterRole\r\nmetadata:\r\n  name: ingress-nginx-admission\r\n  annotations:\r\n    helm.sh\u002Fhook: pre-install,pre-upgrade,post-install,post-upgrade\r\n    helm.sh\u002Fhook-delete-policy: before-hook-creation,hook-succeeded\r\n  labels:\r\n    helm.sh\u002Fchart: ingress-nginx-3.33.0\r\n    app.kubernetes.io\u002Fname: ingress-nginx\r\n    app.kubernetes.io\u002Finstance: ingress-nginx\r\n    app.kubernetes.io\u002Fversion: 0.47.0\r\n    app.kubernetes.io\u002Fmanaged-by: Helm\r\n    app.kubernetes.io\u002Fcomponent: admission-webhook\r\nrules:\r\n  - apiGroups:\r\n      - admissionregistration.k8s.io\r\n    resources:\r\n      - validatingwebhookconfigurations\r\n    verbs:\r\n      - get\r\n      - update\r\n---\r\n# Source: ingress-nginx\u002Ftemplates\u002Fadmission-webhooks\u002Fjob-patch\u002Fclusterrolebinding.yaml\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nkind: ClusterRoleBinding\r\nmetadata:\r\n  name: ingress-nginx-admission\r\n  annotations:\r\n    helm.sh\u002Fhook: pre-install,pre-upgrade,post-install,post-upgrade\r\n    helm.sh\u002Fhook-delete-policy: before-hook-creation,hook-succeeded\r\n  labels:\r\n    helm.sh\u002Fchart: ingress-nginx-3.33.0\r\n    app.kubernetes.io\u002Fname: ingress-nginx\r\n    app.kubernetes.io\u002Finstance: ingress-nginx\r\n    app.kubernetes.io\u002Fversion: 0.47.0\r\n    app.kubernetes.io\u002Fmanaged-by: Helm\r\n    app.kubernetes.io\u002Fcomponent: admission-webhook\r\nroleRef:\r\n  apiGroup: rbac.authorization.k8s.io\r\n  kind: ClusterRole\r\n  name: ingress-nginx-admission\r\nsubjects:\r\n  - kind: ServiceAccount\r\n    name: ingress-nginx-admission\r\n    namespace: ingress-nginx\r\n---\r\n# Source: ingress-nginx\u002Ftemplates\u002Fadmission-webhooks\u002Fjob-patch\u002Frole.yaml\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nkind: Role\r\nmetadata:\r\n  name: ingress-nginx-admission\r\n  annotations:\r\n    helm.sh\u002Fhook: pre-install,pre-upgrade,post-install,post-upgrade\r\n    helm.sh\u002Fhook-delete-policy: before-hook-creation,hook-succeeded\r\n  labels:\r\n    helm.sh\u002Fchart: ingress-nginx-3.33.0\r\n    app.kubernetes.io\u002Fname: ingress-nginx\r\n    app.kubernetes.io\u002Finstance: ingress-nginx\r\n    app.kubernetes.io\u002Fversion: 0.47.0\r\n    app.kubernetes.io\u002Fmanaged-by: Helm\r\n    app.kubernetes.io\u002Fcomponent: admission-webhook\r\n  namespace: ingress-nginx\r\nrules:\r\n  - apiGroups:\r\n      - ''\r\n    resources:\r\n      - secrets\r\n    verbs:\r\n      - get\r\n      - create\r\n---\r\n# Source: ingress-nginx\u002Ftemplates\u002Fadmission-webhooks\u002Fjob-patch\u002Frolebinding.yaml\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nkind: RoleBinding\r\nmetadata:\r\n  name: ingress-nginx-admission\r\n  annotations:\r\n    helm.sh\u002Fhook: pre-install,pre-upgrade,post-install,post-upgrade\r\n    helm.sh\u002Fhook-delete-policy: before-hook-creation,hook-succeeded\r\n  labels:\r\n    helm.sh\u002Fchart: ingress-nginx-3.33.0\r\n    app.kubernetes.io\u002Fname: ingress-nginx\r\n    app.kubernetes.io\u002Finstance: ingress-nginx\r\n    app.kubernetes.io\u002Fversion: 0.47.0\r\n    app.kubernetes.io\u002Fmanaged-by: Helm\r\n    app.kubernetes.io\u002Fcomponent: admission-webhook\r\n  namespace: ingress-nginx\r\nroleRef:\r\n  apiGroup: rbac.authorization.k8s.io\r\n  kind: Role\r\n  name: ingress-nginx-admission\r\nsubjects:\r\n  - kind: ServiceAccount\r\n    name: ingress-nginx-admission\r\n    namespace: ingress-nginx\r\n---\r\n# Source: ingress-nginx\u002Ftemplates\u002Fadmission-webhooks\u002Fjob-patch\u002Fjob-createSecret.yaml\r\napiVersion: batch\u002Fv1\r\nkind: Job\r\nmetadata:\r\n  name: ingress-nginx-admission-create\r\n  annotations:\r\n    helm.sh\u002Fhook: pre-install,pre-upgrade\r\n    helm.sh\u002Fhook-delete-policy: before-hook-creation,hook-succeeded\r\n  labels:\r\n    helm.sh\u002Fchart: ingress-nginx-3.33.0\r\n    app.kubernetes.io\u002Fname: ingress-nginx\r\n    app.kubernetes.io\u002Finstance: ingress-nginx\r\n    app.kubernetes.io\u002Fversion: 0.47.0\r\n    app.kubernetes.io\u002Fmanaged-by: Helm\r\n    app.kubernetes.io\u002Fcomponent: admission-webhook\r\n  namespace: ingress-nginx\r\nspec:\r\n  template:\r\n    metadata:\r\n      name: ingress-nginx-admission-create\r\n      labels:\r\n        helm.sh\u002Fchart: ingress-nginx-3.33.0\r\n        app.kubernetes.io\u002Fname: ingress-nginx\r\n        app.kubernetes.io\u002Finstance: ingress-nginx\r\n        app.kubernetes.io\u002Fversion: 0.47.0\r\n        app.kubernetes.io\u002Fmanaged-by: Helm\r\n        app.kubernetes.io\u002Fcomponent: admission-webhook\r\n    spec:\r\n      containers:\r\n        - name: create\r\n          image: docker.io\u002Fjettech\u002Fkube-webhook-certgen:v1.5.1\r\n          imagePullPolicy: IfNotPresent\r\n          args:\r\n            - create\r\n            - --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc\r\n            - --namespace=$(POD_NAMESPACE)\r\n            - --secret-name=ingress-nginx-admission\r\n          env:\r\n            - name: POD_NAMESPACE\r\n              valueFrom:\r\n                fieldRef:\r\n                  fieldPath: metadata.namespace\r\n      restartPolicy: OnFailure\r\n      serviceAccountName: ingress-nginx-admission\r\n      securityContext:\r\n        runAsNonRoot: true\r\n        runAsUser: 2000\r\n---\r\n# Source: ingress-nginx\u002Ftemplates\u002Fadmission-webhooks\u002Fjob-patch\u002Fjob-patchWebhook.yaml\r\napiVersion: batch\u002Fv1\r\nkind: Job\r\nmetadata:\r\n  name: ingress-nginx-admission-patch\r\n  annotations:\r\n    helm.sh\u002Fhook: post-install,post-upgrade\r\n    helm.sh\u002Fhook-delete-policy: before-hook-creation,hook-succeeded\r\n  labels:\r\n    helm.sh\u002Fchart: ingress-nginx-3.33.0\r\n    app.kubernetes.io\u002Fname: ingress-nginx\r\n    app.kubernetes.io\u002Finstance: ingress-nginx\r\n    app.kubernetes.io\u002Fversion: 0.47.0\r\n    app.kubernetes.io\u002Fmanaged-by: Helm\r\n    app.kubernetes.io\u002Fcomponent: admission-webhook\r\n  namespace: ingress-nginx\r\nspec:\r\n  template:\r\n    metadata:\r\n      name: ingress-nginx-admission-patch\r\n      labels:\r\n        helm.sh\u002Fchart: ingress-nginx-3.33.0\r\n        app.kubernetes.io\u002Fname: ingress-nginx\r\n        app.kubernetes.io\u002Finstance: ingress-nginx\r\n        app.kubernetes.io\u002Fversion: 0.47.0\r\n        app.kubernetes.io\u002Fmanaged-by: Helm\r\n        app.kubernetes.io\u002Fcomponent: admission-webhook\r\n    spec:\r\n      containers:\r\n        - name: patch\r\n          image: docker.io\u002Fjettech\u002Fkube-webhook-certgen:v1.5.1\r\n          imagePullPolicy: IfNotPresent\r\n          args:\r\n            - patch\r\n            - --webhook-name=ingress-nginx-admission\r\n            - --namespace=$(POD_NAMESPACE)\r\n            - --patch-mutating=false\r\n            - --secret-name=ingress-nginx-admission\r\n            - --patch-failure-policy=Fail\r\n          env:\r\n            - name: POD_NAMESPACE\r\n              valueFrom:\r\n                fieldRef:\r\n                  fieldPath: metadata.namespace\r\n      restartPolicy: OnFailure\r\n      serviceAccountName: ingress-nginx-admission\r\n      securityContext:\r\n        runAsNonRoot: true\r\n        runAsUser: 2000\r\n```\r\n\r\n\r\n\r\n```shell\r\n# 安装\r\nkubectl apply -f deploy.yaml\r\n\r\n# 查看ingress 安装信息\r\nkubectl get pod -n ingress-nginx\r\n\r\n# 查看ingress service 暴露的端口，http内部是80，对外暴露则是30509；https集群内是443，对外暴露则是31565\r\n# ingress底层是nginx，因此对外监听的是30509 和 31565 端口\r\n# 注意并不是所有的Ingress对外监听的都是30509和31565，监听的端口在30000-32767之间\r\nkubectl get service -n ingress-nginx\r\n# 查看 创建的ingress服务\r\nkubectl get ingress\r\n# 查看 创建的ingress 详细信息\r\nkubectl describe ingress\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fingress-pod.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n### 4.6.2\tIngress 配置规则\r\n\r\n#### 4.6.2.1\tIngress配置模板\r\n\r\n```yaml\r\napiVersion: networking.k8s.io\u002Fv1   # 资源所属的API群组和版本\r\nkind: Ingress   # 资源类型\r\nmetadata:       # 元数据\r\n  name:  \u003Cstring>       # 资源名称\r\n  namespace: \u003Cstring>   # 命名空间，可选，不指定则是default空间\r\nspec:     \r\n  ingressClassName: nginx   # 适用的Ingress控制器类别，须明确指明\r\n  rules:                    # Ingress规则列表\r\n  - host: \u003Cstring>          # 虚拟主机的FQDN，俗称域名, 可选\r\n    http:\r\n      paths:                # 虚拟主机的PATH定义列表\r\n      - path: \u003Cstring>      # 匹配以什么开头类似于nginx中的location\r\n        pathType: \u003Cstring>    # Prefix：前缀匹配，Exact：不区分大小写，URL：精确匹配，区分大小写\r\n        backend:           # 后端\r\n          service:         #关联后端的Service\r\n            name: \u003Cstring>   # 后端Service的名称\r\n            port:          #后端Service的端口或名称，下面的number、name二选一\r\n              number:      # 端口号\r\n              name:        # 端口名称\r\n```\r\n\r\n#### 4.6.2.2\tIngress 资源\r\n\r\n一个最小的 Ingress 资源示例：\r\n\r\n```yaml\r\napiVersion: networking.k8s.io\u002Fv1\r\nkind: Ingress\r\nmetadata:\r\n  name: minimal-ingress\r\n  annotations:\t\t# 路径重写\r\n    nginx.ingress.kubernetes.io\u002Frewrite-target: \u002F\r\nspec:\r\n  ingressClassName: nginx\r\n  rules:\r\n  - http:\r\n      paths:\r\n      - path: \u002Ftest       # 路径匹配，结合pathType的值Prefix，就是前缀匹配，匹配前缀为 \u002Ftest 的url\r\n        pathType: Prefix  # 匹配规则：前缀匹配\r\n        backend:\r\n          service:\r\n            name: nginx-demo    # 指定service服务名\r\n            port:\r\n              number: 9000      # 指定service服务端口\r\n```\r\n\r\nIngress 需要指定 `apiVersion`、`kind`、 `metadata`和 `spec` 字段。\r\n\r\n每个规则都包含以下信息：\r\n\r\n-  `host`：可选，不指定 `host`，集群内所有节点的IP地址都能匹配到，当然还得结合`paths.path`  指定的路径匹配。\r\n\r\n- `pathType`：路径匹配规则，主要有下面这3中类型：\r\n\r\n  - `Prefix` ：基于以 `\u002F` 分隔的 URL 路径前缀匹配，匹配区分大小写。如`path`路径为`\u002Ffoo`，能匹配`\u002Ffoo`, `\u002Ffoo\u002F`；\r\n  - `Exact`：精确匹配，且区分大小写。如`path`路径为`\u002Ffoo`，只能匹配`\u002Ffoo`，不能匹配`\u002Ffoo\u002F`；\r\n  - `ImplementationSpecific`：对于这种路径类型，匹配方法取决于 IngressClass。\r\n\r\n- `path`：路径匹配（例如 `\u002Ftest`）。如果`pathType`为`Prefix`，那就是匹配前缀为 `\u002Ftest`的路径。\r\n\r\n- `service`：指定的映射的service信息，每个`path`路径都有一个由 `service.name` 和 `service.port.name` 或 `service.port.number` 确定的关联后端。 主机和路径都必须与入站请求的内容相匹配，负载均衡器才会将流量引导到所引用的 Service。\r\n\r\n  -  `service.name` ：指定关联的service名称，这个service必须存在；\r\n  -  `service.port.name`：指定关联的service端口名称。和`service.port.number` 只需指定一个即可，二选一；\r\n  - `service.port.number` ：指定关联的service端口号。和`service.port.name`只需指定一个即可，二选一。\r\n\r\n  \r\n\r\n#### 4.6.2.3\thost主机名通配符\r\n\r\n主机名可以是精确匹配（例如 “`foo.bar.com`”）或者使用通配符来匹配 （例如 “`*.foo.com`”）。 \r\n\r\n- 精确匹配要求 HTTP `host` 头部字段与 `host` 字段值完全匹配。\r\n- 通配符匹配则要求 HTTP `host` 头部字段与通配符规则中的后缀部分相同。\r\n\r\n| 主机        | host 头部         | 匹配与否？                          |\r\n| ----------- | ----------------- | ----------------------------------- |\r\n| `*.foo.com` | `bar.foo.com`     | 基于相同的后缀匹配                  |\r\n| `*.foo.com` | `baz.bar.foo.com` | 不匹配，通配符仅覆盖了一个 DNS 标签 |\r\n| `*.foo.com` | `foo.com`         | 不匹配，通配符仅覆盖了一个 DNS 标签 |\r\n\r\n```yaml\r\napiVersion: networking.k8s.io\u002Fv1\r\nkind: Ingress\r\nmetadata:\r\n  name: ingress-wildcard-host\r\nspec:\r\n  rules:\r\n  - host: \"foo.bar.com\"    # 精确匹配\r\n    http:\r\n      paths:\r\n      - pathType: Prefix\r\n        path: \"\u002Fbar\"\r\n        backend:\r\n          service:\r\n            name: service1\r\n            port:\r\n              number: 80\r\n  - host: \"*.foo.com\"     # 通配符匹配\r\n    http:\r\n      paths:\r\n      - pathType: Prefix\r\n        path: \"\u002Ffoo\"\r\n        backend:\r\n          service:\r\n            name: service2\r\n            port:\r\n              number: 80\r\n```\r\n\r\n#### 4.6.2.4\t简单扇出\r\n\r\n一个扇出（Fanout）配置根据请求的 HTTP URI 将来自同一 IP 地址的流量路由到多个 Service。 Ingress 允许你将负载均衡器的数量降至最低。例如，这样的设置：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002FingressFanOut.svg\" style=\"zoom:70%;\" \u002F>\r\n\r\n```yaml\r\napiVersion: networking.k8s.io\u002Fv1\r\nkind: Ingress\r\nmetadata:\r\n  name: simple-fanout-example\r\nspec:\r\n  rules:\r\n  - host: foo.bar.com\r\n    http:\r\n      paths:\r\n      - path: \u002Ffoo\r\n        pathType: Prefix\r\n        backend:\r\n          service:\r\n            name: service1\r\n            port:\r\n              number: 4200\r\n      - path: \u002Fbar\r\n        pathType: Prefix\r\n        backend:\r\n          service:\r\n            name: service2\r\n            port:\r\n              number: 8080\r\n```\r\n\r\n#### 4.6.2.5\t基于名称的虚拟主机服务\r\n\r\n针对不同的域名流量路由到多个 Service。以下 Ingress 让后台负载均衡器基于 [host 头部字段](https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7230#section-5.4)来路由请求。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002FingressNameBased.svg\" style=\"zoom:70%;\" \u002F>\r\n\r\n```yaml\r\napiVersion: networking.k8s.io\u002Fv1\r\nkind: Ingress\r\nmetadata:\r\n  name: name-virtual-host-ingress\r\nspec:\r\n  rules:\r\n  - host: foo.bar.com\r\n    http:\r\n      paths:\r\n      - pathType: Prefix\r\n        path: \"\u002F\"\r\n        backend:\r\n          service:\r\n            name: service1\r\n            port:\r\n              number: 80\r\n  - host: bar.foo.com\r\n    http:\r\n      paths:\r\n      - pathType: Prefix\r\n        path: \"\u002F\"\r\n        backend:\r\n          service:\r\n            name: service2\r\n            port:\r\n              number: 80\r\n```\r\n\r\n#### 4.6.2.6\t不指定主机名\r\n\r\n如果你所创建的 Ingress 资源没有在 `rules` 中定义主机，则规则可以匹配指向 Ingress 控制器 IP 地址的所有网络流量，而无需基于名称的虚拟主机。\r\n\r\n例如，下面的 Ingress 对象会将请求 `first.bar.com` 的流量路由到 `service1`，将请求 `second.bar.com` 的流量路由到 `service2`，而将所有其他流量路由到 `service3`。\r\n\r\n```yaml\r\napiVersion: networking.k8s.io\u002Fv1\r\nkind: Ingress\r\nmetadata:\r\n  name: name-virtual-host-ingress-no-third-host\r\nspec:\r\n  rules:\r\n  - host: first.bar.com  # 指定虚拟主机名，即域名\r\n    http:\r\n      paths:\r\n      - pathType: Prefix\r\n        path: \"\u002F\"\r\n        backend:\r\n          service:\r\n            name: service1\r\n            port:\r\n              number: 80\r\n  - host: second.bar.com   # 指定虚拟主机名，即域名\r\n    http:\r\n      paths:\r\n      - pathType: Prefix\r\n        path: \"\u002F\"\r\n        backend:\r\n          service:\r\n            name: service2\r\n            port:\r\n              number: 80\r\n  - http:\t\t\t\t    # 不指定虚拟主机名，除了上面指定的域名，其他域名或IP都会进入这里\r\n      paths:\r\n      - pathType: Prefix\r\n        path: \"\u002F\"\r\n        backend:\r\n          service:\r\n            name: service3\r\n            port:\r\n              number: 80\r\n```\r\n\r\n\r\n\r\n### 4.6.3\t使用示例\r\n\r\n（1）创建部署应用：\r\n\r\n```yaml\r\napiVersion: apps\u002Fv1\r\nkind: Deployment\r\nmetadata:\r\n  name: hello-demo\r\nspec:\r\n  replicas: 2\r\n  selector:\r\n    matchLabels:\r\n      app: hello-demo\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: hello-demo\r\n    spec:\r\n      containers:\r\n      - name: tomcat\r\n        image: tomcat:8.5.0\r\n        ports:\r\n        - containerPort: 8080\r\n\r\n---\r\napiVersion: apps\u002Fv1\r\nkind: Deployment\r\nmetadata:\r\n  name: nginx-demo\r\nspec:\r\n  replicas: 2\r\n  selector:\r\n    matchLabels:\r\n      app: nginx-demo\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: nginx-demo\r\n    spec:\r\n      containers:\r\n      - name: nginx\r\n        image: nginx:1.18.0\r\n        ports:\r\n        - containerPort: 80\r\n```\r\n\r\n（2）创建service：\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  labels:\r\n    app: hello-demo\r\n  name: hello-demo\r\nspec:\r\n  selector:\r\n    app: hello-demo\r\n  ports:\r\n  - port: 8000\r\n    protocol: TCP\r\n    targetPort: 8080\r\n---\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  labels:\r\n    app: nginx-demo\r\n  name: nginx-demo\r\nspec:\r\n  selector:\r\n    app: nginx-demo\r\n  ports:\r\n  - port: 9000\r\n    protocol: TCP\r\n    targetPort: 80\r\n```\r\n\r\n（3）创建Ingress应用：\r\n\r\n```yaml\r\napiVersion: networking.k8s.io\u002Fv1\r\nkind: Ingress\r\nmetadata:\r\n  name: ingress-demo\r\nspec:\r\n  ingressClassName: nginx\r\n  rules:\r\n  - host: \"hello.mh.com\"       # 指定匹配的域名\r\n    http:\r\n      paths:\r\n      - pathType: Prefix\r\n        path: \"\u002F\"\r\n        backend:\r\n          service:             # 指定路由到对应service 的名称及端口等信息\r\n            name: hello-demo   # 指定转发的service名称\r\n            port:\r\n              number: 8000     # 指定匹配的service端口\r\n  - host: \"nginx.mh.com\"\r\n    http:\r\n      paths:\r\n      - pathType: Prefix\r\n        path: \"\u002F\"\r\n        backend:\r\n          service:\r\n            name: nginx-demo\r\n            port:\r\n              number: 9000\r\n```\r\n\r\n（4）本地电脑配置 hosts 解析\r\n\r\nwindow电脑配置hosts文件，路径为：`C:\\Windows\\System32\\drivers\\etc\\hosts`，添加域名解析：\r\n\r\n```shell\r\n# k8s集群内容，任意节点ip\r\n192.168.3.71  hello.mh.com\r\n192.168.3.71  nginx.mh.com\r\n```\r\n\r\n（5）访问：通过域名+端口号访问。\r\n\r\n```shell\r\n# 查看ingress 对外监听的端口，注意并不是所有安装的Ingress都是30509\r\nkubectl get service -n ingress-nginx\r\n# 查看创建的ingress\r\nkubectl get ingress\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fingress-service.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n域名访问如下：\r\n\r\n```shell\r\nhello.mh.com:30509\r\nnginx.mh.com:30509\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fingress-nginx.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fingress-tomcat.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n## 4.7\t存储\r\n\r\n​\t为集群中的 Pods 提供长期或临时存储的方法。\r\n\r\n### 4.7.1\t卷 Volume\r\n\r\n​\t容器中的文件在磁盘上是临时存放的，这给在容器中运行较重要的应用带来一些问题。 当容器崩溃或停止时会出现一个问题。此时容器状态未保存， 因此在容器生命周期内创建或修改的所有文件都将丢失。\r\n\r\n​\tKubernetes 支持很多类型的卷。 [Pod](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Fworkloads\u002Fpods\u002F) 可以同时使用任意数目的卷类型。 [临时卷](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Fstorage\u002Fephemeral-volumes\u002F)类型的生命周期与 Pod 相同， 但[持久卷](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Fstorage\u002Fpersistent-volumes\u002F)可以比 Pod 的存活期长。 当 Pod 不再存在时，Kubernetes 也会销毁临时卷；不过 Kubernetes 不会销毁持久卷。 对于给定 Pod 中任何类型的卷，在容器重启期间数据都不会丢失。\r\n\r\n​\t**卷的核心是一个目录**，其中可能存有数据，Pod 中的容器可以访问该目录中的数据。 所采用的特定的卷类型将决定该目录如何形成的、使用何种介质保存数据以及目录中存放的内容。\r\n\r\n​\t使用卷时, 在 `.spec.volumes` 字段中设置为 Pod 提供的卷，并在 `.spec.containers[*].volumeMounts` 字段中声明卷在容器中的挂载位置。\r\n\r\n​\t卷挂载在镜像中的[指定路径](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Fstorage\u002Fvolumes\u002F#using-subpath)下。 Pod 配置中的每个容器必须独立指定各个卷的挂载位置。\r\n\r\nKubernetes 支持以下[卷类型](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Fstorage\u002Fvolumes\u002F#volume-types)：\r\n\r\n- **configMap**\r\n\r\n- **local**\r\n\r\n- **nfs**\r\n\r\n- **persistentVolumeClaim**\r\n\r\n- **secret**\r\n\r\n  还有很多不常用，或已经废弃的卷类型，具体可以查看[官网类型](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Fstorage\u002Fvolumes\u002F#volume-types)。\r\n\r\n\r\n\r\n### 4.7.2\tnfs\r\n\r\n​\tNFS（[Network](https:\u002F\u002Fso.csdn.net\u002Fso\u002Fsearch?q=Network&spm=1001.2101.3001.7020) File System）网络文件系统，主要功能是通过网络让nfs集群间的机器可以彼此共享文件和目录，在任意集群节点修改共享文件或目录中的内容，其他节点都能自动同步变更。\r\n\r\n#### 4.7.2.1\t搭建nfs集群文件系统\r\n\r\n​\t在k8s所有集群节点上，都搭建nfs集群文件系统。\r\n\r\n（1）所有节点\r\n\r\n```shell\r\n#所有机器安装\r\nyum install -y nfs-utils\r\n```\r\n\r\n（2）主节点，这里是指nfs集群的主节点，并非k8s的主节点。当然可以选择跟k8s主节点一台机器作为nfs的主节点，也可以是其他节点。\r\n\r\n```shell\r\n# nfs主节点，将 \u002Fnfs\u002Fdata 暴露出去，以便其他节点共享这个目录\r\necho \"\u002Fnfs\u002Fdata\u002F *(insecure,rw,sync,no_root_squash)\" > \u002Fetc\u002Fexports\r\n\r\nmkdir -p \u002Fnfs\u002Fdata\r\nsystemctl enable rpcbind --now\r\nsystemctl enable nfs-server --now\r\n#配置生效\r\nexportfs -r\r\n# 检查配置是否生效\r\nexportfs\r\n```\r\n\r\n（3）从节点\r\n\r\n```shell\r\n# 查看主节点暴露的目录\r\nshowmount -e 192.168.3.71\r\n\r\n# 创建本机目录\r\nmkdir -p \u002Fnfs\u002Fdata\r\n# 挂载 nfs 服务器上的共享目录到本机路径 \u002Fnfs\u002Fdata\r\nmount -t nfs 192.168.3.71:\u002Fnfs\u002Fdata \u002Fnfs\u002Fdata\r\n\r\n# 写入一个测试文件，然后在其他节点看看是否自动同步\r\necho \"hello nfs server\" > \u002Fnfs\u002Fdata\u002Ftest.txt\r\n```\r\n\r\n\r\n\r\n#### 4.7.2.2\t原生方式数据挂载\r\n\r\n​\t原生挂载指直接挂载到nfs的指定目录下，前提必须在nfs下先创建好目录。\r\n\r\n```yaml\r\napiVersion: apps\u002Fv1\r\nkind: Deployment\r\nmetadata:\r\n  labels:\r\n    app: nginx-pv-demo\r\n  name: nginx-pv-demo\r\nspec:\r\n  replicas: 2\r\n  selector:\r\n    matchLabels:\r\n      app: nginx-pv-demo\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: nginx-pv-demo\r\n    spec:\r\n      containers:\r\n      - image: nginx:1.18.0\r\n        name: nginx\r\n        ports:\r\n        - containerPort: 80\r\n        \r\n        volumeMounts: # 指定容器内挂载的位置\r\n        - name: html\r\n          mountPath: \u002Fusr\u002Fshare\u002Fnginx\u002Fhtml\r\n      volumes:        # 指定Pod外挂载的位置，即宿主机的位置\r\n        - name: html  # 指定挂载卷的名称，和容器中volumeMounts.name对应\r\n          nfs:\r\n            server: 192.168.3.71       # 指定 nfs 集群内任一IP\r\n            path: \u002Fnfs\u002Fdata\u002Fnginx-pv   # 指定 nfs 共享目录里挂载的位置\r\n```\r\n\r\n​\t查看pod挂载信息：\r\n\r\n```shell\r\nkubectl describe deployment nginx-pv-demo\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fpod-nfs.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n### 4.7.3\t持久卷（PV）\r\n\r\n​\t**持久卷（PersistentVolume，PV）** 是外部存储系统中的一块存储空间，即**将应用需要持久化的数据保存到指定位置**。与 Volume 一样，PV 具有持久性，生命周期独立于 Pod。可以由管理员事先制备， 或者使用[存储类（Storage Class）](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Fstorage\u002Fstorage-classes\u002F)来动态制备。\r\n\r\n​\t**持久卷申明（Persistent Volume Claim，PVC）**是对 PV 的申请 (Claim），**申明需要使用的持久卷规格**。PVC 通常由普通用户创建和维护。需要为 Pod 分配存储资源时，用户可以创建一个PVC，指明存储资源的容量大小和访问模式 （比如只读）等信息，Kubernetes 会查找并提供满足条件的 PV。有了 PersistentVolumeClaim，用户只需要告诉 Kubernetes 需要什么样的存储资源，而不必关心真正的空间从哪里分配、如何访问等底层细节信息。\r\n\r\n​\tpv持久卷一般用来存放pod应用运行产生的数据。\r\n\r\n​\tPV 卷的制备有两种方式：静态制备或动态制备。\r\n\r\n（1）**创建PV模板**：\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: PersistentVolume\r\nmetadata:\r\n  name: nfs-pv\r\nspec:\r\n  capacity:\r\n    storage: 1Gi    # 指定pv容量大小\r\n  accessModes:      # 访问模式 \r\n    - ReadWriteMany\r\n  persistentVolumeReclaimPolicy: Retain\r\n  storageClassName: nfs\r\n  nfs:\r\n    path: \u002Fnfs\u002Fdata\u002Fdemo # nfs-server目录\r\n    server: 192.168.3.71 # nfs-server IP 地址\r\n```\r\n\r\n- **accessModes**: 支持的访问模式有3种：\r\n\r\n- - **ReadWriteOnce**：表示 PV 能以 readwrite 模式 mount 到单个节点\r\n\r\n  - - 这个PV只能被某个节点以读写方式挂载，意味着这个PV只能被一个Pod挂载到某个节点上，并且这个Pod可以对这个PV进行读写操作。如果尝试在其他节点上挂载这个PV，就会失败。\r\n\r\n  - **ReadOnlyMany** ：表示 PV 能以 read-only 模式 mount 到多个节点，\r\n\r\n  - - 这个PV能被多个节点以只读方式挂载，意味着这个PV可以被多个Pod挂载到多个节点上。\r\n\r\n  - **ReadWriteMany**：表示 PV 能以 read-write 模式 mount 到多个节点。\r\n\r\n  - - 这个PV能被多个节点以读写方式挂载，意味着这个PV可以被多个Pod挂载到多个节点上。\r\n\r\n- **persistentVolumeReclaimPolicy**：指定 PV 回收策略：\r\n\r\n- - **Retain（保留）**：当 PVC 对象被删除，绑定的PV卷仍然存在，因此数据也仍会存在，数据卷被视为\"已释放（released），该pv卷还不能用于其他pvc申领。\r\n  - **Delete（删除）**：当 PVC 被删除，自动删除 PV 和其数据。\r\n  - **Recycle（回收）**：当 PVC 被删除，如果下层的卷插件支持，会在卷上执行一些基本的擦除 （`rm -rf \u002Fthevolume\u002F*`）操作，之后允许该卷用于新的 PVC 申领。\r\n\r\n​\t值得注意的是，persistentVolumeReclaimPolicy只适用于一些类型的 PV，如 NFS、HostPath、iSCSI 等。对于一些云平台提供的存储，如 AWS EBS 和 Azure Disk，由于底层提供商会自动处理 PV 的回收问题，因此该属性不适用。\r\n\r\n- **storageClassName**: 指定 PV 的class 为 nfs。相当于为 PV 设置了一个分类，PVC可以指定 class 申请相应 class 的 PV。\r\n\r\n\r\n\r\n（2）**创建PVC模板：**\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: PersistentVolumeClaim\r\nmetadata:\r\n  name: nfs-pvc\r\nspec:\r\n  accessModes:          # 访问模式，跟PV支持的访问模式一样，有3种\r\n    - ReadWriteMany\r\n  resources:\r\n    requests:\r\n      storage: 1Gi      # 申名要使用的空间大小\r\n  storageClassName: nfs # 通过名字进行选择，跟PV的storageClassName对应\r\n  #selector:  通过标签形式选择，跟PV的标签对应\r\n  #  matchLabels:\r\n  #    pv-name: nfs-pv\r\n```\r\n\r\n\r\n\r\n#### 4.7.3.1\t创建PV\r\n\r\n```shell\r\n# 创建命令\r\nkubectl apply -f yaml名称\r\n# 查看pv命令\r\nkubectl get persistentVolume\r\n# 查看pv命令简写\r\nkubectl get pv\r\n# 查看详细信息\r\nkubectl describe pv pv名称\r\n```\r\n\r\npv创建又有静态制备和动态制备之分：\r\n\r\n- 静态制备：手动一个一个的创建pv，先创建好了pv，才能创建pvc；\r\n- 动态制备：创建pvc时，自动去创建满足要求的pv，不用手动提前创建pv。\r\n\r\n\r\n\r\n**（1）静态制备**\r\n\r\n```shell\r\n#nfs主节点上创建3个目录\r\nmkdir -p \u002Fnfs\u002Fdata\u002Fdemo\u002F01\r\nmkdir -p \u002Fnfs\u002Fdata\u002Fdemo\u002F02\r\nmkdir -p \u002Fnfs\u002Fdata\u002Fdemo\u002F03\r\n```\r\n\r\n创建PV：\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: PersistentVolume\r\nmetadata:\r\n  name: pv01-demo-10m\r\nspec:\r\n  capacity:\r\n    storage: 10M   #指定容量大小\r\n  accessModes:     # 访问模式\r\n    - ReadWriteMany  # 多个pod 可读写操作\r\n  storageClassName: nfs  # 指定 PV 的class，相当于为PV设置一个分类名称\r\n  persistentVolumeReclaimPolicy: Delete # 在 PVC 被删除后，自动删除 PV 和其数据\r\n  nfs:\r\n    path: \u002Fnfs\u002Fdata\u002Fdemo\u002F01   # nfs-server目录名称\r\n    server: 192.168.3.71      # nfs-server IP 地址\r\n---\r\napiVersion: v1\r\nkind: PersistentVolume\r\nmetadata:\r\n  name: pv02-demo-1gi\r\nspec:\r\n  capacity:\r\n    storage: 1Gi\r\n  accessModes:\r\n    - ReadWriteMany\r\n  storageClassName: nfs\r\n  persistentVolumeReclaimPolicy: Delete # 在 PVC 被删除后，自动删除 PV 和其数据\r\n  nfs:\r\n    path: \u002Fnfs\u002Fdata\u002Fdemo\u002F02  \r\n    server: 192.168.3.71\r\n---\r\napiVersion: v1\r\nkind: PersistentVolume\r\nmetadata:\r\n  name: pv03-demo-3gi\r\nspec:\r\n  capacity:\r\n    storage: 3Gi\r\n  accessModes:\r\n    - ReadWriteMany\r\n  storageClassName: nfs\r\n  persistentVolumeReclaimPolicy: Delete # 在 PVC 被删除后，自动删除 PV 和其数据\r\n  nfs:\r\n    path: \u002Fnfs\u002Fdata\u002Fdemo\u002F03\r\n    server: 192.168.3.71\r\n```\r\n\r\n查看pv信息：\r\n\r\n```shell\r\nkubectl get persistentVolume\r\n# 简写\r\nkubectl get pv\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fpv.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n​\t可以看到刚创建的pv持久卷是处于`Available`（可用）状态。\r\n\r\n每个持久卷会处于以下阶段（Phase）之一：\r\n\r\n- `Available`：卷是一个空闲资源，尚未绑定到任何pvc申领；\r\n\r\n- `Bound`：该卷已经绑定到某pvc申领；\r\n\r\n- `Released`：所绑定的pvc申领已被删除，但是关联存储资源尚未被集群回收（删掉pv路径下的数据才恢复到可用状态）；\r\n\r\n- `Failed`：卷的自动回收操作失败。\r\n\r\n  \r\n\r\n**（2）动态制备**\r\n\r\n​\t查看`4.7.3.4 动态创建pv配置`章。\r\n\r\n\r\n\r\n#### 4.7.3.2\tPVC创建\r\n\r\n```yaml\r\nkind: PersistentVolumeClaim\r\napiVersion: v1\r\nmetadata:\r\n  name: nginx-pvc\r\nspec:\r\n  accessModes: # 指定模式\r\n    - ReadWriteMany\r\n  resources:\r\n    requests:\r\n      storage: 200Mi  # 申明的容量大小\r\n  storageClassName: nfs # 跟PV的storageClassName对应\r\n```\r\n\r\n​\t查看创建的pvc，pvc会自动去查找`storageClassName`为nfs的pv，且能够满足申明容量大小的pv。\r\n\r\n​\t当前申明容量为200M，而上面创建`storageClassName`为nfs的pv，pv02-demo-1gi刚好在这个范围内，能够满足。\r\n\r\n​\t一个pv只能被一个pvc绑定，pvc只能申领`Available`状态的pv。\r\n\r\n```shell\r\nkubectl get persistentVolumeClaim\r\n# 简写\r\nkubectl get pvc\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fpvc.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n#### 4.7.3.3\t创建Pod绑定PVC\r\n\r\n```yaml\r\napiVersion: apps\u002Fv1\r\nkind: Deployment\r\nmetadata:\r\n  labels:\r\n    app: nginx-deploy-pvc\r\n  name: nginx-deploy-pvc\r\nspec:\r\n  replicas: 2\r\n  selector:\r\n    matchLabels:\r\n      app: nginx-deploy-pvc\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: nginx-deploy-pvc\r\n    spec:\r\n      containers:\r\n      - image: nginx:1.18.0\r\n        name: nginx\r\n        volumeMounts:\r\n        - name: html\r\n          mountPath: \u002Fusr\u002Fshare\u002Fnginx\u002Fhtml\r\n      volumes:\r\n        - name: html\r\n          persistentVolumeClaim:  # 指定要绑定的pvc\r\n            claimName: nginx-pvc  # pvc名称\r\n```\r\n\r\n​\t有了 PersistentVolumeClaim，我们只需要告诉 Kubernetes 需要什么样的存储资源，而不必关心真正的空间路径、分配、如何访问等底层细节信息。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fpod-pvc.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n#### 4.7.3.4\t动态创建pv配置\r\n\r\n​\t正常的情况，如果使用nfs的网络共享存储，需要手动的创建pv，然后创建pvc和pv进行绑定。最后在应用程序的pod中来挂载使用这个pvc，达到挂载外部共享存储的目的。\r\n\r\n​\t**provisoner卷插件**：k8s本身支持的动态pv创建不包括nfs，需要声明和安装一个外部插件provisioner（存储分配器），可以动态创建pv，根据pvc请求自动绑定和创建pv（根据定义的pv属性创建pv）。\r\n\r\n​\t**StorageClass**：定义pv属性（存储类型、大小、回收策略等）。\r\n\r\n​\t基本的工作原理就是，provisioner卷工具持续的监控api server，查看创建pvc的请求，如果发现请求的pvc的存储类stroageclass,存储类的提供者和自己的是一致的，就会根据创建的pvc，动态的在nfs中创建pv。\r\n\r\n \r\n\r\n（1）**创建授权账户信息**\r\n\r\n​\t因为nfs-client-provisoner工具是监听k8s api server，因此需要创建授权账户信息，才能进行监控。通过以下yaml文件，创建需要的service account。\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: ServiceAccount\r\nmetadata:\r\n  name: nfs-client-provisioner\r\n  # replace with namespace where provisioner is deployed\r\n  namespace: default\r\n---\r\nkind: ClusterRole\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nmetadata:\r\n  name: nfs-client-provisioner-runner\r\nrules:\r\n  - apiGroups: [\"\"]\r\n    resources: [\"persistentvolumes\"]\r\n    verbs: [\"get\", \"list\", \"watch\", \"create\", \"delete\"]\r\n  - apiGroups: [\"\"]\r\n    resources: [\"persistentvolumeclaims\"]\r\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\r\n  - apiGroups: [\"storage.k8s.io\"]\r\n    resources: [\"storageclasses\"]\r\n    verbs: [\"get\", \"list\", \"watch\"]\r\n  - apiGroups: [\"\"]\r\n    resources: [\"events\"]\r\n    verbs: [\"create\", \"update\", \"patch\"]\r\n---\r\nkind: ClusterRoleBinding\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nmetadata:\r\n  name: run-nfs-client-provisioner\r\nsubjects:\r\n  - kind: ServiceAccount\r\n    name: nfs-client-provisioner\r\n    # replace with namespace where provisioner is deployed\r\n    namespace: default\r\nroleRef:\r\n  kind: ClusterRole\r\n  name: nfs-client-provisioner-runner\r\n  apiGroup: rbac.authorization.k8s.io\r\n---\r\nkind: Role\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nmetadata:\r\n  name: leader-locking-nfs-client-provisioner\r\n  # replace with namespace where provisioner is deployed\r\n  namespace: default\r\nrules:\r\n  - apiGroups: [\"\"]\r\n    resources: [\"endpoints\"]\r\n    verbs: [\"get\", \"list\", \"watch\", \"create\", \"update\", \"patch\"]\r\n---\r\nkind: RoleBinding\r\napiVersion: rbac.authorization.k8s.io\u002Fv1\r\nmetadata:\r\n  name: leader-locking-nfs-client-provisioner\r\n  # replace with namespace where provisioner is deployed\r\n  namespace: default\r\nsubjects:\r\n  - kind: ServiceAccount\r\n    name: nfs-client-provisioner\r\n    # replace with namespace where provisioner is deployed\r\n    namespace: default\r\nroleRef:\r\n  kind: Role\r\n  name: leader-locking-nfs-client-provisioner\r\n  apiGroup: rbac.authorization.k8s.io\r\n```\r\n\r\n​\t将以上的文件内容，放在rbac.yaml文件中，这里面的对象，是放在默认的命名空间中的。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fnfs-rbac.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n（2）**部署nfs-client-provisioner服务**\r\n\r\n​\t使用下面的yaml配置文件，部署nfs-client-provisioner应用\r\n\r\n```yaml\r\nkind: Deployment\r\napiVersion: apps\u002Fv1\r\nmetadata:\r\n  name: nfs-client-provisioner\r\nspec:\r\n  replicas: 1\r\n  selector:\r\n    matchLabels:\r\n      app: nfs-client-provisioner\r\n  strategy:\r\n    type: Recreate\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: nfs-client-provisioner\r\n    spec:\r\n      serviceAccountName: nfs-client-provisioner\r\n      containers:\r\n        - name: nfs-client-provisioner\r\n          image: quay.io\u002Fvbouchaud\u002Fnfs-client-provisioner:3.2 # 修改为本地镜像地址\r\n          volumeMounts:\r\n            - name: nfs-client-root\r\n              mountPath: \u002Fpersistentvolumes\r\n          env:\r\n            - name: PROVISIONER_NAME\r\n              value: fuseim.pri\u002Fifs  # provisioner的名字，可以修改\r\n            - name: NFS_SERVER\r\n              value: 192.168.3.71    # nfs服务器的地址\r\n            - name: NFS_PATH\r\n              value: \u002Fnfs\u002Fdata       # nfs服务器共享地址\r\n      volumes:\r\n        - name: nfs-client-root\r\n          nfs:\r\n            server: 192.168.3.71   # nfs服务器的地址\r\n            path: \u002Fnfs\u002Fdata   # nfs服务器共享地址\r\n```\r\n\r\n​\t将上面的内容，放在nfs_client_provisioner.yaml文件中\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fnfs-client-provisioner.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n（3）**创建storageclass**\r\n\r\n​\t定义pv属性（存储类型、大小、回收策略等）。动态存储的关联关系，都是通过stroageclass来完成的。自动创建pv，默认策略是Delete。\r\n\r\n```yaml\r\napiVersion: storage.k8s.io\u002Fv1\r\nkind: StorageClass\r\nmetadata:\r\n  name: managed-nfs-storage\r\nprovisioner: fuseim.pri\u002Fifs # or choose another name, must match deployment's env PROVISIONER_NAME'\r\nparameters:\r\n  archiveOnDelete: \"false\" # When set to \"false\" your PVs will not be archived\r\n                           # by the provisioner upon deletion of the PVC.\r\n```\r\n\r\n​\t将上面的内容，放在nfs-storage-class.yaml文件中。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fnfs-storage-class.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n（4）**创建pvc**\r\n\r\n​\tstorageclass创建好了之后，创建pvc，pvc会自动去申请nfs的存储，自动创建pv。\r\n\r\n```yaml\r\nkind: PersistentVolumeClaim\r\napiVersion: v1\r\nmetadata:\r\n  name: pvc-test\r\n  annotations: # 指定 storage，自动创建pv\r\n    volume.beta.kubernetes.io\u002Fstorage-class: \"managed-nfs-storage\"\r\nspec:\r\n  accessModes:\r\n    - ReadWriteMany\r\n  resources:\r\n    requests:\r\n      storage: 1Mi\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fnfs-pvc-test.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n​\t可以看到自动创建了pv卷。\r\n\r\n​\tOK，到这里nfs-client-provisioner工具部署成功。\r\n\r\n​\t部署完成nfs-client-provisioner之后，创建好pvc，就可以动态的创建nfs的pv了，不需要手动的进行创建。\r\n\r\n\r\n\r\n### 4.7.4\tConfigMap\r\n\r\n#### 4.7.4.1\tConfigMap\r\n\r\n​\t在 Kubernetes 中，**ConfigMap 是一种用于存储非敏感信息的 Kubernetes 对象**。它用于存储配置数据，如键值对、整个配置文件或 JSON 数据等。ConfigMap 通常用于容器镜像中的配置文件、命令行参数和环境变量等，ConfigMap的数据存储到k8s etcd中。\r\n\r\n​\tnfs一般用来存放pod应用运行产生的数据，configMap一般用来存放pod应用的配置文件。\r\n\r\n**ConfigMap** 可以通过三种方式进行配置数据的注入：\r\n\r\n- 环境变量注入：将配置数据注入到 Pod 中的容器环境变量中。\r\n- 配置文件注入：将配置数据注入到 Pod 中的容器文件系统中，容器可以读取这些文件。\r\n- 命令行参数注入：将配置数据注入到容器的命令行参数中。\r\n\r\n**优点**\r\n\r\n- 避免了硬编码，将配置数据与应用代码分离。\r\n- 便于维护和更新，可以单独修改 ConfigMap 而不需要重新构建镜像。\r\n- 可以通过多种方式注入配置数据，更加灵活。\r\n- 可以通过 Kubernetes 的自动化机制对 ConfigMap 进行版本控制和回滚。\r\n- ConfigMap 可以被多个 Pod 共享，减少了配置数据的重复存储。\r\n\r\n> ConfigMap 在设计上不是用来保存大量数据的。在 ConfigMap 中保存的数据不可超过 1 MiB。如果你需要保存超出此尺寸限制的数据，你可能希望考虑挂载存储卷 或者使用独立的数据库或者文件服务。\r\n\r\n**基础命令：**\r\n\r\n```shell\r\n# 查看configMap\r\nkubectl get configmap\r\n# 简写\r\nkubectl get cm\r\n\r\n#查看详细信息及内容\r\nkubectl describe cm cm名称\r\n# 删除\r\nkubectl delete cm cm名称\r\n```\r\n\r\n**命令行方式：**\r\n\r\n```shell\r\n# key-value方式\r\nkubectl create cm my-config --from-literal=key1=hello --from-literal=mh=hhhhh\r\n\r\n# 通过文件创建\r\necho 'admin' > .\u002Fusername.txt\r\necho '123456' > .\u002Fpassword.txt\r\nkubectl create cm my-config-file --from-file=.\u002Fusername.txt --from-file=.\u002Fpassword.txt\r\n\r\n# 通过文件夹创建,test下所有的文件内容作为键值对\r\nkubectl create cm my-config-p --from-file=test\r\n\r\n# 通过环境变量创建\r\n# 可以将环境变量的值转换为configmap。例如，使用以下命令将当前环境变量的值转换为configmap：\r\nkubectl create configmap my-config --from-env-file=\u003Cenv>\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fconfigmap1.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fconfigmap2.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fconfigmap3.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n**yaml方式：**\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: ConfigMap\r\nmetadata:\r\n  name: my-config\r\ndata: # 配置内容\r\n  key1: value1\r\n  mh: hello\r\n\r\n---\r\napiVersion: v1\r\nkind: ConfigMap\r\nmetadata:\r\n  name: app-config\r\ndata:\r\n  application.yml: |\r\n    name: mh\r\n```\r\n\r\n\r\n\r\n#### 4.7.4.2\tConfigMap 和 Pod\r\n\r\n​\t你可以写一个引用 ConfigMap 的 Pod 的 `spec`，并根据 ConfigMap 中的数据在该 Pod 中配置容器。这个 Pod 和 ConfigMap 必须要在同一个 [名字空间](https:\u002F\u002Fkubernetes.io\u002Fzh-cn\u002Fdocs\u002Fconcepts\u002Foverview\u002Fworking-with-objects\u002Fnamespaces\u002F) 中。\r\n\r\n（1）**官网示例**\r\n\r\n​\t这是一个 ConfigMap 的示例，它的一些键只有一个值，其他键的值看起来像是 配置的片段格式：\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: ConfigMap\r\nmetadata:\r\n  name: game-demo\r\ndata:\r\n  # 类属性键；每一个键都映射到一个简单的值\r\n  player_initial_lives: \"3\"\r\n  ui_properties_file_name: \"user-interface.properties\"\r\n\r\n  # 类文件键\r\n  game.properties: |\r\n    enemy.types=aliens,monsters\r\n    player.maximum-lives=5    \r\n  user-interface.properties: |\r\n    color.good=purple\r\n    color.bad=yellow\r\n    allow.textmode=true \r\n```\r\n\r\n​\t下面是一个 Pod 的示例，它通过使用 `game-demo` 中的值来配置一个 Pod：\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Pod\r\nmetadata:\r\n  name: configmap-demo-pod\r\nspec:\r\n  containers:\r\n    - name: demo\r\n      image: alpine\r\n      command: [\"sleep\", \"3600\"]\r\n      env:\r\n        # 定义环境变量\r\n        - name: PLAYER_INITIAL_LIVES # 请注意这里和 ConfigMap 中的键名是不一样的\r\n          valueFrom:\r\n            configMapKeyRef:\r\n              name: game-demo           # 这个值来自 ConfigMap\r\n              key: player_initial_lives # 需要取值的键\r\n        - name: UI_PROPERTIES_FILE_NAME\r\n          valueFrom:\r\n            configMapKeyRef:\r\n              name: game-demo\r\n              key: ui_properties_file_name\r\n      volumeMounts:\r\n      - name: config\r\n        mountPath: \"\u002Fconfig\"\r\n        readOnly: true\r\n  volumes:\r\n  # 你可以在 Pod 级别设置卷，然后将其挂载到 Pod 内的容器中\r\n  - name: config\r\n    configMap:\r\n      # 提供你想要挂载的 ConfigMap 的名字\r\n      name: game-demo\r\n      # 来自 ConfigMap 的一组键，将被创建为文件\r\n      items:\r\n      - key: \"game.properties\"\r\n        path: \"game.properties\"\r\n      - key: \"user-interface.properties\"\r\n        path: \"user-interface.properties\"\r\n```\r\n\r\n\r\n\r\n（2）**Redis 安装示例**\r\n\r\n**docker安装：**\r\n\r\n```shell\r\n# docker安装redis \r\ndocker run -v \u002Fdata\u002Fredis\u002Fredis.conf:\u002Fetc\u002Fredis\u002Fredis.conf \\\r\n-v \u002Fdata\u002Fredis\u002Fdata:\u002Fdata \\\r\n-d --name my-redis \\\r\n-p 6379:6379 \\\r\nredis:7.2.5  redis-server \u002Fetc\u002Fredis\u002Fredis.conf  # 容器启动时加载配置文件的位置\r\n```\r\n\r\n**创建ConfigMap：**\r\n\r\n命令行方式：\r\n\r\n```shell\r\n#创建redis.conf，内容如下：\r\nappendonly yes\r\nrequirepass root\r\n\r\n# 创建配置，redis保存到k8s的etcd\r\nkubectl create cm redis-conf --from-file=redis.conf\r\n```\r\n\r\nyaml方式：\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: ConfigMap\r\nmetadata:\r\n  name: redis-conf\r\ndata:\r\n  redis.conf: |\r\n    appendonly yes  \r\n    requirepass root\r\n```\r\n\r\n**创建Pod：**\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Pod\r\nmetadata:\r\n  name: redis\r\nspec:\r\n  containers:\r\n  - name: redis\r\n    image: redis:7.2.5\r\n    command:  # 容器启动运行命令\r\n      - redis-server\r\n      - \"\u002Fredis-master\u002Fredis.conf\" # 启动时加载配置文件的位置，容器内部路径\r\n    ports:\r\n    - containerPort: 6379\r\n    volumeMounts:  # 挂载容器内部的路径\r\n    - mountPath: \u002Fdata\r\n      name: data\r\n    - mountPath: \u002Fredis-master\r\n      name: config\r\n  volumes:\r\n    - name: data  # 挂载数据\r\n      emptyDir: {}\r\n    - name: config  # 挂载configMap配置文件\r\n      configMap:\r\n        name: redis-conf  # 对应创建ConfigMap时的metadata.name名称\r\n        items:\r\n        - key: redis.conf # 配置文件中的key名称\r\n          path: redis.conf\r\n```\r\n\r\n\r\n\r\n**创建deployment**\r\n\r\n```yaml\r\napiVersion: apps\u002Fv1\r\nkind: Deployment\r\nmetadata:\r\n  name: redis-demo\r\nspec:\r\n  replicas: 1\r\n  selector:\r\n    matchLabels:\r\n      app: redis-demo\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: redis-demo\r\n    spec:\r\n      containers:\r\n      - name: redis\r\n        image: redis:7.2.5\r\n        command:  # 容器启动运行命令\r\n          - redis-server\r\n          - \"\u002Fredis-master\u002Fredis.conf\" # 启动时加载配置文件的位置，容器内部路径\r\n        ports:\r\n        - containerPort: 6379\r\n        volumeMounts:  # 挂载容器内部的路径\r\n        - mountPath: \u002Fdata\r\n          name: data\r\n        - mountPath: \u002Fredis-master\r\n          name: config\r\n      volumes:\r\n        - name: data  # 挂载数据\r\n          emptyDir: {}\r\n        - name: config  # 挂载configMap配置文件\r\n          configMap:\r\n            name: redis-conf  # 对应创建ConfigMap时的metadata.name名称\r\n            items:\r\n            - key: redis.conf # 配置文件中的key名称\r\n              path: redis.conf\r\n```\r\n\r\n\r\n\r\n**检查默认配置**\r\n\r\n```shell\r\nkubectl exec -it redis -- redis-cli\r\n\r\n127.0.0.1:6379> CONFIG GET appendonly\r\n127.0.0.1:6379> CONFIG GET requirepass\r\n```\r\n\r\n\r\n\r\n### 4.7.5\tSecret\r\n\r\n​\tSecret 对象类型用来保存敏感信息，例如密码、OAuth 令牌和 SSH 密钥。 将这些信息放在 secret 中比放在 [Pod](https:\u002F\u002Fkubernetes.io\u002Fdocs\u002Fconcepts\u002Fworkloads\u002Fpods\u002Fpod-overview\u002F) 的定义或者 [容器镜像](https:\u002F\u002Fkubernetes.io\u002Fzh\u002Fdocs\u002Freference\u002Fglossary\u002F?all=true#term-image) 中来说更加安全和灵活。\r\n\r\n​\t在 Kubernetes 中，Secrets 通常被用于以下场景：\r\n\r\n- 作为卷挂载到 Pod 中，用于存储证书、密钥等敏感文件\r\n- 在 Pod 中使用环境变量，用于存储用户名和密码等敏感信息\r\n- 用于存储 Docker 镜像仓库的登录信息\r\n- 用于存储外部服务的 API 密钥\r\n\r\n\r\n\r\n**示例**：\r\n\r\n​\t创建secret，存储docker登录账户密码，k8s部署应用时引用该secret认证，来拉取镜像：\r\n\r\n```shell\r\nkubectl create secret docker-registry mh-docker \\\r\n--docker-username=mh \\\r\n--docker-password=mh123456 \\\r\n--docker-email=849120289@qq.com\r\n\r\n#命令格式\r\nkubectl create secret docker-registry regcred \\\r\n  --docker-server=\u003C你的镜像仓库服务器> \\\r\n  --docker-username=\u003C你的用户名> \\\r\n  --docker-password=\u003C你的密码> \\\r\n  --docker-email=\u003C你的邮箱地址>\r\n\r\n# docker-registry : 创建一个给docker 注册器使用的secret\r\n# generic ： 从本地file，directory 或者 literal value 创建一个secret\r\n# tls ：创建一个TLS secret\r\n\r\n```\r\n\r\nk8s部署时引用：\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Pod\r\nmetadata:\r\n  name: private-nginx\r\nspec:\r\n  containers:\r\n  - name: private-nginx\r\n    image: leifengyang\u002Fguignginx:v1.0\r\n  imagePullSecrets:\r\n  - name: mh-docker\r\n```\r\n\r\n\r\n\r\n## 4.8\tStatefulSet\r\n\r\n​\t**StatefulSet**是为了解决有状态应用的问题，**Deployment**是为无状态应用设计。\r\n\r\n- 无状态应用：网络可能会变（IP地址）、存储可能会变（卷）、顺序可能会变（启动顺序）。应用场景：应用代码，微服务等；\r\n- 有状态应用：网络不变、存储不变、顺序不变。应用场景：中间件，数据库等，如：MySQL集群、Zookeeper集群、Redis集群、Kafka集群、Nacos集群等。\r\n\r\n​\t其实，`状态`就是数据，这样看来，我们只需要结合Deployment和PersistentVolume，就可以解决有状态应用的部署问题了，即只要解决了应用的[数据持久化](https:\u002F\u002Fso.csdn.net\u002Fso\u002Fsearch?q=数据持久化&spm=1001.2101.3001.7020)问题就行了，但k8s的眼光则显得更加的`高瞻远瞩`，它认为应用的状态不仅仅是数据持久化，还应该包括启动顺序`(服务之间存在依赖关系)`，网络标识`(外部通过唯一标识访问POD)`等，如果将这些内容也`考虑到状态的范畴的话`，不管是deployment还是DaemonSet都会显得力不从心,基于此，才会有StatefulSet 。\r\n\r\n**StatefulSet**特点：\r\n\r\n- 稳定的持久化存储，即pod重新调度后还是能访问到相同的pv存储卷，且一个pod（副本）一份pv卷，多少个副本就有多少个pv卷，不像Deoployment多个副本共享一个pv卷；\r\n\r\n- 稳定的网络访问，pod是没有分配IP的，pod的名称是：sts的`metadata.name`名称 + 后缀（序号0—N），删除pod或重新部署后，pod的名称不变，通过域名访问，访问方式：\r\n  - 域名：`pod名称.service名称.命名空间.svc.cluster.local`；\r\n  - 或：`pod名称.service名称.命名空间`\r\n  - 开启service负载均衡，则可：`service名称` 或`service名称.命名空间.svc`\r\n- 有序部署，有序扩展，即启动pod是有顺序的，在部署或扩展时根据顺序依次进行（0-N），第一个pod部署且启动成功（Runing）后，才会部署第2个pod，如此类推。\r\n\r\n- 有序收缩，有序删除，从后往前（N-1）一个个删除。\r\n\r\n\r\n\r\n（1）创建StatefulSet\r\n\r\n```yaml\r\napiVersion: apps\u002Fv1 # StatefulSet 资源的版本\r\nkind: StatefulSet  #  StatefulSet 类型的资源\r\nmetadata:    # 元数据\r\n  name: web  # StatefulSet的名字\r\nspec:\r\n  serviceName: nginx-svc   # 使用哪个service服务来管理dns\r\n  podManagementPolicy: OrderedReady # 配置有序启动，默认值\r\n  replicas: 2   # 期望副本数\r\n  selector:   # 选择器\r\n    matchLabels: # 按照标签匹配\r\n      app: web   # 选择器名字\r\n  template:     # pod 的模板\r\n    metadata:    # 元数据\r\n      labels:    # pod的标签\r\n        app: web  # 标签值是：app=nginx\r\n    spec:         # pod的期望信息\r\n      containers:   # pod的容器信息\r\n      - name: nginx   # pod的名字\r\n        image: nginx:1.27.0   # 容器镜像信息\r\n        ports:             # 端口\r\n        - containerPort: 80   # 容器的端口\r\n```\r\n\r\npod的管理策略：\r\n\r\n- OrderedReady（有序启动，默认值）：也就是pod的创建是按照顺序来的，第一个pod启动完成后，第二个pod才会启动，如果第一个报错，往后的pod都不会启动。启动后，我们看到的后缀就是sts顺序。\r\n\r\n- Parallet（并发启动）：pod的创建没有顺序。\r\n\r\n\r\n\r\n（2）创建Service\r\n\r\n​\t部署无状态`StatefulSet`应用时，pod是没有分配IP的，也就是部署后pod是无法访问的，因此需要搭配`service`来使用，才能访问pod。\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  name: nginx-svc  # StatefulSet中的spec.serviceName 一致\r\nspec:\r\n  selector:\r\n    app: nginx\r\n  ports:\r\n  - port: 80\r\n  clusterIP: None\r\n```\r\n\r\n​\t部署`service`时，如果StatefulSet的pod不需要负载均衡，仅用于访问pod，可以设置clusterIP为`None`，以免浪费资源。\r\n\r\n​\tService也可以设置为clusterIP，或者NodePort。\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  name: nginx-svc\r\nspec:\r\n  selector:\r\n    app: nginx\r\n  ports:\r\n  - port: 80        # 集群内的端口\r\n    protocol: TCP\r\n    targetPort: 80  # 指定pod中服务的端口（即pod中nginx的监听端口）\r\n    nodePort: 30001 # 暴露宿主机（节点）端口\r\n  type: NodePort\r\n```\r\n\r\n\r\n\r\n（3）访问域名\r\n\r\n​\tservice的域名访问，都只支持在集群之间的pod里。宿主机上是不支持域名访问的。\r\n\r\n```shell\r\n# 进入集群中任意pod\r\nkubectl exec -it pod名称 bin\u002Fbash\r\n\r\n# clusterIP为None，访问域名：pod名称.service名称.default.svc.cluster.local\r\ncurl web-0.nginx-svc.default.svc.cluster.local\r\n# 简写：pod名称.service名称\r\ncurl web-0.nginx-svc\r\n\r\n# 不指定clusterIP为None时，拥有集群IP，自动负载均衡\r\n# 访问域名：service名称.default.svc.cluster.local\r\ncurl nginx-svc.default.svc.cluster.local\r\n# 简写\r\ncurl nginx-svc.default.svc\r\ncurl nginx-svc\r\n```\r\n\r\n\r\n\r\n​\tsts数据持久化，每一个pod（副本）都会单独挂载一个pv卷，并不像Deployment。\r\n\r\n```yaml\r\napiVersion: apps\u002Fv1\r\nkind: StatefulSet\r\nmetadata:\r\n  name: nginx-pv-sts\r\nspec:\r\n  serviceName: nginx-pv-svc\r\n  replicas: 2\r\n  selector:\r\n    matchLabels:\r\n      app: nginx-pv-sts\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: nginx-pv-sts\r\n    spec:\r\n      containers:\r\n      - image: nginx:1.27.0\r\n        name: nginx\r\n        ports:\r\n        - containerPort: 80\r\n \r\n        volumeMounts:\r\n        - name: nginx-10m-pvc\r\n          mountPath: \u002Fusr\u002Fshare\u002Fnginx\u002Fhtml\r\n  volumeClaimTemplates:\r\n  - metadata:\r\n      name: nginx-10m-pvc\r\n    spec:\r\n      storageClassName: managed-nfs-storage\r\n      accessModes:\r\n        - ReadWriteMany\r\n      resources:\r\n        requests:\r\n          storage: 10Mi\r\n---\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  name: nginx-pv-svc  # StatefulSet中的spec.serviceName 一致\r\nspec:\r\n  selector:\r\n    app: nginx-pv-sts # 指定 sts名称\r\n  ports:\r\n  - port: 80\r\n  clusterIP: None\r\n```\r\n\r\n\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fk8s入门操作教程\u002Fsts-pv.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n​\tStatefulSet缩扩容命令和Deployment一样，只是sts是按正序（0—N）扩容，倒序（N—0）缩容。\r\n\r\n\r\n\r\n# 5\tNacos集群部署\r\n\r\n​\tnacos集群部署不能使用内置数据库，必须使用mysql或其他数据库，以便存放nacos配置信息。\r\n\r\n集群部署需要配置：\r\n\r\n- `cluster.conf`：配置nacos集群节点地址；\r\n- `application.properties`：nacos配置信息，数据库连接信息等。\r\n\r\n\r\n\r\n## 5.1\tNacos集群 — MySQL\r\n\r\n### 5.1.1\t安装MySQL\r\n\r\n​\t这里直接使用nacos官方的mysql数据库镜像，省去了手动创建nacos数据库表的麻烦，当然也可以另外部署mysql数据库。\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: ReplicationController\r\nmetadata:\r\n  name: mysql\r\n  namespace: test\r\n  labels:\r\n    name: mysql\r\nspec:\r\n  replicas: 1\r\n  selector:\r\n    name: mysql\r\n  template:\r\n    metadata:\r\n      labels:\r\n        name: mysql\r\n    spec:\r\n      containers:\r\n      - name: mysql\r\n        image: nacos\u002Fnacos-mysql:5.7\r\n        ports:\r\n        - containerPort: 3306\r\n        volumeMounts:\r\n        - name: mysql-data\r\n          mountPath: \u002Fvar\u002Flib\u002Fmysql\r\n        env:\r\n        - name: MYSQL_ROOT_PASSWORD\r\n          value: \"root\"\r\n        - name: MYSQL_DATABASE\r\n          value: \"nacos_devtest\"\r\n        - name: MYSQL_USER\r\n          value: \"nacos\"\r\n        - name: MYSQL_PASSWORD\r\n          value: \"nacos\"\r\n      volumes:\r\n      - name: mysql-data\r\n        nfs:\r\n          server: 192.168.3.71\r\n          path: \u002Fnfs\u002Fdata\u002Fmysql\r\n---\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  name: mysql\r\n  namespace: test\r\n  labels:\r\n    name: mysql\r\nspec:\r\n  ports:\r\n  - port: 3306\r\n    targetPort: 3306\r\n  selector:\r\n    name: mysql\r\n```\r\n\r\n\r\n\r\n`mysql-schema.sql`建表语句：\r\n\r\n```sql\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = config_info                  *\u002F\r\n\u002F******************************************\u002F\r\nCREATE TABLE `config_info` (\r\n  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',\r\n  `data_id` varchar(255) NOT NULL COMMENT 'data_id',\r\n  `group_id` varchar(128) DEFAULT NULL COMMENT 'group_id',\r\n  `content` longtext NOT NULL COMMENT 'content',\r\n  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',\r\n  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\r\n  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',\r\n  `src_user` text COMMENT 'source user',\r\n  `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',\r\n  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',\r\n  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',\r\n  `c_desc` varchar(256) DEFAULT NULL COMMENT 'configuration description',\r\n  `c_use` varchar(64) DEFAULT NULL COMMENT 'configuration usage',\r\n  `effect` varchar(64) DEFAULT NULL COMMENT '配置生效的描述',\r\n  `type` varchar(64) DEFAULT NULL COMMENT '配置的类型',\r\n  `c_schema` text COMMENT '配置的模式',\r\n  `encrypted_data_key` varchar(1024) NOT NULL DEFAULT '' COMMENT '密钥',\r\n  PRIMARY KEY (`id`),\r\n  UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = config_info_aggr             *\u002F\r\n\u002F******************************************\u002F\r\nCREATE TABLE `config_info_aggr` (\r\n  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',\r\n  `data_id` varchar(255) NOT NULL COMMENT 'data_id',\r\n  `group_id` varchar(128) NOT NULL COMMENT 'group_id',\r\n  `datum_id` varchar(255) NOT NULL COMMENT 'datum_id',\r\n  `content` longtext NOT NULL COMMENT '内容',\r\n  `gmt_modified` datetime NOT NULL COMMENT '修改时间',\r\n  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',\r\n  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',\r\n  PRIMARY KEY (`id`),\r\n  UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段';\r\n\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = config_info_beta             *\u002F\r\n\u002F******************************************\u002F\r\nCREATE TABLE `config_info_beta` (\r\n  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',\r\n  `data_id` varchar(255) NOT NULL COMMENT 'data_id',\r\n  `group_id` varchar(128) NOT NULL COMMENT 'group_id',\r\n  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',\r\n  `content` longtext NOT NULL COMMENT 'content',\r\n  `beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps',\r\n  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',\r\n  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\r\n  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',\r\n  `src_user` text COMMENT 'source user',\r\n  `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',\r\n  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',\r\n  `encrypted_data_key` varchar(1024) NOT NULL DEFAULT '' COMMENT '密钥',\r\n  PRIMARY KEY (`id`),\r\n  UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta';\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = config_info_tag              *\u002F\r\n\u002F******************************************\u002F\r\nCREATE TABLE `config_info_tag` (\r\n  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',\r\n  `data_id` varchar(255) NOT NULL COMMENT 'data_id',\r\n  `group_id` varchar(128) NOT NULL COMMENT 'group_id',\r\n  `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',\r\n  `tag_id` varchar(128) NOT NULL COMMENT 'tag_id',\r\n  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',\r\n  `content` longtext NOT NULL COMMENT 'content',\r\n  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',\r\n  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\r\n  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',\r\n  `src_user` text COMMENT 'source user',\r\n  `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',\r\n  PRIMARY KEY (`id`),\r\n  UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag';\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = config_tags_relation         *\u002F\r\n\u002F******************************************\u002F\r\nCREATE TABLE `config_tags_relation` (\r\n  `id` bigint(20) NOT NULL COMMENT 'id',\r\n  `tag_name` varchar(128) NOT NULL COMMENT 'tag_name',\r\n  `tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',\r\n  `data_id` varchar(255) NOT NULL COMMENT 'data_id',\r\n  `group_id` varchar(128) NOT NULL COMMENT 'group_id',\r\n  `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',\r\n  `nid` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'nid, 自增长标识',\r\n  PRIMARY KEY (`nid`),\r\n  UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),\r\n  KEY `idx_tenant_id` (`tenant_id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation';\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = group_capacity               *\u002F\r\n\u002F******************************************\u002F\r\nCREATE TABLE `group_capacity` (\r\n  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',\r\n  `group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID，空字符表示整个集群',\r\n  `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额，0表示使用默认值',\r\n  `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',\r\n  `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限，单位为字节，0表示使用默认值',\r\n  `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数，，0表示使用默认值',\r\n  `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限，单位为字节，0表示使用默认值',\r\n  `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',\r\n  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\r\n  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',\r\n  PRIMARY KEY (`id`),\r\n  UNIQUE KEY `uk_group_id` (`group_id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表';\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = his_config_info              *\u002F\r\n\u002F******************************************\u002F\r\nCREATE TABLE `his_config_info` (\r\n  `id` bigint(20) unsigned NOT NULL COMMENT 'id',\r\n  `nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'nid, 自增标识',\r\n  `data_id` varchar(255) NOT NULL COMMENT 'data_id',\r\n  `group_id` varchar(128) NOT NULL COMMENT 'group_id',\r\n  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',\r\n  `content` longtext NOT NULL COMMENT 'content',\r\n  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',\r\n  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\r\n  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',\r\n  `src_user` text COMMENT 'source user',\r\n  `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',\r\n  `op_type` char(10) DEFAULT NULL COMMENT 'operation type',\r\n  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',\r\n   `encrypted_data_key` varchar(1024) NOT NULL DEFAULT '' COMMENT '密钥',\r\n  PRIMARY KEY (`nid`),\r\n  KEY `idx_gmt_create` (`gmt_create`),\r\n  KEY `idx_gmt_modified` (`gmt_modified`),\r\n  KEY `idx_did` (`data_id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造';\r\n\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = tenant_capacity              *\u002F\r\n\u002F******************************************\u002F\r\nCREATE TABLE `tenant_capacity` (\r\n  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',\r\n  `tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',\r\n  `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额，0表示使用默认值',\r\n  `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',\r\n  `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限，单位为字节，0表示使用默认值',\r\n  `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数',\r\n  `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限，单位为字节，0表示使用默认值',\r\n  `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',\r\n  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\r\n  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',\r\n  PRIMARY KEY (`id`),\r\n  UNIQUE KEY `uk_tenant_id` (`tenant_id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表';\r\n\r\n\r\nCREATE TABLE `tenant_info` (\r\n  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',\r\n  `kp` varchar(128) NOT NULL COMMENT 'kp',\r\n  `tenant_id` varchar(128) default '' COMMENT 'tenant_id',\r\n  `tenant_name` varchar(128) default '' COMMENT 'tenant_name',\r\n  `tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',\r\n  `create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',\r\n  `gmt_create` bigint(20) NOT NULL COMMENT '创建时间',\r\n  `gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',\r\n  PRIMARY KEY (`id`),\r\n  UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),\r\n  KEY `idx_tenant_id` (`tenant_id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';\r\n\r\nCREATE TABLE `users` (\r\n    `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',\r\n\t`username` varchar(50) NOT NULL COMMENT 'username',\r\n\t`password` varchar(500) NOT NULL COMMENT 'password',\r\n\t`enabled` boolean NOT NULL COMMENT 'enabled',\r\n    PRIMARY KEY (`id`)\r\n);\r\n\r\nCREATE TABLE `roles` (\r\n    `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',\r\n\t`username` varchar(50) NOT NULL COMMENT 'username',\r\n\t`role` varchar(50) NOT NULL COMMENT 'role',\r\n    PRIMARY KEY (`id`),\r\n    UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE\r\n);\r\n\r\nCREATE TABLE `permissions` (\r\n    `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',\r\n    `role` varchar(50) NOT NULL COMMENT 'role',\r\n    `resource` varchar(128) NOT NULL COMMENT 'resource',\r\n    `action` varchar(8) NOT NULL COMMENT 'action',\r\n    PRIMARY KEY (`id`),\r\n    UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE\r\n);\r\n```\r\n\r\n\r\n\r\n\r\n\r\n### 5.1.2\t创建nacos集群\r\n\r\n#### 5.1.2.1\t创建命名空间\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Namespace\r\nmetadata:\r\n  name: test\r\n```\r\n\r\n\r\n\r\n#### 5.1.2.2\t创建配置文件\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: ConfigMap\r\nmetadata:\r\n  name: nacos-config\r\n  namespace: test\r\n  labels:\r\n    app: nacos\r\ndata:\r\n  # nacos集群节点域名\r\n  cluster.conf: |\r\n    nacos-0.nacos-svc.test.svc.cluster.local:8848\r\n    nacos-1.nacos-svc.test.svc.cluster.local:8848\r\n    nacos-2.nacos-svc.test.svc.cluster.local:8848\r\n  \r\n  # nacos启动配置文件\r\n  application.properties: |\r\n    # spring\r\n    server.servlet.contextPath=${SERVER_SERVLET_CONTEXTPATH:\u002Fnacos}\r\n    server.contextPath=\u002Fnacos\r\n    server.port=${NACOS_APPLICATION_PORT:8848}\r\n    server.tomcat.accesslog.max-days=30\r\n    server.tomcat.accesslog.pattern=%h %l %u %t \"%r\" %s %b %D %{User-Agent}i %{Request-Source}i\r\n    server.tomcat.accesslog.enabled=${TOMCAT_ACCESSLOG_ENABLED:false}\r\n    server.error.include-message=ALWAYS\r\n    # default current work dir\r\n    server.tomcat.basedir=file:.\r\n    #*************** Config Module Related Configurations ***************#\r\n    ### Deprecated configuration property, it is recommended to use `spring.sql.init.platform` replaced.\r\n    #spring.datasource.platform=${SPRING_DATASOURCE_PLATFORM:}\r\n    # 配置数据库\r\n    spring.sql.init.platform=${SPRING_DATASOURCE_PLATFORM:mysql}\r\n    nacos.cmdb.dumpTaskInterval=3600\r\n    nacos.cmdb.eventTaskInterval=10\r\n    nacos.cmdb.labelTaskInterval=300\r\n    nacos.cmdb.loadDataAtStart=false\r\n    db.num=${MYSQL_DATABASE_NUM:1}\r\n    # 配置数据库连接\r\n    db.url.0=jdbc:mysql:\u002F\u002Fmysql.test.svc:3306\u002Fnacos_devtest?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false\r\n    db.user.0=nacos\r\n    db.password.0=nacos\r\n    ## DB connection pool settings\r\n    db.pool.config.connectionTimeout=${DB_POOL_CONNECTION_TIMEOUT:30000}\r\n    db.pool.config.validationTimeout=10000\r\n    db.pool.config.maximumPoolSize=20\r\n    db.pool.config.minimumIdle=2\r\n    ### The auth system to use, currently only 'nacos' and 'ldap' is supported:\r\n    nacos.core.auth.system.type=${NACOS_AUTH_SYSTEM_TYPE:nacos}\r\n    ### worked when nacos.core.auth.system.type=nacos\r\n    ### The token expiration in seconds:\r\n    nacos.core.auth.plugin.nacos.token.expire.seconds=${NACOS_AUTH_TOKEN_EXPIRE_SECONDS:18000}\r\n    \r\n    # 开启鉴权功能\r\n    nacos.core.auth.enabled=true\r\n    # 自定义用于生成JWT令牌的密钥，注意：原始密钥长度不得低于32字符，且一定要进行Base64编码，否则无法启动节点。\r\n    nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123453456789999876549012345678901232389742349889\r\n    \r\n    ### Turn on\u002Foff caching of auth information. By turning on this switch, the update of auth information would have a 15 seconds delay.\r\n    nacos.core.auth.caching.enabled=${NACOS_AUTH_CACHE_ENABLE:false}\r\n    nacos.core.auth.enable.userAgentAuthWhite=${NACOS_AUTH_USER_AGENT_AUTH_WHITE_ENABLE:false}\r\n    nacos.core.auth.server.identity.key=${NACOS_AUTH_IDENTITY_KEY:nacos}\r\n    nacos.core.auth.server.identity.value=${NACOS_AUTH_IDENTITY_VALUE:nacos}\r\n    ## spring security config\r\n    ### turn off security\r\n    nacos.security.ignore.urls=${NACOS_SECURITY_IGNORE_URLS:\u002F,\u002Ferror,\u002F**\u002F*.css,\u002F**\u002F*.js,\u002F**\u002F*.html,\u002F**\u002F*.map,\u002F**\u002F*.svg,\u002F**\u002F*.png,\u002F**\u002F*.ico,\u002Fconsole-fe\u002Fpublic\u002F**,\u002Fv1\u002Fauth\u002F**,\u002Fv1\u002Fconsole\u002Fhealth\u002F**,\u002Factuator\u002F**,\u002Fv1\u002Fconsole\u002Fserver\u002F**}\r\n    # metrics for elastic search\r\n    management.metrics.export.elastic.enabled=false\r\n    management.metrics.export.influx.enabled=false\r\n    nacos.naming.distro.taskDispatchThreadCount=10\r\n    nacos.naming.distro.taskDispatchPeriod=200\r\n    nacos.naming.distro.batchSyncKeyCount=1000\r\n    nacos.naming.distro.initDataRatio=0.9\r\n    nacos.naming.distro.syncRetryDelay=5000\r\n    nacos.naming.data.warmup=true\r\n    nacos.console.ui.enabled=true\r\n    nacos.core.param.check.enabled=true\r\n```\r\n\r\n\r\n\r\n#### 5.1.2.2\tnacos集群创建\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  name: nacos-svc\r\n  namespace: test\r\n  labels:\r\n    app: nacos\r\nspec:\r\n  ports:\r\n    - port: 8848\r\n      name: client-port\r\n      targetPort: 8848\r\n    - port: 9848\r\n      name: client-rpc\r\n      targetPort: 9848\r\n    - port: 9849\r\n      name: raft-rpc\r\n      targetPort: 9849\r\n  clusterIP: None\r\n  selector:\r\n    app: nacos\r\n---\r\napiVersion: apps\u002Fv1\r\nkind: StatefulSet\r\nmetadata:\r\n  name: nacos\r\n  namespace: test\r\n  labels:\r\n    app: nacos\r\nspec:\r\n  podManagementPolicy: Parallel # 配置无序启动\r\n  serviceName: nacos-svc\r\n  replicas: 3\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: nacos\r\n    spec:\r\n      containers:\r\n        - name: nacos\r\n          image: nacos\u002Fnacos-server:v2.4.0\r\n         # imagePullPolicy: Always 总是下拉新的镜像\r\n          ports:\r\n            - containerPort: 8848\r\n              name: client-port\r\n            - containerPort: 9848\r\n              name: client-rpc\r\n            - containerPort: 9849\r\n              name: raft-rpc\r\n          volumeMounts:\r\n            - name: cluster-config\r\n              mountPath: \u002Fhome\u002Fnacos\u002Fconf\u002Fcluster.conf\r\n              subPath: cluster.conf\r\n            - name: nacos-config\r\n              mountPath: \u002Fhome\u002Fnacos\u002Fconf\u002Fapplication.properties\r\n              subPath: application.properties\r\n      volumes:\r\n        - name: cluster-config    # 挂载configMap配置文件\r\n          configMap:\r\n            name: nacos-config    # 对应创建ConfigMap时的metadata.name名称\r\n            items:\r\n            - key: cluster.conf   # 配置文件中的key名称\r\n              path: cluster.conf\r\n        - name: nacos-config\r\n          configMap:\r\n            name: nacos-config    # 对应创建ConfigMap时的metadata.name名称\r\n            items:\r\n            - key: application.properties\r\n              path: application.properties\r\n  selector:\r\n    matchLabels:\r\n      app: nacos\r\n```\r\n\r\n\r\n\r\n## 5.2\tnacos集群 — PostgreSQL\r\n\r\n### 5.2.1\t安装PostgreSQL\r\n\r\n#### 5.2.1.1\t安装PostgreSQL\r\n\r\ndocker安装方式\r\n\r\n```yaml\r\n# 下拉镜像\r\ndocker pull postgres:16\r\n# 运行，默认账号：postgres\r\ndocker run --name postgres -p 5432:5432 -e POSTGRES_PASSWORD='postgres' -d postgres:16\r\n```\r\n\r\nk8s安装如下\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: ReplicationController\r\nmetadata:\r\n  name: postgres\r\n  namespace: test\r\n  labels:\r\n    name: postgres\r\nspec:\r\n  replicas: 1\r\n  selector:\r\n    name: postgres\r\n  template:\r\n    metadata:\r\n      labels:\r\n        name: postgres\r\n    spec:\r\n      containers:\r\n      - name: postgres\r\n        image: postgres:16\r\n        ports:\r\n        - containerPort: 5432\r\n        env:\r\n        - name: POSTGRES_USER\r\n          value: \"postgres\"\r\n        - name: POSTGRES_PASSWORD\r\n          value: \"postgres\"\r\n---\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  name: postgres-svc\r\n  namespace: test\r\n  labels:\r\n    name: postgres\r\nspec:\r\n  selector:\r\n    name: postgres\r\n  ports:\r\n  - port: 5432\r\n    protocol: TCP\r\n    targetPort: 5432\r\n    nodePort: 30001  # 指定暴露的节点端口，范围必须在30000-32767之间，不指定则随机分配\r\n  type: NodePort\r\n```\r\n\r\n#### 5.2.1.2\t创建nacos配置表\r\n\r\n​\t登录pg数据库：\r\n\r\n```shell\r\nkubectl exec -it -n test postgres-zzxdf bin\u002Fbash\r\n\r\n# 登录pg\r\npsql -U postgres  -d postgres\r\n# 验证是否进入交互控台\r\nselect 1;\r\n\r\nkubectl cp postgres-schema.sql -n test postgres-zcc9t:\u002Froot\r\n\r\n# 导入nacos配置表sql\r\npsql -U postgres -d postgres -f \u002Froot\u002Fpostgres-schema.sql\r\n```\r\n\r\n​\t\r\n\r\n`postgres-schema.sql`建表语句如下：\r\n\r\n```shell\r\nDROP TABLE IF EXISTS \"config_info\";\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = config_info                  *\u002F\r\n\u002F******************************************\u002F\r\nCREATE TABLE \"config_info\" (\r\n        \"id\" bigserial,\r\n        \"data_id\" varchar(255) NOT NULL,\r\n        \"group_id\" varchar(128) DEFAULT NULL,\r\n        \"content\" text NOT NULL,\r\n        \"md5\" varchar(32) DEFAULT NULL,\r\n        \"gmt_create\" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n        \"gmt_modified\" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n        \"src_user\" text,\r\n        \"src_ip\" varchar(50) DEFAULT NULL,\r\n        \"app_name\" varchar(128) DEFAULT NULL,\r\n        \"tenant_id\" varchar(128) DEFAULT '',\r\n        \"c_desc\" varchar(256) DEFAULT NULL,\r\n        \"c_use\" varchar(64) DEFAULT NULL,\r\n        \"effect\" varchar(64) DEFAULT NULL,\r\n        \"type\" varchar(64) DEFAULT NULL,\r\n        \"c_schema\" text,\r\n        \"encrypted_data_key\" varchar(1024) NOT NULL DEFAULT '',\r\n        PRIMARY KEY (\"id\")\r\n);\r\n\r\nCREATE UNIQUE INDEX \"uk_configinfo_datagrouptenant\" ON \"config_info\" (\"data_id\",\"group_id\",\"tenant_id\");\r\n\r\nCOMMENT ON COLUMN \"config_info\".\"id\" IS 'id';\r\nCOMMENT ON COLUMN \"config_info\".\"data_id\" IS 'data id';\r\nCOMMENT ON COLUMN \"config_info\".\"group_id\" IS 'group id';\r\nCOMMENT ON COLUMN \"config_info\".\"content\" IS 'content';\r\nCOMMENT ON COLUMN \"config_info\".\"md5\" IS 'md5';\r\nCOMMENT ON COLUMN \"config_info\".\"gmt_create\" IS '创建时间';\r\nCOMMENT ON COLUMN \"config_info\".\"gmt_modified\" IS '修改时间';\r\nCOMMENT ON COLUMN \"config_info\".\"src_user\" IS 'source user';\r\nCOMMENT ON COLUMN \"config_info\".\"src_ip\" IS 'source ip';\r\nCOMMENT ON COLUMN \"config_info\".\"app_name\" IS 'app name';\r\nCOMMENT ON COLUMN \"config_info\".\"tenant_id\" IS '租户字段';\r\nCOMMENT ON COLUMN \"config_info\".\"c_desc\" IS 'configuration description';\r\nCOMMENT ON COLUMN \"config_info\".\"c_use\" IS 'configuration usage';\r\nCOMMENT ON COLUMN \"config_info\".\"effect\" IS '配置生效的描述';\r\nCOMMENT ON COLUMN \"config_info\".\"type\" IS '配置的类型';\r\nCOMMENT ON COLUMN \"config_info\".\"c_schema\" IS '配置的模式';\r\nCOMMENT ON COLUMN \"config_info\".\"encrypted_data_key\" IS '秘钥';\r\nCOMMENT ON TABLE \"config_info\" IS 'config_info';\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = config_info_aggr             *\u002F\r\n\u002F******************************************\u002F\r\nDROP TABLE IF EXISTS \"config_info_aggr\";\r\n\r\nCREATE TABLE \"config_info_aggr\" (\r\n    \"id\" bigserial,\r\n    \"data_id\" varchar(255) NOT NULL,\r\n    \"group_id\" varchar(128) NOT NULL,\r\n    \"datum_id\" varchar(255) NOT NULL,\r\n    \"content\" text NOT NULL,\r\n    \"gmt_modified\" timestamp NOT NULL,\r\n    \"app_name\" varchar(128) DEFAULT NULL,\r\n    \"tenant_id\" varchar(128) DEFAULT '',\r\n    PRIMARY KEY (\"id\")\r\n);\r\nCREATE UNIQUE INDEX \"uk_configinfoaggr_datagrouptenantdatum\" ON \"config_info_aggr\" (\"data_id\",\"group_id\",\"tenant_id\",\"datum_id\");\r\n\r\nCOMMENT ON COLUMN \"config_info_aggr\".\"id\" IS 'id';\r\nCOMMENT ON COLUMN \"config_info_aggr\".\"data_id\" IS 'data_id';\r\nCOMMENT ON COLUMN \"config_info_aggr\".\"group_id\" IS 'group_id';\r\nCOMMENT ON COLUMN \"config_info_aggr\".\"datum_id\" IS 'datum_id';\r\nCOMMENT ON COLUMN \"config_info_aggr\".\"content\" IS '内容';\r\nCOMMENT ON COLUMN \"config_info_aggr\".\"gmt_modified\" IS '修改时间';\r\nCOMMENT ON COLUMN \"config_info_aggr\".\"app_name\" IS 'app_name';\r\nCOMMENT ON COLUMN \"config_info_aggr\".\"tenant_id\" IS '租户字段';\r\nCOMMENT ON TABLE \"config_info_aggr\" IS '增加租户字段';\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = config_info_beta             *\u002F\r\n\u002F******************************************\u002F\r\nDROP TABLE IF EXISTS \"config_info_beta\";\r\n\r\nCREATE TABLE \"config_info_beta\" (\r\n    \"id\" bigserial,\r\n    \"data_id\" varchar(255) NOT NULL,\r\n    \"group_id\" varchar(128) NOT NULL,\r\n    \"app_name\" varchar(128) DEFAULT NULL,\r\n    \"content\" text NOT NULL,\r\n    \"beta_ips\" varchar(1024) DEFAULT NULL,\r\n    \"md5\" varchar(32) DEFAULT NULL,\r\n    \"gmt_create\" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n    \"gmt_modified\" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n    \"src_user\" text,\r\n    \"src_ip\" varchar(50) DEFAULT NULL,\r\n    \"tenant_id\" varchar(128) DEFAULT '',\r\n    \"encrypted_data_key\" varchar(1024) NOT NULL DEFAULT '',\r\n    PRIMARY KEY (\"id\")\r\n);\r\nCREATE UNIQUE INDEX \"uk_configinfobeta_datagrouptenant\" ON \"config_info_beta\" (\"data_id\",\"group_id\",\"tenant_id\");\r\n\r\nCOMMENT ON COLUMN \"config_info_beta\".\"id\" IS 'id';\r\nCOMMENT ON COLUMN \"config_info_beta\".\"data_id\" IS 'data_id';\r\nCOMMENT ON COLUMN \"config_info_beta\".\"group_id\" IS 'group_id';\r\nCOMMENT ON COLUMN \"config_info_beta\".\"app_name\" IS 'app_name';\r\nCOMMENT ON COLUMN \"config_info_beta\".\"content\" IS '内容';\r\nCOMMENT ON COLUMN \"config_info_beta\".\"beta_ips\" IS 'betaIps';\r\nCOMMENT ON COLUMN \"config_info_beta\".\"md5\" IS 'md5';\r\nCOMMENT ON COLUMN \"config_info_beta\".\"gmt_create\" IS '创建时间';\r\nCOMMENT ON COLUMN \"config_info_beta\".\"gmt_modified\" IS '修改时间';\r\nCOMMENT ON COLUMN \"config_info_beta\".\"src_user\" IS 'source user';\r\nCOMMENT ON COLUMN \"config_info_beta\".\"src_ip\" IS 'source ip';\r\nCOMMENT ON COLUMN \"config_info_beta\".\"tenant_id\" IS '租户字段';\r\nCOMMENT ON COLUMN \"config_info_beta\".\"encrypted_data_key\" IS '密钥';\r\nCOMMENT ON TABLE \"config_info_beta\" IS 'config_info_beta';\r\n\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = config_info_tag              *\u002F\r\n\u002F******************************************\u002F\r\nDROP TABLE IF EXISTS \"config_info_tag\";\r\n\r\nCREATE TABLE \"config_info_tag\" (\r\n        \"id\" bigserial,\r\n        \"data_id\" varchar(255) NOT NULL,\r\n        \"group_id\" varchar(128) NOT NULL,\r\n        \"tenant_id\" varchar(128) DEFAULT '',\r\n        \"tag_id\" varchar(128) NOT NULL,\r\n        \"app_name\" varchar(128) DEFAULT NULL,\r\n        \"content\" text NOT NULL,\r\n        \"md5\" varchar(32) DEFAULT NULL,\r\n        \"gmt_create\" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n        \"gmt_modified\" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n        \"src_user\" text,\r\n        \"src_ip\" varchar(50) DEFAULT NULL,\r\n        PRIMARY KEY (\"id\")\r\n);\r\nCREATE UNIQUE INDEX \"uk_configinfotag_datagrouptenanttag\" ON \"config_info_tag\" (\"data_id\",\"group_id\",\"tenant_id\",\"tag_id\");\r\n\r\nCOMMENT ON COLUMN \"config_info_tag\".\"id\" IS 'id';\r\nCOMMENT ON COLUMN \"config_info_tag\".\"data_id\" IS 'data_id';\r\nCOMMENT ON COLUMN \"config_info_tag\".\"group_id\" IS 'group_id';\r\nCOMMENT ON COLUMN \"config_info_tag\".\"tenant_id\" IS '租户字段';\r\nCOMMENT ON COLUMN \"config_info_tag\".\"tag_id\" IS 'tag_id';\r\nCOMMENT ON COLUMN \"config_info_tag\".\"app_name\" IS 'app_name';\r\nCOMMENT ON COLUMN \"config_info_tag\".\"content\" IS '内容';\r\nCOMMENT ON COLUMN \"config_info_tag\".\"md5\" IS 'md5';\r\nCOMMENT ON COLUMN \"config_info_tag\".\"gmt_create\" IS '创建时间';\r\nCOMMENT ON COLUMN \"config_info_tag\".\"gmt_modified\" IS '修改时间';\r\nCOMMENT ON COLUMN \"config_info_tag\".\"src_user\" IS 'source user';\r\nCOMMENT ON COLUMN \"config_info_tag\".\"src_ip\" IS 'source ip';\r\nCOMMENT ON TABLE \"config_info_tag\" IS 'config_info_tag';\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = config_tags_relation         *\u002F\r\n\u002F******************************************\u002F\r\nDROP TABLE IF EXISTS \"config_tags_relation\";\r\n\r\nCREATE TABLE \"config_tags_relation\" (\r\n        \"id\" int8 NOT NULL,\r\n        \"tag_name\" varchar(128) NOT NULL,\r\n        \"tag_type\" varchar(64) DEFAULT NULL,\r\n        \"data_id\" varchar(255) NOT NULL,\r\n        \"group_id\" varchar(128) NOT NULL,\r\n        \"tenant_id\" varchar(128) DEFAULT '',\r\n        \"nid\" bigserial,\r\n        PRIMARY KEY (\"nid\")\r\n);\r\nCREATE UNIQUE INDEX \"uk_configtagrelation_configidtag\" ON \"config_tags_relation\" (\"id\",\"tag_name\",\"tag_type\");\r\nCREATE UNIQUE INDEX \"idx_configtagrelation_tenant_id\" ON \"config_tags_relation\" (\"tenant_id\");\r\n\r\nCOMMENT ON COLUMN \"config_tags_relation\".\"id\" IS 'id';\r\nCOMMENT ON COLUMN \"config_tags_relation\".\"tag_name\" IS 'tag_name';\r\nCOMMENT ON COLUMN \"config_tags_relation\".\"tag_type\" IS 'tag_type';\r\nCOMMENT ON COLUMN \"config_tags_relation\".\"data_id\" IS 'data_id';\r\nCOMMENT ON COLUMN \"config_tags_relation\".\"group_id\" IS 'group_id';\r\nCOMMENT ON COLUMN \"config_tags_relation\".\"tenant_id\" IS 'tenant_id';\r\nCOMMENT ON COLUMN \"config_tags_relation\".\"nid\" IS 'nid, 自增长标识';\r\nCOMMENT ON TABLE \"config_tags_relation\" IS 'config_tag_relation';\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = group_capacity               *\u002F\r\n\u002F******************************************\u002F\r\nDROP TABLE IF EXISTS \"group_capacity\";\r\n\r\nCREATE TABLE \"group_capacity\" (\r\n        \"id\" bigserial,\r\n        \"group_id\" varchar(128) NOT NULL DEFAULT '',\r\n        \"quota\" int4 NOT NULL DEFAULT '0',\r\n        \"usage\" int4 NOT NULL DEFAULT '0',\r\n        \"max_size\" int4 NOT NULL DEFAULT '0',\r\n        \"max_aggr_count\" int4 NOT NULL DEFAULT '0',\r\n        \"max_aggr_size\" int4 NOT NULL DEFAULT '0',\r\n        \"max_history_count\" int4 NOT NULL DEFAULT '0',\r\n        \"gmt_create\" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n        \"gmt_modified\" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n        PRIMARY KEY (\"id\")\r\n);\r\nCREATE UNIQUE INDEX \"uk_group_id\" ON \"config_info_tag\" (\"group_id\");\r\nCOMMENT ON COLUMN \"group_capacity\".\"id\" IS '主键ID';\r\nCOMMENT ON COLUMN \"group_capacity\".\"group_id\" IS 'Group ID，空字符表示整个集群';\r\nCOMMENT ON COLUMN \"group_capacity\".\"quota\" IS '配额，0表示使用默认值';\r\nCOMMENT ON COLUMN \"group_capacity\".\"usage\" IS '使用量';\r\nCOMMENT ON COLUMN \"group_capacity\".\"max_size\" IS '单个配置大小上限，单位为字节，0表示使用默认值';\r\nCOMMENT ON COLUMN \"group_capacity\".\"max_aggr_count\" IS '聚合子配置最大个数，，0表示使用默认值';\r\nCOMMENT ON COLUMN \"group_capacity\".\"max_aggr_size\" IS '单个聚合数据的子配置大小上限，单位为字节，0表示使用默认值';\r\nCOMMENT ON COLUMN \"group_capacity\".\"max_history_count\" IS '最大变更历史数量';\r\nCOMMENT ON COLUMN \"group_capacity\".\"gmt_create\" IS '创建时间';\r\nCOMMENT ON COLUMN \"group_capacity\".\"gmt_modified\" IS '修改时间';\r\nCOMMENT ON TABLE \"group_capacity\" IS '集群、各Group容量信息表';\r\n\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = his_config_info              *\u002F\r\n\u002F******************************************\u002F\r\nDROP TABLE IF EXISTS \"his_config_info\";\r\n\r\nCREATE TABLE \"his_config_info\" (\r\n        \"id\" int8 NOT NULL,\r\n        \"nid\" bigserial,\r\n        \"data_id\" varchar(255) NOT NULL,\r\n        \"group_id\" varchar(128) NOT NULL,\r\n        \"app_name\" varchar(128) DEFAULT NULL,\r\n        \"content\" text NOT NULL,\r\n        \"md5\" varchar(32) DEFAULT NULL,\r\n        \"gmt_create\" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n        \"gmt_modified\" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n        \"src_user\" text,\r\n        \"src_ip\" varchar(50) DEFAULT NULL,\r\n        \"op_type\" char(10) DEFAULT NULL,\r\n        \"tenant_id\" varchar(128) DEFAULT '',\r\n        \"encrypted_data_key\" varchar(1024) NOT NULL DEFAULT '',\r\n        PRIMARY KEY (\"nid\")\r\n);\r\nCREATE UNIQUE INDEX \"idx_gmt_create\" ON \"his_config_info\" (\"gmt_create\");\r\nCREATE UNIQUE INDEX \"idx_gmt_modified\" ON \"his_config_info\" (\"gmt_modified\");\r\nCREATE UNIQUE INDEX \"idx_did\" ON \"his_config_info\" (\"data_id\");\r\n\r\nCOMMENT ON COLUMN \"his_config_info\".\"id\" IS 'id';\r\nCOMMENT ON COLUMN \"his_config_info\".\"nid\" IS 'nid, 自增标识';\r\nCOMMENT ON COLUMN \"his_config_info\".\"data_id\" IS 'data_id';\r\nCOMMENT ON COLUMN \"his_config_info\".\"group_id\" IS 'group_id';\r\nCOMMENT ON COLUMN \"his_config_info\".\"app_name\" IS 'app_name';\r\nCOMMENT ON COLUMN \"his_config_info\".\"content\" IS 'content';\r\nCOMMENT ON COLUMN \"his_config_info\".\"md5\" IS 'md5';\r\nCOMMENT ON COLUMN \"his_config_info\".\"gmt_create\" IS '创建时间';\r\nCOMMENT ON COLUMN \"his_config_info\".\"gmt_modified\" IS '修改时间';\r\nCOMMENT ON COLUMN \"his_config_info\".\"src_user\" IS 'source user';\r\nCOMMENT ON COLUMN \"his_config_info\".\"src_ip\" IS 'source ip';\r\nCOMMENT ON COLUMN \"his_config_info\".\"op_type\" IS 'operation type';\r\nCOMMENT ON COLUMN \"his_config_info\".\"tenant_id\" IS '租户字段';\r\nCOMMENT ON COLUMN \"his_config_info\".\"encrypted_data_key\" IS '密钥';\r\nCOMMENT ON TABLE \"his_config_info\" IS '多租户改造';\r\n\r\n\r\n\u002F******************************************\u002F\r\n\u002F*   表名称 = tenant_capacity              *\u002F\r\n\u002F******************************************\u002F\r\nDROP TABLE IF EXISTS \"tenant_capacity\";\r\n\r\nCREATE TABLE \"tenant_capacity\" (\r\n        \"id\" bigserial,\r\n        \"tenant_id\" varchar(128) NOT NULL DEFAULT '',\r\n        \"quota\" int4 NOT NULL DEFAULT '0',\r\n        \"usage\" int4 NOT NULL DEFAULT '0',\r\n        \"max_size\" int4 NOT NULL DEFAULT '0',\r\n        \"max_aggr_count\" int4 NOT NULL DEFAULT '0',\r\n        \"max_aggr_size\" int4 NOT NULL DEFAULT '0',\r\n        \"max_history_count\" int4 NOT NULL DEFAULT '0',\r\n        \"gmt_create\" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n        \"gmt_modified\" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n        PRIMARY KEY (\"id\")\r\n);\r\nCREATE UNIQUE INDEX \"uk_tenant_id\" ON \"tenant_capacity\" (\"tenant_id\");\r\n\r\nCOMMENT ON COLUMN \"tenant_capacity\".\"id\" IS '主键ID';\r\nCOMMENT ON COLUMN \"tenant_capacity\".\"tenant_id\" IS 'Tenant ID';\r\nCOMMENT ON COLUMN \"tenant_capacity\".\"quota\" IS '配额，0表示使用默认值';\r\nCOMMENT ON COLUMN \"tenant_capacity\".\"usage\" IS '使用量';\r\nCOMMENT ON COLUMN \"tenant_capacity\".\"max_size\" IS '单个配置大小上限，单位为字节，0表示使用默认值';\r\nCOMMENT ON COLUMN \"tenant_capacity\".\"max_aggr_count\" IS '聚合子配置最大个数';\r\nCOMMENT ON COLUMN \"tenant_capacity\".\"max_aggr_size\" IS '单个聚合数据的子配置大小上限，单位为字节，0表示使用默认值';\r\nCOMMENT ON COLUMN \"tenant_capacity\".\"max_history_count\" IS '最大变更历史数量';\r\nCOMMENT ON COLUMN \"tenant_capacity\".\"gmt_create\" IS '创建时间';\r\nCOMMENT ON COLUMN \"tenant_capacity\".\"gmt_modified\" IS '修改时间';\r\nCOMMENT ON TABLE \"tenant_capacity\" IS '租户容量信息表';\r\n\r\n\r\nDROP TABLE IF EXISTS \"tenant_info\";\r\n\r\nCREATE TABLE \"tenant_info\" (\r\n        \"id\" bigserial,\r\n        \"kp\" varchar(128) NOT NULL,\r\n        \"tenant_id\" varchar(128) default '',\r\n        \"tenant_name\" varchar(128) default '',\r\n        \"tenant_desc\" varchar(256) DEFAULT NULL,\r\n        \"create_source\" varchar(32) DEFAULT NULL,\r\n        \"gmt_create\" int8 NOT NULL,\r\n        \"gmt_modified\" int8 NOT NULL,\r\n        PRIMARY KEY (\"id\")\r\n);\r\n\r\nCREATE UNIQUE INDEX \"uk_tenant_info_kptenantid\" ON \"tenant_info\" (\"kp\",\"tenant_id\");\r\nCREATE UNIQUE INDEX \"idx_tenant_info_tenant_id\" ON \"tenant_info\" (\"tenant_id\");\r\n\r\nCOMMENT ON COLUMN \"tenant_info\".\"id\" IS 'id';\r\nCOMMENT ON COLUMN \"tenant_info\".\"kp\" IS 'kp';\r\nCOMMENT ON COLUMN \"tenant_info\".\"tenant_id\" IS 'tenant_id';\r\nCOMMENT ON COLUMN \"tenant_info\".\"tenant_name\" IS 'tenant_name';\r\nCOMMENT ON COLUMN \"tenant_info\".\"tenant_desc\" IS 'tenant_desc';\r\nCOMMENT ON COLUMN \"tenant_info\".\"create_source\" IS 'create_source';\r\nCOMMENT ON COLUMN \"tenant_info\".\"gmt_create\" IS '创建时间';\r\nCOMMENT ON COLUMN \"tenant_info\".\"gmt_modified\" IS '修改时间';\r\nCOMMENT ON TABLE \"tenant_info\" IS 'tenant_info';\r\n\r\n\r\nDROP TABLE IF EXISTS \"users\";\r\n\r\nCREATE TABLE \"users\" (\r\n        \"id\" bigserial,\r\n        \"username\" varchar(50) NOT NULL,\r\n        \"password\" varchar(500) NOT NULL,\r\n        \"enabled\" boolean NOT NULL,\r\n        PRIMARY KEY (\"id\")\r\n);\r\n\r\nCOMMENT ON COLUMN \"users\".\"id\" IS 'id';\r\nCOMMENT ON COLUMN \"users\".\"username\" IS 'username';\r\nCOMMENT ON COLUMN \"users\".\"password\" IS 'password';\r\nCOMMENT ON COLUMN \"users\".\"enabled\" IS 'enabled';\r\nCOMMENT ON TABLE \"users\" IS '用户信息表';\r\n\r\nDROP TABLE IF EXISTS \"roles\";\r\n\r\nCREATE TABLE \"roles\" (\r\n        \"id\" bigserial,\r\n        \"username\" varchar(50) NOT NULL,\r\n        \"role\" varchar(50) NOT NULL,\r\n        PRIMARY KEY (\"id\")\r\n);\r\nCREATE UNIQUE INDEX \"idx_user_role\" ON \"roles\" (\"username\",\"role\");\r\n\r\nCOMMENT ON COLUMN \"roles\".\"id\" IS 'id';\r\nCOMMENT ON COLUMN \"roles\".\"username\" IS 'username';\r\nCOMMENT ON COLUMN \"roles\".\"role\" IS 'role';\r\nCOMMENT ON TABLE \"roles\" IS '角色表';\r\n\r\n\r\nDROP TABLE IF EXISTS \"permissions\";\r\n\r\nCREATE TABLE \"permissions\" (\r\n    \"id\" bigserial,\r\n    \"role\" varchar(50) NOT NULL,\r\n    \"resource\" varchar(128) NOT NULL,\r\n    \"action\" varchar(8) NOT NULL,\r\n    PRIMARY KEY (\"id\")\r\n);\r\nCREATE UNIQUE INDEX \"uk_role_permission\" ON \"permissions\" (\"role\",\"resource\",\"action\");\r\n\r\nCOMMENT ON COLUMN \"permissions\".\"id\" IS 'id';\r\nCOMMENT ON COLUMN \"permissions\".\"role\" IS 'role';\r\nCOMMENT ON COLUMN \"permissions\".\"resource\" IS 'resource';\r\nCOMMENT ON COLUMN \"permissions\".\"action\" IS 'action';\r\nCOMMENT ON TABLE \"permissions\" IS 'permissions';\r\n```\r\n\r\n\r\n\r\n### 5.2.2\tnacos集群创建\r\n\r\n#### 5.2.2.1\t创建ConfigMap配置\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: ConfigMap\r\nmetadata:\r\n  name: nacos-config\r\n  namespace: test\r\n  labels:\r\n    app: nacos\r\ndata:\r\n  # nacos集群节点域名\r\n  cluster.conf: |\r\n    nacos-0.nacos-svc.test.svc.cluster.local:8848\r\n    nacos-1.nacos-svc.test.svc.cluster.local:8848\r\n    nacos-2.nacos-svc.test.svc.cluster.local:8848\r\n  \r\n  # nacos启动配置文件\r\n  application.properties: |\r\n    # spring\r\n    server.servlet.contextPath=${SERVER_SERVLET_CONTEXTPATH:\u002Fnacos}\r\n    server.contextPath=\u002Fnacos\r\n    server.port=${NACOS_APPLICATION_PORT:8848}\r\n    server.tomcat.accesslog.max-days=30\r\n    server.tomcat.accesslog.pattern=%h %l %u %t \"%r\" %s %b %D %{User-Agent}i %{Request-Source}i\r\n    server.tomcat.accesslog.enabled=${TOMCAT_ACCESSLOG_ENABLED:false}\r\n    server.error.include-message=ALWAYS\r\n    # default current work dir\r\n    server.tomcat.basedir=file:.\r\n    #*************** Config Module Related Configurations ***************#\r\n    ### Deprecated configuration property, it is recommended to use `spring.sql.init.platform` replaced.\r\n    #spring.datasource.platform=${SPRING_DATASOURCE_PLATFORM:}\r\n    #配置 使用postgres数据库\r\n    spring.sql.init.platform=${SPRING_DATASOURCE_PLATFORM:postgresql}\r\n    nacos.cmdb.dumpTaskInterval=3600\r\n    nacos.cmdb.eventTaskInterval=10\r\n    nacos.cmdb.labelTaskInterval=300\r\n    nacos.cmdb.loadDataAtStart=false\r\n    db.num=${MYSQL_DATABASE_NUM:1}\r\n    # 配置pg数据库链接信息\r\n    db.url.0=jdbc:postgresql:\u002F\u002Fpostgres-svc.test.svc:5432\u002Fpostgres?currentSchema=public&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false\r\n    db.user.0=postgres\r\n    db.password.0=postgres\r\n\r\n    # 配置数据库驱动，如果不配置默认使用mysql数据库驱动\r\n    db.pool.config.driverClassName=org.postgresql.Driver\r\n\r\n    ## DB connection pool settings\r\n    db.pool.config.connectionTimeout=${DB_POOL_CONNECTION_TIMEOUT:30000}\r\n    db.pool.config.validationTimeout=10000\r\n    db.pool.config.maximumPoolSize=20\r\n    db.pool.config.minimumIdle=2\r\n    ### The auth system to use, currently only 'nacos' and 'ldap' is supported:\r\n    nacos.core.auth.system.type=${NACOS_AUTH_SYSTEM_TYPE:nacos}\r\n    ### worked when nacos.core.auth.system.type=nacos\r\n    ### The token expiration in seconds:\r\n    nacos.core.auth.plugin.nacos.token.expire.seconds=${NACOS_AUTH_TOKEN_EXPIRE_SECONDS:18000}\r\n\r\n    # 开启鉴权功能\r\n    nacos.core.auth.enabled=true\r\n    # 自定义用于生成JWT令牌的密钥，注意：原始密钥长度不得低于32字符，且一定要进行Base64编码，否则无法启动节点。\r\n    nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123453456789999876549012345678901232389742349889\r\n\r\n    ### Turn on\u002Foff caching of auth information. By turning on this switch, the update of auth information would have a 15 seconds delay.\r\n    nacos.core.auth.caching.enabled=${NACOS_AUTH_CACHE_ENABLE:false}\r\n    nacos.core.auth.enable.userAgentAuthWhite=${NACOS_AUTH_USER_AGENT_AUTH_WHITE_ENABLE:false}\r\n    nacos.core.auth.server.identity.key=${NACOS_AUTH_IDENTITY_KEY:nacos}\r\n    nacos.core.auth.server.identity.value=${NACOS_AUTH_IDENTITY_VALUE:nacos}\r\n    ## spring security config\r\n    ### turn off security\r\n    nacos.security.ignore.urls=${NACOS_SECURITY_IGNORE_URLS:\u002F,\u002Ferror,\u002F**\u002F*.css,\u002F**\u002F*.js,\u002F**\u002F*.html,\u002F**\u002F*.map,\u002F**\u002F*.svg,\u002F**\u002F*.png,\u002F**\u002F*.ico,\u002Fconsole-fe\u002Fpublic\u002F**,\u002Fv1\u002Fauth\u002F**,\u002Fv1\u002Fconsole\u002Fhealth\u002F**,\u002Factuator\u002F**,\u002Fv1\u002Fconsole\u002Fserver\u002F**}\r\n    # metrics for elastic search\r\n    management.metrics.export.elastic.enabled=false\r\n    management.metrics.export.influx.enabled=false\r\n    nacos.naming.distro.taskDispatchThreadCount=10\r\n    nacos.naming.distro.taskDispatchPeriod=200\r\n    nacos.naming.distro.batchSyncKeyCount=1000\r\n    nacos.naming.distro.initDataRatio=0.9\r\n    nacos.naming.distro.syncRetryDelay=5000\r\n    nacos.naming.data.warmup=true\r\n    nacos.console.ui.enabled=true\r\n    nacos.core.param.check.enabled=true\r\n```\r\n\r\n\r\n\r\n#### 5.2.2.2\t创建Nacos集群\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  name: nacos-svc\r\n  namespace: test\r\n  labels:\r\n    app: nacos\r\nspec:\r\n  ports:\r\n    - port: 8848\r\n      name: client-port\r\n      targetPort: 8848\r\n    - port: 9848\r\n      name: client-rpc\r\n      targetPort: 9848\r\n    - port: 9849\r\n      name: raft-rpc\r\n      targetPort: 9849\r\n  clusterIP: None\r\n  selector:\r\n    app: nacos\r\n\r\n---\r\napiVersion: apps\u002Fv1\r\nkind: StatefulSet\r\nmetadata:\r\n  name: nacos\r\n  namespace: test\r\n  labels:\r\n    app: nacos\r\nspec:\r\n  podManagementPolicy: Parallel # 配置无序启动\r\n  serviceName: nacos-svc\r\n  replicas: 3\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: nacos\r\n    spec:\r\n      containers:\r\n        - name: nacos\r\n          image: registry.cn-guangzhou.aliyuncs.com\u002Fmhui\u002Fnacos-server-pg:v2.4.0\r\n          imagePullPolicy: Always # 总是下拉新的镜像\r\n          ports:\r\n            - containerPort: 8848\r\n              name: client-port\r\n            - containerPort: 9848\r\n              name: client-rpc\r\n            - containerPort: 9849\r\n              name: raft-rpc\r\n          volumeMounts:\r\n            - name: cluster-config\r\n              mountPath: \u002Fhome\u002Fnacos\u002Fconf\u002Fcluster.conf\r\n              subPath: cluster.conf\r\n            - name: nacos-config\r\n              mountPath: \u002Fhome\u002Fnacos\u002Fconf\u002Fapplication.properties\r\n              subPath: application.properties\r\n      volumes:\r\n        - name: cluster-config    # 挂载configMap配置文件\r\n          configMap:\r\n            name: nacos-config    # 对应创建ConfigMap时的metadata.name名称\r\n            items:\r\n            - key: cluster.conf   # 配置文件中的key名称\r\n              path: cluster.conf\r\n        - name: nacos-config\r\n          configMap:\r\n            name: nacos-config    # 对应创建ConfigMap时的metadata.name名称\r\n            items:\r\n            - key: application.properties\r\n              path: application.properties\r\n  selector:\r\n    matchLabels:\r\n      app: nacos\r\n```\r\n\r\n\r\n\r\n\r\n\r\n### 5.2.4\t集群内访问\r\n\r\n在k8s集群内，任意节点的pod容器中，访问域名：\r\n\r\n- 域名：`pod名称.service名称.命名空间.svc.cluster.local`，如：`nacos-0.nacos-svc.test.svc.cluster.local:8848\u002Fnacos`\r\n- 或：`pod名称.service名称.命名空间`，如：`nacos-1.nacos-svc.test`\r\n- 或：`service名称.命名空间.svc.cluster.local`，如：`nacos-svc.test.svc.cluster.local:8848\u002Fnacos`\r\n\r\n\r\n\r\n## 5.3\t创建Ingress\r\n\r\n如果需要对外暴露，可以配置Ingress。\r\n\r\n```yaml\r\napiVersion: networking.k8s.io\u002Fv1\r\nkind: Ingress\r\nmetadata:\r\n  name: nacos-ingress\r\n  namespace: test\r\n  labels:\r\n    app: nacos\r\nspec:\r\n  rules:\r\n  - http:\r\n      paths:\r\n      - pathType: Prefix\r\n        path: \u002Fnacos\r\n        backend:\r\n          service:\r\n            name: nacos-svc\r\n            port:\r\n              number: 8848\r\n```\r\n\r\n访问：http:\u002F\u002F192.168.3.71:30509\u002Fnacos\u002F\r\n\r\n\r\n\r\n```yaml\r\napiVersion: networking.k8s.io\u002Fv1\r\nkind: Ingress\r\nmetadata:\r\n  name: postgres-ingress\r\n  namespace: test\r\n  labels:\r\n    app: postgres\r\nspec:\r\n  rules:\r\n  - host: \"postgres.k8s.com\"\r\n    http:\r\n      paths:\r\n      - pathType: Prefix\r\n        path: \u002F\r\n        backend:\r\n          service:\r\n            name: postgres-svc\r\n            port:\r\n              number: 5432\r\n```\r\n\r\n",{"_path":283,"slug":284,"title":284,"description":285,"excerpt":285,"date":229,"tags":286,"type":15,"cover":287,"content":288},"\u002Fknowledge\u002Flinux环境下tomcat的安装","linux环境下tomcat的安装","Linux环境下Tomcat安装 一 Tomcat官网下载 官网地址：https:\u002F\u002Ftomcat.apache.org\u002F 二 Tomcat安装 1 上传文件到Linux系统 ​ 步骤如下：",[124,74,183],"\u002Fknowledge-assets\u002Flinux环境下tomcat的安装\u002F官网下载.png","## Linux环境下Tomcat安装\r\n\r\n## 一\tTomcat官网下载\r\n\r\n官网地址：https:\u002F\u002Ftomcat.apache.org\u002F\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Flinux环境下tomcat的安装\u002F官网下载.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n## 二\tTomcat安装\r\n\r\n### 1\t上传文件到Linux系统\r\n\r\n​\t步骤如下：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Flinux环境下tomcat的安装\u002F上传到linux系统.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n### 2\t解压压缩包\r\n\r\n​\t进入文件所在目录：\r\n\r\n```java\r\ncd \u002Fusr\u002Flocal\u002Fsoftware\r\n```\r\n\r\n​\t解压 apache-tomcat-8.5.70.tar.gz 到当前目录：\r\n\r\n```java\r\ntar -zxvf apache-tomcat-8.5.70.tar.gz\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Flinux环境下tomcat的安装\u002Ftomcat解压.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n### 3\t移动文件\r\n\r\n```java\r\nmv apache-tomcat-8.5.70 ..\u002Fapache-tomcat-8.5.70\r\n```\r\n\r\n### 4\t启动Tomcat\r\n\r\n​\t切换到tomcat安装目录，通过命令启动tomcat\r\n\r\n```java\r\nbash startup.sh\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Flinux环境下tomcat的安装\u002Ftomcat启动.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n### 5\t浏览器访问\r\n\r\n​\t访问路径：ip+端口号。\r\n\r\n​\t我这里远程服务器ip为：124.71.226.136:8080\r\n\r\n​\t默认端口号为：8080\r\n\r\n​\t可以通过conf\u002Fserver.xml文件修改端口号。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Flinux环境下tomcat的安装\u002F远程访问tomcat首页.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n",{"_path":290,"slug":291,"title":292,"description":293,"excerpt":293,"date":229,"tags":294,"type":15,"cover":295,"content":296},"\u002Fknowledge\u002Flinux虚拟机动态ip修改成静态ip","linux虚拟机动态ip修改成静态ip","查看dns解析","**Linux虚拟机动态ip修改成静态ip** 1 进入网络配置目录 输入 ls，查看文件名是ens-32 还是ens-33，我这里是 ifcfg-ens33 2 修改文件 3 修改文件内容。可以删除全部内容，粘贴下",[124,74],"\u002Fknowledge-assets\u002Flinux虚拟机动态ip修改成静态ip\u002F网络配置文件.png","**Linux虚拟机动态ip修改成静态ip**\r\n\r\n1\t进入网络配置目录\r\n\r\n```java\r\ncd \u002Fetc\u002Fsysconfig\u002Fnetwork-scripts\u002F\r\n```\r\n\r\n输入 ls，查看文件名是ens-32  还是ens-33，我这里是 ifcfg-ens33\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Flinux虚拟机动态ip修改成静态ip\u002F网络配置文件.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n2\t修改文件\r\n\r\n```java\r\nvi ifcfg-ens33\r\n```\r\n\r\n3\t修改文件内容。可以删除全部内容，粘贴下面的内容到文件中。\r\n\r\n```java\r\n输入999dd 删除所有内容\r\n```\r\n\r\n文件内容修改如下：\r\n\r\n```shell\r\nTYPE=\"Ethernet\"\r\nPROXY_METHOD=\"none\"\r\nBROWSER_ONLY=\"no\"\r\nBOOTPROTO=\"static\"       #需要修改为static\r\nDEFROUTE=\"yes\"\r\nIPADDR=192.168.2.128     #ip地址修改\r\nGATEWAY=192.168.2.2      #网关地址修改，不可任意修改，必须参照下面的要求修改\r\nDNS1=8.8.8.8             # Google dns域名服务\r\nDNS2=114.114.114.114     # 114 DNS域名解析\r\nDNS3=223.5.5.5           # 阿里公共 DNS域名解析\r\nNAME=\"ens33\"\r\nUUID=\"ba52ece4-f2e7-44a4-a126-1e76d95a1bf2\"\r\nDEVICE=\"ens33\"\r\nONBOOT=\"yes\"\r\nZONE=public\r\n```\r\n\r\n\r\n\r\n4\t重新启动一下网络。修改完成后，保存，重新启动网络。\r\n\r\n```java\r\nsystemctl restart network\r\n```\r\n\r\n5\t检查是否能联网\r\n\r\n```java\r\nping www.baidu.com\r\n```\r\n\r\n​\t连网成功。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Flinux虚拟机动态ip修改成静态ip\u002F联网检查.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n```shell\r\n# 查看dns解析\r\ncat \u002Fetc\u002Fresolv.conf\r\n```\r\n\r\n\r\n\r\n6\t网关地址修改。\r\n\r\n​\t6.1\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Flinux虚拟机动态ip修改成静态ip\u002F查看网关地址.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n​\t6.2\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Flinux虚拟机动态ip修改成静态ip\u002F查看网关地址1.png\" style=\"zoom:70%;\" \u002F>\r\n\r\n​\t6.3\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Flinux虚拟机动态ip修改成静态ip\u002F查看网关地址2.png\" style=\"zoom:70%;\" \u002F>\n",{"_path":298,"slug":299,"title":299,"description":300,"excerpt":300,"date":229,"tags":301,"type":15,"cover":302,"content":303},"\u002Fknowledge\u002Fmaven常见问题记录","maven常见问题记录","maven常见问题记录 1、maven 引入自定义jar，打包报错（打包不会自动加载自定义jar引起的错误） 解决办法： mvn install:install-file：安装文件 -Dfile：待安装包所在位置 -DgroupId：包的GroupId -DartifactId：包的artifactId -Dversi",[136],"\u002Fknowledge-assets\u002Fmaven常见问题记录\u002Finstall_2022-09-13_11-59-35.png","# maven常见问题记录\r\n\r\n### 1、maven 引入自定义jar，打包报错（打包不会自动加载自定义jar引起的错误）\r\n\r\n解决办法：\r\n\r\n```\r\nmvn install:install-file -Dfile=E:\\openSource\\test\\itext-2.1.7.js7.jar -DgroupId=com.lowagie -DartifactId=itext -Dversion=2.1.7.js7 -Dpackaging=jar\r\n```\r\n\r\nmvn install:install-file：安装文件\r\n-Dfile：待安装包所在位置\r\n-DgroupId：包的GroupId\r\n-DartifactId：包的artifactId\r\n-Dversion：包的version\r\n-Dpackaging：包的文件类型\r\n\r\n成功安装截图：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmaven常见问题记录\u002Finstall_2022-09-13_11-59-35.png\" style=\"zoom:90%;\" \u002F>\r\n\r\n注：如：jar 最终存放本地库目录为：E:\\openSource\\mavenRepository\\com\\lowagie\\itext\\2.1.7.js7\\itext-2.1.7.js7.jar 。maven命令的 -Dfile 指定文件存放的位置不要和最终本地库存放的路径一致，否则报错。可以将jar 先放在一个临时的文件夹中。install后会jar会自动复制到最终目录，install前本地库目录也不能存在该jar。\r\n\r\n否则报错：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmaven常见问题记录\u002Finstall_2022-09-13_12-35-49.png\" style=\"zoom:90%;\" \u002F>\r\n\r\n\r\n\r\n",{"_path":305,"slug":306,"title":307,"description":308,"excerpt":308,"date":229,"tags":309,"type":15,"cover":312,"content":313},"\u002Fknowledge\u002Fmybatis源码阅读","mybatis源码阅读","MyBatis源码阅读","MyBatis源码阅读 1 MyBatis架构设计 MyBatis架构四层的作用： - API 接口层：提供增、删、改、查功能接口，通过API接口对数据库进行操作。 - 数据处理层：主要负责SQL的查询、解",[310,44,311],"MySQL","MyBatis","\u002Fknowledge-assets\u002Fmybatis源码阅读\u002FMyBatis架构设计.png","# MyBatis源码阅读\r\n\r\n## 1 MyBatis架构设计\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmybatis源码阅读\u002FMyBatis架构设计.png\" style=\"zoom:80%;\" \u002F>\r\n\r\nMyBatis架构四层的作用：\r\n\r\n - API 接口层：提供增、删、改、查功能接口，通过API接口对数据库进行操作。\r\n - 数据处理层：主要负责SQL的查询、解析、执行以及结果映射的处理，主要作用：解析SQL，根据调用请求完成一次数据库操作。\r\n - 框架支撑层：负责调用基础服务支撑，包含事务管理、连接池管理、缓存管理等公共组件的封装，为上层提供基础服务支撑。\r\n - 引导层：引导层是配置和启动MyBatis配置信息的方式。\r\n\r\n## 2 MyBatis主要组件及其相互关系\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmybatis源码阅读\u002FMyBatis核心组件及调用关系.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n## 3\t源码剖析\r\n\r\n### 3.1\t源码环境搭建\r\n\r\n#### 3.1.1\t源码下载\r\n\r\n官网: https:\u002F\u002Fmybatis.org\u002Fmybatis-3\u002Fzh\u002Findex.html\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmybatis源码阅读\u002Fmybatis官网.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n在此选择想阅读的版本下载：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmybatis源码阅读\u002Fmybatis源码下载.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n本文的分析的源码版本为: mybatis-3.5.13版本。直接跳转链接：https:\u002F\u002Fgithub.com\u002Fmybatis\u002Fmybatis-3\u002Freleases\u002Ftag\u002Fmybatis-3.5.13\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmybatis源码阅读\u002Fmybatis源码下载2.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n下载完成后，导入项目如下：\r\n\r\n注: 不同的mybatis版本，要求的jdk环境版本不同，在工程源码的`README.md`文档中标注了对应的jdk版本，本人电脑环境jdk版本为 jdk 17。\r\n\r\n#### 3.1.2\tidea导入源码工程\r\n\r\n项目结构及编写测试代码如下:\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmybatis源码阅读\u002Fmybatis源码工程.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n#### 3.1.3\tmybatis主配置类 ( mybatis-config.xml )\r\n\r\n```xml\r\n\u003C?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n\u003C!DOCTYPE configuration\r\n        PUBLIC \"-\u002F\u002Fmybatis.org\u002F\u002FDTD Config 3.0\u002F\u002FEN\"\r\n        \"https:\u002F\u002Fmybatis.org\u002Fdtd\u002Fmybatis-3-config.dtd\">\r\n\r\n\u003Cconfiguration>\r\n    \u003C!-- autoMappingBehavior should be set in each test case -->\r\n    \u003Cenvironments default=\"development\">\r\n        \u003Cenvironment id=\"development\">\r\n            \u003C!-- 使用JDBC事务管理 -->\r\n            \u003CtransactionManager type=\"JDBC\">\r\n                \u003Cproperty name=\"\" value=\"\"\u002F>\r\n            \u003C\u002FtransactionManager>\r\n            \u003C!-- 数据库连接池 -->\r\n            \u003CdataSource type=\"POOLED\">\r\n                \u003Cproperty name=\"driver\" value=\"com.mysql.cj.jdbc.Driver\"\u002F>\r\n                \u003Cproperty name=\"url\" value=\"jdbc:mysql:\u002F\u002Flocalhost:3306\u002Ftest?useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;allowPublicKeyRetrieval=true\"\u002F>\r\n                \u003Cproperty name=\"username\" value=\"root\"\u002F>\r\n                \u003Cproperty name=\"password\" value=\"admin\"\u002F>\r\n            \u003C\u002FdataSource>\r\n        \u003C\u002Fenvironment>\r\n    \u003C\u002Fenvironments>\r\n\r\n    \u003C!-- 引入映射配置文件 -->\r\n    \u003Cmappers>\r\n        \u003Cmapper resource=\"mapper\u002FUserMapper.xml\"\u002F>\r\n    \u003C\u002Fmappers>\r\n\r\n\u003C\u002Fconfiguration>\r\n```\r\n\r\n#### 3.1.4\tsql映射配置类 ( UserMapper.xml )\r\n\r\n```xml\r\n\u003C?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n\u003C!DOCTYPE mapper\r\n        PUBLIC \"-\u002F\u002Fmybatis.org\u002F\u002FDTD Mapper 3.0\u002F\u002FEN\"\r\n        \"https:\u002F\u002Fmybatis.org\u002Fdtd\u002Fmybatis-3-mapper.dtd\">\r\n\r\n\u003Cmapper namespace=\"user\">\r\n\r\n  \u003Cselect id=\"findUserById\" parameterType=\"int\" resultType=\"top.mengh.pojo.User\">\r\n    SELECT * FROM user WHERE id = #{id}\r\n  \u003C\u002Fselect>\r\n\r\n\u003C\u002Fmapper>\r\n```\r\n\r\n#### 3.1.5\tPOJO实体类\r\n\r\n```java\r\npublic class User {\r\n  private Integer id;\r\n  private String name;\r\n\r\n  @Override\r\n  public String toString() {\r\n    return \"User{\" +\r\n      \"id=\" + id +\r\n      \", name='\" + name + '\\'' +\r\n      '}';\r\n  }\r\n\r\n  public Integer getId() {\r\n    return id;\r\n  }\r\n\r\n  public void setId(Integer id) {\r\n    this.id = id;\r\n  }\r\n\r\n  public String getName() {\r\n    return name;\r\n  }\r\n\r\n  public void setName(String name) {\r\n    this.name = name;\r\n  }\r\n}\r\n```\r\n\r\n#### 3.1.6\tmysql数据库表\r\n\r\n```sql\r\nCREATE TABLE `user`  (\r\n  `id` int(0) NOT NULL,\r\n  `name` varchar(255),\r\n  PRIMARY KEY (`id`)\r\n);\r\n\r\nINSERT INTO `user` VALUES (1, '张三');\r\nINSERT INTO `user` VALUES (2, '李四');\r\n```\r\n\r\n#### 3.1.7\t测试类\r\n\r\n```java\r\npublic class MybatisTest {\r\n\r\n  \u002F**\r\n   * 测试方法: 传统方式\r\n   *\u002F\r\n  @Test\r\n  public void baseTest() throws IOException {\r\n    \u002F\u002F 1. 通过类加载器对配置文件进行加载,加载成字节输入流,存到内存中,注意:只是加载,配置文件并没有解析\r\n    InputStream inputStream = Resources.getResourceAsStream(\"mybatis-config.xml\");\r\n\r\n    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\r\n\r\n    SqlSession sqlSession = sqlSessionFactory.openSession();\r\n\r\n    User User = sqlSession.selectOne(\"user.findUserById\", 1);\r\n\r\n    sqlSession.close();\r\n\r\n    System.out.println(\"User = \" + User);\r\n    System.out.println(\"Mybatis源码环境搭建成功...\");\r\n  }\r\n}\r\n```\r\n\r\n### 3.2\t初始化-加载配置\r\n\r\n 通过类加载器对配置文件进行加载，加载成字节输入流，存到内存中，注意：只是加载，并没有解析。\r\n\r\n```java\r\n\u002F\u002F在这里并不指定加载器\r\nInputStream inputStream = Resources.getResourceAsStream(\"mybatis-config.xml\");\r\n```\r\n\r\n**Resources.java**：MyBatis源码编写的资源类\r\n\r\n```java\r\npackage org.apache.ibatis.io;\r\n\r\npublic class Resources {\r\n  private static final ClassLoaderWrapper classLoaderWrapper = new ClassLoaderWrapper();\r\n  \u002F\u002F 底层调用1\r\n  public static InputStream getResourceAsStream(String resource) throws IOException {\r\n    \u002F*不指定加载器,这里传入空的加载器*\u002F\r\n    return getResourceAsStream(null, resource);\r\n  }\r\n  \u002F\u002F 底层调用2\r\n  public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {\r\n    \u002F* classLoaderWrapper: 类加载器的包装类*\u002F\r\n    InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader);\r\n    if (in == null) {\r\n      throw new IOException(\"Could not find resource \" + resource);\r\n    }\r\n    return in;\r\n  }\r\n  \u002F\u002F.............\r\n}\r\n```\r\n\r\n**ClassLoaderWrapper.java**：类加载器的包装类，里面有多个加载器，调用该类可以轮流从多个加载器中加载资源文件，提高成功率。\r\n\r\n```java\r\npackage org.apache.ibatis.io;\r\n\r\npublic class ClassLoaderWrapper {\r\n\r\n  ClassLoader defaultClassLoader;\r\n  ClassLoader systemClassLoader;\r\n  \r\n  ClassLoaderWrapper() {\r\n    try {\r\n      systemClassLoader = ClassLoader.getSystemClassLoader();\r\n    } catch (SecurityException ignored) {\r\n      \u002F\u002F AccessControlException on Google App Engine\r\n    }\r\n  }\r\n  \u002F\u002F 底层调用3\r\n  public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {\r\n    \u002F* getClassLoaders(classLoader)方法返回5个加载器*\u002F\r\n    return getResourceAsStream(resource, getClassLoaders(classLoader));\r\n  }\r\n  \u002F\u002F 底层调用4 ，该方法返回5个加载器\r\n  ClassLoader[] getClassLoaders(ClassLoader classLoader) {\r\n    return new ClassLoader[] {\r\n      \u002F\u002F 参数指定的类加载器\r\n      classLoader,\r\n      \u002F\u002F 默认类加载器\r\n      defaultClassLoader,\r\n      \u002F\u002F 当前线程绑定的类加载器\r\n      Thread.currentThread().getContextClassLoader(),\r\n      \u002F\u002F 当前类使用的类加载器\r\n      getClass().getClassLoader(),\r\n      \u002F\u002F 系统加载器\r\n      systemClassLoader\r\n    };\r\n  }\r\n  \r\n  \u002F\u002F 底层调用5 ，从classLoader数组中(共5个加载器),选择一个能加载resource文件的加载器，加载为输入流\r\n  InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {\r\n    \u002F\u002F 从classLoader数组中,遍历每一个加载器加载resource文件,并返回输入流,加载成功直接返回,不需要继续往下加载\r\n    for (ClassLoader cl : classLoader) {\r\n      if (null != cl) {\r\n        \u002F\u002F try to find the resource as passed\r\n        InputStream returnValue = cl.getResourceAsStream(resource);\r\n        \u002F\u002F now, some class loaders want this leading \"\u002F\", so we'll add it and try again if we didn't find the resource\r\n        if (null == returnValue) {\r\n          returnValue = cl.getResourceAsStream(\"\u002F\" + resource);\r\n        }\r\n        if (null != returnValue) {\r\n          return returnValue;\r\n        }\r\n      }\r\n    }\r\n    return null; \u002F\u002F 5个加载器中都无法加载该resource配置文件（mybatis-config.xml）,则返回null\r\n  }\r\n  \u002F\u002F........\r\n}\r\n```\r\n\r\n### 3.3\t解析核心配置文件\r\n\r\nMyBatis中最重要的两个配置文件：主配置文件( `mybatis-config.xml `) 、sql映射配置文件 ( `xxxMapper.xml` ) 。\r\n\r\n`mybatis-config.xml `文件：环境信息配置( 即: 数据库连接信息、事务管理等)、插件配置、sql映射配置文件等，如下图所示。而xml中的这些信息，java通过流读取、解析，最终转换成`Configuration.java`对象存储起来，便于后续使用（数据库连接、事务管理、映射文件中的所有sql语句信息等，都直接从该对象中获取）。\r\n\r\n官网介绍: https:\u002F\u002Fmybatis.org\u002Fmybatis-3\u002Fzh\u002Fconfiguration.html\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmybatis源码阅读\u002Fmybatis主配置文件.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n`xxxMapper.xml` 文件：用于数据库数据查询，sql语句编写。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmybatis源码阅读\u002Fmybatis映射器.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n\r\n\r\n```java\r\nSqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\r\n```\r\n\r\n**SqlSessionFactoryBuilder.java** ：sql会话工厂构建类\r\n\r\n```java\r\npackage org.apache.ibatis.session;\r\n\r\npublic class SqlSessionFactoryBuilder {\r\n  \u002F\u002F调用1\r\n  public SqlSessionFactory build(InputStream inputStream) {\r\n    return build(inputStream, null, null);\r\n  }\r\n    \r\n  \u002F**\r\n   * 调用2\r\n   * @param inputStream : 主配置文件输入流\r\n   * @param environment : 决定加载哪种环境,包括数据源和事务管理器.即:\u003Cenvironment id=\"development\">中的id值;\r\n   *           如果该参数为null,那么就会使用默认的环境配置,即:\u003Cenvironments default=\"development\">中的default环境.\r\n   * @param properties : 属性配置\r\n   * @return\r\n   *\u002F\r\n  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {\r\n    try {\r\n      \u002F\u002F XMLConfigBuilder: 用来解析xml配置文件\r\n      \u002F\u002F todo 使用构建者模式: 当一个对象内部使用超过4个成员属性变量,可以使用构建者模式,在这里是用于构建configuration对象.\r\n      \u002F\u002F todo 好处: 降低耦合,分离复杂对象的创建\r\n      \u002F\u002F 调用2-1 创建XPathParser解析器对象,根据inputStream解析成了document对象,2.创建全局配置对象Configuration对象\r\n      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);\r\n      \u002F\u002F parser.parse(): 使用XPATH解析xml配置文件,将配置文件封装到Configuration对象中\r\n      \u002F\u002F 返回DefaultSqlSessionFactory对象,该对象拥有Configuration对象(即配置文件信息)\r\n      \u002F\u002F调用2-2：parser.parse()，2-3：build()\r\n      return build(parser.parse());\r\n    } catch (Exception e) {\r\n      throw ExceptionFactory.wrapException(\"Error building SqlSession.\", e);\r\n    } finally {\r\n      ErrorContext.instance().reset();\r\n      try {\r\n        if (inputStream != null) {\r\n          inputStream.close();\r\n        }\r\n      } catch (IOException e) {\r\n        \u002F\u002F Intentionally ignore. Prefer previous error.\r\n      }\r\n    }\r\n  }\r\n    \u002F\u002F......\r\n}\r\n```\r\n\r\n**XMLConfigBuilder.java** ：mybatis源码设计，主要用来解析主配置xml文件类\r\n\r\n```java\r\npackage org.apache.ibatis.builder.xml;\r\n\r\npublic class XMLConfigBuilder extends BaseBuilder {\r\n  \u002F\u002F底层调用2-1-1\r\n  public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {\r\n    this(Configuration.class, inputStream, environment, props);\r\n  }\r\n  \u002F\u002F底层调用2-1-2\r\n  public XMLConfigBuilder(Class\u003C? extends Configuration> configClass, InputStream inputStream, String environment, Properties props) {\r\n    \u002F\u002F XPathParser基于Java XPath解析器,用于解析Mybatis中的配置文件\r\n    this(configClass, new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);\r\n  }\r\n    \r\n  \u002F\u002F底层调用2-1-5\r\n  private XMLConfigBuilder(Class\u003C? extends Configuration> configClass, XPathParser parser, String environment, Properties props) {\r\n    \u002F\u002F 创建Configuration对象,并通过TypeAliasRegistry注册一些Mybatis内部相关的别名\r\n    super(newConfig(configClass));\r\n    ErrorContext.instance().resource(\"SQL Mapper Configuration\");\r\n    this.configuration.setVariables(props);\r\n    this.parsed = false;\r\n    this.environment = environment;\r\n    this.parser = parser;\r\n  }\r\n\r\n  \u002F\u002F底层调用2-2-1\r\n  public Configuration parse() {\r\n    if (parsed) {\r\n      throw new BuilderException(\"Each XMLConfigBuilder can only be used once.\");\r\n    }\r\n    parsed = true;\r\n    \u002F\u002F parser.evalNode(\"\u002Fconfiguration\"): 通过XPath解析器,从配置文件的根节点开始解析,最终将解析的内容封装到Configuration对象中\r\n    parseConfiguration(parser.evalNode(\"\u002Fconfiguration\"));\r\n    return configuration;\r\n  }\r\n\r\n  \u002F\u002F底层调用2-2-2\r\n  private void parseConfiguration(XNode root) {\r\n    try {\r\n      \u002F\u002F issue #117 read properties first\r\n      propertiesElement(root.evalNode(\"properties\"));\r\n      Properties settings = settingsAsProperties(root.evalNode(\"settings\"));\r\n      loadCustomVfs(settings);\r\n      loadCustomLogImpl(settings);\r\n      typeAliasesElement(root.evalNode(\"typeAliases\"));\r\n      pluginElement(root.evalNode(\"plugins\"));\r\n      objectFactoryElement(root.evalNode(\"objectFactory\"));\r\n      objectWrapperFactoryElement(root.evalNode(\"objectWrapperFactory\"));\r\n      reflectorFactoryElement(root.evalNode(\"reflectorFactory\"));\r\n      settingsElement(settings);\r\n      \u002F\u002F read it after objectFactory and objectWrapperFactory issue #631\r\n      \u002F* 解析\u003C\u002Fenvironments>标签*\u002F\r\n      environmentsElement(root.evalNode(\"environments\"));\r\n      databaseIdProviderElement(root.evalNode(\"databaseIdProvider\"));\r\n      typeHandlerElement(root.evalNode(\"typeHandlers\"));\r\n      \u002F* 解析\u003C\u002Fmappers>标签,加载映射文件流程主入口*\u002F\r\n      mapperElement(root.evalNode(\"mappers\"));\r\n    } catch (Exception e) {\r\n      throw new BuilderException(\"Error parsing SQL Mapper Configuration. Cause: \" + e, e);\r\n    }\r\n  }\r\n  \r\n  \u002F\u002F 解析\u003C\u002Fenvironments>标签\r\n  private void environmentsElement(XNode context) throws Exception {\r\n    if (context != null) {\r\n      if (environment == null) {\r\n        environment = context.getStringAttribute(\"default\");\r\n      }\r\n      \u002F\u002F 遍历解析\u003Cenvironment>节点\r\n      for (XNode child : context.getChildren()) {\r\n        String id = child.getStringAttribute(\"id\");\r\n        \u002F\u002F 判断\u003Cenvironment>节点id和\u003Cenvironments>指定的id值是否相等\r\n        if (isSpecifiedEnvironment(id)) {\r\n          \u002F\u002F 事务工厂\r\n          TransactionFactory txFactory = transactionManagerElement(child.evalNode(\"transactionManager\"));\r\n          \u002F\u002F 连接池工厂\r\n          DataSourceFactory dsFactory = dataSourceElement(child.evalNode(\"dataSource\"));\r\n          DataSource dataSource = dsFactory.getDataSource();\r\n          Environment.Builder environmentBuilder = new Environment.Builder(id).transactionFactory(txFactory)\r\n              .dataSource(dataSource);\r\n          configuration.setEnvironment(environmentBuilder.build());\r\n          break;\r\n        }\r\n      }\r\n    }\r\n  }\r\n    \r\n  \u002F\u002F解析数据源配置节点,并创建连接池工厂\r\n  private DataSourceFactory dataSourceElement(XNode context) throws Exception {\r\n    if (context != null) {\r\n      \u002F\u002F 获取连接池类型\r\n      String type = context.getStringAttribute(\"type\");\r\n      \u002F\u002F 获取数据库连接四要素信息\r\n      Properties props = context.getChildrenAsProperties();\r\n      \u002F\u002F 通过连接池类型名称,首先从mybatis设计的TypeAliasRegistry自定义类型注册器中获取，\r\n      \u002F\u002F 如果不存在(即第三方类),最终才调用类加载器Class.forName(name)加载，然后再通过反射创建连接池工厂对象\r\n      DataSourceFactory factory = (DataSourceFactory) resolveClass(type).getDeclaredConstructor().newInstance();\r\n      factory.setProperties(props);\r\n      return factory;\r\n    }\r\n    throw new BuilderException(\"Environment declaration requires a DataSourceFactory.\");\r\n  }\r\n    \r\n    \r\n  \u002F\u002F 解析\u003C\u002Fmappers>标签,加载映射文件流程主入口\r\n  private void mapperElement(XNode parent) throws Exception {\r\n    if (parent != null) {\r\n      for (XNode child : parent.getChildren()) {\r\n        if (\"package\".equals(child.getName())) {\r\n          String mapperPackage = child.getStringAttribute(\"name\");\r\n          configuration.addMappers(mapperPackage);\r\n        } else {\r\n          String resource = child.getStringAttribute(\"resource\");\r\n          String url = child.getStringAttribute(\"url\");\r\n          String mapperClass = child.getStringAttribute(\"class\");\r\n          \u002F\u002F 一个\u003Cmapper> 标签中不能同时存在resource、url、class三种类型,最多只能存在一种\r\n          if (resource != null && url == null && mapperClass == null) {\r\n            ErrorContext.instance().resource(resource);\r\n            \u002F\u002F 将映射文件,如: resource=\"mapper\u002FUserMapper.xml\"文件,加载成数据输入流\r\n            try (InputStream inputStream = Resources.getResourceAsStream(resource)) {\r\n              \u002F\u002F 创建一个映射配置xml解析器，在里面创建XPathParser解析器,并将输入流转换成document对象\r\n              XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource,\r\n                  configuration.getSqlFragments());\r\n              \u002F\u002F 解析映射文件(即UserMapper.xml)内容,并封装到Configuration对象中\r\n              mapperParser.parse();\r\n            }\r\n          } else if (resource == null && url != null && mapperClass == null) {\r\n            ErrorContext.instance().resource(url);\r\n            try (InputStream inputStream = Resources.getUrlAsStream(url)) {\r\n              XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url,\r\n                  configuration.getSqlFragments());\r\n              \u002F\u002F 解析映射文件内容\r\n              mapperParser.parse();\r\n            }\r\n          } else if (resource == null && url == null && mapperClass != null) {\r\n            \u002F\u002F 代理的方式\r\n            Class\u003C?> mapperInterface = Resources.classForName(mapperClass);\r\n            configuration.addMapper(mapperInterface);\r\n          } else {\r\n            throw new BuilderException(\r\n                \"A mapper element may only specify a url, resource or class, but not more than one.\");\r\n          }\r\n        }\r\n      }\r\n    }\r\n  }\r\n    \r\n    \r\n    \r\n    \r\n}\r\n```\r\n\r\n\r\n\r\n```java\r\npackage org.apache.ibatis.builder.xml;\r\n\r\npublic class XMLMapperBuilder extends BaseBuilder {\r\n    \r\n  public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource,\r\n      Map\u003CString, XNode> sqlFragments) {\r\n    \u002F\u002F 创建XPathParser解析器,并将输入流转换成document对象\r\n    this(new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()), configuration,\r\n        resource, sqlFragments);\r\n  }\r\n\r\n  private XMLMapperBuilder(XPathParser parser, Configuration configuration, String resource,\r\n      Map\u003CString, XNode> sqlFragments) {\r\n    super(configuration);\r\n    this.builderAssistant = new MapperBuilderAssistant(configuration, resource);\r\n    this.parser = parser;\r\n    this.sqlFragments = sqlFragments;\r\n    this.resource = resource;\r\n  }\r\n\r\n  public void parse() {\r\n    \u002F\u002Fresource: 映射文件名称(如:mapper\u002FUserMapper.xml),这里判断的意思是只解析一次，如果已经解析过则不再解析\r\n    if (!configuration.isResourceLoaded(resource)) {\r\n      \u002F\u002F 解析映射文件(即:UserMapper.xml)中的\u003C\u002Fmapper>根节点\r\n      configurationElement(parser.evalNode(\"\u002Fmapper\"));\r\n      configuration.addLoadedResource(resource);\r\n      bindMapperForNamespace();\r\n    }\r\n\r\n    parsePendingResultMaps();\r\n    parsePendingCacheRefs();\r\n    parsePendingStatements();\r\n  }\r\n    \r\n  \u002F\u002F 解析映射文件(如:UserMapper.xml)中的\u003C\u002Fmapper>根节点\r\n  private void configurationElement(XNode context) {\r\n    try {\r\n      \u002F\u002F 映射文件的命名空间\r\n      String namespace = context.getStringAttribute(\"namespace\");\r\n      if (namespace == null || namespace.isEmpty()) {\r\n        throw new BuilderException(\"Mapper's namespace cannot be empty\");\r\n      }\r\n      builderAssistant.setCurrentNamespace(namespace);\r\n      cacheRefElement(context.evalNode(\"cache-ref\"));\r\n      cacheElement(context.evalNode(\"cache\"));\r\n      parameterMapElement(context.evalNodes(\"\u002Fmapper\u002FparameterMap\"));\r\n      resultMapElements(context.evalNodes(\"\u002Fmapper\u002FresultMap\"));\r\n      sqlElement(context.evalNodes(\"\u002Fmapper\u002Fsql\"));\r\n      \u002F\u002F 解析映射文件中的sql语句\r\n      buildStatementFromContext(context.evalNodes(\"select|insert|update|delete\"));\r\n    } catch (Exception e) {\r\n      throw new BuilderException(\"Error parsing Mapper XML. The XML location is '\" + resource + \"'. Cause: \" + e, e);\r\n    }\r\n  }\r\n\r\n  \u002F\u002F 解析select|insert|update|delete节点列表\r\n  private void buildStatementFromContext(List\u003CXNode> list) {\r\n    if (configuration.getDatabaseId() != null) {\r\n      buildStatementFromContext(list, configuration.getDatabaseId());\r\n    }\r\n    buildStatementFromContext(list, null);\r\n  }\r\n    \r\n    \r\n}\r\n```\r\n\r\n\r\n\r\n\r\n\r\nXPathParser.java类：基于Java XPath解析器，用于解析Mybatis中所有xml的配置文件\r\n\r\n```java\r\npackage org.apache.ibatis.parsing;\r\n\r\npublic class XPathParser {\r\n\r\n  private final Document document;\r\n  private boolean validation;\r\n  private EntityResolver entityResolver;\r\n  private Properties variables;\r\n  private XPath xpath;\r\n\r\n  public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {\r\n    commonConstructor(validation, variables, entityResolver);\r\n    \u002F\u002F 解析xml配置文件为document对象\r\n    this.document = createDocument(new InputSource(inputStream));\r\n  }\r\n  \r\n  \u002F\u002F将输入流通过dom解析，转成document对象\r\n  private Document createDocument(InputSource inputSource) {\r\n    \u002F\u002F important: this must only be called AFTER common constructor\r\n    try {\r\n      \u002F\u002F java原生解析xml的document创建工厂\r\n      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();\r\n      \u002F\u002F 进行dtd或者schema校验\r\n      factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);\r\n      factory.setValidating(validation);\r\n\r\n      factory.setNamespaceAware(false);\r\n      \u002F\u002F 设置忽略注释为true\r\n      factory.setIgnoringComments(true);\r\n      \u002F\u002F 设置是否忽略元素内容中的空白\r\n      factory.setIgnoringElementContentWhitespace(false);\r\n      factory.setCoalescing(false);\r\n      factory.setExpandEntityReferences(true);\r\n\t  \u002F\u002Fjava 原生DocumentBuilder类\r\n      DocumentBuilder builder = factory.newDocumentBuilder();\r\n      builder.setEntityResolver(entityResolver);\r\n      builder.setErrorHandler(new ErrorHandler() {\r\n        \u002F\u002F.....\r\n      });\r\n      \u002F\u002F java原生通过dom解析,获取document对象\r\n      return builder.parse(inputSource);\r\n    } catch (Exception e) {\r\n      throw new BuilderException(\"Error creating document instance.  Cause: \" + e, e);\r\n    }\r\n  }\r\n  \u002F\u002F.......\r\n}\r\n```\r\n\r\n### 3.4\t解析映射配置文件\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmybatis源码阅读\u002Fmybatis映射配置文件.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n映射配置文件大体内容如下:\r\n\r\n```xml\r\n\u003Cmapper namespace=\"user\">\r\n\r\n  \u003Cselect id=\"findUserById\" parameterType=\"int\" resultType=\"top.mengh.pojo.User\">\r\n    SELECT * FROM user WHERE id = #{id}\r\n  \u003C\u002Fselect>\r\n\r\n\u003C\u002Fmapper>\r\n```\r\n\r\n重点: \r\n\r\n- 映射配置文件中的标签和属性如何解析封装\r\n- sql占位符如何替换成问号( 即: SELECT * FROM user WHERE id = ? )\r\n- 动态sql如何进行解析\r\n\r\n\r\n\r\n\r\n\r\n### 3.5\t解析SqlSource流程\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n",{"_path":315,"slug":316,"title":317,"description":318,"excerpt":318,"date":229,"tags":319,"type":15,"cover":320,"content":321},"\u002Fknowledge\u002Fmysqlbinlog恢复数据","mysqlbinlog恢复数据","MySQL binlog恢复数据","MySQL binlog恢复数据 1 基本操作 1.1 查看是否开启binlog日志 1.2 获取binlog文件列表 1.3 查看第一个binlog文件的内容 1.4 查看当前正在写入的binlog文件 1.5 查看指定binlog文件的内容 1.5.1 方式一",[310],"\u002Fknowledge-assets\u002Fmysqlbinlog恢复数据\u002Fshow-binlog-01.png","# MySQL binlog恢复数据\r\n\r\n## 1\t基本操作\r\n\r\n### 1.1\t查看是否开启binlog日志\r\n\r\n```sql\r\nshow variables like 'log_%';\r\n```\r\n\r\n### 1.2\t获取binlog文件列表 \r\n\r\n```sql\r\nshow binary logs;\r\n#或\r\nshow master logs;\r\n```\r\n\r\n### 1.3\t查看第一个binlog文件的内容\r\n\r\n```sql\r\nshow binlog events; \r\n```\r\n\r\n### 1.4\t查看当前正在写入的binlog文件\r\n\r\n```sql\r\nshow master status;\r\n```\r\n\r\n### 1.5\t查看指定binlog文件的内容 \r\n\r\n#### 1.5.1\t方式一\r\n\r\n```sql\r\nshow binlog events in 'binlog.000001';\r\nshow binlog events in 'binlog.000005';\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmysqlbinlog恢复数据\u002Fshow-binlog-01.png\" style=\"zoom:85%;\" \u002F>\r\n\r\n#### 1.5.2\t方式二：使用mysqlbinlog 工具\r\n\r\n```sql\r\nmysqlbinlog binlog.000005\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmysqlbinlog恢复数据\u002Fshow-binlog-02.png\" style=\"zoom:85%;\" \u002F>\r\n\r\n### 1.6\t刷新日志\r\n\r\n```sql\r\n#此刻开始产生一个新编号的binlog，如 binlog.000003\r\n#每当mysqld服务重启时，也会自动执行刷新binlog日志命令\r\nFlush logs;\r\n```\r\n\r\n### 1.7\t清空所有binlog日志\r\n\r\n```sql\r\nreset master;\r\n```\r\n\r\n### 1.8\t恢复日志\r\n\r\n#### 1.8.1\t寻找开始的节点与结束的节点\r\n\r\n```sql\r\nmysqlbinlog binlog.000005\r\n```\r\n\r\n#### 1.8.2\t生成导出数据\r\n\r\n```sql\r\nmysqlbinlog --start-position [开始节点]  --stop-position [结束节点] \u002Fvar\u002Flib\u002Fmysql\u002Fbinlog.000005 > test.sql\r\n#示例：\r\nmysqlbinlog --start-position 326  --stop-position 1218 \u002Fvar\u002Flib\u002Fmysql\u002Fbinlog.000006 > test.sql\r\n```\r\n\r\n#### 1.8.3\t导入数据库\r\n\r\n```sql\r\nmysql -uroot -proot \u003C test.sql\r\n#或\r\nmysql -uroot -p \u003C test.sql\r\n```\r\n\r\n#### 1.8.4\t合并一次性导入\r\n\r\n```sql\r\n.\u002Fmysqlbinlog --start-position [开始节点] --stop-position [结束节点] \u002Fvar\u002Flib\u002Fmysql\u002Fbinlog.000005 ｜ mysql -uroot -proot\r\n#示例：\r\nmysqlbinlog --start-position 2841 --stop-position 3733 \u002Fvar\u002Flib\u002Fmysql\u002Fbinlog.000006 ｜ \u002Fusr\u002Fbin\u002Fmysql -uroot -p\r\n```\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n",{"_path":323,"slug":324,"title":325,"description":326,"excerpt":326,"date":229,"tags":327,"type":15,"cover":328,"content":329},"\u002Fknowledge\u002Fmysql安装","mysql安装","MySQL 数据库安装","MySQL 数据库安装 1 window环境安装 官网下载 https:\u002F\u002Fdev.mysql.com\u002Fdownloads\u002Fmysql\u002F 进入官网下载window版本。 2 Linux环境安装 2.1 mysql8.0.31 在线安装 2.1.1 官网下载安装包 ​ 官网下载地址：https:\u002F\u002Fdev.mysql.c",[310,124],"\u002Fknowledge-assets\u002Fmysql安装\u002Fdownload.png","# MySQL 数据库安装\r\n\r\n# 1\twindow环境安装\r\n\r\n官网下载 https:\u002F\u002Fdev.mysql.com\u002Fdownloads\u002Fmysql\u002F 进入官网下载window版本。\r\n\r\n\r\n\r\n# 2\tLinux环境安装\r\n\r\n## 2.1\tmysql8.0.31 在线安装\r\n\r\n### 2.1.1\t官网下载安装包\r\n\r\n​\t\t官网下载地址：https:\u002F\u002Fdev.mysql.com\u002Fdownloads\u002Fmysql\u002F \r\n\r\n​\t\t进入官网下载对应的系统及数据库版本。如：服务器操作系统为x86_64：CentOS 8.2 64bit ，下载类型选择如下图所示。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmysql安装\u002Fdownload.png\" style=\"zoom:75%;\" \u002F>\r\n\r\n### 2.1.2\t仅下载所需要用的安装包\r\n\r\nmysql5.7 只需要下载：\r\n\r\n```\r\nmysql-community-common-5.7.22-1.el7.x86_64.rpm\r\nmysql-community-client-5.7.22-1.el7.x86_64.rpm\r\nmysql-community-libs-5.7.22-1.el7.x86_64.rpm\r\nmysql-community-server-5.7.22-1.el7.x86_64.rpm\r\n```\r\n\r\nmysql8.0 需要下载：\r\n\r\n```\r\nmysql-community-common-8.0.31-1.el8.x86_64.rpm\r\nmysql-community-libs-8.0.31-1.el8.x86_64.rpm\r\nmysql-community-client-8.0.31-1.el8.x86_64.rpm\r\nmysql-community-server-8.0.31-1.el8.x86_64.rpm\r\nmysql-community-client-plugins-8.0.31-1.el8.x86_64.rpm\r\nmysql-community-icu-data-files-8.0.31-1.el8.x86_64.rpm\r\n```\r\n\r\n### 2.1.3\t安装RPM包\r\n\r\n(1)先把postfix 和mariadb-libs卸载掉，不然的会有依赖包冲突\r\n\r\n```\r\nrpm -e postfix mariadb-libs\r\n```\r\n\r\n(2)安装mysql的依赖net-tools和 perl\r\n\r\n```\r\nyum -y install net-tools perl\r\n```\r\n\r\n(3)安装mysql-common包\r\n\r\n```\r\nrmp -ivh mysql-community-common-8.0.31-1.el8.x86_64.rpm\r\n```\r\n\r\n(4)安装mysql-libs包\r\n\r\n```\r\nrpm -ivh mysql-community-libs-8.0.31-1.el8.x86_64.rpm\r\n```\r\n\r\nmysql8.0安装libs包的时候会报错，缺少依赖包：mysql-community-client-plugins。\r\n\r\nerror: Failed dependencies:\r\n        mysql-community-client-plugins = 8.0.31-1.el8 is needed by mysql-community-libs-8.0.31-1.el8.x86_64\r\n\r\n则需要先安装缺少的依赖，再安装libs包，安装依赖包命令如下：\r\n\r\n```\r\nrpm -ivh mysql-community-client-plugins-8.0.31-1.el8.x86_64.rpm\r\n```\r\n\r\n(5)安装mysql-client包\r\n\r\n```\r\nrpm -ivh mysql-community-client-8.0.31-1.el8.x86_64.rpm\r\n```\r\n\r\n(6)安装mysql-server包\r\n\r\n```\r\nrpm -ivh mysql-community-server-8.0.31-1.el8.x86_64.rpm\r\n```\r\n\r\nmysql8.0安装libs包的时候会报错，缺少依赖包：mysql-community-icu-data-files。\r\n\r\nerror: Failed dependencies:\r\n        mysql-community-icu-data-files = 8.0.31-1.el8 is needed by mysql-community-server-8.0.31-1.el8.x86_64\r\n\r\n则需要先安装缺少的依赖，再安装libs包，安装依赖包命令如下：\r\n\r\n```\r\nrpm -ivh mysql-community-icu-data-files-8.0.31-1.el8.x86_64.rpm\r\n```\r\n\r\n### 2.1.4\t安装后配置\r\n\r\n#### 2.1.4.1\t启动MySQL服务\r\n\r\n(1)设置开机启动\r\n\r\n```\r\nsystemctl enable mysqld\r\n```\r\n\r\n(2)启动MySql服务\r\n\r\n```\r\nsystemctl start mysqld\r\n```\r\n\r\n(3)查看mysql是否启动成功\r\n\r\n```\r\nps -aux | grep mysql\r\n```\r\n\r\n#### 2.1.4.2\t修改root密码\r\n\r\n(1)获取临时密码\r\n\r\n​\t由于MySQL5.7、8.0安装好后会给root用户分配一个临时密码，所以我们先查看临时密码：\r\n\r\n```\r\ngrep 'temporary password' \u002Fvar\u002Flog\u002Fmysqld.log\r\n```\r\n\r\n```\r\n[root@VM-20-2-centos log]# grep 'temporary password' \u002Fvar\u002Flog\u002Fmysqld.log\r\n2022-10-20T03:18:04.265586Z 6 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: (QxfU?l0ejU=\r\n```\r\n\r\nroot@localhost冒号后面的就是root用户的临时密码：(QxfU?l0ejU=\r\n\r\n(2)使用临时密码登录\r\n\r\n```\r\nmysql -u root -p\r\n```\r\n\r\n回车后输入上面的临时密码。\r\n\r\n(3)修改密码\r\n\r\n```\r\n#如修改密码为!QAZzaq1\r\nmysql> ALTER USER 'root'@'localhost' IDENTIFIED BY '!QAZzaq1';\r\nQuery OK, 0 rows affected (0.03 sec)\r\n\r\nmysql> FLUSH PRIVILEGES;\r\nQuery OK, 0 rows affected (0.00 sec)\r\n\r\nmysql> exit\r\n```\r\n\r\n***注意：mysql5.7、8.0增加了安全级别，密码必须包含：大小写字母、数字和特殊符号，并且长度不能少于8位。***\r\n\r\n#### 2.1.4.3\t（可选）开放远程访问\r\n\r\n​\t\tmysql5.7和8.0语法有区别，有些不支持。\r\n\r\nmysql5.7授权命令：\r\n\r\n```\r\nmysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '!QAZzaq1'  WITH GRANT OPTION;\r\nmysql> FLUSH PRIVILEGES;\r\n```\r\n\r\nmysql8.0授权命令：\r\n\r\n```\r\nGRANT ALL ON *.* TO 'root'@'%';\r\nFLUSH PRIVILEGES;\r\n```\r\n\r\n8.0版本授权时如果报以下错误，则：\r\n\r\n```\r\nmysql> GRANT ALL ON *.* TO 'root'@'%';\r\nERROR 1410 (42000): You are not allowed to create a user with GRANT\r\n\r\nmysql> show databases;\r\n\r\n#进入mysql数据库；\r\nmysql> use mysql;\r\n\r\n#查看root用户是否具有权限，和host主机地址是否为%\r\nmysql> select host,user,grant_priv from user;\r\n+-----------+------------------+------------+\r\n| host      | user             | grant_priv |\r\n+-----------+------------------+------------+\r\n| localhost | root             | Y          |\r\n| localhost | mysql.infoschema | N          |\r\n| localhost | mysql.session    | N          |\r\n| localhost | mysql.sys        | N          |\r\n+-----------+------------------+------------+\r\n\r\n#修改root用户host为%\r\nmysql> update user set host='%' where user='root';\r\nQuery OK, 1 row affected (0.03 sec)\r\nRows matched: 1  Changed: 1  Warnings: 0\r\n\r\n#再次授权\r\nmysql> GRANT ALL ON *.* TO 'root'@'%';\r\n\r\n#刷新权限\r\nmysql> FLUSH PRIVILEGES;\r\n```\r\n\r\n\r\n\r\n## 2.2\tmysql8.0.27在线安装\r\n\r\n### 2.2.1\t下载\r\n\r\n```shell\r\n# 下载\r\nwget https:\u002F\u002Fdev.mysql.com\u002Fget\u002FDownloads\u002FMySQL-8.0\u002Fmysql-8.0.27-1.el7.x86_64.rpm-bundle.tar\r\n\r\n# 解压\r\ntar -xvf mysql-8.0.27-1.el7.x86_64.rpm-bundle.tar\r\n```\r\n\r\n### 2.2.2\t安装RPM包\r\n\r\n```shell\r\n# 顺序安装RPM包\r\nrpm -ivh mysql-community-common-8.0.27-1.el7.x86_64.rpm\r\nrpm -ivh mysql-community-client-plugins-8.0.27-1.el7.x86_64.rpm\r\nrpm -ivh mysql-community-libs-8.0.27-1.el7.x86_64.rpm\r\nrpm -ivh mysql-community-client-8.0.27-1.el7.x86_64.rpm\r\nrpm -ivh mysql-community-server-8.0.27-1.el7.x86_64.rpm\r\n```\r\n\r\n若遇到依赖问题，可尝试使用 `--nodeps --force` 选项（需谨慎）。\r\n\r\n### 2.2.3\t安装后配置（通用）\r\n\r\n#### 2.2.3.1\t启动 MySQL 服务\r\n\r\n```shell\r\n# 启动mysql服务\r\nsystemctl start mysqld\r\n# 配置开机启动\r\nsystemctl enable mysqld\r\n```\r\n\r\n#### 2.2.3.2\t修改root密码\r\n\r\n（1）获取临时密码：\r\n\r\n​\t由于MySQL5.7、8.0安装好后会给root用户分配一个临时密码，所以我们先查看临时密码：\r\n\r\n```\r\ngrep 'temporary password' \u002Fvar\u002Flog\u002Fmysqld.log\r\n```\r\n\r\n```\r\n[root@dm01 mysql]# grep 'temporary password' \u002Fvar\u002Flog\u002Fmysqld.log\r\n2025-09-22T00:40:42.492137Z 6 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: EohA,ZNDR8,k\r\n```\r\n\r\n​\troot@localhost冒号后面的就是root用户的临时密码：EohA,ZNDR8,k\r\n\r\n(2)使用临时密码登录\r\n\r\n```shell\r\nmysql -u root -p\r\n```\r\n\r\n​\t回车后输入上面的临时密码。\r\n\r\n(3)修改密码\r\n\r\n```sql\r\n-- 如修改密码为!QAZzaq1\r\nmysql> ALTER USER 'root'@'localhost' IDENTIFIED BY '!QAZzaq1';\r\nQuery OK, 0 rows affected (0.03 sec)\r\n\r\nmysql> FLUSH PRIVILEGES;\r\nQuery OK, 0 rows affected (0.00 sec)\r\n\r\nmysql> exit\r\n```\r\n\r\n***注意：mysql5.7、8.0增加了安全级别，密码必须包含：大小写字母、数字和特殊符号，并且长度不能少于8位。***\r\n\r\n#### 2.2.3.3\t（可选）配置远程访问\r\n\r\n```sql\r\n-- 选择数据库\r\nmysql> use mysql;\r\n\r\n-- 查看用户表\r\nmysql> select host,user,grant_priv from user;\r\n+-----------+------------------+------------+\r\n| host      | user             | grant_priv |\r\n+-----------+------------------+------------+\r\n| localhost | mysql.infoschema | N          |\r\n| localhost | mysql.session    | N          |\r\n| localhost | mysql.sys        | N          |\r\n| localhost | root             | Y          |\r\n+-----------+------------------+------------+\r\n4 rows in set (0.00 sec)\r\n\r\n-- 开放root账号远程访问\r\nmysql> update user set host='%' where user='root';\r\nQuery OK, 1 row affected (0.00 sec)\r\n\r\n-- 刷新权限\r\nmysql> FLUSH PRIVILEGES;\r\n```\r\n\r\n#### 2.2.3.4（可选）配置 `my.cnf`\r\n\r\n可根据需要编辑 `\u002Fetc\u002Fmy.cnf`，例如设置字符集：\r\n\r\n```shell\r\n[mysqld]\r\ncharacter-set-server=utf8mb4\r\ncollation-server=utf8mb4_unicode_ci\r\ndefault_authentication_plugin=mysql_native_password  # 可选，解决某些客户端连接问题:cite[2]\r\n```\r\n\r\n修改配置后重启服务生效：\r\n\r\n```shell\r\nsystemctl restart mysqld\r\n```\r\n\r\n\r\n\r\n## 2.2\tCentOS 离线安装8.X\r\n\r\n### 2.2.1 MySQL官网下载\r\n\r\n#### 2.2.1.1\t查看glibc版本\r\n\r\n检查Linux服务器C语言标准库版本，mysql基于C编写，因此需要C环境，官网上只需要下载该基于glibc版本的mysql即可。\r\n\r\n```shell\r\nldd --version\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmysql安装\u002Fldd.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n#### 2.2.1.2\t[官网下载](https:\u002F\u002Fdev.mysql.com\u002Fdownloads\u002Fmysql\u002F)\r\n\r\n下载地址：https:\u002F\u002Fdev.mysql.com\u002Fdownloads\u002Fmysql\u002F，MySQL是收费的，社区版是不收费的，所以市面上大家都用社区版。下载跟Linux服务器适配的glibc环境，安装时就不用再安装C语言标准库。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmysql安装\u002Fdownload8.4.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n点击【开始下载】：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmysql安装\u002Fdownload8.4-2.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n### 2.2.2\t安装前检查\r\n\r\n#### 2.2.2.1\t检查是否安装有mysql\r\n\r\n```shell\r\nrpm -qa |grep -i mysql\r\n\r\n# yum卸载\r\nyum remove mysql80-community-release-el8-1.noarch\r\nyum remove mysql-community-server-8.0.27-1.el8.x86_64\r\n# 也可以用rpm卸载\r\nrpm -ev mysql80-community-release-el7-7.noarch\r\nrpm -ev mysql-community-client-plugins-8.0.22-1.ky3.kb1.x86_64\r\n```\r\n\r\n#### 2.2.2.2\t检查是否安装有mariadb\r\n\r\n```shell\r\nrpm -qa | grep mariadb\r\n\r\n# 使用rpm卸载\r\nrpm -e --nodeps mariadb-libs-5.5.56-2.el7.x86_64\r\n```\r\n\r\n#### 2.2.2.3\t安装前先关闭 selinux\r\n\r\nSELinux（Security-Enhanced Linux）是 Linux 系统的一个安全模块，主要用于加强系统的安全性。它通过强制访问控制（MAC）来限制进程和用户对系统资源（如文件、端口等）的访问。即使某个进程或用户具有某些权限，SELinux 也可以通过策略来限制其操作，防止潜在的安全风险。\r\n\r\n- **关闭 SELinux 的好处**\r\n  - 减少兼容性问题：一些旧的应用程序或服务可能与 SELinux 不兼容，关闭 SELinux 可以避免这些问题。\r\n  - 简化配置和管理：SELinux 配置和管理较为复杂，关闭它可以简化系统管理，减少安全配置的工作量。\r\n  - 提高系统性能：虽然性能影响通常较小，但在高负载的情况下，SELinux 的安全检查可能会带来额外的性能开销，关闭它可以稍微提高系统性能。\r\n\r\n- **关闭 SELinux 的风险**\r\n  - 关闭 SELinux 会降低系统的安全性，特别是在遭遇外部攻击时，可能增加系统被入侵的风险。因此，如果没有特别的兼容性需求，建议在生产环境中保持 SELinux 启用。\r\n\r\n```shell\r\nvi \u002Fetc\u002Fselinux\u002Fconfig\r\n# 将SELINUX 的值 修改为disabled\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmysql安装\u002Fselinux.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n- `disabled`：SELinux 已禁用。\r\n- `enforcing`：SELinux 处于启用并强制执行模式。\r\n- `permissive`：SELinux 处于启用，打印警告但不强制执行模式\r\n\r\n\r\n\r\n### 2.2.3\t开始安装\r\n\r\n#### 2.2.3.1\t上传并解压\r\n\r\n```shell\r\ncd \u002Fusr\u002Flocal\r\n\r\n# 解压 tar.xz 文件使用：tar -xf 命令\r\ntar -xvf mysql-8.4.4-linux-glibc2.17-x86_64.tar.xz\r\n```\r\n\r\n#### 2.2.3.2\t重命名\r\n\r\n```shell\r\nmv mysql-8.4.4-linux-glibc2.17-x86_64 mysql-8.4.4\r\n```\r\n\r\n\r\n\r\n#### 2.2.3.3\t配置环境变量\r\n\r\n```shell\r\nvi \u002Fetc\u002Fprofile\r\n文件末尾添加：\r\nexport PATH=$PATH:\u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fbin\r\n# 重新加载环境变量\r\nsource \u002Fetc\u002Fprofile\r\n```\r\n\r\n#### 2.2.3.4\t创建用户\r\n\r\n```shell\r\n#创建mysql用户组和用户并准备MySQL数据库的存储目录\r\n#创建一个新的用户组，命名为“mysql”\r\ngroupadd mysql\r\n#创建一个新的用户，命名为“mysql”\r\nuseradd -r -g mysql mysql\r\n#设置MySQL数据库的存储目录及其权限\r\n#创建目录\r\nmkdir -p \u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fdata\r\n#修改权限\r\nchown mysql:mysql -R \u002Fusr\u002Flocal\u002Fmysql-8.4.4\r\n\r\n# 切换到mysql用户操作\r\nsu - mysql\r\n```\r\n\r\n#### 2.2.3.5\t添加配置文件\r\n\r\n```shell\r\nmkdir \u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fconf\r\nvi \u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fconf\u002Fmy.cnf\r\n```\r\n\r\nmy.cnf配置内容：\r\n\r\n```properties\r\n[mysql]\r\n# 默认字符集\r\ndefault-character-set=utf8mb4\r\n[client]\r\nport       = 3306\r\nsocket     = \u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fdata\u002Fmysql.sock\r\n[mysqld]\r\nport       = 3306\r\nserver-id  = 1\r\nuser       = root\r\nsocket     = \u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fdata\u002Fmysql.sock\r\n# 安装目录 \r\nbasedir    = \u002Fusr\u002Flocal\u002Fmysql-8.4.4\r\n# 数据存放目录\r\ndatadir    = \u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fdata\r\nlog-bin    = mysql-bin\r\ninnodb_data_home_dir      =\u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fdata\r\ninnodb_log_group_home_dir =\u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fdata\r\n# 日志及进程数据的存放目录\r\nlog-error =\u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fdata\u002Fmysql.log\r\npid-file  =\u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fdata\u002Fmysql.pid\r\n# 服务端字符集\r\ncharacter-set-server=utf8mb4\r\n# 区分大小写\r\nlower_case_table_names=0\r\n```\r\n\r\n\r\n\r\n#### 2.2.3.6\t初始化数据库\r\n\r\n```shell\r\nmysqld --defaults-file=\u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fconf\u002Fmy.cnf --basedir=\u002Fusr\u002Flocal\u002Fmysql-8.4.4 --datadir=\u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fdata --user=mysql --initialize-insecure\r\n\r\n\r\n参数说明：\r\n–defaults-file：指定配置文件（要放在–initialize 前面）\r\n–user： 指定用户，必须和my.cnf中指定的一样\r\n–basedir：指定安装目录\r\n–datadir：指定初始化数据目录\r\n–intialize-insecure：初始化无密码（否则生成随机密码）\r\n```\r\n\r\n#### 2.2.3.7\t启\u002F停数据库\r\n\r\n```shell\r\n\u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fbin\u002Fmysqld_safe --defaults-file=\u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fconf\u002Fmy.cnf &\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmysql安装\u002Fstart.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n登录并设置密码：\r\n\r\n```shell\r\n# 首次登录无密码\r\nmysql -u root --skip-password\r\n# 设置密码，如：admin\r\nalter user 'root'@'localhost' identified by 'admin';\r\n# 刷新权限\r\nFLUSH PRIVILEGES;\r\n```\r\n\r\n开启远程访问：\r\n\r\n```shell\r\n# 开启远程访问\r\nselect host,user,plugin from mysql.user;\r\n#修改root用户host为%\r\nupdate mysql.user set host = '%' where user='root';\r\n#刷新权限\r\nFLUSH PRIVILEGES;\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmysql安装\u002Fupdate-user.png\" style=\"zoom:70%;\" \u002F>\r\n\r\n停止数据库：\r\n\r\n```shell\r\n# 停止数据库\r\nmysqladmin shutdown\r\n# 输入密码，停止数据库服务\r\nmysqladmin -u root -p shutdown\r\n```\r\n\r\n\r\n\r\n#### 2.2.3.8\t防火墙开放3306端口\r\n\r\n```shell\r\n#查看3306端口状态：no 表示未开启\r\nfirewall-cmd --query-port=3306\u002Ftcp\r\n#永久开放端口\r\nfirewall-cmd --add-port=3306\u002Ftcp --permanent\r\n#重启防火墙\r\nsystemctl restart firewalld\r\n```\r\n\r\n\r\n\r\n#### 2.2.3.9\t设置开机自启\r\n\r\n```shell\r\n# 拷贝mysql.server启动脚本到\u002Fetc\u002Finit.d\u002F目录下，并命名为mysql\r\ncp \u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fsupport-files\u002Fmysql.server \u002Fetc\u002Finit.d\u002Fmysql\r\n\r\n# 修改myql启动脚本内容\r\nvi \u002Fetc\u002Finit.d\u002Fmysql\r\n```\r\n\r\n修改内容如下：\r\n\r\n```properties\r\n# mysql安装目录，必须与my.cnf中指定的路径一致\r\nbasedir=\u002Fusr\u002Flocal\u002Fmysql-8.4.4\r\n# mysql数据目录，必须与my.cnf中指定的路径一致\r\ndatadir=\u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fdata\r\n\r\n# 指定配置文件启动\r\nother_args=\"--defaults-file=\u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fconf\u002Fmy.cnf\"\r\n\r\n# 注释脚本中的启动命令\r\n#$bindir\u002Fmysqld_safe --datadir=\"$datadir\" --pid-file=\"$mysqld_pid_file_path\" $other_args >\u002Fdev\u002Fnull &\r\n# 启动命令修改为如下，不在指定 --datadir 和 --pid-file\r\n$bindir\u002Fmysqld_safe  $other_args >\u002Fdev\u002Fnull &\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmysql安装\u002Fmysql-server.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n赋予脚本执行权限：\r\n\r\n```shell\r\nchmod +x \u002Fetc\u002Finit.d\u002Fmysql\r\n\r\n# 添加服务\r\nchkconfig --add mysql\r\n\r\n# 设置服务开机自启\r\nchkconfig mysql on\r\n# 设置服务开机不自启\r\nchkconfig mysql off\r\n```\r\n\r\n以后就可以使用以下命令启停服务，只要mysql脚本中有什么参数，就可以使用什么参数，跟直接执行`sh mysql.server xxx参数`一个原理。\r\n\r\n```shell\r\n# 查看 \r\nservice mysql status\r\n# 停服务 \r\nservice mysql stop\r\n# 起服务 \r\nservice mysql start\r\n# 重启服务 \r\nservice mysql restart\r\n\r\n# 也可以使用systemctl命令\r\nsystemctl status mysql\r\nsystemctl start mysql\r\nsystemctl stop mysql\r\nsystemctl restart mysql\r\n```\r\n\r\n\r\n\r\n## 2.2\tRocky Linux 离线安装8.4.8\r\n\r\n### 2.2.1 MySQL官网下载\r\n\r\n#### 2.2.1.1\t查看glibc版本\r\n\r\n检查Linux服务器C语言标准库版本，mysql基于C编写，因此需要C环境，官网上只需要下载该基于glibc版本的mysql即可。\r\n\r\n```shell\r\n# 查看系统 glibc 版本\r\nldd --version\r\n\r\n# 查看系统支持的 glibc 版本\r\nstrings \u002Flib64\u002Flibc.so.6 | grep GLIBC\r\n\r\n# 您会看到包含：\r\nGLIBC_2.34\r\nGLIBC_2.33\r\nGLIBC_2.32\r\nGLIBC_2.31\r\nGLIBC_2.30\r\nGLIBC_2.29\r\nGLIBC_2.28\r\n... 等\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmysql安装\u002Fldd2.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n#### 2.2.1.2\t[官网下载](https:\u002F\u002Fdev.mysql.com\u002Fdownloads\u002Fmysql\u002F)\r\n\r\n下载地址：https:\u002F\u002Fdev.mysql.com\u002Fdownloads\u002Fmysql\u002F，MySQL是收费的，社区版是不收费的，所以市面上大家都用社区版。下载跟Linux服务器适配的glibc环境，安装时就不用再安装C语言标准库。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmysql安装\u002Fdownload8.4.8.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n点击【开始下载】：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmysql安装\u002Fdownload8.4-2.png\" style=\"zoom:67%;\" \u002F>\r\n\r\n### 2.2.2\t安装前检查\r\n\r\n#### 2.2.2.1\t检查是否安装有mysql\r\n\r\n```shell\r\nrpm -qa |grep -i mysql\r\n\r\n# yum卸载\r\nyum remove mysql80-community-release-el8-1.noarch\r\nyum remove mysql-community-server-8.0.27-1.el8.x86_64\r\n# 也可以用rpm卸载\r\nrpm -ev mysql80-community-release-el7-7.noarch\r\nrpm -ev mysql-community-client-plugins-8.0.22-1.ky3.kb1.x86_64\r\n```\r\n\r\n#### 2.2.2.2\t检查是否安装有mariadb\r\n\r\n```shell\r\nrpm -qa | grep mariadb\r\n\r\n# 使用rpm卸载\r\nrpm -e --nodeps mariadb-libs-5.5.56-2.el7.x86_64\r\n```\r\n\r\n#### 2.2.2.3\t安装前先关闭 selinux\r\n\r\nSELinux（Security-Enhanced Linux）是 Linux 系统的一个安全模块，主要用于加强系统的安全性。它通过强制访问控制（MAC）来限制进程和用户对系统资源（如文件、端口等）的访问。即使某个进程或用户具有某些权限，SELinux 也可以通过策略来限制其操作，防止潜在的安全风险。\r\n\r\n- **关闭 SELinux 的好处**\r\n  - 减少兼容性问题：一些旧的应用程序或服务可能与 SELinux 不兼容，关闭 SELinux 可以避免这些问题。\r\n  - 简化配置和管理：SELinux 配置和管理较为复杂，关闭它可以简化系统管理，减少安全配置的工作量。\r\n  - 提高系统性能：虽然性能影响通常较小，但在高负载的情况下，SELinux 的安全检查可能会带来额外的性能开销，关闭它可以稍微提高系统性能。\r\n\r\n- **关闭 SELinux 的风险**\r\n  - 关闭 SELinux 会降低系统的安全性，特别是在遭遇外部攻击时，可能增加系统被入侵的风险。因此，如果没有特别的兼容性需求，建议在生产环境中保持 SELinux 启用。\r\n\r\n```shell\r\nvi \u002Fetc\u002Fselinux\u002Fconfig\r\n# 将SELINUX 的值 修改为disabled\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmysql安装\u002Fselinux.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n- `disabled`：SELinux 已禁用。\r\n- `enforcing`：SELinux 处于启用并强制执行模式。\r\n- `permissive`：SELinux 处于启用，打印警告但不强制执行模式\r\n\r\n\r\n\r\n### 2.2.3\t开始安装\r\n\r\n#### 2.2.3.1\t上传并解压\r\n\r\n```shell\r\ncd \u002Fhome\u002Ftools\r\n\r\n# 解压 tar.xz 文件使用：tar -xf 命令\r\ntar -xvf mysql-8.4.8-linux-glibc2.28-x86_64.tar.xz\r\n```\r\n\r\n#### 2.2.3.2\t重命名\r\n\r\n```shell\r\nmv mysql-8.4.8-linux-glibc2.28-x86_64 mysql\r\n```\r\n\r\n\r\n\r\n#### 2.2.3.3\t配置环境变量\r\n\r\n```shell\r\nvi \u002Fetc\u002Fprofile\r\n文件末尾添加：\r\nexport PATH=$PATH:\u002Fhome\u002Ftools\u002Fmysql\u002Fbin\r\n# 重新加载环境变量\r\nsource \u002Fetc\u002Fprofile\r\n```\r\n\r\n#### 2.2.3.4\t创建数据目录\r\n\r\n```shell\r\n#（1）创建用户，也可以不创建\r\n#创建mysql用户组和用户并准备MySQL数据库的存储目录\r\n#创建一个新的用户组，命名为“mysql”\r\ngroupadd mysql\r\n#创建一个新的用户，命名为“mysql”\r\nuseradd -r -g mysql mysql\r\n\r\n#（2）创建数据目录\r\n#设置MySQL数据库的存储目录及其权限\r\n#创建目录\r\nmkdir \u002Fhome\u002Ftools\u002Fmysql\u002Fdata\r\n\r\n#（3）修改目录权限，如果没有创建mysql用户，请忽略\r\nchown mysql:mysql -R mkdir \u002Fhome\u002Ftools\u002Fmysql\r\n# 切换到mysql用户操作\r\nsu - mysql\r\n```\r\n\r\n#### 2.2.3.5\t添加配置文件\r\n\r\n```shell\r\nmkdir \u002Fhome\u002Ftools\u002Fmysql\u002Fconf\r\nvi \u002Fhome\u002Ftools\u002Fmysql\u002Fconf\u002Fmy.cnf\r\n```\r\n\r\nmy.cnf配置内容：\r\n\r\n```properties\r\n[mysql]\r\n# 默认字符集\r\ndefault-character-set=utf8mb4\r\n\r\n[client]\r\nport       = 3306\r\nsocket     = \u002Fhome\u002Ftools\u002Fmysql\u002Fdata\u002Fmysql.sock\r\n\r\n[mysqld]\r\n# ===== 基本配置 =====\r\nport       = 3306\r\nserver_id  = 1\r\nuser       = root\r\nsocket     = \u002Fhome\u002Ftools\u002Fmysql\u002Fdata\u002Fmysql.sock\r\n# 安装目录 \r\nbasedir    = \u002Fhome\u002Ftools\u002Fmysql\r\n# 数据存放目录\r\ndatadir    = \u002Fhome\u002Ftools\u002Fmysql\u002Fdata\r\npid_file = \u002Fdata\u002Fmysql\u002Fmysql.pid\r\n\r\n# ===== 二进制日志配置 =====\r\nlog_bin =\u002Fhome\u002Ftools\u002Fmysql\u002Fdata\u002Fmysql-bin\r\nbinlog_format = ROW\r\nbinlog_row_image = minimal\r\nlog_slave_updates = ON\r\n# ===== 完全关闭二进制日志 =====\r\n#skip-log-bin\r\n#log_bin = OFF\r\n#disable-log-bin\r\n\r\n# ===== binlog 过期时间（保留7天） =====\r\nbinlog_expire_logs_seconds = 3600  # 1天\r\n# expire_logs_days = 7  # 兼容旧版本\r\n\r\n# ===== binlog 自动清理 =====\r\nbinlog_expire_logs_auto_purge = ON\r\nbinlog_expire_logs_auto_purge_interval = 3600  # 每小时检查一次\r\n\r\n# ===== 连接配置 =====\r\nmax_connections = 1000\r\nmax_connect_errors = 10000\r\nwait_timeout = 600\r\ninteractive_timeout = 600\r\nthread_cache_size = 128\r\n\r\n# ===== 日志配置 =====\r\ngeneral_log = 0\r\nslow_query_log = 1\r\nslow_query_log_file = \u002Fhome\u002Ftools\u002Fmysql\u002Fdata\u002Fslow.log\r\nlong_query_time = 1\r\nlog_queries_not_using_indexes = 1\r\nlog_error = \u002Fhome\u002Ftools\u002Fmysql\u002Fdata\u002Fmysql.log\r\nlog_error_verbosity = 3\r\n\r\n# ===== 字符集配置 =====\r\ncharacter-set-server = utf8mb4\r\ncollation-server = utf8mb4_unicode_ci\r\n# 区分大小写\r\nlower_case_table_names=0\r\n```\r\n\r\n\r\n\r\n#### 2.2.3.6\t初始化数据库\r\n\r\n```shell\r\nmysqld --defaults-file=\u002Fhome\u002Ftools\u002Fmysql\u002Fconf\u002Fmy.cnf --basedir=\u002Fhome\u002Ftools\u002Fmysql --datadir=\u002Fhome\u002Ftools\u002Fmysql\u002Fdata --user=root --initialize-insecure\r\n\r\n\r\n参数说明：\r\n–defaults-file：指定配置文件（要放在–initialize 前面）\r\n–user： 指定用户，必须和my.cnf中指定的一样\r\n–basedir：指定安装目录\r\n–datadir：指定初始化数据目录\r\n–intialize-insecure：初始化无密码（否则生成随机密码）\r\n```\r\n\r\n#### 2.2.3.7\t启\u002F停数据库\r\n\r\n```shell\r\n\u002Fhome\u002Ftools\u002Fmysql\u002Fbin\u002Fmysqld_safe --defaults-file=\u002Fhome\u002Ftools\u002Fmysql\u002Fconf\u002Fmy.cnf &\r\n\r\n\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmysql安装\u002Fstart.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n登录并设置密码：\r\n\r\n```shell\r\n# 首次登录无密码\r\nmysql -u root --skip-password\r\n# 设置密码，如：admin\r\nalter user 'root'@'localhost' identified by 'admin';\r\n# 刷新权限\r\nFLUSH PRIVILEGES;\r\n```\r\n\r\n开启远程访问：\r\n\r\n```shell\r\n# 开启远程访问\r\nselect host,user,plugin from mysql.user;\r\n#修改root用户host为%\r\nupdate mysql.user set host = '%' where user='root';\r\n#刷新权限\r\nFLUSH PRIVILEGES;\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmysql安装\u002Fupdate-user.png\" style=\"zoom:70%;\" \u002F>\r\n\r\n停止数据库：\r\n\r\n```shell\r\n# 停止数据库\r\nmysqladmin shutdown\r\n# 输入密码，停止数据库服务\r\nmysqladmin -u root -p shutdown\r\n```\r\n\r\n\r\n\r\n#### 2.2.3.8\t防火墙开放3306端口\r\n\r\n```shell\r\n#查看3306端口状态：no 表示未开启\r\nfirewall-cmd --query-port=3306\u002Ftcp\r\n#永久开放端口\r\nfirewall-cmd --add-port=3306\u002Ftcp --permanent\r\n#重启防火墙\r\nsystemctl restart firewalld\r\n```\r\n\r\n\r\n\r\n#### 2.2.3.9\t设置开机自启\r\n\r\n```shell\r\n# 拷贝mysql.server启动脚本到\u002Fetc\u002Finit.d\u002F目录下，并命名为mysql\r\ncp \u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fsupport-files\u002Fmysql.server \u002Fetc\u002Finit.d\u002Fmysql\r\n\r\n# 修改myql启动脚本内容\r\nvi \u002Fetc\u002Finit.d\u002Fmysql\r\n```\r\n\r\n修改内容如下：\r\n\r\n```properties\r\n# mysql安装目录，必须与my.cnf中指定的路径一致\r\nbasedir=\u002Fusr\u002Flocal\u002Fmysql-8.4.4\r\n# mysql数据目录，必须与my.cnf中指定的路径一致\r\ndatadir=\u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fdata\r\n\r\n# 指定配置文件启动\r\nother_args=\"--defaults-file=\u002Fusr\u002Flocal\u002Fmysql-8.4.4\u002Fconf\u002Fmy.cnf\"\r\n\r\n# 注释脚本中的启动命令\r\n#$bindir\u002Fmysqld_safe --datadir=\"$datadir\" --pid-file=\"$mysqld_pid_file_path\" $other_args >\u002Fdev\u002Fnull &\r\n# 启动命令修改为如下，不在指定 --datadir 和 --pid-file\r\n$bindir\u002Fmysqld_safe  $other_args >\u002Fdev\u002Fnull &\r\n```\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmysql安装\u002Fmysql-server.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n赋予脚本执行权限：\r\n\r\n```shell\r\nchmod +x \u002Fetc\u002Finit.d\u002Fmysql\r\n\r\n# 添加服务\r\nchkconfig --add mysql\r\n\r\n# 设置服务开机自启\r\nchkconfig mysql on\r\n# 设置服务开机不自启\r\nchkconfig mysql off\r\n```\r\n\r\n以后就可以使用以下命令启停服务，只要mysql脚本中有什么参数，就可以使用什么参数，跟直接执行`sh mysql.server xxx参数`一个原理。\r\n\r\n```shell\r\n# 查看 \r\nservice mysql status\r\n# 停服务 \r\nservice mysql stop\r\n# 起服务 \r\nservice mysql start\r\n# 重启服务 \r\nservice mysql restart\r\n\r\n# 也可以使用systemctl命令\r\nsystemctl status mysql\r\nsystemctl start mysql\r\nsystemctl stop mysql\r\nsystemctl restart mysql\r\n```\r\n\r\n\r\n\r\n\r\n\r\n# 3\t容器化安装\r\n\r\n## 3.1\tdocker 容器安装\r\n\r\n### 3.1.1\t拉取镜像\r\n\r\n```shell\r\n# 拉取镜像\r\ndocker pull mysql\r\n# 或者\r\ndocker pull mysql:8.0.37\r\n\r\n# 以上两个命令是一致的，默认拉取的就是 latest 版本的\r\n# 我们还可以用下面的命令来查看可用版本：\r\ndocker search mysql\r\n```\r\n\r\n\r\n\r\n### 3.1.2\t配置文件\r\n\r\n```shell\r\n# 创建配置目录如下，并进入该目录\r\ncd \u002Fusr\u002Flocal\u002Fmysql\u002Fconf\r\n# 打开并创建一个my.cnf文件\r\nvi my.cnf\r\n```\r\n\r\n（1）**8.0.x版本`my.cnf`文件**\r\n\r\n```properties\r\n[client]\r\ndefault-character-set=utf8mb4\r\n\r\n[mysql]\r\ndefault-character-set=utf8mb4\r\n\r\n[mysqld]\r\n# 设置东八区时区\r\ndefault-time_zone = '+8:00'\r\n\r\n# 设置密码验证规则，default_authentication_plugin参数已被废弃\r\n# 改为authentication_policy\r\n# default_authentication_plugin=mysql_native_password\r\nauthentication_policy=mysql_native_password\r\n\r\n# 限制导入和导出的数据目录\r\n# 为空，不限制导入导出的数据目录；\r\n# 指定目录，必须从该目录导入导处，且MySQL不会自动创建该目录；\r\n# 为NULL，禁止导入与导出功能\r\n#secure_file_priv=\u002Fvar\u002Flib\u002Fmysql\r\nsecure_file_priv=\r\n\r\ninit_connect='SET collation_connection = utf8mb4_0900_ai_ci'\r\ninit_connect='SET NAMES utf8mb4'\r\n\r\ncharacter-set-server=utf8mb4\r\ncollation-server=utf8mb4_0900_ai_ci\r\n\r\nskip-character-set-client-handshake\r\nskip-name-resolve\r\n```\r\n\r\n默认的鉴权方式，我们修改为```mysql_native_password```，不然的话连接会报错。因为在mysql8以后的默认加密方式改变了，由``` mysql_native_password```改为了```caching_sha2_password```。这种加密凡是在客户端无法访问，客户端支持的是```mysql_native_password``` 。\r\n\r\n（2）**8.4.x版本的`my.cnf`配置文件**\r\n\r\n```properties\r\n# For advice on how to change settings please see\r\n# http:\u002F\u002Fdev.mysql.com\u002Fdoc\u002Frefman\u002F8.4\u002Fen\u002Fserver-configuration-defaults.html\r\n\r\n[mysqld]\r\n#\r\n# Remove leading # and set to the amount of RAM for the most important data\r\n# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.\r\n# innodb_buffer_pool_size = 128M\r\n#\r\n# Remove leading # to turn on a very important data integrity option: logging\r\n# changes to the binary log between backups.\r\n# log_bin\r\n#\r\n# Remove leading # to set options mainly useful for reporting servers.\r\n# The server defaults are faster for transactions and fast SELECTs.\r\n# Adjust sizes as needed, experiment to find the optimal values.\r\n# join_buffer_size = 128M\r\n# sort_buffer_size = 2M\r\n# read_rnd_buffer_size = 2M\r\n\r\n# 区分大小写\r\nlower_case_table_names=0\r\n\r\nhost-cache-size=0\r\nskip-name-resolve\r\ndatadir=\u002Fvar\u002Flib\u002Fmysql\r\nsocket=\u002Fvar\u002Frun\u002Fmysqld\u002Fmysqld.sock\r\nsecure-file-priv=\u002Fvar\u002Flib\u002Fmysql-files\r\nuser=mysql\r\n\r\npid-file=\u002Fvar\u002Frun\u002Fmysqld\u002Fmysqld.pid\r\n[client]\r\nsocket=\u002Fvar\u002Frun\u002Fmysqld\u002Fmysqld.sock\r\n\r\n!includedir \u002Fetc\u002Fmysql\u002Fconf.d\u002F\r\n```\r\n\r\n\r\n\r\n### 3.1.3\t运行容器\r\n\r\n（1）**8.0.x版本**\r\n\r\n```shell\r\ndocker run -p 3306:3306 --name mysql --restart=always --privileged=true \\\r\n-v \u002Fusr\u002Flocal\u002Fmysql\u002Flog:\u002Fvar\u002Flog\u002Fmysql \\\r\n-v \u002Fusr\u002Flocal\u002Fmysql\u002Fdata:\u002Fvar\u002Flib\u002Fmysql \\\r\n-v \u002Fusr\u002Flocal\u002Fmysql\u002Fconf:\u002Fetc\u002Fmysql \\\r\n-v \u002Fetc\u002Flocaltime:\u002Fetc\u002Flocaltime:ro \\\r\n-e MYSQL_ROOT_PASSWORD=123456 -d mysql:8.0.22\r\n\r\n#忽略大小写，8.0 之后只能在初始化时指定\r\ndocker run -p 3306:3306 --name mysql  --privileged=true -e MYSQL_ROOT_PASSWORD=Great@2024 -d mysql:8.0.22 --lower_case_table_names=1\r\n```\r\n\r\n（2）**8.4.x版本**\r\n\r\n高版本还需要指定：conf.d目录，由于mysql的配置目录\u002Fetc\u002Fmysql下有两个空目录， 上面的执行命令仅挂载了当前目录，导致里面的两个目录没有权限挂载到宿主机内， 应该将挂载目录指定到具体的目录下：\r\n\r\n```shell\r\ndocker run -p 3306:3306 --name mysql --restart=always --privileged=true \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fmysql\u002Flog:\u002Fvar\u002Flog\u002Fmysql \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fmysql\u002Fdata:\u002Fvar\u002Flib\u002Fmysql \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fmysql\u002Fconf:\u002Fetc\u002Fmysql \\\r\n-v \u002Fusr\u002Flocal\u002Fsoftware\u002Fmysql\u002Fconf:\u002Fetc\u002Fmysql\u002Fconf.d \\\r\n-v \u002Fetc\u002Flocaltime:\u002Fetc\u002Flocaltime:ro \\\r\n-e MYSQL_ROOT_PASSWORD=!QAZ2wsx#EDC -d mysql:8.4.0\r\n```\r\n\r\n（3）**命令解读**\r\n\r\n```shell\r\n-p 3306:3306：指定宿主机端口与容器端口映射关系\r\n--name mysql：创建的容器名称\r\n--restart=always：总是跟随docker启动\r\n--privileged=true：获取宿主机root权限\r\n-v \u002Fusr\u002Flocal\u002Fmysql\u002Fconf:\u002Fetc\u002Fmysql：映射my.cnf配置目录，宿主机:容器\r\n-v \u002Fetc\u002Flocaltime:\u002Fetc\u002Flocaltime:ro：让容器的时钟与宿主机时钟同步，避免时区的问题，ro是read only的意思，就是只读。\r\n-e MYSQL_ROOT_PASSWORD=123456：指定mysql环境变量，root用户的密码为123456\r\n-d ：表示后台运行容器\r\n```\r\n\r\n\r\n\r\n### 3.1.4 查看正在运行的容器\r\n\r\n```shell\r\n# 查看正在运行的容器\r\ndocker ps\r\n# 查看所有的docker容器\r\ndocker ps -a\r\n```\r\n\r\n这个时候如果显示的是up状态，那就是启动成功了。如果是restarting，说明是有问题的。我们可以查看日志：\r\n\r\n```shell\r\ndocker logs -f mysql\r\n```\r\n\r\n### 3.1.5\t重启mysql容器\r\n\r\n```shell\r\ndocker restart mysql\r\n```\r\n\r\n### 3.1.6\t进入容器内部\r\n\r\n```shell\r\ndocker exec -it mysql \u002Fbin\u002Fbash\r\n```\r\n\r\n### 3.1.7\t授权远程访问\r\n\r\n#### 3.1.7.1\t登录mysql\r\n\r\n```shell\r\nmysql -u root -p\r\n```\r\n\r\n#### 3.1.7.2\t选择数据库\r\n\r\n```mysql\r\n# 查看数据库\r\nmysql> show databases;\r\n# 选择数据库\r\nmysql> use mysql;\r\n\r\n# 查看大小写是否敏感，1：不区分，0：区分大小写\r\nmysql> show VARIABLES like '%lower%';\r\n```\r\n\r\n#### 3.1.7.3\t查看用户信息\r\n\r\n```mysql\r\n# 查看root用户是否具有权限，和host主机地址是否为%，如果host为%，则已具备远程访问权限\r\nmysql> select host,user,plugin from user;\r\n+-----------+------------------+-----------------------+\r\n| host      | user             | plugin                |\r\n+-----------+------------------+-----------------------+\r\n| %         | root             | mysql_native_password |\r\n| localhost | mysql.infoschema | caching_sha2_password |\r\n| localhost | mysql.session    | caching_sha2_password |\r\n| localhost | mysql.sys        | caching_sha2_password |\r\n| localhost | root             | mysql_native_password |\r\n+-----------+------------------+-----------------------+\r\n5 rows in set (0.00 sec)\r\n```\r\n\r\n#### 3.1.7.4\t两个root用户的存在\r\n\r\n在mysql用户表中出现两个“root”用户是因为mysql允许在不同的主机上使用相同的用户名创建用户。这是因为mysql使用“用户名@主机”的形式来标识一个用户，其中“用户名”是用户的名称，“主机”是用户所连接的主机名或者IP地址。\r\n\r\n```mysql\r\n# 如果存在两个账号，本地登录则自动使用host为本地的账号登录，远程登录则自动使用%的，\r\n# 注意这是两个不同的账号，密码也不一定相同（可以只修改为不一样的密码），权限也是不同的，增加了运维管理负担\r\n# 查询对比两者的权限差异\r\nmysql> show grants for 'root'@'localhost';\r\nmysql> show grants for 'root'@'%';\r\n\r\n# 可以删除其中一个，这里删除host为%的账号\r\nmysql> drop user 'root'@'%';\r\n```\r\n\r\n#### 3.1.7.5\t授予远程访问权限\r\n\r\n```mysql\r\n# 修改root用户host为%，即开放远程访问权限\r\nmysql> update user set host='%' where user='root';\r\n\r\n# 授权所有权限给root@'%'账号，如果不是新建的root账号，可以不用设置\r\nmysql> grant all on *.* to root@'%';\r\n\r\n# 刷新权限（授权，或者开放远程访问才生效）\r\nmysql> FLUSH PRIVILEGES;\r\n```\r\n\r\n#### 3.1.7.6\t修改密码\r\n\r\n```mysql\r\n# 如修改密码为!QAZzaq1\r\nmysql> ALTER USER 'root'@'%' IDENTIFIED BY '!QAZzaq1';\r\nQuery OK, 0 rows affected (0.03 sec)\r\n\r\nmysql> exit\r\n```\r\n\r\n\r\n\r\n## 3.2\tKubernetes 安装\r\n\r\n#### 3.2.1\tMySQL部署分析\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fmysql安装\u002Fmysql.png\" style=\"zoom:50%;\" \u002F>\r\n\r\nmysql部署需考虑数据挂载、配置文件挂载，环境变量（密码）配置。\r\n\r\n- 容器内的数据目录：\u002Fvar\u002Flib\u002Fmysql\r\n\r\n- 容器内的配置目录：\u002Fetc\u002Fmysql\u002Fconf.d ，主要是：my.cnf\r\n- 容器内的日志目录：\u002Fvar\u002Flog\u002Fmysql\r\n- 环境变量参数为：MYSQL_ROOT_PASSWORD（登录密码）\r\n\r\n\r\n\r\n#### 3.2.2\t创建ConfigMap\r\n\r\n创建一个`mysql-conf.yaml`文件，并填入以下内容，即`my.cnf`配置。\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: ConfigMap\r\nmetadata:\r\n  namespace: his\r\n  name: mysql-conf\r\nspec:\r\n  template:\r\n    metadata:\r\n      labels: {}\r\ndata:\r\n  my.conf: |-\r\n    [client]\r\n    default-character-set=utf8mb4\r\n\r\n    [mysql]\r\n    default-character-set=utf8mb4\r\n\r\n    [mysqld]\r\n    # 设置东八区时区\r\n    default-time_zone = '+8:00'\r\n\r\n    # 设置密码验证规则，default_authentication_plugin参数已被废弃\r\n    # 改为authentication_policy\r\n    #default_authentication_plugin=mysql_native_password\r\n    authentication_policy=mysql_native_password\r\n\r\n    # 限制导入和导出的数据目录\r\n    # 为空，不限制导入导出的数据目录；\r\n    # 指定目录，必须从该目录导入导处，且MySQL不会自动创建该目录；\r\n    # 为NULL，禁止导入与导出功能\r\n    #secure_file_priv=\u002Fvar\u002Flib\u002Fmysql\r\n    secure_file_priv=\r\n\r\n    init_connect='SET collation_connection = utf8mb4_0900_ai_ci'\r\n    init_connect='SET NAMES utf8mb4'\r\n\r\n    character-set-server=utf8mb4\r\n    collation-server=utf8mb4_0900_ai_ci\r\n\r\n    skip-character-set-client-handshake\r\n    skip-name-resolve\r\n```\r\n\r\n创建configMap配置：\r\n\r\n```shell\r\nkubectl apply -f mysql-conf.yaml\r\n```\r\n\r\n\r\n\r\n#### 3.2.3\t创建存储卷\r\n\r\n> 有状态应用不建议先创建存储卷，应该是在创建应用部署的时候再配置。如果先创建pvc卷，那么后续增加副本的时候不会自动创建新的pvc卷，这就违背了有状态应用部署原则。有状态应用部署的存储卷，一个pvc绑定一个pod，并不是多个pod共享一个pvc卷。因此不能使用下面这种方式创建。\r\n\r\n​\t创建一个`mysql-pvc.yaml`文件，并指定存储卷大小，指定storageClassName策略，自动创建pv卷。\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: PersistentVolumeClaim\r\nmetadata:\r\n  namespace: his\r\n  name: mysql-pvc\r\nspec:\r\n  accessModes:\r\n    - ReadWriteOnce\r\n  resources:\r\n    requests:\r\n      storage: 5Gi\r\n  storageClassName: nfs-storage\r\n```\r\n\r\n创建pvc存储卷声明：\r\n\r\n```shell\r\nkubectl apply -f mysql-pvc.yaml\r\n```\r\n\r\n\r\n\r\n#### 3.2.4\t创建应用部署\r\n\r\n部署有状态应用的时候，会自动帮我们也创建了service服务，默认创建的是None模式的，只能集群内通过域名访问。当然等部署成功了之后，手动删除默认的service服务，然后根据自己需求再创建新的service。\r\n\r\n创建一个`mysql-sts.yaml`文件，并指定mysql镜像版本，数据挂载、配置挂载信息，还有Service信息：\r\n\r\n```yaml\r\napiVersion: apps\u002Fv1\r\nkind: StatefulSet\r\nmetadata:\r\n  namespace: his\r\n  labels:\r\n    app: mysql-sts\r\n  name: mysql-sts\r\n  annotations:\r\n    kubesphere.io\u002Fdescription: mysql数据库\r\nspec:\r\n  replicas: 1\r\n  selector:\r\n    matchLabels:\r\n      app: mysql-sts\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: mysql-sts\r\n      annotations:\r\n        logging.kubesphere.io\u002Flogsidecar-config: '{}'\r\n    spec:\r\n      containers:\r\n        - name: mysql-dxsumn\r\n          imagePullPolicy: IfNotPresent\r\n          image: 'mysql:8.4.0'\r\n          resources:\r\n            limits:\r\n              memory: 2048Mi\r\n          ports:\r\n            - name: tcp-3306\r\n              protocol: TCP\r\n              containerPort: 3306\r\n              servicePort: 3306\r\n          volumeMounts:\r\n            - name: host-time\r\n              mountPath: \u002Fetc\u002Flocaltime\r\n              readOnly: true\r\n            - name: volume-lu805i\r\n              readOnly: false\r\n              mountPath: \u002Fvar\u002Flib\u002Fmysql\r\n            - name: volume-nrwp8i\r\n              readOnly: true\r\n              mountPath: \u002Fetc\u002Fmysql\u002Fconf.d\r\n          env:\r\n            - name: MYSQL_ROOT_PASSWORD\r\n              value: admin\r\n      serviceAccount: default\r\n      affinity: {}\r\n      initContainers: []\r\n      volumes:\r\n        - hostPath:\r\n            path: \u002Fetc\u002Flocaltime\r\n            type: ''\r\n          name: host-time\r\n        - name: volume-lu805i\r\n          persistentVolumeClaim:\r\n            claimName: mysql-pvc\r\n        - name: volume-nrwp8i\r\n          configMap:\r\n            name: mysql-conf\r\n            items:\r\n              - key: my.conf\r\n                path: my.conf\r\n      imagePullSecrets: null\r\n  updateStrategy:\r\n    type: RollingUpdate\r\n    rollingUpdate:\r\n      partition: 0\r\n  serviceName: mysql-sts-7ds6\r\n---\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  namespace: his\r\n  labels:\r\n    app: mysql-sts\r\n  name: mysql-sts-7ds6\r\n  annotations:\r\n    kubesphere.io\u002Falias-name: mysql-sts\r\n    kubesphere.io\u002FserviceType: statefulservice\r\nspec:\r\n  sessionAffinity: None\r\n  selector:\r\n    app: mysql-sts\r\n  ports:\r\n    - name: tcp-3306\r\n      protocol: TCP\r\n      port: 3306\r\n      targetPort: 3306\r\n  clusterIP: None\r\n```\r\n\r\n\r\n\r\n#### 3.2.5\t访问\r\n\r\n​\t创建有状态应用部署时，会自动帮我们也创建了service，默认是None，只能在集群内部通过域名访问，如：`mysql-sts-7ds6.his`。\r\n\r\n```shell\r\n# mysql 使用远程主机的方式登录\r\nmysql -uroot -hmysql-sts-7ds6 -p\r\n```\r\n\r\n​\t如果想要集群外部访问，可以重新创建类型为NodeIP的服务，或者创建Ingress的方式来供外部访问。\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  namespace: his\r\n  labels:\r\n    app: mysql-svc\r\n  name: mysql-svc\r\nspec:\r\n  sessionAffinity: None\r\n  selector:\r\n    app: mysql-sts\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: mysql-svc\r\n  ports:\r\n    - name: http-3306\r\n      protocol: TCP\r\n      targetPort: 3306\r\n      port: 3306\r\n      nodePort: 31000 # 暴露到宿主机的端口\r\n  type: NodePort\r\n```\r\n\r\n\r\n\r\n# 4\tmysql操作命令\r\n\r\n## 4.1\t登录命令\r\n\r\n```shell\r\nmysql -u root -p\r\n```\r\n\r\n\r\n\r\n## 4.2\t导入文件命令\r\n\r\n在MySQL中，有多种方法可以导入sql文件。以下是几种常见的方法：\r\n\r\n（1）使用mysql命令行工具：\r\n\r\n```shell\r\nmysql -u \u003C用户名> -p \u003C数据库名> \u003C \u003Csql文件路径>`\r\n```\r\n\r\n这会将指定的sql文件导入到指定的数据库中。在运行该命令时，你将会被要求输入密码。\r\n\r\n（2）使用source命令：\r\n\r\n```shell\r\n# 先登录\r\nmysql -u root -p\r\n# 切换数据库\r\nmysql> use \u003C数据库名>;\r\n# 导入\r\nmysql> source \u003Csql文件路径>;`\r\n```\r\n\r\n在MySQL的命令行中，先选择要导入数据的目标数据库，然后使用source命令指定sql文件的路径来导入。\r\n\r\n",{"_path":331,"slug":332,"title":333,"description":334,"excerpt":334,"date":229,"tags":335,"type":15,"cover":26,"content":336},"\u002Fknowledge\u002Fmysql权限设置","mysql权限设置","MySQL权限设置","MySQL权限设置 1、Mysql下创建新的用户 ​ 新创建的用户，默认情况下是没有任何权限的 2、给用户分配权限 （1）示例：给zhangsan分配所有权限 （2）示例：让 zhangsan 拥有 test数据库demo表查询权限-- （3）示例：给来自10.163.225.87的用户joe分配可对数据库vtdc的e",[310],"## MySQL权限设置\r\n\r\n\r\n\r\n1、Mysql下创建新的用户\r\n\r\n​\t\t新创建的用户，默认情况下是没有任何权限的\r\n\r\n```sql\r\ncreate user 用户名 identified by '密码';\r\n--示例：创建一个账号：zhangsan，密码：123456 --\r\ncreate user 'zhangsan' identified by '123456';\r\n```\r\n\r\n2、给用户分配权限\r\n\r\n```sql\r\ngrant 权限 on 数据库.数据表 to '用户' @ '主机名';\r\n```\r\n\r\n（1）示例：给zhangsan分配所有权限\r\n\r\n```sql\r\n#主机名为%，表示任意地址可访问\r\ngrant all on *.* to 'zhangsan'@'%';\r\n```\r\n\r\n（2）示例：让 zhangsan 拥有 test数据库demo表查询权限--\r\n\r\n```sql\r\ngrant select on test.demo to 'zhangsan'@'%';\r\n```\r\n\r\n（3）示例：给来自10.163.225.87的用户joe分配可对数据库vtdc的employee表进行select,insert,update,delete,create,drop等操作的权限，并设定口令为123。\r\n\r\n```sql\r\ngrant select,insert,update,delete,create,drop on vtdc.employee to joe@10.163.225.87 identified by ‘123′;\r\n```\r\n\r\n（4）示例：给来自10.163.225.87的用户joe分配可对数据库vtdc所有表进行所有操作的权限，并设定口令为123。\r\n\r\n```sql\r\ngrant all privileges on vtdc.* to joe@10.163.225.87 identified by ‘123′;\r\n```\r\n\r\n（5）示例：给本机用户joe分配可对所有数据库的所有表进行所有操作的权限，并设定口令为123。\r\n\r\n```sql\r\ngrant all privileges on *.* to joe@localhost identified by ‘123′;\r\n```\r\n\r\n3、收回权限\r\n\r\n​\t\t一般只有root用户才具有该权限。\r\n\r\n```sql\r\nrevoke 权限 on 数据库.数据表 from '用户'@'主机名';\r\n```\r\n\r\n（1）收回 zhangsan的所有权限\r\n\r\n```sql\r\nrevoke all on *.* from 'zhangsan' @'%';\r\n```\r\n\r\n",{"_path":338,"slug":339,"title":340,"description":341,"excerpt":341,"date":229,"tags":342,"type":15,"cover":26,"content":344},"\u002Fknowledge\u002Fnacos2-4-0持久化到postgres数据库","nacos2-4-0持久化到postgres数据库","Nacos2.4.0持久化到Postgres数据库","Nacos2.4.0持久化到Postgres数据库 1 简介 2 源码修改 3 部署 3.1 下拉 nacos-server镜像",[103,343],"Nacos","# Nacos2.4.0持久化到Postgres数据库\r\n\r\n## 1\t简介\r\n\r\n\r\n\r\n## 2\t源码修改\r\n\r\n\r\n\r\n## 3\t部署\r\n\r\n3.1\t下拉 nacos-server镜像\r\n\r\n```shell\r\n# 下拉nacos镜像\r\ndocker pull nacos\u002Fnacos-server:v2.4.0\r\n# 运行 nacos\r\ndocker run --env MODE=standalone --name nacos -d -p 8848:8848 -p 9848:9848 -p 9849:9849 nacos\u002Fnacos-server:v2.4.0\r\n# 上传修改源码后，打的 nacos-server.jar 和 application.properties\r\ndocker cp nacos-server.jar nacos:\u002Fhome\u002Fnacos\u002Ftarget\r\ndocker cp application.properties nacos:\u002Fhome\u002Fnacos\u002Fconf\r\n\r\n# 重启容器\r\ndocker restart nacos\r\n```\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n",{"_path":346,"slug":347,"title":348,"description":349,"excerpt":349,"date":229,"tags":350,"type":15,"cover":351,"content":352},"\u002Fknowledge\u002Fnginx安装","nginx安装","Nginx下载及安装","Nginx下载及安装 1 Window环境安装 1.1 官网下载nginx ​ 网址：https:\u002F\u002Fnginx.org\u002Fen\u002Fdownload.html，下载步骤请往后看，下载稳定版本如 nginx-1.18.0.zip，下载后解压如下：",[124,13],"\u002Fknowledge-assets\u002Fnginx安装\u002Fnginx-window.png","# Nginx下载及安装\r\n\r\n# 1\tWindow环境安装\r\n\r\n## 1.1\t官网下载nginx\r\n\r\n​\t\t网址：https:\u002F\u002Fnginx.org\u002Fen\u002Fdownload.html，下载步骤请往后看，下载稳定版本如 nginx-1.18.0.zip，下载后解压如下：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fnginx安装\u002Fnginx-window.png\" style=\"zoom:75%;\" \u002F>\r\n\r\n## 1.2\t启动nginx\r\n\r\n​\t\t直接双击nginx.exe，双击后一个黑色的弹窗一闪而过。\r\n\r\n## 1.3\t检查是否启动成功\r\n\r\n​\t\t浏览器网址输入：http:\u002F\u002Flocalhost\u002F，看到如下界面则表示启动成功：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fnginx安装\u002Fnginx-succese.png\" style=\"zoom:75%;\" \u002F>\r\n\r\n\r\n\r\n# 2\tLinux环境在线安装\r\n\r\n​\t\t安装nginx之前需要安装nginx所需要的依赖，pcre包和zlib用以支持重写,正则以及网页压缩等等，OpenSSL是一个[开放源代码](https:\u002F\u002Fbaike.baidu.com\u002Fitem\u002F开放源代码)的[软件](https:\u002F\u002Fbaike.baidu.com\u002Fitem\u002F软件)[库](https:\u002F\u002Fbaike.baidu.com\u002Fitem\u002F库)包，应用程序可以使用这个包来进行安全通信，避免窃听，同时确认另一端连接者的身份。\r\n\r\n## 2.1\t直接安装\r\n\r\n### 2.1.1\tReHat系\r\n\r\n```shell\r\n# 安装nginx\r\nsudo yum install nginx\r\n\r\n# 验证安装\r\nnginx -v\r\n\r\n# 启动nginx\r\nsudo systemctl start nginx\r\n\r\n# 设置开机自启\r\nsudo systemctl enable nginx\r\n\r\n# 查看状态\r\nsudo systemctl status nginx\r\n```\r\n\r\n### 2.1.2\tDebian 系\r\n\r\n```shell\r\n# 更新包列表，也可以不执行\r\nsudo apt update\r\n\r\n# 安装nginx\r\nsudo apt install nginx\r\n\r\n# 验证安装\r\nnginx -v\r\n\r\n# 启动nginx\r\nsudo systemctl start nginx\r\n\r\n# 设置开机自启\r\nsudo systemctl enable nginx\r\n\r\n# 查看状态\r\nsudo systemctl status nginx\r\n```\r\n\r\n\r\n\r\n## 2.2\t源码编译安装\r\n\r\n​\t使用源码编译的方式，需要先安装nginx的编译环境，以及nginx所需要的依赖库。\r\n\r\n### 2.2.1\t安装pcre、zlib、openssl\r\n\r\n```shell\r\nyum install pcre -y\r\nyum install pcre-devel -y\r\nyum install zlib -y\r\nyum install zlib-devel -y\r\nyum install openssl -y\r\nyum install openssl-devel -y\r\n```\r\n\r\n### 2.2.2\t安装nginx\r\n\r\n```shell\r\n#解压\r\ncd \u002Fusr\u002Flocal\r\ntar -zxvf nginx-1.16.0.tar.gz\r\n#进行configure配置,查看是否报错\r\ncd nginx-1.16.0\u002F\r\n\r\n.\u002Fconfigure\r\n#编译\r\nmake\r\n#安装\r\nmake install\r\n#在 \u002Fusr\u002Flocal\u002Fnginx目录下,可以看到如下4个目录:\r\n#conf配置文件,html网页文件,logs日志文件,sbin主要二进制程序\r\n```\r\n\r\n**PS**：如果出现这个错误：.\u002Fconfigure: error: C compiler cc is not found，则执行这个命令：\r\n\r\n```shell\r\nyum -y install gcc gcc-c++ autoconf automake make\r\n```\r\n\r\n### 2.2.3\t启动nginx\r\n\r\n```shell\r\n#检查 nginx.conf 配置文件是否有错\r\n\u002Fusr\u002Flocal\u002Fnginx\u002Fsbin\u002Fnginx -t\r\n#nginx启动命令:\r\n\u002Fusr\u002Flocal\u002Fnginx\u002Fsbin\u002Fnginx\r\n#指定配置文件启动\r\n\u002Fusr\u002Flocal\u002Fnginx\u002Fsbin\u002Fnginx -c \u002Fusr\u002Flocal\u002Fnginx\u002Fconf\u002Fnginx.conf\r\n#关闭命令:\r\n\u002Fusr\u002Flocal\u002Fnginx\u002Fsbin\u002Fnginx -s stop\r\n#重启命令:\r\n\u002Fusr\u002Flocal\u002Fnginx\u002Fsbin\u002Fnginx -s reload\r\n```\r\n\r\n\r\n\r\n# 3\tLinux Contos环境离线安装\r\n\r\n安装nginx需要先将官网下载的源码进行编译，编译依赖gcc环境。如果系统自带gcc版本太低，则需要升级gcc版本或者降低nginx版本。如果nginx安装报错，可能是缺少这些`pcre、zlib、openssl`依赖，如果没有安装这些依赖，Nginx是安装不成功的。\r\n\r\n## 3.1\tnginx 下载及安装\r\n\r\n### 3.1.1 nginx 下载\r\n\r\n[官网](https:\u002F\u002Fnginx.org\u002Fen\u002Fdownload.html)：https:\u002F\u002Fnginx.org\u002Fen\u002Fdownload.html\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fnginx安装\u002Fnginx.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n### 3.1.2 nginx 安装\r\n\r\n```shell\r\n# 解压\r\ntar -zxvf nginx-1.6.2.tar.gz\r\n\r\n# 进入nginx源码目录\r\ncd nginx-1.6.2\u002F\r\n\r\n# 执行配置脚本，可以自定义配置，如 --prefix 指定安装路径\r\n.\u002Fconfigure\r\n# 或\r\n.\u002Fconfigure --prefix=\u002Fusr\u002Flocal\u002Fnginx-1.6.2\r\n\r\n# 编译安装(仍然是再当前解压后的文件夹下执行) \r\n# 编译\r\nmake\r\n# 安装\r\nmake install\r\n```\r\n\r\n\r\n\r\n### 3.1.3\tnginx启动\r\n\r\n```shell\r\n# 查看版本\r\nsbin\u002Fnginx -v\r\n# 检查配置文件是否正确\r\nsbin\u002Fnginx -t\r\n# 启动nginx\r\nsbin\u002Fnginx\r\n# 重新加载配置\r\nsbin\u002Fnginx -s reload\r\n# 停止\r\nsbin\u002Fnginx -s stop\r\n```\r\n\r\n\r\n\r\n## 3.2\tnginx依赖安装\r\n\r\n如果nginx安装过程出现报错、缺少依赖，可按照如下安装对应的依赖。\r\n\r\n### 3.2.1\tgcc 下载及安装\r\n\r\n安装nginx需要先将官网下载的源码进行编译，编译依赖gcc环境，如果没有gcc环境，则需要安装：\r\n\r\n[gcc](https:\u002F\u002Fftp.gnu.org\u002Fgnu\u002Fgcc\u002F)：https:\u002F\u002Fftp.gnu.org\u002Fgnu\u002Fgcc\u002F\r\n\r\n[gmp](https:\u002F\u002Fftp.gnu.org\u002Fgnu\u002Fgmp\u002F)：https:\u002F\u002Fftp.gnu.org\u002Fgnu\u002Fgmp\u002F\r\n\r\n[isl](https:\u002F\u002Fwww.mirrorservice.org\u002Fsites\u002Fsourceware.org\u002Fpub\u002Fgcc\u002Finfrastructure\u002F)：https:\u002F\u002Fwww.mirrorservice.org\u002Fsites\u002Fsourceware.org\u002Fpub\u002Fgcc\u002Finfrastructure\u002F\r\n\r\n[mpc](https:\u002F\u002Fftp.gnu.org\u002Fgnu\u002Fmpc\u002F)：https:\u002F\u002Fftp.gnu.org\u002Fgnu\u002Fmpc\u002F\r\n\r\n[mpfr](https:\u002F\u002Fftp.gnu.org\u002Fgnu\u002Fmpfr\u002F)：https:\u002F\u002Fftp.gnu.org\u002Fgnu\u002Fmpfr\u002F\r\n\r\n\r\n\r\n### 3.2.2\tpcre下载及安装\r\n\r\nnginx的http模块使用pcre来解析正则表达式，因此需要在Linux上安装pcre库。\r\n\r\n#### 3.2.2.1\tpcre 下载\r\n\r\n[官网下载](https:\u002F\u002Fsourceforge.net\u002Fprojects\u002Fpcre\u002Ffiles\u002Fpcre\u002F)：https:\u002F\u002Fsourceforge.net\u002Fprojects\u002Fpcre\u002Ffiles\u002Fpcre\u002F\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fnginx安装\u002Fpcre-download.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n#### 3.2.2.2\tpcre 安装\r\n\r\n```shell\r\ntar -xvf pcre-8.43.tar.gz\r\ncd pcre-8.43\r\n.\u002Fconfigure  \r\nmake\r\nmake install\r\n```\r\n\r\n\r\n\r\n### 3.2.3\tzlib下载及安装\r\n\r\nzlib库提供了很多压缩和解压缩的方式，nginx使用zlib对http包的内容进行gzip，因此Linux上需要安装zlib库。\r\n\r\n#### 3.2.3.1\tzlib 下载\r\n\r\n[官网](https:\u002F\u002Fwww.zlib.net\u002F)：https:\u002F\u002Fwww.zlib.net\u002F\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fnginx安装\u002Fzlib-download.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n#### 3.2.3.2\tzlib 安装\r\n\r\n```shell\r\ntar -zxvf zlib-1.2.11.tar.gz\r\ncd zlib-1.2.11\r\n.\u002Fconfigure\r\nmake\r\nmake install\r\n```\r\n\r\n\r\n\r\n### 3.2.4 openssl安装\r\n\r\nopenssl是一个强大的安全套接字层密码库，囊括主要的密码算法、常用的密钥和证书封装管理功能及ssl协议，并提供丰富的应用程序供测试或其他目的使用。\r\n\r\n#### 3.2.4.1\topenssl 下载\r\n\r\n[官网](https:\u002F\u002Fopenssl-library.org\u002Fsource\u002F)：https:\u002F\u002Fopenssl-library.org\u002Fsource\u002F\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fnginx安装\u002Fopenssl-download.png\" style=\"zoom:60%;\" \u002F>\r\n\r\n#### 3.2.4.2\topenssl 安装\r\n\r\n```shell\r\ntar -xvf openssl-1.0.2r.tar.gz\r\ncd openssl-1.0.2r\r\n.\u002Fconfig\r\nmake\r\nmake install\r\n```\r\n\r\n\r\n\r\n## 3.3\tnginx加入服务启动项\r\n\r\n### 3.3.1\t配置环境变量\r\n\r\n```shell\r\nvi \u002Fetc\u002Fprofile\r\n#在 profile文件最后一行添加配置:\r\n\tPATH=$PATH:\u002Fusr\u002Flocal\u002Fnginx\u002Fsbin\r\n\texport PATH\r\n#刷新载入系统配置文件\r\nsource \u002Fetc\u002Fprofile\r\n```\r\n\r\n### 3.3.2\t新增nginx.service 文件\r\n\r\n```shell\r\nvi \u002Fusr\u002Flib\u002Fsystemd\u002Fsystem\u002Fnginx.service\r\n```\r\n\r\n文件中添加如下内容：\r\n\r\n```shell\r\n[Unit]\r\nDescription=nginx\r\nAfter=network.target\r\n\r\n[Service]\r\nType=forking\r\nExecStart=\u002Fusr\u002Flocal\u002Fnginx\u002Fsbin\u002Fnginx\r\n# ExecStart=\u002Fusr\u002Flocal\u002Fnginx\u002Fsbin\u002Fnginx -c  \u002Fusr\u002Flocal\u002Fnginx\u002Fconf\u002Fnginx.conf\r\nExecReload=\u002Fusr\u002Flocal\u002Fnginx\u002Fsbin\u002Fnginx -s reload\r\nExecStop=\u002Fusr\u002Flocal\u002Fnginx\u002Fsbin\u002Fnginx -s stop\r\nPrivateTmp=true\r\n\r\n[Install]\r\nWantedBy=multi-user.target\r\n```\r\n\r\n**PS**:  注意上面的ExecStart\u002FExecReload\u002FExecStop 必须以自己的nginx安装路径为主。\r\n\r\n自定义nginx.service 说明：\r\n\r\n```shell\r\n[Unit]\t#服务的说明\r\nDescription\t#描述服务\r\nAfter\t#描述服务类别\r\n[Service]\t#服务运行参数的设置\r\nType=forking\t#是后台运行的形式\r\nExecStart\t#为服务的具体运行命令\r\nExecReload\t#为重启命令\r\nExecStop\t#为停止命令\r\nPrivateTmp=True\t#表示给服务分配独立的临时空间\r\n#注意：[Service]的启动、重启、停止命令全部要求使用绝对路径\r\n[Install]\t#运行级别下服务安装的相关设置，可设置为多用户，即系统运行级别为3\r\n```\r\n\r\n### 3.3.3\tsystemctl操作服务命令 \r\n\r\n```shell\r\nsystemctl start nginx.service\t#启动nginx服务\r\nsystemctl stop nginx.service\t#停止nginx服务\r\nsystemctl enable nginx.service\t#设置开机自启动\r\nsystemctl disable nginx.service\t#停止开机自启动\r\nsystemctl status nginx.service\t#查看服务当前状态\r\nsystemctl restart nginx.service\t#重新启动服务\r\nsystemctl list-units --type=service\t#查看所有已启动的服务\r\n```\r\n\r\n# 4\tRocky Linux 9.6 安装\r\n\r\n4.1\t在联网的系统下载nginx rpm包\r\n\r\n```shell\r\nmkdir nginx-pkg\r\ncd nginx-pkg\u002F\r\n# 下载nginx相关依赖到当前目录\r\ndnf download --resolve nginx\r\n# 查看当前rpm文件\r\n[root@localhost nginx-pkg]# ls\r\nnginx-1.20.1-24.el9.x86_64.rpm  \r\nnginx-core-1.20.1-24.el9.x86_64.rpm  \r\nnginx-filesystem-1.20.1-24.el9.noarch.rpm\r\n```\r\n\r\n\r\n\r\n4.2\t拷贝到远程服务器\r\n\r\n```shell\r\nscp -r nginx-pkg root@192.168.2.4:\u002Fusr\u002Flocal\u002F\r\n```\r\n\r\n\r\n\r\n4.3\trpm命令安装\r\n\r\n```shell\r\n# 一次性安装\r\nrpm -ivh *.rpm\r\n\r\n# 如果安装失败，则按照以下分别安装\r\n# 使用最小化安装，忽略不必要的依赖\r\nrpm -ivh --nodeps nginx-filesystem-1.20.1-24.el9.noarch.rpm\r\nrpm -ivh --nodeps nginx-core-1.20.1-24.el9.x86_64.rpm\r\nrpm -ivh --nodeps nginx-1.20.1-24.el9.x86_64.rpm\r\n```\r\n\r\n\r\n\r\n\r\n\r\n",{"_path":354,"slug":355,"title":356,"description":357,"excerpt":357,"date":229,"tags":358,"type":15,"cover":359,"content":360},"\u002Fknowledge\u002Fspringboot集成swagger2接口文档","springboot集成swagger2接口文档","SpringBoot集成Swagger2接口文档","SpringBoot集成Swagger2接口文档 ​ Swagger自带的ui界面不怎么友好，**ui-xiaoymin** 是Swagger第三方ui界面。 1、pom.xml 添加 Maven 依赖 application.yal配置 2、创建Swagger2配置类 Swagger2Config 3、启动器 4、控",[74,104,136],"\u002Fknowledge-assets\u002Fspringboot集成swagger2接口文档\u002Fuser.png","## SpringBoot集成Swagger2接口文档\r\n\r\n​\t\tSwagger自带的ui界面不怎么友好，**ui-xiaoymin** 是Swagger第三方ui界面。\r\n\r\n### 1、pom.xml 添加 Maven 依赖\r\n\r\n```xml\r\n\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n\u003Cproject xmlns=\"http:\u002F\u002Fmaven.apache.org\u002FPOM\u002F4.0.0\"\r\n         xmlns:xsi=\"http:\u002F\u002Fwww.w3.org\u002F2001\u002FXMLSchema-instance\"\r\n         xsi:schemaLocation=\"http:\u002F\u002Fmaven.apache.org\u002FPOM\u002F4.0.0 http:\u002F\u002Fmaven.apache.org\u002Fxsd\u002Fmaven-4.0.0.xsd\">\r\n    \u003CmodelVersion>4.0.0\u003C\u002FmodelVersion>\r\n\r\n    \u003CgroupId>top.mengh\u003C\u002FgroupId>\r\n    \u003CartifactId>swagger2-ui-xiaoymin-demo\u003C\u002FartifactId>\r\n    \u003Cversion>1.0.0\u003C\u002Fversion>\r\n\r\n    \u003Cparent>\r\n        \u003CgroupId>org.springframework.boot\u003C\u002FgroupId>\r\n        \u003CartifactId>spring-boot-starter-parent\u003C\u002FartifactId>\r\n        \u003Cversion>2.4.3\u003C\u002Fversion>\r\n        \u003CrelativePath\u002F> \u003C!-- lookup parent from repository -->\r\n    \u003C\u002Fparent>\r\n\r\n    \u003Cdependencies>\r\n        \u003C!-- 引入web包 -->\r\n        \u003Cdependency>\r\n            \u003CgroupId>org.springframework.boot\u003C\u002FgroupId>\r\n            \u003CartifactId>spring-boot-starter-web\u003C\u002FartifactId>\r\n        \u003C\u002Fdependency>\r\n        \u003C!--swagger2文档-->\r\n        \u003Cdependency>\r\n            \u003CgroupId>com.github.xiaoymin\u003C\u002FgroupId>\r\n            \u003CartifactId>knife4j-spring-boot-starter\u003C\u002FartifactId>\r\n            \u003Cversion>3.0.2\u003C\u002Fversion>\r\n        \u003C\u002Fdependency>\r\n    \u003C\u002Fdependencies>\r\n\u003C\u002Fproject>\r\n```\r\n\r\n\r\n\r\napplication.yal配置\r\n\r\n```yml\r\nserver:\r\n  port: 8080\r\n\r\nspring:\r\n  # 文档生成\r\n  swagger2:\r\n    enabled: true\r\n```\r\n\r\n\r\n\r\n### 2、创建Swagger2配置类 Swagger2Config\r\n\r\n```java\r\n@EnableSwagger2\r\n@EnableKnife4j\r\n@Configuration\r\npublic class Swagger2Config {\r\n\r\n    @Value(\"${spring.swagger2.enabled}\")\r\n    private Boolean swaggerEnabled;\r\n\r\n    \u002F\u002F 配置一个 Docket Bean，这个 Bean 中，配置映射路径和要扫描的接口的位置\r\n    @Bean \u002F\u002F 用户端控制器的接口文档\r\n    public Docket createUserApi() {\r\n        return new Docket(DocumentationType.SWAGGER_2)\r\n                .apiInfo(apiInfo(\"用户端\"))\r\n                .groupName(\"用户端\")\r\n                .enable(swaggerEnabled)\r\n                .select()\r\n            \t\u002F\u002F加了 ApiOperation 注解的类，才生成接口文档\r\n                \u002F\u002F.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))\r\n                \u002F\u002F指定包下的类，才生成接口文档\r\n                .apis(RequestHandlerSelectors\r\n                      .basePackage(\"top.mengh.swagger2.controller.user\"))\r\n                .paths(PathSelectors.any())\r\n                .build();\r\n    }\r\n    \r\n    @Bean \u002F\u002F 管理端控制器的接口文档\r\n    public Docket createAdminApi() {\r\n        return new Docket(DocumentationType.SWAGGER_2)\r\n                .apiInfo(apiInfo(\"管理后台\"))\r\n                .groupName(\"管理后台\")\r\n                .enable(swaggerEnabled)\r\n                .select()\r\n                .apis(RequestHandlerSelectors\r\n                      .basePackage(\"top.mengh.swagger2.controller.admin\"))\r\n                .paths(PathSelectors.any())\r\n                .build()\r\n                .securitySchemes(Arrays.asList(securitySchemes())) \u002F\u002F主要生成请求头token\r\n                .securityContexts(Arrays.asList(securityContexts()));\u002F\u002F主要生成请求头token\r\n    }\r\n\r\n    \u002F\u002F 文档描述说明,主要配置一下 Swagger2 文档网站的信息\r\n    \u002F\u002F  例如网站的 title，网站的描述，联系人的信息，使用的协议等等。\r\n    private ApiInfo apiInfo(String title) {\r\n        return new ApiInfoBuilder()\r\n                \u002F\u002F 文档的标题\r\n                .title(title + \"文档\")\r\n                \u002F\u002F 文档说明\r\n                .description(\"注意事项：..... \")\r\n                \u002F\u002F 显示主页\r\n                .termsOfServiceUrl(\"http:\u002F\u002F127.0.0.1:8080\")\r\n                \u002F\u002F 文档版本\r\n                .version(\"1.0\")\r\n                .build();\r\n    }\r\n\r\n    \u002F\u002F通过 securitySchemes 来配置全局参数，这里的配置是一个名为 token 的请求头\r\n    private SecurityScheme securitySchemes() {\r\n        return new ApiKey(\"token\", \"token\", \"header\");\r\n    }\r\n    \u002F\u002FsecurityContexts 则用来配置有哪些请求需要携带 Token，这里我们配置了所有请求\r\n    private SecurityContext securityContexts() {\r\n        return SecurityContext.builder()\r\n                .securityReferences(defaultAuth())\r\n                .forPaths(PathSelectors.any())\r\n                .build();\r\n    }\r\n\r\n    private List\u003CSecurityReference> defaultAuth() {\r\n        AuthorizationScope authorizationScope = new AuthorizationScope(\"xxx\", \"描述信息\");\r\n        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];\r\n        authorizationScopes[0] = authorizationScope;\r\n        return Arrays.asList(new SecurityReference(\"token\", authorizationScopes));\r\n    }\r\n}\r\n```\r\n\r\n\r\n\r\n### 3、启动器\r\n\r\n```java\r\n@SpringBootApplication\r\npublic class SwaggerApp {\r\n    public static void main(String[] args) throws UnknownHostException {\r\n        ConfigurableApplicationContext application = SpringApplication.run(Swagger2App.class, args);\r\n        ConfigurableEnvironment environment = application.getEnvironment();\r\n        System.out.println(\"----------------------------------------------------------\");\r\n        System.out.println(\"应用启动成功! 访问连接:\");\r\n        System.out.println(\"Swagger文档: \\t\\thttp:\u002F\u002F\" + InetAddress.getLocalHost().getHostAddress()\r\n                + \":\" + environment.getProperty(\"server.port\") + \"\u002Fdoc.html\");\r\n        System.out.println(\"----------------------------------------------------------\");\r\n    }\r\n}\r\n```\r\n\r\n\r\n\r\n### 4、控制器（测试）\r\n\r\n#### （1）用户端控制器\r\n\r\n```java\r\npackage top.mengh.swagger2.controller.user;\r\n\r\n@Api(value = \"用户端订单控制器\", tags = \"订单控制器userOrder\")\r\n@RequestMapping(\"\u002Fuser\u002Forder\")\r\n@RestController\r\npublic class UserOrderController {\r\n    @ApiOperation(\"获取订单详情\")\r\n    @GetMapping(\"\u002FgetId\")\r\n    public String getId(@ApiParam(value = \"订单id\") @RequestParam Integer id) {\r\n        return \"获取订单详情成功！订单id => \" + id;\r\n    }\r\n}\r\n```\r\n\r\n\r\n\r\n#### （2）管理端控制器\r\n\r\n```java\r\npackage top.mengh.swagger2.controller.admin;\r\n\r\n@Api(value = \"订单控制器\", tags = \"订单控制器adminOrder\")\r\n@RequestMapping(\"\u002Fadmin\u002Forder\")\r\n@RestController\r\npublic class AdminOrderController {\r\n\r\n    @ApiOperation(\"获取订单详情\")\r\n    @GetMapping(\"\u002FgetId\")\r\n    public String getId(@ApiParam(name = \"订单id\") Integer id) {\r\n        return \"获取订单详情成功! id = \" + id;\r\n    }\r\n\r\n    @ApiOperation(\"新增订单\")\r\n    @ApiImplicitParams({\r\n        @ApiImplicitParam(value = \"订单名字\", name = \"name\", required = true),\r\n        @ApiImplicitParam(value = \"数量\", name = \"number\", dataType = \"String\"),\r\n        @ApiImplicitParam(value = \"类型\", name = \"type\", required = true)})\r\n    @PostMapping(\"\u002Fsave\")\r\n    public Boolean save(@RequestParam String name, String number, Integer type) {\r\n        System.out.println(\"name = \" + name + \"number = \" + number + \"type = \" + type);\r\n        return true;\r\n    }\r\n}\r\n```\r\n\r\n\r\n\r\n### 5、Swagger2接口文档界面\r\n\r\n​\t\t访问路径：http:\u002F\u002Flocalhost:8080\u002Fdoc.html\r\n\r\n#### （1）用户端控制器\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fspringboot集成swagger2接口文档\u002Fuser.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n#### （2）管理端控制器\r\n\r\n##### a、参数显示\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fspringboot集成swagger2接口文档\u002Fadminparent.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n##### b、url携带请求头信息\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002Fspringboot集成swagger2接口文档\u002Fadmintoken.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n\r\n\r\n### 6、Swagger2 常用注解说明\r\n\r\n#### @Api() 控制器说明\r\n\r\n​\t\t贴在控制器类上，说明该类的功能名称。\r\n\r\n```java\r\n@Api(value = \"订单控制器\", tags = \"界面显示的名称\")\r\npublic class carController{...}\r\n```\r\n\r\n#### @ApiOperation() 接口说明\r\n\r\n​\t\t贴在方法上，说明该方法的功能名称。\r\n\r\n```java\r\npublic class carController{\r\n\t@ApiOperation(\"界面显示的方法功能名称\")\r\n    public Car getDetail(Integer id){...}\r\n}\r\n```\r\n\r\n#### @ApiImplicitParams() 接口参数说明\r\n\r\n​\t\t用于方法上，对方法参数、字段说明，包含多个 **@ApiImplicitParam**\r\n\r\n```java\r\npublic class carController{\r\n\t@ApiImplicitParams({@ApiImplicitParam(value = \"名字\", name = \"name\", required = true),\r\n            @ApiImplicitParam(value = \"数量\", name = \"number\", required = false),\r\n            @ApiImplicitParam(value = \"类型\", name = \"type\", required = true)})\r\n\tpublic Object save(@RequestParam String name, String number, Integer type){...}\r\n}\r\n```\r\n\r\n#### @ApiParam() 接口参数说明\r\n\r\n​\t\t贴在方法参数上，说明该参数，字段。\r\n\r\n```java\r\npublic class carController{\r\n\tpublic Object getId(@ApiParam(value = \"订单id\") @RequestParam Integer id){...}\r\n}\r\n```\r\n\r\n#### @ApiModel() 实体类说明\r\n\r\n​\t\t贴在实体类或inVo、outVo类上，用于说明该实体类的功能\r\n\r\n```java\r\n@ApiModel(value = \"Car对象\", description = \"车辆信息\")\r\npublic class car{...}\r\n```\r\n\r\n#### @ApiModelProperty() 实体类字段说明\r\n\r\n​\t\t用于方法，字段，表示对[model](https:\u002F\u002Fso.csdn.net\u002Fso\u002Fsearch?q=model&spm=1001.2101.3001.7020)属性、字段的说明\r\n\r\n```java\r\npublic class car{\r\n\t@ApiModelProperty(value = \"订单id\")\r\n\tprivate Long id;\r\n}\r\n```\r\n\r\n",{"_path":362,"slug":363,"title":364,"description":365,"excerpt":365,"date":229,"tags":366,"type":15,"cover":368,"content":369},"\u002Fknowledge\u002F手机基于termux搭建linux环境","手机基于termux搭建linux环境","手机基于Termux搭建Linux环境","手机基于Termux搭建Linux环境 1 安装Termux 1.1 Termux简介 Termux是一个Android终端仿真应用程序，用于在Android手机上搭建一个完整的Linux，不需要root权限，Termux就可以正常运行。Termux基本实现Linux下的许多基本操作。可以用Termux安装Python",[103,124,74,13,367],"Termux","\u002Fknowledge-assets\u002F手机基于termux搭建linux环境\u002Ftermux-install.png","# 手机基于Termux搭建Linux环境\r\n\r\n# 1 安装Termux\r\n\r\n## 1.1 Termux简介\r\n\r\nTermux是一个Android终端仿真应用程序，用于在Android手机上搭建一个完整的Linux，不需要root权限，Termux就可以正常运行。Termux基本实现Linux下的许多基本操作。可以用Termux安装Python，Java，Nginx，Docker等。此外还可以使用ssh和电脑相互访问，操作等。\r\n\r\nTermux实现Docker安装，需要基于Qemu虚拟器环境，毕竟Termux不是真正的Linux系统，没有Docker所需要的环境。因此通过Qemu虚拟器（可以理解成类型VM虚拟机），安装alpine Linux系统，才能安装Docker。\r\n\r\n## 1.2 官网下载apk\r\n\r\n下载网址：https:\u002F\u002Fgithub.com\u002Ftermux\u002Ftermux-app\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002F手机基于termux搭建linux环境\u002Ftermux-install.png\" style=\"zoom:80%;\" \u002F>\r\n\r\n进入下载页面，根据手机芯片架构选择对应的apk下载：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002F手机基于termux搭建linux环境\u002Ftermux-install-1.png\" style=\"zoom:90%;\" \u002F>\r\n\r\n下载完成后，直接安装即可。安装完成后进入，界面显示如下：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002F手机基于termux搭建linux环境\u002Ftermux-install-2.jpg\" style=\"zoom:50%;\" \u002F>\r\n\r\n## 1.3 镜像源切换\r\n\r\n```shell\r\ntermux-change-repo\r\n```\r\n\r\n回车会弹出如下界面，按空格选择，回车确定，直接回车确定即可：\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002F手机基于termux搭建linux环境\u002Ftermux-install-3.jpg\" style=\"zoom:50%;\" \u002F>\r\n\r\n\r\n\r\n在这里选择一个镜像源，可以选择国内清华，阿里等：\r\n\r\n```shell\r\n清华源 https:\u002F\u002Ftuna.tsinghua.edu.cn\u002F\r\n阿里源 https:\u002F\u002Fmirrors.aliyun.com\u002F\r\n中科大源 https:\u002F\u002Fmirrors.ustc.edu.cn\u002F\r\n南京大学 https:\u002F\u002Fmirror.nju.edu.cn\u002F\r\n网易源 https:\u002F\u002Fmirrors.163.com\u002F\r\n腾讯源 https:\u002F\u002Fmirrors.cloud.tencent.com\u002F\r\n```\r\n\r\n这里选择南京大学的镜像源，按空格选中，回车确认，或者直接点击界面操作，如果弹出需要输入```Y|N```直接输入```Y```即可。\r\n\r\n\u003Cimg src=\"\u002Fknowledge-assets\u002F手机基于termux搭建linux环境\u002Ftermux-install-4.jpg\" style=\"zoom:50%;\" \u002F>\r\n\r\n选择镜像源之后，需要更新系统，如果弹出需要输入```Y|N```直接输入```Y```即可。\r\n\r\n```shell\r\npkg update\r\n```\r\n\r\n这里可以安装一个测试程序，好比```hello world```\r\n\r\n```shell\r\n# 安装 sl\r\npkg install sl\r\n# 启动，界面会出现一辆火车\r\nsl\r\n```\r\n\r\n\r\n\r\n# 2 安装Qemu\r\n\r\n## 2.1 Qemu简介\r\n\r\n\r\n\r\n## 2.2 下载\r\n\r\n\r\n\r\n```shell\r\n# 安装虚拟机\r\npkg install qemu-system-x86-64-headless qemux-utils\r\n# 下载alpine镜像源\r\nwget http:\u002F\u002Fdl-cdn.alpinelinux.org\u002Falpine\u002Fv3.12\u002Freleases\u002Fx86_64\u002Falpine-virt-3.12.3-x86_64.iso\r\n\r\n# 创建虚拟磁盘\r\n# -f 指定硬盘格式，“virt-alpine.img”是自定义的磁盘名称，\r\n# “10G”代表创建一个最大容量为10G的镜像，可调节，最少2g以保证docker能正常安装\r\nqemu-img create -f qcow2 virt-alpine.img 10G\r\n```\r\n\r\n\r\n\r\n# 3 Docker安装\n",1787799115361]