一开始博客使用的 Halo,发现问题比较多啊,时不时的莫名其妙主题各种报错,有时候还要升级,麻烦的要死,于是就想弄简单点。

这两天抽空反复倒腾了一遍,不小心还把镜像给尼玛删了,发的文章都没了,痛定思痛,要做改变!

众所周知,我懒出名了,我觉得这种事情你不要老是让我操心啊,最好是一年都不要动一下才好,这搞的跟什么一样。

研究一会儿,最终还是决定 docsify+github 来弄,初步的想法是本地写好 MD 文件直接 push 到 github上,然后触发 github 的webhook,触发脚本去 pull 代码到服务器上。

这样的话还有点想象空间,以后可以省去一大部分同步文章的工作,都可以出发回调去通过 API 同步,不过暂时还没有调研这些平台是否能支持,不过应该问题不大。

试试解决方案可不可行吧,我觉得很 nice。

docsify 搭建安装

首先安装 docsify-cli 工具

  1. npm i docsify-cli -g

然后进入自己的目录,初始化

  1. docsify init ./

这样就差不多了,多了几个文件,简单修改一下 index.html,配置下名字和代码仓库的信息,开启下左边的侧边栏。

同时补充一点插件,都从网上搂的。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
  7. <meta name="description" content="Description">
  8. <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
  9. <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css">
  10. </head>
  11. <body>
  12. <div id="app"></div>
  13. <script>
  14. window.$docsify = {
  15. name: '艾小仙',
  16. repo: 'https://github.com/irwinai/JavaInterview.git',
  17. loadSidebar: true,
  18. autoHeader: true,
  19. subMaxLevel: 3,
  20. sidebarDisplayLevel: 1, // set sidebar display level
  21. count:{
  22. countable:true,
  23. fontsize:'0.9em',
  24. color:'rgb(90,90,90)',
  25. language:'chinese'
  26. },
  27. search: {
  28. maxAge: 86400000, // Expiration time, the default one day
  29. paths: [], // or 'auto'
  30. placeholder: '开始搜索',
  31. noData: '啥也没有!'
  32. },
  33. copyCode: {
  34. buttonText : '点击复制',
  35. errorText : '错误',
  36. successText: '复制成功'
  37. },
  38. footer: {
  39. copy: '<span>艾小仙 &copy; 2022</span>',
  40. auth: '赣ICP备2021008029号-1',
  41. pre: '<hr/>',
  42. style: 'text-align: right;',
  43. class: 'className'
  44. }
  45. }
  46. </script>
  47. <!-- Docsify v4 -->
  48. <script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
  49. <!-- 搜索 -->
  50. <script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script>
  51. <!-- 图片放大缩小支持 -->
  52. <script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/zoom-image.min.js"></script>
  53. <!-- 拷贝文字内容 -->
  54. <script src="//cdn.jsdelivr.net/npm/docsify-copy-code/dist/docsify-copy-code.min.js"></script>
  55. <!-- 字数插件 -->
  56. <script src="https://cdn.jsdelivr.net/npm/docsify-count@latest/dist/countable.min.js"></script>
  57. <!-- 分页导航 -->
  58. <script src="//unpkg.com/docsify-pagination/dist/docsify-pagination.min.js"></script>
  59. <!-- 侧边栏扩展与折叠 -->
  60. <script src="//cdn.jsdelivr.net/npm/docsify-sidebar-collapse/dist/docsify-sidebar-collapse.min.js"></script>
  61. <!-- 页脚信息 -->
  62. <script src="//unpkg.com/docsify-footer-enh/dist/docsify-footer-enh.min.js"></script>
  63. <!-- GitTalk评论 -->
  64. <!-- <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/gitalk/dist/gitalk.css">
  65. <script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/gitalk.min.js"></script>
  66. <script src="//cdn.jsdelivr.net/npm/gitalk/dist/gitalk.min.js"></script> -->
  67. </body>
  68. </html>

然后运行,本地会启动 http://localhost:3000,直接看看效果

  1. docsify serve

大概就这个样子了

侧边栏还没有,使用命令生成一下,会自动帮我们根据目录创建一个_sidebar.md文件,也就是我们的侧边栏了。

  1. docsify generate .

然后再看看效果怎么样,差不多就这样,需要注意的是文件名不能有空格,否则生成的侧边栏目录会有问题,需要修改一下文件名使用中划线或者下换线替换空格(我无法理解为什么不能用空格)。

