중앙 로그 수집을 위해 Eleastcsearch, Fluentd, Kibana를 이용해 EFK 스택을 구축해보도록 합니다.
1. 앞선 글
중앙 로그 수집을 위해 로그 수집기를 알아봤습니다: 2020.10.28 - [Programming] - LogStash vs Fluentd - 어떤 것을 선택해야 할까
Fluentd를 사용해보고자 했지만 미뤄졌던 일이 이제야 사용해 볼만한 기회가 찾아와 좀 더 자세히 포스팅하기로 했습니다.
EFK 스택은 기존 ELK 스택의 변형입니다. 기존 로그 수집 미들웨어인 Logstash 대신 Fluentd를 사용한 스택입니다. Elasticsearch, Logstash, Fluentd, Kibana에 대한 설명은 이 글에서 다루지 않도록 하겠습니다.
이 글의 예시는 Visual Studio의 dotNet5.0을 이용해 예시 프로젝트를 만들고 그 프로젝트의 로그를 fluentd를 통해 elasticsearch로 보낸 뒤 kibana에서 확인하는 과정으로 진행하도록 하겠습니다.
해당 내용은 다음 git 저장소에서 확인할 수 있습니다: FluentdTester
2. 테스트용 프로젝트 생성.
VisualStuio를 열고 dotNet 5.0을 사용해 WebAPI 프로젝트를 생성합니다. 프로젝트는 HTTPS를 지원하지 않도록 설정하였으며 Docker 지원은 체크해 생성합니다.
로그를 남기기 위해 Serilog를 사용하도록 합니다. NuGet 패키지 관리자를 열어 Serilog, Serilog.Sinks.File, Serilog.Formatting.Elasticsearch 패키지를 설치합니다.
Serilog는 로그를 남기기 위함이며 Serilog.Sink.File은 로그를 파일에 쓰기 위함이고 Serilog.Formatting.Elasticsearch는 로그 형식을 Elasticseach에 맞게 남겨주는 데 사용합니다.
새 컨트롤러를 생성해 Get요청이 오면 로그를 남기도록 코드를 작성합니다.
using Microsoft.AspNetCore.Mvc;
using Serilog;
using Serilog.Core;
using Serilog.Formatting.Elasticsearch;
namespace FluentdTester
{
[Route("api/[controller]")]
[ApiController]
public class LogController : ControllerBase
{
private readonly Logger logger;
public LogController()
{
logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.Enrich.FromLogContext()
.Enrich.WithProperty("Service", "LogTester")
.WriteTo.File(new ElasticsearchJsonFormatter(), "logs/fluentd-test.log", rollingInterval: RollingInterval.Day)
.CreateLogger();
}
// GET: api/log/test
[HttpGet("test")]
public IActionResult Get()
{
logger.Debug(string.Format("This is sample log."));
return Ok();
}
}
}
다음은 편의를 위한 코드 수정입니다. Production 환경에서도 swagger에 접속할 수 있도록 Startup.cs 파일을 수정합니다.
// Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "FluentdLogTester v1"));
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
이제 도커 이미지로 빌드해 봅시다. 자동으로 생성된 Dockerfile을 우클릭 해 Docker 이미지 빌드를 클릭합니다.
정상적으로 빌드되는지 확인합니다. 해당 방식으로 이미지를 빌드하면 자동으로 latest 태그가 설정되어 빌드가 됩니다.
3. fluentd 추가하기.
앞서 작성한 프로그램이 로그를 남기면 fluentd는 그 로그파일을 읽어 Elasticsearch로 로그를 전송하는 역할을 담당하게 될 겁니다. 이렇게 로그 파일을 추적해 로그를 전송하는 방식은 fluentd의 "tail" Input Plugin을 사용합니다. 자세한 내용은 공식 홈페이지를 참고해 주시기 바랍니다: Fluentd - tail
로그를 읽어 들이는 Input Plugin이 있으면 반대로 읽은 로그를 Elasticsearch로 전송하는 기능도 있습니다. 다행히도 별도의 구현을 할 필요 없이 바로 Elasticsearch로 로그를 보낼 수 있도록 Elasticsearch Output Plugin을 제공해주고 있습니다. 자세한 내용은 공식 홈페이지를 참고해 주시기 바랍니다: Fluentd - elasticsearch
이제 tail과 elasticsearch를 사용할 수 있도록 fluentd의 설정 파일을 작성하도록 하겠습니다.
#/fluentd/conf/fluent.conf
<source>
@type tail
path /app/logs/fluentd-tester/*.log
pos_file /app/logs/td-agent/logtest.log.pos
tag logtest
<parse>
@type json
</parse>
</source>
<match *.**>
@type copy
<store>
@type elasticsearch
host elasticsearch
port 9200
logstash_format true
logstash_prefix fluentd
logstash_dateformat %Y%m%d
include_tag_key true
type_name access_log
tag_key @log_name
flush_interval 1s
</store>
<store>
@type stdout
</store>
</match>
앞서 작성한 프로그램의 로그를 읽어 elasticsearch로 전송하는 설정 파일입니다. 다음으로는 이 설정 파일과 elasticsearch 플러그인을 사용할 수 있도록 fluentd 이미지를 빌드하는 dockerfile을 작성합니다.
# /fluentd/dockerfile
FROM fluentd:v1.9.1-debian-1.0
COPY /conf/* /fluentd/etc/
USER root
RUN ["gem", "install", "fluent-plugin-elasticsearch", "--no-document", "--version", "4.3.3"]
USER fluent
이제 이 dockerfile을 사용해 fluentd 이미지를 빌드해 줍니다.
$ docker build . -t my-fluentd:0.0.1
** 여기서는 conf 파일을 포함하는 이미지를 미리 빌드해서 사용합니다.
** 만약 docker-compose에서 새로 빌드하고자 한다면 dockerfile의 "COPY /conf/* /etc/"를 사용할 수 없으므로 별도로 conf 파일을 옮겨주는 작업이 필요합니다.
4. 배포를 위한 docker-compose 작성.
이 글은 간단한 테스트를 위한 글이므로 테스트 프로그램, fluentd, Elasticsearch, Kibana 모두 한 docker-compose 파일 내에 작성해 배포하도록 진행하겠습니다.
version: '3.9'
volumes:
test-logs:
services:
fluentd-tester:
image: fluentdtester:latest
volumes:
- test-logs:/app/logs
depends_on:
- "fluentd"
expose:
- "8080"
ports:
- "8080:80"
fluentd:
image: my-fluentd:0.0.1
user: root
volumes:
- test-logs:/app/logs/fluentd-tester
depends_on:
- "elasticsearch"
ports:
- "24224:24224"
- "24224:24224/udp"
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
environment:
- "discovery.type=single-node"
expose:
- "9200"
ports:
- "9200:9200"
kibana:
image: kibana:7.10.1
depends_on:
- "elasticsearch"
ports:
- "5601:5601"
내용은 간단합니다. 앞서 빌드한 이미지인 fluentdtester:latest와 my-fluentd:0.0.1 그리고 elasticsearch와 kibana를 실행시킵니다. fluentd-tester와 fluentd 서비스는 test-logs라는 이름의 볼륨을 이용해 데이터를 공유하도록 해주었습니다.
이를 통해 fluentd-service에서 작성한 로그파일에 fluentd가 접근해 tail로 로그파일을 elasticsearch로 전송합니다.
다음 명령어를 통해 docker-compose를 실행시켜봅시다.
$ docker-copmpose up -d
정상적으로 컨테이너들이 실행된 것을 확인할 수 있습니다.
5. 동작 확인.
컨테이너가 정상적으로 실행되었다면 이제 테스트 로그를 남겨봅시다. 다음 주소로 이동해 swagger를 사용해 로그를 남깁시다.
http://localhost:8080/swagger/index.html
정상적으로 로그가 남았음을 확인하고 싶다면 컨테이너에 접속해 /app/logs 폴더에 들어가 확인해보시면 됩니다.
이제 키바나에 접속해 인덱스 패턴을 생성해야 합니다. 다음 주소로 접속해 인덱스 패턴을 생성합니다.
http://localhost:5601/app/management/kibana/indexPatterns
Create index 화면에서 "fluentd-*" 패턴을 생성해줍니다.
Time Field는 @timestamp를 선택합니다.
이제 discover로 이동합니다.
http://localhost:5601/app/discover/
앞서 남긴 로그를 확인할 수 있습니다.
'Programming' 카테고리의 다른 글
[NGINX] NGINX 컨닝 페이퍼 (0) | 2021.05.07 |
---|---|
[Jenkins | Docker] Jenkins로 Docker 이미지 빌드하기. (0) | 2021.04.18 |
[Windows] WSL1 삭제하기. (0) | 2021.04.01 |
[SSL] Certbot을 이용한 인증서 갱신하기. (1) | 2021.02.09 |
파일 서비스 프로토콜: SMB, AFP, NFS, FTP, TFTP, RSync, WebDAV (0) | 2021.01.30 |