EACH (ElasticSearch Logstash + + Kibana)

1, Profil ELK


1.1 Quel est le ELK


 ElasticSearch est un moteur de recherche distribué open source, ses caractéristiques sont les suivantes: distribution, zéro configuration, auto-découverte, l'indice auto-tranche, le mécanisme de réplication d'index, les interfaces de style reposant, plusieurs sources de données, telles que la recherche automatique de charge.


 Logstash est un outil de complètement open source, il peut recueillir votre journal, filtrer et stocker pour une utilisation ultérieure (comme la recherche).


 Kibana est également une source et des outils gratuits ouverts, LOGGUE Kibana peut fournir une analyse de l'interface Web conviviale Logstash et ElasticSearch qui peuvent vous aider à résumer, analyser et rechercher des journaux de données importantes.
 

1.2, l'application ELK


 architecture fournisseur d'électricité
 

 numéro
1, l' API est pas la même chose, comment allons - nous intégrer? - "dubbo défini par la spécification de l' API uniforme
2, l'opération aura des marques (comportement de l' utilisateur de piste) entre les sous - systèmes ---" log
3, chaque sous - système génère un journal respectif Log Consolidation --- - « logstash
. 4 , l'AOP enterré sortie asynchrone journal

 scénario spécifique 1
est déplacé par un tiers recharge prépayée

Sortie journal: chaque fois qu'un journal d'impression d'appel asynchrone

 

Distribué équilibrage de la charge:

Trop de machines peuvent recharger (pour sélectionner dynamiquement un courant relativement inactif de la machine pour effectuer cette tâche)

 

problème:

R: Mon frère, aujourd'hui pour aider à vérifier le numéro de téléphone 138 001 380 000 enregistrement de recharge (succès)

B: Attendre

Au bout de 5 minutes

 

R: Que diriez-vous

B: Attendez, laissant trois machines ne vérifiait pas fin

 

Conclusion: si nous pouvons régler tous les journaux ensemble, il n'y aurait pas un problème à une enquête

 

solution:

  1. Pouvez-vous mettre un journal sur la base de données.

Trop de données, et le journal aucun des formats de journaux standard, le programme de base de données n'est pas recommandé, et la pression est trop grande

  1. système de traitement des données en utilisant les grands journaux

Le coût est trop élevé, et l'environnement distribué de chaque règle du journal du système ne sont pas les mêmes.

 pratiques commerciales spécifiques

Log Collection: Logstash
stockage journal: ElasticSearch
journal affiche: Kibana
pour Taiwan journal du serveur n'est pas unifié, offre une variété de règles de récupération afin de faciliter l'affichage visuel

 Résumé

problème Distribué apporter: plusieurs nœuds, l'équilibrage de charge, la dispersion de journal, haute coûts d'exploitation et de maintenance (nécessite un suivi humain)


1.3 Système de gestion de journal centralisé


Une partie du courant dominant actuel système centralisé de gestion des journaux


1, simple: Rsyslog


2. Commercialisation: Splunk


3. Open Source: Scribe (FaceBook), Chukwa (Apache)


4, ELK le plus étendu (Stack élastique) (langage Java)


www.elastic.co/cn


1,4, ELK

ElasticSearch

Java

En temps réel et la recherche distribuée moteur d'analyse, il peut être utilisé pour la recherche en texte intégral , la recherche et l' analyse structurée, Lucene. Solr

Logstash

JRuby

la capacité de canal en temps réel la collecte des données moteur, comprenant un filtre d'entrée, le module de sortie, faire en général l' analyse de format de journal dans le module de filtration

Kibana

JavaScript

plate - forme ElasticSerach pour fournir l' analyse et la visualisation de la Web plate - forme . Il peut indexer ElasticSerach recherche, les données d'appel et générer une variété de dimensions tableau Figure

1,5 log


Connexion: Programme d'enregistrement de piste --- course
niveaux: erreur, INFO, DEBUG, WARN
but: trouver de l' information facile à localiser et enregistrer des informations supplémentaires pour supprimer les liens d'affaires étrangers

Filebeat Présentation
Lorsque vous avez des centaines de milliers de visage, voire des dizaines de milliers de serveurs de journaux, les machines virtuelles et conteneurs générés, s'il vous plaît adieu SSH il. Filebeat vous fournira une méthode de type léger, et pour transmettre le fichier journal de synthèse, de sorte que les choses simples ne sont pas compliquées.
Lors de la transmission des données vers ou Logstash ElasticSearch, Filebeat contrepression protocole sensible, pour prendre en compte une plus grande quantité de données. Si Logstash est occupé à traiter les données, vous pouvez laisser Filebeat savoir ralentir la vitesse de lecture. Une fois que la congestion est résolu, Filebeat sera restauré à son rythme d' origine et de continuer à courir.
Que ce soit dans un environnement, qui se cache toujours un risque d'interruption de l' application. Filebeat capable de lire et transmettre la ligne du journal, s'il y a une interruption sera de retour à la normale après tout, continue à partir de la position d' arrêt avant l'interruption.
 

2. Préparation

2.1, installez Centos7

Plus de 2G de mémoire est recommandé

2.2, la configuration de base

 Définissez l'adresse IP

vi /etc/sysconfig/network-scripts/ifcfg-eno33

service network restart

 ajouter des utilisateurs et autorisés

[root@localhost ~]# adduser elk1

[root@localhost ~]# passwd elk1

[root@localhost ~]# whereis sudoers

[root@localhost ~]# ls -l /etc/sudoers

[root@localhost ~]# chmod -v u+w /etc/sudoers

[root@localhost ~]# vi /etc/sudoers

## Allow root to run any commands anywher  
root    ALL=(ALL)       ALL  
linuxidc  ALL=(ALL)       ALL  #这个是新增的用户

[root@localhost ~]# chmod -v u-w /etc/sudoers

[root@localhost ~]# su elk1

3, ElasticSerach


3.1, l'environnement d'installation de Java
 

 extraction de paquet d'installation

[root@localhost jdk1.8]# tar -zxvf jdk-8u171-linux-x64.tar.gz

 Configuration des variables d'environnement Java

[root@localhost jdk1.8.0_171]# vi /etc/profile

Dans le fichier add

export JAVA_HOME=/home/elk1/jdk1.8/jdk1.8.0_171
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=.:$JAVA_HOME/LIB:$JRE_HOME/LIB:$CLASSPATH
export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
[root@localhost jdk1.8.0_171]# source /etc/profile
[root@localhost jdk1.8.0_171]# java -version
java version "1.8.0_171"
Java(TM) SE Runtime Environment (build 1.8.0_171-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.171-b11, mixed mode)

3.2, ElasticSerach installation autonome

[root@localhost elasticserach]# tar -zxvf elasticsearch-6.3.1.tar.gz

[root@localhost elasticserach]# cd elasticsearch-6.3.1/bin

[root@localhost bin]# ./elasticsearch

[root@localhost bin]# su elk1
[elk1@localhost bin]$ ./elasticsearch

[root@localhost bin]# chown -R elk1:elk1 /home/elk1/elasticsearch

[elk1@localhost bin]$ ./elasticsearch

[elk1@localhost config]$ vi jvm.options

[elk1@localhost bin]$ ./elasticsearch

[root@localhost jdk1.8.0_171]# curl 127.0.0.1:9200

#后台启动
[elk1@localhost bin]$ ./elasticsearch -d

#关闭程序
[elk1@localhost bin]$ ps -ef|grep elastic

[elk1@localhost bin]$ kill 10097

#设置浏览器访问
[root@localhost bin]systemctl stop firewalld
[root@localhost bin]vi config/elasticsearch.yml

Problèmes d'installation:

[1] [2] Solution

[root@localhost bin]# vi /etc/security/limits.conf

[3] Solution

[root@localhost bin]# vi /etc/sysctl.conf
[root@localhost bin]# sysctl -p

3.3, l'installation du cluster ElasticSerach

 Modifiez le fichier de configuration elasticserach.yml

vim /elasticsearch.yml
cluster.name: aubin-cluster#必须相同 
# 集群名称(不能重复)
node.name: els1(必须不同)
# 节点名称,仅仅是描述名称,用于在日志中区分(自定义)
#指定了该节点可能成为 master 节点,还可以是数据节点
	node.master: true
	node.data: true
path.data: /var/lib/elasticsearch
# 数据的默认存放路径(自定义)
path.logs: /var/log/elasticsearch 
# 日志的默认存放路径 
network.host: 192.168.0.1 
# 当前节点的IP地址 
http.port: 9200 
# 对外提供服务的端口
transport.tcp.port: 9300
#9300为集群服务的端口 
discovery.zen.ping.unicast.hosts: ["172.18.68.11", "172.18.68.12","172.18.68.13"] 
# 集群个节点IP地址,也可以使用域名,需要各节点能够解析 
discovery.zen.minimum_master_nodes: 2 
# 为了避免脑裂,集群节点数最少为 半数+1

Remarque: Les données et les données vide journaux

192.168.14.12:9200/_cat/nodes?v

3.4, installez le plug-in tête


 Télécharger la tête de prise

wget https://github.com/mobz/elasticsearch-head/archive/elasticsearch-head-master.zip

Vous pouvez également utiliser git pour télécharger l'hypothèse yum install git

unzip elasticsearch-head-master.zip

 installer Node.js

wget https://npm.taobao.org/mirrors/node/latest-v4.x/node-v4.4.7-linux-x64.tar.gz
tar -zxvf     node-v9.9.0-linux-x64.tar.gz

 Node.js pour ajouter des variables d'environnement

source /etc/profile

 test

node -v 

npm -v

 l'installation grunt (grunt est un outil de construction très pratique, vous pouvez travailler package compressé, test, exécution, etc.)

Dans ElasticSearch-tête maître

npm install -g grunt-cli

npm install
(npm install -g cnpm --registry=https://registry.npm.taobao.org)

 modifier le fichier de configuration ElasticSearch
édition ElasticSearch-6.3.1 / config / elasticsearch.yml, ajoutez ce qui suit:

http.cors.enabled: true
http.cors.allow-origin: "*"

 modifié Gruntfile.js (note '')
ouvre ElasticSearch-tête maître / Gruntfile.js, se connecter à trouver les propriétés suivantes, le nouveau nom d' hôte: '*':

connect: {
        server: {
            options: {
                hostname: '*',
                port: 9100,
                base: '.',
                keepalive: true
            }
        }
}   

 Démarrer ElasticSearch-tête

进入elasticsearch-head目录,执行命令:grunt server

 début d'arrière-plan ElasticSearch-tête

nohup grunt server &exit

 bouchon de tête fermée

ps -aux|grep head
kill 进程号

3.5, API ElasticSerach

 reste ElasticSearch api suivre le format suivant:

curl -X<REST Verb> <Node>:<Port>/<Index>/<Type>/<ID>

 Vérifiez les informations sur la version es

curl IP:9200

 Vérifiez si le cluster santé

http://IP:9200/_cat/health?v

 afficher la liste des noeuds

http://IP:9200/_cat/nodes?v

 liste tous les index et la taille de stockage

http://IP:9200/_cat/indices?v

 Création d'un index

curl -XPUT 'IP:9200/XX?pretty'

 Ajouter un type

curl -XPUT 'IP:9200/XX/external/2?pretty' -d '
{
   "gwyy": "John"
}'

 un type de mise à jour

curl -XPOST 'IP:9200/XX/external/1/_update?pretty' -d '
{
   "doc": {"name": "Jaf"}
}'

 supprimer l'index spécifié

curl -XDELETE 'IP:9200/_index?pretty'

3.6, les détails de configuration

ElasticSearch.yml l
ES configuration associée
 

# 集群的名字,以此作为是否同一集群的判断条件
cluster.name: elasticsearch
# 节点名字,以此作为集群中不同节点的区分条件
node.name: node-1
#设置当前节点既可以为主节点也可以为数据节点
node.master: true
node.data: true
# 索引分片个数,默认为5片
#index.number_of_shards: 5
# 索引副本个数,默认为1个副本
#index.number_of_replicas: 1
# 数据存储目录(多个路径用逗号分隔)
discovery.zen.ping.unicast.hosts: ["192.168.14.14","192.168.14.15"]
discovery.zen.minimum_master_nodes: 2
#数据目录
path.data: /home/elk1/elasticserach/data
# 日志目录
path.logs: /home/elk1/elasticserach/logs
# 修改一下ES的监听地址,这样别的机器才可以访问
network.host: 192.168.14.13
# 设置节点间交互的tcp端口(集群),默认是9300
transport.tcp.port: 9300
# 监听端口(默认的就好)
http.port: 9200
# 增加新的参数,这样head插件才可以访问es
http.cors.enabled: true
http.cors.allow-origin: "*"

Jvm.options l
La configuration de la machine virtuelle Java

 Log4j2.properties
configuration du journal
 

3.7, le mode Elasticserach

 Développement et production est divisé en deux modes
de manière de distinguer

以transport的地址是否绑定在localhost为标准(实际地址)
即:elasticserach.yml文件中的network.host配置

 différence de mode
(1) l'avertissement demandera vérification de la configuration lorsque vous démarrez le prochain mode de développement Exceptions
(2) dans le cadre du mode de production vérifierai de configuration d'erreur de manière rapide à exception de démarrage et de lancement
 

3.8, le fonctionnement elasticserach

 concepts de base
du document: Document Object
 Index: Index (bibliothèque)
 Type: index Type de données (tableau)
 Champ ,: champs, propriétés du document (champs)
 Interrogation DSL: Syntaxe de requête (SQL)
opérations  CRUD
 créer un document
demande:

POST /newbies/student/1
{
"name":"zhangsan",
"clazz":"0115bigdata",
"description":"we are family"
}

Retours:

{
  "_index": "newbies",
  "_type": "student",
  "_id": "1",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 2,
    "failed": 0
  },
  "_seq_no": 0,
  "_primary_term": 1
}

 obtenir le document
demande:

GET newbies/student/1

Retours:

{
  "_index": "newbies",
  "_type": "student",
  "_id": "1",
  "_version": 1,
  "found": true,
  "_source": {
    "name": "zhangsan",
    "clazz": "0115bigdata",
    "description": "we are family"
  }
}

 mettre à jour le document
demande:

POST /newbies/student/1/_update
{
"doc":{
"description":"hello world"
}
}

Retours:

{
  "_index": "newbies",
  "_type": "student",
  "_id": "1",
  "_version": 2,
  "result": "updated",
  "_shards": {
    "total": 2,
    "successful": 2,
    "failed": 0
  },
  "_seq_no": 1,
  "_primary_term": 1
}

 supprimer un document
demande:

DELETE newbies/student/1

Résultats de la requête:

{
  "_index": "newbies",
  "_type": "student",
  "_id": "1",
  "found": false
}

 Elasticserach requêtes
 chaîne de requête

GET /newbies/student/_sea'rch?q=关键字

Retours:

{
  "took": 8,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 0.2876821,
    "hits": [
      {
        "_index": "newbies",
        "_type": "student",
        "_id": "1",
        "_score": 0.2876821,
        "_source": {
          "name": "zhangsan",
          "clazz": "0115bigdata",
          "description": "we are family"
        }
      }
    ]
  }
}

 Recherche DSL

GET newbies/student/_search
{
  "query":{
    "term":{
      "name":{
          "value":"zhangsan"
        
      }
    } 
  }
}

4, Logstash

4.1, installez logstash

[root@localhost logstash]# tar -zxvf logstash-6.3.1.tar.gz
[root@localhost logstash-6.3.1]# cd config
[root@localhost config]# vi log4j_to_es.conf

input {
        file {
                path=>[""]
                type=>""
                start_position=>"beginning"
        }
}
output {
        stdout {
                codec=>rubydebug
        }
}
[root@localhost logstash-6.3.1]# ./bin/logstash -f config/log4j_to_es.conf

4,2, entrée, sortie, filtre

 entrée

input{file{path=>”/tomcat/logs/abc.log”}}

 sortie

output{stdout{codec=>rubydebug}} 

 filtre insert
 Grok
. 1, sur la base des expressions régulières fournit un modèle riche réutilisable (motif)
2, à partir de cette structure peut être le traitement des données non structurées
 La date
convertit un type de chaîne de caractères des types de champs horodatage, pour faciliter le traitement ultérieur des données
 muter
ajouter, modifier, supprimer, et d' autres domaines liés au processus de remplacement
 

4.3, le format logstash Nginx log contenu

 Création fichier nginx_logstash.conf

input {
  stdin { }
}

filter {
  grok {
    match => {
      "message" => '%{IPORHOST:remote_ip} - %{DATA:user_name} \[%{HTTPDATE:time}\] "%{WORD:request_action} %{DATA:request} HTTP/%{NUMBER:http_version}" %{NUMBER:response} %{NUMBER:bytes} "%{DATA:referrer}" "%{DATA:agent}"'
    }
  }

  date {
    match => [ "time", "dd/MMM/YYYY:HH:mm:ss Z" ]
    locale => en
  }

  geoip {
    source => "remote_ip"
    target => "geoip"
  }

  useragent {
    source => "agent"
    target => "user_agent"
  }
}

output {
stdout {
 codec => rubydebug
 }
}

 Logstash commencer l' analyse du fichier nginx
head -n 2 /home/elk1/nginx_logs|./logstash -f ../config/nginx_logstash.conf
l Résultats
 

{
         "user_name" => "-",
          "referrer" => "-",
        "@timestamp" => 2015-05-17T08:05:32.000Z,
           "request" => "/downloads/product_1",
              "time" => "17/May/2015:08:05:32 +0000",
             "geoip" => {
         "country_code3" => "NL",
             "longitude" => 4.8995,
        "continent_code" => "EU",
              "latitude" => 52.3824,
              "timezone" => "Europe/Amsterdam",
         "country_code2" => "NL",
                    "ip" => "93.180.71.3",
          "country_name" => "Netherlands",
              "location" => {
            "lat" => 52.3824,
            "lon" => 4.8995
        }
    },
          "@version" => "1",
      "http_version" => "1.1",
         "remote_ip" => "93.180.71.3",
           "message" => "93.180.71.3 - - [17/May/2015:08:05:32 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\"",
             "bytes" => "0",
        "user_agent" => {
          "minor" => "3",
             "os" => "Debian",
           "name" => "Debian APT-HTTP",
        "os_name" => "Debian",
          "build" => "",
          "major" => "1",
         "device" => "Other"
    },
             "agent" => "Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)",
              "host" => "localhost.localdomain",
          "response" => "304",
    "request_action" => "GET"
}

5, Kibana
5.1, Kibana AnSo
 

[root@localhost kibana]# tar -zxvf kibana-6.3.1-linux-x86_64.tar.gz
[root@localhost kibana]# cd kibana-6.3.1-linux-x86_64/config
[root@localhost config]# vi kibana.yml

[root@localhost bin]# ./kibana

5.2, agencement de Kibana


 dossier de configuration dans le fichier de configuration
 Kibana.yml instructions de configuration commune
 

Server.host/server.port:访问的端口号和地址(地址设置后才能被外网访问)

Elasticsearch.url:访问elasticserach的地址

5.3, Caractéristiques de Kibana

Discover:数据搜索查看
Visualize:图标制作
Dashboard:仪表盘制作
Timeline:时序数据的高级可视化分析
DevTools:开发者工具
Management:kibana相关配置

6, Filebeat和packetbeat
6.1, Filebeat


 Télécharger Filebeat
https://www.elastic.co/cn/downloads/beats/filebeat 
afficher la médiane du système: getconf LONG_BIT

2.2, Packetbeat


 Packetbeat introduction
(1) Pour en temps réel aux paquets réseau d'analyse
(2) analyser automatiquement le protocole de couche d'application (capture)
le DNS, Http, Redis, Mysql, etc.
 Packetbeat crawl elasticserach données de demande
(1) entre dans le répertoire packetbeat, créez un fichier es.yml
éditer le fichier (2) es.yml
 

packetbeat.interfaces.device: ens33#网卡

packetbeat.protocols.http:
ports: [9200]#es端口
send_request: true#抓取请求信息
include_body_for: ["application/json", "x-www-form-urlencoded"]#包含内容
output.console:
pretty: true#控制台输出

(3) Début packetbeat

sudo ./packetbeat -e -c es.yml -strict.perms=false

7, Nginx

    安装nginx
