문제점
담당하고 있는 프로젝트는 세션을 이용하여 인증을 처리하고 있다. 어드민 툴이라서 배포가 잦은 편인데, 배포로 인해 Pod가 재시작되면 세션 정보가 초기화 돼서 모든 사용자의 로그인이 모두 풀린다는 문제가 있었다. 그래서 배포를 할 때 사용자가 최대한 없는 시간을 활용하거나, 업무 시간 이후에 하는 등, 배포 시간에 많은 신경을 써야 했다. 이 문제를 해결하기 위해 Redis 세션을 적용하게 되었다. 세션이 스프링 Pod이 아닌 Redis에 저장되기 때문에, Pod가 재시작되어도 세션이 휘발되지 않게 된다.
Redis Pod 배포
먼저 사용할 Redis를 K8S에 배포했다. 어드민 툴의 로그인 용도로만 사용되기 때문에, PVC를 활용해서 단일 Pod로 배포하기로 결정하였다. Redis 이미지 버전은 배포 당시 최신 버전인 7.0.8을 사용하였고, K8S Secret을 활용하여 비밀번호 설정을 추가하였다. Helm 차트를 활용하였고 간단한 yaml 파일은 다음과 같다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
labels:
app: redis
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7.0.8
imagePullPolicy: IfNotPresent
command: ["redis-server", "--requirepass", "$(password)"]
volumeMounts:
- name: data
mountPath: /data
env:
- name: password
valueFrom:
secretKeyRef:
key: password
name: redis-secret
volumes:
- name: data
persistentVolumeClaim:
claimName: redis-pvc
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: redis-pvc
labels:
app: redis
spec:
storageClassName: general
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
---
apiVersion: v1
kind: Service
metadata:
name: redis-svc
labels:
app: redis
spec:
selector:
app: redis
type: ClusterIP
ports:
- protocol: TCP
port: 6379
targetPort: 6379
---
apiVersion: v1
kind: Secret
metadata:
name: redis-secret
type: Opaque
data:
password: {base64비밀번호}
Spring 설정
다음 차례는 Spring과 Redis 연동이다. Spring에서 라이브러리를 제공해 줘서 간단하게 설정할 수 있다.
라이브러리는 spring-boot-starter-data-redis와 spring-session-data-redis를 maven 혹은 gradle로 설치할 수 있다. 그다음, 라이브러리를 활용해서 다음과 같은 Redis Configuration 클래스를 만들어주면 된다.
@Configuration
@EnableSpringHttpSession
public class RedisConfig extends AbstractHttpSessionApplicationInitializer {
private String host = "localhost";
private int port = 6379;
private String password = "pwd";
@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration redisConfig = new RedisStandaloneConfiguration(host, port);
redisConfig.setPassword(password);
return new LettuceConnectionFactory(redisConfig);
}
@Bean
public RedisOperations<String, Object> sessionRedisOperations() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory());
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
return template;
}
@Bean
public RedisSessionRepository sessionRepository(RedisOperations<String, Object> sessionRedisOperations) {
RedisSessionRepository redisSessionRepository = new RedisSessionRepository(sessionRedisOperations);
redisSessionRepository.setDefaultMaxInactiveInterval(Duration.ofSeconds(sessionExpireTime));
return redisSessionRepository;
}
}
위에서 사용된 LettuceConnectionFactory는 Spring과 Redis가 통신하는 데 사용되는 라이브러리이다. 구버전의 스프링에서는 Jedis라는 라이브러리를 디폴트로 사용했지만, 훨씬 더 좋은 성능의 Lettuce라는 새로운 라이브러리가 디폴트로 바뀌게 되었다.
그 외 설정은 Redis 엔드포인트, 접근 비밀번호 설정, Serialization 설정 및 Redis 키 값의 만료 시간 설정이다.
결론
로그인을 하면 세션 정보가 Redis에 저장되기 때문에, 배포를 위해 Pod가 재시작되어도 더 이상 사용자들의 로그인은 끊어지지 않게 되었고, 시간에 상관없이 배포를 진행할 수 있게 되었다.
'Spring' 카테고리의 다른 글
Mysql - Spring으로 SSL 연결하는 방법(K8S 환경, Mac OS 기준) (0) | 2023.06.19 |
---|---|
Spring - 전략패턴을 활용한 Excel Export (0) | 2023.03.31 |
Spring - 비동기 api CompeletableFuture를 활용한 성능 개선 (20) | 2023.03.29 |
Spring - JpaTransactionManager의 동작 원리 (0) | 2023.01.09 |
Spring - TransactionManager란? (0) | 2023.01.07 |