Elasticsearch - Comment copier un index sur une autre instance ?

Contexte

Nous avons deux instances Elasticsearch distinctes (qui ne sont pas dans le même cluster). Le but est de regarder ensemble les solutions qui existent pour copier un index d’une instance à l’autre.

comment copier in index entre deux instance elasticsearch

Nous allons utiliser l’outil curl pour interagir avec elasticsearch. Comme cela est fortement conseillé depuis longtemps et par défaut maintenant, les accès sont sécurisés et protégés par un certificat SSL. Je suis resté avec le certificat auto-généré par défaut. C’est pourquoi j’ajoute l’option --insecure au niveau de la commande curl

curl --request GET \
  --insecure    \
  --url https://ADR_IP_INSTANCE_A:9200/ \
  --header 'Authorization: Basic ZWxhc3RpYzo0ZFpQUFlTRExaSWpOQmFQUGZVUw=='

Voici le résultat :

{
	"name": "localhost",
	"cluster_name": "elasticsearch",
	"cluster_uuid": "xJqE_y6GS2OuWNaNpSrn3A",
	"version": {
		"number": "8.9.0",
		"build_flavor": "default",
		"build_type": "tar",
		"build_hash": "8aa461beb06aa0417a231c345a1b8c38fb498a0d",
		"build_date": "2023-07-19T14:43:58.555259655Z",
		"build_snapshot": false,
		"lucene_version": "9.7.0",
		"minimum_wire_compatibility_version": "7.17.0",
		"minimum_index_compatibility_version": "7.0.0"
	},
	"tagline": "You Know, for Search"
}

Utilisation de la réindexation

La première possibilité est de passer par une demande de réindexation de l’instance B depuis un index hébergé sur l’instance A.

avertissement Pré-requis : l’instance A doit être accessible via le réseau pour l’instance B.

Il est nécessaire d’ajouter l’instance A dans la liste blanche comme source pour la réindexation au niveau de l’instance B.

Pour cela, il faut modifier le fichier elasticsearch.yml de l’instance B pour rajouter la ligne suivante :

....
reindex.remote.whitelist: [ADR_IP_INSTANCE_A:9200]

Il sera nécessaire de redémarrer l’instance afin que la configuration soit prise en compte.

Maintenant, il reste plus qu’à lancer la commande pour démarrer la réindexation sur l’instance B.

Cela se fait avec une simple commande curl (ou équivalent permettant d’utiliser la méthode POST)

curl --request POST --insecure \
  --url httsp://ADR_IP_INSTANCE_B:9200/_reindex \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Basic CHAINE_ENCODE_A_RENSEIGNER_ICI' \
  --data '{
  "source": {
    "remote": {
      "host": "https://ADR_IP_INSTANCE_A:9200",
      "username": "elastic",
      "password": "MOT_A_PASSE_A_RENSEIGNER_ICI"
    },
    "index": "mon-index",
    "query": {
      "match_all": {}
    }
  },
  "dest": {
    "index": "mon-index"
  }
}'

Si tout se passe bien, vous obtenez le résultat suivant :

{
	"took": 294,
	"timed_out": false,
	"total": 1,
	"updated": 0,
	"created": 1,
	"deleted": 0,
	"batches": 1,
	"version_conflicts": 0,
	"noops": 0,
	"retries": {
		"bulk": 0,
		"search": 0
	},
	"throttled_millis": 0,
	"requests_per_second": -1.0,
	"throttled_until_millis": 0,
	"failures": []
}

astuce Vous pouvez utiliser la commande _stats pour surveiller la réindexation

Exemple avec curl :

curl --insecure --header 'Authorization: Basic CHAINE_ENCODE_A_RENSEIGNER_ICI' \
     --url https://ADR_IP:9200/mon-index/_stats

astuce Consulter la documentation de l’Api REINDEX d’elasticsearch. Cette dernière est très riche.

Utilisation de la sauvegarde et restauration

La sauvegarde

La première étape est de définir un dépôt de sauvegarde (backup) au niveau de l’instance A. Pour cela, nous modifions le fichier elasticsearch.yml et rajouter la ligne suivante

path.repo: /datas/es-a/repo

avertissement Pré-requis : le répertoire /datas/es-a/repo devra exister avant le redémarrage.

Un redémarrage de l’instance A est nécessaire afin que la nouvelle configuration soit prise en compte.

A partir de ce moment, nous allons pouvoir passer à la seconde étape en définissant le répertoire pour la sauvegarde grâce à la commande curl suivante :

curl --request POST \
  --insecure --header 'Authorization: Basic CHAINE_ENCODE_A_RENSEIGNER_ICI==' \
  --url https://ADR_IP_INSTANCE_A:9200/_snapshot/backups \
  --header 'Content-Type: application/json' \
  --data '{
  "type": "fs",
  "settings": {
    "location": "/datas/es-a/repo/backups"
  }
}'

Nous obtenons la réponse suivante :

{
	"acknowledged": true
}

