top bar

글 목록

2017년 5월 10일 수요일

[Elasticsearch] AWS + Docker 기반 Elasticsearch 클러스터 구성

회사 업무 관계로, AWS + Docker 기반의 Elasticsearch 클러스터를 구성하게 되었다. 그냥 지나가면 까먹을 것 같아 정리 한다.

00. Prerequisite



docker : Docker version 1.13.0
docker-compose : docker-compose version 1.10.0
AWS instance Type : r4.large
Elasticsearch : 5.4.0

먼저 작업 디렉토리를 ~/elasticsearch 라고 가정하자.


01. Dockerfile 작성



아래와 같이 Dockerfile 을 작성한다.

FROM docker.elastic.co/elasticsearch/elasticsearch:5.4.0
 
WORKDIR /usr/share/elasticsearch
RUN bin/elasticsearch-plugin install discovery-ec2

베이스 이미지는 'docker.elastic.co/elasticsearch/elasticsearch:5.4.0' 이다.

AWS EC2 인스턴스를 사용해 클러스터를 구성해야 하기 때문에 기존의 zen discovery 는 사용할 수 없다. 따라서 docker 이미지를 구울때 'discovery-ec2' 플러그인을 설치해야 한다.


02. docker build



Dockerfile이 위치하고 있는 디렉토리에서, 아래와 같이 'elasticsearch-aws' 라는 이름으로
docker 이미지를 생성한다.

$ docker build -t elasticsearch-aws .

> build log
Sending build context to Docker daemon 4.096 kB
Step 1/4 : FROM docker.elastic.co/elasticsearch/elasticsearch:5.4.0
 ---> 4c093701c312
Step 2/4 : WORKDIR /usr/share/elasticsearch
 ---> c784b97dc1e0
Removing intermediate container a93494f1f6f3
Step 3/4 : RUN bin/elasticsearch-plugin install discovery-ec2
 ---> Running in a609bd73f8c7
-> Downloading discovery-ec2 from elastic
[=================================================] 100%??
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@     WARNING: plugin requires additional permissions     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
* java.lang.RuntimePermission accessDeclaredMembers
* java.lang.RuntimePermission getClassLoader
See http://docs.oracle.com/javase/8/docs/technotes/guides/security
/permissions.html
for descriptions of what these permissions allow and 
the associated risks.
-> Installed discovery-ec2
 ---> 6108494a5131
Removing intermediate container a609bd73f8c7
Step 4/4 : EXPOSE 9200 9300
 ---> Running in 78105875f3c7
 ---> e6fd47d7d666
Removing intermediate container 78105875f3c7
Successfully built e6fd47d7d666

위의 Warning은 일단 무시하자.


03. elasticsearch.yml 작성



작업 디렉토리에 'config' 디렉토리를 생성하고,
elasticsearch YAML 설정파일을 작성하여 위치 시키자.

cluster.name: my-aws-cluster
 
node.name: my-node2
 
node.master: true
node.data: true
 
network.host: 0.0.0.0
network.publish_host: _ec2:privateIp_
 
discovery.type: ec2
 
discovery.zen.minimum_master_nodes: 1
discovery.zen.ping.unicast.hosts:
 - [this host ip]
 - [host ip 1]
 - [host ip 2]
 
xpack.security.enabled: false

위와 같이 'network.publish_host' 설정을 하게되면 ec2의 private ip 로 호스트가 바인딩 된다. 'discovery.type: ec2' 설정도 빠지면 안된다.


04. docker-compose.yml 작성



그냥 docker run 명령어로 필요한 옵션을 주어 동작을 하게 할 순 있지만, 옵션을 부여하는게 불편하고, 스크립트로 작성해도 유지보수가 귀찮다.

따라서 YAML 형식의 설정을 지원하는 docker-compose로 컨테이너를 구동하려고 한다.
아래와 같이 작업 디렉토리에 docker-compose.yml 파일을 작성한다.

