背景
wiki.js 是非常优秀的开源 Wiki 系统,尽管在与 xwiki 功能相比 ,还不算完善,但也在不断进步。 常用的功能还是比较实用的,如:Wiki 写作、分享、权限管理功能还是非常实用的,UI 设计非常的漂亮,精美的界面和直观的操作体验,能够满足小团队的基本知识管理需求。
认真阅读全文,教你怎么领取礼品
我们需要在 PetaExpress KubeSphere 容器平台中部署 Kubernetes集群
在 Peta Express 中部署 Kubernetes 非常的简单方便,直接使用 PetaExpress 中内置的 QKE 就可以了,首先我们需要登录到 PetaExpress 控制台(登录地址:https://cn.petaexpress.com ),在产品与服务中找到 AppCenter 控制台 → 应用中心。
找到 QKE 立即部署即可。
按照提示输入名称,选择集群规模等关键信息,然后提交就可以了。但需要注意集群的配置,如果是开发测试可以选择 “基础型开发环境” 或 “企业型测试环境”,如果是生产的话则可以选择 “基础型生产环境” 或 “企业型生产环境”,也可以自定义集群规模和HA。
我们使用 OpenEBS 作为存储,OpenEBS 默认安装的 Local StorageClass 在 Pod 销毁后自动删除,不适合用于我的数据存储,我们在 Local StorageClass 基础上稍作修改,创建新的 StorageClass,允许 Pod 销毁后,PV 内容继续保留,手动决定怎么处理。
在项目空间的 存储 → 存储类型 → 创建 进行storageClass的创建
名称:localretain
存储系统:自定义
存储卷扩容:否
回收机制:Retain
访问模式:ReadWriteOnce
存储系统:openebs.io/local
存储卷延迟绑定:延迟绑定
编辑完成后点击创建,或直接点击编辑YAML,将以下yaml内容粘贴后点击创建
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: WaitForFirstConsumer
部署 PostgreSQL 数据库
鉴于我们团队在多个项目中也需要使用 PostgreSQL, 为了提高 PostgreSQL 数据库的利用率和统一管理,我们独立部署 PostgreSQL,并在安装 wiki.js 时,配置为使用外部数据库。
准备用户名密码配置
我们使用 Secret 保存 PostgreSQL 用户密码等敏感信息。
在项目空间的配置 → 保密字典 → 创建进行保密字典的创建。
首先我们定义一个名称就叫 postgres-prod 点击下一步,类型保持默认设置即可, 添加键值对数据。
键为POSTGRES_PASSWORD,值为password ( 密码自行准备修改 )
准备数据库初始化脚本
使用 ConfigMap 保存数据库初始化脚本,在 数据库创建时,将 ConfigMap 中的数据库初始化脚本挂载到 /docker-entrypoint-initdb.d, 容器初始化时会自动执行该脚本。
在项目空间的配置 → 配置字典 → 创建进行配置字典的创建。
名称就叫 wikijs-postgres-init 然后下一步,添加键值对数据。
键为init.sql,值为
CREATE DATABASE wikijs;
CREATE USER wikijs with password ‘password’;
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 用户的密码自行准备,明文保存。
准备存储
我们使用 OpenEBS 来提供存储服务。可以通过创建 PVC 来提供持久化存储。
这里声明一个 10G 的 PVC。
需按照以下步骤操作
在项目空间的存储 → 存储卷 → 创建进行PVC的创建。
名称就叫postgres-prod-data,然后下一步,进行存储设置。
存储类型:localretain
访问模式:ReadWriteOnce
存储卷容量:10G
高级设置无需修改,点击创建按钮即可
部署 PostgreSQL 数据库
在前面的步骤准备好各种配置信息和存储后,就可以开始部署 PostgreSQL 服务了。
我们的 Kubernetes 没有配置存储阵列,使用的是 OpenEBS 作为存储,采用 Deployment 方式部署 PostgreSQL。
需按照以下步骤操作
在项目空间的 应用负载 → 工作负载 → 部署 → 创建 进行 PostgreSQL 服务的创建。
基本信息里名称就叫做postgres-prod,然后进行下一步容器组设置
容器组配置
这一步的核心就是配置postgres的容器。
容器组副本数量选择1,点击添加容器
镜像选择dockerhub中的abcfy2/zhparser:12-alpine,并选择使用默认端口,容器名称改为postgres-prod
勾选环境变量,点击引用配置字典或保密字典,资源选择postgres-prod 保密字典,资源中的键选择POSTGRES_PASSWORD,之后点击对勾完成容器配置,点击下一步配置存储卷设置
存储设置
在这一步有两个操作
挂载存储卷
挂载配置字典
挂载存储卷
选择现有存储卷postgres-prod-data,权限为读写,挂载地址为/var/lib/postgresql/data,配置好后点击对勾完成配置
挂载配置字典
选择配置字典wikijs-postgres-init,权限为只读,挂载地址为/docker-entrypoint-initdb.d,配置好后点击对勾完成配置
配置好后如下图
点击下一步进入最后的高级设置
高级设置里是一些额外配置,可以根据自己场景选择调整配置,调整完成后点击创建。
创建供其他 Pod 访问的 Service
在项目空间的应用负载 → 服务 → 创建 进行服务的创建
名称就叫postgres-prod然后下一步,进入服务设置
内部访问模式选择虚拟IP地址,指定工作负载选择postgres-prod
端口协议:TCP
端口名称:tcp-5432
容器端口:5432
服务端口:5432
点击下一步进入高级设置
高级设置里是一些额外配置,可以根据自己场景选择调整配置,调整完成后点击创建。
部署 wiki.js
准备用户名密码配置
我们使用Secret保存 wiki.js 用于连接数据库的用户名密码等敏感信息。
在项目空间的配置 → 保密字典 → 创建进行保密字典的创建。
名称就叫 wikijs 然后下一步,类型选择默认, 添加键值对数据。
键为DB_USER,值为wikijs ( 和上方初始化脚本中的用户名保持一致 )
键为DB_PASS,值为password( 和上方初始化脚本中的密码保持一致 )
准备数据库连接配置
我们使用 ConfigMap 保存 wiki.js 的数据库连接信息。
在项目空间的配置 → 配置字典 → 创建进行配置字典的创建。
名称就叫 wikijs 然后下一步,添加键值对数据。
DB_TYPE: postgres
DB_HOST: postgres-prod
DB_PORT: 5432
DB_NAME: wikijs
HA_ACTIVE: true
创建数据库用户和数据库
如果 PostgreSQL 数据库里没有创建 wikijs 用户和数据 ,需要手工完成一下工作:
通过『数据库工具』连接 PostgreSQL 数据库,执行一下 SQL 语句,完成数据库和用户的创建、授权。
CREATE DATABASE wikijs;
CREATE USER wikijs with password ‘password’;
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
这里我们采用 Deployment 方式部署 wiki.js。
在项目空间的 应用负载 → 工作负载 → 部署 → 创建 进行 wiki.js 服务的创建。
基本信息里名称就叫做wikijs,然后进行下一步容器组设置
容器组配置
这一步的核心就是配置wikijs的容器。
容器组副本数量选择1,点击添加容器
镜像选择dockerhub中的requarks/wiki:2,并选择使用默认端口,容器名称改为wikijs
勾选环境变量,点击引用配置字典或保密字典,先添加刚才创建的保密字典wikijs,然后添加配置字典wikijs,之后点击对勾完成容器配置,点击下一步配置存储卷设置
存储卷此处无需设置,点击下一步进入高级配置
高级设置里是一些额外配置,可以根据自己场景选择调整配置,调整完成后点击创建。
创建访问 wiki.js 的 Service
在项目空间的应用负载 → 服务 → 创建 进行服务的创建
名称就叫wikijs然后下一步,进入服务设置
内部访问模式选择虚拟IP地址,指定工作负载选择wikijs
端口协议:TCP
端口名称:tcp-3000
容器端口:3000
服务端口:3000
点击下一步进入高级设置,勾选外部访问,访问模式选择NodePort,完成后点击创建。
然后可以使用NodePort的IP + Port进行访问wikijs。
配置 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
在项目空间的配置 → 配置字典 → 创建进行配置字典的创建。
名称就叫 wikijs-zhparser 然后下一步,添加两个键值对数据。
键为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)
/* global WIKI */
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.`)
},
/**
* INIT
*/
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.`)
},
/**
* QUERY
*
* @param {String} q Query
* @param {Object} opts Additional options
*/
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)
}
},
/**
* CREATE
*
* @param {Object} page Page to create
*/
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])
},
/**
* UPDATE
*
* @param {Object} page Page to update
*/
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])
},
/**
* DELETE
*
* @param {Object} page Page to delete
*/
async deleted(page) {
await WIKI.models.knex(‘pagesVector’).where({
locale: page.localeCode,
path: page.path
}).del().limit(1)
},
/**
* RENAME
*
* @param {Object} page Page to rename
*/
async renamed(page) {
await WIKI.models.knex(‘pagesVector’).where({
locale: page.localeCode,
path: page.path
}).update({
locale: page.destinationLocaleCode,
path: page.destinationPath
})
},
/**
* REBUILD INDEX
*/
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 进入wikijs工作负载的详情页
点击左侧更多操作,选择编辑设置
点击存储卷 → 挂载配置字典或保密字典
选择配置字典wikijs-zhparser,权限为只读,挂载地址为/wiki/server/modules/search/postgres,配置好后点击对勾完成配置
配置 wiki.js ,启用基于 PostgreSQL 的全文检索
新的Deployment创建完成后
打开 wiki.js 管理
点击搜索引擎
选择 Database – PostgreSQL
在 Dictionary Language 的下拉菜单里选择 chinese_zh。
点击应用,并重建索引。
完成配置。
总结
“K8S学习教程(三):在PetaExpress KubeSphere 容器部署 Wiki 系统 wiki.js 并启用中文全文检索”重点讲解了wiki.js的部署方式,特别强调了其对中文全文检索功能的支持。集成了 PostgreSQL 和 zhparser 中文分词插件。
相对于标准的 wiki.js 安装部署过程,主要做了以下配置:
1、wiki.js 镜像外挂了 ConfigMap ,用于修改原 Docker 镜像里关于 PostgreSQL 搜索引擎配置的信息,以支持 chinese_zh 选项。
2、PostgreSQL 镜像采用了 abcfy2/zhparser:12-alpine ,这个镜像自带 zhparser 中文分词插件。
凭此文章可以去petaexpress官网发工单 充值≥1美元送10美元,奖励数量有限先到先得。→点击去领取←
申领步骤:注册→登录→充值→发工单 回复“文章网址+文章标题+申请奖励”,
咨询:
QQ:1984236768
Skype帐号:live:.cid.b9765a3144e14781
PDF查看:K8S学习教程(三)_在PetaExpress KubeSphere 容器部署 Wiki 系统 wiki.js 并启用中文全文检索