How do I test my Fluentd config in combination with Elasticsearch? - docker

Problem:
I have a complicated setup where I use Elasticsearch and FluentD as part of my logging stack. I would like to add a metric and test the FluentD config for that.
How can I do that?
Idea:
Use docker-compose to start an EFK stack. Create a docker container that writes to stdout and simulates logs.
Problem with my idea:
The logs written by mylogger never seem to reach Elasticsearch. What am I doing wrong? myloggeris a container that simply writes to stdout in a loop and forever using bash.
docker-compose.yaml
version: '3'
services:
logger:
image: mylogger
links:
- fluentd
logging:
driver: "fluentd"
options:
fluentd-address: localhost:24224
tag: httpd.access
fluentd:
build: ./fluentd
volumes:
- ./fluentd/conf:/fluentd/etc
links:
- "elasticsearch"
ports:
- "24224:24224"
- "24224:24224/udp"
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
container_name: elasticsearch
environment:
- "discovery.type=single-node"
expose:
- "9200"
ports:
- "9200:9200"
kibana:
image: kibana:7.10.1
links:
- "elasticsearch"
ports:
- "5601:5601"
fluent.conf File does not contain the changes that I want to make, yet.
<source>
#type forward
port 24224
bind 0.0.0.0
</source>
<label #FLUENT_LOG>
<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>
</label>

Related

How can I configure logging to fluentd without docker?