多级目录生成问题

另外还有一个问题是无法生成多级目录,也就是不能超过二级目录,这个我自己随便改了一下。

去 docsify-cli 官方 git 仓库下载源码,然后把这个丢进去,在目录下执行 node generate.js 就可以,底部测试目录改成自己的目录。

  1. 'use strict'
  2. const fs = require('fs')
  3. const os = require('os')
  4. const {cwd, exists} = require('../util')
  5. const path = require('path')
  6. const logger = require('../util/logger')
  7. const ignoreFiles = ['_navbar', '_coverpage', '_sidebar']
  8. // eslint-disable-next-line
  9. function test (path = '', sidebar) {
  10. // 获取当前目录
  11. const cwdPath = cwd(path || '.')
  12. // console.log('cwdPath', cwdPath, !!exists(cwdPath));
  13. // console.log('///////', cwdPath, path, cwd(path || '.'))
  14. if (exists(cwdPath)) {
  15. if (sidebar) {
  16. const sidebarPath = cwdPath + '/' + sidebar || '_sidebar.md';
  17. if (!exists(sidebarPath)) {
  18. genSidebar(cwdPath, sidebarPath)
  19. logger.success(`Successfully generated the sidebar file '${sidebar}'.`)
  20. return true
  21. }
  22. logger.error(`The sidebar file '${sidebar}' already exists.`)
  23. process.exitCode = 1
  24. return false
  25. }
  26. return false;
  27. }
  28. logger.error(`${cwdPath} directory does not exist.`)
  29. }
  30. let tree = '';
  31. function genSidebar(cwdPath, sidebarPath) {
  32. // let tree = '';
  33. let lastPath = ''
  34. let nodeName = ''
  35. let blankspace = '';
  36. let test = 0;
  37. const files = getFiles(cwdPath);
  38. console.log(JSON.stringify(files));
  39. getTree(files);
  40. fs.writeFile(sidebarPath, tree, 'utf8', err => {
  41. if (err) {
  42. logger.error(`Couldn't generate the sidebar file, error: ${err.message}`)
  43. }
  44. })
  45. return;
  46. getDirFiles(cwdPath, function (pathname) {
  47. path.relative(pathname, cwdPath) // 找cwdPath的相对路径
  48. pathname = pathname.replace(cwdPath + '/', '')
  49. let filename = path.basename(pathname, '.md') // 文件名
  50. let splitPath = pathname.split(path.sep) // 路径分割成数组
  51. let blankspace = '';
  52. if (ignoreFiles.indexOf(filename) !== -1) {
  53. return true
  54. }
  55. nodeName = '- [' + toCamelCase(filename) + '](' + pathname + ')' + os.EOL
  56. if (splitPath.length > 1) {
  57. if (splitPath[0] !== lastPath) {
  58. lastPath = splitPath[0]
  59. tree += os.EOL + '- ' + toCamelCase(splitPath[0]) + os.EOL
  60. }
  61. tree += ' ' + nodeName
  62. // console.error('tree=====', tree, splitPath, splitPath.length);
  63. } else {
  64. if (lastPath !== '') {
  65. lastPath = ''
  66. tree += os.EOL
  67. }
  68. tree += nodeName
  69. }
  70. })
  71. fs.writeFile(sidebarPath, tree, 'utf8', err => {
  72. if (err) {
  73. logger.error(`Couldn't generate the sidebar file, error: ${err.message}`)
  74. }
  75. })
  76. }
  77. function getFiles (dir) {
  78. // let path = require('path');
  79. // let fs = require('fs');
  80. let rootDir = dir;
  81. var filesNameArr = []
  82. let cur = 0
  83. // 用个hash队列保存每个目录的深度
  84. var mapDeep = {}
  85. mapDeep[dir] = 0
  86. // 先遍历一遍给其建立深度索引
  87. function getMap(dir, curIndex) {
  88. var files = fs.readdirSync(dir) //同步拿到文件目录下的所有文件名
  89. files.map(function (file) {
  90. //var subPath = path.resolve(dir, file) //拼接为绝对路径
  91. var subPath = path.join(dir, file) //拼接为相对路径
  92. var stats = fs.statSync(subPath) //拿到文件信息对象
  93. // 必须过滤掉node_modules文件夹
  94. if (file != 'node_modules') {
  95. mapDeep[file] = curIndex + 1
  96. if (stats.isDirectory()) { //判断是否为文件夹类型
  97. return getMap(subPath, mapDeep[file]) //递归读取文件夹
  98. }
  99. }
  100. })
  101. }
  102. getMap(dir, mapDeep[dir])
  103. function readdirs(dir, folderName, myroot) {
  104. var result = { //构造文件夹数据
  105. path: dir,
  106. title: path.basename(dir),
  107. type: 'directory',
  108. deep: mapDeep[folderName]
  109. }
  110. var files = fs.readdirSync(dir) //同步拿到文件目录下的所有文件名
  111. result.children = files.map(function (file) {
  112. //var subPath = path.resolve(dir, file) //拼接为绝对路径
  113. var subPath = path.join(dir, file) //拼接为相对路径
  114. var stats = fs.statSync(subPath) //拿到文件信息对象
  115. if (stats.isDirectory()) { //判断是否为文件夹类型
  116. return readdirs(subPath, file, file) //递归读取文件夹
  117. }
  118. if (path.extname(file) === '.md') {
  119. const path = subPath.replace(rootDir + '/', '');
  120. // console.log(subPath, rootDir, '========', path);
  121. return { //构造文件数据
  122. path: path,
  123. name: file,
  124. type: 'file',
  125. deep: mapDeep[folderName] + 1,
  126. }
  127. }
  128. })
  129. return result //返回数据
  130. }
  131. filesNameArr.push(readdirs(dir, dir))
  132. return filesNameArr
  133. }
  134. function getTree(files) {
  135. for (let i=0; i<files.length;i++) {
  136. const item = files[i];
  137. if (item) {
  138. if (item.deep === 0) {
  139. if (item.children) {
  140. getTree(item.children)
  141. }
  142. } else {
  143. let blankspace = ''
  144. for (let i = 1; i < item.deep; i++) {
  145. blankspace += ' '
  146. }
  147. // console.log('-' + blankspace + '-', item.deep)
  148. if (item.type === 'directory') {
  149. tree += os.EOL + blankspace + '- ' + toCamelCase(item.title) + os.EOL
  150. } else if (item.type === 'file') {
  151. tree += os.EOL + blankspace + '- [' + item.name + '](' + item.path + ')' + os.EOL
  152. // console.log('tree', tree);
  153. }
  154. if (item.children) {
  155. getTree(item.children)
  156. }
  157. }
  158. }
  159. }
  160. }
  161. function getDirFiles(dir, callback) {
  162. fs.readdirSync(dir).forEach(function (file) {
  163. let pathname = path.join(dir, file)
  164. if (fs.statSync(pathname).isDirectory()) {
  165. getDirFiles(pathname, callback)
  166. } else if (path.extname(file) === '.md') {
  167. callback(pathname)
  168. }
  169. })
  170. }
  171. function toCamelCase(str) {
  172. return str.replace(/\b(\w)/g, function (match, capture) {
  173. return capture.toUpperCase()
  174. }).replace(/-|_/g, ' ')
  175. }
  176. test("/Users/user/Documents/JavaInterview/", "sidebar.md");

