synchronization

This commit is contained in:
offends 2024-07-19 17:09:37 +08:00
commit 13cf58216b
37 changed files with 1644 additions and 0 deletions

53
.drone-base-image.yml Normal file
View File

@ -0,0 +1,53 @@
kind: pipeline
type: docker
name: Build Hexo-Images
trigger:
event:
include:
- custom
steps:
- name: Build Hexo-Images
image: plugins/docker
pull: if-not-exists
settings:
registry:
from_secret: REGISTRY
username:
from_secret: DOCKER_USERNAME
password:
from_secret: DOCKER_PASSWORD
repo:
from_secret: REPO
dry_run: false
tags:
- hexo
context: ./
dockerfile: ./Dockerfile-hexo
build_args:
# - IMAGENAME=node:alpine
- IMAGENAME=registry.cn-hangzhou.aliyuncs.com/offends/hexo:node-alpine
- name: Build Hexo-Async-Images
image: plugins/docker
pull: if-not-exists
settings:
registry:
from_secret: REGISTRY
username:
from_secret: DOCKER_USERNAME
password:
from_secret: DOCKER_PASSWORD
repo:
from_secret: REPO
dry_run: false
tags:
- hexo-async
context: ./
dockerfile: ./Dockerfile-hexo-async
build_args:
- IMAGENAME=registry.cn-hangzhou.aliyuncs.com/offends/hexo:hexo
volumes:
- name: dockersock
host:
path: /var/run/docker.sock

110
.drone-sync-images.yml Normal file
View File

@ -0,0 +1,110 @@
kind: pipeline
type: docker
name: Synchronization Nginx-Images
trigger:
event:
include:
- custom
steps:
- name: 同步 Nginx-Images
image: docker:dind
volumes:
- name: dockersock
path: /var/run/docker.sock
environment:
DOCKER_USERNAME:
from_secret: DOCKER_USERNAME
DOCKER_PASSWORD:
from_secret: DOCKER_PASSWORD
REGISTRY:
from_secret: REGISTRY
REPO:
from_secret: REPO
BUILD:
from_secret: BUILD
commands:
- |
docker pull nginx:alpine-slim \
&& docker login $REGISTRY -u $DOCKER_USERNAME -p $DOCKER_PASSWORD \
&& docker tag nginx:alpine-slim $REPO:nginx-alpine-slim \
&& docker push $REPO:nginx-alpine-slim
volumes:
- name: dockersock
host:
path: /var/run/docker.sock
---
kind: pipeline
type: docker
name: Synchronization Twikoo-Images
trigger:
event:
include:
- custom
steps:
- name: 同步 Twikoo-Images
image: docker:dind
volumes:
- name: dockersock
path: /var/run/docker.sock
environment:
DOCKER_USERNAME:
from_secret: DOCKER_USERNAME
DOCKER_PASSWORD:
from_secret: DOCKER_PASSWORD
REGISTRY:
from_secret: REGISTRY
REPO:
from_secret: REPO
BUILD:
from_secret: BUILD
commands:
- |
docker pull imaegoo/twikoo:latest \
&& docker login $REGISTRY -u $DOCKER_USERNAME -p $DOCKER_PASSWORD \
&& docker tag imaegoo/twikoo:latest $REPO:twikoo \
&& docker push $REPO:twikoo
volumes:
- name: dockersock
host:
path: /var/run/docker.sock
---
kind: pipeline
type: docker
name: Synchronization Node-Alpine-Image
trigger:
event:
include:
- custom
steps:
- name: 同步 Node-Alpine-Image
image: docker:dind
volumes:
- name: dockersock
path: /var/run/docker.sock
environment:
DOCKER_USERNAME:
from_secret: DOCKER_USERNAME
DOCKER_PASSWORD:
from_secret: DOCKER_PASSWORD
REGISTRY:
from_secret: REGISTRY
REPO:
from_secret: REPO
BUILD:
from_secret: BUILD
commands:
- |
docker pull node:alpine \
&& docker login $REGISTRY -u $DOCKER_USERNAME -p $DOCKER_PASSWORD \
&& docker tag node:alpine $REPO:node-alpine \
&& docker push $REPO:node-alpine
volumes:
- name: dockersock
host:
path: /var/run/docker.sock

112
.drone.yml Normal file
View File