Maintenant, nous allons pouvoir lancer la sauvegarde.

curl --request POST \
  --insecure --header 'Authorization: Basic CHAINE_ENCODE_A_RENSEIGNER_ICI' \
  --url https://localhost:9200/_snapshot/backups/backup_20230730?wait_for_completion=true

astuce L’ajout du paramètre wait_for_completion permet d’attendre que l’opération soit terminée. Ainsi quand la commande nous rend la main, la sauvegarde est faite.

avertissement Inversement, il est préférable d’utiliser cette option si la sauvegarde s’exécute dans un temps raisonnable.

Voici le résultat (mon index mon-index est très petit)

{
	"snapshot": {
		"snapshot": "backup_20230730",
		"uuid": "xXYjHpcDRHmRXlN9ey3XXA",
		"repository": "backups",
		"version_id": 8090099,
		"version": "8.9.0",
		"indices": [
			"mon-index",
			".security-7"
		],
		"data_streams": [],
		"include_global_state": true,
		"state": "SUCCESS",
		"start_time": "2023-07-30T11:56:49.099Z",
		"start_time_in_millis": 1691150209099,
		"end_time": "2023-07-30T11:56:49.299Z",
		"end_time_in_millis": 1691150209299,
		"duration_in_millis": 200,
		"failures": [],
		"shards": {
			"total": 2,
			"failed": 0,
			"successful": 2
		},
		"feature_states": [
			{
				"feature_name": "security",
				"indices": [
					".security-7"
				]
			}
		]
	}
}

Nous allons pouvoir créer l’archive. Pour cela, nous allons nous déplacer dans le répertoire où se trouve la sauvegarde. Dans notre cas, c’est le répertoire /datas/es-a/repo/backups/backup_20230730, puis de créer l’archive avec la commande tar en incluant toue le contenu du répertoire

cd /datas/es-a/repo/backups/backup_20230730
tar czvf ../backups-20230730.tar.gz *

La sauvegarde est terminée.

La restauration

Nous allons pouvoir continuer avec la restauration.

Comme tout à l’heure, il est nécessaire de définir un dépôt repo pour la restauration (restore) au niveau de l’instance B. Pour cela, nous modifions sur le fichier elasticsearch.yml et rajouter la ligne suivante

path.repo: /datas/es-b/repo

avertissement Pré-requis : le répertoire /datas/es-b/repo devra exister avant le redémarrage.

Un redémarrage de l’instance B est nécessaire afin que la nouvelle configuration soit prise en compte.

Nous allons créer physiquement le répertoire restore

cd /datas/es-b/repo
mkdir restore

Dans le répertoire, il faut décompresser l’archive précédente.

cd /datas/es-b/repo/restore
tar xzvf backups-20230717.tar.gz
rm backups-20230717.tar.gz

avertissement Vérifier que les droits des fichiers soient corrects. C’est à dire que l’utilisateur utilisé pour exécuter elasticsearch doit avoir les droits sur ces fichiers.

Dans un premier temps, nous allons déclarer le répertoire au niveau d’Elasticsearch, avec la commande suivante:

curl --request POST \
  --insecure --header 'Authorization: Basic CHAINE_ENCODE_A_RENSEIGNER_ICI' \
  --url https://ADR_IP_INSTANCE_B:9200/_snapshot/restore \
  --header 'Content-Type: application/json' \
  --data '{
  "type": "url",
  "settings": {
    "url": "file:/datas/socle/repo/restore"
  }
}'

Nous obtenons la réponse suivante :

{
	"acknowledged": true
}

Nous allons pouvoir lister les sauvegardes possibles :

curl --request GET \
  --insecure --header 'Authorization: Basic CHAINE_ENCODE_A_RENSEIGNER_ICI' \
  --url 'https://ADR_INSTANCE_B:9200/_snapshot/restore/*?verbose=false'

Nous obtenons le résultat suivant :

{
	"snapshots": [
		{
			"snapshot": "backup_20230730",
			"uuid": "xXYjHpcDRHmRXlN9ey3XXA",
			"repository": "restore",
			"indices": [
				".security-7",
				"mon-index"
			],
			"data_streams": [],
			"state": "SUCCESS"
		}
	],
	"total": 1,
	"remaining": 0
}

Nous avons bien notre sauvegarde backup_20230730 contenant deux index dont mon-index

Maintenant, nous allons pouvoir lancer la restauration avec la commande suivante :

curl --request POST \
  --insecure --header 'Authorization: Basic CHAINE_ENCODE_A_RENSEIGNER_ICI' \
  --url https://ADR_INSTANCE_B:9200/_snapshot/restore/backup_20230730/_restore \
  --header 'Content-Type: application/json' \
  --data '{
  "indices": "mon-index"
}'

astuce Dans le cas ci-dessus, j’ai filtré pour restaurer uniquement l’index qui m’intéresse.

En retour, vous obtenez le message suivant :

{
	"accepted": true
}

Il faudra attendre en fonction du volume des données mais sinon voila le tour est joué.