在K8s上部署Mastodon
准备工作
因为原来用于跑毛象的服务器(参见旧文《Docker下的Mastodon安装笔记》 )到期停机了,正好手里有一个高配的arm免费机可以用,于是就打算把服务迁移过来——顺便试试部署到K8s上。
需要:
- 一台或多台服务器集群,内存至少4G,推荐8G,最好16G或更多,有外网IP,有一个域名
- 安装Kubernetes集群(可以使用k3s、minikube或云服务商的K8s服务,本文使用一个kubeadm安装的单节点k8s,见《在单机上用kubeadm安装K8s》)
- 一个SMTP服务——第三方或本地,这里用了第三方服务
- 创建必要的存储目录(根据实际节点名称调整路径,这里使用/var/data)
- 拉取Redis/Postgresql/ES/Mastodon镜像
crictl pull redis:7-alpine
crictl pull postgres:17-alpinie
crictl pull elasticsearch:7.10.1
crictl pull ghcr.io/mastodon/mastodon:v4.5.2
crictl pull ghcr.io/mastodon/mastodon-streaming:v4.5.2
配置存储
1. 创建命名空间
首先创建mastodon命名空间:
kubectl apply -f ns_mastodon.yml
ns_mastodon.yml
apiVersion: v1
kind: Namespace
metadata:
name: mastodon
2. 配置Local PV/PVC(用于有状态服务)
我们使用local PV/PVC为PostgreSQL、Redis和Elasticsearch提供持久化存储:
Redis存储配置
# 创建Redis数据目录(在目标节点上)
sudo mkdir -p /var/data/redis/data
sudo chown 999:999 /var/data/redis/data
# 应用PV/PVC配置
kubectl apply -f local_redis.yml
local_redis.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-redis-data
labels:
type: local
spec:
capacity:
storage: 10Gi # 总容量,根据实际需要调整
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-redis-data
local:
path: /var/data/redis/data
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- myserver # 替换为实际节点名称
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: redis-data-pvc
namespace: mastodon
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi # 主数据存储大小
storageClassName: local-redis-data
selector:
matchLabels:
type: local
PostgreSQL存储配置
# 创建PostgreSQL数据目录(在目标节点上)
sudo mkdir -p /var/data/pgdata
sudo mkdir -p /var/data/pgbak
sudo chown 70:70 /var/data/pgdata /var/data/pgbak
sudo chmod 700 /var/data/pgdata
# 应用PV/PVC配置
kubectl apply -f local_posgresql.yml # 内容参考redis,不过需要配置data和bak两个PV/PVC
Elasticsearch存储配置
# 创建Elasticsearch数据目录(在目标节点上)
sudo mkdir -p /var/data/elasticsearch
sudo chown 1000:1000 /var/data/elasticsearch
# 应用PV/PVC配置
kubectl apply -f local_elasticsearch.yml # 内容参考redis
3. 配置NFS PV/PVC(用于Mastodon Public文件夹)
Mastodon需要共享存储来存储用户上传的媒体文件,因为需要同时给两个服务(web和streaming)使用,所以使用NFS PV/PVC:
# 创建NFS共享目录
sudo mkdir -p /var/data/mastodon
sudo chown 991:991 /var/data/mastodon
# 配置NFS服务器(如果尚未配置)
# 安装NFS服务器
sudo apt-get install nfs-kernel-server
# 配置NFS导出
echo "/var/data/mastodon *(rw,sync,no_subtree_check,no_root_squash,all_squash,anonuid=991,anongid=991)" | sudo tee -a /etc/exports
sudo exportfs -a # 应用配置
sudo systemctl restart nfs-kernel-server
sudo exportfs -v # 查看应用结果
# 应用NFS配置
kubectl apply -f nfs_mastodon.yml
nsf_mastodon.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-mastodon-data-web
labels:
type: nfs
spec:
capacity:
storage: 150Gi # 总容量,根据实际需要调整
volumeMode: Filesystem
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs-mastodon-data-web
nfs:
server: 10.244.0.1 # flannel的IP
path: /var/data/mastodon
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mastodon-data-web-pvc
namespace: mastodon
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 150Gi # 主数据存储大小
storageClassName: nfs-mastodon-data-web
selector:
matchLabels:
type: nfs
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-mastodon-data-sidekiq
labels:
type: nfs
spec:
capacity:
storage: 150Gi # 总容量,根据实际需要调整
volumeMode: Filesystem
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs-mastodon-data-sidekiq
nfs:
server: 10.244.0.1 # 连同一个NFS
path: /var/data/mastodon
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mastodon-data-sidekiq-pvc
namespace: mastodon
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 150Gi # 主数据存储大小
storageClassName: nfs-mastodon-data-sidekiq
selector:
matchLabels:
type: nfs
部署有状态服务(Stateful Headless Services)
1. 部署Redis
创建Redis的StatefulSet配置:
kubectl apply -f svc_redis.yml
svc_redis.yml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
namespace: mastodon
spec:
serviceName: redis-headless # 需要一个 Headless Service 管理网络标识
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
ports:
- containerPort: 6379
volumeMounts:
- name: redis-data
mountPath: /data
livenessProbe:
exec:
command: ["redis-cli", "ping"]
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
exec:
command: ["redis-cli", "ping"]
initialDelaySeconds: 5
periodSeconds: 10
volumes:
- name: redis-data
persistentVolumeClaim:
claimName: redis-data-pvc # 直接使用现有 PVC
volumeClaimTemplates: []
---
apiVersion: v1
kind: Service
metadata:
name: redis-headless
namespace: mastodon
spec:
clusterIP: None # Headless Service,直接解析到 Pod IP
selector:
app: redis
ports:
- port: 6379
name: redis
2. 部署PostgreSQL
PostgreSQL使用StatefulSet和Headless Service:
kubectl apply -f svc_postgresql.yml # 内容参考svc_redis.yml,不过要mount两个卷
3. 部署Elasticsearch
创建Elasticsearch的StatefulSet配置:
kubectl apply -f svc_elasticsearch.yml # 内容参考svc_redis.yml
4. 验证部署
kubectl get statefulsets -n mastodon
kubectl get pods -n mastodon -l app=postgresql
kubectl get services -n mastodon | grep postgresql
配置Mastodon
1. 准备环境配置文件
编辑 env.production 文件,配置以下关键参数:
# Redis配置
REDIS_HOST=redis-headless.mastodon.svc.cluster.local
REDIS_PORT=6379
# 数据库配置
DB_HOST=postgresql-headless.mastodon.svc.cluster.local
DB_PORT=5432
DB_NAME=mastodon
DB_USER=mastodon
DB_PASS=你的数据库密码
# Elasticsearch配置
ES_ENABLED=true
ES_HOST=es-headless.mastodon.svc.cluster.local
ES_PORT=9200
# 域名配置
LOCAL_DOMAIN=你的域名
2. 创建Secret配置
将环境配置创建为Secret:
kubectl create secret generic mastodon-env --from-env-file=env.production -n mastodon
3. 部署Mastodon服务
注意:除非是全新安装的实例,否则此操作需要在数据库恢复后进行。
创建Mastodon的Deployment配置:
kubectl apply -f svc_mastodon.yml # 类似svc_redis.yml,不过里面有三个服务:web,streaming,sidekiq
其中mastodon的web和streaming是以NodePort方式输出服务。
恢复数据库
1. 全库备份恢复方式
使用pg_dumpall备份全库再恢复到k8s里。
# 从源docker环境备份整个库
docker exec postgresql pg_dumpall -U postgres | gzip > pgoldbak.sql.gz
# 把备份传输到k8s环境
# 恢复数据
gunzip -c pgoldbak.sql.gz | kubectl exec postgresql -i -n mastodon --command -- psql -U postgres
2. 基于WAL的增量备份恢复方式
备份恢复方式参考《PostgreSQL的连续备份配置》
3. 启动实例
恢复数据库确认无误后即可启动毛象实例。
启动服务
所有服务启动后检查状态:
kubectl get all -n mastodon
如果所有Pod都处于Running状态,说明部署成功。如果有问题,则需要查看日志检查原因。
kubectl logs -f <podname> -nmastodon
配置Nginx反向代理
创建Nginx配置,将流量代理到Mastodon服务:
cat > nginx/mastodon.conf << EOF
upstream backend {
server <NODE_IP>:3xxxx; # 替换为节点IP和mastodon-web的NodePort
}
upstream streaming {
server <NODE_IP>:3yyyy; # 替换为节点IP和mastodon-streaming的NodePort
}
server {
listen 80;
server_name 你的域名;
return 301 https://\$server_name\$request_uri;
}
server {
listen 443 ssl http2;
server_name 你的域名;
ssl_certificate /etc/ssl/你的域名/fullchain.pem;
ssl_certificate_key /etc/ssl/你的域名/privkey.pem;
root /var/data/mastodon/public;
location / {
try_files \$uri @proxy;
}
location @proxy {
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_set_header Proxy "";
proxy_pass_header Server;
proxy_pass http://backend;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "upgrade";
tcp_nodelay on;
}
location /api/v1/streaming/ {
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_set_header Proxy "";
proxy_pass http://streaming;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "upgrade";
tcp_nodelay on;
}
}
EOF
日常运维
1. 监控服务状态
# 查看所有资源状态
kubectl get all -n mastodon
# 查看Pod日志
kubectl logs -f deployment/mastodon-web -n mastodon
kubectl logs -f deployment/mastodon-streaming -n mastodon
kubectl logs -f deployment/mastodon-sidekiq -n mastodon
# 查看有状态服务日志
kubectl logs -f statefulset/postgresql -n mastodon
kubectl logs -f statefulset/redis -n mastodon
kubectl logs -f statefulset/elasticsearch -n mastodon
2. 定期清理
由于联邦宇宙中的内容会不断增加,需要定期清理过期数据,具体实现与之前docker方式部署一样,只是把docker命令改成相应的kubectl命令。
可以将这些清理任务添加到crontab中定期执行。
3. 备份与恢复
也可以参考前文实现,或者参考pgsql的wal备份那篇用备份wal的方式实现连续备份。
4. 升级Mastodon版本
升级Mastodon需要按顺序进行:
- 备份数据库
- 更新镜像版本
- 重新部署服务
# 更新镜像版本
sed -i 's|ghcr.io/mastodon/mastodon:v4.5.2|ghcr.io/mastodon/mastodon:新版本|g' svc_mastodon.yml
sed -i 's|ghcr.io/mastodon/mastodon-streaming:v4.5.2|ghcr.io/mastodon/mastodon-streaming:新版本|g' svc_mastodon.yml
# 重新部署
kubectl apply -f svc_mastodon.yml
故障排除
1. Pod无法启动
检查Pod状态和日志:
kubectl describe pod <pod-name> -n mastodon
kubectl logs <pod-name> -n mastodon
常见问题:
- 存储卷挂载失败:检查PV/PVC状态
kubectl get pv,pvc -n mastodon - 资源配置不足:检查资源限制
kubectl describe pod <pod-name> -n mastodon | grep -A 5 Resources - 镜像拉取失败:检查镜像名称和标签
2. 服务无法访问
检查服务状态:
kubectl get services -n mastodon
kubectl describe service <service-name> -n mastodon
确保NodePort在正确范围内(30000-32767)。
3. 数据库连接问题
检查数据库服务:
# 测试数据库连接
kubectl run test-db-connection --rm -i --restart=Never \
--image=postgres:17-alpine --namespace=mastodon -- \
psql -h postgresql-headless.mastodon.svc.cluster.local -U postgres -c "\l"
4. 存储问题
检查存储状态:
kubectl get pv,pvc -n mastodon
kubectl describe pvc <pvc-name> -n mastodon
确保本地目录存在且有正确权限。
总结
本指南介绍了如何使用Kubernetes部署Mastodon实例,包括:
- 存储配置:使用local PV/PVC为有状态服务(PostgreSQL、Redis、Elasticsearch)提供持久化存储
- 网络配置:使用NFS PV/PVC为Mastodon public文件夹提供共享存储
- 服务部署:使用StatefulSet和Headless Service部署有状态服务,使用Deployment部署无状态服务
- 运维管理:包括监控、清理、备份、升级等日常运维操作
相比docker-compose部署方式,Kubernetes部署提供了更好的可扩展性、高可用性和运维便利性。可以根据实际需求调整资源配置和副本数量。
注意事项
- 安全性:生产环境需要配置更严格的安全策略,如Network Policies、Pod Security Policies等
- 性能:根据实际负载调整资源限制和副本数量
- 监控:建议配置Prometheus和Grafana进行监控
- 备份:定期备份数据库和重要数据
- 更新:关注Mastodon和安全更新,及时升级
如有问题,请参考Mastodon官方文档或Kubernetes官方文档。
推送到[go4pro.org]