文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

KubeSphere中如何部署Wiki系统wiki.js并启用中文全文检索

2023-07-02 12:52

关注

今天小编给大家分享一下KubeSphere中如何部署Wiki系统wiki.js并启用中文全文检索的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

背景

wiki.js 是优秀的开源 Wiki 系统,相较于 xwiki ,功能目前性上比 xwiki 不够完善,但也在不断进步。 Wiki 写作、分享、权限管理功能还是有的,胜在 UI 设计很漂亮,能满足小团队的基本知识管理需求。

以下工作是在 KubeSphere 3.2.1 + Helm 3 已经部署好的情况下进行的。

准备 storageclass

我们使用 OpenEBS 作为存储,OpenEBS 默认安装的 Local StorageSlass 在 Pod 销毁后自动删除,不适合用于我的 MySQL 存储,我们在 Local StorageClass 基础上稍作修改,创建新的 StorageClass,允许 Pod 销毁后,PV 内容继续保留,手动决定怎么处理。

apiVersion: v1items:- apiVersion: storage.k8s.io/v1  kind: StorageClass  metadata:    annotations:      cas.openebs.io/config: |        - name: StorageType          value: "hostpath"        - name: BasePath          value: "/var/openebs/localretain/"      openebs.io/cas-type: local      storageclass.beta.kubernetes.io/is-default-class: "false"      storageclass.kubesphere.io/supported-access-modes: '["ReadWriteOnce"]'    name: localretain  provisioner: openebs.io/local  reclaimPolicy: Retain  volumeBindingMode: WaitForFirstConsumerkind: Listmetadata:  resourceVersion: ""  selfLink: ""

部署 PostgreSQL 数据库

我们团队其他项目中也需要使用 PostgreSQL, 为了提高 PostgreSQL 数据库的利用率和统一管理,我们独立部署 PostgreSQL,并在安装 wiki.js 时,配置为使用外部数据库。

准备用户名密码配置

我们使用 Secret 保存 PostgreSQL 用户密码等敏感信息。

kind: SecretapiVersion: v1metadata:  name: postgres-proddata:  POSTGRES_PASSWORD: xxxxtype: Opaque

以上 POSTGRES_PASSWORD 自行准备,为 base64 编码的数据。

准备数据库初始化脚本

使用 ConfigMap 保存数据库初始化脚本,在 数据库创建时,将 ConfigMap 中的数据库初始化脚本挂载到 /docker-entrypoint-initdb.d, 容器初始化时会自动执行该脚本。

apiVersion: v1kind: ConfigMapmetadata:  name: wikijs-postgres-initdata:  init.sql: |-    CREATE DATABASE wikijs;    CREATE USER wikijs with password 'xxxx';    GRANT CONNECT ON DATABASE wikijs to wikijs;    GRANT USAGE ON SCHEMA public TO wikijs;    GRANT SELECT,update,INSERT,delete ON ALL TABLES IN SCHEMA public TO wikijs;    ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO wikijs;

以上 wikijs 用户的密码自行准备,明文保存。

准备存储

我们使用 KubeSphere 默认安装的 OpenEBS 来提供存储服务。可以通过创建 PVC 来提供持久化存储。

这里声明一个 10G 的 PVC。

kind: PersistentVolumeClaimapiVersion: v1metadata:  name: postgres-prod-data  finalizers:    - kubernetes.io/pvc-protectionspec:  accessModes:    - ReadWriteOnce  resources:    requests:      storage: 10Gi  storageClassName: localretain  volumeMode: Filesystem

部署 PostgreSQL 数据库

在前面的步骤准备好各种配置信息和存储后,就可以开始部署 PostgreSQL 服务了。

我们的 Kubernetes 没有配置存储阵列,使用的是 OpenEBS 作为存储,采用 Deployment 方式部署 PostgreSQL。

apiVersion: apps/v1kind: Deploymentmetadata:  labels:    app: postgres-prod  name: postgres-prodspec:  replicas: 1  selector:    matchLabels:      app: postgres-prod  template:    metadata:      labels:        app: postgres-prod    spec:      containers:        - name: db          imagePullPolicy: IfNotPresent          image: 'abcfy2/zhparser:12-alpine'          ports:            - name: tcp-5432              protocol: TCP              containerPort: 5432          envFrom:          - secretRef:              name: postgres-prod          volumeMounts:            - name: postgres-prod-data              readOnly: false              mountPath: /var/lib/postgresql/data            - name: wikijs-postgres-init              readOnly: true              mountPath: /docker-entrypoint-initdb.d      volumes:        - name: postgres-prod-data          persistentVolumeClaim:            claimName: postgres-prod-data        - name: wikijs-postgres-init          configMap:            name: wikijs-postgres-init