@ -0,0 +1,112 @@
kind: pipeline
type: docker
name: Build Hexo-Async-Offends-Blog
trigger:
event:
include:
- custom
steps:
- name: Hexo-Async-Offends-Blog
image: docker:dind
volumes:
- name: dockersock
path: /var/run/docker.sock
- name: kubectl
path: /usr/local/bin/kubectl
- name: config
path: /root/.kube/config
environment:
DOCKER_USERNAME:
from_secret: DOCKER_USERNAME
DOCKER_PASSWORD:
from_secret: DOCKER_PASSWORD
REGISTRY:
from_secret: REGISTRY
REPO:
from_secret: REPO
BUILD:
from_secret: BUILD
commands:
- docker login $REGISTRY -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
- |
if [ -z "$BUILD" ]; then
echo -e "\e[31m变量未指定,请检查Secret\e[0m"
exit 1
else
if [ -n "$BUILD" ] && { [ "$BUILD" = Hexo-async-offends ] || [ "$BUILD" = "All" ]; }; then
echo -e "\033[32m开始构建\033[0m"
cd /drone/src/ \
&& docker build --build-arg IMAGENAME=registry.cn-hangzhou.aliyuncs.com/offends/hexo:hexo-async -t $REPO:hexo-async-offends -f Dockerfile-hexo-async-offends --no-cache . \
&& docker push $REPO:hexo-async-offends \
&& kubectl -n blog rollout restart deployment blog
else
echo -e "\033[33m不构建,跳过\033[0m"
fi
if [ -n "$BUILD" ] && { [ "$BUILD" = Gateway-kubernetes ] || [ "$BUILD" = "All" ]; }; then
echo -e "\033[32m开始构建\033[0m"
cd /drone/src/gateway \
&& docker build --build-arg IMAGENAME=registry.cn-hangzhou.aliyuncs.com/offends/hexo:nginx-alpine-slim -t $REPO:gateway-kubernetes -f Dockerfile-kubernetes --no-cache . \
&& docker push $REPO:gateway-kubernetes
else
echo -e "\033[33m不构建,跳过\033[0m"
fi
fi
volumes:
- name: dockersock
host:
path: /var/run/docker.sock
- name: kubectl
host:
path: /usr/local/bin/kubectl
- name: config
host:
path: /root/.kube/config
---
kind: pipeline
type: docker
name: Build Gateway-docker
trigger:
event:
include:
- custom
steps:
- name: Gateway-docker
image: docker:dind
volumes:
- name: dockersock
path: /var/run/docker.sock
environment:
DOCKER_USERNAME:
from_secret: DOCKER_USERNAME
DOCKER_PASSWORD:
from_secret: DOCKER_PASSWORD
REGISTRY:
from_secret: REGISTRY
REPO:
from_secret: REPO
BUILD:
from_secret: BUILD
commands:
- |
if [ -z "$BUILD" ]; then
echo -e "\e[31m变量未指定,请检查Secret\e[0m"
exit 1
else
if [ -n "$BUILD" ] && [ "$BUILD" = Gateway-docker ]; then
echo -e "\033[32m开始构建\033[0m"
cd /drone/src/gateway \
&& docker login $REGISTRY -u $DOCKER_USERNAME -p $DOCKER_PASSWORD \
&& docker build --build-arg IMAGENAME=registry.cn-hangzhou.aliyuncs.com/offends/hexo:nginx-alpine-slim -t $REPO:gateway-docker -f Dockerfile-docker --no-cache . \
&& docker push $REPO:gateway-docker
else
echo -e "\033[33m不构建,跳过\033[0m"
fi
fi
volumes:
- name: dockersock
host:
path: /var/run/docker.sock

28
.gitignore vendored Normal file
View File

@ -0,0 +1,28 @@
# ---> macOS
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

20
Dockerfile-hexo Normal file
View File

@ -0,0 +1,20 @@
ARG IMAGENAME
FROM ${IMAGENAME}
LABEL maintainer="Offends <offends4@163.com>"
# 开启国内加速
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
&& npm config set registry https://registry.npmmirror.com \
&& apk update
RUN npm install -g hexo-cli \
&& hexo init hexo \
&& npm install --prefix /hexo/
WORKDIR /hexo
EXPOSE 4000
CMD ["hexo", "server"]

7
Dockerfile-hexo-async Normal file
View File

@ -0,0 +1,7 @@
ARG IMAGENAME
FROM ${IMAGENAME}
RUN npm install --save hexo-renderer-less hexo-renderer-ejs \
&& npm install --save hexo-theme-async@latest \
&& sed -i 's/theme: landscape/theme: async/g' _config.yml

View File

