redis
部署
[root@k8s-master redis]# ls
namespace.yaml redis-config.yaml redis-master.yaml redis-slave.yaml
[root@k8s-master redis]# cat namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: redis
[root@k8s-master redis]# cat redis-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: redis-config
namespace: redis
data:
redis-master.conf: |
port 6379
bind 0.0.0.0
protected-mode no
daemonize no
timeout 0
save ""
appendonly no
maxmemory 1gb
maxmemory-policy allkeys-lru
redis-slave.conf: |
port 6379
bind 0.0.0.0
protected-mode no
daemonize no
timeout 0
save ""
appendonly no
maxmemory 1gb
maxmemory-policy allkeys-lru
slaveof redis-master-0.redis-master.redis.svc.cluster.local 6379
slave-read-only yes
redis-master
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis-master
namespace: redis
spec:
serviceName: redis-master
replicas: 1
selector:
matchLabels:
app: redis-master
template:
metadata:
labels:
app: redis-master
spec:
containers:
- name: redis-master
image: redis:6
command:
- /bin/sh
- -c
- |
redis-cli FLUSHALL # 清空所有缓存
redis-server /etc/redis/redis-master.conf
ports:
- containerPort: 6379
volumeMounts:
- name: redis-config
mountPath: /etc/redis
- name: redis-data
mountPath: /data
volumes:
- name: redis-data
persistentVolumeClaim:
claimName: redis-master-pvc
- name: redis-config
configMap:
name: redis-config
---
apiVersion: v1
kind: Service
metadata:
name: redis-master
namespace: redis
spec:
clusterIP: None
selector:
app: redis-master
ports:
- port: 6379
targetPort: 6379
redis-slave
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis-slave
namespace: redis
spec:
serviceName: redis-slave
replicas: 2
selector:
matchLabels:
app: redis-slave
template:
metadata:
labels:
app: redis-slave
spec:
containers:
- name: redis-slave
image: redis:6
command:
- /bin/sh
- -c
- |
redis-cli FLUSHALL # 清空所有缓存
redis-server /etc/redis/redis-master.conf
ports:
- containerPort: 6379
volumeMounts:
- name: redis-config
mountPath: /etc/redis
volumes:
- name: redis-config
configMap:
name: redis-config
---
apiVersion: v1
kind: Service
metadata:
name: redis-slave
namespace: redis
spec:
clusterIP: None
selector:
app: redis-slave
ports:
- port: 6379
targetPort: 6379
mysql
部署
[root@k8s-master mysql]# ls
aaa_mysql.sh configmap.yaml init-scripts.yaml master.yaml mysql.yaml secret.yaml slave.yaml
[root@k8s-master mysql]# cat mysql.yaml
apiVersion: v1
kind: Namespace
metadata:
name: mysql
[root@k8s-master mysql]# cat secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysql-secrets
namespace: mysql
type: Opaque
data:
root-password: MTIzLmNvbQ== # 解码后:123.com
[root@k8s-master mysql]# cat init-scripts.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-init-scripts
namespace: mysql
data:
master-init.sql: |
# 从环境变量获取密码(避免明文)
CREATE USER IF NOT EXISTS 'rsyncuser'@'%' IDENTIFIED BY '123.com';
GRANT REPLICATION SLAVE ON *.* TO 'rsyncuser'@'%';
CREATE DATABASE IF NOT EXISTS discuz;
CREATE USER IF NOT EXISTS 'discuz'@'%' IDENTIFIED BY '123.com';
GRANT ALL PRIVILEGES ON discuz.* TO 'discuz'@'%';
CREATE DATABASE IF NOT EXISTS biyesheji;
CREATE USER IF NOT EXISTS 'tomcat'@'%' IDENTIFIED BY '123.com';
GRANT ALL PRIVILEGES ON biyesheji.* TO 'tomcat'@'%';
FLUSH PRIVILEGES;
slave-init.sql: |
CHANGE MASTER TO
MASTER_HOST = 'mysql-master-0.mysql-master.mysql.svc.cluster.local',
MASTER_PORT = 3306,
MASTER_USER = 'rsyncuser',
MASTER_PASSWORD = '123.com', # 从环境变量获取
MASTER_AUTO_POSITION = 1;
START SLAVE;
[root@k8s-master mysql]# cat configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-config
namespace: mysql
data:
master.cnf: |
[mysqld]
server-id=10
log_bin=/var/lib/mysql/mysql-bin.log
read_only=0
bind-address=0.0.0.0
gtid_mode=ON
enforce_gtid_consistency=ON
default_authentication_plugin=mysql_native_password
slave1.cnf: |
[mysqld]
server-id=20
relay_log=/var/lib/mysql/mysql-relay-bin.log
log_bin=/var/lib/mysql/mysql-bin.log
read_only=1
bind-address=0.0.0.0
gtid_mode=ON
enforce_gtid_consistency=ON
default_authentication_plugin=mysql_native_password

