Elastic Search란 ?
역색인(역인덱스) 구조로 검색 시 속도를 빠르게 처리할 수 있음
1. 인덱스 생성
2. 데이터 저장
3. 검색 API 요청
구현 과정
1. 의존성 추가
implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'
2. yml 설정
3. config 작성
기존에 상속받아서 첫 번째 사진처럼 사용했던 AbstracElasticsearchConfiguration이 Deprecated 되었다.
ElasticsearchConfiguration을 상속받아서 ClientConfiguration을 bean으로 등록했다.
@Configuration
@EnableElasticsearchRepositories
public class ElasticsearchConfig extends ElasticsearchConfiguration {
@Value("${spring.data.elasticsearch.host}")
private String host;
@Override
public ClientConfiguration clientConfiguration() {
return ClientConfiguration.builder()
.connectedTo(host)
.build();
}
}
4. Document 작성
5. mapping, setting 설정 파일 작성
5. Repository 작성
6. API 호출
Trouble Shooting
1. docker compose로 es를 실행했는데 curl로 접속하면 아래와 같이 떴다.
$ curl http://localhost:9200
curl: (52) Empty reply from server
docker로 확인한 es 컨테이너 로그
"WARN", "message":"received plaintext http traffic on an https channel, closing connection Netty4HttpChannel{localAddress=/192.168.176.2:9200, remoteAddress=/192.168.176.3:56902}", "ecs.version": "1.2.0","service.name":"ES_ECS","event.dataset":"elasticsearch.server","process.thread.name":"elasticsearch[single-node][transport_worker][T#7]","log.logger":"org.elasticsearch.http.netty4.Netty4HttpServerTransport","elasticsearch.cluster.uuid":"Kki1HQp2SjGZ5fv6w3fPtw","elasticsearch.node.id":"gb5vQ_VSTrmyJ51uxc0B8A","elasticsearch.node.name":"single-node","elasticsearch.cluster.name":"soni"}
원인 : http 보안 관련 문제로 추가 설정이 필요하다.
해결 : docker compse 파일 es 서비스 environment 부분에 아래 코드를 추가해 보안 기능을 비활성화 한다.
- xpack.security.enabled=false //X-Pack 보안 기능을 비활성화한다.
짠 !
Elastic search EC2에 배포
미루고 미뤄왔던 .... 배포 서버에 Elastic Search 적용시키기 !
1. EC2 서버의 OS와 아키텍처 확인
Elasticsearch 설치파일을 받아오기 위해 사전 체크 !
$ cat /etc/os-release // OS 확인
-> Amazon Linux
$ uname -m //아키텍처 확인
-> x86_64 : Intel 또는 AMD 기반 아키텍쳐
2. Elasticsearch 파일 다운로드
로컬에서 Elasticsearch 8.13.4 버전으로 개발을 진행했기 때문에 같은 버전으로 배포를 해줄 것이다.
다운로드 페이지에서 다운 받으면 되는데 원하는 버전을 받기 위해서는
우측 Summary -> 첫 번째 옵션 View past releases에 가서 고르면 된다.
고른 뒤에 많은 설치 파일 들 중에 나는 1에서 찾은데로 x86_64 버전의 파일로 받아준다.
RPM 패키지 매니저로 설치해줄 것이기 때문에 .rpm 파일의 다운로드 링크가 필요하다.
아래 체크된 옵션에서 마우스 우클릭 후 링크 복사
wget 명령어와 함께 붙여넣어준다.
$ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.13.4-x86_64.rpm
* wget : 네트워크를 통해 파일을 다운로드 하는 명령줄 도구.
주로 HTTP, HTTPS, FTP 등의 프로토콜을 통해 원격 서버에서 파일을 가져올 때 사용. -> 단순 파일, sw다운 용도
3. RPM 파일 설치
$ sudo rpm -i elasticsearch-8.13.4-x86_64.rpm
* rpm : Red Hat Package Manager. 레드햇 계열 Linux 시스템에서 sw설치, 업데이트, 제거에 사용하는 패키지 관리 시스템. -> 다운한 .rpm 파일을 설치하고 관리
설치하고 나면 The generated password for the elastic built-in superuser is 뒤에 나오는 토큰을 복사해두자.
(다시 찾기 귀찮으니까 ㅎㅎ)
4. ES 설치 확인
$ rpm -qa | grep elasticsearch
5. ES 서비스 시작
$ sudo systemctl enable elasticsearch // 지정한 서비스를 부팅 시 자동 시작하도록 설정.
$ sudo systemctl start elasticsearch
$ sudo systemctl status elasticsearch //running이면 정상 동작
5-1. 보안 그룹 9200 포트 인바운드 규칙 접근 허용
REST API 액세스를 위해 TCP 9200 포트를 추가해준다.
6. 접속 테스트
$ curl http://localhost:9200 or
$ curl -X GET http://localhost:9200
둘 다 결과는 같으나 -X 옵션은 HTTP 메소드를 지정해준다는 의미.
첫 번째 명령어로 할 경우에 기본 GET요청 의미.
-> 이러면 curl: (52) Empty reply from server 오류가 나버리고
로그를 확인해보면 다음과 같이 뜬다.
Trouble Shooting
➡️문제
: http 요청 접근 실패
➡️원인
: 로그(실행 중 발생하는 오류) 확인
$ sudo tail -f /var/log/elasticsearch/elasticsearch.log
[2024-11-21T19:04:52,455][WARN ][o.e.h.n.Netty4HttpServerTransport] [ip-172-31-5-83.ap-northeast-2.compute.internal] received plaintext http traffic on an https channel, closing connection Netty4HttpChannel{localAddress=/[0:0:0:0:0:0:0:1]:9200, remoteAddress=/[0:0:0:0:0:0:0:1]:43010}
볼드된 부분을 해석해보면 HTTPS 채널에서 평문 HTTP를 수신해서 요청이 차단됨.
-> ES가 보안 기능을 활성화하고 있고 HTTPS를 요구하는 설정으로 동작하고 있음을 의미.
ES 8.x 버전부터 기본 보안이 활성화 되어 HTTP 요청을 차단하고 HTTPS요청만 허용한다.
➡️해결 :
1. (로컬 테스트에서만) 보안 비활성화
$ sudo vi /etc/elasticsearch/elasticsearch.yml로 가서
xpack.security.enabled: false로 변경
운영환경에서 절대로 XXXXXXXXXXXXXX
2. HTTPS로 요청보내기
$ curl -X GET "https://localhost:9200" -u elastic:3에서 복사해두라고했던 보안토큰 --insecure
* --insecure : 인증서 검증 무시
짜잔 정상적으로 접속한 것을 확인할 수있다.
다만 이제 우리의 어플리케이션에서 접속해야하므로 https로 해줘보겠다.
Trouble Shooting)
와 ............ 정말 오래 걸렸던 오류 해결 ㅠ
ec2 서버에서는 curl 명령어로 접근해도 위처럼 아주 잘 뜨는데
프로젝트 실행시키려고 하면 냅다 그냥 UnknownHost 오류가 뜨면서 어플리케이션이 실행되지를 않았다 ㅠㅠㅠㅠㅠ
https로 해서 보안 관련 Credentails 설정이 문제가 있나 싶어서 필요 없는 http로 접근을 해봐도 마찬가지였고 .......
그러다 갑자기 생각이 든 게 내가 로컬에서는
spring: data: elasticsearch: host: 부분을 localhost:9200으로만 작성해두었다.
현재 배포 환경의 yml에는 계속 http://ec2탄력IP:9200 or https://ec2탄력IP:9200으로 작성을 하고 있었다.
해결하기 까지의 나의 삽질..
1. https로 하기 위해서 username과 password를 yml에 설정해두고 아래와 같이 config파일을 작성하였다.
(이렇게 할 경우 로컬 yml에 username과 password 항목을 null로 만들어 둬야 한다.)
package com.sj.Petory.config;
import ch.qos.logback.core.net.server.Client;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
import java.util.Objects;
@Configuration
@EnableElasticsearchRepositories
public class ElasticsearchConfig extends ElasticsearchConfiguration {
@Value("${spring.data.elasticsearch.host}")
private String host;
@Value("${spring.data.elasticsearch.username:#{null}}")
private String username;
@Value("${spring.data.elasticsearch.password:#{null}}")
private String password;
@Override
public ClientConfiguration clientConfiguration() {
if (Objects.isNull(username) && Objects.isNull(password)) {
return ClientConfiguration.builder()
.connectedTo(host)
.build();
}
return ClientConfiguration.builder()
.connectedTo(host)
.withBasicAuth(username, password)
.build();
}
}
ClientConfigurationBuilder가 Deprecated되어서 어떤 방법을 써야할 지 고민하다가
일단 직관적으로 username &password가 둘다 null 일 경우는 -> 로컬 host만 세팅.
둘 다 값이 있을 경우 -> 관련 정보세팅.
이것도 원래는 withCredentials()가 있었는데 없어져서 한참 찾아 헤맸다. ㅠ
2. 그래도 같은 오류가 발생해서 인증서를 만들어 저장하려고 하다가 -> 보류.
너무 오래걸려서 일단 http로 다시 해보기로 함.
3. http:ec2 EIP:9200 해줬음에도 똑같은 오류............
알
고
보
니
spring.data.elasticsearch.host 는 host와 관련한 정보만 적어주는 것이었따 .........................
나는 이 변수 값을 @Value로 config 클래스에서 받아쓰니까 그냥 내가 정하기 나름이라고 (<<<<<대체 왜 ???????? jwt나 flyway등 다 봐도 정해진 옵션값들인데) 생각했던 거 같다. 뭘 쓰든 간에.
오래 앉아있다 보니까 정신이 나간 건지.......
다시 정리하자면
spring.data.elasticsearch.host는 호스트와 포트만 입력해야한다. 따라서 그냥 ec2 EIP:9200만 입력해줘도 됐던 것...
프로토콜 까지 함께 입력하려면 spring.elasticsearch.uris를 쓰면 된다.
ㅠ 눈물의 해결
참고
공식문서
https://docs.spring.io/spring-data/elasticsearch/reference/elasticsearch.html
초기 세팅
spring 공식 문서
https://docs.spring.io/spring-data/elasticsearch/reference/elasticsearch/reactive-template.html
검색 api 구현
https://docs.spring.io/spring-data/elasticsearch/reference/elasticsearch/reactive-template.html
docker compose 파일 구성
es 기본
https://velog.io/@haden/spring-Spring-%EC%97%90%EC%84%9C-Elastic-Search-%ED%99%9C%EC%9A%A9-1
docker에서 es
https://velog.io/@soyeon207/ES-2.-docker-%EC%97%90%EC%84%9C-ES-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0