@ -0,0 +1,10 @@
ARG IMAGENAME
FROM ${IMAGENAME}
COPY ./app/* /app/
RUN apk update && apk add --no-cache --virtual .build-deps curl bash git \
&& bash /app/init.sh \
&& rm -rf /app \
&& apk del .build-deps

20
README.md Normal file
View File

@ -0,0 +1,20 @@
# Hexo-Async-Offends
## 基础变量配置
| 变量名 | 变量值 | 备注 |
| :-------------: | :---------------------------------------------------: | :------------: |
| DOCKER_USERNAME | | 镜像仓库账号 |
| DOCKER_PASSWORD | | 镜像仓库密码 |
| REGISTRY | registry.cn-hangzhou.aliyuncs.com | 镜像仓库地址 |
| REPO | registry.cn-hangzhou.aliyuncs.com/<命名空间>/<镜像名> | 镜像的仓库名称 |
## 管理构建变量配置
| 变量名 | 变量值 | 备注 |
| :----: | :----------------: | :-------------------------------: |
| BUILD | Hexo-async-offends | 构建 Async-Offends 初始化环境镜像 |
| BUILD | Gateway-kubernetes | 构建 kubernetes 网关镜像 |
| BUILD | Gateway-docker | 构建 docker 网关镜像 |
| BUILD | All | 构建跟博客有关所有构建 |

3
app/404.md Normal file
View File

@ -0,0 +1,3 @@
---
layout: 404
---

282
app/_config.async.yml Normal file
View File

@ -0,0 +1,282 @@
# 默认主题配置, 开启切换主题功能
theme:
switch: true
default: style-light # style-light style-dark
# 网站图标 Favicon
favicon:
logo: /img/favicon-16x16.png
icon16: /img/favicon-16x16.png
icon32: /img/favicon-32x32.png
appleTouchIcon: /img/favicon-16x16.png
webmanifest: /site.webmanifest
visibilitychange: true
hidden: /img/favicon-32x32.png
showText: 打咩~
hideText: 咿呀哒~
# 字体图标 Icon
assets:
third_party_provider: https://npm.elemecdn.com
icons:
type: symbol
css:
js: //at.alicdn.com/t/c/font_3637590_i4hyyea14ur.js
# 用户信息 User
user:
name: Offends
first_name:
last_name:
email: offends4@163.com
domain: https://blog.offends.cn
avatar: /img/avatar.png
describe: 现充爆炸吧
ruleText: 尊重原创足矣。
# 导航栏 TopBars
top_bars:
- title: 首页
url: /
- title: 分类
url: /categories/
# - title: 标签
# url: /tags/
- title: 其它
url: '#'
children:
- title: 关于
url: /about/
- title: 留言
url: /comment/
- title: 友链
url: /links/
# 侧栏 Sidebar
sidebar:
social:
- name: github
icon: icon-github
url: https://github.com/dinghui40
- name: gitee
icon: icon-gitee
url: https://gitee.com/offends
# 打字动画
typedTextPrefix: [' ']
typedText: [ 'I`m Ding Hui','Welcome Back']
info:
- key: 地址
val: 银河系
- key: 年龄
val: 不清楚
- key: 实力
val: 上升期
# - key: <div><iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=260 height=86 src="//music.163.com/outchain/player?type=2&id=466808591&auto=0&height=66"></iframe></div>
# 横幅 Banner
banner:
use_cover: false
default:
type: img
bgurl: /img/desktop.png
bannerText:
position: top
fit: cover
index:
bannerTitle: 业精于勤,荒于嬉。
bannerText:
archive:
bannerTitle: 积土而为山,积水而为海。
bannerText:
links:
bannerTitle: 渚寒烟淡,棹移人远,飘渺行舟如叶。
bannerText:
comment:
bannerTitle: 天下兴亡,咱们有责,嘿嘿。
bannerText:
about:
bannerTitle: 四顾山光接水光,<br>凭栏十里芰荷香。
bannerText:
# 页脚 Footer
footer:
# 起始年份
copyrightYear: 2020
# 显示框架
powered:
enable: true
# 显示备案号
beian:
enable: true
icp: 京ICP备2022021046号
# 运行时间
live_time:
enable: true
prefix: footer.tips
start_time: 01/3/2022 00:00:00
# 其他信息
custom_text: <a href="https://beian.mps.gov.cn/#/query/webSearch" rel="noopener" target="_blank">京公网安备11010502052505号</a>
# 打赏 Reward
reward:
enable: true
comment: I'm so cute. Please give me money.
methods:
- name: 支付宝
path: /img/zfb.png
- name: 微信
path: /img/wx.png
# 文章目录
toc:
enable: true
list_number: true
max_depth: 3
min_depth: 1
# 图片懒加载
lazyload:
enable: true
# 归档页
archive:
type: less
# 版权信息
creative_commons:
license: by-nc-sa
language: deed.zh
post: true
clipboard: false
# 自定义封面图
cover:
default: /img/block.png
type: img
# 上下篇文章
post_pagination:
enable: true
type: small
# 文章过期提醒
notice_outdate:
enable: false
style: flat
limit_day: 365
position: top
# 文章破图时默认图片
error_img:
flink: /img/404.gif
post_page: /img/404.jpg
# 分类卡片
categorie_card:
enable: true
len: 2
list: ["已完成", "待验证"]
# 固定按钮块
rightside:
readmode: true
aside: true
# 日期格式化 Date Format
datetime_foramt:
post_card:
date: YY/MM/DD
time: HH:mm
post_info:
type: updated
date: MM/DD
time: HH:mm
archive:
date: MM/DD
time: HH:mm
# 代码高亮 Highlight
highlight:
theme: true
title: mac
copy: true
lang: true
code_word_wrap: true
height_limit: 200 # 超出时,显示折叠按钮
# 自定义图标 Icon
icons:
# 主题切换图标
sun: icon-sun
moon: icon-moon
# 首页视频播放
play: icon-yunhang
# 邮箱
email: icon-email
# 分类进入图标
next: icon-arrow-right
# 文章详情 日期
calendar: icon-rili
# 文章详情 时间
clock: icon-shijian
# 文章详情 作者
user: icon-yonghu
# 返回顶部 v1.1.3+
back_top: icon-backtop
# 查询 v1.1.5+
search: icon-chaxun
# 关闭 v1.1.5+
close: icon-guanbi
# 打赏 v1.1.7+
reward: icon-qiandai
# 用户信息和文章目录切换 v1.2.10+
user_tag: icon-yonghu1
toc_tag: icon-liebiao
# 右下角固定按钮 v1.2.11+
read: icon-yuedu
arrows: icon-arrows-h
# 代码块
double_arrows: icon-angle-double-down
copy: icon-copy
# 关于 About
about:
insert: none # 插入规则 before插入在内容前 | after插入在内容后 | none不插入
title: 温故而知新,可以为师矣。
introduction: 大家好,我是 Offends很高兴您能在浩瀚如烟的互联网世界里发现这个博客更感谢您能够饶有兴致地浏览这个页面。建立这个 Blog 是出于兴趣爱好,我将在此分会分享一些学习笔记,可能还会分享少许图片、视频以及其他有趣东西的链接。
blog:
<ul class="trm-list">
<li>程序Hexo </li>
<li>主题Hexo-theme-async </li>
</ul>
privacy: 本网站不会追踪访客行为,且不要求访客提供任何敏感信息(比如真实姓名、身份证号码、手机号等),因而也不存在任何隐私泄漏问题。访客参与评论,必须遵守法律法规和基本道德规范,文明礼貌。严禁发布任何有关淫秽、反动、暴力、博彩、恐吓、低俗的内容或违法信息,在尊重言论自由的同时请保持和平与理性。请勿对他人采取不友好的评论或其它过激行为。
# 评论 Comment
comment:
twikoo:
enable: true
envId: https://blog.offends.cn/twikoo
# 本地搜索
search:
enable: true
type: local
# 百度自动推送
baidu_push: true
# 字数统计
wordcount:
enable: true
count: true
time: true
# 数学公式
katex:
copy_tex: true
global: false
options: {}
# 渐入式应用
sw: true

16
app/index.less Normal file
View File

@ -0,0 +1,16 @@
.var-primary(@primary: #afb42b; @primary-weak: #c0ca33) {
--primary : @primary;
--primary-70 : fade(@primary, 70%);
--primary-50 : fade(@primary, 50%);
--primary-30 : fade(@primary, 30%);
--primary-weak : @primary-weak;
--primary-weak-50: fade(@primary-weak, 50%);
}
:root {
.var-primary(#5a5df0, #697be2);
&.dark {
.var-primary(#a4ce60, #82df7a);
}
}

163
app/init.sh Executable file
View File

@ -0,0 +1,163 @@
#!/bin/bash
#############################################################################################
# 用途: Hexo-Async-Deployer 项目初始化脚本
# 作者: 丁辉
# 编写日期: 2021-10-1
# 更新日期: 2024-07-09
#############################################################################################
# 加载检测脚本
source <(curl -sS https://gitee.com/offends/Linux/raw/main/File/Shell/Check_command.sh)
# 初始化基础信息
function INIT_BASE_INFO() {
# 修改基础模版
sed -i "s#language: en#language: zh-Hans#g" /hexo/_config.yml
sed -i "s#author: John Doe#author: Offends#g" /hexo/_config.yml
SEND_INFO "初始化基础信息"
# 本地搜索
CHECK_COMMAND_NULL npm install hexo-generator-searchdb
# 数字统计
CHECK_COMMAND_NULL npm install hexo-wordcount
# 初始化基础信息
CHECK_COMMAND_NULL mv /app/_config.async.yml /hexo/_config.async.yml
CHECK_DIR /hexo/source/_data/
CHECK_COMMAND_NULL mv /app/links.yml /hexo/source/_data/links.yml
CHECK_COMMAND_NULL mv /app/404.md /hexo/source/404.md
CHECK_COMMAND_NULL mv /app/site.webmanifest /hexo/source/site.webmanifest
CHECK_DIR /hexo/source/_data/style/
CHECK_COMMAND_NULL mv /app/index.less /hexo/source/_data/style/index.less
}
# 初始化页面
function INIT_PAGE() {
# 分类
CHECK_COMMAND_NULL npm install hexo-generator-category
# 页面名称
PAGE_NAME=(
"categories"
"links"
"about"
"comment"
)
# 循环创建页面
for name in ${PAGE_NAME[@]}; do
# 创建页面
CHECK_COMMAND_NULL hexo new page $name
if [ $? -eq 0 ]; then
# 创建页面成功
SEND_INFO "创建页面 $name 成功"
else
# 创建页面失败
SEND_WARN "创建页面 $name 失败"
fi
done
# 修改页面内容
# 友情链接
sed -i 's#title: links#title: 友情链接#g' /hexo/source/links/index.md
sed -i '3a\layout: links' /hexo/source/links/index.md
# 关于
sed -i 's#title: about#title: 关于#g' /hexo/source/about/index.md
sed -i '3a\layout: about' /hexo/source/about/index.md
sed -i '4a\single_column: false' /hexo/source/about/index.md
sed -i '5a\comments: false' /hexo/source/about/index.md
# 留言
sed -i 's#title: comment#title: 留言#g' /hexo/source/comment/index.md
sed -i '3a\layout: comment' /hexo/source/comment/index.md
# 分类
sed -i 's#title: categories#title: 分类#g' /hexo/source/categories/index.md
sed -i '3a\layout: category' /hexo/source/categories/index.md
sed -i '4a\single_column: true' /hexo/source/categories/index.md
sed -i '5a\comments: false' /hexo/source/categories/index.md
}
# 初始化图片
function INIT_IMAGE() {
# 存储地址
MINIO_URL="https://minio.offends.cn:9000/offends/hexo-async"
IMAGE_NAME=(
"avatar.png"
"favicon-16x16.png"
"favicon-32x32.png"
"block.png"
"desktop.png"
"wx.png"
"zfb.png"
"demo.png"
"404.gif"
"404.jpg"
)
CHECK_DIR /hexo/source/img
# 循环下载页面
for name in ${IMAGE_NAME[@]}; do
# 下载图片
CHECK_COMMAND_NULL curl -so /hexo/source/img/$name $MINIO_URL/$name
done
SEND_INFO "初始化图片成功"
}
# 收录配置
function INIT_BAIDU_SITEMAP() {
SEND_INFO "初始化收录配置"
################################## 百度Sitemap 和 Google Sitemap ##################################
CHECK_COMMAND_NULL npm install hexo-generator-sitemap
CHECK_COMMAND_NULL npm install hexo-generator-baidu-sitemap
sed -i "s#url: http://example.com#url: https://blog.offends.cn#g" /hexo/_config.yml
sed -i '/^url:/ {N; s/\n/\nroot: \/\n/;}' /hexo/_config.yml
sed -i 's/permalink: :year\/:month\/:day\/:title\//permalink: :title.html/' /hexo/_config.yml
cat << EOF >> /hexo/_config.yml
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml
EOF
sed -i '1i<meta name="google-site-verification" content="V1iIzgHls93z_BAPofTvRD8jwh01u4Ls0fqXgGo86Ro" />' /hexo/node_modules/hexo-theme-async/layout/_partial/head.ejs
sed -i '1i<meta name="baidu-site-verification" content="codeva-MZXYU3JS1x" />' /hexo/node_modules/hexo-theme-async/layout/_partial/head.ejs
################################## 百度主动推送 ##################################
CHECK_COMMAND_NULL npm install hexo-baidu-url-submit
sed -i '/deploy:/!b;n;s/ type: \x27\x27/- type: baidu_url_submitter/' /hexo/_config.yml
cat << EOF >> /hexo/_config.yml
baidu_url_submit:
count: 200
host: blog.offends.cn
token: CRBfMzmp8EjAnQCl
path: baidu_urls.txt
EOF
}
# 添加看板娘
function ADD_TOUCH_ICON() {
SEND_INFO "添加看板娘"
git clone https://githubfast.com/stevenjoezhang/live2d-widget.git /hexo/node_modules/hexo-theme-async/source/live2d-widget
sed -i '1i<script src="/live2d-widget/autoload.js"></script>' /hexo/node_modules/hexo-theme-async/layout/_partial/head.ejs
sed -i '1i<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome/css/font-awesome.min.css">' /hexo/node_modules/hexo-theme-async/layout/_partial/head.ejs
sed -i '2s/^/\/\/ /; 3s/^\/\///' /hexo/node_modules/hexo-theme-async/source/live2d-widget/autoload.js
sed -i 's/z-index: 1;/z-index: 9999;/g' /hexo/node_modules/hexo-theme-async/source/live2d-widget/waifu.css
sed -i 's/e=1/e=5/g' /hexo/node_modules/hexo-theme-async/source/live2d-widget/waifu-tips.js
}
# 音乐位置 : 符号去除
# function INIT_MUSIC() {
# sed -i 's/<%- __(item.key) %>:/<%- __(item.key) %>/g' /hexo/node_modules/hexo-theme-async/layout/_partial/sidebar/card/info.ejs
# }
# 执行全部初始化
function INIT_ALL() {
# 初始化基础信息
INIT_BASE_INFO
# 初始化页面
INIT_PAGE
# 初始化图片
INIT_IMAGE
# 收录配置
INIT_BAIDU_SITEMAP
# 添加看板娘
ADD_TOUCH_ICON
}
INIT_ALL

3
app/languages.yml Normal file
View File

@ -0,0 +1,3 @@
zh-Hans:
site:
title: 本站信息

8
app/links.yml Normal file
View File

@ -0,0 +1,8 @@
- name: 31100Cafe
url: https://www.biuling.top
image: https://jsd.cdn.zzko.cn/gh/CheckingChen/image-hosting@master/avatar.6awsc8i38s80.webp
desc: Creativity,起飞!
- name: 白云苍狗
url: https://www.imalun.com
image: https://www.imalun.com/images/avatar.jpg?v=1
desc: 醒,亦在人间;梦,亦在人间。

20
app/site.webmanifest Normal file
View File

@ -0,0 +1,20 @@
{
"name": "Offends",
"short_name": "Offends",
"icons": [
{
"src": "/img/favicon-16x16.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/img/favicon-32x32.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#fff",
"background_color": "#fff",
"display": "standalone",
"start_url": "/"
}

23
chart/.helmignore Normal file
View File

@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/

24
chart/Chart.yaml Normal file
View File

@ -0,0 +1,24 @@
apiVersion: v2
name: blog-chart
description: A Helm chart for Kubernetes
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.16.0"

17
chart/README.md Normal file
View File

@ -0,0 +1,17 @@
> 本文作者:丁辉
# Helm部署
开始部署
```bash
helm install blog ./chart \
--namespace blog --create-namespace
```
卸载
```bash
helm uninstall blog -n blog
```

View File

@ -0,0 +1,7 @@
Please visit this URL after startup:
{{ if .Values.ingress.host }}
https://{{ .Values.ingress.host }}
{{ end }}

View File

@ -0,0 +1,17 @@
{{/*
Startup parameter
*/}}
{{- define "argument" -}}
progressDeadlineSeconds: 200
replicas: 1
revisionHistoryLimit: 1
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
{{- end }}
{{- define "imagePullPolicy" -}}
imagePullPolicy: IfNotPresent
{{- end }}