mysql-master
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql-master
namespace: mysql
spec:
serviceName: mysql-master
replicas: 1
selector:
matchLabels:
app: mysql-master
template:
metadata:
labels:
app: mysql-master
spec:
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secrets
key: root-password
volumeMounts:
- name: mysql-config
mountPath: /etc/mysql/conf.d/master.cnf
subPath: master.cnf
- name: master-init-script # 仅挂载主库脚本
mountPath: /docker-entrypoint-initdb.d/master-init.sql
subPath: master-init.sql # 明确指定脚本名
volumes:
- name: mysql-config
configMap:
name: mysql-config
items:
- key: master.cnf
path: master.cnf
- name: master-init-script # 关联 ConfigMap 中的主库脚本
configMap:
name: mysql-init-scripts
items:
- key: master-init.sql
path: master-init.sql
---
apiVersion: v1
kind: Service
metadata:
name: mysql-master
namespace: mysql
spec:
ports:
- port: 3306
name: mysql
clusterIP: None
selector:
app: mysql-master




mysql-slave
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql-slave
namespace: mysql
spec:
serviceName: mysql-slave
replicas: 1
selector:
matchLabels:
app: mysql-slave
template:
metadata:
labels:
app: mysql-slave
spec:
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secrets
key: root-password
volumeMounts:
- name: mysql-config
mountPath: /etc/mysql/conf.d/slave.cnf
subPath: slave1.cnf
- name: init-script
mountPath: /docker-entrypoint-initdb.d
volumes:
- name: mysql-config
configMap:
name: mysql-config
items:
- key: slave1.cnf
path: slave1.cnf
- name: init-script
configMap:
name: mysql-init-scripts
---
apiVersion: v1
kind: Service
metadata:
name: mysql-slave
namespace: mysql
spec:
ports:
- port: 3306
name: mysql
clusterIP: None
selector:
app: mysql-slave
web-nginx
构建自定义镜像
配置文件
nginx
server {
listen 80;
server_name localhost;
root /var/www/html;
index index.php index.html index.htm;
access_log /var/log/nginx/discuz_access.log;
error_log /var/log/nginx/discuz_error.log;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php83-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}

php-fpm
[www]
user = nginx
group = nginx
listen = /run/php/php83-fpm.sock
listen.owner = nginx
listen.group = nginx
listen.mode = 0660
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
php_admin_value[error_log] = /var/log/php83/www-error.log
php_admin_flag[log_errors] = on
Dockerfile
FROM alpine:latest
RUN apk update && apk add --no-cache \
php83 php83-fpm php83-mysqlnd php83-gd php83-mbstring \
php83-curl php83-json php83-openssl php83-xml \
php83-mysqli php83-tokenizer php83-pdo php83-pdo_mysql \
nginx php83-redis vim
RUN mkdir -p \
/run/nginx \
/var/www/html \
/run/php &&\
chown -R nginx:nginx /var/www/html /run/nginx && \
chmod 755 /var/www/html
#nginx配置
COPY discuz.conf /etc/nginx/http.d/default.conf
#php配置
COPY www.conf /etc/php83/php-fpm.d/www.conf
#暴露端口
EXPOSE 80
#运行
CMD ["sh","-c","php-fpm83 --nodaemonize & nginx -g 'daemon off;'"]

启动容器

编写测试文件
index.html
web-nginx
info.php
<?php
phpinfo();
?>

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
$host = 'mysql-master-0.mysql-master.mysql.svc.cluster.local'; // 数据库主机地址
$user = 'discuz'; // MySQL 用户名
$pass = '123.com'; // MySQL 用户密码
$dbname = 'discuz'; // 要连接的数据库名
// 尝试连接 MySQL
$conn = new mysqli($host, $user, $pass, $dbname);
// 检查连接错误
if ($conn->connect_error) {
// 连接失败时终止脚本并输出错误
die('连接失败:' . $conn->connect_error);
}
// 连接成功,输出数据库版本信息
echo "MySQL 连接成功!数据库版本:" . $conn->server_info;
?>

