AWS, Open Distro for Elasticsearch 설치
Serverless 환경은 장단점이 명확하다. 명확한 장점은 개발 및 관리 지만, 제공해 주는 주체(AWS)가 설정해 놓은 범위 밖에 있는 요구사항을 수용할 수 없다는 단점이 있다. RDS 의 Serverless 는 아직 Aurora 5.6(=MySQL 5.6)만 대응 가능하고, Elasticsearch 는 6.7 에 머물고 있거니와 사용자 사전이 불가능했다. 때문에 용도에 맞게 Serverless 및 설치형 서비스를 고려해야 하는데, 로그 수집 및 분석은 형태소 구분이 없기 때문에 AES(AWS Elasticsearch Service)를 사용하고, 플러그인 확장이 필요한 경우 설치형을 선택하기로 했다.
Open Distro for Elasticsearch
Elasticsearch 를 EC2 Instance 에 설치하기로 결정한 순간 Amazon 이 지난 3월 공개한 Open Distro for Elasticsearch(이하 ODE)가 떠올랐다. Elastic.co와 전혀 무관한 ODE 는 Apache License 2.0 을 준수하는 순수 오픈소스 기반으로 Github 에 코드가 공개되어 있어 별도의 비용을 지불하지 않고 Elasticsearch 의 유료 모델에서 제공했던 것과 유사한 기능들을 사용할 수 있다.
- 보안
- 암호화 통신
- 사용자 인증 및 롤 제어
- Index/Field/Document 수준의 제어
- 감사 로그 처리
- LDAP/AD, SMAL 지원
- 멀티테넌트 (Multi-tenant)
- Cross-cluster 검색
- Alert 통보
- SQL 구문 지원
- 성능 분석기 제공
하나같이 매우 유용한 기능들이고 꼭 필요했던 기능들이다. 이 포스트는 EC2 Instance 에 Elasticsearch 와 ODE 를 설치하고, 형태소 분석을 위한 노리와 사용자 사전 설치를 담고 있다.
설치환경
환경 | 버전 |
EC2 Instance Type | t3.large (+30GiB EBS) (1) |
Elasticsearch | 7.0.1 (2) |
Open Distro for Elasticsearch | 1.0.1 |
Java | 1.8.0-openjdk-devel (3) |
(1) Elasticsearch 가 동작하려면 최소 4GiB 이상의 메모리가 필요하다. 운영체제가 일정양의 메모리를 사용하고, Elasticsearch의 JVM 의 힙메모리에 일정량의 메모리를 할당하기 때문이다. 하지만, 형태소 분석등을 원활하게 진행하려면 JVM 힙 크기를 넉넉하게 지정해 줄 필요가 있다. 때문에 t3.large 를 기반으로 한다.
(2) AES 가 6.7 에 머무르고 있는걸 보면 ODE 를 위한 개발은 1회성이 아니라, 지속적으로 진행되고 있음을 히스토리에서 확인할 수 있다. 물론 이 포스트를 작성하는 시점에서 Elasticsearch 는 7.2가 최신 이지만. Elasticsearch 를 7.0.1을 선택한 이유는 ODE 의 최신 버전(1.0.1)이 이 버전을 지원하고 있기 때문이다.
(3) Java LTS 는 11이나, ODE 의 사양에 따르면 Amazon Linux 2 는 Java 8 설치를 권하고 있다. 뿐만 아니라 Logstash 도 Java 8에서 안정적 이라는 걸 고려해보자.
※ 7월 16일 현재 (출처 : https://opendistro.github.io/for-elasticsearch-docs/#version-history)
Elasticsearch 설치
Amazon Linux 2 는 RPM 설치 형태로 진행된다. ODE 는 Elasticsearch에 플러그인 추가 형태로 들어가 있어, Elasticsearch 와 ODE 가 함께 설치된다. 주의 해야 할 부분은 Java 는 반드시 ‘-devel’ 을 설치해야 한다.
$ cd /etc/yum.repos.d/ # yum repo 에 ODE 추가. Elasticsearch 도 보인다. $ sudo curl https://d3g5vo6xdbdb9a.cloudfront.net/yum/opendistroforelasticsearch-artifacts.repo -o opendistroforelasticsearch-artifacts.repo (1/3): elasticsearch-7.x/primary | 28 kB 00:00:00 (2/3): opendistroforelasticsearch-artifacts-repo/primary_db | 20 kB 00:00:00 (3/3): elasticsearch-6.x/primary | 104 kB 00:00:01 # Java 8 설치 $ sudo yum install java-1.8.0-openjdk-devel # Elasticsearch 설치. 함께 설치되는 ODE 플러그인들이 보인다. $ sudo yum install opendistroforelasticsearch ======================================================================================================================================= Package Arch Version Repository Size ======================================================================================================================================= Installing: opendistroforelasticsearch noarch 1.0.1-1 opendistroforelasticsearch-artifacts-repo 2.8 k Installing for dependencies: elasticsearch-oss x86_64 7.0.1-1 elasticsearch-7.x 254 M opendistro-alerting noarch 1.0.0.0-1 opendistroforelasticsearch-artifacts-repo 3.9 M opendistro-job-scheduler noarch 1.0.0.1-1 opendistroforelasticsearch-artifacts-repo 218 k opendistro-performance-analyzer noarch 1.0.0.0-1 opendistroforelasticsearch-artifacts-repo 15 M opendistro-security noarch 1.0.0.1-1 opendistroforelasticsearch-artifacts-repo 26 M opendistro-sql noarch 1.0.0.0-1 opendistroforelasticsearch-artifacts-repo 6.0 M Transaction Summary ======================================================================================================================================= Install 1 Package (+6 Dependent packages) # 라이브러리 이전 $ sudo ln -s /usr/lib/jvm/java-1.8.0/lib/tools.jar /usr/share/elasticsearch/lib/ # Elasticsearch 가동 (중지는 stop) $ sudo systemctl start elasticsearch.service
설치 후 elasticsearch/elasticsearch.yml 를 살펴보면 ODE 관련 옵션들을 확인할 수 있다. 특이한 부분은 Kibana가 데모 인증서를 통해 TLS 암호화 되어 있다는 점. 단, 인증서가 자체적으로 생성된 것으로 SSL 오류가 예상된다.
######## Start OpenDistro for Elasticsearch Security Demo Configuration ######## # WARNING: revise all the lines below before you go into production opendistro_security.ssl.transport.pemcert_filepath: esnode.pem opendistro_security.ssl.transport.pemkey_filepath: esnode-key.pem opendistro_security.ssl.transport.pemtrustedcas_filepath: root-ca.pem opendistro_security.ssl.transport.enforce_hostname_verification: false opendistro_security.ssl.http.enabled: true opendistro_security.ssl.http.pemcert_filepath: esnode.pem opendistro_security.ssl.http.pemkey_filepath: esnode-key.pem opendistro_security.ssl.http.pemtrustedcas_filepath: root-ca.pem opendistro_security.allow_unsafe_democertificates: true opendistro_security.allow_default_init_securityindex: true opendistro_security.authcz.admin_dn: - CN=kirk,OU=client,O=client,L=test, C=de opendistro_security.audit.type: internal_elasticsearch opendistro_security.enable_snapshot_restore_privilege: true opendistro_security.check_snapshot_restore_write_privileges: true opendistro_security.restapi.roles_enabled: ["all_access", "security_rest_api_access"] cluster.routing.allocation.disk.threshold_enabled: false node.max_local_storage_nodes: 3 ######## End OpenDistro for Elasticsearch Security Demo Configuration ########
정상 동작 여부를 확인해 보기 위해 curl 을 사용해 Elasticsearch의 API 를 호출해보자. –insecure 는 인증서의 진위 여부를 확인하지 않고 진행 하라는 의미다. 특별히 문제가 발생할 부분은 없지만, 오류가 발생하는지 한번 확인해보자.
$ curl -XGET https://localhost:9200 -u admin:admin --insecure { "name" : "ip-10-10-102-183.ap-northeast-1.compute.internal", "cluster_name" : "elasticsearch", "cluster_uuid" : "3K4aPUWWQVOmA6XpsK3jnw", "version" : { "number" : "7.0.1", "build_flavor" : "oss", "build_type" : "rpm", "build_hash" : "e4efcb5", "build_date" : "2019-04-29T12:56:03.145736Z", "build_snapshot" : false, "lucene_version" : "8.0.0", "minimum_wire_compatibility_version" : "6.7.0", "minimum_index_compatibility_version" : "6.0.0-beta1" }, "tagline" : "You Know, for Search" } $ curl -XGET https://localhost:9200/_cat/nodes?v -u admin:admin --insecure ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name 127.0.0.1 10 34 14 0.91 0.43 0.17 mdi * ip-10-10-102-183.ap-northeast-1.compute.internal $ curl -XGET https://localhost:9200/_cat/plugins?v -u admin:admin --insecure name component version ip-10-10-102-183.ap-northeast-1.compute.internal opendistro-job-scheduler 1.0.0 ip-10-10-102-183.ap-northeast-1.compute.internal opendistro_alerting 1.0.0.0 ip-10-10-102-183.ap-northeast-1.compute.internal opendistro_performance_analyzer 1.0.0.0 ip-10-10-102-183.ap-northeast-1.compute.internal opendistro_security 1.0.0.1 ip-10-10-102-183.ap-northeast-1.compute.internal opendistro_sql 1.0.0.0 $ systemctl status elasticsearch.service ● elasticsearch.service - Elasticsearch Loaded: loaded (/usr/lib/systemd/system/elasticsearch.service; disabled; vendor preset: disabled) Active: active (running) since Thu 2019-07-18 15:49:03 UTC; 2min 9s ago Docs: http://www.elastic.co Main PID: 11994 (java) CGroup: /system.slice/elasticsearch.service └─11994 /usr/share/elasticsearch/jdk/bin/java -Xms1g -Xmx1g -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupan... Jul 18 15:49:20 ip-10-10-102-183.ap-northeast-1.compute.internal elasticsearch[11994]: at com.amazon.opendistro.elasti...) Jul 18 15:49:20 ip-10-10-102-183.ap-northeast-1.compute.internal elasticsearch[11994]: at com.amazon.opendistro.elasti...) Jul 18 15:49:20 ip-10-10-102-183.ap-northeast-1.compute.internal elasticsearch[11994]: at com.amazon.opendistro.elasti...) Jul 18 15:49:20 ip-10-10-102-183.ap-northeast-1.compute.internal elasticsearch[11994]: at com.amazon.opendistro.elasti...) Jul 18 15:49:20 ip-10-10-102-183.ap-northeast-1.compute.internal elasticsearch[11994]: at java.base/java.security.Acce...) Jul 18 15:49:20 ip-10-10-102-183.ap-northeast-1.compute.internal elasticsearch[11994]: at com.amazon.opendistro.elasti...) Jul 18 15:49:20 ip-10-10-102-183.ap-northeast-1.compute.internal elasticsearch[11994]: at com.amazon.opendistro.elasti...) Jul 18 15:49:20 ip-10-10-102-183.ap-northeast-1.compute.internal elasticsearch[11994]: at java.base/java.util.concurre...) Jul 18 15:49:20 ip-10-10-102-183.ap-northeast-1.compute.internal elasticsearch[11994]: at java.base/java.util.concurre...) Jul 18 15:49:20 ip-10-10-102-183.ap-northeast-1.compute.internal elasticsearch[11994]: at java.base/java.lang.Thread.r...) Hint: Some lines were ellipsized, use -l to show in full.
JVM의 힙 사이즈를 늘리고 고정하자. 기본으로 1GB 로 설정되어 있는걸 4GB 로 늘리자. 좀더 여유 있는 동작을 보장한다.
$ cat /etc/elasticsearch/jvm.options . . -Xms4g -Xmx4g . .
수정된 내용을 반영하고, 부팅 시 자동으로 실행되도록 서비스 옵션을 변경하자.
$ sudo systemctl daemon-reload $ sudo systemctl enable elasticsearch.service Created symlink from /etc/systemd/system/multi-user.target.wants/elasticsearch.service to /usr/lib/systemd/system/elasticsearch.service.
Kibana 설치
앞서 설정한 정보 덕분에 Kibana 설치는 매우 간단하다. yum으로 설치가 가능하며, Elasticsearch와 같이 ODE 관련 항목 들이 함께 설치된다. 그리고 인터넷에서도 접속할 수 있도록 server.host 항목을 추가하자. 0.0.0.0은 ANY 이기 때문에, 실제 서비스에서는 꼭 필요한 CIDR 로 제한해야 한다.
$ sudo yum install opendistroforelasticsearch-kibana
$ cat /etc/kibana/kibana.yml
.
.
elasticsearch.url: https://localhost:9200 # hosts 로 변경
elasticsearch.ssl.verificationMode: none
elasticsearch.username: kibanaserver
elasticsearch.password: kibanaserver
elasticsearch.requestHeadersWhitelist: ["securitytenant","Authorization"]
opendistro_security.multitenancy.enabled: true
opendistro_security.multitenancy.tenants.preferred: ["Private", "Global"]
server.host: 0.0.0.0 # 추가
수정된 내용을 반영하고, Kibana 역시 시스템 시작 시 자동 시작 할 수 있도록 하자. (이 시점에서는 동작하고 있지 않기 때문에 시작하면 되고 아니라면 restart)
$ sudo systemctl start kibana $ sudo systemctl daemon-reload $ sudo systemctl enable kibana.service Created symlink from /etc/systemd/system/multi-user.target.wants/kibana.service to /etc/systemd/system/kibana.service.
설치가 완료됐다. EC2 Instance 의 IP 에 Port 5601 을 브라우저에 입력하면 Kibana 화면이 보인다. 그런데! (예:http://{EC2 Instance Public IP}:5601) URL 만 입력하면 보이던 Kibana 에 로그인 화면이 보인다. (우와!!!! 아마 기존 Kibana 의 관리 정책 때문에 골머리 썩힌 사람이라면 다 비슷한 반응일 듯)
※ 초기 계정 및 비밀번호는 admin 임
그리고. ODE 에서 추가된 3개의 메뉴가 눈에 띈다.
Open Distro for Elasticsearch 와 Kibana 설치가 완료됐다. 유료 모델을 구독하지 않아도 알람, 보안, SQL 등의 다양한 기능을 제공하고 있다. 아마도 가장 유용한건 간단하면서도 필요했던 사용자 인증일것이고, SQL 은 JSON 문법에 익숙하지 않은 사람들도 쉽게 사용할 수 있도록 도와준다.
특히 Alert 기능은 Slack 등과 같은 메신저에 웹훅을 전달해 이상 유무를 효과적으로 전달할 수 있는데, 이는 앞선 포스트에서 이미 구축한 적 있다.
$ sudo /usr/share/elasticsearch/bin/elasticsearch-plugin list opendistro-job-scheduler opendistro_alerting opendistro_performance_analyzer opendistro_security opendistro_sql $ sudo /usr/share/kibana/bin/kibana-plugin list [email protected] [email protected]
형태소 분석기 설치
과거 Elasticsearch 에는 한글 형태소 분석으로 은전한닢(=소전)을 사용했지만, 6.4부터 ‘공식 플러그인’ 형태로 제공한다. 플러그인 명칭은 ‘analysis-nori‘ 이며, 루씬 프로젝트에서 공식적으로 제공하는 한글 형태소 분석기다. 일본어 형태소 분석기인 Kuromoji를 개발한 Jim Ferenczi가 역시 개발한 플러그인 이며, 기본적으로 세종 말뭉치를 사용하며 기존 형태소 분석기 대비 30% 이상 향상된 성능을 보인다. (즉, Nori는 Kuromoji의 fork다!)
공식 플러그인 이기 때문에 쉽게 설치가 가능하다.
$ bin/elasticsearch-plugin install analysis-nori $ bin/elasticsearch-plugin list analysis-nori opendistro-job-scheduler opendistro_alerting opendistro_performance_analyzer opendistro_security opendistro_sql $ systemctl restart elasticsearch
별도의 설정이 없는 상태에서 형태소 분석 결과는 다음과 같다. ‘아버지가방에들어가신다’를 분석해 보면 뭔가 어눌한 분석 결과가 나온다.
위 결과를 이해하려면 Nori 의 동작 구조를 이해 해야 한다. 기본적으로 Nori는 하나의 토크나이저와 2개의 토큰필터로 구성되어 있다. 토크나이저는 루씬에서 형태소 형태로 분리하는데 사용되며, 두가지 옵션을 지원한다.
- nori_tokenizer
- decompound_mode: 복합명사 처리 여부
- none (기본값) : 처리하지 않음
- discard : 처리 후 원본 데이터를 삭제한다
- mixed : 처리 후 원본 데이터를 유지한다
- user_dictionary: 사용자 정의 사전. 명사와 복합명사를 등록할 수 있다.
- decompound_mode: 복합명사 처리 여부
Nori 는 문장을 왼쪽에서 부터 오른쪽 방향으로 문자 하나씩 이동하며 처리한다. 현재 포지션의 문자로 시작되는 단어 중 사전과 일치하는 단어가 있다면 간택(?) 되며, 입력 단어를 기준으로 이전 시간의 모든 단어들에 대한 비용을 계산하고, 비용이 적은 인덱스와 단어는 Viterbi Path 에 저장된다.
가장 늦게 Viterbi Path에 추가된 단어를 시작으로 bracktrace함수를 통해 이전 시간의 단어를 계속해 추출해 나가며, 이 단어들의 목록이 Optimal Path 가 되며 토크나이징 결과물이 된다. 때문에 ‘아버지가방에들어가신다’ 에서 ‘아버지’ ‘가방’ ‘들어가’가 word로 분류되어 형태소가 분석된 것. 그럼 ‘신다’가 사라진건 불용어(stopwords, 검색어로서 가치가 없는 단어)로 제거 되었기 때문에 사라졌다.
Nori 사전 구조는 CSV(array) 형식의 텍스트로 저장된 사전을 Finite State Transducer(FST)로 부호화 하고 Binary 구조로 재 구성한 형태를 Matrix.def 에서 가변 길이로 변경 한 후 직렬화 되어있다. 문제는 사용자 사전의 한계. 사용자 사전의 품사가 존재하지 않아 단순히 형태소 분석용으로만 적합해 은전한닢으로 갈아타기로 결정. 내용이 길어져서 #2 편으로.