mirror of https://github.com/Mai-with-u/MaiBot.git
feat: 为helm chart添加WebUI的辅助容器,用于反向同步配置到ConfigMap
parent
14514ba837
commit
4f6e159000
|
|
@ -1,7 +1,6 @@
|
|||
stages:
|
||||
# - initialize-maibot-git-repo
|
||||
- build
|
||||
- package
|
||||
- build-image
|
||||
- package-helm-chart
|
||||
|
||||
# 仅在helm-chart分支运行
|
||||
workflow:
|
||||
|
|
@ -9,45 +8,9 @@ workflow:
|
|||
- if: '$CI_COMMIT_BRANCH == "helm-chart"'
|
||||
- when: never
|
||||
|
||||
## 查询并将麦麦仓库的工作区置为最后一个tag的版本
|
||||
#initialize-maibot-git-repo:
|
||||
# stage: initialize-maibot-git-repo
|
||||
# image: reg.mikumikumi.xyz/base/git:latest
|
||||
# cache:
|
||||
# key: git-repo
|
||||
# policy: push
|
||||
# paths:
|
||||
# - target-repo/
|
||||
# script:
|
||||
# - git clone https://github.com/Mai-with-u/MaiBot.git target-repo/
|
||||
# - cd target-repo/
|
||||
# - export MAIBOT_VERSION=$(git describe --tags --abbrev=0)
|
||||
# - echo "Current version is ${MAIBOT_VERSION}"
|
||||
# - git reset --hard ${MAIBOT_VERSION}
|
||||
# - echo ${MAIBOT_VERSION} > MAIBOT_VERSION
|
||||
# - git clone https://github.com/MaiM-with-u/maim_message maim_message
|
||||
# - git clone https://github.com/MaiM-with-u/MaiMBot-LPMM.git MaiMBot-LPMM
|
||||
# - ls -al
|
||||
#
|
||||
## 构建最后一个tag的麦麦本体的镜像
|
||||
#build-core:
|
||||
# stage: build
|
||||
# image: reg.mikumikumi.xyz/base/kaniko-builder:latest
|
||||
# cache:
|
||||
# key: git-repo
|
||||
# policy: pull
|
||||
# paths:
|
||||
# - target-repo/
|
||||
# script:
|
||||
# - cd target-repo/
|
||||
# - export BUILD_CONTEXT=$(pwd)
|
||||
# - ls -al
|
||||
# - export BUILD_DESTINATION="reg.mikumikumi.xyz/maibot/maibot:tag-$(cat MAIBOT_VERSION)"
|
||||
# - build
|
||||
|
||||
# 将Helm Chart版本作为tag,构建并推送镜像
|
||||
# 构建并推送adapter-cm-generator镜像
|
||||
build-adapter-cm-generator:
|
||||
stage: build
|
||||
stage: build-image
|
||||
image: reg.mikumikumi.xyz/base/kaniko-builder:latest
|
||||
# rules:
|
||||
# - changes:
|
||||
|
|
@ -60,15 +23,33 @@ build-adapter-cm-generator:
|
|||
- export BUILD_ARGS="--destination ${TMP_DST}:latest"
|
||||
- build
|
||||
|
||||
# 构建并推送core-webui-cm-sync镜像
|
||||
build-core-webui-cm-sync:
|
||||
stage: build-image
|
||||
image: reg.mikumikumi.xyz/base/kaniko-builder:latest
|
||||
# rules:
|
||||
# - changes:
|
||||
# - helm-chart/core-webui-cm-sync/**
|
||||
script:
|
||||
- export BUILD_CONTEXT=helm-chart/core-webui-cm-sync
|
||||
- export TMP_DST=reg.mikumikumi.xyz/maibot/core-webui-cm-sync
|
||||
- export CHART_VERSION=$(cat helm-chart/Chart.yaml | grep '^version:' | cut -d' ' -f2)
|
||||
- export BUILD_DESTINATION="${TMP_DST}:${CHART_VERSION}"
|
||||
- export BUILD_ARGS="--destination ${TMP_DST}:latest"
|
||||
- build
|
||||
|
||||
# 打包并推送helm chart
|
||||
package-helm-chart:
|
||||
stage: package
|
||||
stage: package-helm-chart
|
||||
image: reg.mikumikumi.xyz/mirror/helm:latest
|
||||
# rules:
|
||||
# - changes:
|
||||
# - helm-chart/files/**
|
||||
# - helm-chart/templates/**
|
||||
# - helm-chart/.gitignore
|
||||
# - helm-chart/.helmignore
|
||||
# - helm-chart/Chart.yaml
|
||||
# - helm-chart/README.md
|
||||
# - helm-chart/values.yaml
|
||||
script:
|
||||
- export CHART_VERSION=$(cat helm-chart/Chart.yaml | grep '^version:' | cut -d' ' -f2)
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
adapter-cm-generator
|
||||
core-webui-cm-sync
|
||||
.gitlab-ci.yml
|
||||
|
|
@ -5,6 +5,6 @@ WORKDIR /app
|
|||
|
||||
COPY . /app
|
||||
|
||||
RUN pip3 install --no-cache-dir -i https://mirrors.ustc.edu.cn/pypi/simple -r requirements.txt
|
||||
RUN pip3 install --no-cache-dir -r requirements.txt
|
||||
|
||||
ENTRYPOINT ["python3", "adapter-cm-generator.py"]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
# 此镜像用于辅助麦麦的WebUI更新配置文件,随core容器持续运行
|
||||
FROM python:3.13-slim
|
||||
|
||||
WORKDIR /MaiMBot
|
||||
|
||||
COPY . /MaiMBot
|
||||
|
||||
RUN pip3 install --no-cache-dir -r requirements.txt
|
||||
|
||||
ENTRYPOINT ["python3", "core-webui-cm-sync.py"]
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
#!/bin/python3
|
||||
# 这个程序的作用是辅助麦麦的WebUI更新配置文件,随core容器持续运行。
|
||||
# 麦麦的配置文件存储于ConfigMap中,挂载进core容器后属于只读文件,无法直接修改。
|
||||
# 此程序将core容器内的配置文件替换为可读写的中间层临时文件。启动时将实际配置文件写入,并在后台持续检测文件变化,实时同步到k8s apiServer,反向修改ConfigMap。
|
||||
# 工作目录:/MaiMBot/webui-cm-sync
|
||||
|
||||
import os
|
||||
import time
|
||||
from datetime import datetime
|
||||
from kubernetes import client, config
|
||||
from watchdog.observers import Observer
|
||||
from watchdog.events import FileSystemEventHandler
|
||||
|
||||
work_dir = '/MaiMBot/webui-cm-sync'
|
||||
os.chdir(work_dir)
|
||||
|
||||
config.load_incluster_config()
|
||||
core_api = client.CoreV1Api()
|
||||
with open("/var/run/secrets/kubernetes.io/serviceaccount/namespace", "r") as f:
|
||||
namespace = f.read().strip()
|
||||
release_name = os.getenv("RELEASE_NAME")
|
||||
configmap_name = f'{release_name}-maibot-core'
|
||||
|
||||
# 过滤列表,只监控指定文件
|
||||
target_files = {
|
||||
os.path.abspath("model_config.toml"): "model_config.toml",
|
||||
os.path.abspath("bot_config.toml"): "bot_config.toml"
|
||||
}
|
||||
|
||||
|
||||
def get_configmap():
|
||||
"""获取core的ConfigMap内容"""
|
||||
cm = core_api.read_namespaced_config_map(name=configmap_name, namespace=namespace)
|
||||
return cm.data
|
||||
|
||||
|
||||
def set_configmap(configmap_data: dict[str, str]):
|
||||
"""设置core的ConfigMap内容"""
|
||||
core_api.patch_namespaced_config_map(configmap_name, namespace, {'data': configmap_data})
|
||||
|
||||
|
||||
class ConfigObserverHandler(FileSystemEventHandler):
|
||||
"""配置文件变化的事件处理器"""
|
||||
def on_modified(self, event):
|
||||
if os.path.abspath(event.src_path) in target_files:
|
||||
print(
|
||||
f'[{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}] File `{event.src_path}` was modified. Start to sync...')
|
||||
with open(event.src_path, "r", encoding="utf-8") as _f:
|
||||
current_data = _f.read()
|
||||
new_cm = {
|
||||
target_files[os.path.abspath("model_config.toml")]: current_data
|
||||
}
|
||||
try:
|
||||
set_configmap(new_cm)
|
||||
except client.exceptions.ApiException as _e:
|
||||
print(f'\tError while setting configmap:\n'
|
||||
f'\t\tStatus Code: {_e.status}\n'
|
||||
f'\t\tReason: {_e.reason}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# 初始化配置文件
|
||||
print(f'[{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}] Initializing config files...')
|
||||
try:
|
||||
__initial_model_config = get_configmap()['model_config.toml']
|
||||
__initial_bot_config = get_configmap()['bot_config.toml']
|
||||
except client.exceptions.ApiException as e:
|
||||
print(f'\tError while getting configmap:\n'
|
||||
f'\t\tStatus Code: {e.status}\n'
|
||||
f'\t\tReason: {e.reason}')
|
||||
exit(1)
|
||||
with open('model_config.toml', 'w') as f:
|
||||
f.write(__initial_model_config)
|
||||
with open('bot_config.toml', 'w') as f:
|
||||
f.write(__initial_bot_config)
|
||||
with open('ready', 'w') as f:
|
||||
f.write('true')
|
||||
print(f'[{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}] Initializing done. Ready to sync.')
|
||||
|
||||
# 持续检测变化并同步
|
||||
observer = Observer()
|
||||
observer.schedule(ConfigObserverHandler(), '', recursive=False)
|
||||
observer.start()
|
||||
try:
|
||||
while True:
|
||||
time.sleep(1)
|
||||
except KeyboardInterrupt:
|
||||
observer.stop()
|
||||
observer.join()
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
toml~=0.10.2
|
||||
kubernetes~=34.1.0
|
||||
watchdog~=6.0.0
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
#!/bin/sh
|
||||
# 此脚本用于覆盖core容器的默认启动命令,进行一些初始化
|
||||
# 1
|
||||
# 由于k8s与docker-compose的卷挂载方式有所不同,需要利用此脚本为一些文件和目录提前创建好软链接
|
||||
# /MaiMBot/data是麦麦数据的实际挂载路径
|
||||
# /MaiMBot/statistics是统计数据的实际挂载路径
|
||||
# 2
|
||||
# 此脚本等待辅助容器webui-cm-sync就绪后再启动麦麦
|
||||
# 通过检测/MaiMBot/webui-cm-sync/ready文件来判断
|
||||
|
||||
set -e
|
||||
echo "[K8s Init] Preparing volume..."
|
||||
|
||||
# 初次启动,在存储卷中检查并创建关键文件和目录
|
||||
mkdir -p /MaiMBot/data/plugins
|
||||
mkdir -p /MaiMBot/data/logs
|
||||
if [ ! -d "/MaiMBot/statistics" ]
|
||||
then
|
||||
echo "[K8s Init] Statistics volume disabled."
|
||||
else
|
||||
touch /MaiMBot/statistics/index.html
|
||||
fi
|
||||
|
||||
# 删除默认插件目录,准备创建用户插件目录软链接
|
||||
rm -rf /MaiMBot/plugins
|
||||
|
||||
# 创建软链接,从存储卷链接到实际位置
|
||||
ln -s /MaiMBot/data/plugins /MaiMBot/plugins
|
||||
ln -s /MaiMBot/data/logs /MaiMBot/logs
|
||||
if [ -f "/MaiMBot/statistics/index.html" ]
|
||||
then
|
||||
ln -s /MaiMBot/statistics/index.html /MaiMBot/maibot_statistics.html
|
||||
fi
|
||||
|
||||
echo "[K8s Init] Volume ready."
|
||||
|
||||
# 如果启用了WebUI,则等待辅助容器webui-cm-sync就绪,然后创建中间层配置文件软链接
|
||||
if [ "$MAIBOT_WEBUI_ENABLED" = "true" ]
|
||||
then
|
||||
echo "[K8s Init] WebUI enabled. Waiting for container 'webui-cm-sync' ready..."
|
||||
while [ ! -f /MaiMBot/webui-cm-sync/ready ]; do
|
||||
sleep 1
|
||||
done
|
||||
echo "[K8s Init] Container 'webui-cm-sync' ready."
|
||||
mkdir -p /MaiMBot/config
|
||||
ln -s /MaiMBot/webui-cm-sync/model_config.toml /MaiMBot/config/model_config.toml
|
||||
ln -s /MaiMBot/webui-cm-sync/bot_config.toml /MaiMBot/config/bot_config.toml
|
||||
echo "[K8s Init] Config files middle layer for WebUI created."
|
||||
else
|
||||
echo "[K8s Init] WebUI disabled."
|
||||
fi
|
||||
|
||||
# 启动麦麦
|
||||
echo "[K8s Init] Waking up MaiBot..."
|
||||
echo
|
||||
exec python bot.py
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
#!/bin/sh
|
||||
# 此脚本用于覆盖core容器的默认启动命令
|
||||
# 由于k8s与docker-compose的卷挂载方式有所不同,需要利用此脚本为一些文件和目录提前创建好软链接
|
||||
# /MaiMBot/data是麦麦数据的实际挂载路径
|
||||
# /MaiMBot/statistics是统计数据的实际挂载路径
|
||||
|
||||
set -e
|
||||
echo "[VolumeLinker] Preparing volume..."
|
||||
|
||||
# 初次启动,在存储卷中检查并创建关键文件和目录
|
||||
mkdir -p /MaiMBot/data/plugins
|
||||
mkdir -p /MaiMBot/data/logs
|
||||
if [ ! -d "/MaiMBot/statistics" ]
|
||||
then
|
||||
echo "[VolumeLinker] Statistics volume disabled."
|
||||
else
|
||||
touch /MaiMBot/statistics/index.html
|
||||
fi
|
||||
|
||||
# 删除空的插件目录,准备创建软链接
|
||||
rm -rf /MaiMBot/plugins
|
||||
|
||||
# 创建软链接,从存储卷链接到实际位置
|
||||
ln -s /MaiMBot/data/plugins /MaiMBot/plugins
|
||||
ln -s /MaiMBot/data/logs /MaiMBot/logs
|
||||
if [ -f "/MaiMBot/statistics/index.html" ]
|
||||
then
|
||||
ln -s /MaiMBot/statistics/index.html /MaiMBot/maibot_statistics.html
|
||||
fi
|
||||
|
||||
# 启动麦麦
|
||||
echo "[VolumeLinker] Starting MaiBot..."
|
||||
exec python bot.py
|
||||
|
|
@ -18,17 +18,21 @@ spec:
|
|||
spec:
|
||||
containers:
|
||||
- name: core
|
||||
command: # 为了在k8s中初始化存储卷,这里替换启动命令为指定脚本
|
||||
command: # 为了在k8s中初始化,这里替换启动命令为指定脚本
|
||||
- sh
|
||||
args:
|
||||
- /MaiMBot/volume-linker.sh
|
||||
- /MaiMBot/k8s-init.sh
|
||||
env:
|
||||
- name: TZ
|
||||
value: Asia/Shanghai
|
||||
value: "Asia/Shanghai"
|
||||
- name: EULA_AGREE
|
||||
value: 99f08e0cab0190de853cb6af7d64d4de
|
||||
value: "99f08e0cab0190de853cb6af7d64d4de"
|
||||
- name: PRIVACY_AGREE
|
||||
value: 9943b855e72199d0f5016ea39052f1b6
|
||||
value: "9943b855e72199d0f5016ea39052f1b6"
|
||||
{{- if .Values.core.webui.enabled }}
|
||||
- name: MAIBOT_WEBUI_ENABLED
|
||||
value: "true"
|
||||
{{- end}}
|
||||
image: {{ .Values.core.image.repository | default "sengokucola/maibot" }}:{{ .Values.core.image.tag | default "0.11.5-beta" }}
|
||||
imagePullPolicy: {{ .Values.core.image.pullPolicy }}
|
||||
ports:
|
||||
|
|
@ -47,14 +51,15 @@ spec:
|
|||
volumeMounts:
|
||||
- mountPath: /MaiMBot/data
|
||||
name: data
|
||||
- mountPath: /MaiMBot/volume-linker.sh
|
||||
- mountPath: /MaiMBot/k8s-init.sh
|
||||
name: scripts
|
||||
readOnly: true
|
||||
subPath: volume-linker.sh
|
||||
subPath: k8s-init.sh
|
||||
- mountPath: /MaiMBot/.env
|
||||
name: config
|
||||
readOnly: true
|
||||
subPath: .env
|
||||
{{- if not .Values.core.webui.enabled }}
|
||||
- mountPath: /MaiMBot/config/model_config.toml
|
||||
name: config
|
||||
readOnly: true
|
||||
|
|
@ -63,10 +68,26 @@ spec:
|
|||
name: config
|
||||
readOnly: true
|
||||
subPath: bot_config.toml
|
||||
{{- end }}
|
||||
{{- if .Values.statistics_dashboard.enabled }}
|
||||
- mountPath: /MaiMBot/statistics
|
||||
name: statistics
|
||||
{{- end }}
|
||||
{{- if .Values.core.webui.enabled }}
|
||||
- mountPath: /MaiMBot/webui-cm-sync
|
||||
name: webui-cm-sync
|
||||
{{- end }}
|
||||
{{- if .Values.core.webui.enabled }}
|
||||
- name: webui-cm-sync
|
||||
image: {{ .Values.core.webui.cm_sync.image.repository | default "reg.mikumikumi.xyz/maibot/core-webui-cm-sync" }}:{{ .Values.core.webui.cm_sync.image.tag | default "0.11.5-beta" }}
|
||||
imagePullPolicy: {{ .Values.core.webui.cm_sync.image.pullPolicy }}
|
||||
env:
|
||||
- name: RELEASE_NAME
|
||||
value: {{ .Release.Name }}
|
||||
volumeMounts:
|
||||
- mountPath: /MaiMBot/webui-cm-sync
|
||||
name: webui-cm-sync
|
||||
{{- end }}
|
||||
{{- if .Values.core.setup_default_plugins }}
|
||||
initContainers: # 用户插件目录存储在存储卷中,会在启动时覆盖掉容器的默认插件目录。此初始化容器用于默认插件更新后或麦麦首次启动时为用户自动安装默认插件到存储卷中
|
||||
- args:
|
||||
|
|
@ -86,6 +107,7 @@ spec:
|
|||
readOnly: true
|
||||
subPath: setup-plugins.py
|
||||
{{- end }}
|
||||
serviceAccountName: {{ .Release.Name }}-maibot-sa
|
||||
{{- if .Values.core.image.pullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{ toYaml .Values.core.image.pullSecrets | nindent 8 }}
|
||||
|
|
@ -104,8 +126,8 @@ spec:
|
|||
claimName: {{ .Release.Name }}-maibot-core
|
||||
- configMap:
|
||||
items:
|
||||
- key: volume-linker.sh
|
||||
path: volume-linker.sh
|
||||
- key: k8s-init.sh
|
||||
path: k8s-init.sh
|
||||
{{- if .Values.core.setup_default_plugins }}
|
||||
- key: setup-plugins.py
|
||||
path: setup-plugins.py
|
||||
|
|
@ -127,3 +149,7 @@ spec:
|
|||
persistentVolumeClaim:
|
||||
claimName: {{ .Release.Name }}-maibot-statistics-dashboard
|
||||
{{- end }}
|
||||
{{- if .Values.core.webui.enabled }}
|
||||
- emptyDir: {}
|
||||
name: webui-cm-sync
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ metadata:
|
|||
namespace: {{ .Release.Namespace }}
|
||||
data:
|
||||
# core
|
||||
volume-linker.sh: |
|
||||
{{ .Files.Get "files/volume-linker.sh" | nindent 4 }}
|
||||
k8s-init.sh: |
|
||||
{{ .Files.Get "files/k8s-init.sh" | nindent 4 }}
|
||||
# core的初始化容器
|
||||
{{- if .Values.core.setup_default_plugins }}
|
||||
setup-plugins.py: |
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ spec:
|
|||
backoffLimit: 2
|
||||
template:
|
||||
spec:
|
||||
serviceAccountName: {{ .Release.Name }}-maibot-adapter-cm-generator
|
||||
serviceAccountName: {{ .Release.Name }}-maibot-sa
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: adapter-cm-generator
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
# 动态生成adapter配置文件的configmap所需要的rbac授权
|
||||
# 初始化及反向修改ConfigMap所需要的rbac授权
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-maibot-adapter-cm-generator
|
||||
name: {{ .Release.Name }}-maibot-sa
|
||||
namespace: {{ .Release.Namespace }}
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-maibot-adapter-cm-gen-role
|
||||
name: {{ .Release.Name }}-maibot-role
|
||||
namespace: {{ .Release.Namespace }}
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
|
|
@ -21,13 +21,13 @@ rules:
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-maibot-adapter-cm-gen-role-binding
|
||||
name: {{ .Release.Name }}-maibot-rolebinding
|
||||
namespace: {{ .Release.Namespace }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ .Release.Name }}-maibot-adapter-cm-generator
|
||||
name: {{ .Release.Name }}-maibot-sa
|
||||
namespace: {{ .Release.Namespace }}
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: {{ .Release.Name }}-maibot-adapter-cm-gen-role
|
||||
name: {{ .Release.Name }}-maibot-role
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
|
|
@ -67,6 +67,11 @@ core:
|
|||
|
||||
webui: # WebUI相关配置
|
||||
enabled: true # 默认启用
|
||||
cm_sync: # WebUI的辅助容器配置
|
||||
image:
|
||||
repository: # 默认 reg.mikumikumi.xyz/maibot/core-webui-cm-sync
|
||||
tag: # 默认 0.11.5-beta
|
||||
pullPolicy: IfNotPresent
|
||||
service:
|
||||
type: ClusterIP # ClusterIP / NodePort 指定NodePort可以将内网的服务端口映射到物理节点的端口
|
||||
port: 8001 # 服务端口
|
||||
|
|
|
|||
Loading…
Reference in New Issue