• 初体验:动手搭建“小清新式“、版本控制、持续集成的局域网文档系统


    您所在的团队是否拥有良好的文档分享氛围?文档是否方便查询和阅读?更新文档是否非常繁琐?

    想象一下,如果您所在的团队拥有这样一套项目文档网站,是否 项目的长期维护会很轻松

    就像Square公司的开源项目,通过聚合页引导至不同的项目 :

    square.png

    每个项目又拥有主题分明、聚合于目录导航下的网页文档,例如:

    诚然,通过 Github.IO 及类似方式,可以较为简单的部署一套在线静态文档网站。

    但公司项目文档并不适合对外公开,您是否想在公司局域网范围内,自己动手搭建一套用于 版本控制自动部署持续集成 的网页文档呢?

    以往的繁琐 与 如今的简明

    1.png

    曾经,我像图中这样,在本地或EDM软件维护文档空间,经历繁琐地检索、排查找到文档,再进行分享、阅读。

    img.png

    而现在,我习惯像这样,访问网页,通过不超过3级的目录,直接定位到文档内容,进行阅读

    实现思路

    核心思路:对重点内容编写轻量级文档,并以某种便于查找的索引方式聚合文档内容,将其托管于方便访问的网站。

    典型的方式:

    • 使用Markdown形式的轻量级文档,撰写重点内容,每一篇都主题鲜明
    • 按照主题与项目模块的之间的关系、主题之间的关联性,组织目录结构,形成 “索引”
    • 是用Gitbook、博客生成器等软件,将其制作成静态网站
    • 部署静态网站

    在此基础上,再加上自动部署、版本控制

    涉及到的技能树,其中蓝色高亮部分一般能让人眼前一亮

    should_continue.png

    判断是否需要继续阅读

    可能您已经 满怀期待 地准备开始跟随博客 展开实践,但出于责任心,我建议您结合下述 流程图参考经历 判断下 是否真的需要继续

    如果您已经确定要了解笔者是如何实现这一系统的,可以直接进入下一个章节

    3.png

    供参考的例子

    A公司

    背景:

    • 研发团队百人规模,4-5条业务线,业务线之间存在一定数量的人员共享(例如移动端,web端后端救火队员)
    • 业务线之间有(业务、技术)交流,流动人员需要接入、交出
    • 除去服务端接口文档(YApi or Swagger),项目设计类文档一般托管于 Confluence

    团队有强烈的 “基于文档交流、存档备份、查阅回顾、知识转移” 的需求有分享氛围

    遇到的典型困难:

    • 当不熟悉文档空间时,查找的难度大
    • 维护文档空间内容索引难

    B公司

    背景:

    • 业务线独立,互不干涉,基本没有技术沟通(私下的交流除外)
    • 业务线研发团队30-40人规模
    • 技术资料无明确要求

    仅在小组范围内存在 “碎片化” 的文档材料,可能托管于印象笔记、可能托管于项目代码库,可能在某电脑中

    典型困难:

    • 聊胜于无,最终基本以查代码解决问题

    C公司

    背景:

    • 涉足医疗行业
    • 文档等资料的编写和管理发行遵照法规条款,受各种部门监管
    • 使用EDM系统

    典型困难:

    • 各种文档的出发点契合法规需求,内容不一定满足研发人员的诉求(例如:往往我们需要详尽的类图、活动图、时序图、状态图、组件及对象生命周期关系,但文档一般只从系统角度给出程序流程图)
    • 针对"查询设计细节点"而言,存在大量的内容噪声信息
    • 文档空间大、内容多、检索难度高

    从上述的三个案例来看,主要矛盾是文档内容不契合使用者诉求。

    文档系统难用是次要矛盾。

    在公司推行这一方案时,首先要确定主要矛盾能被解决,即团队愿意编写、维护一系列的文档(或内容资料)。
    当团队拥有这些长期维护的文档、资料时,就可以着手解决系统不好用的问题。

    否则不能有效推行,那此时只能退而求其次,尝试掌握额外的技能。

    开始动手

    明确环境

    按照我们的目标,可以确定,我们需要以下必要环境:

    • 一个局域网,不能有AP隔离、网段不能访问隔离(即设备间可以互相访问)
    • 一台部署文档服务的机器
    • 多台访问设备

    作者按:如果您已经开始在公司正式开始推行,大概率会申请到一台Linux虚机或者Docker;小范围尝试时,可能是使用自己的办公电脑,一般是Windows or macOS系统,Linux概率较低。

    作者手边有一台 macOS10.15.7的机器,下文所有内容均以此版本为背景,注意:不同的操作系统可能会遇到不同的问题。

    接下来我们需要搞定以下软件环境,注意目前处于macOS 10.15.7环境下

    • Gitlab 服务 及账号(至少具备创建、读取、提交项目的权限),版本无特定要求,用公司现成的即可
    • Docker 4.7.0 (77141),未调查版本特定要求,该版本已确定可用,较新
    • Docker-ubuntu 镜像,未调查版本特定要求,可使用最新版本
    • Gitbook 3.2.3, 版本无特定要求,用于生成Gitbook,结合需求选用版本

    Docker

    接下来我们开始安装Docker,并从基本镜像开始搭建静态网站

    安装

    首先下载 并安装Docker,这一步基本不会遇到问题

    安装完成后,通过 docker version 命令,可以获得docker各个模块的版本信息

    获取ubuntu镜像

    docker image pull ubuntu:latest
    
    • 1

    以上命令可以获取官方镜像仓库中的最新的Ubuntu镜像

    生成容器

    docker run -p 80:80 --name doc -i -t ubuntu /bin/bash
    
    • 1

    通过以上命令可以 基于ubuntu镜像 得到一个 名为 doc 的容器 ,映射本机80端口和容器的80端口,可使用bash。

    docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
    
    • 1

    docker run 等价于 docker container run,在docker的迭代中,功能越来越多,增加了分组

    注意:我在第一次体验docker时,没有处理好端口映射(随机端口分配),带来了很多问题,后面会给出专门的解决方案。

    读者朋友可以结合以下内容做一些尝试,体会下各种功能

    常用选项说明:

    • -d, --detach=false, 指定容器运行于前台还是后台,默认为false
    • -i, --interactive=false, 打开STDIN,用于控制台交互
    • -t, --tty=false, 分配tty设备,该可以支持终端登录,默认为false
    • -u, --user=“”, 指定容器的用户
    • -a, --attach=[], 登录容器(必须是以docker run -d启动的容器)
    • -w, --workdir=“”, 指定容器的工作目录
    • -c, --cpu-shares=0, 设置容器CPU权重,在CPU共享场景使用
    • -e, --env=[], 指定环境变量,容器中可以使用该环境变量
    • -m, --memory=“”, 指定容器的内存上限
    • -P, --publish-all=false, 指定容器暴露的端口
    • -p, --publish=[], 指定容器暴露的端口
    • -h, --hostname=“”, 指定容器的主机名
    • -v, --volume=[], 给容器挂载存储卷,挂载到容器的某个目录
    • –volumes-from=[], 给容器挂载其他容器上的卷,挂载到容器的某个目录
    • –cap-add=[], 添加权限,权限清单详见:http://linux.die.net/man/7/capabilities
    • –cap-drop=[], 删除权限,权限清单详见:http://linux.die.net/man/7/capabilities
    • –cidfile=“”, 运行容器后,在指定文件中写入容器PID值,一种典型的监控系统用法
    • –cpuset=“”, 设置容器可以使用哪些CPU,此参数可以用来容器独占CPU
    • –device=[], 添加主机设备给容器,相当于设备直通
    • –dns=[], 指定容器的dns服务器
    • –dns-search=[], 指定容器的dns搜索域名,写入到容器的/etc/resolv.conf文件
    • –entrypoint=“”, 覆盖image的入口点
    • –env-file=[], 指定环境变量文件,文件格式为每行一个环境变量
    • –expose=[], 指定容器暴露的端口,即修改镜像的暴露端口
    • –link=[], 指定容器间的关联,使用其他容器的IP、env等信息
    • –lxc-conf=[], 指定容器的配置文件,只有在指定–exec-driver=lxc时使用
    • –name=“”, 指定容器名字,后续可以通过名字进行容器管理,links特性需要使用名字
    • –net=“bridge”, 容器网络设置:
      • bridge 使用docker daemon指定的网桥
      • host //容器使用主机的网络
      • container:NAME_or_ID >//使用其他容器的网路,共享IP和PORT等网络资源
      • none 容器使用自己的网络(类似–net=bridge),但是不进行配置
    • –privileged=false, 指定容器是否为特权容器,特权容器拥有所有的capabilities
    • –restart=“no”, 指定容器停止后的重启策略:
      • no:容器退出时不重启
      • on-failure:容器故障退出(返回值非零)时重启
      • always:容器退出时总是重启
    • –rm=false, 指定容器停止后自动删除容器(不支持以docker run -d启动的容器)
    • –sig-proxy=true, 设置由代理接受并处理信号,但是SIGCHLD、SIGSTOP和SIGKILL不能被代理

    为容器内的APP安装nginx

    通过nginx可以很方便的代理静态站点,已经基于Ubuntu镜像,所以可以通过apt进行各类软件安装

    先更新apt的资源,如果源出现问题,可以自行换源

    apt-get update
    
    • 1

    安装nginx

    apt-get install -y nginx
    
    • 1

    此处的过程一般不会出现问题

    为容器内的APP安装Vim

    因为是通过终端操作,Vim是必须的。

    值得注意的是,docker中使用vim只能使用最基本的指令,需要适应

    apt-get install -y vim
    
    • 1

    修改nginx配置

    此时,您可以先确定好静态网站内容的存放文件目录,笔者将其托管于Gitlab,并clone到了docker 容器中.

    apt-get install git 安装git

    通过 whereis 命令找到nginx的安装位置 whereis nginx ,按照惯例:/etc 下存放配置文件,/sbin、/bin下是可执行文件

    进入配置文件目录,使用VIM修改 default 文件内容

    修改 root 配置,指定为静态网站根目录。

    例如:

    ##
    # You should look at the following URL's in order to grasp a solid understanding
    # ... 注释内容移除
    ##
    
    # Default server configuration
    #
    server {
        listen 80 default_server;
        listen [::]:80 default_server;
        root /usr/local/work/doc/_book;
    
    
        server_name _;
    
        location / {
            # First attempt to serve request as file, then
            # as directory, then fall back to displaying a 404.
            try_files $uri $uri/ =404;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    保存。

    输入 nginx 启动nginx ,理论上环境变量已完善,若出现问题可自行配置环境变量

    输入 ps -ef 可查看进程,确保nginx已经启动

    确认端口映射

    进入mac的Terminal,可以新建也可以退出docker的交互式容器

    按序按ctrl+p,ctrl+q 可退出交互式容器

    使用 docker ps 命令查看运行中的容器的端口映射情况。 docker ps -a 可以查看全部容器的情况。

    使用 docker port "容器名" 命令可以查看 容器内部端口 到 docker容器在mac上分配的端口

    例如,上文中我们将80端口分配给静态网站,称之容器内部端口。而此docker容器运行一个依托于mac真机的虚拟平台上,mac真机为其分配了一个端口。

    如果创建容器时没有指定端口或者启动时获取端口失败,docker容器会被分配一个端口,举个例子,可能是67890端口。

    此时,通过访问 localhost:67890 已经可以访问到静态站内容

    通过端口映射解决

    如上文所述,即便创建容器时指定了端口映射关系,也难以保障下次启动容器时还能获得一致的端口。

    我们模拟一次docker重启

    停止容器运行

    docker stop "容器名"
    
    • 1

    注意,重新启动容器应用命令为:

    docker start 容器名
    
    • 1

    而非 docker run

    如果没有配置nginx自动启动,则需要重启nginx,不进入交互式容器可使用命令:

    docker exec "容器名" nginx
    
    • 1

    顺带确认容器中运行的进程:

    docker top "容器名"
    
    • 1

    再次确认端口关系,可能会很不幸,假定已经改变为65432端口。但没有关系,挑一个喜欢的端口,例如 66666

    进行端口映射。

    题外话,如果是Linux机器,我们可以使用iptables 命令处理转发

    有些早期的博客指导修改 /var/lib/docker/containers/[hash_of_the_container]/hostconfig.json 配置转发,但该版本的docker并没有该文件。

    通过macOS的端口映射

    可参考此博客

    但是步骤太复杂了,如果不是系统性的运用转发机制,我这么懒的人一定会采用临时规则方案:

    echo "rdr pass proto tcp from any to any port {机器端口} -> 127.0.0.1 port {docker 镜像端口}" | sudo pfctl -Ef -
    
    • 1

    结合我们假设的设定:

    echo "rdr pass proto tcp from any to any port 66666 -> 127.0.0.1 port 65432" | sudo pfctl -Ef -
    
    • 1

    通过:

    sudo pfctl -F all -f /etc/pf.conf
    
    • 1

    可以删除临时规则

    Gitbook or other

    在上文内容中,我们已经默认使用了 Gitbook 生成文档静态网站, 使用教程 不再展开。

    您也可以选用其他的软件工具生成网站

    如果存在通过路由器构建的子网

    简单回顾物理拓扑:存在必不可少局域网和一台文档服务器。

    在早期的体验阶段,我们选用了个人办公电脑架设文档服务器。

    而出于方便办公的目的,我们很有可能自行购买了路有设备,通过路由器接入公司的局域网,将办公电脑、个人电脑、手机等接入路由器构建的子网

    此时,其他同事通过公司局域网访问该文档服务器就会 遇到麻烦 ,不过很好解决,基于公司局域网的管理,一般个人分配的IP固定,该场景下该IP对应路由器设备

    分配一个路由器的端口作为访问文档服务的端口,通过路由器管理设置将该端口的访问定向转发到 部署文档服务器的机器 的文档服务端口,上文中使用了66666端口

    当然,这样处理的前提是路由器按照静态IP分配,否则需要时常维护映射关系。

    更新、CI、版本化

    文档是需要长期维护的,必然会牵涉到更改、修订、新增。

    在上文中,我们将生成的静态网站内容托管于Git,这是较差的做法,但可以在本地处理编译、生成静态网站资源时的 环境问题 而减少服务器的维护。

    针对原始文档进行版本控制是必要的。引入健壮的环境维护机制后,在服务端进行静态网站资源编译、生成,是更佳的做法。

    通过Git等VCS的帮助,已经拥有健全的版本管理方式,只需要采用相应的实践方式即可,例如参考Git最佳实践拆分发布、维护分支,通过tag维护发布版本

    自动获取更新、部署

    以上文中的做法为例,此时仅需要 周期性的 获取Git仓库中发布分支的最新内容即可。

    如果已经在服务端实施编译、生成,可以编写定时任务脚本进行CI,也可以进一步引入jenkins,增加构建任务,通过web-hook机制可以实现实时部署。

    同时获得多个版本

    有时我们希望获得 文档、内容片段 在不同版本下的内容,在此方案基础上也容易实现。

    针对不同的版本(tag),check-out 并编译、生成至 与版本一一映射 的文件目录,通过Nginx配置的方式即可实现。

    此时,需要通过不同的URL访问不同的版本,这对于使用者并不友好,本着 以人为本 的原则,可以进行一次 优化

    编写 “扫描” 程序或者脚本,扫出已经CheckOut、并在Nginx配置中有效的版本文件目录,(一般做法是将各个版本的目录规整至同一路径下,将该路径作为站点Root目录)
    通过版本(tag)与文件目录名的映射关系、Git插件,取出版本Commit信息。聚合信息后按照模板生成入口页

    优化永无止境 ,只要对文档、文档章节建立索引机制,将文档内容解析为AST,“比对文档章节在各个版本下的变化” 将可行,通过定制Gitbook插件的方式,
    可将各章节在各个版本下的内容加以聚合、通过Spinner等方式切换阅读。

    结语

    至此,我们已经完成了基础目标,而文档中提到的技能树,要全部点亮想必也需要一定的时间,尤其是结合 GitMarkdown AST解析模板引擎等内容,自研一套软件用于网页生成。读者朋友们可以丰富自己的业余生活了。

  • 相关阅读:
    LVS部署-DR集群
    Python文件操作(05):Excel操作
    学习java的day02
    VMvare虚拟机安装国产麒麟V10桌面操作系统
    51单片机智能语音识别分类垃圾箱桶新国标垃圾分类4种垃圾脚踏开关4个舵机
    题解 P8757 [蓝桥杯 2021 省 A2] 完美序列
    Tomcat的HTTP Connector
    Spring Boot 国际化踩坑指南
    文心一言 VS 讯飞星火 VS chatgpt (91)-- 算法导论8.3 4题
    《数据结构、算法与应用C++语言描述》使用C++语言实现二维数组矩阵
  • 原文地址:https://blog.csdn.net/a774057695/article/details/125456640