version: '2'
services:
 elasticsearch:
  image: elasticsearch-aws
  container_name: elasticsearch
  volumes:
   - ./config/elasticsearch.yml:/usr/share/elasticsearch/config
/elasticsearch.yml
   - esdata:/usr/share/elasticsearch/data
  ports:
   - 9200:9200
   - 9300:9300
  environment:
   ES_JAVA_OPTS: "-Xmx2048m -Xms2048m"
 
volumes:
 esdata:
  driver: local


위에서 중요한 설정은 'volumes' 인데, 일단 해당 설정의 첫번째 라인은, 호스트 서버의 외부 elasticsearch.yml 파일을 컨테이너 내부의 elasticsearch.yml 파일에 덮어 쓰는 것이다.
그리고 두번째 라인은 'named volume' 으로서, 컨테이너 내부 디렉토리에 컨테이너 외부 디렉토리를 마운트시키는데, docker자체에서 'esdata' 라는 볼륨으로 관리된다.

해당 볼륨은 service의 이름과 합쳐져서 'elasticsearch_esdata' 라는 볼륨으로 생성되며,
아래와 같은 명령어로 확인 할 수 있다.

$ docker volume inspect elasticsearch_esdata
[
    {
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/elasticsearch_esdata/_data",
        "Name": "elasticsearch_esdata",
        "Options": {},
        "Scope": "local"
    }
]

위에 'Mountpoint' 값이 마운트된 컨테이너 외부 호스트 디렉토리를 가르킨다.


05. 구동



아래의 명령어로 구동시킨다. 백그라운드 구동일 경우 '-d' 옵션을 붙인다.

$ docker-compose up


06. 클러스터링



위의 01~04 단계를 거친 동일한 docker 기반 elasticsearch 설정을 가지고,
2대의 AWS 인스턴스에 elasticsearch 노드를 띄워서 클러스터링을 해 보려고 한다.
아래를 순서대로 진행한다.

① 1번 AWS 인스턴스에 'node1' elasticsearch 노드 구동
② 2번 AWS 인스턴스에 'node2' elasticsearch 노드 구동

① ② 를 차례대로 진행하면 node1 쪽 로그에 아래와 같이 출력된다.






로그를 보면 알겠지만 뒤늦게 구동된 node2 가 마스터노드인 node1을 발견했다는 내용을 확인 할 수 있다.

그리고 동시에 node2 쪽 로그에는 아래와 같이 출력된다.





반대로 마스터노드인 node1에서는 node2를 ec2 discovery를 이용해 찾고, 클러스터에 추가했다는 내용을 확인 할 수 있다.

이로서 클러스터 구축 완료!

2017년 5월 4일 목요일

[Elasticsearch] 5.x 버전에서 'head' 플러그인, 'bigdesk' 플러그인 적용 방법

개요



 정말 오랫만에 엘라스틱서치에 관한 포스팅을 하려고한다. 필자가 한창 다루던 시절의 엘라스틱서치의 버전은 1.x 대 중반 이었다. 하지만 그동안 엘라스틱 서치는 끊임없이 발전하여 2.x을 넘어 5.x버전의 엘라스틱서치가 릴리즈 되어 버렸다.

 그동안 어떤 스펙들이 추가되었고, 삭제되었는지는 차차 알아가야 하겠지만, 이제와서 엘라스틱서치를 설치하고 돌려보려니, 예전엔 아주 유용하게 쓰였던 'head' 와 'bigdesk' 플러그인을 이제는 'plug in' 하여 쓰지 못한다는 사실을 알게 되었다. 이유는 아래 문서에 잘 설명이 되어 있다.

