mysql一主多从 k8s部署实际案例

一、Kubernetes配置(MySQL主从集群)

  1. 主库StatefulSet配置(master-mysql.yaml):
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql-master
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
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "root123"
        - name: MYSQL_DATABASE
          value: "app_db"
        # 主库配置参数
        args:
        - "--server-id=1"
        - "--log-bin=mysql-bin"
        - "--binlog_do_db=app_db"
        - "--gtid-mode=ON"
        - "--enforce-gtid-consistency=ON"
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
  volumeClaimTemplates:
  - metadata:
      name: mysql-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "standard"
      resources:
        requests:
          storage: 20Gi
  1. 从库StatefulSet配置(slave-mysql.yaml):
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql-slave
spec:
  serviceName: "mysql-slave"
  replicas: 2  # 两个从库实例
  selector:
    matchLabels:
      app: mysql-slave
  template:
    metadata:
      labels:
        app: mysql-slave
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "root123"
        # 从库配置参数
        args:
        - "--server-id=$HOSTNAME_SLICE"  # 动态生成唯一server-id
        - "--relay-log=mysql-relay"
        - "--read-only=ON"
        - "--gtid-mode=ON"
        - "--enforce-gtid-consistency=ON"
        - "--skip-slave-start"  # 等待手动配置主从复制
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
  volumeClaimTemplates:
  - metadata:
      name: mysql-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "standard"
      resources:
        requests:
          storage: 20Gi

二、Java读写分离实现(Spring Boot示例)

  1. 数据源配置(application.yml):
spring:
  datasource:
    master:
      jdbc-url: jdbc:mysql://mysql-master:3306/app_db
      username: root
      password: root123
      driver-class-name: com.mysql.cj.jdbc.Driver
    slaves:
      - jdbc-url: jdbc:mysql://mysql-slave-0:3306/app_db
        username: root
        password: root123
      - jdbc-url: jdbc:mysql://mysql-slave-1:3306/app_db
        username: root
        password: root123
  1. 动态数据源配置类:
/**
 * 动态数据源配置
 */
@Configuration
@EnableTransactionManagement
@MapperScan("com.example.mapper")
public class DynamicDataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public DataSource slaveDataSource() {
        // 创建从库数据源列表
        List<DataSource> slaves = new ArrayList<>();
        // 这里需要根据实际配置动态加载从库数据源
        // ...(具体实现根据配置加载多个从库)

        // 负载均衡策略(轮询)
        return new LoadBalancedDataSource(slaves);
    }

    @Bean
    public DataSource dynamicDataSource(
            @Qualifier("masterDataSource") DataSource master,
            @Qualifier("slaveDataSource") DataSource slave) {
        
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("master", master);
        targetDataSources.put("slave", slave);
        
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(master);
        
        return dynamicDataSource;
    }
}
  1. 数据源路由实现:
