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尝试)