View File

@ -0,0 +1,87 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.deployment.blog.name }}
labels:
app: {{ .Values.deployment.blog.labels.app }}
spec:
{{- include "argument" . | nindent 2 }}
selector:
matchLabels:
app: {{ .Values.deployment.blog.labels.app }}
template:
metadata:
labels:
app: {{ .Values.deployment.blog.labels.app }}
spec:
{{- if .Values.global.enabled }}
volumes:
- name: data
persistentVolumeClaim:
claimName: blog-pvc
{{- end }}
containers:
- name: {{ .Values.deployment.blog.name }}
image: {{ .Values.deployment.blog.image }}:{{ .Values.deployment.blog.tag }}
{{- include "imagePullPolicy" . | nindent 8 }}
ports:
- containerPort: {{ .Values.blog.targetPort }}
protocol: TCP
{{- if .Values.global.enabled }}
volumeMounts:
{{- range .Values.deployment.blog.volumeMounts }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
{{- end }}
{{- end }}
readinessProbe:
failureThreshold: 3
initialDelaySeconds: 5
periodSeconds: 3
successThreshold: 1
tcpSocket:
port: {{ .Values.blog.targetPort }}
timeoutSeconds: 10
resources:
limits:
memory: {{ .Values.deployment.blog.limits.memory }}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.deployment.blog_gateway.name }}
labels:
app: {{ .Values.deployment.blog_gateway.labels.app }}
spec:
{{- include "argument" . | nindent 2 }}
selector:
matchLabels:
app: {{ .Values.deployment.blog_gateway.labels.app }}
template:
metadata:
labels:
app: {{ .Values.deployment.blog_gateway.labels.app }}
spec:
containers:
- name: {{ .Values.deployment.blog_gateway.name }}
image: {{ .Values.deployment.blog_gateway.image }}:{{ .Values.deployment.blog_gateway.tag }}
{{- include "imagePullPolicy" . | nindent 8 }}
env:
{{- range .Values.deployment.blog_gateway.env }}
- name: {{ .name }}
value: {{ .value }}
{{- end }}
ports:
- containerPort: {{ .Values.blog_gateway.targetPort }}
protocol: TCP
readinessProbe:
failureThreshold: 3
initialDelaySeconds: 5
periodSeconds: 3
successThreshold: 1
tcpSocket:
port: {{ .Values.blog_gateway.targetPort }}
timeoutSeconds: 10
resources:
limits:
memory: {{ .Values.deployment.blog_gateway.limits.memory }}

