Start the Lab and Tour the Interfaces

10 min
Audience
beginner, all lesson 02 prerequisites green
Duration
30 min (plus the first image download)
Module
1/7
Learning goal
start the stack, load the data, read etat, send a first query in Kibana Dev Tools and in Neo4j Browser

In One Picture

Starting the lab is like turning on the lights in a three-story building. demarrer flips the main switch, then a caretaker walks up to each floor to check that the lights are really on before handing you the keys: that caretaker is Docker Compose's healthchecks. Kibana is not even allowed to start before Elasticsearch has been declared healthy. Then importer fills Elasticsearch's shelves, charger-graphe fills Neo4j's, and etat gives you the building's floor plan: who is there, who answers, how many documents in each index. The rest of the lesson is a guided tour of the two rooms where you will spend the course: Kibana's Dev Tools console and Neo4j Browser.

How It Works

demarrer chains three docker compose steps: pull (downloads the images, ~6 GB the first time, nothing afterward), up -d (creates and launches the containers in the background), then a wait loop that queries docker inspect every 3 seconds until each container is healthy.

The word healthy comes from docker-compose.yml. Each service declares a test there that Docker replays regularly:

ServiceTest run inside the containerFrequency
elasticsearchcurl -fsS http://localhost:9200/_cluster/health must contain "status":"green" or "yellow"every 10 s, 30 attempts, 30 s grace period at startup
kibanacurl -fsS http://localhost:5601/api/status must contain "level":"available"every 10 s, 30 attempts, 40 s grace period
neo4jwget -qO- http://localhost:7474 answersevery 10 s, 30 attempts, 30 s grace period

As long as the test fails, the container is starting; when it succeeds, healthy; after 30 failures, unhealthy. The kibana service declares depends_on: elasticsearch: condition: service_healthy: Compose only launches it once Elasticsearch is healthy, which avoids the infamous "Kibana server is not ready yet" at startup.

Two details of the compose file deserve a word right now. xpack.security.enabled=false: no password or certificate for Elasticsearch; this is a local lab, never a production configuration. cluster.routing.allocation.disk.threshold_enabled=false: Elasticsearch will not switch your indexes to read-only if your disk goes over 95% (lesson 04, failure no. 5).

Step by Step

The lab kit first. Everything that follows is run from the root of the kit — https://github.com/hrhouma2/aiopsatlas-recherche-graphes-labo-fr — retrieved with git clone https://github.com/hrhouma2/aiopsatlas-recherche-graphes-labo-fr or with the Code → Download ZIP button (lesson 02, step 4). If dir (or ls) does not show docker-compose.yml, labo.sh, and labo.ps1, you are not in the right place.

