Quản lí Docker Log với Fluentd và ElasticSearch trên Ubuntu 16.04
Giới thiệu
Khi triển khai Docker container, bạn sẽ gặp một yêu cầu duy trì và lưu trữ log ở một nơi an toàn hơn container. Docker có một logging driver đi kèm là Fluentd, làm việc tập trung và lưu trữ log dễ dàng hơn, để bạn có thể phân tích dữ liệu.
Fluentd là một trình thu thập dữ liệu mã nguồn mở để thống nhất cơ sở lưu trữ log của bạn. nó kết hợp các giải pháp đối với việc tính toán, ứng dụng, và dữ liệu với nhau để việc thu thập và lưu trữ log trở nên đơn giản và dễ mở rộng.
Fluentd có 4 tính năng chính khiến nó có khả năng xây dựng các pipeline mượt mà và đang tin cậy dùng cho việc quản lí log.
- Log được kết hợp với JSON: Fluentd cố gắng để cấu trúc dữ liệu như JSON càng nhiều càng tốt. Điều này cho phép Fluentd để thống nhất tất cả các khía cạnh của xử lý log: thu thập, lọc, đệm, và xuất bản ghi log trên nhiều nguồn và điểm đến khác nhau. Việc xử lý dữ liệu downstream là dễ dàng hơn nhiều với JSON, vì nó có đủ cấu trúc để có thể truy cập mà không làm cứng hóa sơ đồ dữ liệu.
- Hỗ trợ plugin: Fluentd có một hệ thống plugin linh hoạt cho phép cộng đồng để mở rộng chức năng của nó. Hơn 300 plugin cộng đồng đóng góp các plugin kết nối hàng chục nguồn dữ liệu đến hàng chục đầu ra dữ liệu và cho phép thao tác với dữ liệu khi cần thiết. Bằng cách sử dụng plug-in, bạn có thể tận dụng tốt hơn các bản ghi của mình ngay lập tức.
- Tối thiểu tài nguyên yêu cầu: Một trình thu thập dữ liệu cần có dung lượng nhẹ để nó chạy thoải mái trên mọi máy. Fluentd được viết bằng C và Ruby, nên đòi hỏi tối thiểu tài nguyên của hệ thống. Bản tiêu chuẩn của nó chiếm 30-40MB bộ nhớ và có thể xử lý 13.000 event / giây / lõi.
- Độ tin cậy: Data loss sẽ không bao giờ xuất hiện. Fluentd hỗ trợ cả bộ đệm dựa trên bộ nhớ và file để tránh data loss. Nó cũng hỗ trợ chuyển đổi dự phòng mạnh mẽ và có thể được thiết lập cho tính sẵn sàng cao.
Trong hướng dẫn này, bạn sẽ học cách để cài đặt Fluentd và cấu hình nó để thu thập các bản ghi từ các Docker container. Sau đó bạn sẽ truyền dữ liệu đến một container khác chạy Elasticsearch trên cùng một máy chủ Ubuntu 16.04 và truy vấn các bản ghi..
Yêu cầu
- Một Ubuntu 16.04 server có ít nhất 4GB RAM với một sudo non-root user. Tham khảo bài viết Thiết lập ban đầu cho server dùng Ubuntu 16.04
- Docker được cài theo Bước 1 và Bước 2 trong bài viết Cách Cài đặt và Sử dụng Docker trên Ubuntu 16.04
Bước 1 — Cài Fluentd
Cách đơn giản nhất để cài Fluentd là qua gói td-agent
. Treasure Data, tác giả của Fluentd, đã đóng gói Fluentd cùng một Ruby runtime đi kèm, nên bạn không cần cài thêm một trường Ruby nòa để chạy Fluentd. Họ cũng cung cấp một đoạn script giúp update n=bản mới nhất của td-agent
trên repository và cài gói đó cho bạn.
Log in vào server với non-root user:
ssh sammy@your_server_ip
Cài gói td-agent
bằng cách sử dung đoạn mã của Treasure Data. Đầu tiên, download đoạn script:
\curl -L http://toolbelt.treasuredata.com/sh/install-ubuntu-xenial-td-agent2.sh -o install-td-agent.sh
Nếu muốn xem đoạn script, mở nó với nano:
nano install-td-agent.sh
Sau đó chạy nó để cài gói td-agent
:
sh install-td-agent.sh
Khởi động td-agent
:
sudo systemctl start td-agent
Kiểm tra lại log để xem quá trình cài đặt đã hoàn tất hay chưa.
tail /var/log/td-agent/td-agent.log
Output:
....2016-12-02 19:45:31 +0000 [info]: listening fluent socket on 0.0.0.0:24224 2016-12-02 19:45:31 +0000 [info]: listening dRuby uri="druby://127.0.0.1:24230" object="Engine"
Tiếp theo cài Elasticsearch plugin cho Fluentd với lệnh td-agent-gem
:
sudo td-agent-gem install fluent-plugin-elasticsearch
Note: Fluentd có thể được coi là một Ruby gem và có thể được cài với gem install fluentd. Nếu đã cài môi trường phát triển đển chạy Ruby, bạn có thể cài Fluentd và Elasticsearch plugin qua lệnh gem như sau:
gem install fluentd --no-rdoc --no-ri
gem install fluentd-plugin-elasticsearch --no-rdoc --no-ri
Bước 2 — Cấu hình Fluentd
Fluentd cần biết nơi nó cần thu thập thông tin, và nơi gửi các thông tín nó thu thập được. Bạn sẽ thiết lập những địa chỉ này trong file cấu hình Fluentd ở /etc/td-agent/td-agent.conf
.
Mở file trong nano:
sudo nano /etc/td-agent/td-agent.conf
Xóa tất cả nội dung trong file để viết lại.
Đầu tiên định nghĩa thẻ source
. Thêm vào file cấu hình những dòng sau:
@type forward port 24224
Thư mục nguồn được đặt là forward
. forward là một giao thức của Fluentd chạy ở tầng trên của TCP và được sử dụng bởi Docker khi nó gửi log đến Fluentd.
Khi những log bắt đầu được ghi, chúng sẽ có thêm một vài trường kết hợp, bao gồm time
, tag
, message
, container_id
...Bạn sẽ sử dụng thông tin bên trong _tag_
để quyết định nơi Fluentd sẽ gửi dũ liệu đến. Quá trình này gọi là data routing.
Để cấu hình nó, thêm một thẻ match
khớp với các thành phần của thẻ tag
như sau:
docker.**>
@typeelasticsearch logstash_format true
host 127.0.0.1
port 9200
flush_interval 5s
Luật này cho phép các bản ghi với một tag bắt đầu bằng docker.
sẽ được gửi đến Elasticsearch đang hoạt động trên địa chỉ 127.0.0.1
tại cổng 9200
. flush_interval
quyết định khoảng thời gian giữa hai lần gửi bản ghi của Fluentd đến Elasticsearch.
Lưu và đóng file, sau đó khởi động lại dịch vụ td-agent
để áp dụng các thay đổi.
sudo systemctl restart td-agent
Bước 3 — Khởi động Container Elasticsearch
Ta sẽ dùng Docker để chạy các bản cài đặt của Elasticsearch, vì việc này nhanh chóng hơn so với tự cấu hình Elasticsearch. Ở đây ta sẽ dùng Elasticsearch Docker image để tạo container.
Để sửu dụng image này, tăng giá trị của max_map_count
trên Docker host như sau:
sudo sysctl -w vm.max_map_count=262144
Sau đó chạy lệnh sau để download Elasticsearch image và khởi động container:
docker run -d -p 9200:9200 -p 9300:9300 elasticsearch
Image sẽ được tải về và Elasticsearch container sẽ khởi động sau đó. Đảm bảo rằng container đang chạy bình thường bằng cách kiểm tra tiến trình Docker với lệnh:
docker ps
Bạn sẽ thấy:
Output
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
76e96943491f elasticsearch "/docker-entrypoint.s" About a minute ago Up 51 seconds 0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp gigantic_hawking
Nếu container không được liệt kê, hãy khởi động nó một lần nữa với cờ -d thêm vào để container chạy với quyền ưu tiên. Chạy lệnh docker run -p 9200:9200 -p 9300:9300 elasticsearch và tìm kiếm các thông báo lỗi cụ thể. Các lỗi thường gặp là một số vấn đề với việc không có đủ bộ nhớ hệ thống, hoặc rằng giá trị max_map_count
trên máy chủ Docker của bạn quá thấp. Kiểm tra tất cả các bước trong hướng dẫn này .
Giờ Elasticsearch đang chạy trong container, ta sẽ tạo một vài log và đưa nó vào Fluentd.
Bước 4 — Tạo Log từ Docker Container
Với Docker, bạn có thể cư xử với log như một luồng( stream) dữ liệu đầu ra tiêu chuẩn (STDOUT
) giao diện lỗi (STDERR
). Khi khởi động một ứng dụng trong Docker, hãy thiết lập để Docker đẩy log ra sử dụng logging driver của Fluentd. Dịch vụ Fluentd sẽ nhận log và gửi chúng đến Elasticsearch.
Kiểm tra lại bằng một lệnh Bash bên trong Docker container như sau:
docker run --log-driver=fluentd ubuntu /bin/echo 'Hello world'
Lệnh này sẽ in dòng chữ Hello world
, đồng thời cũng được bắt bởi Docker Fluentd driver gửi đến Fluentd service. Sau 5 giây như đã cấu hình ở trên, bản ghi sẽ được đẩy đến Elasticsearch.
Cuối cùng hãy xác nhận rằng Elasticsearch đang nhận các bản ghi. Dùng curl
để gửi một câu hỏi đến Elasticsearch:
curl -XGET 'http://localhost:9200/_all/_search?q=*'
Output:
{"took":2,"timed_out":false,"_shards":{"total":1,"successful":1,"failed":0},"hits":{"total":1,"max_score":1.0,"hits":[{"_index":"logstash-2016.12.02","_type":"fluentd","_id":"AVQwUi-UHBhoWtOFQKVx","_score":1.0,"_source":{"container_id":"d16af3ad3f0d361a1764e9a63c6de92d8d083dcc502cd904155e217f0297e525","container_name":"/nostalgic_torvalds","source":"stdout","log":"Hello world","@timestamp":"2016-12-02T14:59:26-06:00"}}]}}
Bạn sẽ có một vài sự kiện được ghi log, tùy thuộc vào cài đặt. Một sự kiện thường bắt đầu với {"took":
với thông tin về thời gian bản ghi đưuọc ghi cùng với một vài thông tin tương tác với container nguồn. Như output ở trên, Elasticsearch đang nhận dữ liệu từ Docker container.
Tổng kết
Thu thập các bản ghi từ Docker container là chỉ là một cách để sử dụng Fluentd. Nhiều người dùng dùng Fluentd để xây dựng một logging pipeline thực hiện cả tìm kiếm thời gian thực đăng nhập và lưu trữ lâu dài. Kiến trúc này tận dụng khả năng của Fluentd để sao chép luồng dữ liệu và xuất chúng ra nhiều hệ thống lưu trữ. Ví dụ, bạn có thể sử dụng Elasticsearch cho thời gian thực tìm kiếm, nhưng sử dụng MongoDB hoặc Hadoop choo việc phân tích và lưu trữ lâu dài.
Các ứng dụng web tạo ra rất nhiều bản ghi log, và chúng thường có định dạng không thống nhất và lưu trữ trên hệ thống tập tin địa phương. Điều này có thể gây ra vấn đề vì hai lý do.
Thứ nhất, các bản ghi rất khó để phân tích theo cú pháp lập trình, đòi hỏi rất nhiều biểu thức tính toán thông thường, và do đó rất khó dễ tiếp cận cho những ai muốn tìm hiểu hành vi người dùng thông qua phân tích thống kê, rà soát kết quả của thử nghiệm A / B, hoặc phát hiện lỗi.
Thứ hai, các bản ghi không thể truy cập trong thời gian thực vì số lượng lớn log dạng văn bản được nạp vào hệ thống lưu trữ. Tệ hơn nữa, nếu ổ đĩa của máy chủ bị hỏng vì quá tải, các bản ghi sẽ bị mất hoặc bị hỏng.
Fluentd giải quyết cả hai vấn đề này bằng cách cung cấp thư viện logger hỗ trợ nhiều ngôn ngữ lập trình khác nhau với một API phù hợp. Mỗi logger sẽ gửi một bản ghi có chứa timestamp, tag, và một sự kiện định dạng JSON đến Fluentd, như những gì diễn ra trong hướng dẫn này. Có những thư viện logger cho Ruby, Node.js, Go, Python, Perl, PHP, Java và C++. Điều này cho phép các ứng dụng khả năng thực hiện các tác vụ mà không cần quan tâm đến việc lưu trữ đầu ra; vì logger sẽ gửi dữ liệu cho Fluentd một cách không đồng bộ,cho phép đệm những bản ghi trước khi vận chuyển chúng ra khỏi backend system.