Halo 简介
Halo 是一款现代化的开源博客/CMS系统,具有快捷部署和较多漂亮主题模版的特性,深受很多用户喜欢,Halo 还提供了完善的 Content API 和 Admin API,这让用户可以用于开发单页面模板,微信小程序,各种系统插件等。Halo 的官方网站地址是 https://halo.cn。
写在前面
Halo 的单机部署非常简单,在具有 JRE 的操作系统里,只需要一条命令即可完成部署,自身包含 H2 Database;并且 Halo 还提供了基于 docker 的容器镜像,同样单机环境一条镜像启动命令即可完成部署。同时 Halo 为了支持较大规模的访问请求,也支持采用外置 MySQL 数据库和 Redis 作为缓存组件。官方文档提供了Docker Compose配置文件,可以同时创建 Halo + MySQL + Redis 实例,参考链接地址:https://docs.halo.run/getting-started/install/other/docker-compose。
KubeSphere 是一款在 Kubernetes 之上构建的面向云原生应用的分布式操作系统,完全开源,支持多云与多集群管理,提供全栈的 IT 自动化运维能力,支持 DevOps 工作流和微服务治理等等,总之 KubeSphere 是一款超厉害的 kubernetes 发行版软件平台。
即然 Halo 的部署已经如此之简单了,为啥还要折腾将 Halo 部署在 KubeSphere 平台之上,对于个人建站来说多少有点“千里马拉犁耙”感觉。其实主要还是因为 Halo 的部署可以结合一个标准的 web 集群所依赖的部分组件,而且目前网上关于 halo 在 Kubernetes 上部署的文章很少,几乎没有,个人也是抱着学习的心态认为在 kubesphere 上部署 Halo 可以更好的帮我们了解 kubesphere 平台的一些操作使用技巧,因而写了这篇文章。在 kubephere 官方文档 快速入门 章节有一篇《创建并部署 WordPress 》,作为 kubesphere 入门教程,这篇文档写的已经相当不错,但是我个人觉得还需要一个当对于部署 wordpress 来说进阶版的操作教程,这也是写这篇文章的另一个初衷,在 kubesphere 上部署 halo,涉及到的知识点除了包含 MySQL 数据库之外,还增加了 Redis 缓存组件,并且还较部署wordpress 那篇文档增加了 ConfigMap 和 初始化容器(Init Container)的使用。
本文全程参考该 kubesphere 官方文档《创建并部署 WordPress》的写作手法,
部署架构
本次部署组合采用 Halo + MySQL + Redis。Halo 作为前端服务,MySQL 作为后端数据库,Redis 作缓存。在 kubesphere 平台上创建一个项目,该项目下创建三个服务,分别是 halo-sevice,mysql-service 和 redis-service,具体服务包含内容如下:
准备工作
KubeSphere 需要提前安装好,安装文档参考 kubesphere 社区文档。kubesphere 安装完成之后,创建企业空间、项目、用户和角色。这里我们已经创建好了名称为 demo-workspace 的企业空间,并在该空间里创建了名称为 halo 的项目,创建了具有该项目操作权限的用户。
安装部署
步骤1:创建密钥
创建 halo 服务所需密钥
环境变量 SPRING_DATASOURCE_PASSWORD
和 SPRING_REDIS_PASSWORD
是分别是 halo 服务连接到 MySQL 数据库与 halo 服务连接到 Redis 的密码。在此步骤中,需要创建一个密钥来保存,以避免明文使用该密码。
1、使用准备工作创建的账户登陆 KubeSphere 控制台,访问halo项目的详情页并导航到配置。在保密字典中,点击右侧的创建。
2、 输入基本信息(将其命名为 halo-secret
)并点击下一步。在下一页中,选择类型为默认,然后点击添加数据来添加键值对。输入如下所示的键(Key)SPRING_DATASOURCE_PASSWORD
和值(Value)123456
,点击右下角 √ 进行确认。继续点击添加数据来添加第二组键值对。输入如下所示的键(Key)SPRING_REDIS_PASSWORD
和值(Value)123456
,点击右下角 √ 进行确认。完成后,点击创建按钮以继续。
创建 MySQL 服务所需密钥
按照以上相同的步骤创建一个名为 mysql-secret
的 MySQL 密钥,输入键(Key)MYSQL_ROOT_PASSWORD
和值(Value)123456
。
步骤2:创建 ConfigMap
创建 MySQL 服务所需配置
MySQL 数据库的配置主要存放在 my.cnf
文件里,本次部署需要的配置内容如下:
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
[mysqld]
default_authentication_plugin=mysql_native_password
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
explicit_defaults_for_timestamp=true
1、使用准备工作创建的账户登陆 KubeSphere 控制台,访问 halo 项目的详情页并导航到配置。在配置字典中,点击右侧的创建。
2、输入基本信息(将其命名为 mysql-config
)并点击下一步。在下一页中,点击添加数据来添加键值对。输入如下所示的键(Key)和值(Value),点击右下角 √ 进行确认。完成后,点击创建按钮以继续。
创建 Redis 服务所需配置
Redis 的配置主要存放在 redis.conf
文件里,本次部署需要的配置内容如下:
port 6379
bind 0.0.0.0
appendonly yes
protected-mode no
requirepass 123456
按照以上相同的步骤创建一个名为 redis-config
的 ConfigMap,输入如下所示的键(Key)和值(Value),点击右下角 √ 进行确认。完成后,点击创建按钮以继续。
步骤3:创建存储卷
1、访问存储下的存储卷,点击创建。
2、输入卷的基本信息(例如,将其命名为 halo-pvc
),然后点击下一步。
3、在存储卷设置中,需要选择一个可用的存储类型,并设置访问模式和存储卷容量。可以直接使用默认值,点击下一步继续。
4、在高级设置中,无需添加额外的配置,点击创建完成即可。
步骤4:创建应用程序
添加 MySQL 后端组件
1、导航到应用负载下的应用,选择自制应用 > 创建。
2、输入基本信息(例如,在应用名称一栏输入 halo
),然后点击下一步。
3、在服务设置中,点击创建服务以在应用中设置组件。
4、设置组件的服务类型为有状态服务。
5、 输入有状态服务的名称(例如 mysql-service
)并点击下一步。
6、 在容器设置中,点击添加容器。
7、在搜索框中输入 mysql:8.0.27
,按下回车键,然后点击使用默认端口。由于配置还未设置完成,请不要点击右下角的 √ 按钮。
8、 向下滚动到环境变量,点击引用配置文件或密钥。输入名称 MYSQL_ROOT_PASSWORD
,然后选择 mysql-secret
资源和前面步骤中创建的密钥 MYSQL_ROOT_PASSWORD
。继续点击添加环境变量,输入键 MYSQL_DATABASE
值 halodb
。完成后点击 √ 保存配置,最后点击下一步继续。
9、选择存储卷设置中的添加存储卷模板,输入存储卷名称( mysql-pvc
)和挂载路径(模式:读写
,路径:/var/lib/mysql
)的值。完成后,点击 √ 保存配置。
10、选择存储卷中的挂载配置字典或保密字典,点击选择配置字典,选择 mysql-config
,输入挂载路径(模式:只读
,路径:/etc/mysql/conf.d/my.cnf
)的值,点击挂载路径输入框最右面灰色方块,指定子路径 my.cnf
,点击确认。完成后,点击 √ 保存配置。击下一步继续。
11、在高级设置中,可以直接点击创建,也可以按需选择其它选项。
12、现在,MySQL 组件已经添加完成。
添加 Redis 后端组件
1、按照以上相同的步骤创建一个名为 redis-service
的有状态服务
2、在容器设置中,点击添加容器。在搜索框中输入 busybox:1.32
,按下回车键,容器类型选择为初始化容器,容器名称填写为 system-init
。由于配置还未设置完成,请不要点击右下角的 √ 按钮。
3、向下滚动到启动命令,勾选上启动命令,如数以下命令:
sh,-c,echo 2048 > /proc/sys/net/core/somaxconn && echo never > /sys/kernel/mm/transparent_hugepage/enabled
参数留空。继续向下滚动到容器安全上下文,打开访问控制下的特选模式开关。完成后点击 √ 保存配置。
4、在容器设置中,继续点击添加容器。在搜索框中输入 redis:5.0.8
,按下回车键,然后点击使用默认端口,容器类型选择为工作容器
,容器名称填写为 halo-redis
。由于配置还未设置完成,请不要点击右下角的 √ 按钮。
5、向下滚动到健康检查,勾选上健康检查,点击存活检查下的添加探针,选择TCP端口,端口填写 6379
,初始延迟填写 300
,超时时间填写 1
,检查间隔填写 10
,成功阈值填写 1
,失败阈值填写 3
,完成后点击 √ 保存存活检查配置。
点击就绪检查下的添加探针,选择TCP端口,端口填写 6379
,初始延迟填写 5
,超时时间填写 1
,检查间隔填写 10
,成功阈值填写 1
,失败阈值填写 3
,完成后点击 √ 保存就绪检查配置。
6、向下滚动到启动命令,勾选上启动命令,如数以下命令:
sh,-c,redis-server /usr/local/etc/redis/redis.conf
参数留空。完成后点击 √ 保存配置。最后点击下一步继续。
7、选择存储卷设置中的添加存储卷模板,输入存储卷名称(redis-pvc
)和挂载路径的值,为容器组 halo-redis
配置挂载路径,模式:读写
,挂载路径:/data
。完成后,点击 √ 保存配置。
8、选择存储卷中的挂载配置字典或保密字典,点击选择配置字典,选择 redis-config
,为容器组 halo-redis
配置挂载路径(模式:只读
,路径:/usr/local/etc/redis/redis.conf
)的值,点击挂载路径输入框最右面灰色方块,指定子路径 redis.conf
,点击确认。完成后,点击 √ 保存配置。击下一步继续。
9、在高级设置中,可以直接点击创建,也可以按需选择其它选项。
10、现在,Redis 组件已经添加完成。
添加 Halo 前端组件
1、再次点击创建服务,选择无状态服务。输入名称 halo-service
并点击下一步。
2、与上述步骤类似,点击添加容器,在搜索栏中输入 halohub/halo:1.5.2
并按下回车键,然后滚动下滑到端口设置,名称配置为 http-8090
,容器端口配置为 8090
,服务端口配置为 8090
。
3、向下滚动到环境变量,这里需要配置10个环境变量,如下:
SERVER_PORT=8090
# halo门户对外暴漏的端口,这里配置的值要跟上面端口配置保持一致
SPRING_DATASOURCE_DRIVER_CLASS_NAME=com.mysql.cj.jdbc.Driver
# 数据库类型的选择,支持H2Database和MySQL数据库,这里配置的数据库为MySQL
SPRING_DATASOURCE_URL=jdbc:mysql://mysql-service:3306/halodb?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
# 数据库连接地址,k8s里采用dns通信,所以这里3306端口前面需要填写为MySQL的Service名称
SPRING_DATASOURCE_USERNAME=root
# 数据库的用户名
SPRING_DATASOURCE_PASSWORD=halo-secret.SPRING_DATASOURCE_PASSWORD
# 访问数据库使用的密码,这里应选择使用引用配置文件或密钥的方式,避免明文密码,引用前面创建的secret
HALO_ADMIN_PATH=admin
# Halo支持自定义后台管理的根路径,这里默认admin即可。
HALO_CACHE=redis
# 缓存方式,目前支持memory、level和redis三种,这里选择redis。
SPRING_REDIS_PORT=6379
# 访问redis的端口号
SPRING_REDIS_DATABASE=0
# 保持默认即可,默认为0
SPRING_REDIS_HOST=redis-service
# redis连接地址,k8s采用dns通信,所以之类填写redis的service名称。
SPRING_REDIS_PASSWORD=halo-secret.SPRING_REDIS_PASSWORD
# 访问redis使用的密码,这里应选择使用引用配置文件或密钥的方式,避免明文密码,引用前面创建的secret
环境变量相关说明可参考 Halo 官方文档:https://docs.halo.run/getting-started/config
按照上述内容配置环境变量,截图如下,完成后,点击 √ 保存配置,选择下一步。
4、选择存储卷设置中的挂载存储卷,选择存储卷 helo-pvc
,配置挂载模式:读写
,路径:/root/.halo
)的值。完成后,点击 √ 保存配置。点击下一步继续。
5、在高级设置中,直接点击创建。
6、现在 Halo 前端组件也设置完成,点击下一步继续。
7、在路由设置里设置路由规则(应用路由Ingress),点击添加路由规则,选择指定域名,域名和协议根据自己需求填写,将 halo-service
的 8090
端口暴漏给外部。
8、创建后,应用将显示在应用列表中。
步骤5:验证应用
在工作负载中,分别检查部署和有状态副本集中 halo-service-v1
、mysql-service-v1
和 redis-service-v1
的状态。如果状态为运行中,说明 Halo 已经成功创建。
步骤6:通过 NodePort 访问 Halo
1、若要在集群外访问 Halo,首先导航到项目设置 > 网关设置,点击开启网关。访问模式这里选择 NodePort
,然后确定。
2、导航到应用负载 > 应用路由,点击 halo-ingress-xxxx
进去该应用路由,根据页面 域名+端口
访问 halo 门户。
备注:域名需要可以被 dns 解析,若不能被解析需要在本地 hosts 文件添加相应解析信息。如果需要在 Halo 门户上上传较大的附件,例如,图片、视频、主题包等,需要在应用路由上配置如下注释内容:
nginx.ingress.kubernetes.io/proxy-body-size: '0'
否则上传将会失败,报 413 Request Entity Too Large 错误。
Halo 门户页面如下:
写在最后
通过将 Halo 部署在 kubesphere 上借助部署(Deployment)多副本伸缩能力可以轻松实现 Halo 的分布式部署,通过配置容器组调度规则,可以实现 Halo 前端服务的分布式多活架构,如下图,容器组调度规则配置为分散调度,尽可能将容器组副本调度到不同的节点上。
配置之后,会发现容器组副本尽可能分散在不同的工作节点上:
使用该方案也有一个前提就是 halo 前端服务挂载的持久化存储卷需为共享文件系统,例如,本次采用的 NFS 文件存储。
当然,只有 halo 前端服务支持分布式部署还远远不够,若想实现整个系统具备分布式高可用的能力,在某一个工作节点发生故障的时候不影响 Halo 网站的正常访问,还需要后端 MySQL 数据库和 Redis缓存采用集群部署,例如,MySQL 和 Redis 都采用一主多从的部署方案。