아래와 같은 설정을 하는 와중에 오해한 부분을 찾았습니다.
Headless service
Headless service는 Kubernetes에서 특별한 유형의 서비스입니다.
일반적인 Kubernetes 서비스는 서비스에 연결된 파드들에 대한 로드 밸런싱과 DNS 이름 해석을 제공합니다.
그러나 Headless 서비스는 이러한 기능을 비활성화하고, 대신 각 파드에 직접 접근할 수 있는 방법을 제공합니다.
일반적인 서비스는 가상 IP와 DNS 레코드를 가지며, 이 IP 주소로 들어오는 트래픽을 서비스에 연결된 파드 중 하나로 자동으로 로드 밸런싱합니다.
반면에 Headless 서비스는 이러한 가상 IP를 생성하지 않습니다.
대신, DNS 쿼리를 통해 연결된 모든 파드의 IP 주소를 직접 반환합니다.
Headless 서비스는 다음과 같은 경우에 유용합니다:
- 서비스 디스커버리
- 클러스터 내의 다른 애플리케이션에서 서비스를 찾을 때 파드의 실제 IP 주소를 알아야 하는 경우
- 상태 저장 애플리케이션
- 데이터베이스 클러스터나 메시지 큐와 같은 상태를 저장하는 애플리케이션이 클러스터 내에서 실행될 때, 각 노드가 서로를 명확하게 식별할 필요가 있습니다.
Headless 서비스는 spec.clusterIP: None을 설정함으로써 생성됩니다.
이 설정은 Kubernetes에게 서비스에 대한 클러스터 IP를 생성하지 않도록 지시합니다.
그 결과, DNS 조회 시에는 서비스를 구성하는 파드의 IP 주소가 직접 반환됩니다.
이러한 방식은 예를 들어, 분산 데이터베이스나 분산 메시지 큐와 같은 애플리케이션에서 각 인스턴스가 자신의 역할을 명확히 알아야 하는 경우에 유용합니다.
sentinel 접속 후 IP 가 아래와 같이 조회가 되는 걸 확인 후 JAVA 설정을 아래와 같이 했습니다.
- sentinel master 명 확인 해주세요. ( redis cmd 에서 확인 가능 )
- name : master name
- ip : 외부 ( ex : web application ) 에서 접근가능한 ip 주소
redis-cli -p 26379
AUTH 1234
sentinel masters
/**
* Redis Configuration
* @author soobin@naver.com
*/
@EnableRedisRepositories
@Configuration
@Deprecated
public class RedisConfig {
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
/** k8s info **/
final String SERVICE_NAME = "lucy3-redis-headless";
final String NAME_SPACE = "lucy3";
/** redis info **/
final String MASTER_NAME = "mymaster";
final String PASSWORD = "1234";
final int SENTINEL_PORT = 26379;
RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
.master(MASTER_NAME)
.sentinel("lucy3-redis-node-0." + SERVICE_NAME + "." + NAME_SPACE + ".svc.cluster.local", SENTINEL_PORT)
.sentinel("lucy3-redis-node-1." + SERVICE_NAME + "." + NAME_SPACE + ".svc.cluster.local", SENTINEL_PORT)
.sentinel("lucy3-redis-node-2." + SERVICE_NAME + "." + NAME_SPACE + ".svc.cluster.local", SENTINEL_PORT);
sentinelConfig.setPassword(RedisPassword.of(PASSWORD));
return new LettuceConnectionFactory(sentinelConfig);
}
@Bean
public RedisTemplate<String, ?> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(this.redisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
return redisTemplate;
}
}
redis service 를 참조해야합니다.
redis service 가 두 개가 존재하는데 spring 설정에서는 redis headless service 가 아닌 redis service 를 참조해야 합니다.
왜냐면 redis headless service 는 클러스터 내부의 pod ( master, slave, sentinel) 들이 서로 통신할 때 사용하는 headless service 입니다.
그래서 아래와 같이 수정할 수 있습니다.
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
/** k8s info **/
final String NAME_SPACE = "lucy3";
final int SENTINEL_PORT = 26379;
final String SENTINEL_HOST = "lucy3-redis." + NAME_SPACE + ".svc.cluster.local";
/** redis info **/
final String MASTER_NAME = "mymaster";
final String PASSWORD = "1234";
RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
.master(MASTER_NAME)
.sentinel(SENTINEL_HOST, SENTINEL_PORT);
sentinelConfig.setPassword(RedisPassword.of(PASSWORD));
return new LettuceConnectionFactory(sentinelConfig);
}
결국 headless service 와 service 의 쓰임새를 잘 알고 쓰지 못하고 있었다.
headless service 로 연결해도 연결은 되지만 쓰임새에 맞게 사용하지 못했었다 ;;;