개발/Elasticsearch

aws elasticsearch snapshot 으로 데이터 백업 with java

보리ing 2021. 2. 9. 19:00

 지금 서비스하고 있는 aws elasitcsearch 버전이 6.8인데 7.7에서 힙 메모리 사용이 확 개선되어, 가장 최신 버전인 7.9 버전으로 마이그레이션 하려고 한다.

 

1. s3 bucket 생성

-snapshot 저장할 s3 bucket 생성한다.

 

2. IAM - 역할 생성

iam - 역할 - 역할 만들기 

ec2 선택해서 다음 - 다음 - 다음 역할이름 입력하여 역할 만들기 완료

 

3. 역할에 신뢰관계 설정

생성한 역할에 신뢰 관계 - 신뢰 관계 편집 

 

ec2 대신 es로 변경

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "es.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

신뢰 정책 업데이트

 

4. 해당 역할에 정책 연결

정책 연결 - 정책생성을 통해 정책을 정의해도 되고, 인라인 정책에 추가해도 된다.

인라인 정책 추가 - json

사용 bucket명은 testsnapshot-bucket

{
  "Version": "2012-10-17",
  "Statement": [{
      "Action": [
        "s3:ListBucket"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::testsnapshot-bucket"
      ]
    },
    {
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::testsnapshot-bucket/*"
      ]
    }
  ]
}

 

이제 iam 작업은 다 끝났다.

 

 

5. snapshot repository 생성

 

현 프로젝트에 gradle에  추가되어있는 관련 디펜던시

'org.springframework.boot' version '2.2.8.RELEASE' 환경

implementation group: 'org.springframework.cloud', name: 'spring-cloud-starter-aws', version: '2.2.1.RELEASE'
implementation 'org.springframework.data:spring-data-elasticsearch:3.2.8.RELEASE'
implementation 'software.amazon.awssdk:auth:2.13.42'

 

a.kibana

PUT _snapshot/my-snapshot-repo-name
{
  "type": "s3",
  "settings": {
    "bucket": "s3-bucket-name",
    "base_path": "es-snapshot/test",
    "region": "region",
    "role_arn": "arn:aws:iam::123456789012:role/TheSnapshotRole",
    "compress" : "true"
  }
}

 

와같이 입력하여 생성 할 수 있다곤 하는데 되지 않아 java로 작업 하였다.

 

{
  "Message": "User: anonymous is not authorized to perform: iam:PassRole on resource: "
}​

와 같은 에러 메세지 발생

 

b. java

 

  private static String region = "ap-northeast-2";
    private static String serviceName = "es";
    private static String aesEndpoint = "old 엔드포인트"
    private static String newAesEndpoint = "new 엔드포인트"
    private static String snapshotRepository = "/_snapshot/whitelabel_backup";
    private static String snapshotSettings = "{ \"type\": \"s3\", \"settings\": { \"bucket\": \"testsnapshot-bucket\", \"region\": \"ap-northeast-2\", \"base_path\": \"es-snapshot/test\", \"compress\":\"true\", \"role_arn\": \"위에서 생성한 역할"\ } }";

    static final AWSCredentialsProvider credentialsProvider = new DefaultAWSCredentialsProviderChain();

    public String doSnapshot() throws IOException {
        RestClient esClient = esClient(serviceName, region);

        // Register a snapshot repository
        HttpEntity entity = new NStringEntity(snapshotSettings, ContentType.APPLICATION_JSON);
        Request request = new Request("PUT", snapshotRepository);
        request.setEntity(entity);
        // request.addParameter(name, value); // optional parameters
        Response response = esClient.performRequest(request);
        System.out.println(response.getStatusLine().getStatusCode());
        System.out.println(response.toString());
        return response.toString();
    }

    public static RestClient esClient(String serviceName, String region) {
        AWS4Signer signer = new AWS4Signer();
        signer.setServiceName(serviceName);
        signer.setRegionName(region);
        HttpRequestInterceptor interceptor = new AWSRequestSigningApacheInterceptor(serviceName, signer, credentialsProvider);
        return RestClient.builder(HttpHost.create(aesEndpoint)).setHttpClientConfigCallback(hacb -> hacb.addInterceptorLast(interceptor)).build();
    }

    public static RestClient newEsClient(String serviceName, String region) {
        AWS4Signer signer = new AWS4Signer();
        signer.setServiceName(serviceName);
        signer.setRegionName(region);
        HttpRequestInterceptor interceptor = new AWSRequestSigningApacheInterceptor(serviceName, signer, credentialsProvider);
        return RestClient.builder(HttpHost.create(newAesEndpoint)).setHttpClientConfigCallback(hacb -> hacb.addInterceptorLast(interceptor)).build();
    }

status code 200이 나오면 정상 처리

 

kibana에서 

GET _snapshot 

으로 

{
  "cs-automated" : {
    "type" : "s3"
  },
  "whitelabel_backup" : {
    "type" : "s3",
    "settings" : {
      "bucket" : "testsnapshot-bucket",
      "base_path" : "es-snapshot/test",
      "region" : "ap-northeast-2",
      "role_arn" : "생성한 역할",
      "compress" : "true"
    }
  }
}

확인 가능

 

6. elasticsearch snapshot 해당 s3에 저장

    public void moveToS3() throws IOException {

        RestClient esClient = esClient(serviceName, region);

        // Save indexes into S3 repository
        String takeSnapShot = "{\n  \"indices\": \"*\",\n  \"ignore_unavailable\": true,\n  \"include_global_state\": false\n}";
        HttpEntity entity = new NStringEntity(takeSnapShot, ContentType.APPLICATION_JSON);
        Request request = new Request("PUT", snapshotRepository + "/snapshot-all");
        request.setEntity(entity);

        Response response = esClient.performRequest(request);

        System.out.println(response.toString());
    }

 

 

7.  5.b와 같은 방법으로 새 elasticsearch server snpashot repository 생성

 

8. 새 서버에 백업 데이터 복구

 

    public void EsRestore() throws IOException {

        RestClient esClient = newEsClient(serviceName, region);

        // Restoring snapshot as ES indices
        String takeSnapShot = "{\n  \"indices\": \"test-index\",\n  \"ignore_unavailable\": true,\n  \"include_global_state\": false\n}";
        HttpEntity entity = new NStringEntity(takeSnapShot, ContentType.APPLICATION_JSON);
        Request request = new Request("POST", snapshotRepository + "/snapshot-all/_restore");
        request.setEntity(entity);

        Response response = esClient.performRequest(request);

        System.out.println(response.toString());
    }