# wwwgmo stack ## Description Examples site with nginx, phpfpm, mysql, phpmyadmin, elasticsearch and kibana ## Build environment |**folders**|**description**| |:---|:---| |docker.sh|files to build the docker image| |docker/mariadb|env file| |docker/nginx|config file| |docker/php-fpm|files to create docker image| |src|site source| ## Docker ### Global environment variables Copy file ALL `.env.dist` to `.env` Complete or modify the values according to your needs ### Build #### Install plugin php for elasticsearch ```bash ./docker.sh install ``` #### Build image ```bash ./docker.sh build ``` or ```bash ./docker.sh build-no-cache ``` ### Start ```bash ./docker.sh start ``` #### Check ```bash docker exec wwwgmo-mariadb mysql -uroot -p mysql -e 'SELECT user,host FROM mysql.user;' ``` ```bash docker exec wwwgmo-elasticsearch curl -u elastic: http://wwwgmo-elasticsearch:9200/_cluster/health?pretty ``` ```bash docker exec wwwgmo-php-fpm curl -s -u elastic: http://wwwgmo-elasticsearch:9200/_cluster/health?pretty ``` #### Access http://: ## kubernetes |**folders**|**description**| |:---|:---| |deploy.sh|files to deploy on k8s or k3s (see ./deploy.s -h)| |helm|Chart root folder| |Chart.yaml|Charts file| |values-configs.yml|configs file use for kubernetes manifest| |values-secrets.yaml|secrets file for kubernetes manifet (Must be encrypted with sops in a production environment)| |templates/elasticsearch|manifests for elasticsearch| |templates/kibana|manifests for kibana| |templates/mariadb|manifests for mariadb| |templates/phpmyadmin|manifests for phpmyadmin| |templates/php-fpm|manifest for php-fpm| ### Secret registry (regcred) You need credential to pull an image from private registry. Create or modify the secret ```bash kubectl create secret docker-registry secret-regcred --dry-run=client \ --docker-server=https://index.docker.io/v1/ \ --docker-username= \ --docker-password= \ --docker-email= -o yaml > helm/template/secret-regcred.yaml ``` ### Certificats ```bash cat certs/gmolab.net.key | base64 -w0 ``` copy the base64 result into file `values-secrets.yaml` in ssl_key key ```bash cat certs/gmolab.net.crt | base64 -w0 ``` copy the base64 result into file `values-config.yaml` in ssl_crt key ### Docker image version In the `helm/Chart.yaml` file, the `appVersion` value must match the version of the docker image (see DOCKER_IMAGE_VERSION in the `.env` file and SITE_VERSION in the `docker/php-fpm/.env` file) ## Deployment by script This is the recommended way >This script builds the docker image based on the Kubernetes VM architecture (AMD64 or ARM64). At each deployment the minor version of the image is incremented by 1. ```bash ./deploy.md -n wwwgmo -k k3s ``` ## Manual deployment ### Set kubesystem config ```bash rm -f $HOME/.kube/config ``` for **k3s** ```bash ln -s $HOME/.kube/k3s $HOST/.kube/config ``` for **k8s** ```bash ln -s $HOST/.kube/k8s $HOST/.kube/config ``` ### Set namespace and kube system ```bash export NS=wwwgmo export KUBE_SYS=k3s|k8s ``` ### Test template ```bash helm template $NS --set kube=$KUBE_SYS ./helm --values=./helm/values-configs.yaml --values=./helm/values-secrets.yaml --namespace $NS ``` ### Chart deployment ```bash helm upgrade $NS --set kube=$KUBE_SYS ./helm --install --atomic --cleanup-on-fail --values=./helm/values-configs.yaml --values=./helm/values-secrets.yaml --namespace $NS --create-namespace ``` ## Remove ```bash helm uninstall $NS -n $NS kubectl delete namespaces $NS ``` ## NOTES ### Cronjob When we deploy manually (I do not why) you must trig manually the cronjob to make a DB backup to termine correctly the helm command ```bash kubectl create job -n $NS --from=cronjob/cronjob-mariadb-backupdb dbbackup-$(date +%Y-%m-%d-%H-%M-%S) ``` ## Database Not necessary because created during deployment. We leave the procedure below for information First export NS environment variable ```bash export NS= ``` You can use `createDBOnKube.sh` or create manually with below commands #### Create user ```bash kubectl -n $NS exec statefulset-mariadb-0 --container mariadb -- /bin/bash -c "/usr/bin/mysql -u root -p -e \"CREATE USER 'gmo_db'@'%' IDENTIFIED BY '';\"" ``` #### Check user ```bash kubectl -n $NS exec statefulset-mariadb-0 --container mariadb -- /bin/bash -c "/usr/bin/mysql -u root -p -e 'SELECT user,host FROM mysql.user;'" ``` #### Create database ```bash kubectl -n $NS exec statefulset-mariadb-0 --container mariadb -- /bin/bash -c "/usr/bin/mysql -u root -p -e \"CREATE DATABASE gmo_db;\"" ``` #### Check database ```bash kubectl -n $NS exec statefulset-mariadb-0 --container mariadb -- /bin/bash -c "/usr/bin/mysql -u root -p -e 'SHOW DATABASES;'" ``` #### Grants access ```bash kubectl -n $NS exec statefulset-mariadb-0 --container mariadb -- /bin/bash -c "/usr/bin/mysql -u root -p -e \"GRANT ALL PRIVILEGES ON gmo_db.* TO 'gmo_db'@'%';FLUSH PRIVILEGES;\"" ``` #### Check grants ```bash kubectl -n $NS exec statefulset-mariadb-0 --container mariadb -- /bin/bash -c "/usr/bin/mysql -u root -p -e \"SHOW GRANTS FOR 'gmo_db'@'%';\"" ``` ## Troubeshooting ### How to Fix "Pods stuck in Terminating status" Error ```bash kubectl get pods --all-namespaces | grep Terminating | while read line; do pod_name=$(echo $line | awk '{print $2}' ) \ name_space=$(echo $line | awk '{print $1}' ); \ kubectl delete pods $pod_name -n $name_space --grace-period=0 --force done ``` ## Sources [Elasticsearch-PHP](https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html) [Pull an Image from a Private Registry](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/) [MariaDB Statefulset](https://mariadb.org/create-statefulset-mariadb-application-in-k8s/) [PHP-FPM, nginx, kubernetes and docker](https://matthewpalmer.net/kubernetes-app-developer/articles/php-fpm-nginx-kubernetes.html) https://www.elastic.co/guide/en/elasticsearch/reference/8.18/docker.html ## Changelog ### 3.25 (2024-04-14) **New features:** * added elasticsearch and kibana * added option `install` to script `docker.sh` to install php elasticserch module * created `deploy.sh` script **Fixed bugs:** * problem with display environment var in php site **Updated:** * added new features in README.md * added Changelog part in README.md --- ### 2.5 (2024-03-29) **Fixed bugs:** * fixed somes bugs **New features:** * posibility to deploy on k3s or k8s **Updated:** * updated README.md --- ### 1.0 (2024-03-01) * Created from scratch Ignorer et passer au contenu Vous avez dit : J'ai l'erreur suivante lorsque j'exécute mon ficher docker-compose.yml: [2025-06-19T16:58:29.674+00:00][ERROR][elasticsearch-service] Unable to retrieve version information from Elasticsearch nodes. security_exception Root causes: security_exception: missing authentication credentials for REST request [/_nodes?filter_path=nodes.*.version%2Cnodes.*.http.publish_address%2Cnodes.*.ip] Mon fichier docker-compose.yml elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:8.18.2 container_name: elasticsearch environment: - node.name=es01 - cluster.name=es-docker-cluster - discovery.type=single-node - bootstrap.memory_lock=true - xpack.security.enabled=true - ELASTIC_PASSWORD=changeme - xpack.security.http.ssl.enabled=false - ES_JAVA_OPTS=-Xms1g -Xmx1g ulimits: memlock: soft: -1 hard: -1 ports: - "9200:9200" - "9300:9300" volumes: # - esdata:/usr/share/elasticsearch/data - wwwgmo-elasticsearch:/usr/share/elasticsearch/data kibana: image: docker.elastic.co/kibana/kibana:8.18.2 container_name: kibana depends_on: - elasticsearch environment: - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 - xpack.security.enabled=false ports: - "5601:5601" ChatGPT a dit : L’erreur que vous rencontrez est causée par l’activation de la sécurité dans Elasticsearch (xpack.security.enabled=true) sans fournir d’identifiants d’authentification lors de la tentative d’accès à l'API REST. 🔍 Détail de l'erreur : security_exception: missing authentication credentials for REST request [/_nodes?...] Cela signifie que Kibana ou un autre service tente de communiquer avec Elasticsearch sans credentials, alors que ce dernier requiert une authentification. ✅ Solution 1 : Aligner la sécurité entre Kibana et Elasticsearch Actuellement : Elasticsearch a xpack.security.enabled=true Kibana a xpack.security.enabled=false Ce n’est pas compatible. Kibana doit être configuré pour utiliser les identifiants quand Elasticsearch a la sécurité activée. 🛠 Modifier la section kibana comme suit : kibana: image: docker.elastic.co/kibana/kibana:8.18.2 container_name: kibana depends_on: - elasticsearch environment: - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 - ELASTICSEARCH_USERNAME=elastic - ELASTICSEARCH_PASSWORD=changeme ports: - "5601:5601" ⚠️ Important : On utilise ici ELASTICSEARCH_USERNAME=elastic et ELASTICSEARCH_PASSWORD=changeme, car vous avez défini ce mot de passe dans la variable d'environnement ELASTIC_PASSWORD côté Elasticsearch. ✅ Solution 2 : Désactiver complètement la sécurité (pour développement uniquement) Si vous êtes en environnement de test ou de développement local, vous pouvez désactiver la sécurité côté Elasticsearch. environment: - xpack.security.enabled=false Dans ce cas, gardez aussi Kibana sans sécurité : - xpack.security.enabled=false ⚠️ Pas recommandé en production : cette approche désactive les protections d’accès aux données. 🧪 Astuce : Tester si tout fonctionne Une fois les containers relancés, testez l’accès à Elasticsearch : curl -u elastic:changeme http://localhost:9200 Et pour Kibana : ouvrez http://localhost:5601 dans un navigateur. Souhaitez-vous : Garder la sécurité activée et intégrer les credentials dans tous les services ? Ou désactiver la sécurité pour un usage local plus simple ? Vous avez dit : Garder la sécurité activée et intégrer les credentials dans tous les services ChatGPT a dit : Parfait ! Si vous souhaitez garder la sécurité activée, alors il faut que tous les services clients (comme Kibana) s’authentifient auprès d’Elasticsearch. Voici comment ajuster correctement votre docker-compose.yml pour intégrer les identifiants. ✅ Fichier docker-compose.yml corrigé version: "3.8" services: elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:8.18.2 container_name: elasticsearch environment: - node.name=es01 - cluster.name=es-docker-cluster - discovery.type=single-node - bootstrap.memory_lock=true - xpack.security.enabled=true - xpack.security.http.ssl.enabled=false - ELASTIC_PASSWORD=changeme - ES_JAVA_OPTS=-Xms1g -Xmx1g ulimits: memlock: soft: -1 hard: -1 ports: - "9200:9200" - "9300:9300" volumes: - wwwgmo-elasticsearch:/usr/share/elasticsearch/data kibana: image: docker.elastic.co/kibana/kibana:8.18.2 container_name: kibana depends_on: - elasticsearch environment: - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 - ELASTICSEARCH_USERNAME=elastic - ELASTICSEARCH_PASSWORD=changeme ports: - "5601:5601" volumes: wwwgmo-elasticsearch: 🔐 Authentification à l'API Elasticsearch (test via curl) Une fois vos conteneurs démarrés, testez si l'accès avec mot de passe fonctionne : curl -u elastic:changeme http://localhost:9200 Réponse attendue : { "name": "es01", "cluster_name": "es-docker-cluster", "cluster_uuid": "...", "version": { "number": "8.18.2", ... }, "tagline": "You Know, for Search" } ✅ Accès à Kibana Ouvrez http://localhost:5601 dans votre navigateur. Kibana devrait démarrer sans vous afficher d'erreur liée à la connexion Elasticsearch. ✅ Recommandation de sécurité (optionnelle) Pour un environnement plus sûr : Créez un nouvel utilisateur avec des permissions spécifiques pour Kibana, via l’API ou l’interface d’admin de Kibana. Évitez d'utiliser elastic en production, car c’est un super admin. Souhaitez-vous un exemple de script pour créer un utilisateur avec rôle personnalisé ? Vous avez dit : Error: [config validation of [elasticsearch].username]: value of "elastic" is forbidden. This is a superuser account that cannot write to system indices that Kibana needs to function. Use a service account token instead. Learn more: https://www.elastic.co/guide/en/elasticsearch/reference/8.0/service-accounts.html at ensureValidConfiguration (/usr/share/kibana/node_modules/@kbn/core-config-server-internal/src/ensure_valid_configuration.js:44:11) at Server.preboot (/usr/share/kibana/node_modules/@kbn/core-root-server-internal/src/server.js:181:7) at Root.preboot (/usr/share/kibana/node_modules/@kbn/core-root-server-internal/src/root/index.js:48:14) at bootstrap (/usr/share/kibana/node_modules/@kbn/core-root-server-internal/src/bootstrap.js:96:29) at Command. (/usr/share/kibana/src/cli/serve/serve.js:235:5) ChatGPT a dit : Merci pour ce message d’erreur très clair — Kibana refuse catégoriquement d'utiliser l'utilisateur elastic à partir d'Elasticsearch 8, car : ❌ elastic est un super-utilisateur. Il ne peut pas être utilisé pour que Kibana écrive dans les indices système, ce qui est nécessaire pour qu'il fonctionne correctement. ✅ Solution recommandée : utiliser un service account token 🔐 Étapes pour créer un Service Account Token pour Kibana : Lancer Elasticsearch avec sécurité activée Gardez xpack.security.enabled=true Assurez-vous que le conteneur Elasticsearch fonctionne Créer un Service Account Token pour Kibana Ouvrez un terminal et exécutez : docker exec -it elasticsearch \ bin/elasticsearch-service-tokens create kibana kibana-token Cela génère un token dans ce format : AAEAAWVsYXN0aWMvY2liYW5hL2tpYmFuYS10b2tlbjoxR3VOSVZzUjZsb3pk... Mettre à jour votre docker-compose.yml pour Kibana Supprimez ELASTICSEARCH_USERNAME et ELASTICSEARCH_PASSWORD, et utilisez ELASTICSEARCH_SERVICEACCOUNTTOKEN à la place : kibana: image: docker.elastic.co/kibana/kibana:8.18.2 container_name: kibana depends_on: - elasticsearch environment: - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 - ELASTICSEARCH_SERVICEACCOUNTTOKEN=AAEAAWVsYXN0aWMvY2liYW5hL2tpYmFuYS10b2tlbjoxR3VOSVZzUjZsb3pk... ports: - "5601:5601" (remplace le token par celui généré précédemment) 🔄 Ensuite : Redémarre les services : docker-compose down docker-compose up -d Va sur http://localhost:5601 pour voir Kibana se connecter correctement. 🔎 Besoin d'aller plus loin ? Si tu préfères créer un utilisateur dédié à Kibana au lieu d’un token de service, je peux aussi te guider pas à pas avec elasticsearch-users ou via l'API REST. Souhaites-tu cette alternative ? Vous avez dit : oui ChatGPT a dit : Parfait ! Voici comment créer un utilisateur dédié à Kibana, via l'API REST d'Elasticsearch, avec des rôles appropriés pour permettre à Kibana de fonctionner sans utiliser le super-utilisateur elastic. 🎯 Objectif Créer un utilisateur, par exemple kibana_system_user, qui a le rôle kibana_system (prérequis minimum pour que Kibana fonctionne). ✅ Étapes détaillées 1. 🔐 Authentifiez-vous avec le super-utilisateur elastic Exécute cette commande pour vérifier que tu peux parler à Elasticsearch : curl -u elastic:changeme http://localhost:9200 2. 👤 Créer un nouvel utilisateur kibana_system_user curl -X POST http://localhost:9200/_security/user/kibana_system_user \ -u elastic:changeme \ -H "Content-Type: application/json" \ -d '{ "password" : "kibanapassword", "roles" : [ "kibana_system" ], "full_name" : "Kibana System User", "email" : "kibana@example.com" }' ⚠️ Le mot de passe ici est kibanapassword. Tu peux le changer selon tes préférences. 3. 🔧 Modifier docker-compose.yml pour Kibana Mets à jour la section Kibana avec ces variables d’environnement : kibana: image: docker.elastic.co/kibana/kibana:8.18.2 container_name: kibana depends_on: - elasticsearch environment: - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 - ELASTICSEARCH_USERNAME=kibana_system_user - ELASTICSEARCH_PASSWORD=kibanapassword ports: - "5601:5601" 4. 🔄 Redémarre les services docker-compose down docker-compose up -d 5. ✅ Accès à Kibana Rends-toi sur http://localhost:5601. Kibana devrait démarrer sans erreur de permission, car il utilise désormais un utilisateur restreint, mais autorisé à accéder aux indices système nécessaires. ✅ Résumé Élément Valeur Utilisateur Elasticsearch kibana_system_user Rôle attribué kibana_system Mot de passe kibanapassword (ou autre) Avantage Bonne pratique, sécurisé Souhaites-tu aussi créer un utilisateur pour ingester des données dans Elasticsearch via une application ? Vous avez dit : et tout ca dans un fichier docker-compose ChatGPT a dit : Parfait, je vais t’aider à tout intégrer dans un seul docker-compose.yml, avec : Elasticsearch sécurisé Création automatique de l’utilisateur kibana_system_user avec le rôle kibana_system Kibana configuré pour utiliser cet utilisateur ⚠️ Important : Elasticsearch ne permet pas nativement la création d'utilisateurs via le docker-compose.yml, donc on doit ajouter un script d'initialisation personnalisé monté dans le conteneur, qui s'exécute au démarrage. ✅ Structure du projet recommandée : project/ ├── docker-compose.yml ├── elasticsearch/ │ └── create_kibana_user.sh 🔧 elasticsearch/create_kibana_user.sh (script d'init) #!/bin/bash # Attendre qu'Elasticsearch soit démarré echo "⏳ Attente du démarrage d'Elasticsearch..." until curl -u elastic:changeme -s http://localhost:9200 >/dev/null; do sleep 2 done echo "✅ Elasticsearch est prêt. Création de l'utilisateur Kibana..." # Créer un utilisateur pour Kibana curl -X POST http://localhost:9200/_security/user/kibana_system_user \ -u elastic:changeme \ -H "Content-Type: application/json" \ -d '{ "password" : "kibanapassword", "roles" : [ "kibana_system" ], "full_name" : "Kibana System User" }' echo "✅ Utilisateur Kibana créé avec succès." Donne les permissions au script : chmod +x elasticsearch/create_kibana_user.sh 📦 docker-compose.yml complet version: "3.8" services: elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:8.18.2 container_name: elasticsearch environment: - node.name=es01 - cluster.name=es-docker-cluster - discovery.type=single-node - bootstrap.memory_lock=true - xpack.security.enabled=true - xpack.security.http.ssl.enabled=false - ELASTIC_PASSWORD=changeme - ES_JAVA_OPTS=-Xms1g -Xmx1g ulimits: memlock: soft: -1 hard: -1 ports: - "9200:9200" - "9300:9300" volumes: - wwwgmo-elasticsearch:/usr/share/elasticsearch/data - ./elasticsearch/create_kibana_user.sh:/usr/local/bin/create_kibana_user.sh command: > bash -c " /bin/tini -g -- /usr/local/bin/docker-entrypoint.sh & pid=$!; sleep 20; bash /usr/local/bin/create_kibana_user.sh; wait $pid " kibana: image: docker.elastic.co/kibana/kibana:8.18.2 container_name: kibana depends_on: - elasticsearch environment: - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 - ELASTICSEARCH_USERNAME=kibana_system_user - ELASTICSEARCH_PASSWORD=kibanapassword ports: - "5601:5601" volumes: wwwgmo-elasticsearch: ✅ Lancer le tout Dans ton terminal : docker-compose down -v docker-compose up --build ✅ Résultat attendu Elasticsearch démarre avec la sécurité activée Un script crée automatiquement un utilisateur kibana_system_user Kibana l'utilise pour se connecter Tout est prêt et fonctionnel sans intervention manuelle Souhaites-tu que je t’aide à ajouter aussi un utilisateur applicatif (ex: my_app_user) avec accès en lecture/écriture ? Joindre Rechercher Voix ChatGPT peut faire des erreurs. Envisagez de vérifier les informations importantes.