View File

@ -0,0 +1,36 @@
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
{{- if .Values.ingress.redirection.enabled}}
annotations:
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/permanent-redirect-code: "301"
#kubernetes.io/ingress.class: "nginx"
ingress.kubernetes.io/ssl-redirect: "true"
ingress.kubernetes.io/secure-backends: "true"
ingress.kubernetes.io/force-ssl-redirect: "true"
{{- end }}
name: {{ .Values.ingress.name }}
spec:
ingressClassName: nginx
rules:
- host: {{ .Values.ingress.host }}
http:
paths:
- pathType: Prefix
backend:
service:
name: {{ .Values.ingress.service.name }}
port:
number: {{ .Values.ingress.service.port.number }}
path: /
{{- if .Values.ingress.tls.enabled}}
tls:
- hosts:
{{- range $.Values.ingress.tls.hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .Values.ingress.tls.secretName }}
{{- end }}
{{- end }}

18
chart/templates/pvc.yaml Normal file
View File

@ -0,0 +1,18 @@
{{- if .Values.global.enabled -}}
apiVersion: v1
kind: List
items:
{{- range .Values.global.pvcConfigs }}
- apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ .name }}
spec:
accessModes:
- {{ .accessModes }}
storageClassName: {{ .storageClass }}
resources:
requests:
storage: {{ .storage }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,41 @@
apiVersion: v1
kind: Service
metadata:
name: {{ .Values.deployment.blog.name }}
spec:
selector:
app: {{ .Values.deployment.blog.labels.app }}
ports:
- name: {{ .Values.deployment.blog.name }}
protocol: TCP
port: {{ .Values.blog.port }}
targetPort: {{ .Values.blog.targetPort }}
type: {{ .Values.blog.type }}
---
apiVersion: v1
kind: Service
metadata:
name: {{ .Values.deployment.blog_gateway.name }}
spec:
selector:
app: {{ .Values.deployment.blog_gateway.labels.app }}
ports:
- name: {{ .Values.deployment.blog_gateway.name }}
protocol: TCP
port: {{ .Values.blog_gateway.port }}
targetPort: {{ .Values.blog_gateway.targetPort }}
type: {{ .Values.blog_gateway.type }}
---
apiVersion: v1
kind: Service
metadata:
name: {{ .Values.statefulset.blog_twikoo.name }}
spec:
selector:
app: {{ .Values.statefulset.blog_twikoo.labels.app }}
ports:
- name: {{ .Values.statefulset.blog_twikoo.name }}
protocol: TCP
port: {{ .Values.blog_twikoo.port }}
targetPort: {{ .Values.blog_twikoo.targetPort }}
type: {{ .Values.blog_twikoo.type }}

View File

@ -0,0 +1,54 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: {{ .Values.statefulset.blog_twikoo.name }}
spec:
podManagementPolicy: OrderedReady
replicas: 1
revisionHistoryLimit: 0
selector:
matchLabels:
app: {{ .Values.statefulset.blog_twikoo.labels.app }}
serviceName: {{ .Values.statefulset.blog_twikoo.name }}
minReadySeconds: 5
template:
metadata:
labels:
app: {{ .Values.statefulset.blog_twikoo.labels.app }}
spec:
terminationGracePeriodSeconds: 5
containers:
- name: {{ .Values.statefulset.blog_twikoo.name }}
image: {{ .Values.statefulset.blog_twikoo.image }}:{{ .Values.statefulset.blog_twikoo.tag }}
env:
{{- range .Values.statefulset.blog_twikoo.env }}
- name: {{ .name }}
value: "{{ .value }}"
{{- end }}
ports:
- containerPort: {{ .Values.blog_twikoo.targetPort }}
protocol: TCP
resources:
limits:
memory: {{ .Values.statefulset.blog_twikoo.limits.memory }}
livenessProbe:
failureThreshold: 3
initialDelaySeconds: 5
periodSeconds: 3
successThreshold: 1
tcpSocket:
port: {{ .Values.blog_twikoo.targetPort }}
timeoutSeconds: 20
{{- if .Values.global.enabled }}
volumeMounts:
{{- range .Values.statefulset.blog_twikoo.volumeMounts }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
{{- end }}
{{- end }}
{{- if .Values.global.enabled }}
volumes:
- name: data
persistentVolumeClaim:
claimName: twikoo-pvc
{{- end }}

86
chart/values.yaml Normal file
View File

@ -0,0 +1,86 @@
# Default values for blog.
global:
enabled: true
pvcConfigs:
- name: blog-pvc
storageClass: "" # 指定存储卷, 不指定则需要集群内存在默认的存储卷
storage: "10Gi"
accessModes: ReadWriteOnce
- name: twikoo-pvc
storageClass: "" # 指定存储卷, 不指定则需要集群内存在默认的存储卷
storage: "10Gi"
accessModes: ReadWriteOnce
deployment:
blog:
name: blog
labels:
app: blog
image: registry.cn-hangzhou.aliyuncs.com/offends/hexo
tag: hexo-async-offends
limits:
memory: 512Mi
volumeMounts:
- name: data
mountPath: /hexo/source/_posts
blog_gateway:
name: blog-gateway
labels:
app: blog-gateway
image: registry.cn-hangzhou.aliyuncs.com/offends/hexo
tag: gateway-kubernetes
limits:
memory: 512Mi
env:
- name: localhost
value: "blog.offends.cn"
statefulset:
blog_twikoo:
name: blog-twikoo
labels:
app: blog-twikoo
image: registry.cn-hangzhou.aliyuncs.com/offends/hexo
tag: twikoo
limits:
memory: 128Mi
env:
- name: TWIKOO_THROTTLE
value: "1000"
volumeMounts:
- name: data
mountPath: /app/data
blog:
port: 4000
targetPort: 4000
type: ClusterIP
blog_gateway:
port: 80
targetPort: 80
type: ClusterIP
blog_twikoo:
port: 8080
targetPort: 8080
type: ClusterIP
# kubectl create secret tls blog-tls --key nginx.key --cert nginx.pem -n blog
ingress:
enabled: true
name: blog-ingress
host: blog.offends.cn
service:
name: blog-gateway
port:
number: 80
tls:
enabled: true
hosts:
- blog.offends.cn
secretName: blog-tls
redirection: #是否开启http重定向到https
enabled: true

50
docker-compose.yaml Normal file
View File

@ -0,0 +1,50 @@
version: "3"
networks:
blog_network:
driver: bridge
file_network:
driver: bridge
services:
blog:
depends_on:
- blog-twikoo
image: registry.cn-hangzhou.aliyuncs.com/offends/hexo:hexo-async-offends
container_name: blog
restart: always
volumes:
- /data/blog/data:/hexo/source/_posts
networks:
- blog_network
blog-twikoo:
image: imaegoo/twikoo:latest
container_name: blog-twikoo
restart: always
volumes:
- /data/blog/twikoo:/app/data
environment:
- TWIKOO_THROTTLE=1000
# - TWIKOO_PORT=4444
networks:
- blog_network
nginx-https:
depends_on:
- blog-twikoo
- blog
image: registry.cn-hangzhou.aliyuncs.com/offends/hexo:gateway-docker
container_name: blog-nginx
restart: always
# network_mode: "host"
volumes:
- /data/blog/cert:/etc/nginx/conf.d/cert
environment:
- DOMAIN_NAME=blog.offends.cn
ports:
- "80:80"
- "443:443"
networks:
- blog_network
- file_network

13
gateway/Dockerfile-docker Normal file
View File

@ -0,0 +1,13 @@
ARG IMAGENAME
FROM ${IMAGENAME}
ENV DOMAIN_NAME=default
EXPOSE 80 443
COPY ./ssl.conf.template /etc/nginx/conf.d/ssl.conf.template
VOLUME ["/etc/nginx/conf.d/cert/"]
CMD /bin/sh -c "envsubst '\$DOMAIN_NAME' < /etc/nginx/conf.d/ssl.conf.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"

View File

@ -0,0 +1,11 @@
ARG IMAGENAME
FROM ${IMAGENAME}
ENV DOMAIN_NAME=default
EXPOSE 80
COPY ./default.conf.template /etc/nginx/conf.d/default.conf.template
CMD /bin/sh -c "envsubst '\$localhost' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"

View File

@ -0,0 +1,16 @@
server {
listen 80;
server_name ${DOMAIN_NAME};
location / {
proxy_pass http://blog:4000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /twikoo {
proxy_pass http://blog-twikoo:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}

32
gateway/ssl.conf.template Normal file
View File

@ -0,0 +1,32 @@
server{
listen 80;
server_name ${DOMAIN_NAME};
#(第一种)把http的域名请求转成https
#return 301 https://$host$request_uri;
#(第二种)强制将http的URL重写成https
rewrite ^(.*) https://$server_name$1 permanent;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
ssl_certificate /etc/nginx/conf.d/cert/nginx.pem;
ssl_certificate_key /etc/nginx/conf.d/cert/nginx.key;
location / {
proxy_pass http://blog:4000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /twikoo {
proxy_pass http://blog-twikoo:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}

78
kubernetes/blog.yaml Normal file
View File

@ -0,0 +1,78 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: blog-pvc
namespace: blog
spec:
accessModes:
- ReadWriteOnce
storageClassName: ""
resources:
requests:
storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: blog
name: blog-deployment
labels:
app: blog
spec:
progressDeadlineSeconds: 200
replicas: 1
revisionHistoryLimit: 1
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
selector:
matchLabels:
app: blog
template:
metadata:
labels:
app: blog
spec:
volumes:
- name: data
persistentVolumeClaim:
claimName: blog-pvc
containers:
- name: blog
image: registry.cn-hangzhou.aliyuncs.com/offends/hexo:hexo-async-offends
imagePullPolicy: IfNotPresent
ports:
- containerPort: 4000
protocol: TCP
volumeMounts:
- name: data
mountPath: /hexo/source/_posts
readinessProbe:
failureThreshold: 3
initialDelaySeconds: 5
periodSeconds: 3
successThreshold: 1
tcpSocket:
port: 4000
timeoutSeconds: 10
resources:
limits:
memory: 512Mi
---
apiVersion: v1
kind: Service
metadata:
namespace: blog
name: blog
spec:
selector:
app: blog
ports:
- name: blog
protocol: TCP
port: 4000
targetPort: 4000
type: LoadBalancer
allocateLoadBalancerNodePorts: false

59
kubernetes/gateway.yaml Normal file
View File

@ -0,0 +1,59 @@
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: blog
name: blog-gateway
labels:
app: blog-gateway
spec:
progressDeadlineSeconds: 200
replicas: 1
revisionHistoryLimit: 1
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
selector:
matchLabels:
app: blog-gateway
template:
metadata:
labels:
app: blog-gateway
spec:
containers:
- name: blog-gateway
image: registry.cn-hangzhou.aliyuncs.com/offends/hexo:gateway-kubernetes
imagePullPolicy: IfNotPresent
env:
- name: localhost
value: "blog.offends.cn"
ports:
- containerPort: 80
protocol: TCP
readinessProbe:
failureThreshold: 3
initialDelaySeconds: 5
periodSeconds: 3
successThreshold: 1
tcpSocket:
port: 80
timeoutSeconds: 10
resources:
limits:
memory: 512Mi
---
apiVersion: v1
kind: Service
metadata:
namespace: blog
name: blog-gateway
spec:
selector:
app: blog-gateway
ports:
- name: blog-gateway
protocol: TCP
port: 80
targetPort: 80

View File

@ -0,0 +1,30 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/permanent-redirect-code: "301"
kubernetes.io/ingress.class: "nginx"
ingress.kubernetes.io/ssl-redirect: "true"
ingress.kubernetes.io/secure-backends: "true"
ingress.kubernetes.io/force-ssl-redirect: "true"
name: blog-ingress
namespace: blog
spec:
ingressClassName: nginx
rules:
- host: blog.offends.cn
http:
paths:
- pathType: Prefix
backend:
service:
name: blog-gateway
port:
number: 80
path: /
# 只有在启用 TLS 时才需要此部分
tls:
- hosts:
- blog.offends.cn
secretName: blog-tls

View File

@ -0,0 +1,23 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: blog-ingress
namespace: blog
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: blog.offends.cn
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: blog-gateway
port:
number: 80
tls:
- hosts:
- blog.offends.cn
secretName: blog-tls

View File

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: blog

63
kubernetes/twikoo.yaml Normal file
View File

@ -0,0 +1,63 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
namespace: blog
name: twikoo
spec:
podManagementPolicy: OrderedReady
replicas: 1
revisionHistoryLimit: 0
selector:
matchLabels:
app: twikoo
serviceName: blog-twikoo
minReadySeconds: 5
template:
metadata:
labels:
app: twikoo
spec:
terminationGracePeriodSeconds: 5
containers:
- name: twikoo
image: registry.cn-hangzhou.aliyuncs.com/offends/hexo:twikoo
env:
- name: TWIKOO_THROTTLE
value: "1000"
# - name: TWIKOO_PORT
# value: "4444"
ports:
- containerPort: 8080
protocol: TCP
resources:
limits:
memory: 128Mi
livenessProbe:
failureThreshold: 3
initialDelaySeconds: 5
periodSeconds: 3
successThreshold: 1
tcpSocket:
port: 8080
timeoutSeconds: 20
volumeMounts:
- name: host-path-volume
mountPath: /app/data
volumes:
- name: host-path-volume
hostPath:
path: /data/blog/twikoo
---
apiVersion: v1
kind: Service
metadata:
namespace: blog
name: blog-twikoo
spec:
selector:
app: twikoo
ports:
- port: 8080
targetPort: 8080
protocol: TCP
type: ClusterIP