How to: een EFK-stack implementeren in Kubernetes met xpack-beveiliging
In deze Kubernetes-tutorial leer je hoe je best een EFK-stack instelt op Kubernetes met xpack-beveiligingsfunctie, ingeschakeld voor logstreaming, loganalyse en logmonitoring.
Wanneer meerdere applicaties en services op een Kubernetes-cluster worden uitgevoerd, is het logischer om al je Kubernetes Cluster-logboeken naar één gecentraliseerde logboekinfrastructuur te streamen voor eenvoudige logboekanalyse. Dit kan jou helpen om snel de grote hoeveelheid loggegevens die door je pods worden geproduceerd, te doorzoeken en te analyseren. Door de xpack-beveiligingsfunctie in te schakelen, kan je het volgende maken en beheren: gebruikers, rollen, weergaven, .... . Dit geeft de mogelijkheid om bepaalde toestemming te geven om een ​​subset van applicatielogboeken (indexen) te bekijken, te bewerken, aan te maken, ....
Een populaire gecentraliseerde oplossing voor logboekregistratie is de Elasticsearch-, Fluentd- en Kibana-stack (EFK).
Wat doet elk onderdeel?
- Elasticsearch: vangt binnenkomende gegevens op en slaat ze op in indexen.
- Fluentd: volgt applicaties in jouw cluster en stuurt deze rechtstreeks naar Elasticsearch.
- Kibana: maakt het mogelijk om logs te bekijken, query's uit te voeren, een eigen dashboard te maken, … vanuit Elasticsearch Indexes (data).
Elastic heeft onlangs verklaard dat beveiligingsfuncties standaard met de basislicentie worden gedistribueerd.
Elastic heeft een aantal beveiligingsfuncties gratis uitgebracht als onderdeel van de standaarddistributie (basislicentie) vanaf Elastic Stack 6.8 en 7.1. Dit nieuwe functieaanbod omvat de mogelijkheid om netwerkverkeer te versleutelen met SSL, gebruikers aan te maken en te beheren, rollen te definiëren die toegang op index- en clusterniveau beschermen en Kibana volledig te beveiligen.
1. Vereisten
Voordat we met deze handleiding kunnen beginnen, moet je ervoor zorgen dat je de volgende zaken ter beschikking hebt:
- Een Kubernetes 1.10+ cluster met op rollen gebaseerd toegangsbeheer (RBAC) ingeschakeld.
- Het kubectl-opdrachtregelprogramma dat is geïnstalleerd op uw lokale computer en is geconfigureerd om verbinding te maken met uw cluster.
- (Optioneel) SealedSecret Controller geïmplementeerd in het cluster en kubeseal geïnstalleerd op uw lokale computer.
Zodra je deze componenten hebt ingesteld, ben je klaar om met deze handleiding te beginnen. Let's go!
2. Creëren van de Namespaces
Laten we beginnen met het maken van de nodigde name spaces voor elke toepassing.
Elasticsearch Namespace:
kind: Namespace
apiVersion: v1
metadata:
name: elasticsearch
group: elasticsearch
FluentD namespace:
kind: Namespace
apiVersion: v1
metadata:
name: fluentd
group: fluentd
Kibana namespace:
kind: Namespace
apiVersion: v1
metadata:
name: fluentd
group: fluentd
Once we have created the yaml files, we can deploy the yaml files to the cluster:
Zodra we de yaml-bestanden hebben gecreëerd, kunnen we de yaml-bestanden implementeren in de cluster:
kubectl create -f elasticsearch.yaml -f kibana.yaml -f fluentd.yaml
De volgende output zou moeten verschijnen:
namespace/elasticsearch created
namespace/kibana created
namespace/fluentd created
We kunnen valideren of de namespaces succesvol zijn gemaakt door de volgende opdracht uit te voeren:
kubectl get namespaces
De volgende output zou moeten verschijnen:
NAME STATUS AGE
default Active 15d
kube-system Active 15d
elasticsearch Active 1m
kibana Active 1m
fluentd Active 1m
3. Elasticsearch Statefulset implementeren
Eerst moeten we Elasticsearch implementeren. Elasticsearch is de kerncomponent in de stack, Fluentd en Kibana kunnen niet werken zonder ElasticSearch.
Je vindt meer informatie over Elasticsearch door op deze link te klikken: https://www.elastic.co/what-is/elasticsearch
3.1 Serviceaccount maken
Laten we eerst beginnen met het maken van de RBAC-resources. We zullen de Elasticsearch ServiceAccount voldoende toestemming geven om de cluster te verkennen en naar andere Elasticsearch-knooppunten te zoeken.
apiVersion: v1
kind: ServiceAccount
metadata:
name: elasticsearch
namespace: elasticsearch
labels:
app: elasticsearch
We hebben ons ServiceAccount, nu moeten we de ClusterRole creëren en deze binden aan de elasticsearch ServiceAccount.
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: elasticsearch
labels:
k8s-app: elasticsearch
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
rules:
- apiGroups:
- ""
resources:
- "services"
- "namespaces"
- "endpoints"
verbs:
- "get"
Het binden aan de ServiceAccount.
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: elasticsearch
name: elasticsearch
labels:
k8s-app: elasticsearch
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
subjects:
- kind: ServiceAccount
name: elasticsearch
namespace: elasticsearch
apiGroup: ""
roleRef:
kind: ClusterRole
name: elasticsearch
apiGroup: ""
3.2 Headless-services creëren
Voor de volgende stap hebben we een serviceresource in het cluster nodig. We zullen een Headless Service-resource maken met de naam elasticsearch in de naamruimte elasticsearch. Wanneer we onze Elasticsearch StatefulSet koppelen aan deze Service, retourneert de Service DNS A-records (service-name.namespace.svc.cluster.local) vanaf dat punt naar Elasticsearch Pods met de app: elasticsearch label. We zullen deze DNS-records later configureren voor onze Statefulset, dus Elasticsearch zal naar deze knooppunten zoeken.
apiVersion: v1
kind: Service
metadata:
name: elasticsearch
namespace: elasticsearch
labels:
app: elasticsearch
spec:
selector:
app: elasticsearch
ports:
- name: rest
port: 9200
targetPort: 9200
- name: transport
port: 9300
targetPort: 9300
Laten we onze yaml-bestanden implementeren in het cluster:
kubectl create -f Service.yaml -f ServiceAccount.yaml -f ClusterRole.yaml -f ClusterRoleBinding.yaml
Laten we nu kijken of de elasticsearch-service met succes is geïmplementeerd:
kubectl get services -n elasticsearch
De volgende output zou moeten verschijnen:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
elasticsearch ClusterIP None <none> 9200/TCP,9300/TCP 1m
3.3 Statefulset maken
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: elasticsearch
namespace: elasticsearch
spec:
serviceName: elasticsearch
replicas: 3
updateStrategy:
type: OnDelete
selector:
matchLabels:
app: elasticsearch
template:
metadata:
labels:
app: elasticsearch
spec:
securityContext:
fsGroup: 1000
initContainers:
- name: increase-vm-max-map
image: busybox
imagePullPolicy: IfNotPresent
securityContext:
privileged: true
command: [ "sysctl", "-w", "vm.max_map_count=262144" ]
containers:
- name: elasticsearch
image: docker.elastic.co/elasticsearch/elasticsearch:8.3.2
env:
- name: node.name
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NODE_MASTER
valueFrom:
configMapKeyRef:
name: elasticsearch-config
key: NODE_MASTER
- name: NODE_DATA
valueFrom:
configMapKeyRef:
name: elasticsearch-config
key: NODE_DATA
- name: NUMBER_OF_MASTERS
valueFrom:
configMapKeyRef:
name: elasticsearch-config
key: NUMBER_OF_MASTERS
- name: NUMBER_OF_REPLICAS
valueFrom:
configMapKeyRef:
name: elasticsearch-config
key: NUMBER_OF_REPLICAS
- name: ES_JAVA_OPTS
valueFrom:
configMapKeyRef:
name: elasticsearch-config
key: ES_JAVA_OPTS
- name: ES_PORT
value: "9200"
- name: ELASTIC_PASSWORD
valueFrom:
secretKeyRef:
name: elastic-credentials
key: ELASTIC_PASSWORD
ports:
- containerPort: 9200
name: rest
protocol: TCP
- containerPort: 9300
name: transport
protocol: TCP
volumeMounts:
- name: elasticsearch-data
mountPath: /usr/share/elasticsearch/data
- name: elasticsearch-yml
mountPath: /usr/share/elasticsearch/config/elasticsearch.yml
subPath: elasticsearch.yml
resources:
requests:
cpu: "1000m"
memory: "2Gi"
limits:
cpu: "1000m"
memory: "2Gi"
volumes:
- name: elasticsearch-yml
configMap:
name: elasticsearch-config
items:
- key: elasticsearch.yml
path: elasticsearch.yml
volumeClaimTemplates:
- metadata:
name: elasticsearch-data
annotations:
volume.beta.kubernetes.io/storage-class: gp3
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 50Gi
We hebben enkele omgevingsvariabelen gedefinieerd in onze Statefulset-resources. Sommige variabelen zijn van ConfigMap en sommige van een geheim.
Secret bevat het wachtwoord van de Elasticsearch admin-gebruiker.
Voer de volgende opdracht uit om een ​​yaml-bestand te maken voor het elasticsearch-beheerderswachtwoord:
# Create SealedSecret for the admin elasticsearch password
kubectl -n elasticsearch create secret generic elastic-credentials \
--from-literal=ELASTIC_PASSWORD='STRONG-PASSWORD' \
--dry-run=client -o yaml | ${KUBESEAL_BINARY} --cert ${KUBESEAL_CERT_PATH} --format yaml > SealedSecret-ElasticCredentials.yaml
Indien je geen SealedSecret-controller hebt, kan je een geheime bron maken door de volgende opdracht uit te voeren:
# Create SealedSecret for the admin elasticsearch password
kubectl -n elasticsearch create secret generic elastic-credentials \
--from-literal=ELASTIC_PASSWORD='STRONG-PASSWORD' \
--dry-run=client -o yaml > SealedSecret-ElasticCredentials.yaml
Met de bovenstaande opdracht wordt het yaml-bestand gemaakt dat in het cluster moet worden geïmplementeerd.
3.4 ConfigMap maken
De Configmap bevat het elasticsearch.yml-blok met extra Elasticsearch-configuratie. We voegen onze Service DNS-records toe aan onze discovery.seed_hosts, Elasticsearch zoekt naar extra knooppunten.
Dit blok wordt op de pod gemount onder de locatie /usr/share/elasticsearch/config/elasticsearch.yml.
apiVersion: v1
kind: ConfigMap
metadata:
name: elasticsearch-config
namespace: elasticsearch
data:
elasticsearch.yml: |
cluster.name: "elasticsearch"
bootstrap.memory_lock: false
xpack.license.self_generated.type: basic
network.host: "0.0.0.0"
logger.org.elasticsearch.transport: error
logger.org.elasticsearch.discovery: error
discovery.seed_hosts:
- elasticsearch-0.elasticsearch.elasticsearch.svc.cluster.local:9300
- elasticsearch-1.elasticsearch.elasticsearch.svc.cluster.local:9300
- elasticsearch-2.elasticsearch.elasticsearch.svc.cluster.local:9300
cluster.initial_master_nodes:
- elasticsearch-0
- elasticsearch-1
- elasticsearch-2
NODE_MASTER: "true"
NODE_DATA: "true"
NUMBER_OF_MASTERS: "3"
NUMBER_OF_REPLICAS: "2"
Deze volumekoppeling wordt ook gedeclareerd in statefulset.yaml:
volumeMounts:
- name: elasticsearch-data
mountPath: /usr/share/elasticsearch/data
- name: elasticsearch-yml
mountPath: /usr/share/elasticsearch/config/elasticsearch.yml
subPath: elasticsearch.yml
Implementeer al je yaml-bestanden en zorg ervoor dat Elasticsearch zonder problemen werkt. Als Elasticsearch niet correct werkt, kan je de containerlogboeken volgen of de Pod/Statefulset beschrijven.
kubectl create -f ConfigMap.yaml -f Statefulset.yaml
De volgende output zou moeten verschijnen:
configmap/elasticsearch-config created
statefulset/elasticsearch created
Laten we eens kijken of de elasticsearch statefulset met succes is geïmplementeerd.
kubectl get pod -n elasticsearch
NAMESPACE NAME READY STATUS RESTARTS AGE
elasticsearch elasticsearch-0 1/1 Running 0 2m
elasticsearch elasticsearch-1 1/1 Running 0 1m
elasticsearch elasticsearch-2 1/1 Running 0 30sc
3.5 xpack functie inschakelen
3.5.1 Certificaten genereren
Elasticsearch start niet wanneer de beveiligingsfunctie is ingeschakeld zonder dat de beveiligingsconfiguratie is geconfigureerd!
Voordat we de beveiligingsfunctie kunnen inschakelen, moeten we certificaten voor ElasticSearch-knooppunten genereren. Elasticsearch-knooppunten communiceren veilig met elkaar.
Voer de volgende opdrachten uit in de elasticsearch-container.
kubectl -n elasticsearch exec -ti elasticsearch-0 -- bash
# Create certificates
elasticsearch-certutil ca --out /tmp/elastic-stack-ca.p12 --pass ''
elasticsearch-certutil cert --name security-master --dns security-master --ca /tmp/elastic-stack-ca.p12 --pass '' --ca-pass '' --out /tmp/elastic-certificates.p12
# copy certificates to local machine
sudo kubectl cp elasticsearch/elasticsearch-0:/tmp/elastic-stack-ca.p12 ./elastic-stack-ca.p12
sudo kubectl cp elasticsearch/elasticsearch-0:/tmp/elastic-certificates.p12 ./elastic-certificates.p12
# Validate and extract PEM
openssl pkcs12 -nodes -passin pass:'' -in elastic-certificates.p12 -out elastic-certificate.pem
Zodra we ons certificaat hebben gegenereerd en gekopieerd van de container naar onze lokale machine, maken we een SealedSecret van het PEM-bestand. We zullen dit PEM-bestand later aan de container koppelen.
# Create SealedSecret for the P12 file
kubectl -n elasticsearch create secret generic elastic-certificate-pem \
--from-file=elastic-certificates.p12 \
--dry-run=client -o yaml | ${KUBESEAL_BINARY} --cert ${KUBESEAL_CERT_PATH} --format yaml > SealedSecret-ElasticCertificates.yaml
Indien je geen SealedSecret-controller hebt, kan je een geheime bron maken door de volgende opdracht uit te voeren.
# Create SealedSecret for the P12 file
kubectl -n elasticsearch create secret generic elastic-certificate-pem \
--from-file=elastic-certificates.p12 \
--dry-run=client -o yaml > SealedSecret-ElasticCertificates.yaml
Met de bovenstaande opdracht wordt het yaml-bestand gemaakt dat in het cluster moet worden geïmplementeerd.
3.5.2 beveiligingsfuncties van xpack inschakelen
Wanneer je het certificaat met succes hebt ontwikkeld en geïmplementeerd in het cluster, kunnen we nu beveiligingsfuncties inschakelen.
Voeg de volgende configuratie toe aan de elasticsearch.yml-configuratie in het bestand ConfigMap.yaml:
xpack.license.self_generated.type: basic
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
xpack.security.http.ssl.enabled: false
xpack.security.http.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
xpack.security.http.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
Zodra je xpack.security.enabled instelt op true, worden xpack-beveiligingsfuncties ingeschakeld. Maar alleen deze instelling inschakelen is niet voldoende. We moeten ook onze nieuw gegenereerde certificaten koppelen en configureren.
Koppel het geheim dat de certificaten bevat aan de StatefulSet:
volumeMounts:
- name: elasticsearch-data
mountPath: /usr/share/elasticsearch/data
- name: elasticsearch-yml
mountPath: /usr/share/elasticsearch/config/elasticsearch.yml
subPath: elasticsearch.yml
- name: elastic-certificates
mountPath: /usr/share/elasticsearch/config/certs
.....
.....
volumes:
- name: elasticsearch-yml
configMap:
name: elasticsearch-config
items:
- key: elasticsearch.yml
path: elasticsearch.yml
- name: elastic-certificates
secret:
secretName: elastic-certificates
Bewaar en vervang de ConfigMap en Statefulset. Wacht tot alle pods zijn beëindigd en opnieuw zijn gestart. Indien de pods niet automatisch opnieuw worden opgestart, schaal de statefulset omlaag en schaal deze daarna weer omhoog:
kubectl -n elasticsearch scale statefulset elasticsearch --replicas 0
#wait till all nodes are deleted
kubectl -n elasticsearch scale statefulset elasticsearch --replicas 3
Tail logs en zorg ervoor dat Elasticsearch goed werkt. Als Elasticsearch niet correct werkt, kan je de containerlogboeken volgen of de Pod/Statefulset beschrijven.
Uw bestand ConfigMap.yaml en Statefulset.yaml zou er als volgt uit moeten zien.
3.5.3 Statefulset
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: elasticsearch
namespace: elasticsearch
spec:
serviceName: elasticsearch
replicas: 3
updateStrategy:
type: OnDelete
selector:
matchLabels:
app: elasticsearch
template:
metadata:
labels:
app: elasticsearch
spec:
securityContext:
fsGroup: 1000
initContainers:
- name: increase-vm-max-map
image: busybox
imagePullPolicy: IfNotPresent
securityContext:
privileged: true
command: [ "sysctl", "-w", "vm.max_map_count=262144" ]
containers:
- name: elasticsearch
image: "defined_in_kustomization"
env:
- name: node.name
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NODE_MASTER
valueFrom:
configMapKeyRef:
name: elasticsearch-config
key: NODE_MASTER
- name: NODE_DATA
valueFrom:
configMapKeyRef:
name: elasticsearch-config
key: NODE_DATA
- name: NUMBER_OF_MASTERS
valueFrom:
configMapKeyRef:
name: elasticsearch-config
key: NUMBER_OF_MASTERS
- name: NUMBER_OF_REPLICAS
valueFrom:
configMapKeyRef:
name: elasticsearch-config
key: NUMBER_OF_REPLICAS
- name: ES_JAVA_OPTS
valueFrom:
configMapKeyRef:
name: elasticsearch-config
key: ES_JAVA_OPTS
- name: ES_PORT
value: "9200"
- name: ELASTIC_PASSWORD
valueFrom:
secretKeyRef:
name: elastic-credentials
key: ELASTIC_PASSWORD
ports:
- containerPort: 9200
name: rest
protocol: TCP
- containerPort: 9300
name: transport
protocol: TCP
volumeMounts:
- name: elasticsearch-data
mountPath: /usr/share/elasticsearch/data
- name: elasticsearch-yml
mountPath: /usr/share/elasticsearch/config/elasticsearch.yml
subPath: elasticsearch.yml
- name: elastic-certificates
mountPath: /usr/share/elasticsearch/config/certs
resources:
requests:
cpu: "1000m"
memory: "2Gi"
limits:
cpu: "1000m"
memory: "2Gi"
volumes:
- name: elasticsearch-yml
configMap:
name: elasticsearch-config
items:
- key: elasticsearch.yml
path: elasticsearch.yml
- name: elastic-certificates
secret:
secretName: elastic-certificates
volumeClaimTemplates:
- metadata:
name: elasticsearch-data
annotations:
volume.beta.kubernetes.io/storage-class: gp3
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 50Gi
3.5.3.1 Readinessprobe
Als je de readinessprobe wil toevoegen, voeg het volgende toe aan je Statefulset.yaml:
readinessProbe:
exec:
command:
- /bin/bash
- -c
- |-
health=$(curl -s -o /dev/null -u elastic:${ELASTIC_PASSWORD} --write-out "%{http_code}" localhost:9200/_cluster/health?local=true)
if [[ ${health} -ne 200 ]]; then exit 1; fi
initialDelaySeconds: 5
3.5.4 Configmap
apiVersion: v1
kind: ConfigMap
metadata:
name: elasticsearch-config
namespace: elasticsearch
data:
elasticsearch.yml: |
cluster.name: "elasticsearch"
bootstrap.memory_lock: false
xpack.license.self_generated.type: basic
xpack.monitoring.collection.enabled: true
xpack.security.http.ssl.enabled: false
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
xpack.security.http.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
xpack.security.http.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
network.host: "0.0.0.0"
logger.org.elasticsearch.transport: error
logger.org.elasticsearch.discovery: error
discovery.seed_hosts:
- elasticsearch-0.elasticsearch.elasticsearch.svc.cluster.local:9300
- elasticsearch-1.elasticsearch.elasticsearch.svc.cluster.local:9300
- elasticsearch-2.elasticsearch.elasticsearch.svc.cluster.local:9300
cluster.initial_master_nodes:
- elasticsearch-0
- elasticsearch-1
- elasticsearch-2
NODE_MASTER: "true"
NODE_DATA: "true"
NUMBER_OF_MASTERS: "3"
NUMBER_OF_REPLICAS: "2"
ES_JAVA_OPTS: "-Djava.net.preferIPv4Stack=true -Xms1750m -Xmx1750m"
4. Fluentd DaemonSet inzetten
Nu is het tijd om containerlogboeken naar Elasticsearch te sturen. We hebben onze FluentD-naamruimte al gemaakt.
Je vindt meer informatie over FluentD door op de volgende link te klikken: https://www.fluentd.org/
4.1 ServiceAccount aanmaken
Laten we opnieuw beginnen met het maken van de RBAC-resources. We zullen de FluentD ServiceAccount voldoende toestemming geven om de cluster- en staartcontainerlogboeken te verkennen.
apiVersion: v1
kind: ServiceAccount
metadata:
name: fluentd
namespace: fluentd
labels:
app: fluentd
Vervolgens ClusterRole en bind het aan de vloeiende ServiceAccount.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: fluentd
labels:
app: fluentd
rules:
- apiGroups:
- ""
resources:
- pods
- namespaces
verbs:
- get
- list
- watch
Bind het nu aan het serviceaccount.
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: fluentd
roleRef:
kind: ClusterRole
name: fluentd
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: fluentd
namespace: fluentd
4.2 ConfigMap maken
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
namespace: fluentd
labels:
app: fluentd
spec:
selector:
matchLabels:
app: fluentd
template:
metadata:
labels:
app: fluentd
spec:
serviceAccountName: fluentd
containers:
- name: fluentd
image: "defined_in_kustomization"
env:
- name: FLUENT_ELASTICSEARCH_HOST
valueFrom:
configMapKeyRef:
name: fluentd-config
key: FLUENT_ELASTICSEARCH_HOST
- name: FLUENT_ELASTICSEARCH_PORT
value: "9200"
- name: FLUENT_ELASTICSEARCH_SCHEME
value: "http"
- name: FLUENTD_SYSTEMD_CONF
value: disable
- name: K8S_NODE_NAME
valueFrom:
configMapKeyRef:
name: fluentd-config
key: K8S_NODE_NAME
- name: FLUENT_ELASTICSEARCH_USER
valueFrom:
configMapKeyRef:
name: fluentd-config
key: FLUENT_ELASTICSEARCH_USER
- name: FLUENT_ELASTICSEARCH_PASSWORD
valueFrom:
secretKeyRef:
name: fluentd-credentials
key: FLUENT_ELASTICSEARCH_PASSWORD
resources:
limits:
memory: 512Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
- name: fluentd-config
mountPath: /fluentd/etc
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
- name: fluentd-config
configMap:
name: fluentd-config
items:
- key: fluent.conf
path: fluent.conf
4.3 DaemonSet maken
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
namespace: fluentd
labels:
app: fluentd
spec:
selector:
matchLabels:
app: fluentd
template:
metadata:
labels:
app: fluentd
spec:
serviceAccountName: fluentd
containers:
- name: fluentd
image: "defined_in_kustomization"
env:
- name: FLUENT_ELASTICSEARCH_HOST
valueFrom:
configMapKeyRef:
name: fluentd-config
key: FLUENT_ELASTICSEARCH_HOST
- name: FLUENT_ELASTICSEARCH_PORT
value: "9200"
- name: FLUENT_ELASTICSEARCH_SCHEME
value: "http"
- name: FLUENTD_SYSTEMD_CONF
value: disable
- name: K8S_NODE_NAME
valueFrom:
configMapKeyRef:
name: fluentd-config
key: K8S_NODE_NAME
- name: FLUENT_ELASTICSEARCH_USER
valueFrom:
configMapKeyRef:
name: fluentd-config
key: FLUENT_ELASTICSEARCH_USER
- name: FLUENT_ELASTICSEARCH_PASSWORD
valueFrom:
secretKeyRef:
name: fluentd-credentials
key: FLUENT_ELASTICSEARCH_PASSWORD
resources:
limits:
memory: 512Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
- name: fluentd-config
mountPath: /fluentd/etc
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
- name: fluentd-config
configMap:
name: fluentd-config
items:
- key: fluent.conf
path: fluent.conf
Het FLUENT_ELASTICSEARCH_PASSWORD is hetzelfde wachtwoord dat we hebben gedefinieerd in de Elasticsearch-configuratie (ELASTIC_PASSWORD).
Definieer de omgevingsvariabelen in het bestand ConfigMap.yaml, we definiëren ook enkele aangepaste Fluentd-configuraties. Deze configuratie wordt op de Fluentd-container gemonteerd.
Implementeer al jouw yaml-bestanden en zorg ervoor dat Fluentd zonder problemen werkt. Als Fluentd niet correct werkt, kan je de containerlogboeken volgen of de Pod/DaemonSet beschrijven.
5. Kibana-implementatie implementeren
Nu hebben we opslag (Elasticsearch) en gegevensstroom (Fluentd). Vervolgens hebben we Kibana nodig om de gegevens in te zien / te bewerken / ….
De configuratie van Kibana is bijna hetzelfde als Elasticsearch en Fluentd. We definiëren enkele omgevingsvariabelen om onze Kibana-configuratie te maken.
Hoofdzakelijk zijn deze configuraties:
- gebruikersnaam en wachtwoord van de kibana-gebruiker
- verbindingsinstellingen naar elastic search
- hetzelfde Elasticsearch-certificaat is gekoppeld
5.1 Kibana referenties maken
Gebruikersnaam en paswoord van Kibana
Wanneer we Kibana lanceren, is de eerste vraag die Kibana ons stelt: "Wat is de gebruikersnaam en het wachtwoord van de Kibana-gebruiker". De gebruikersnaam is kibana_system. Het wachtwoord kan worden opgehaald vanuit de Elasticsearch-container.
Exec naar een van de Elasticsearch-containers en voer de volgende opdracht uit:
kubectl -n elasticsearch exec -ti elasticsearch-0 -- bash
#This will generate a random string. Save the password!
./bin/elasticsearch-reset-password -u kibana_system
Maak een SealedSecret en implementeer deze met het opgegeven wachtwoord:
kubectl -n kibana create secret generic kibana-credentials \
--from-literal=ELASTICSEARCH_PASSWORD='XXXXX' \
--dry-run=client -o yaml | ${KUBESEAL_BINARY} --cert ${KUBESEAL_CERT_PATH} --format yaml > SealedSecret-KibanaCredentials.yaml
Indien je geen SealedSecret-controller hebt, kan je een geheime bron maken door de volgende opdracht uit te voeren.
kubectl -n kibana create secret generic kibana-credentials \
--from-literal=ELASTICSEARCH_PASSWORD='XXXXX' \
--dry-run=client -o yaml > SealedSecret-KibanaCredentials.yaml
Met de bovenstaande opdracht wordt het yaml-bestand gemaakt dat in het cluster moet worden geïmplementeerd.
5.2 Dienst creëren
Nu is het tijd om de serviceresource te maken. Kibana is toegankelijk via poort 5601 en gebruikt de app: kibana-label om de doelpods van de service te selecteren.
apiVersion: v1
kind: Service
metadata:
name: kibana
namespace: kibana
labels:
app: kibana
spec:
selector:
app: kibana
ports:
- name: http
port: 80
targetPort: 5601
5.3 Implementatie creëren
Zorg ervoor dat het ELASTICSEARCH_PASSWORD is gedefinieerd in de omgevingsvariabele en het juiste geheim leest.
We moeten ook een nieuw geheim maken van hetzelfde PEM-certificaat dat we bij de eerste stap hebben gegenereerd om later op de container te monteren.
# Create SealedSecret for the P12 file
kubectl -n kibana create secret generic elastic-certificate-pem \
--from-file=elastic-certificates.p12 \
--dry-run=client -o yaml | ${KUBESEAL_BINARY} --cert ${KUBESEAL_CERT_PATH} --format yaml > SealedSecret-KibanaCertificates.yaml
Indien je geen SealedSecret-controller hebt, kan je een geheime bron maken door de volgende opdracht uit te voeren.
# Create SealedSecret for the P12 file
kubectl -n kibana create secret generic elastic-certificate-pem \
--from-file=elastic-certificates.p12 \
--dry-run=client -o yaml > SealedSecret-KibanaCertificates.yaml
Met de bovenstaande opdracht wordt het yaml-bestand gemaakt dat in het cluster moet worden geïmplementeerd.
apiVersion: apps/v1
kind: Deployment
metadata:
name: kibana
namespace: kibana
labels:
app: kibana
spec:
replicas: 1
selector:
matchLabels:
app: kibana
template:
metadata:
labels:
app: kibana
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- kibana
topologyKey: kubernetes.io/hostname
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- kibana
topologyKey: topology.kubernetes.io/zone
containers:
- name: kibana
image: docker.elastic.co/kibana/kibana:8.3.2
resources:
limits:
cpu: 1000m
requests:
cpu: 100m
env:
- name: ELASTICSEARCH_HOSTS
valueFrom:
configMapKeyRef:
name: kibana-config
key: ELASTICSEARCH_HOSTS
- name: SERVER_NAME
valueFrom:
configMapKeyRef:
name: kibana-config
key: SERVER_NAME
- name: ELASTICSEARCH_USERNAME
valueFrom:
configMapKeyRef:
name: kibana-config
key: ELASTICSEARCH_USERNAME
- name: ELASTICSEARCH_PASSWORD
valueFrom:
secretKeyRef:
name: kibana-credentials
key: ELASTICSEARCH_PASSWORD
ports:
- containerPort: 5601
name: http
protocol: TCP
volumeMounts:
- name: kibana-certificates
mountPath: /usr/share/kibana/config/certs
- name: kibana-yml
mountPath: /usr/share/kibana/config/kibana.yml
subPath: kibana.yml
volumes:
- name: kibana-certificates
secret:
secretName: kibana-certificates
- name: kibana-yml
configMap:
name: kibana-config
items:
- key: kibana.yml
path: kibana.yml
5.4 ConfigMap maken
apiVersion: v1
kind: ConfigMap
metadata:
name: kibana-config
namespace: kibana
data:
kibana.yml: |
#
# ** THIS IS AN AUTO-GENERATED FILE **
#
# Default Kibana configuration for docker target
server.host: "0.0.0.0"
server.shutdownTimeout: "5s"
elasticsearch.hosts: [ "http://elasticsearch:9200" ]
monitoring.ui.container.elasticsearch.enabled: true
xpack.encryptedSavedObjects.encryptionKey: f9cd92d3834129433fb0404740b5e89c
xpack.reporting.encryptionKey: e3de4fcf3fb5e6f973ce024121ead576
xpack.security.encryptionKey: 4afebd157537e0f1b2c0b8deddff6b68
SERVER_NAME: "kibana.example.com"
ELASTICSEARCH_HOSTS: "http://elasticsearch.elasticsearch.svc.cluster.local:9200"
ELASTICSEARCH_USERNAME: "kibana_system"
Implementeer alle configuraties in de repository en volg de logboeken van Kibana.
En de installatie is klaar! 🎉
Je kan nu jouw indexen toevoegen, gebruikers configureren, rollen configureren, ... en logboeken controleren!
6. Conclusie
In deze Kubernetes-zelfstudie hebben we laten zien hoe Elasticsearch, Fluentd en Kibana (EFK Stack) op een Kubernetes-cluster kunnen worden ingesteld en geconfigureerd.
Centraliseer en maak het leven van de ontwikkelaars gemakkelijk door containerlogboeken zichtbaar te maken in één gecentraliseerde logboekinfrastructuur!
Als je deze tutorial interessant vond en in de toekomst meer informatie wil over deze onderwerpen, volg ons dan op LinkedIn!