개인프로젝트/twitter 실시간 데이터 프로젝트(ELK stack)

[docker] python+filebeat+elk 환경 만들기

장경훈 2022. 10. 17. 16:14

1. 프로젝트 폴더 기본 구조 설계

  • elasticsearch
    • elasticsearch.yml
  • logstash
    • config
    • pipeline
    • templates
  • kibana
    • kibana.yml
  • filebeat
    • filebeat.yml
  • python
    • Dockerfile
    • models
    • lib.txt
  • docker-compose.yml
  • mylog

우선 기본적인 ELK의 설정파일인 .yml 파일들은 관리하기 편하게 하기 위해서 볼륨 마운트를 하여 설정하며 logstash의 경우에만 pipeline, templates을 따로 보관하여 vscode에서 작성하는 게 편하고 직관적이라고 생각하여 따로 분류해서 마운트 시켰다. 또한 python 같은 경우에는 모듈을 다운받아야 하기 때문에 Dockerfile을 이용해서 필요한 모듈을 다운 받은 이미지를 생성하였고 모델 폴더 안에 hussingface에서 받은 감정분석 모델을 넣을 예정이다. 프로젝트 컨테이너는 docker-compose로 한 번에 관리하는 방식을 설계했다. 여기서 mylog폴더는 python에서 읽어 들인 실시간 데이터를 저장하는 폴더이다.

 

2.  Python Dockerfile

##Dockerfile

FROM python:3.8  #python 3.8 이미지 불러오기 
COPY python/lib.txt /lib.txt #컨테이너에 lib.txt 파일 복사 
RUN pip install --user --upgrade pip # pip 업그레이드 한 후 
RUN pip install --no-cache-dir --user -r /lib.txt # lib.txt에 적은 모듈 다운로드
#lib.txt

requests #tiwtter api 호출에 필요한 모듈 request 
torch==1.11.0 #pytorch다운
tqdm #머신러닝 모델을 사용하기 위한 모듈
transformers #머신러닝 모델을 사용하기 위한 모듈
sentence-transformers #머신러닝 모델을 사용하기 위한 모듈
eland==8.2 #elasticsearch와 pytorch를 연동시키기 위한 모듈
elasticsearch==8.4.2 #elasticsearch 버전 일치를 위한 재설치

 

파이썬 환경을 위의 코드와 같이 구성했으며 이 작업을 하면서 발생한 문제는 차후 프로젝트를 마친 후 따로 생긴 문제들만을 모은 포스팅에 작성할 예정이다.

 

3.Docker-compose.yml

version: '3'
services:
  elasticsearch:
    container_name: elasticsearch
    image: elasticsearch:8.4.2
    environment: 
      - bootstrap.memory_lock=true
      - discovery.type=single-node
      - "ES_JAVA_OPTS=-Xms1g -Xmx1g"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    ports:
      - 9200:9200
      - 9300:9300
    volumes:
      - ./elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
    stdin_open: true
    tty: true
    networks:
      default_bridge:
        ipv4_address: 172.18.0.2
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "50"  
  kibana:
    container_name: kibana
    image: kibana:8.4.2
    ulimits:
      memlock:
        soft: -1
        hard: -1
    ports:
      - 5601:5601
    volumes:
      - ./kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml
    links:
      - elasticsearch:elasticsearch
    depends_on:
      - elasticsearch
    stdin_open: true
    tty: true
    networks:
      default_bridge:
        ipv4_address: 172.18.0.3
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "50"
  logstash:
    container_name: logstash
    image: logstash:8.4.2
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - ./logstash/pipeline:/usr/share/logstash/pipeline
      - ./logstash/templates:/usr/share/logstash/templates
      - ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml
      - ./logstash/config/pipelines.yml:/usr/share/logstash/config/pipelines.yml
    ports:
      - 5044:5044
    links:
      - elasticsearch:elasticsearch
    depends_on:
      - elasticsearch
    stdin_open: true
    tty: true

    networks:
      default_bridge:
        ipv4_address: 172.18.0.4
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "50"
  filebeat:
    user: root
    container_name: filebeat
    image: docker.elastic.co/beats/filebeat:8.4.2
    links:
      - logstash:logstash
    depends_on:
      - logstash
    volumes:
      - ./mylog:/usr/share/filebeat/mylog
      - ./filebeat/filebeat.yml:/usr/share/filebeat/filebeat.yml
    command: ["--strict.perms=false"]
    ulimits:
      memlock:
        soft: -1
        hard: -1
    stdin_open: true
    tty: true
    
    networks:
      default_bridge:
        ipv4_address: 172.18.0.5
    deploy:
      mode: global
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "50"
  python:
    container_name: python
    build:
      context: .
      dockerfile: ./python/Dockerfile
    volumes:
      - ./mylog:/usr/share/mylog
      - ./python/send_data.py:/usr/share/script/send_data.py
      - ./python/deploy_model.py:/usr/share/script/deploy_model.py
    depends_on:
      - filebeat
    stdin_open: true
    tty: true
    
    networks:
      default_bridge:
        ipv4_address: 172.18.0.6

networks:
  default_bridge:
    ipam:
      driver: default
      config:
        - subnet: 172.18.0.0/16

 

