Production 级别的 clickhouse 不是随便就能搞出来的,需要对其有更深入的理解。这篇主题只是针对如何在 k8s 里快速搭建一还行的 clickhouse。主要是为了实现整个系统不对外有额外的依赖,所有的依赖服务都包含在 k8s 集群中。和 将 MySQL 通过 presslabs/mysql-operator 部署到 k8s 内部 这篇对于 mysql 的处理非常类似。
之前用于测试的 clickhouse 是一非常随便的 deployment 实现,其主要缺点有如下几个:
其中 3 的诉求并不强烈,毕竟在测试阶段对这部分的要求没有那么高,而且如果真的想要高可用可能甚至都不应该将 clickhouse 放进 k8s 里。不过 1 2 的诉求还是很强烈的。那么我这里的工作也都是针对 1 2 两项进行的。
这里采用了 Altinity/clickhouse-operator 这个方案。该方案不仅仅是完美解决了 1 2 两项问题,甚至是 3 也有做了还不错的处理。不过我这里就没有测试扩容和高可用了,主要测试的是 1 2 两部分。
按照文档安装 operator:
curl -s https://raw.githubusercontent.com/Altinity/clickhouse-operator/master/deploy/operator-web-installer/clickhouse-operator-install.sh | OPERATOR_NAMESPACE=infra bash
这里我把 operator 安装的 namespace 放到了 infra。
apiVersion: v1
kind: "ConfigMap"
metadata:
name: "serving-db-mounted-configmap" # [5]
data:
01_create_databases.sh: |
#!/bin/bash
set -e
clickhouse client -n <<-EOSQL
CREATE DATABASE IF NOT EXISTS serving;
EOSQL
---
apiVersion: "clickhouse.altinity.com/v1"
kind: "ClickHouseInstallation"
metadata:
name: "serving-db"
spec:
configuration:
settings: # [5]
max_concurrent_queries: 400
clusters:
- name: "serving-db"
layout:
shardsCount: 1
replicasCount: 1
defaults: # [1]
templates:
podTemplate: pod-template
dataVolumeClaimTemplate: data-volume-template
logVolumeClaimTemplate: log-volume-template
serviceTemplate: svc-template
templates:
serviceTemplates: # [2]
- name: svc-template
generateName: clickhouse-{chi}
spec:
ports:
- name: http
port: 8123
- name: tcp
port: 9000
type: ClusterIP
podTemplates: # [3]
- name: pod-template
spec:
containers:
- name: clickhouse
image: yandex/clickhouse-server:22.1.3
volumeMounts:
- name: serving-db-configmap-volume
mountPath: /docker-entrypoint-initdb.d
volumes:
- name: serving-db-configmap-volume
configMap:
name: serving-db-mounted-configmap
volumeClaimTemplates: # [4]
- name: data-volume-template
reclaimPolicy: Retain
spec:
storageClassName: local
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
- name: log-volume-template
reclaimPolicy: Retain
spec:
storageClassName: local
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
这个 yaml 是我集成了自己的所有诉求的最终版本,可以看到它主要包含两个部分:
serving-db-mounted-configmap
其中包含了初始化数据库的内容,这部分不是必须要,只有需要初始化数据库的时候才有ClickHouseInstallation
这个是 clickhouse operator 所提供的 crd 顾名思义,就用于创建 clickhouse 核心 crd。具体每一个东西什么意思还是看文档吧,我这里主要介绍下目前实现了上述诉求相关的内容我在上面做了注释标记([1] 这样子),下面我一个个做介绍。
defaults.templates
下定义了一系列的模板(Template)其包含了
serviceTemplate
: 暴露 clickhouse 的 service 的结构podTemplate
: 创建 clickhouse 自身的 pod 的结构dataVolumeClaimTemplate
: 提供给 clickhouse 的存储的结构serviceTemplate
其默认的类型为 LoadBalancer
由于我们的集群里不支持也不希望使用这个类型,因此这里做了自定义将其修改为了 ClusterIP
podTemplate
中首先选择 image 版本为 22.1.3 其次增加了一个额外的 volumeMounts 到路径 /docker-entrypoint-initdb.d 这样做是为了利用该 operator 所提供的钩子,实现数据库的初始,具体文档参见 02-templates-07-bootstrap-schema.yamlvolumeClaimTemplates
分别定义了 clikchouse 的日志和数据的 PVconfiguration.settings
可以自定义 clickhouse 的配置,这里我仅仅是修改了 max_concurrent_queries
这个配置,这里所写的配置最终会被合并到 clickhouse 的配置中clickhouse operator 很好的解决了我目前的两大诉求,不过在使用过程中也遇到了一个额外的问题:clickhouse 默认用户 default 无法通过 kubernete dns 去访问 clickhouse。仔细查看了下配置,发现其配置只支持 <service-name>.<namespace>.svc.cluster.local
的域名访问。这样做有两个明显的问题:
<service-name>.<namespace>
这样的 k8s 内支持的短域名访问解决的办法也很简单,就是不要用这个 default
用户,去创建一个新的用户并且设置可以访问的 ip 即可。
写 blog 的时候经常需要做中英文混排,然后这个混排为了美观需要在中和英文之间添加空格。现在形成习惯了,看到别人没有在中英文混排里添加空格都觉得有点难受。不过之前这个格式要求都靠自己敲空格敲出来的,感觉效率有点低下,恰巧发现了 autocorrect 这个工具,可以实现这个功能,这里尝试把它和我写 blog 用的 neovim 集成下实现自动格式化的功能。
首先 autocorrect
本身已经是一个二进制文件了,通过如下命令可以实现对文件的处理:
$ autocorrect --fix <filepath>
因为 vim 有一些插件可以实现在保存的时候对文件进行格式化而 autocorrect 的处理也可以认为是一种格式化因此思路就很一致了。不过相较于很多格式化工具可以以文本内容的方式传递,autocorrect 只能对文件做修改,流程上会稍微有一点区别。这里我列一下集成思路:
autocmd
的命令,可以某些重要的事件发生时(或者发生前后)执行一系列命令,这里就需要监听 BufWritePost
即当 Buf 写成功后执行一个命令我使用的是 neovim 这里就按照它的配置结果做了实现,vim 的实现也是类似的,只是具体的目录结构会有略微区别而已。
.config/nvim/after/ftplugin/markdown.vim
:
function! MarkdownFormat()
silent !autocorrect --fix '%:p' "3
let view = winsaveview() "4
silent edit "5
call winrestview(view)
redraw! "6
endfunction
augroup markdownFormat "1
autocmd! "2
autocmd BufWritePost * if &filetype ==# 'markdown' | call MarkdownFormat() | endif "7
augroup END
具体做一些解释:
augroup
相当于设置命名空间保证这个 autocmd 不影响其他的 autocmdautocmd!
是清理当前 augroup
下的所有 autocmd
没有这命令会发现不知不觉每次保存的时候 autocorrect 会执行多次,具体什么原因我尚不清楚,毕这也是我第一次折腾这些命令,后续如果有更多了解会做更多记录slient !autocorrent --fix '%:p'
!
slient
是为了不要展示其执行的结果,我们只关心它执行了,不想看到它的返回内容'%:p'
就是当前文件的绝对路径winsaveview
是保当前视图的一些信息,并且在重新加载文件后恢复,为的是不要让正在编辑的文件的视图位置、光标位置发生跳动提升体验slient edit
是重新加载文件redraw!
是刷当前视图if &filetype ==# 'markdown'
是判断当前文件格式是否为 markdown 只有是 markdown 的时候才这行这个 autocmd
k8s 为了鼓励大家更新,其 kubeadm 默认的证书有效期为 1 年,任何 k8s 版本的更新都会触发证书的更新。如果证书过期了可以按照如下方式处理:
kubeadm certs check-expiration
可以查看证书的有效期,如果报错没有命令 certs
那么可以尝试命令 kubeadm alpha certs ...
kubeadm certs renew all
更新所有证书/etc/kubernetes/manifests/
挪走,比如重命名为 manifests.1
20 秒以上,等待 static pod 全部都关闭了,然后重命名回来,这个步骤就是强迫所有的 static pod 重启,官网文档 就是这么建议操作的/etc/kubernetes/admin.conf
拷贝到自己的电脑,并将其其中的 api-server 的访问地址修改成从自己电脑可以访问的地址即可,然后具体的管理可以参考 维护一大堆 kubeconfig 的一些实践这样做现在并不是最好的方法,目前可以改进的方式有如下几个: