--- title: Ambiente de Monitoramento Dockmon tags: Docker, Prometheus, AWS --- # Ambiente de Monitoramento Dockmon [![hackmd-github-sync-badge](https://hackmd.io/o8hoT9nsRP-gdEa1MHLN_A/badge)](https://hackmd.io/o8hoT9nsRP-gdEa1MHLN_A) ![Projeto](https://img.shields.io/badge/Equipe-DevOps-green?style=for-the-badge&logo=superuser) ![Projeto](https://img.shields.io/badge/Projeto-Monitoramento-green?style=for-the-badge&logo=prometheus) ## Apresentação Este documento traz os detalhes do projeto de monitoração Dockmon, bem como fazer para replicá-lo localmente, para o desenvolvimento/ajuste de alguma de funções e/ou recursos. O ambiente é baseado em docker e utiliza Prometheus, Nginx, MySQL e Grafana. O código foi hospedado com o CodeCommit da AWS. ## Por que Docker A escolha por docker se dá pela facilidade de replicação do ambiente, facilitando o desenvolvimento de novos recursos, bem como ajustes em sua estrutura. Um outro ponto é o encapsulamento da aplicação de forma a isolar e preservar as suas configurações. :whale: ## Como usar esse repositório ### Configurando a chave SSH O primeiro passo é configurar a chave de acesso ao repositório. Vamos nomeá-la 'commit': ```gherkin= ssh-keygen -t rsa -b 4096 -C "euandros@vansor.tech" Generating public/private rsa key pair. Enter file in which to save the key (/home/esantos/.ssh/id_rsa): /home/esantos/.ssh/commit Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/esantos/.ssh/commit. Your public key has been saved in /home/esantos/.ssh/commit.pub. The key fingerprint is: SHA256:BOnAtS6CqC8VStnrA5EgJPMp38TsdZlzULdN+4eA4O0 EUANDROS The key's randomart image is: +---[RSA 4096]----+ |+. . .o.o.. . . | |+o +o .+ * o + . | |+ * +oo B + o o | |.O.= o.o + . o | |+.+.= . S E . o| |o..o . .| |..o | |.. o | | .. . | +----[SHA256]-----+ -t: escolha do tipo da chave -b: definição do tamanho da chave em bits -C: insere como comentário o e-mail da conta ``` #### Upload da Chave Faça a cópia do conteúdo de sua chave pública e o insira nas configurações de credenciais de segurança da AWS: ```gherkin= cat /home/esantos/.ssh/commit.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDNKYVzo2MqwIpIsNlHdXToURydhj3wds bVtEUj0WSszrd3M69syx7PRHBl9lSC6AsUdTN5IW+dCfgCR8PaVQmclktsBr3vyS/+cqVk yT2VnqqF3E/Ou0oYHPPc+usu0Lr9T8N9aXVX0meaNyUCUH7RUkdzobceHt4uXJBGN8rfXW udVlSDgp3y5T9bnYNBvDd8pSWENzi4f+7A6OvfguMXDjYdxNpeYnyaQZRU4vG2yhB0h94o 36E6NTzPFfavbvTTwLwIUKR7ZiYc01cSvOXxRWJfjK/uBSzbvGfipHsk3N0q+umzi79aQm L9KuggJaVEHdGZXBjeJMS/m/LUkjNvGRfzrkrm+JH/Iy092qL34Gxp7VulfaSscie8Gj/U T1DjrWCslZmPkKroUrFswe/87HpCiCioFVXkTPoDZQj91dviz+09v5wumULcFJyOZ9nZ4s MEwnUSNcaJZpnajCdnHhe64V2OxA7IyZBTDdvitbnLHP8dAaShcPx37Qk9V8gHaFEOvPcm 8ZYW/7lLixptxfXSyoFM3XchqOZ0Cuqm/CXWxX6Ul5kuCgqC4Ll6HJKLUSfC4Avjk2TfBU vYLctfS1rrvUO6mO/w5w25vxITbNFaND6WMBK26R+L8aR9j8EeGXmfiQ3OppbsRYLGYqX2 /Xtawj9xMaaqFE1qwF8z/w== euandros@vansor.tech ``` ##### Configurando o acesso ao Repositório Com a chave configurada, será necessário criar o arquivo de configuração com os dados de acesso. Por este motivo, acesse ao seu diretório ```~/.ssh``` e crie um arquivo nomeado config com os seguintes dados: ```gherkin= cd ~/.ssh nano config > Host git-codecommit.*.amazonaws.com > User APKASAXOOBB5SQEXEMPLO #ID gerada após o upload da sua chave SSH. > IdentityFile ~/.ssh/commit #Informe o nome da chave. ``` ###### Salve o arquivo e saia. Altere a permissão do arquivo com o seguinte comando ```gherkin= chmod 600 config ``` ##### Testando a configuração Teste a sua configuração e confirme a conexão, para que o domínio seja adicionado ao arquivo ```hosts``` de seu sistema: ```gherkin= ssh git-codecommit.us-east-1.amazonaws.com You have successfully authenticated over SSH. You can use Git to interact with AWS CodeCommit. Interactive shells are not supported.Connection to git-codecommit.us-east-1.amazonaws.com closed by remote host. Connection to git-codecommit.us-east-1.amazonaws.com closed. ``` ##### Adicionando o repositório remoto Crie, em sua pasta pessoal, o diretório ```~/projetos```. Acesse-o e o inicialize como um repositorio GIT. Feito isso, adicione o nosso repositório como remoto, de forma que possa enviar seus `commits`. Não se esqueça de efetuar a configuração de seu perfil, nas configurações do GIT. Assegure que o pacote ```git``` esteja instalado em seu sistema: ```gherkin= mkdir ~/projetos cd ~/projetos git init git config --global user.name "Euandros" git config --global user.mail "euandros@vansor.tech" git remote add "dockmon" ssh://git-codecommit.us-east-1.amazonaws.com/v1/repos/dockmon ``` Pronto. Agora é só recriar o ambiente, localmente, para iniciar a sua task de configuração do exporter. ## Comandos úteis A seguir estão os comandos necessários para iniciar o ambiente em sua máquina: | Comando | Finalidade | | ------------------------------------|:------------------------------------------------------------------------------------| | docker-compose up | inicia o ambiente a partir das configurações presentes no arquivo docker-compose.yml| | docker-compose stop | para o ambiente que fora gerado anteriormente | | docker-compose start | inicia o ambiente que fora parado previamente | | docker-compose restart | reinicia o ambiente que fora parado previamente | | docker inspect <CONTAINER_ID> | faz a inspeção do contêiner e traz o detalhamento de sua estrutura | | docker exec -i -t <CONTAINER_ID> sh | executa um comando em modo interativo com o contêiner disponibilizando um shell | Para maiores detalhes, acesse: [Docker](https://docs.docker.com/) # O Ambiente O nosso ambiente de monitoramento está configurado da seguinte maneira: | Nome do Contêiner | Finalidade | | -----------------------------|:----------------------------------------------------------------------------------------------| | dockmon-prometheus | Contêiner que executa a aplicação Prometheus, a que faz a coleta das métricas do ambiente. | | dockmon-grafana | Contêiner que executa a aplicação Grafana, a que é responsável por gerar os dashboards. | | dockmon-pushgateway | Contêiner que executa a aplicação PushGateway, a que é responsável por receber métricas e direcioná-las ao Prometheus | | dockmon-mysql | Contêiner que executa o banco de dados dedicado à aplicação Grafana | | dockmon-alertmanager | Contêiner que executa a aplicação Alert Manager, que é responsável por disparar os alertas de eventos observados no ambiente. | | dockmon-nginx | Contêiner que executa o NGINX como proxy reverso, sobre as demais aplicações. | | dockmon-promtool | Contêiner que executa a ferramenta promtool, a que é responsável por checar e validar a existência de erros ou inconsistências nos arquivos ```prometheus.yml``` e ```prometheus.rules.yml```. | A seguir, veremos a configuração de cada um, em detalhe. --- ## NGINX O **NGINX** está configurado como *proxy reverso*, escutando a porta em que o **Prometheus** publica, redirecionando-a para uma nova. Abaixo, estão as sua configurações, a começar pelo arquivo ```docker-compose.yml``` : ```gherkin= services: nginx: image: nginx container_name: dockmon-nginx volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf - ./nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf - ./prometheus/.credentials:/etc/prometheus/.credentials - ./prometheus/ssl/:/etc/prometheus/ssl - ./nginx/www/:/opt/www/ restart: "always" network_mode: host ports: - 80:80 - 443:443 - 1234:1234 ``` No passo acima, temos a chamada no docker-compose para o contêiner do **NGINX**. Primeiramente, declaramos o nome do serviço que iremos usar, em que cada serviço, corresponde a um contêiner (aplicação). Em nosso exemplo ```nginx```. Logo abaixo, é declarada a imagem de contêiner que será usada como base, bem como o nome que atribuiremos a ele, respectivamente ```ìmage``` e ```container_name```. Na sequência, observamos que são declarados os ```volumes``` que serão montados e usados pelo docker. No caso do **NGINX** houve uma particularidade na configuração, a que nos levou a declarar os seus dois arquivos de configuração como volumes, igualmente para o arquivo de credencial de acesso seguro, para que o container já subisse com os arquivos montados e disponíveis para uso, sobrescrevendo os da configuração padrão da imagem. ```gherkin= volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf - ./nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf - ./prometheus/.credentials:/etc/prometheus/.credentials ``` O contêiner foi configurado para fazer o seu ``` restart``` sempre que o ocorrer a sua queda. A sua rede está operando no modo ```host```, isto é, ele receberá um ip válido de acordo com a rede do host em que for executado. As portas, ```ports```, que serão utilizadas são apresentadas na lista, uma abaixo da outra. ```gherkin= restart: "always" network_mode: host ports: - 80:80 - 443:443 - 1234:1234 ``` O **NGINX** está configurado para escutar a porta padrão do **Prometheus**, a ```9090```, efetuar o seu redirecionamento para a porta ```1234```, conforme vimos acima. A seguir está a configuração que fizemos para esse fim, no arquivo ```default.conf``` ```gherkin= server { listen 1234 ssl; ssl_certificate /etc/prometheus/ssl/prometheus-cert.pem; ssl_certificate_key /etc/prometheus/ssl/prometheus-private-key.pem; location / { auth_basic "Prometheus"; auth_basic_user_file /etc/prometheus/.credentials; proxy_pass http://localhost:9090/; } } ``` Além de fazer o redirecionamento, o **NGINX** requerirá a validação por meio de usuário e senha, conforme configurado no arquivo ```.credentials```. São eles: > * **Usuário**: admin > * **Senha**: BYK6138T@$%79! O NGINX também terá em sua configuração, futuramente, o **Alert Manager** e o **Grafana** por trás do *proxy reverso*. --- ## PROMTOOL O **Promtool** é o validador do código dos arquivos ```prometheus.yml``` e ```prometheus.rules.yml```, verificando se há inconsistência na indentação, ou na forma de declaração utilizada. ```gherkin= promtool: image: jacknagel/promtool container_name: dockmon-promtool volumes: - ./prometheus:/tmp/ command: check config /tmp/prometheus.yml ``` Em linhas gerais, o contêiner executa o comando de checagem do arquivo e como saída temos a resposta se há ou não falhas. Se sim, ele nos indica em qual linha e impede que o contêiner do **Prometheus** seja carregado com falhas. ```gherkin= ./promtool check config prometheus.yml Checking prometheus.yml SUCCESS: 1 rule files found Checking prometheus.rules.yml FAILED: [yaml: line 174: did not find expected '-' indicator] ``` --- ## PROMETHEUS O **Prometheus** é a nossa ferramenta de monitoramento, que monitora e coleta as métricas do ambiente de nossos clientes. Em nosso cenário, ele está configurado com acesso seguro, utilizando certificado e chave SSL. Abaixo estão as sua configurações, a começar pelo ```docker-compose.yml```: ```gherkin= prometheus: image: prom/prometheus:latest container_name: dockmon-prometheus volumes: - ./prometheus/:/etc/prometheus/ - prometheus_data:/prometheus command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' - '--web.console.libraries=/usr/share/prometheus/console_libraries' - '--web.console.templates=/usr/share/prometheus/consoles' - '--web.listen-address=0.0.0.0:9090' - '--web.enable-admin-api' - '--web.external-url=https://localhost:1234' ports: - 9090:9090 depends_on: - promtool ``` A configuração do compose não apresenta grande diferença em relação aos demais, senão pela declaração dos comandos que serão executados após a carga do contêiner. Por meio da chave ```command``` os declaramos em lista. ```gherkin= command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' - '--web.console.libraries=/usr/share/prometheus/console_libraries' - '--web.console.templates=/usr/share/prometheus/consoles' - '--web.listen-address=0.0.0.0:9090' - '--web.enable-admin-api' - '--web.external-url=https://localhost:1234' ``` Um ponto que precisamos nos atentar é à presença da chave ```depends_on```, a que estabelece uma relação de dependência. No caso, a execução do contêiner do **Prometheus** só ocorrerá após a validação do código por meio do **Promtool**. Abaixo temos o arquivo ```prometheus.yml```: ```gherkin= global: scrape_interval: 15s scrape_timeout: 10s evaluation_interval: 1m rule_files: - 'prometheus.rules.yml' scrape_configs: - job_name: 'prometheus' scrape_interval: 5s static_configs: - targets: ['localhost:9090'] - job_name: 'node' scrape_interval: 5s static_configs: - targets: [IP da Máquina:9100] - job_name: 'snmp' static_configs: - targets: - IP_do_Alvo metrics_path: /snmp params: module: [if_mib] relabel_configs: - source_labels: [__address__] target_label: __param_target - source_labels: [__param_target] target_label: instance - target_label: __address__ replacement: IP da Máquina:9116 - job_name: ‘rabbitmq’ static_configs: - targets: [IP da Máquina:15672] metrics_path: /api/metrics - job_name: ‘pushgateway’ scrape_interval: 1s static_configs: - targets: [IP da Máquina:9091] - job_name: 'mysql_exporter' scrape_interval: 15s static_configs: - targets: ['IP da Máquina:9104', 'IP da Máquina:9105'] - job_name: 'java-exp' scrape_interval: 5s static_configs: - targets: [IP da Máquina:8080] ``` O arquivo contém as configurações necessárias para a coleta de métricas do ambiente, a partir dos ```exporters``` configurados previamente. O arquivo inicia apresentando as configurações globais, aquelas que serão aplicadas a toda coleta que será especificada no restante do documento. ```gherkin= global: scrape_interval: 15s <- Intervalo de tempo em que cada coleta será efetuada scrape_timeout: 10s <- Intervalo de tempo em que será aguardado entre uma coleta e outra, caso apresente falha. evaluation_interval: 1m <- Período de avaliação da execução da regra de coleta, antes de iniciar o alerta. ``` Logo abaixo é declarado o caminho do arquivo de regras de alertas: ```gherkin= rule_files: - 'prometheus.rules.yml' ``` A coleta de cada exporter é referendada como *job* e traz a seguinte configuração: ```gherkin= - job_name: 'java-exp' <- Nome do Job scrape_interval: 5s <- Intervalo de tempo da coleta especifico do job static_configs: - targets: [IP da Máquina:8080] <- IP da máquina em que está instalado o exporter. ``` Em alguns jobs podemos especificar o caminho em que a coleta publicará as métricas: ```gherkin= - job_name: ‘rabbitmq’ static_configs: - targets: [IP da Máquina:15672] metrics_path: /api/metrics <- Caminho da publicação das métricas. ``` --- ## ALERT MANAGER O **Alert Manager** é a ferramenta responsável por fazer o envio de alertas de falhas observadas no ambiente, para os canais que configuramos previamente. Ele utiliza das regras descritas no arquivo ```prometheus.rules.yml``` para gerir quando e o que enviar como alerta. O arquivo é iniciado pela chave ```groups```, a que receberá os grupos de alertas, de acordo com a função/serviço/aplicação. Em nosso cenário, o primeiro grupo é aquele que gravará as regras, isto é, aquelas que serão pré-carregadas, dada a frequência de uso, `recording_rules`, sendo seguido pelo grupo de regras referente ao `Hardware Alerts`. ```gherkin= groups: - name: recording_rules rules: - record: node_exporter:node_memory_free:memory_used_percents expr: 100 - 100 * (node_memory_MemFree / node_memory_MemTotal) - name: Hardware Alerts rules: - alert: Node Exporter Indisponível expr: up{job="node_exporter"} == 0 for: 1m labels: severity: major annotations: title: Node na instância {{ $labels.instance }} - está indisponível description: Falha ao coletar o {{ $labels.job }} na {{ $labels.instance }} no último minuto. Node parece estar fora. ``` Abaixo do nome do grupo, nos é apresentado o campo `rules`, que traz abaixo de si a estrutura da regra. O item `record` traz o nome da regra seguida pelo detalhe da coleta. Por sua vez, o item `expr` traz a expressão que será usada pela regra: ```gherkin= record: node_exporter:node_memory_free:memory_used_percents expr: 100 - 100 * (node_memory_MemFree / node_memory_MemTotal) ``` O grupo de regras de alertas, terá uma estrutura similar: O nome da regra é expresso pelo item `alert` e o período de tempo necessário para o disparo do alerta é expresso pelo item ```for```. ```gherkin= - alert: Node Exporter Indisponível expr: up{job="node_exporter"} == 0 for: 1m ``` Em ```lables``` nós temos os detalhes da severidade, ```severity```, como também as anotações da regra, como o título, que será usado para o envio da mensagem, ```title``` e sua descrição, ```description```: ```gherkin= labels: severity: major annotations: title: Node na instância {{ $labels.instance }} - está indisponível description: Falha ao coletar o {{ $labels.job }} na {{ $labels.instance }} no último minuto. Node parece estar fora. ``` No arquivo ```alertmanager.yml``` nós teremos a configuração do alertmanager e a sua integração com os canais: ```gherkin= global: resolve_timeout: 5m http_config: {} smtp_hello: localhost smtp_require_tls: true slack_api_url: https://hooks.slack.com/services/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 route: receiver: slack-notifications group_by: - alertname - datacenter - app receivers: - name: slack-notifications slack_configs: - send_resolved: false http_config: {} api_url: https://hooks.slack.com/services/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 channel: '#alertas' username: '{{ template "slack.default.username" . }}' color: '{{ if eq .Status "firing" }}danger{{ else }}good{{ end }}' title: '[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .GroupLabels.alertname }} - {{ range .Alerts }} {{ .Labels.severity }} {{ end }}' title_link: '{{ template "slack.default.titlelink" . }}' pretext: '{{ template "slack.default.pretext" . }}' text: '{{ template "slack.myorg.text" . }}' footer: '{{ template "slack.default.footer" . }}' fallback: '{{ template "slack.default.fallback" . }}' callback_id: '{{ template "slack.default.callbackid" . }}' icon_emoji: '{{ template "slack.default.iconemoji" . }}' icon_url: '{{ template "slack.default.iconurl" . }}' templates: [] ``` No campo ```global``` nós temos as configurações gerais do **Alert Manager**: ```gherkin= global: resolve_timeout: 5m <- Intervalo de tempo de comunicação entre o **Alert Manager** e o **Prometheus**. http_config: {} <- Configuração do acesso HTTP smtp_hello: localhost <- Configuração do SMTP smtp_require_tls: true <__| slack_api_url: https://hooks.slack.com/services/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 ^ |__ Configuração da API do Slack. ``` O grupo ```route``` nos traz os detalhes de qual canal receberá os alertas e a maneira como os receberá. ```gherkin= route: receiver: slack-notifications <- Nome do destinatário group_by: <- Agrupamento dos alertas - alertname <- Agrupamento por: nome dos alertas - datacenter <- Agrupamento por: localização - app <- Agrupamento por: aplicação ``` O grupo ```receivers``` traz as informações do destinatário (canal) que receberá os alertas: ```gherkin= receivers: - name: slack-notifications slack_configs: - send_resolved: false http_config: {} api_url: https://hooks.slack.com/services/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 channel: '#alertas' username: '{{ template "slack.default.username" . }}' color: '{{ if eq .Status "firing" }}danger{{ else }}good{{ end }}' title: '[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .GroupLabels.alertname }} - {{ range .Alerts }} {{ .Labels.severity }} {{ end }}' title_link: '{{ template "slack.default.titlelink" . }}' pretext: '{{ template "slack.default.pretext" . }}' text: '{{ template "slack.myorg.text" . }}' footer: '{{ template "slack.default.footer" . }}' fallback: '{{ template "slack.default.fallback" . }}' callback_id: '{{ template "slack.default.callbackid" . }}' icon_emoji: '{{ template "slack.default.iconemoji" . }}' icon_url: '{{ template "slack.default.iconurl" . }}' templates: [] ``` Como podemos observar, há - novamente - a apresentação do endereço da API do canal, `api_url` e o canal em que o alerta será publicado, `channel`. Abaixo temos a delimitação de cores, `colors`, do titulo que será usado no envio,`title` e outros detalhes da forma como a mensagem será estruturada. Um campo que precisamos estar atentos é o `send_resolved`, em que determinamos se será enviada ou não mensagem de resolução, assim que o alerta for resolvido. Abaixo, temos a forma como o **Alert Manager** é declarado no `docker-compose.yml` ```gherkin= alertmanager: image: prom/alertmanager container_name: dockmon-alertmanager ports: - 9093:9093 volumes: - ./alertmanager/:/etc/alertmanager/ - ./data/alertmanager:/data command: - '--config.file=/etc/alertmanager/alertmanager.yml' - '--storage.path=/data' ``` --- ## MSYQL O **MYSQL**, em nosso cenário, é usado para armazenar as informações geradas/carregadas pelo Grafana. Vejamos o seu compose: ```gherkin= db: image: mysql:5.6 container_name: dockmon-mysql environment: MYSQL_ROOT_PASSWORD: HKf16a@123 MYSQL_DATABASE: grafana MYSQL_USER: grafana MYSQL_PASSWORD: BYK6138t@123 command: [mysqld, --character-set-server=utf8mb4, --collation-server=utf8mb4_unicode_ci, --innodb_monitor_enable=all, --max-connections=1001] ports: - 3306:3306 healthcheck: test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"] timeout: 10s retries: 10 ``` Nesta estrutura, nós temos o uso da chave ```environment```, a que usamos para declarar variáveis do ambiente: ```gherkin= environment: MYSQL_ROOT_PASSWORD: HKf16a@123 <- Senha do usuário root, do banco. MYSQL_DATABASE: grafana <- Nome da base de dados que será criada. MYSQL_USER: grafana <- Usuário que será criado para manipulação da base. MYSQL_PASSWORD: BYK6138t@123 <- Senha que será atribuída ao usuário. ``` Temos, também, a execução de uma checagem da saúde do serviço utilizado no contêiner, a que é apresentada pela chave ```healthcheck```. Nela especificamos qual o teste será efetuado, ```test```, o período de tempo em que será executada uma nova execução, ```timeout```, bem como a quantidade de tentativas em caso de erro, ```retries```: ```gherkin= healthcheck: test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"] timeout: 10s retries: 10 ``` --- ## GRAFANA O **Grafana** é a aplicação responsável por gerar os dashboards tendo por base os dados coletados pelo **Prometheus**. Vejamos o seu compose: ```gherkin= grafana: image: grafana/grafana:latest container_name: dockmon-grafana volumes: - ./grafana/provisioning/:/etc/grafana/provisioning/ environment: - VIRTUAL_HOST=grafana.loc - GF_SERVER_ROOT_URL=http://grafana.loc - GF_DATABASE_NAME=grafana - GF_DATABASE_USER=grafana - GF_DATABASE_PASSWORD=BYK6138t@123 - GF_DATABASE_TYPE=mysql - GF_DATABASE_HOST=db:3306 - GF_DATABASE_MAX_OPEN_CONN=300 - GF_SESSION_PROVIDER=mysql - GF_SESSION_PROVIDER_CONFIG=grafana:BYK6138t@123@tcp(db:3306)/grafana?allowNativePasswords=true - GF_SERVER_ROUTER_LOGGING=true - GF_LOG_CONSOLE_FORMAT=json - GF_LOG_FILTERS=alerting.notifier:debug,alerting.notifier.slack:debug,auth:debug - GF_AUTH_TOKEN_ROTATION_INTERVAL_MINUTES=2 - GF_SECURITY_ADMIN_USER=${ADMIN_USER:-admin} - GF_SECURITY_ADMIN_PASSWORD=${ADMIN_PASSWORD:-HKf16a123} - GF_USERS_ALLOW_SIGN_UP=false ports: - 3000:3000 depends_on: - db command: ["./grafana/valida-mysql.sh", "db:3306", "--", "python", "app.py"] ``` Tal como no contêiner do **MYSQL**, este também utiliza a declaração de variáveis do ambiente, ```environment```, para informar/detalhar quais os detalhes do *banco de dados* que serão utilizados, bem como detalhes da *sessão* e de *segurança/acesso*, sendo elas declaradas como: ```GF_DATABASE```, ```GF_SESSION```, ```GF_AUTH``` e ```GF_SECURITY```. Um outro ponto importante a ser atentado é o estabelecimento de uma dependência para a chamada/execução desse contêiner, a que ocorrerá apenas após a disponibilidade do banco, que é validada por meio de um script. ```gherkin= depends_on: - db command: ["./grafana/valida-mysql.sh", "db:3306", "--", "python", "app.py"] ``` o *script valida-mysql.sh*, em detalhe: ```gherkin= #!/bin/bash set -e set -x host="$1" shift cmd="$@" until mysql -h "$host" -u ${MYSQL_USER} -p${MYSQL_PASSWORD} ${MYSQL_DATABASE} -e 'select 1'; do >&2 echo "MySQL está indisponível - aguardando" sleep 1 done >&2 echo "Mysql está respondendo - comando executado" exec $cmd ``` De uma forma geral, o *script* faz a tentativa de se conectar a base de dados, que definimos no contêiner **MYSQL**, com os dados de usuário que informamos, e executar um *select*. Essa instrução é repetida até que seja possivel concluí-la e, para as tentativas que não forem bem sucedidas temos a saida *"MySQL está indisponível - aguardando"*, a que muda quando o *select* for efetudado, *"Mysql está respondendo - comando executado"*. Uma vez finalizado, o contêiner do *Grafana* é iniciado. --- # Configuração dos Exporters do Prometheus ## Apresentação Este documento traz a configuração padrão dos exporters do Prometheus, utilizados em produção. É mostrado onde o arquivo deve ser alocado, bem como deve ser efetuada a configuração do serviço que irá manipulá-lo. Seguiremos algumas convenções, as que serão detalhadas a seguir. ## Convenções Para garantirmos que qualquer membro da equipe possa atuar na manutenção ou configuração de novos itens no ambiente, se fez necessário adotar um padrão para a implantação de cada exporter, em produção. O primeiro ponto a ser seguido é que cada exporter, isto é, seu **arquivo binário** deve ser alocado em um diretório prório em **```/usr/local/bin```**. Para os **arquivos de configuração** de cada exporter, usaremos o seguinte file system: **```/etc/sysconfig```**. Por sua vez, os **serviços** deverão ser alocados em **```/etc/systemd/system```**. Para deixar mais fácil a compreensão, tomemos o exemplo do node exporter. ### Node Exporter O node exporter é o responsável por coletar e publicar as métricas da infraestrutura física do servidor em que está instalado, isto é, consumo de CPU, Load, consumo de Memória, etc. Abaixo estão os passos a serem seguidos para sua configuração em um servidor de produção. #### Obtendo o Exporter Faremos o download do exporter e o alocaremos em seu diretório padrão: ```gherkin= esantos@vansor235: cd Downloads && wget https://github.com/prometheus/node_exporter/releases/download/v*/node_exporter-*.*-amd64.tar.gz` esantos@vansor235: sudo mkdir /usr/local/bin/node_exporter/ esantos@vansor235: tar xvfz node_exporter-*.*-amd64.tar.gz esantos@vansor235: sudo cp node_exporter-*.*-amd64/node_exporter /usr/local/bin/node_exporter/ ``` #### Criação do Usuário O exporter deve ser executado com o seu próprio usuário, o que deve ser configurado como uma conta sem privilégios. ```gherkin= sudo useradd node_exporter -s /sbin/nologin ``` #### Criação do Serviço Para manipularmos o estado do exporter, nós devemos criar um arquivo de serviço que fará a sua gestão. Por esse motivo, criaremos o arquivo **```node_exporter.service```** em **```/etc/systemd/system/```**, com o conteúdo abaixo: ```gherkin= esantos@vansor235: nano /etc/systemd/system/node_exporter.service [Unit] Description=Node Exporter [Service] User=node_exporter EnvironmentFile=/etc/sysconfig/node_exporter/node_exporter ExecStart=/usr/local/bin/node_exporter/node_exporter $OPTIONS [Install] WantedBy=multi-user.target ``` É necessário ressaltar que, ao executarmos o serviço, tal como acima, ele cerregará as opções padrão de coletores: |Opção |Finalidade | |----- |:--------- | |diskstats |Publica as estatísticas de I/O do disco a partir de **```/proc/diskstats.```** | |filesystem |Publica as estatísticas do **```filesystem statistics```**, como o espaço de disco em uso | |loadavg |Publica a carga do load average. | |meminfo |Publica as estatísticas da memória a partir de **```/proc/meminfo```**. | |netdev |Publica as estatísticas de interface de rede a partir de **```/proc/netstat```**, como os bytes transferidos. | |netstat |Publica as estatísticas de rede a partir de **```/proc/net/netstat```**. | |stat |Publica diversas estatísticas a partir de **```/proc/stat```**, o que inclui o uso da CPU, tempo de boot, forks e interrupts. | |textfile |Publica estatísticas lidas a partir do disco local. A flag **```--collector.textfile.directory```** precisa ser configurada. | |time |Publica o tempo atual do sistema. | Contudo, é uma boa prática usar o arquivo de configuração, referenciado na opção ```EnvironmentFile``` para aplicarmos as opções específicas que queremos para a execução. Sendo assim, podemos criar o arquivo **```node_exporter```** em **```/etc/sysconfig/node_exporter```**: ```gherkin= esantos@vansor235: sudo mkdir /etc/sysconfig/node_exporter/ esantos@vansor235: nano /etc/sysconfig/node_exporter/node_exporter OPTIONS="--collector.textfile.directory /var/lib/node_exporter/textfile_collector" # Acima temos um exemplo das opções que podemos usar. Para verificar as demais, utilize o comando /usr/local/bin/node_exporter --help. ``` #### Colocando cada coisa em seu lugar - [x] Download do Exporter - [x] Criação do Diretório do Exporter - [x] Criação do Usuário - [x] Criação do Serviço - [x] Criação do Diretório de Configuração - [x] Criação do Arquivo de Configuração - [x] Alteração da Permissão dos Diretórios Agora que fizemos a maior parte da configuração, devemos nos atentar em atribuir a propriedade/permissão do usuário **`node_exporter`** aos diretórios e ao arquivo de seu serviço: ```gherkin= esantos@vansor235: sudo chown -R node_exporter:node_exporter /usr/local/bin/node_exporter/ esantos@vansor235: sudo chown -R node_exporter:node_exporter /etc/sysconfig/node_exporter/ esantos@vansor235: sudo chown node_exporter:node_exporter /etc/systemd/system/node_exporter.service ``` Feito isso, devemos recarregar o `daemon` do `systemctl` e habilitarmos o serviço que criamos: ```gherkin= esantos@vansor235: sudo systemctl daemon-reload esantos@vansor235: sudo systemctl enable node_exporter ``` O serviço será manipulado com as opções **start**, **stop** e **restart**. #### Testando a Configuração Vamos iniciar o node e verificar se ele está operando corretamente: ```gherkin= esantos@vansor235: sudo systemctl start node_exporter esantos@vansor235: curl http://localhost:9100/metrics # HELP go_gc_duration_seconds A summary of the GC invocation durations. # TYPE go_gc_duration_seconds summary go_gc_duration_seconds{quantile="0"} 3.8996e-05 go_gc_duration_seconds{quantile="0.25"} 4.5926e-05 go_gc_duration_seconds{quantile="0.5"} 5.846e-05 ``` Como vimos, a coleta e a publicação estão ocorrendo sem falhas, e as métricas podem ser acessadas via navegador, pelo mesmo endereço e porta acima. #### Configurando a Coleta da Métricas no Prometheus Vamos editar o arquivo **prometheus.yml** adicionando o conteúdo abaixo: ```gherkin= esantos@vansor235: cd projetos/prometheus esantos@vansor235: nano prometheus.yml - job_name: 'node_exporter' scrape_interval: 5s static_configs: - targets: ['IP DA MÁQUINA:9100'] ``` Depois de salvar o arquivo será necessário reiniciar o conteiner do **Prometheus**, para que ele seja carregado com as novas configurações. Após isso, poderemos já observar a coleta, na interface da aplicação. ![](https://i.imgur.com/Yrc6cZv.png) #### Conclusão Estes passos que seguimos, bem como a estrutura de hierarquia de arquivos que utilizamos são os mesmos que devem ser seguidos para todos os demais exporters que venham a ser configurados. Isso auxiliará na configuração e sustentação do ambiente, por meio de qualquer membro da equipe. :+1: ---