All the queries of this lesson: elasticsearch/requetes/01-03-premiere-visite.txt.

  1. Start the stack. From the kit folder:

    bash
    ./labo.sh demarrer
    powershell
    .\labo.ps1 demarrer

    The script displays three blocks: == Téléchargement des images == (long the first time, silent afterward), == Démarrage == (Compose's Container labo-elasticsearch Started lines), then == Attente que chaque service soit prêt == where each line fills with dots until prêt (…s). It ends with:

    text
    Le labo est prêt.
      Kibana                 http://localhost:5601   (Dev Tools : menu ☰ → Management → Dev Tools)
      Elasticsearch          http://localhost:9200
      Neo4j Browser          http://localhost:7474   (utilisateur neo4j · mot de passe aiopsatlas2026)
    
    Étape suivante : ./labo.sh importer   puis   ./labo.sh charger-graphe

    What you should see: three prêt (elasticsearch, kibana, neo4j). Allow one to two minutes after the download. If a line shows unhealthy, exited, or délai dépassé, go straight to lesson 04.

  2. Load the Elasticsearch indexes.

    bash
    ./labo.sh importer

    The command creates each index with its mapping (files elasticsearch/mappings/*.json) then sends the data to the _bulk API. Real output, here on a lab where the indexes already existed (the command can be replayed safely):

    text
    == Import dans elasticsearch ==
    — index cours existe déjà — conservé
      ✔ données cours chargées
    — index avis existe déjà — conservé
      ✔ données avis chargées
    — index acces existe déjà — conservé
      ✔ données acces chargées
    
    index docs.count store.size
    acces      12000      1.5mb
    avis         609     74.6kb
    cours        504    183.6kb
    
    Import terminé. Attendu : cours = 504, avis = 609, acces = 12000.

    What you should see: the first time, the lines become ✔ index cours créé avec son mapping. The three counters must be exactly 504, 609, and 12000; the documents carry their own _id, so rerunning the import never creates a duplicate.

  3. Load the Neo4j graph.

    bash
    ./labo.sh charger-graphe

    The script executes neo4j/cypher/01-contraintes.cypher (uniqueness constraints and indexes) then 02-charger.cypher (LOAD CSV + MERGE for each file in neo4j/import/). It ends with the summary computed by the script's last query, MATCH (n) RETURN labels(n)[0] AS etiquette, count(*) AS noeuds ORDER BY etiquette:

    text
    etiquette, noeuds
    "Competence", 22
    "Cours", 504
    "Etudiant", 300
    "Professeur", 30
    "Ville", 16
    
    Graphe chargé. Attendu : Competence 22, Cours 504, Etudiant 300, Professeur 30, Ville 16.

    What you should see: 872 nodes in total. Everything uses MERGE, so replaying the command creates no duplicate.

  4. Read the lab status. This is the command you will type most often:

    bash
    ./labo.sh etat

    Real output (here with the OpenSearch profile active, which will not appear on your machine before module 5):

    text
    == Conteneurs ==
    NAME                         STATUS                    PORTS
    labo-elasticsearch           Up 16 minutes (healthy)   0.0.0.0:9200->9200/tcp, [::]:9200->9200/tcp
    labo-kibana                  Up 16 minutes (healthy)   0.0.0.0:5601->5601/tcp, [::]:5601->5601/tcp
    labo-neo4j                   Up 14 minutes (healthy)   0.0.0.0:7474->7474/tcp, [::]:7474->7474/tcp, 0.0.0.0:7687->7687/tcp, [::]:7687->7687/tcp
    labo-opensearch              Up 16 minutes (healthy)   0.0.0.0:9201->9200/tcp, [::]:9201->9200/tcp
    labo-opensearch-dashboards   Up 16 minutes             0.0.0.0:5602->5601/tcp, [::]:5602->5601/tcp
    
    == Services ==
      ✔ Elasticsearch : {"status":"green","number_of_nodes":1}
         index : acces 12000 avis    609 cours   504
      ✔ Kibana répond (http://localhost:5601)
      ✔ Neo4j répond — nœuds : 872
      ✔ OpenSearch : {"status":"green","number_of_nodes":1}

    What you should see: (healthy) on every container line, green for the cluster, the three index counters, and 872 nodes. Without OpenSearch, the last line says — OpenSearch non démarré (profil optionnel : ./labo.sh demarrer opensearch).

  5. Open Kibana Dev Tools. Go to http://localhost:5601. Kibana is in French (I18N_LOCALE=fr-FR). Click the menu at the top left; in the Management section, choose Outils de développement (the French translation of "Dev Tools"; the breadcrumb shows Outils de développement > Console). You land on the Console tab, Shell sub-tab: an editor on the left, the response on the right. The Effacer cette entrée (Clear this input) button empties the sample editor.

    What you should see: when you type a query, a ▶ button (« Cliquer pour envoyer la requête », Click to send request) appears at the end of the line. Shortcut: Ctrl + Enter (⌘ + Enter on Mac) sends the query under the cursor. At the bottom right of the response, Kibana displays the HTTP code and the duration, for example 200 - OK 23 ms.

  6. First query: cluster health.

    text
    GET _cluster/health
    json
    {
      "cluster_name": "labo",
      "status": "green",
      "timed_out": false,
      "number_of_nodes": 1,
      "number_of_data_nodes": 1,
      "active_primary_shards": 53,
      "active_shards": 53,
      "unassigned_shards": 0,
    
      "active_shards_percent_as_number": 100
    }

    What you should see: "status": "green". The lab indexes are created with number_of_replicas: 0, so no replica is waiting: green on a single node. The number of shards (53) includes Kibana system indexes; it may vary.

  7. Who answers, and which indexes exist?

    text
    GET /

    Response: "name": "labo-es-1", "cluster_name": "labo", "version": { "number": "9.5.3", …, "lucene_version": "10.5.1" }, "tagline": "You Know, for Search".

    text
    GET _cat/indices/cours,avis,acces?v&s=index
    text
    health status index uuid                   pri rep docs.count docs.deleted store.size pri.store.size dataset.size
    green  open   acces aii68fsfQXKyt5wqkE1mPA   1   0      12000            0      1.5mb          1.5mb        1.5mb
    green  open   avis  W9j_JrwJT4mdzpWcS5k7xg   1   0        609            0     74.6kb         74.6kb       74.6kb
    green  open   cours pmq403ZgSZWeHJY9uNw1Qw   1   0        504            0    183.6kb        183.6kb      183.6kb

    What you should see: pri 1, rep 0, and the three counters. ?v adds the header line, s=index sorts by name. Without the cours,avis,acces filter, GET _cat/indices?v also lists internal indexes whose names start with a dot (.internal.alerts-…): ignore them.

  8. The node and the counts.

    text
    GET _cat/nodes?v
    text
    ip         heap.percent ram.percent cpu load_1m load_5m load_15m node.role   master name
    172.24.0.2           39          63   2    0.43    0.38     0.64 cdfhilmrstw *      labo-es-1
    text
    GET cours/_count
    json
    { "count": 504, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 } }

    Same for GET avis/_count"count": 609 and GET acces/_count"count": 12000. What you should see: a single node, master *, and heap.percent around 40% with the compose file's -Xmx1g setting.

  9. A first document.

    text
    GET cours/_search
    json
    {
      "query": { "match_all": {} },
      "size": 1
    }

    Response (truncated):

    json
    {
      "took": 1,
      "hits": {
        "total": { "value": 504, "relation": "eq" },
        "max_score": 1,
        "hits": [
          {
            "_index": "cours",
            "_id": "C0001",
            "_score": 1,
            "_source": {
              "id": "C0001",
              "titre": "Docker expliqué simplement",
              "categorie": "DevOps", "sujet": "Docker", "niveau": "debutant",
              "prix": 129, "note_moyenne": 4.4, "nb_avis": 327,
              "professeur": { "id": "P001", "nom": "Karim Caron", "ville": "Gatineau" },
    
            }
          }
        ]
      }
    }

    What you should see: hits.total.value = 504 (all documents match match_all) but only one is returned thanks to size: 1. Dev Tools sends a GET with a body as a POST under the hood; both are accepted.

  10. Open Neo4j Browser and connect. Go to http://localhost:7474. The Connect to instance window already offers Protocol neo4j:// and Connection URL localhost:7687 (the Bolt port, not 7474). Leave Database user as neo4j, type the Password aiopsatlas2026, click Connect. What you should see: at the top, a green dot and Instance: neo4j://localhost:7687, Database: neo4j, User: neo4j. The Database information panel on the left shows Nodes (872) with the labels Competence, Cours, Etudiant, Professeur, Ville, and Relationships (3,712) with COUVRE, ENSEIGNE, HABITE, INSCRIT_A, PREREQUIS_DE. The sidebar offers Database overview, Saved Cypher, History, Cypher reference, Parameters, Settings (the interface is in English).

  11. First Cypher query. In the editor at the top (neo4j$), type then click Run (or Ctrl + Enter):

    cypher
    MATCH (c:Cours) RETURN c LIMIT 25

    What you should see: a result frame with three views Graph, Table, Raw, and on the right Results overview: Nodes (25) · Cours (25). In Graph view, 25 orange bubbles; click one of them to see its properties (id, titre, categorie, prix…). In Table view, the same 25 nodes as JSON. Module 6 teaches you to write these queries; for now, you know where to type them.

  12. And OpenSearch? The lab can also start OpenSearch 3.8.0 and OpenSearch Dashboards on ports 9201 and 5602, with ./labo.sh demarrer opensearch then ./labo.sh importer opensearch. It is an optional profile of Compose: it is not launched by default, and it requires 6 GB of memory for Docker. We activate it in module 5, to replay the same queries on both engines and compare. Nothing to do today.

If Something Goes Wrong

  • Kibana shows "Kibana server is not ready yet" right after demarrer → Kibana has started but has not yet finished connecting to Elasticsearch and creating its internal indexes. Wait 30 seconds and reload the page. If the message persists beyond two minutes, ./labo.sh journal kibana (lesson 04, failure no. 4).

  • Dev Tools answers 404 with "type": "index_not_found_exception", "reason": "no such index [cour]" → Typo in the index name (cour instead of cours). Elasticsearch does not guess; GET _cat/indices?v gives you the exact names. Variant: 400 with "no handler found for uri [/cours/_serch] and method [GET]" → this time the API name is misspelled (_serch).

  • Dev Tools answers 400 with x_content_parse_exception … was expecting double-quote to start field name → The JSON is malformed, most often an extra comma before the closing brace ("size": 1, }). The editor underlines the faulty line in red even before sending.

  • Neo4j Browser: "Connection to instance failed — The client is unauthorized due to authentication failure." (details: Neo.ClientError.Security.Unauthorized) → Wrong password. It is aiopsatlas2026 (set by NEO4J_AUTH in the compose file), not the default password neo4j. Retype it, with no trailing space.

  • etat shows Neo4j répond — nœuds : 0 → The container is running but you forgot charger-graphe. Run it; it takes about thirty seconds.

Key Takeaways

  • The startup trio: demarrer, importer, charger-graphe. The last two can be replayed without creating duplicates (explicit identifiers on the Elasticsearch side, MERGE on the Neo4j side).
  • demarrer waits for each container's healthy status; that status comes from the healthchecks in docker-compose.yml, and Kibana only starts after Elasticsearch thanks to depends_on … service_healthy.
  • etat at a glance: (healthy) everywhere, cluster green, 504 / 609 / 12000 documents, 872 nodes.
  • Kibana Dev Tools: ☰ menu → Management → Outils de développement (Dev Tools); one query = one GET path line followed by its JSON pasted underneath; Ctrl + Enter to send.
  • Neo4j Browser: http://localhost:7474, Bolt connection on localhost:7687, user neo4j, password aiopsatlas2026; results are read in Graph, Table, or Raw.

Going Further

The file 01-03-premiere-visite.txt is in the exact Dev Tools format: in the console, the Importer les requêtes (Import requests) button (icon at the top right of the editor) accepts this file and pastes it into the editor. All the files in the elasticsearch/requetes/ folder work this way; you will never have to retype a query from the course.