/**
 * 动态数据源路由器
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();

    @Override
    protected Object determineCurrentLookupKey() {
        return CONTEXT_HOLDER.get();
    }

    public static void setDataSource(String dataSource) {
        CONTEXT_HOLDER.set(dataSource);
    }

    public static void clearDataSource() {
        CONTEXT_HOLDER.remove();
    }
}
  1. 自定义注解实现读写分离:
/**
 * 数据源选择注解
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
    DataSourceType value() default DataSourceType.MASTER;
}

public enum DataSourceType {
    MASTER, SLAVE
}
  1. AOP切面实现:
@Aspect
@Component
public class DataSourceAspect {

    @Before("@annotation(dataSource)")
    public void beforeSwitchDS(JoinPoint point, DataSource dataSource) {
        DataSourceType value = dataSource.value();
        if (value == DataSourceType.MASTER) {
            DynamicDataSource.setDataSource("master");
        } else {
            DynamicDataSource.setDataSource("slave");
        }
    }

    @Before("execution(* com.example.service..*.save*(..)) || " +
            "execution(* com.example.service..*.update*(..)) || " +
            "execution(* com.example.service..*.delete*(..))")
    public void writeOperations() {
        DynamicDataSource.setDataSource("master");
    }

    @AfterReturning("execution(* com.example.service..*.*(..))")
    public void afterReturning() {
        DynamicDataSource.clearDataSource();
    }
}

三、部署说明

  1. 集群初始化步骤:
# 部署主库
kubectl apply -f kubernetes/mysql/master-mysql.yaml

# 等待主库启动完成后部署从库
kubectl apply -f kubernetes/mysql/slave-mysql.yaml

# 验证Pod状态
kubectl get pods -l app=mysql-master
kubectl get pods -l app=mysql-slave
  1. 主从复制配置(在从库Pod中执行):
# 进入从库容器
kubectl exec -it mysql-slave-0 -- bash

# 在MySQL中执行
CHANGE MASTER TO
MASTER_HOST='mysql-master',
MASTER_USER='root',
MASTER_PASSWORD='root123',
MASTER_AUTO_POSITION=1;

START SLAVE;

四、架构特点说明

  1. 数据一致性保障:
  • 使用GTID实现事务一致性
  • 半同步复制配置(需在MySQL配置中额外添加)
  • 自动故障转移机制(建议配合k8s探针使用)
  1. 读写分离策略:
  • 写操作强制路由主库
  • 读操作自动负载均衡
  • 事务中强制使用主库
  1. 扩展性设计:
  • 从库数量可动态调整(修改StatefulSet replicas)
  • 自动水平扩展从库集群
  • 支持多可用区部署(需配置亲和性策略)

注意事项:

  1. 生产环境需配置Secret管理数据库密码
  2. 建议添加MySQL连接池配置(如HikariCP)
  3. 需要配置合适的持久化存储方案
  4. 建议添加监控和报警机制(Prometheus+Granafa)
以下是k8s加docker的项目案例: 假设我们有个简单的Web应用程序,它使用Python Flask框架编写,并使用MySQL作为数据库。 我们将使用Docker容器化应用程序和数据库,并使用Kubernetes进行部署和管理。 1. Docker容器化应用程序和数据库 首先,我们将使用Docker容器化我们的应用程序和数据库。 对于应用程序,我们需要创建个Dockerfile,其中包含以下内容: ``` FROM python:3.8-slim-buster WORKDIR /app COPY requirements.txt requirements.txt RUN pip install -r requirements.txt COPY . . CMD ["python", "app.py"] ``` 这个Dockerfile使用Python 3.8作为基本映像,并将应用程序代码复制到容器中。它还将requirements.txt文件复制到容器中,并使用pip安装所有必需的依赖项。最后,它设置了个CMD指令,该指令在容器启动时运行应用程序。 对于数据库,我们将使用MySQL,并使用以下Docker Compose文件将其容器化: ``` version: '3' services: db: image: mysql:5.7 command: --default-authentication-plugin=mysql_native_password restart: always environment: MYSQL_ROOT_PASSWORD: example MYSQL_DATABASE: myapp MYSQL_USER: user MYSQL_PASSWORD: password ports: - "3306:3306" volumes: - data:/var/lib/mysql volumes: data: ``` 这个Docker Compose文件将创建MySQL 5.7容器,并设置它的根密码,数据库名称和用户凭据。它还将将容器的3306端口映射到机的3306端口,并使用卷将数据保存在本地。 2. 部署Kubernetes 现在我们将使用Kubernetes将我们的应用程序和数据库部署到集群中。 对于应用程序,我们需要创建个Deployment和个Service。Deployment将使用我们之前创建的应用程序Docker映像,并定义个Pod模板,该模板将运行个容器并暴露端口5000。Service将使用该Deployment,并将其暴露到集群中的其他Pod和外部客户端。 以下是我们的应用程序Deployment和Service的YAML定义: ``` apiVersion: apps/v1 kind: Deployment metadata: name: myapp spec: replicas: 2 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: containers: - name: myapp image: myapp:latest ports: - containerPort: 5000 --- apiVersion: v1 kind: Service metadata: name: myapp spec: selector: app: myapp ports: - name: http port: 80 targetPort: 5000 type: LoadBalancer ``` 对于数据库,我们将使用个单独的Deployment和Service。Deployment将使用我们之前创建的MySQL Docker映像,并定义个Pod模板,该模板将运行个容器并暴露端口3306。Service将使用该Deployment,并将其暴露到集群中的其他Pod和外部客户端。 以下是我们的数据库Deployment和Service的YAML定义: ``` apiVersion: apps/v1 kind: Deployment metadata: name: mysql spec: replicas: 1 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:5.7 env: - name: MYSQL_ROOT_PASSWORD value: example - name: MYSQL_DATABASE value: myapp - name: MYSQL_USER value: user - name: MYSQL_PASSWORD value: password ports: - containerPort: 3306 volumeMounts: - name: data mountPath: /var/lib/mysql volumes: - name: data persistentVolumeClaim: claimName: mysql-data --- apiVersion: v1 kind: Service metadata: name: mysql spec: selector: app: mysql ports: - name: mysql port: 3306 targetPort: 3306 clusterIP: None ``` 这个Deployment将创建MySQL容器,并设置其根密码,数据库名称和用户凭据。它还将将容器的3306端口暴露给其他Pod,但不向外部客户端暴露。Service将在Pod之间创建个DNS条目,使它们可以相互访问。 3. 部署应用程序 现在我们可以使用kubectl命令将应用程序和数据库部署到集群中: ``` kubectl apply -f app-deployment.yaml kubectl apply -f db-deployment.yaml ``` 这将创建Deployment和Service对象,并在集群中启动Pod。 4. 测试应用程序 最后,我们可以使用kubectl port-forward命令将应用程序的Service暴露到本地机的端口,并使用Web浏览器访问该端口以测试应用程序: ``` kubectl port-forward svc/myapp 8080:80 ``` 这将将Service的80端口映射到本地机的8080端口。现在,我们可以使用Web浏览器访问http://localhost:8080,以查看我们的应用程序是否正常工作。 这就是个简单的k8s加docker的项目案例
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值