创建供其他 Pod 访问的 Service

apiVersion: v1kind: Servicemetadata:  name: postgres-prodspec:  selector:    app: postgres-prod  ports:    - protocol: TCP      port: 5432      targetPort: tcp-5432

完成 PostgreSQL 部署

测试略

部署 wiki.js

准备用户名密码配置

我们使用 Secret 保存 wiki.js 用于连接数据库的用户名密码等敏感信息。

apiVersion: v1kind: Secretmetadata:  name: wikijsdata:  DB_USER: d2lraWpz  DB_PASS: xxxxtype: Opaque

以上 DB_PASS 自行准备,为 base64 编码的数据。

准备数据库连接配置

我们使用 ConfigMap 保存 wiki.js 的数据库连接信息。

apiVersion: v1kind: ConfigMapmetadata:  name: wikijsdata:  DB_TYPE: postgres  DB_HOST: postgres-prod.infra  DB_PORT: "5432"  DB_NAME: wikijs  HA_ACTIVE: "true"

创建数据库用户和数据库

如果 PostgreSQL 数据库里没有创建 wikijs 用户和数据 ,需要手工完成一下工作:

通过『数据库工具』连接 PostgreSQL 数据库,执行一下 SQL 语句,完成数据库和用户的创建、授权。

CREATE DATABASE wikijs;CREATE USER wikijs with password 'xxxx';GRANT CONNECT ON DATABASE wikijs to wikijs;GRANT USAGE ON SCHEMA public TO wikijs;GRANT SELECT,update,INSERT,delete ON ALL TABLES IN SCHEMA public TO wikijs;ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO wikijs;

以上 wikijs 的密码自行修改。

准备 wiki.js 的 yaml 部署文件

采用 Deployment 方式 部署 wiki.js 的 yaml 文件如下:

# wikijs-deploy.yamlapiVersion: apps/v1kind: Deploymentmetadata:  labels:    app: wikijs  name: wikijsspec:  replicas: 1  selector:    matchLabels:      app: wikijs  template:    metadata:      labels:        app: wikijs    spec:      containers:        - name: wikijs          image: 'requarks/wiki:2'          ports:            - name: http-3000              protocol: TCP              containerPort: 3000          envFrom:          - secretRef:              name: wikijs          - configMapRef:              name: wikijs

创建集群内访问 wiki.js 的 Service

# wikijs-svc.yamlapiVersion: v1kind: Servicemetadata:  name: wikijsspec:  selector:    app: wikijs  ports:    - protocol: TCP      port: 3000      targetPort: http-3000

创建集群外访问的 Ingress

# wikijs-ing.yamlkind: IngressapiVersion: networking.k8s.io/v1metadata:  name: wikijsspec:  ingressClassName: nginx  rules:    - host: wiki.xxxx.cn      http:        paths:          - path: /            pathType: ImplementationSpecific            backend:              service:                name: wikijs                port:                  number: 3000

以上 host 域名需要自行配置。

执行部署

$ kubectl apply -f wikijs-deploy.yaml$ kubectl apply -f wikijs-svc.yaml$ kubectl apply -f wikijs-ing.yaml

配置 wiki.js 支持中文全文检索

wiki.js 的全文检索支持基于 PostgreSQL 的检索,也支持 Elasticsearch 等,相对来说, PostgreSQL 比较轻量级,本项目中,我们使用 PostgreSQL 的全文检索。

但是,因为 PostgreSQL 不支持中文分词,需要额外安装插件并配置启用中文分词,下面描述了为 wiki.js 启动基于 PostgreSQL 数据库中文分词的全文检索。

授予 wikijs 用户临时超管权限

通过数据库管理工具登录有超管权限的 PostgreSQL 用户,临时授予 wiki.js 用户临时超管权限,便于启动中文分词功能。

ALTER USER wikijs WITH SUPERUSER;

启用数据库的中文分词能力

使用数据库管理工具登录 PostgreSQL 数据库的 wikijs 用户,执行以下命令,启动数据库的中文分词功能。