#安装依赖环境
yum install gcc-c++
yum install pcre-devel
yum install zlib zlib-devel
yum install openssl openssl-deve
#//一键安装上面四个依赖
#yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel

#解压
tar -xvf nginx-1.13.7.tar.gz

#进入nginx目录
cd /usr/local/nginx  #执行命令

./configure

#执行make命令make//执行make install命令
make
make install
//启动命令
nginx/sbin/nginx
//停止命令
nginx/sbin/nginx -s stop或者 : nginx -s quit
    //重启命令
    nginx -s reload

8, la visualisation de données réelles Demo

8.1, la description réelle

exigences:

groupe Collection requête Elasticserach

Analyse de la déclaration de requête commune, la réponse et à long

 

plan

Collecte des données: Packetbeat + logstash

Analyse des données: Kibana + ElasticSearch

 

8,2, la préparation

	Production Cluster(生产环境)
1、Elasticsearch 192.168.14.13:9200
2、Kibana 192.168.14.15:5601
	Monitoring Cluster(监控环境)
1、Elasticsearch 192.168.14.16:8200
2、Kibana 192.168.14.16:8601
	Logstash\packetbeat

8.3, combat

      Début de la collecte cluster de données

Début ES:

./elasticsearch

Modifier la configuration Kibana

./kibana    #启动

 Démarrez le cluster d'analyse de données
(1) ES commencent
ditto
(2) Démarrer logstash
 

input {
    beats {
        port => 5044
    }
}
filter {
    if "search" in [request]{
        grok {
            match => { "request" => ".*\n\{(?<query_body>.*)"}
        }
        grok {
            match => { "path" => "\/(?<index>.*)\/_search"}
        }
     if [index] {
      } else {
            mutate {
              add_field  => { "index" => "All" }
        }
      }

      mutate {
              update  => { "query_body" => "{%{query_body}"}}
      }

  #    mutate {
  #        remove_field => [ "[http][response][body]" ]
  #    }
}

output {
  #stdout{codec=>rubydebug}

  if "search" in [request]{
        elasticsearch {
        hosts => "127.0.0.1:9200"
        }
   }
}

(3) Début

./bin/logstash -f config/log4j_to_es.conf
附录:防火墙配置
1、firewalld的基本使用
启动: systemctl start firewalld
关闭: systemctl stop firewalld
查看状态: systemctl status firewalld 
开机禁用  : systemctl disable firewalld
开机启用  : systemctl enable firewalld
 
2.systemctl是CentOS7的服务管理工具中主要的工具,它融合之前service和chkconfig的功能于一体。
启动一个服务:systemctl start firewalld.service
	关闭一个服务:systemctl stop firewalld.service
	重启一个服务:systemctl restart firewalld.service
	显示一个服务的状态:systemctl status firewalld.service
	在开机时启用一个服务:systemctl enable firewalld.service
	在开机时禁用一个服务:systemctl disable firewalld.service
	查看服务是否开机启动:systemctl is-enabled firewalld.service
	查看已启动的服务列表:systemctl list-unit-files|grep enabled
	查看启动失败的服务列表:systemctl --failed
3.配置firewalld-cmd
查看版本: firewall-cmd --version
查看帮助: firewall-cmd --help
显示状态: firewall-cmd --state
查看所有打开的端口: firewall-cmd --zone=public --list-ports
更新防火墙规则: firewall-cmd --reload
查看区域信息:  firewall-cmd --get-active-zones
查看指定接口所属区域: firewall-cmd --get-zone-of-interface=eth0
拒绝所有包:firewall-cmd --panic-on
取消拒绝状态: firewall-cmd --panic-off
查看是否拒绝: firewall-cmd --query-panic
 
4.那怎么开启一个端口呢
添加
firewall-cmd --zone=public --add-port=80/tcp --permanent    (--permanent永久生效,没有此参数重启后失效)
重新载入
firewall-cmd --reload
查看
firewall-cmd --zone= public --query-port=80/tcp
删除
firewall-cmd --zone= public --remove-port=80/tcp --permanent

 

Publié 322 articles originaux · Praise gagné 46 · vues 110 000 +

Je suppose que tu aimes

Origine blog.csdn.net/qq_31784189/article/details/105206251
conseillé
Classement