目录
一、整体架构
本项目为在一主三从的Kubernetes集群上部署WordPress博客。因为WordPress部分容器版本自行集成Apache和PHP服务,因此在Kubernetes上部署WordPress只需提供MySQL存储数据和Redis缓存Session会话即可。Kubernetes集群基础架构如下:
#k8s-master01 172.29.7.10
#k8s-node01 172.29.7.11
#k8s-node02 172.29.7.12
#k8s-node03 172.29.7.13
#nfs-server 172.29.7.20
#参考往期博客部署NFS-CSI-Driver使Kubernetes集群能调用NFS本地服务器
root@k8s-master01:~# cat /etc/hosts 127.0.0.1 localhost 172.29.7.10 k8s-master01.wlm.com k8s-master01 kubeapi.wlm.com kubeapi 172.29.7.11 k8s-node01.wlm.com k8s-node01 172.29.7.12 k8s-node02.wlm.com k8s-node02 172.29.7.13 k8s-node03.wlm.com k8s-node03 root@k8s-master01:~# kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-master01 Ready control-plane 17d v1.29.10 k8s-node01 Ready <none> 17d v1.29.10 k8s-node02 Ready <none> 17d v1.29.10 k8s-node03 Ready <none> 17d v1.29.10
二、部署MySQL主从
为了确保数据的高可用和容灾性部署MySQL主从为WordPress提供服务。MySQL为有状态服务应该使用Operator或Statefulset进行部署,此处涉及到主从复制配置复杂,因此简化使用Deployment进行部署。
#创建项目存放位置
root@k8s-master01:~# mkdir -pv wordpress/mysql/
root@k8s-master01:~# cd wordpress/mysql/#创建PVC实现持久化
root@k8s-master01:~/wordpress/mysql# cat mysql-pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mysql-pvc-master namespace: wordpress spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi storageClassName: nfs-csi --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mysql-pvc-slave namespace: wordpress spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi storageClassName: nfs-csi
#创建Secret存放MySQL密码(密码为wlm123使用base64加密后如下)
root@k8s-master01:~/wordpress/mysql# kubectl create secret generic mysql-secret --from-literal='root-password'='wlm123' --from-literal='db-password'='wlm123' --dry-run=client -o yaml > mysql-secret.yaml root@k8s-master01:~/wordpress/mysql# cat mysql-secret.yaml apiVersion: v1 data: db-password: d2xtMTIz root-password: d2xtMTIz kind: Secret metadata: namespace: wordpress name: mysql-secret
#创建ConfigMap为MySQL提供配置文件,同时实现主从复制
root@k8s-master01:~/wordpress/mysql# cat mysql-config.yaml apiVersion: v1 kind: ConfigMap metadata: name: mysql-config namespace: wordpress data: my.cnf: | [mysqld] server-id=1 log_bin=/var/lib/mysql/mysql-bin.log bind-address = 0.0.0.0 character-set-server = utf8mb4 default_authentication_plugin=mysql_native_password [client] default-character-set = utf8mb4 root@k8s-master01:~/wordpress/mysql# cat mysql-config-slave.yaml apiVersion: v1 kind: ConfigMap metadata: name: mysql-config-slave namespace: wordpress data: my.cnf: | [mysqld] server-id=22 log_bin=/var/lib/mysql/mysql-bin.log bind-address = 0.0.0.0 character-set-server = utf8mb4 default_authentication_plugin=mysql_native_password read-only=ON relay_log=relay-log relay_log_index=relay-log.index [client] default-character-set = utf8mb4
#可选操作,创建Service Account赋予MySQL服务名称空间管理员身份,确保其有权限读取Secret
root@k8s-master01:~/wordpress/mysql# cat mysql-sc.yaml apiVersion: v1 kind: ServiceAccount metadata: creationTimestamp: null name: mysql-sc namespace: wordpress root@k8s-master01:~/wordpress/mysql# cat rbac.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: wordpress name: secret-reader rules: - apiGroups: ["*"] resources: ["*"] verbs: ["*"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: namespace: wordpress name: read-secrets subjects: - kind: ServiceAccount name: mysql-sc namespace: wordpress roleRef: kind: Role name: secret-reader apiGroup: rbac.authorization.k8s.io
#部署MySQL应用
root@k8s-master01:~/wordpress/mysql# cat mysql-deploy.yaml --- apiVersion: apps/v1 kind: Deployment metadata: name: mysql-master namespace: wordpress spec: replicas: 1 selector: matchLabels: app: mysql role: master template: metadata: labels: app: mysql role: master spec: serviceAccountName: mysql-sc containers: - name: mysql image: mysql:5.7 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: root-password - name: MYSQL_DATABASE value: "wp" - name: MYSQL_USER value: "wpuser" - name: MYSQL_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: db-password ports: - containerPort: 3306 volumeMounts: - name: mysql-data mountPath: /var/lib/mysql - name: mysql-config mountPath: /etc/mysql/conf.d volumes: - name: mysql-data persistentVolumeClaim: claimName: mysql-pvc-master - name: mysql-config configMap: name: mysql-config --- apiVersion: v1 kind: Service metadata: name: mysql-master namespace: wordpress spec: ports: - port: 3306 targetPort: 3306 selector: app: mysql role: master root@k8s-master01:~/wordpress/mysql# cat mysql-deploy-slave.yaml --- apiVersion: apps/v1 kind: Deployment metadata: name: mysql-slave namespace: wordpress spec: replicas: 1 selector: matchLabels: app: mysql role: slave template: metadata: labels: app: mysql role: slave spec: serviceAccountName: mysql-sc containers: - name: mysql image: mysql:5.7 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: root-password - name: MYSQL_DATABASE value: "wp" - name: MYSQL_USER value: "wpuser" - name: MYSQL_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: db-password ports: - containerPort: 3306 volumeMounts: - name: mysql-data mountPath: /var/lib/mysql - name: mysql-config-slave mountPath: /etc/mysql/conf.d volumes: - name: mysql-data persistentVolumeClaim: claimName: mysql-pvc-slave - name: mysql-config-slave configMap: name: mysql-config-slave --- apiVersion: v1 kind: Service metadata: name: mysql-slave namespace: wordpress spec: ports: - port: 3306 targetPort: 3306 selector: app: mysql role: slave
#进入MySQL创建复制账户并进行主从配置,确保IO线程和SQL线程正常运行
root@k8s-master01:~/wordpress/mysql# kubectl apply -f . root@k8s-master01:~/wordpress/mysql# kubectl exec -it mysql-master-7ff66bfb86-bvlfg -n wordpress -- mysql -uroot -pwlm123 mysql> create user 'replica'@'%' identified by 'wlm123'; mysql> grant replication slave on *.* to 'replica'@'%'; mysql> flush privileges; mysql> show master status\G; *************************** 1. row *************************** File: mysql-bin.000003 Position: 1538 Binlog_Do_DB: Binlog_Ignore_DB: Executed_Gtid_Set: 1 row in set (0.00 sec) root@k8s-master01:~/wordpress/mysql# kubectl exec -it mysql-slave-58cf89f5dd-nh4sz -n wordpress -- mysql -uroot -pwlm123 mysql> CHANGE MASTER TO -> MASTER_HOST='mysql-master', -> MASTER_USER='replica', -> MASTER_PASSWORD='wlm123', -> MASTER_LOG_FILE='mysql-bin.000003', -> MASTER_LOG_POS=1538; mysql> START SLAVE; mysql> show slave status\G; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: mysql-master Master_User: replica Master_Port: 3306 Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000003 Read_Master_Log_Pos: 1538 Relay_Log_File: relay-log.000002 Relay_Log_Pos: 320 Relay_Master_Log_File: mysql-bin.000003 Slave_IO_Running: Yes Slave_SQL_Running: Yes
三、部署Redis哨兵
为了确保Redis故障自动转移,使用Satefulset配置Redis一主两从三哨兵。
#创建项目目录
root@k8s-master01:~# mkdir wordpress/redis/
root@k8s-master01:~# cd wordpress/redis/#创建PVC实现持久化
root@k8s-master01:~/wordpress/redis# cat redis-pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: redis-pvc namespace: wordpress spec: accessModes: - ReadWriteMany resources: requests: storage: 10Gi storageClassName: nfs-csi
#创建ConfigMap为Redis提供配置文件
root@k8s-master01:~/wordpress/redis# cat redis-config.yaml apiVersion: v1 kind: ConfigMap metadata: name: redis-config namespace: wordpress data: redis.conf: | bind 0.0.0.0 masterauth 123456 requirepass 123456 port 6379 protected-mode no slave-read-only yes root@k8s-master01:~/wordpress/redis# cat redis-sen-config.yaml apiVersion: v1 kind: ConfigMap metadata: name: redis-sentinel-config namespace: wordpress data: sentinel.conf: | port 26379 sentinel monitor mymaster redis-0.redis-svc.wordpress.svc.cluster.local 6379 2 sentinel down-after-milliseconds mymaster 5000 sentinel failover-timeout mymaster 10000 sentinel auth-pass mymaster 123456 sentinel resolve-hostnames yes
#部署HeadLess Service使Redis各Pod可通过名称相互解析IP地址
root@k8s-master01:~/wordpress/redis# cat redis-svc.yaml --- apiVersion: v1 kind: Service metadata: name: redis-svc namespace: wordpress spec: clusterIP: None ports: - port: 6379 targetPort: 6379 selector: app: redis --- apiVersion: v1 kind: Service metadata: name: redis-sentinel namespace: wordpress spec: clusterIP: None ports: - port: 26379 targetPort: 26379 selector: app: redis-sentinel
#部署redis应用
root@k8s-master01:~/wordpress/redis# cat redis.yaml apiVersion: apps/v1 kind: StatefulSet metadata: name: redis namespace: wordpress spec: serviceName: redis-svc replicas: 3 selector: matchLabels: app: redis template: metadata: labels: app: redis spec: containers: - name: redis image: redis:6.2-alpine ports: - containerPort: 6379 volumeMounts: - name: redis-data mountPath: /data - name: redis-config mountPath: /usr/local/etc/redis command: - sh - -c - | cp /usr/local/etc/redis/redis.conf /data/redis.conf && \ redis-server /data/redis.conf volumes: - name: redis-config configMap: name: redis-config - name: redis-data persistentVolumeClaim: claimName: redis-pvc root@k8s-master01:~/wordpress/redis# cat redis-sen.yaml apiVersion: apps/v1 kind: StatefulSet metadata: name: redis-sentinel namespace: wordpress spec: serviceName: redis-sentinel replicas: 3 selector: matchLabels: app: redis-sentinel template: metadata: labels: app: redis-sentinel spec: containers: - name: redis-sentinel image: redis:6.2-alpine ports: - containerPort: 26379 volumeMounts: - name: redis-sentinel-config mountPath: /usr/local/etc/redis readOnly: true - name: redis-sen-data mountPath: /data command: - sh - -c - | cp /usr/local/etc/redis/sentinel.conf /data/sentinel.conf && \ redis-sentinel /data/sentinel.conf volumes: - name: redis-sentinel-config configMap: name: redis-sentinel-config - name: redis-sen-data persistentVolumeClaim: claimName: redis-pvc
#手动配置Redis的主从复制,进入哨兵Pod确保哨兵状态正常
root@k8s-master01:~/wordpress/redis# kubectl apply -f redis-pvc.yaml root@k8s-master01:~/wordpress/redis# kubectl apply -f redis-config.yaml root@k8s-master01:~/wordpress/redis# kubectl apply -f redis-sen-config.yaml root@k8s-master01:~/wordpress/redis# kubectl apply -f redis-svc.yaml root@k8s-master01:~/wordpress/redis# kubectl apply -f redis.yaml root@k8s-master01:~/wordpress/redis# kubectl exec -it redis-1 -n wordpress -- sh /data # redis-cli -a 123456 Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. 127.0.0.1:6379> replicaof redis-0.redis-svc.wordpress.svc.cluster.local 6379 OK 127.0.0.1:6379> exit /data # exit root@k8s-master01:~/wordpress/redis# kubectl exec -it redis-2 -n wordpress -- sh /data # redis-cli -a 123456 Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. 127.0.0.1:6379> replicaof redis-0.redis-svc.wordpress.svc.cluster.local 6379 OK root@k8s-master01:~/wordpress/redis# kubectl exec -it redis-0 -n wordpress -- sh /data # redis-cli -a 123456 Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. 127.0.0.1:6379> info replication # Replication role:master connected_slaves:2 slave0:ip=10.244.3.38,port=6379,state=online,offset=70,lag=1 slave1:ip=10.244.2.38,port=6379,state=online,offset=70,lag=1 master_failover_state:no-failover master_replid:09a96f14ebbcf02e358bd675d853dc5797743af5 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:70 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:70 root@k8s-master01:~/wordpress/redis# kubectl exec -it redis-sentinel-0 -n wordpress -- sh /data # redis-cli -p 26379 127.0.0.1:26379> info sentinel # Sentinel sentinel_masters:1 sentinel_tilt:0 sentinel_running_scripts:0 sentinel_scripts_queue_length:0 sentinel_simulate_failure_flags:0 master0:name=mymaster,status=ok,address=10.244.1.61:6379,slaves=2,sentinels=3
四、部署WordPress
WordPress为无状态应用使用Deployment即可完成部署,可根据业务情况进行控制副本数量。
#创建项目目录
root@k8s-master01:~# mkdir wordpress/deploy/
root@k8s-master01:~# cd wordpress/deploy/#创建PVC实现持久化并部署应用
root@k8s-master01:~/wordpress/deploy# cat pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: wordpress-pvc namespace: wordpress spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi storageClassName: nfs-csi root@k8s-master01:~/wordpress/deploy# cat wordpress.yaml apiVersion: apps/v1 kind: Deployment metadata: name: wordpress namespace: wordpress spec: replicas: 2 selector: matchLabels: app: wordpress template: metadata: labels: app: wordpress spec: containers: - name: wordpress image: wordpress:6.7-php8.1-apache env: - name: WORDPRESS_DB_HOST value: "mysql-master:3306" - name: WORDPRESS_DB_USER value: "wpuser" - name: WORDPRESS_DB_PASSWORD value: "wlm123" - name: WORDPRESS_DB_NAME value: "wp" - name: WORDPRESS_REDIS_HOST value: "redis-svc:6379" ports: - containerPort: 80 volumeMounts: - name: wordpress-storage mountPath: /var/www/html volumes: - name: wordpress-storage persistentVolumeClaim: claimName: wordpress-pvc --- apiVersion: v1 kind: Service metadata: name: wordpress namespace: wordpress spec: type: LoadBalancer selector: app: wordpress ports: - protocol: TCP port: 80 targetPort: 80 root@k8s-master01:~/wordpress/deploy# kubectl get svc -n wordpress NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE mysql-master ClusterIP 10.104.10.121 <none> 3306/TCP 16d mysql-slave ClusterIP 10.104.11.245 <none> 3306/TCP 16d redis-sentinel ClusterIP None <none> 26379/TCP 3d1h redis-svc ClusterIP None <none> 6379/TCP 3d1h wordpress LoadBalancer 10.101.6.62 172.29.7.52 80:31292/TCP 15d
#通过LoadBalance暴露的External-IP访问Web页面进行配置
#为WordPress配置Ingress服务,方便外部流量管理
root@k8s-master01:~/wordpress/deploy# kubectl create ingress wordpress --rule="wordpress.wlm.com/*"=wordpress:80 --class=nginx -n wordpress --dry-run=client -o yaml > ingress-wordpress.yaml root@k8s-master01:~/wordpress/deploy# cat ingress-wordpress.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: creationTimestamp: null name: wordpress namespace: wordpress spec: ingressClassName: nginx rules: - host: wordpress.wlm.com http: paths: - backend: service: name: wordpress port: number: 80 path: / pathType: Prefix status: loadBalancer: {} root@k8s-master01:~/wordpress/deploy# kubectl get svc -n ingress-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx-controller LoadBalancer 10.107.247.232 172.29.7.51 80:31631/TCP,443:32678/TCP 16d ingress-nginx-controller-admission ClusterIP 10.106.45.66 <none> 443/TCP 16d
#通过客户端修改本地hosts文件使域名指向Ingress的IP进行博客访问
五、注意事项
MySQL主从需要确保各容器内配置的server-id唯一,若扩容MySQL从服务需要手动修改配置确保server-id唯一性。
MySQL配置文件需要修改默认认证插件至mysql_native_password避免密码验证失败。
Redis使用6.2版本时需要再Sentinel配置文件内加参数sentinel resolve-hostnames yes,否则无法解析pod名称,即使添加无头服务也不能解析,使用kubectl log pod会有相关提示,在reids-0内使用nslookup命令可验证无头服务已正常生效。
Redis哨兵模式需要修改配置文件,Configmap使用只读挂载时,需要用命令把配置文件复制到持久化的data目录,使用sentinel命令指定data目录下的配置文件