CREATE EXTENSION pg_trgm;CREATE EXTENSION zhparser;CREATE TEXT SEARCH CONFIGURATION pg_catalog.chinese_zh (PARSER = zhparser);ALTER TEXT SEARCH CONFIGURATION chinese_zh ADD MAPPING FOR n,v,a,i,e,l WITH simple;-- 忽略标点影响ALTER ROLE wikijs SET zhparser.punctuation_ignore = ON;-- 短词复合ALTER ROLE wikijs SET zhparser.multi_short = ON;-- 测试一下select ts_debug('chinese_zh', '青春是最美好的年岁,青春是最灿烂的日子。每一个人的青春都无比宝贵,宝贵的青春只有与奋斗为伴才最闪光、最出彩。');

取消 wikijs 用户的临时超管权限

登录 PostgreSQL 数据库 wikijs 用户,取消 wikijs 用户的超管权限。

ALTER USER wikijs WITH NOSUPERUSER;

创建支持中文分词的配置 ConfigMap

# zh-parse.yamlkind: ConfigMapapiVersion: v1metadata:  name: wikijs-zhparserdata:  definition.yml: |-    key: postgres    title: Database - PostgreSQL    description: Advanced PostgreSQL-based search engine.    author: requarks.io    logo: https://static.requarks.io/logo/postgresql.svg    website: https://www.requarks.io/    isAvailable: true    props:      dictLanguage:        type: String        title: Dictionary Language        hint: Language to use when creating and querying text search vectors.        default: english        enum:          - simple          - danish          - dutch          - english          - finnish          - french          - german          - hungarian          - italian          - norwegian          - portuguese          - romanian          - russian          - spanish          - swedish          - turkish          - chinese_zh        order: 1  engine.js: |-    const tsquery = require('pg-tsquery')()    const stream = require('stream')    const Promise = require('bluebird')    const pipeline = Promise.promisify(stream.pipeline)        module.exports = {      async activate() {        if (WIKI.config.db.type !== 'postgres') {          throw new WIKI.Error.SearchActivationFailed('Must use PostgreSQL database to activate this engine!')        }      },      async deactivate() {        WIKI.logger.info(`(SEARCH/POSTGRES) Dropping index tables...`)        await WIKI.models.knex.schema.dropTable('pagesWords')        await WIKI.models.knex.schema.dropTable('pagesVector')        WIKI.logger.info(`(SEARCH/POSTGRES) Index tables have been dropped.`)      },            async init() {        WIKI.logger.info(`(SEARCH/POSTGRES) Initializing...`)        // -> Create Search Index        const indexExists = await WIKI.models.knex.schema.hasTable('pagesVector')        if (!indexExists) {          WIKI.logger.info(`(SEARCH/POSTGRES) Creating Pages Vector table...`)          await WIKI.models.knex.schema.createTable('pagesVector', table => {            table.increments()            table.string('path')            table.string('locale')            table.string('title')            table.string('description')            table.specificType('tokens', 'TSVECTOR')            table.text('content')          })        }        // -> Create Words Index        const wordsExists = await WIKI.models.knex.schema.hasTable('pagesWords')        if (!wordsExists) {          WIKI.logger.info(`(SEARCH/POSTGRES) Creating Words Suggestion Index...`)          await WIKI.models.knex.raw(`            CREATE TABLE "pagesWords" AS SELECT word FROM ts_stat(              'SELECT to_tsvector(''simple'', "title") || to_tsvector(''simple'', "description") || to_tsvector(''simple'', "content") FROM "pagesVector"'            )`)          await WIKI.models.knex.raw('CREATE EXTENSION IF NOT EXISTS pg_trgm')          await WIKI.models.knex.raw(`CREATE INDEX "pageWords_idx" ON "pagesWords" USING GIN (word gin_trgm_ops)`)        }        WIKI.logger.info(`(SEARCH/POSTGRES) Initialization completed.`)      },            async query(q, opts) {        try {          let suggestions = []          let qry = `            SELECT id, path, locale, title, description            FROM "pagesVector", to_tsquery(?,?) query            WHERE (query @@ "tokens" OR path ILIKE ?)          `          let qryEnd = `ORDER BY ts_rank(tokens, query) DESC`          let qryParams = [this.config.dictLanguage, tsquery(q), `%${q.toLowerCase()}%`]          if (opts.locale) {            qry = `${qry} AND locale = ?`            qryParams.push(opts.locale)          }          if (opts.path) {            qry = `${qry} AND path ILIKE ?`            qryParams.push(`%${opts.path}`)          }          const results = await WIKI.models.knex.raw(`            ${qry}            ${qryEnd}          `, qryParams)          if (results.rows.length < 5) {            const suggestResults = await WIKI.models.knex.raw(`SELECT word, word <-> ? AS rank FROM "pagesWords" WHERE similarity(word, ?) > 0.2 ORDER BY rank LIMIT 5;`, [q, q])            suggestions = suggestResults.rows.map(r => r.word)          }          return {            results: results.rows,            suggestions,            totalHits: results.rows.length          }        } catch (err) {          WIKI.logger.warn('Search Engine Error:')          WIKI.logger.warn(err)        }      },            async created(page) {        await WIKI.models.knex.raw(`          INSERT INTO "pagesVector" (path, locale, title, description, "tokens") VALUES (            ?, ?, ?, ?, (setweight(to_tsvector('${this.config.dictLanguage}', ?), 'A') || setweight(to_tsvector('${this.config.dictLanguage}', ?), 'B') || setweight(to_tsvector('${this.config.dictLanguage}', ?), 'C'))          )        `, [page.path, page.localeCode, page.title, page.description, page.title, page.description, page.safeContent])      },            async updated(page) {        await WIKI.models.knex.raw(`          UPDATE "pagesVector" SET            title = ?,            description = ?,            tokens = (setweight(to_tsvector('${this.config.dictLanguage}', ?), 'A') ||            setweight(to_tsvector('${this.config.dictLanguage}', ?), 'B') ||            setweight(to_tsvector('${this.config.dictLanguage}', ?), 'C'))          WHERE path = ? AND locale = ?        `, [page.title, page.description, page.title, page.description, page.safeContent, page.path, page.localeCode])      },            async deleted(page) {        await WIKI.models.knex('pagesVector').where({          locale: page.localeCode,          path: page.path        }).del().limit(1)      },            async renamed(page) {        await WIKI.models.knex('pagesVector').where({          locale: page.localeCode,          path: page.path        }).update({          locale: page.destinationLocaleCode,          path: page.destinationPath        })      },            async rebuild() {        WIKI.logger.info(`(SEARCH/POSTGRES) Rebuilding Index...`)        await WIKI.models.knex('pagesVector').truncate()        await WIKI.models.knex('pagesWords').truncate()        await pipeline(          WIKI.models.knex.column('path', 'localeCode', 'title', 'description', 'render').select().from('pages').where({            isPublished: true,            isPrivate: false          }).stream(),          new stream.Transform({            objectMode: true,            transform: async (page, enc, cb) => {              const content = WIKI.models.pages.cleanHTML(page.render)              await WIKI.models.knex.raw(`                INSERT INTO "pagesVector" (path, locale, title, description, "tokens", content) VALUES (                  ?, ?, ?, ?, (setweight(to_tsvector('${this.config.dictLanguage}', ?), 'A') || setweight(to_tsvector('${this.config.dictLanguage}', ?), 'B') || setweight(to_tsvector('${this.config.dictLanguage}', ?), 'C')), ?                )              `, [page.path, page.localeCode, page.title, page.description, page.title, page.description, content,content])              cb()            }          })        )        await WIKI.models.knex.raw(`          INSERT INTO "pagesWords" (word)            SELECT word FROM ts_stat(              'SELECT to_tsvector(''simple'', "title") || to_tsvector(''simple'', "description") || to_tsvector(''simple'', "content") FROM "pagesVector"'            )          `)        WIKI.logger.info(`(SEARCH/POSTGRES) Index rebuilt successfully.`)      }    }

更新 wikijs 的 Deployment

wiki.js 的基于 PostgreSQL 的全文检索引擎配置位于 /wiki/server/modules/search/postgres ,我们将前面配置的 ConfigMap 加载到这个目录。

# wikijs-zh.yamlkind: DeploymentapiVersion: apps/v1metadata:  name: wikijs  labels:    app: wikijsspec:  replicas: 1  selector:    matchLabels:      app: wikijs  template:    metadata:      labels:        app: wikijs    spec:      volumes:        - name: volume-dysh5f          configMap:            name: wikijs-zhparser            defaultMode: 420      containers:        - name: wikijs          image: 'requarks/wiki:2'          ports:            - name: http-3000              containerPort: 3000              protocol: TCP          envFrom:            - secretRef:                name: wikijs            - configMapRef:                name: wikijs          volumeMounts:            - name: volume-dysh5f              readOnly: true              mountPath: /wiki/server/modules/search/postgres

配置 wiki.js ,启用基于 PostgreSQL 的全文检索

$ kubectl apply -f zh-parse.yaml$ kubectl apply -f wikijs-zh.yaml

以上就是“KubeSphere中如何部署Wiki系统wiki.js并启用中文全文检索”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