如何 运行 spring 在 Kubernetes 中启动集成测试

How to run spring boot integration test in Kubernetes

我在 src/intrgTest/groovy 位置对我的 spring 启动应用程序进行了简单的集成测试,下面是测试

@AutoConfigureMockMvc
@WebMvcTest
class WebControllerTest extends Specification {

  @Autowired
  private MockMvc mvc

  def "when get is performed then the response has status 200 and content is 'Hello world!'"() {
    expect: "Status is 200 and the response is 'Hello world!'"
    mvc.perform(get("/hello"))
      .andExpect(status().isOk())
      .andReturn()
      .response
      .contentAsString == "Hello world!"
  }
}

当我在 Kubernetes 中创建一个 pod 时,我想 运行 这个测试用例来检查应用程序是否正常工作。我怎样才能做到这一点?

下面是 kubernetes

的 deployment.yml 文件
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: spring-boot-deployment
spec:
  selector:
    matchLabels:
      app: spring-boot-app
  replicas: 2 
  template:
    metadata:
      labels:
        app: spring-boot-app
    spec:
      containers:
      - name: spring-boot-app
        image: spring-boot-test-images:63
        ports:
        - containerPort: 80

查看测试,它是健康检查而不是集成测试。理想情况下,集成测试应该 运行 使用 mvn test 作为持续集成的一部分,然后再执行实际部署,而不是之后。

你真的不需要写一个健康检查的测试,然后在应用程序部署到kubernetes上后执行它。您可以简单地在部署 yaml 中定义 readiness probe,Kubernetes 将在将 pod 标记为 READY 并开始向其发送流量之前执行健康检查。

如果您使用 spring 启动版本早于 2.3,那么您可以使用执行器端点 /actuator/health,如果您使用 spring 启动 2.3,则 /actuator/health/readiness端点作为就绪探测器。

apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: spring-boot-deployment
spec:
  selector:
    matchLabels:
      app: spring-boot-app
  replicas: 2 
  template:
    metadata:
      labels:
        app: spring-boot-app
    spec:
      containers:
      - name: spring-boot-app
        image: spring-boot-test-images:63
        ports:
        - containerPort: 80
        readinessProbe:
          httpGet:
            port: 8080
            path: /actuator/health
        initialDelaySeconds: 10

如果你想在某些外部系统(如 redis 或 dynamo)上进行健康检查,你可以为此编写 custom health indicator。以下示例来自 spring,提供 RedisHealthIndicator

public class RedisHealthIndicator extends AbstractHealthIndicator {

    private final RedisConnectionFactory redisConnectionFactory;

    public RedisHealthIndicator(RedisConnectionFactory connectionFactory) {
        super("Redis health check failed");
        Assert.notNull(connectionFactory, "ConnectionFactory must not be null");
        this.redisConnectionFactory = connectionFactory;
    }

    @Override
    protected void doHealthCheck(Health.Builder builder) throws Exception {
        RedisConnection connection = RedisConnectionUtils.getConnection(this.redisConnectionFactory);
        try {
            doHealthCheck(builder, connection);
        }
        finally {
            RedisConnectionUtils.releaseConnection(connection, this.redisConnectionFactory, false);
        }
    }

    private void doHealthCheck(Health.Builder builder, RedisConnection connection) {
        if (connection instanceof RedisClusterConnection) {
            RedisHealth.up(builder, ((RedisClusterConnection) connection).clusterGetClusterInfo());
        }
        else {
            RedisHealth.up(builder, connection.info());
        }
    }

}