语雀写作,Kubernetes部署——Hexo相关的持续集成
背景
之前也尝试过Github Action相关的工具进行语雀和博客的持续集成,但是它会依赖语雀Webhook、函数计算服务、Github Action等,其中一个出问题,那么整个流程就不可用。因此在“尽量减少外部依赖”的思路下,除了必须的Hexo仓库和语雀,重新在Kubernetes集群上构建了基于Elog+Hexo博客的持续集成流程。
你需要做的前期准备工作是:
- 一个原始hexo git仓库
- 一个安装了Ingress、Cert Manager的K8s集群和K8s操作经验;没有的话可以参考前面的文章搭建一套云上云下的轻量K3s集群
- 喝一杯咖啡的时间
流程介绍
整个博客自动化的流程如上图所示:
- Kubernetes集群中的elog-yuque-syner通过Elog定时获取是否有内容更新
- 当在语雀等平台完成内容写作,内容发生变动后,syner中的elog感知到之后发起blog Pod资源的删除
- Kubernetes集群中的Deployment控制器就会拉起一个新的Pod
- 新的Pod首先会从Git拉取基础的Hexo站点配置
- Pod中的Elog工具会拉取语雀中更新过后的博客内容
- Hexo生成网站内容,Caddy启动,博客重新部署完成
操作方法
密钥配置
从本地SSH私钥文件创建Secrets, 需要确认这个私钥对应的公钥已经在git仓库中配置过
1 2
| kubectl crete ns blog kubectl create - n blog secret generic private-key --from-file=id_rsa=<SSH私钥文件路径>
|
部署博客
按如下blog.yaml文件修改对应配置后,部署Hexo博客相关的资源至集群中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
| apiVersion: v1 kind: ConfigMap metadata: name: init-script namespace: blog data:
elog.env: | YUQUE_USERNAME=<语雀用户名> YUQUE_PASSWORD=<语雀密码> YUQUE_LOGIN=<账号登陆名> YUQUE_REPO=<仓库ID> elog.config.js: | module.exports = { write: { platform: 'yuque-pwd', 'yuque-pwd': { username: process.env.YUQUE_USERNAME, password: process.env.YUQUE_PASSWORD, login: process.env.YUQUE_LOGIN, repo: process.env.YUQUE_REPO, onlyPublic: false, onlyPublished: true, linebreak: false, }, }, deploy: { platform: 'local', local: { outputDir: './source/_posts', filename: 'title', format: 'matter-markdown', catalog: false, formatExt: '', }, }, image: { enable: false }, } init.sh: | mkdir -p /root/.ssh/ cp /etc/ssh-key/id_rsa /root/.ssh/ chmod 600 /root/.ssh/id_rsa cd /tmp/ ssh-keyscan -p 22 github.com >> ~/.ssh/known_hosts git clone git@github.com:demo/site.git cd ./site npm --registry https://registry.npmmirror.com install rm -rf source/_posts/* cp /tmp/script/elog.config.js ./ elog sync -e /tmp/script/elog.env hexo generate cp -R ./public/* /tmp/public/ yuque-sync.sh: | cd /cache cp /tmp/script/elog.config.js ./ while true; do result=$(elog sync -e /tmp/script/elog.env) echo $result if echo "$result" | grep -q "没有需要同步的文档"; then sleep 15 else kubectl --token=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) delete pods -l app=hexo-caddy sleep 5m fi done --- apiVersion: v1 kind: ConfigMap metadata: name: caddy-config namespace: blog data: Caddyfile: | :80 { root * /var/www/html file_server } --- apiVersion: apps/v1 kind: Deployment metadata: name: hexo-caddy namespace: blog spec: selector: matchLabels: app: hexo-caddy replicas: 1 template: metadata: labels: app: hexo-caddy spec: initContainers: - name: init image: registry.cn-hangzhou.aliyuncs.com/custom-toolkit/toolkit:hexo-git-openssh-elog imagePullPolicy: Always command: ["sh"] args: ["/tmp/script/init.sh"] volumeMounts: - name: private-key mountPath: /etc/ssh-key readOnly: true - name: script-vol mountPath: /tmp/script - name: public-vol mountPath: /tmp/public containers: - name: caddy image: caddy:2.4.0-alpine command: ["caddy"] args: ["run", "--config", "/etc/caddy/Caddyfile"] volumeMounts: - name: public-vol mountPath: /var/www/html - name: caddy-vol mountPath: /etc/caddy/ ports: - containerPort: 80 volumes: - name: private-key secret: secretName: private-key - name: public-vol emptyDir: {} - name: script-vol configMap: name: init-script - name: caddy-vol configMap: name: caddy-config --- apiVersion: v1 kind: Service metadata: labels: app: hexo-caddy name: hexo-caddy-service namespace: blog spec: ports: - protocol: TCP port: 80 targetPort: 80 selector: app: hexo-caddy --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: hexo-caddy namespace: blog annotations: traefik.ingress.kubernetes.io/router.middlewares: default-redirectscheme-https@kubernetescrd cert-manager.io/cluster-issuer: letsencrypt-prod spec: tls: - secretName: hexo-blog-cert hosts: - <你的博客域名> rules: - host: <你的博客域名> http: paths: - path: / pathType: ImplementationSpecific backend: service: name: hexo-caddy-service port: number: 80
|
总结下上面配置中的注意点,必须修改的包括:
- 语雀账号和仓库配置
- Hexo博客仓库地址和文件夹名
- 博客域名
可能需要修改的包括:
- 集群内的Ingress配置,用于重定向
- 集群内的Cert Manager Issuer,用于为你的博客域名自动签发证书
部署定时同步任务
等待第二步中的博客部署成功后,按如下elog-yuque-syncer.yaml文件部署定时同步专用的Pod。Pod启动时会默认执行一次博客重建,可以用来验证任务是否能够执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| apiVersion: v1 kind: ServiceAccount metadata: name: pod-operator-sa namespace: blog --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: pod-operator-role namespace: blog rules: - apiGroups: [""] resources: ["pods"] verbs: ["*"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: authorization-role-binding namespace: blog subjects: - kind: ServiceAccount name: pod-operator-sa roleRef: kind: Role name: pod-operator-role apiGroup: rbac.authorization.k8s.io --- apiVersion: apps/v1 kind: Deployment metadata: name: elog-yuque-syncer namespace: blog spec: selector: matchLabels: app: elog-yuque-syncer replicas: 1 template: metadata: labels: app: elog-yuque-syncer spec: serviceAccountName: pod-operator-sa containers: - name: syncer image: registry.cn-hangzhou.aliyuncs.com/custom-toolkit/toolkit:hexo-git-openssh-elog imagePullPolicy: Always command: ["sh"] args: ["/tmp/script/yuque-sync.sh"] volumeMounts: - name: script-vol mountPath: /tmp/script - name: cache-vol mountPath: /cache volumes: - name: cache-vol emptyDir: {} - name: script-vol configMap: name: init-script
|
部署完毕后,执行以下命令观察博客Pod是否正常删除
1 2 3
| hexo kubectl -n blog logs -l app=elog-yuque-syncer
# 正常返回如: pod "hexo-caddy-66956dcbfd-ppdpc" deleted
|
附录
工具镜像Dockerfile如下
1 2 3 4 5 6 7 8 9
| FROM --platform=linux/amd64 alpine@sha256:48d9183eb12a05c99bcc0bf44a003607b8e941e1d4f41f9ad12bdcc4b5672f86
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories && \ apk add --no-cache curl git openssh nodejs npm && \ node -v && npm -v RUN npm install -g hexo-cli @elog/cli@0.12.2 && \ rm -rf /var/cache/apk/* RUN wget https://dl.k8s.io/release/v1.28.4/bin/linux/amd64/kubectl -O /usr/local/bin/kubectl && \ chmod a+x /usr/local/bin/kubectl
|