<?php
$redis = new Redis();
try {
// 连接Master(替换为你的实际地址和端口)
$conn = $redis->connect('redis-master.redis.svc.cluster.local', 6379, 2);
if ($conn) {
echo "连接成功!";
echo "Redis响应:" . $redis->ping(); // 测试服务响应
} else {
echo "连接失败(无错误信息)";
}
} catch (RedisException $e) {
// 打印具体错误(如:连接超时、拒绝连接、认证失败等)
echo "Redis连接错误:" . $e->getMessage();
}

导入dicuz文件
docker cp ./ c37e6292ca17:/var/www/html/
修改属主

修改discuz默认配置(upload/config/)
config_global_default.php
数据库

从库
redis数据库

config_ucenter_default.php

镜像导出
[root@k8s-master web-nginx]# docker commit 9fbf6304f924 web-nginx:latest
sha256:79c04b1494346f3e4111229e2d902c40ee73c8beb1ad9d65df2111c0906fa73b
[root@k8s-master web-nginx]# docker save -o web-nginx.tar web-nginx:latest

镜像导入每个节点



部署web-nginx
编写 启动文件

启动

访问





默认即可

问题
出现这个页面时,将redi缓存清理就ok



taomcat
自定义镜像

下载镜像
docker pull tomcat:8


生成测试镜像
docker run -itd --name tomcat -v /root/xm/tomcat/shangcheng/:/usr/local/tomcat/webapps/ --restart=always tomcat:8

sql文件拷贝给mysql库

注入sql语句
将复制的 sql文件内容拷贝到 configmap.yaml 文件中


主配置 匹配cofihmap
volumeMounts:
- name: biyesheji-sql
mountPath: /docker-entrypoint-initdb.d/biyesheji.sql
subPath: biyesheji.sql
volumes:
- name: biyesheji-sql
configMap:
name: mysql-config
items:
- key: biyesheji.sql
path: biyesheji.sql

验证

编写镜像

修改商城默认配置

vim WEB-INF/classes/jdbc.properties

vim /usr/local/tomcat/webapps/biyesheji/WEB-INF/classes/jdbc.properties

docker commit d44d4163 shangcheng:v1
docker save -o shangcheng.tar a4e0365

将镜像拷给各节点



docker tag a4e036 shangcheng:v1
如果
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> a4e0365f328b 6 minutes ago 208MB
部署商城
apiVersion: v1
kind: Namespace
metadata:
name: web
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep-tomcat
namespace: web
spec:
replicas: 1
selector:
matchLabels:
app: web-tomcat
template:
metadata:
labels:
app: web-tomcat
spec:
containers:
- name: tomcat
image: shangcheng:v1 # 使用你的镜像
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080 # 容器内暴露的端
---
apiVersion: v1
kind: Service
metadata:
name: svc-tomcat
namespace: web # 指定命名空间为 discuz
spec:
type: NodePort
ports:
- port: 8080 # 集群内访问端口
targetPort: 8080 # 容器内端口
nodePort: 30808 # 对外暴露的节点端口
selector:
app: web-tomcat # 匹配 Deployment 的标签

启动
结论
访问成功(/biyesheji/fore/foreIndex/) 
discuz与nginx基于域名访问

拷贝镜像并导入


解压并提交


loadbalance模式
kubectl -n ingress-nginx edit svc ingress-nginx-controller


创建ip池
cat >IPAddressPool.yaml<<EOF
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: planip-pool #这里与下面的L2Advertisement的ip池名称需要一样
namespace: metallb-system
spec:
addresses:
- 192.168.11.140-192.168.11.170 #自定义ip段
EOF

关联IP池
cat >L2Advertisement.yaml<<EOF
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: planip-pool
namespace: metallb-system
spec:
ipAddressPools:
- planip-pool #这里需要跟上面ip池的名称保持一致
EOF

提交
kubectl apply -f IPAddressPool.yaml
kubectl apply -f L2Advertisement.yaml