I made a docker-compose.yml, which runs .NET Core web server and fluentd.
docker-compose.yml:
version: "2"
services:
webserver:
build:
context: ..
dockerfile: ./MyProject/Dockerfile
container_name: webserver
depends_on: [ fluentd ]
ports:
- "8080:80"
logging:
driver: fluentd
options:
fluentd-address: fluentd:24224
fluentd-async: "true"
fluentd-max-retries: 30
tag: "web.log"
fluentd:
build:
context: ./fluentd
dockerfile: Dockerfile
container_name: fluentd
volumes:
- ./fluentd/conf:/fluentd/etc
ports:
- "24224:24224"
- "24224:24224/udp"
fluent.conf:
<source>
#type forward
port 24224
bind 0.0.0.0
</source>
<match web.log>
#type stdout
</match>
However, if I should run my .NET server not as a docker container, how can I configure logging to fluentd like fluentd-address? (fluentd is still running on docker, but web server isn't.)

Build the EFK system used for simulating logging server on Docker

I want to simulate laravel logging to EFK system server
Base on this, I build up two container. One of laravel project's container. The ohter is EFK system container
but EFK's fluentd does not catch any data or event
my container's compose:
version: '3'
services:
nginx:
image: nginx:latest
ports:
- 8010:80
volumes:
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:delegated
- ./server:/var/www/:delegated
depends_on:
- php
- fluentd
logging:
driver: "fluentd"
options:
fluentd-address: fluentd:24225
fluentd-async-connect: 'true'
fluentd-retry-wait: '1s'
fluentd-max-retries: '30'
tag: fubo.logger
php:
container_name: php-laravel
build: ./php
volumes:
- ./server:/var/www/:delegated
db:
build: ./mysql
volumes:
- ./mysql/data/:/var/lib/mysql
ports:
- 3306:3306
phpmyadmin:
image: phpmyadmin/phpmyadmin:latest
ports:
- 8811:80
depends_on:
- db
fluentd:
build: ./fluentd
volumes:
- ./fluentd/conf:/fluentd/etc
ports:
- "24225:24224"
- "24225:24224/udp"
networks:
- docker-efk_efk_network
networks:
docker-efk_efk_network:
external: true
my container's fluent.conf:
<source>
#type tail
path /etc/logs/laravel.log
pos_file /etc/logs/laravel.log.pos
tag docker.space
<parse>
#type json
</parse>
</source>
<match *.**>
#type forward
send_timeout 60s
recover_wait 10s
hard_timeout 60s
<server>
name dockerSpace
host docker-efk-fluentd-1
port 24224
weight 60
</server>
</match>
EFK's container compose:
version: '3'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.15.1
container_name: elasticsearch
restart: unless-stopped
environment:
- discovery.type=single-node
- xpack.security.enabled=false
ports:
- 9200:9200
kibana:
image: docker.elastic.co/kibana/kibana:7.15.1
container_name: kibana
restart: unless-stopped
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
- I18N_LOCALE=zh-tw
ports:
- 5601:5601
links:
- elasticsearch
fluentd:
build: ./fluentd
volumes:
- ./fluentd/conf/:/fluentd/etc/
links:
- elasticsearch
ports:
- "24224:24224"
- "24224:24224/udp"
networks:
- efk_network
networks:
efk_network:
driver: bridge
EFK's container fluent.conf:
<source>
#type forward
port 24225
bind docker-space_fluentd_1
</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>
This is my container networks list:
name
driver
scope
docker-efk_default
bridge
local
docker-efk_efk_network
bridge
local
docker-space_default
bridge
local
What's wrong my understanding?
There are two step to do:
First, ensurce both of container has connected each other. More detail can see this.
How to link multiple docker-compose services via network
Second, modify EFK container's fluentd configuare:
<source>
#type forward
bind 0.0.0.0
port 24224
</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>
And ... it's work.

Docker Logging Efk 7.10.1 Compose ECONNREFUSED

just trying to build a test app for learning purposes on how to collect Docker logs to EFK (Elasticsearch7.10.1 + Fluentd + Kibana7.10.1) stack.
Elastic starts up fine and is reachable from http://localhost:5601/
But fluentd-* is not available as an index pattern, I assume do to the error I am getting on the logs from kibana:
kibana_1 | {"type":"log","#timestamp":"2021-01-03T23:46:32Z","tags":["error","elasticsearch","monitoring"],"pid":6,"message":"Request error, retrying\nGET http://elasticsearch:9200/_xpack => connect ECONNREFUSED 172.20.0.3:9200"}
kibana_1 | {"type":"log","#timestamp":"2021-01-03T23:46:32Z","tags":["warning","elasticsearch","monitoring"],"pid":6,"message":"Unable to revive connection: http://elasticsearch:9200/"}
kibana_1 | {"type":"log","#timestamp":"2021-01-03T23:46:32Z","tags":["warning","elasticsearch","monitoring"],"pid":6,"message":"No living connections"}
kibana_1 | {"type":"log","#timestamp":"2021-01-03T23:46:32Z","tags":["warning","plugins","licensing"],"pid":6,"message":"License information could not be obtained from Elasticsearch due to Error: No Living connections error"}
kibana_1 | {"type":"log","#timestamp":"2021-01-03T23:46:32Z","tags":["warning","plugins","monitoring","monitoring"],"pid":6,"message":"X-Pack Monitoring Cluster Alerts will not be available: No Living connections"}
kibana_1 | {"type":"log","#timestamp":"2021-01-03T23:46:32Z","tags":["error","elasticsearch","data"],"pid":6,"message":"[ConnectionError]: connect ECONNREFUSED 172.20.0.3:9200"}
kibana_1 | {"type":"log","#timestamp":"2021-01-03T23:46:32Z","tags":["error","savedobjects-service"],"pid":6,"message":"Unable to retrieve version information from Elasticsearch nodes."}
172.20.0.3:9200 and http://elasticsearch:9200/ are not reachable through browser
http://localhost:9200/ is reachable
What am I missing? I have been working on this for a week and don't know where to look anymore, thanks!
Docker-compose.yml
version: '2'
services:
web:
image: httpd
ports:
- "8080:80"
links:
- fluentd
logging:
driver: "fluentd"
options:
fluentd-address: localhost:24224
tag: httpd.access
fluentd:
build: ./fluentd
volumes:
- ./fluentd/conf
links:
- "elasticsearch"
ports:
- "24224:24224"
- "24224:24224/udp"
elasticsearch:
image: elasticsearch:7.10.1
environment:
- "network.host=0.0.0.0"
- "transport.host=127.0.0.1"
expose:
- 9200
ports:
- "9200:9200"
kibana:
image: kibana:7.10.1
environment:
server.host: 0.0.0.0
elasticsearch.hosts: http://localhost:9200
ports:
- "5601:5601"
Dockerfile
# fluentd/Dockerfile
FROM fluent/fluentd:v1.11.5-debian-1.0
RUN ["gem", "install", "fluent-plugin-elasticsearch", "--no-document", "--version", "4.0.4"]
fluentd.conf file
# fluentd/conf/fluent.conf
<source>
#type forward
port 24224
bind 0.0.0.0
</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>
This is totally fine and the expected outcome.
In docker, if you want your service (Kibana) to be available from the localhost you should map it's port to localhost. You are doing that by:
ports:
- "5601:5601"
then you can access Kibana from your browser (localhost) by using http://localhost:5601
On other hand, internally, if you want to access one container from another you should use the container name (rather than localhost) - so if you want to access the Kibana within the elasticsearch container you would execute into the elasticsearch container and call:
curl http://kibana:5601
EDIT:
one interesting case is your web container that uses a different port internally and externally, so from localhost you would:
curl http://localhost:8080
while internally (within that docker network) you will access by:
http://web
(you can omit the 80 since its the default http port)
EDIT2:
As stated in the documentation, the default value for elasticsearch.hosts is http://elasticsearch:9200.

Docker: Ship log files being written inside containers to ELK stack

I am running a django application using docker, and using python logging in django settings to write api logs inside a logs folder. When I restart my container my log files are also removed (which is understandable).
I would like to ship my logs (e.g. /path/to/workdir/logs/django.log) to elasticsearch. I am confused since my searches tell me to ship this path /var/lib/docker/containers/*/*.log but I don't think this is what I want.
Any ideas on how I ship my logs inside the container to ELK Stack?
You can ship logs from docker containers stdout / stderr to elasticsearch using the gelf logging driver.
Configure the services to with the gelf logging driver (docker-compose.yml):
version: '3.7'
x-logging:
&logstash
options:
gelf-address: "udp://localhost:12201"
driver: gelf
services:
nginx:
image: 'nginx:1.17.3'
hostname: 'nginx'
domainname: 'example.com'
depends_on:
- 'logstash'
ports:
- '80:80'
volumes:
- '${PWD}/nginx/nginx.conf:/etc/nginx/nginx.conf:ro'
logging: *logstash
elasticsearch:
image: 'elasticsearch:7.1.1'
environment:
- 'discovery.type=single-node'
volumes:
- 'elasticsearch:/usr/share/elasticsearch/data'
expose:
- '9200'
- '9300'
kibana:
image: 'kibana:7.1.1'
depends_on:
- 'elasticsearch'
ports:
- '5601:5601'
volumes:
- '${PWD}/kibana/kibana.yml:/usr/share/kibana/config/kibana.yml'
logstash:
build: 'logstash'
depends_on:
- 'elasticsearch'
volumes:
- 'logstash:/usr/share/logstash/data'
ports:
- '12201:12201/udp'
- '10514:10514/udp'
volumes:
elasticsearch:
logstash:
Note: the above example configures the logging using extension fields.
The minimal nginx.conf used for this example:
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log debug;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
server {
listen 80;
server_name _;
location / {
return 200 'OK';
}
}
}
The logstash image is a custom build using the below Dockerfile:
FROM logstash:7.1.1
USER 0
COPY pipeline/gelf.cfg /usr/share/logstash/pipeline
COPY pipeline/pipelines.yml /usr/share/logstash/config
COPY settings/logstash.yml /usr/share/logstash/config
COPY patterns /usr/share/logstash/patterns
RUN rm /usr/share/logstash/pipeline/logstash.conf
RUN chown -R 1000:0 /usr/share/logstash/pipeline /usr/share/logstash/patterns /usr/share/logstash/config
USER 1000
... the relevant logstash gelf plugin config:
input {
gelf {
type => docker
port => 12201
}
}
filter { }
output {
if [type] == "docker" {
elasticsearch { hosts => ["elasticsearch:9200"] }
stdout { codec => rubydebug }
}
}
... and pipelines.yml:
- pipeline.id: "gelf"
path.config: "/usr/share/logstash/pipeline/gelf.cfg"
... and logstash.yml to persist the data:
queue:
type: persisted
drain: true
The process running in the container logs to stdout / stderr, docker pushes the logs to logstash using the gelf logging driver (note: the logstash address is localhost because the docker service discovery is not available to resolve the service name - the ports must be mapped to the host and the logging driver must be configured using localhost) which outputs the logs to elasticsearch that you can index in kibana:

Can't log from (fluentd) logdriver using service name in compose

I have the following setup in docker:
Application (httpd)
Fluentd
ElasticSearch
Kibana
The configuration of the logdriver of the application is describing the fluentd container. The logs will be saved in ES and shown in Kibana.
When the logdriver is configured as this, it works:
web:
image: httpd
container_name: httpd
ports:
- "80:80"
links:
- fluentd
logging:
driver: "fluentd"
options:
fluentd-address: localhost:24224
tag: httpd.access
And fluentd is mapping its exposed port 24224 on port 24224 of the host.
fluentd:
build: ./fluentd
image: fluentd
container_name: fluentd
links:
- "elasticsearch"
ports:
- "24224:24224"
But I don't want to expose my fluentd on the hostnetwork. I want to keep it 'private' inside the docker network (I only want to map the app and kibana on the host network) so like this:
fluentd:
build: ./fluentd
image: fluentd
container_name: fluentd
links:
- "elasticsearch"
The port 24224 is still exposed (in the dockerfile) but it's not mapped on the host network. Now I want change the config of the logdriver of my app:
logging:
driver: "fluentd"
options:
fluentd-address: fluentd:24224
tag: httpd.access
So fluentd is the name of the fluentd container and they are in the same network but the app is not able to make a connection with it.
failed to initialize logging driver: dial tcp: lookup fluentd
Is this maybe because the logging option is executed before the 'link'-option in the compose file?
Is there a way to let this work?
This is not possible currently. The docker deamon which handles the log drivers is a process running on the host machine. It is not a service in your network and is therefore unable to resolve servicenames to IP's. See this github issue for more detailed explanations.
You will have to publish a port for this to work.

Resources