这样的话一切不就都好起来了吗?看看最终的效果。

nginx 配置

webhook 暂时还没弄,先手动 push 上去然后把文件都传到服务器上去,再设置一下 nginx 。

  1. server {
  2. listen 80;
  3. listen [::]:80;
  4. server_name aixiaoxian.vip;
  5. client_max_body_size 1024m;
  6. location / {
  7. root /你的目录;
  8. index index.html;
  9. }
  10. }
  11. server {
  12. listen 443 ssl;
  13. server_name aixiaoxian.vip;
  14. root /usr/share/nginx/html;
  15. ssl_certificate cert/aixiaoxian.pem;
  16. ssl_certificate_key cert/aixiaoxian.key;
  17. ssl_session_cache shared:SSL:1m;
  18. ssl_session_timeout 10m;
  19. ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
  20. ssl_prefer_server_ciphers on;
  21. ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #表示使用的TLS协议的类型。
  22. include /etc/nginx/default.d/*.conf;
  23. location / {
  24. root /你的目录;
  25. index index.html;
  26. }
  27. }

这时候你去 reload nginx 会发现网站可能 403 了,把你的 ng 文件第一行改了,甭管后面是啥,改成 root 完事儿。

  1. user root;

这样就 OK 了。

内网穿透

然后,就需要搞一个 webhook 的程序了,但是在此之前,为了本地能测试 webhook 的效果,需要配置个内网穿透的程序,我们使用 ngrok 。

先安装。

  1. brew install ngrok/ngrok/ngrok

然后需要注册一个账号,这里没关系,直接 google 登录就好了,之后进入个人页面会提示你使用步骤。

按照步骤来添加 token,然后映射 80 端口。

如果后面发现 ngrok 命令找不到,可以去官网手动下一个文件,丢到/usr/local/bin目录中就可以了。

成功之后可以看到 ngrok 的页面,使用他给我们提供的 Forwarding 地址,就是我们的公网地址。

我随便弄了个 80 端口,这里用自己到时候项目的端口号映射就行了,后面我们改成 9000。

webhook

配置好之后,就去我们的 github 项目设置 webhook,使用上面得到的地址。

这样就设置OK了,然后搞个 Java 程序去,监听 9000 端口,随便写个 Controller

  1. @PostMapping("/webhook")
  2. public void webhook(@RequestBody JsonNode jsonNode) {
  3. System.out.println("json===" + jsonNode);
  4. }

然后随便改点我们的文档,push 一下,收到了 webhook 的回调,其实我们根本不关注回调的内容,我们只要收到这个通知,就去触发重新拉取代码的指令就行。

  1. {
  2. "repository": {
  3. "id": 306793662,
  4. "name": "JavaInterview",
  5. "full_name": "irwinai/JavaInterview",
  6. "private": false,
  7. "owner": {
  8. "name": "irwinai",
  9. "email": "415586662@qq.com",
  10. "login": "irwinai"
  11. },
  12. "html_url": "https://github.com/irwinai/JavaInterview",
  13. "description": null,
  14. "fork": false
  15. },
  16. "pusher": {
  17. "name": "irwinai",
  18. "email": "415586662@qq.com"
  19. },
  20. "sender": {
  21. "login": "irwinai",
  22. "id": 4981449
  23. }
  24. }

接着,我们实现代码逻辑,根据回调执行命令去拉取最新的代码到本地,为了能通过 Java 操作 Git,引入 JGit。

  1. <dependency>
  2. <groupId>org.eclipse.jgit</groupId>
  3. <artifactId>org.eclipse.jgit</artifactId>
  4. <version>5.13.1.202206130422-r</version>
  5. </dependency>

为了简单,我每次都是重新 clone 仓库下来,正常来说应该第一次 clone,后面直接 pull 代码,这里为了省事儿,就先这样操作。

  1. @RestController
  2. public class WebhookController {
  3. private static final String REMOTE_URL = "https://github.com/irwinai/JavaInterview.git";
  4. @PostMapping("/webhook")
  5. public void webhook(@RequestBody JsonNode jsonNode) throws Exception {
  6. File localPath = new File("/Users/user/Downloads/TestGitRepository");
  7. // 不管那么多,先删了再说
  8. FileUtils.deleteDirectory(localPath);
  9. //直接 clone 代码
  10. try (Git result = Git.cloneRepository()
  11. .setURI(REMOTE_URL)
  12. .setDirectory(localPath)
  13. .setProgressMonitor(new SimpleProgressMonitor())
  14. .call()) {
  15. System.out.println("Having repository: " + result.getRepository().getDirectory());
  16. }
  17. }
  18. private static class SimpleProgressMonitor implements ProgressMonitor {
  19. @Override
  20. public void start(int totalTasks) {
  21. System.out.println("Starting work on " + totalTasks + " tasks");
  22. }
  23. @Override
  24. public void beginTask(String title, int totalWork) {
  25. System.out.println("Start " + title + ": " + totalWork);
  26. }
  27. @Override
  28. public void update(int completed) {
  29. System.out.print(completed + "-");
  30. }
  31. @Override
  32. public void endTask() {
  33. System.out.println("Done");
  34. }
  35. @Override
  36. public boolean isCancelled() {
  37. return false;
  38. }
  39. }
  40. }

代码执行后已经是 OK 了,可以直接拉取到代码,那么至此,差不多已经 OK 了,后面把代码直接丢服务器上去跑着就拉倒了。

服务器的问题

好了,你以为到这里就结束了吗?年轻了,年轻了。。。

这代码丢到服务器上跑会发现报错连不上 github,如果你是阿里云服务器的话。

解决方案是找到 /etc/ssh/ssh_config,删掉 GSSAPIAuthentication no 这行前面的注释,然后保存,你才会发现真的是能下载了。

同时,nginx 我们映射另外一个域名作为回调的域名,这里需要主要以下你的 https 证书,因为我是免费版的,所以 https 这个域名无法生效,那 webhook 回调注意用 http 就行。

  1. server {
  2. listen 80;
  3. listen [::]:80;
  4. server_name test.aixiaoxian.vip;
  5. client_max_body_size 1024m;
  6. location / {
  7. proxy_pass http://127.0.0.1:9000;
  8. proxy_set_header HOST $host;
  9. proxy_set_header X-Forwarded-Proto $scheme;
  10. proxy_set_header X-Real-IP $remote_addr;
  11. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  12. }
  13. }
  14. server {
  15. listen 443 ssl;
  16. server_name test.aixiaoxian.vip;
  17. root /usr/share/nginx/html;
  18. ssl_certificate cert/aixiaoxian.pem;
  19. ssl_certificate_key cert/aixiaoxian.key;
  20. ssl_session_cache shared:SSL:1m;
  21. ssl_session_timeout 10m;
  22. ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
  23. ssl_prefer_server_ciphers on;
  24. ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #表示使用的TLS协议的类型。
  25. include /etc/nginx/default.d/*.conf;
  26. location / {
  27. proxy_pass http://127.0.0.1:9000;
  28. proxy_set_header HOST $host;
  29. proxy_set_header X-Forwarded-Proto $scheme;
  30. proxy_set_header X-Real-IP $remote_addr;
  31. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  32. }
  33. }

OK,如果你用上面的方式还无法解决,可以换一种方式,直接通过 Java 直接 shell 脚本去处理。

  1. rm -rf /root/docs/JavaInterview
  2. git clone https://github.91chi.fun//https://github.com/irwinai/JavaInterview.git

用脚本的目的是可以用加速的 git 地址,否则服务器访问经常会失败,这个找个插件就可以有加速地址了。

  1. public class ShellCommandsHelper extends CommandHelper {
  2. private static final File file = new File(FILE_PATH);
  3. @Override
  4. public void exec() {
  5. try {
  6. FileUtils.forceMkdir(file);
  7. log.info("Starting clone repository...");
  8. Process process = Runtime.getRuntime().exec("sh " + SHELL_PATH, null, file);
  9. int status = process.waitFor();
  10. if (status != 0) {
  11. log.error("[ShellCommandsHelper] exec shell error {}", status);
  12. }
  13. } catch (Exception e) {
  14. log.error("[ShellCommandsHelper] exec shell error", e);
  15. }
  16. }
  17. }

代码上传的问题

好了,这样通过手动上传代码的方式其实已经可以用了,但是为了部署更方便一点,我建议安装一个插件Alibaba Cloud Toolkit,其他云服务器有的也有这种类型的插件。

安装好插件之后会进入配置的页面,需要配置一个accessKey

去自己的阿里云账号下面配置。

配置好了之后,点击Tools-Deploy to xxx,我是 ECS ,所以选择 ECS 服务器即可。

然后在这里会自动加载出你的服务器信息,然后选择自己的部署目录,同时选择一个 Command 也就是执行命令。

这个命令随便找个目录创建一个这个脚本,放那里就行了,最后点击 Run,代码就飞快的上传了。

  1. source /etc/profile
  2. killall -9 java
  3. nohup java -jar /root/tools/sync-tools-0.0.1-SNAPSHOT.jar > nohup.log 2>&1 &

结束

基本的工作已经做完了,那其实还有挺多细节问题没有处理的,比如失败重试、回调鉴权等等问题,这只是一个非常初级的版本。

同步代码 git 地址:https://github.com/irwinai/sync-tools

文章仓库地址:https://github.com/irwinai/JavaInterview

博客地址:https://aixiaoxian.vip/#/

搭建个人博客,Docsify+Github webhook+JGit解决方案的更多相关文章

  1. 搭建个人博客-hexo+github

    自己也算是摸爬滚打搭建成功,然后自己再重新安装部署一遍,把完整步骤分享给大家,同时最后有一些连接,如果我的步骤不行,大家可以参考其他人的(这个有点花费时间,大家提前有个心理准备 - _-) 一.第一步 ...

  2. 零基础免费搭建个人博客-hexo+github

    使用hexo生成静态博客并架设在免费的github page平台 准备 系统: Window 7 64位 使用软件: Git v1.9.5[下载地址] 百度云 360云盘 访问密码 d269 Git官 ...

  3. GitHub Pages + Hexo搭建个人博客网站-github风格-采坑记录

    目录 1.本机安装nodejs 2.github上创建仓库 3.安装hexo 4.hexo主题 5.配置主题 6.添加文章 7.使用分类和标签 8.增加文章目录 9.推送github 使用github ...

  4. 使用jekyll和Github搭建个人博客

    一.使用jekyll和Github三步搭建个人博客 在 Github 上建一个库,库的名字是xxx.github.com,其中的xxx是你的github的账号名(图中标注的不要勾选) 注:如果没有Gi ...

  5. 使用Jekyll + GitHub Pages免费搭建个人博客

    使用Jekyll + GitHub Pages免费搭建个人博客 My Blog:无名の辈 | VectorX (vectorxxxx.github.io) Download Ruby:Download ...

  6. Hexo+Git一个小时快速搭建个人博客

    搭建本地环境:Hexo框架 Hexo为何物 Hexo 是一个快速.简洁且高效的博客框架.Hexo 使用Markdown解析文章,并瞬间利用靓丽的主题生成静态网页.其中,Markdown是一个用于将普通 ...

  7. 【原】Github+Hexo+NextT搭建个人博客

    摘要 GitHub 是一个开源项目的托管网站,相信很多人都听过.在上面有很多高质量的项目代码,我们也可以把自己的项目代码托管到GitHub,与朋友们共享交流.GitHub Pages 是Github为 ...

  8. hexo+github搭建个人博客

    最近用hexo+github搭建了自己的个人博客-https://liuyfl.github.io,其中碰到了一些问题,记录下来,以便查阅. hexo+github在win7环境下搭建个人博客:hex ...

  9. 【一】Ubuntu14.04+Jekyll+Github Pages搭建静态博客

    本系列有五篇:分别是 [一]Ubuntu14.04+Jekyll+Github Pages搭建静态博客:主要是安装方面 [二]jekyll 的使用 :主要是jekyll的配置 [三]Markdown+ ...

随机推荐

  1. 使用Socket实现HttpServer(三)

    使用Socket实现HttpServer(三) 这一章继续对我们的服务器进行优化,引入 NIO package com.fengsir.network.step4; import java.io.IO ...

  2. k8s pod故障分类与排查

    一.Pod故障状态基本有几种Pod状态 处于PendingPod状态 处于WaitingPod状态 处于ContainerCreatingPod状态 ImagePullBackOffPod状态 Cra ...

  3. Azure Virtual Desktop(一)创建配置管理

    一,引言 Azure 虚拟创面是一项 Azure 服务,可以让我们管理: 1)VDI(虚拟桌面基础架构) 2)云端的 RDSH:RDSH 是 RDS(远程桌面服务)中的一个角色.这些类型的服务器用于托 ...

  4. 地铁系统ajax人性化操作

    根据选择的城市不同,显示的地铁系统和线路图也不同

  5. php进制转换

    前端html页面代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...

  6. 安卓记账本开发学习day10

    完成了最后一部分功能 1.柱状分析每月的支出或收入 2. 删除所有记录

  7. Java语言学习day08--7月7日

    ###13遍历数组​ * A:遍历数组​ * 在操作数组时,经常需要依次访问数组中的每个元素,这种操作称作数组的遍历​ * B:练习​ public class ArrayDemo04 {​ publ ...

  8. 【python免费代码】设计一个简单的学生信息管理系统

    文章目录 前言 一.理解 二.部分截图展示 三.代码 四.总结 前言 设计一个简单的学生信息管理系统,实现以下功能(bug) : 录入学生信息,信息以文件方式存储 以学生学号或者学生姓名为条件查询该学 ...

  9. HMS Core分析服务助您掌握用户分层密码,实现整体收益提升

    随着市场愈发成熟,开发者从平衡收益和风险的角度开始逐步探索混合变现的优势,内购+广告就是目前市场上混合变现的主要方式之一. 对于混合变现模式,您是否有这样的困惑: 如何判断哪些用户更愿意看广告.哪些用 ...

  10. 聊聊FLINK-25631贡献

    从入行做数据库开发,到2018年过渡到大数据开发,可以说我已经与sql朝夕相处了七八年了,经常惊讶于简单的语法就能产生复杂的操作,而且还能根据索引等统计信息自动优化,不禁很想实现自己的sql语法,却不 ...