添加规则
kubectl apply -f ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress # 创建一个类型为Ingress的资源
metadata:
name: nginx-ingress # 这个资源的名字为 nginx-ingress
namespace: web
spec:
ingressClassName: nginx # 使用nginx
rules:
- host: nginx.wezzer.com # 访问此内容的域名
http:
paths:
- backend:
service:
name: svc-discuz # 对应nginx的服务名字,该规则的namespace必须与service的一致
port:
number: 80 # 访问的端口
path: / # 匹配规则
pathType: Prefix # 匹配类型,这里为前缀匹配
- host: tomcat.wezzer.com # 访问此内容的域名
http:
paths:
- backend:
service:
name: svc-tomcat # 对应nginx的服务名字,该规则的namespace必须与service的一致
port:
number: 8080 # 访问的端口
path: / # 匹配规则
pathType: Prefix # 匹配类型,这里为前缀匹配


修改hosts文件
结果


持久化部署(pvc)
确保每台主机下载 nfs-utils
1、共享目录文件
vim /etc/exports

2、mysql 可持久化
2.1、生成pv对应 共享目录
apiVersion: v1
kind: PersistentVolume
metadata:
name: mysql-master
spec:
capacity:
storage: 10Gi
accessModes: ["ReadWriteMany"]
nfs:
path: /data/mysql/master
server: 192.168.11.20
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: mysql-slave
spec:
capacity:
storage: 10Gi
accessModes: ["ReadWriteMany"]
nfs:
path: /data/mysql/slave
server: 192.168.11.20


2.2、生成对应pvc 对应 pv
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-master-pvc
namespace: mysql
spec:
accessModes: ["ReadWriteMany"]
resources:
requests:
storage: 8Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-slave-pvc
namespace: mysql
spec:
accessModes: ["ReadWriteMany"]
resources:
requests:
storage: 8Gi


2.3、修改配置文文件 对应 pvc
mysql启动时会查看 /var/lib/mysql/ 文件 ,如果是空,则进行初始化操作,如果有这继承该文件内容
master

slave

更新

结果

3、redis 持久化
3.1、添加pv 对应 共享目录
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: redis-master
spec:
capacity:
storage: 10Gi
accessModes: ["ReadWriteMany"]
nfs:
path: /data/redis/master
server: 192.168.11.20
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: redis-slave
spec:
capacity:
storage: 10Gi
accessModes: ["ReadWriteMany"]
nfs:
path: /data/redis/slave
server: 192.168.11.20
3.2、添加pvc 对应pv
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: redis-master-pvc
namespace: redis
spec:
accessModes: ["ReadWriteMany"]
resources:
requests:
storage: 8Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: redis-slave-pvc
namespace: redis
spec:
accessModes: ["ReadWriteMany"]
resources:
requests:
storage: 8Gi

3.3、修改配置文件 对应 pvc
master

slave

更新

结果

4、web-discuz 持久化
4.1、添加pv 对应 共享目录
apiVersion: v1
kind: PersistentVolume
metadata:
name: nginx-discuz
spec:
capacity:
storage: 10Gi
accessModes: ["ReadWriteMany"]
nfs:
path: /data/discuz
server: 192.168.11.20

4.2、添加pvc 对应 pv
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: discuz-pvc
namespace: web
spec:
accessModes: ["ReadWriteMany"]
resources:
requests:
storage: 8Gi

4.3、再共享目录中添加对应文件
chown -R 100:101 *



4.4、修改配置文件 对应 pvc
spec.template.spec 下的 containers 添加 volumeMounts
spec.template.spec(与 containers 同级)中添加 volumes 部分


4.5、访问





4.6、验证持久化
将discuz论坛部署后

添加新用户



删除 nginx的pod
删除 mysql的pod



删除redis 的pod


5、tomcat 持久化
5.1、添加 pv 对应 共享目录
apiVersion: v1
kind: PersistentVolume
metadata:
name: tomcat-shangcheng
spec:
capacity:
storage: 10Gi
accessModes: ["ReadWriteMany"]
nfs:
path: /data/tomcat
server: 192.168.11.20

5.2、添加pvc 对应 pv
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: tomcat-pvc
namespace: web
spec:
accessModes: ["ReadWriteMany"]
resources:
requests:
storage: 8Gi

5.3、修改配置文件 对应 pvc
volumeMounts:
- name: tomcat-data
mountPath: /usr/local/tomcat/webapps
volumes:
- name: tomcat-data
persistentVolumeClaim:
claimName: tomcat-pvc


5.4、访问文件修改
结果


访问
(访问失败,可以删除tomcatpod尝试)

