위의 설정 파일이 길기 때문에 실제 github에 올릴때는 주석을 달겠지만 이 포스팅에서는 각각의 컨테이너의 옵션에 대해서 중요한 부분을 정리해 보려고 한다.

  • 공통사항 
    • filebeat+ELK 는 모두 현재 안정화된 최신버전인 8.4.2 버전의 이미지를 불러서 사용했다.
    • 각각의 컨테이너 ip를 17.2.18.0.0/16 안에있는 ip로 고정적으로 지정했다.
    • filbeat+elk의 도커 컨테이너 로그는 최대10mb 사이즈로 50개까지 가능하게 지정했다.
    • 안정성을 위해 filebeat+elk의 스와핑 비활성화.
  • ElasticSearch
    • 메모리락을 걸어서 최대 1gb의 메모리를 가지게 설정했다.
    • local 환경에서 프로젝트를 실행하기 때문에 single-node방식으로 설정했다.
    • ElasticSearch.yml을 마운트하여 설정을 편하게 할 수 있게 했다.
    • 포트는 일반적으로 사용하는 9200으로 설정했다.
  • Logstash
    • 설정파일, 파이프라인, 템플릿을 관리하기 편하게 하기 위해서 따로 마운트 했다.
    • ElasticSearch와 links를 하여 서로 통신이 용의 하게 만들었고 depends_on 옵션으로 ElasticSearch가 실행된 후 Logstash가 실행되게 설정했다.
    • 포트는 일반적으로 사용하는 5044로 설정했다.
  • Kibana
    • kibana.yml 설정파일을 마운트 하여 관리하기 편하게 했다.
    • Elasticsearch와 links를 통해 통신이 용의 하며 depends_on으로 ElasticSearch가 실행된 후 실행되게 설정했다.
    • 포트는 일반적으로 사용하는 5601을 사용
  • Filebeat
    • 위의 ELK와 같이 설정파일을 마운트 하여 관리한다
    • Logstash가 실행되고 난 후 실행해야 하므로 depends_on을 logstash로 설정했다.
    • 파이썬에서 저장한 파일을 불러오기 위한 폴더를 마운트하여 서로 공유할 수 있도록 설정했다.
  • Python
    • 이미지는 앞서 생성한 모델이 적용된 이미지를 사용한다
    • 컨테이너안에서 스크립트를 실행하여 데이터를 보내기 위해 스크립트 파일을 마운트하고 로그가 저장되는 폴더를 마운트 하여 파일을 저장하게 설정했다.
    • filebeat가 실행되고 난 후 실시간 데이터를 보내기 위해서 depends_on을 filbeat로 설정했다.

 

4.elasticsearch.yml

## Default Elasticsearch configuration from Elasticsearch base image.
## https://github.com/elastic/elasticsearch/blob/main/distribution/docker/src/docker/config/elasticsearch.yml
#
cluster.name: "docker-cluster"
network.host: 0.0.0.0

## X-Pack settings
## see https://www.elastic.co/guide/en/elasticsearch/reference/current/security-settings.html
#
xpack.license.self_generated.type: trial
xpack.security.enabled: false
xpack.security.enrollment.enabled: false

Elasticsearch의 설정파일은 위와 같다. 외부 허용을 하기 위해 0.0.0.0으로 호스트를 설정했고 보안 옵션 같은 경우에 로컬 환경에서 하기 때문에 크게 문제가 생길 것이라고 생각되지 않아서 false로 설정했다.

 

5. Logstash 설정파일

#logstash.yml

http.host: "0.0.0.0"
xpack.monitoring.elasticsearch.hosts: [ "http://elasticsearch:9200" ]
# This file is where you define your pipelines. You can define multiple.
# For more information on multiple pipelines, see the documentation:
#   https://www.elastic.co/guide/en/logstash/current/multiple-pipelines.html

- pipeline.id: main
  path.config: "/usr/share/logstash/pipeline"

Logstash 또한 ElasticSearch와 동일하게 외부 연결을 허용해주었고 모니터링을 설정했다. 또한 파이프라인은 컨테이너 안에 마운트 한 파이프라인 폴더로 설정하여 정상적으로 데이터가 전송될 수 있도록 설정했다.

 

6.Kibana 설정 파일

#kibana.yml

server.host: "0.0.0.0"

elasticsearch.hosts: [ "http://elasticsearch:9200" ]
monitoring.ui.container.elasticsearch.enabled: true

똑같이 외부 접속을 허용해주었고 elasticsearch와 연동시키고 모니터링까지 사용 가능하게 설정하였다.

 

7.filebeat 설정 파일

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /usr/share/filebeat/mylog/data.log

output.logstash:
  hosts: ["logstash:5044"]

파일 비트의 설정은 input을 로그파일 즉 파이썬에서 작성된 twitter api의 정보를 불러와서 logstash로 전송하는 코드이며 파일 경로는 docker-compose에서 마운트 한 경로로 지정했다.

 

8. 실행 확인

정상적으로 컨테이너들이 실행되는 것을 볼 수 있다.

 

 

여기까지 하는 것도 처음이다 보니 생각보다 많은 시간이 소요된 것 같다. 너무 많은 오류들이 발생했었기 때문에 이런 오류들은 따로 추후에 포스팅으로 정리할 예정이다. 개인적으로는 프로젝트 환경 설정하는 게 가장 고려해야 할 부분이 많아서 어렵다고 생각하는데 이제 환경 설정은 성공적으로 했기 때문에 그래도 프로젝트를 완성시킬 수 있을 것 같은 자신감이 좀 생기는 것 같다.