https://www.elastic.co/kr/blog/running-site-plugins-with-elasticsearch-5-0

 요약하자면, 이제까지의 플러그인들은 말그대로 엘라스틱서치 클러스터 서버에 플러그 '인' 되어서 마치 웹서비스처럼 제공 되었다. 하지만 이것은 보안 취약점을 낳았고, 때문에 플러그인에 대한 지원이 되지 않는다(라고 이해했음 ㄷㄷ) 라는 것이었다. 대신에 기존의 플로그인을 대체할 'X-Pack' 이라는 서비스를 제공하는데, 아주 기본적인 Basic package를 제외하고는 유료인것 같다... ㄷㄷ

 하지만 방법은 있다. 각 플러그인을 'standalone' 으로 구동시키고, Elasticsearch 클러스터에 붙이는 것이다. 하나씩 알아보자.


Head 사용



비교적 간단하다.

1) git clone 으로 소스 내려받기

$ git clone git://github.com/mobz/elasticsearch-head.git

2) npm install

해당 소스의 루트 디렉토리에서, npm install 을 통해 의존성을 설치한다

$ npm install

3) npm 을 이용해 standalone server 를 구동

$ npm run start

> elasticsearch-head@0.0.0 start /Users/rover/Devspace
/elastic-practice/head
> grunt server

Running "connect:server" (connect) task
Waiting forever...
Started connect web server on http://localhost:9100

4) localhost:9100 으로 접속하여 확인
























Bigdesk 사용




일단 http://bigdesk.org/ 이곳에서 zip이든, tar든, 다운 받고 압축을 해제 한다.
압축을 해제 하면 아래와 같은 파일들이 보일 것이다.

$ tree bigdesk -L 1
bigdesk
├── LICENSE
├── NOTICE
├── README.md
├── bigdesk-1.0.0.jpg
├── bigdesk-2.0.0-SNAPSHOT.jpg
├── css
├── images
├── index.html
└── js


여기서 그냥 index.html 을 브라우져로 연다. 그리고 ES node REST endpoint 의 텍스트 필드에 'localhost:9200' 으로 입력하고 'connection' 을 클릭한다.

어찌보면 매우 간단한 standalone 방법인데,
위와 같이 하면 아래와 같은 alert 창을 볼 것이다.












어찌된 일인지 버전을 막아 놓았다.
그래서... 다른 방법이 없어 자바스크립트 소스를 조금 손대 보았다.

자바스크립트 소스를 뒤져보면, js/store/BigdeskStore.js 파일에 위의 버전을 체크하는 로직이 숨어있다. 아래와 같다

version = version.number;
var _vArray = version.split(".");
if (_vArray.length > 2 && _model.checkVersion(_vArray)) {
    _model.versionVerified(version);
    _model.initCluster(connection);
} else {
    _model.yellAboutVersion(version);
}

'_model.checkVersion' 함수에서 버전을 체크 한 후, false 일 경우 _model.yellAboutVersion 함수를 호출한다.

yellAboutVersion: function(version) {
    var message =
        "*********************************\n" +
        "Bigdesk may not work correctly!\n" +
        "Found ES node version: " + version + "\n" +
        "Requires ES node version: >= 1.0.0.RC1\n" +
        "*********************************";
    console.log(message);
    if (alert) { alert(message); }
}

따라서.... 저 버전을 체크하는 if else 문을 제거하고, 바로 _model.initCluster 함수를 호출하게 했다. 그렇게 되면 connection에서 가져온 클러스터 정보를 model에 세팅하게 되고, 아래처럼 정상적으로 클러스터 현황이 모니터링 된다.




















결론



불과 몇년전에 비해 엘라스틱서치는 많은 기능이 추가/제거 되었고 개선되었다.
그러한 흐름속에서 built-in 방식으로 사용되었던 플러그인들이 어떠한 이슈(위에서 설명한 것처럼 보안 이슈 등등)로 인해 없어지는건 자연 스러울 지도 모르겠다.

어찌됬든, 사라진 플러그인을 실무에 정식으로 사용하는건 무리가 있겠으나, 뭐 학습용으로는 괜찮지 싶다.

그리고 'X-pack' 이라는것이 일단은 유료니까..