

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# Amazon EMR on EKS에서 보안 및 Spark 운영자
<a name="spark-operator-security"></a>

Spark 운영자를 사용하는 경우 클러스터 액세스 권한을 설정하는 몇 가지 방법이 있습니다. 첫 번째에서는 역할 기반 액세스 제어를 사용합니다. 역할 기반 액세스 제어(RBAC)는 조직 내 개인의 역할에 따라 액세스를 제한합니다. 액세스를 처리하는 기본적인 방법이 되었습니다. 두 번째 액세스 방법은 할당된 특정 권한을 통해 리소스 액세스를 제공하는 AWS Identity and Access Management 역할을 수임하는 것입니다.

**Topics**
+ [역할 기반 액세스 제어(RBAC)를 사용하여 클러스터 액세스 권한 설정](spark-operator-security-rbac.md)
+ [서비스 계정에 대한 IAM 역할(IRSA)을 사용하여 클러스터 액세스 권한 설정](spark-operator-security-irsa.md)

# 역할 기반 액세스 제어(RBAC)를 사용하여 클러스터 액세스 권한 설정
<a name="spark-operator-security-rbac"></a>

Spark 운영자를 배포하기 위해 Amazon EMR on EKS는 Spark 운영자와 Spark 앱을 위한 두 가지 역할 및 서비스 계정을 생성합니다.

**Topics**
+ [운영자 서비스 계정 및 역할](#spark-operator-sa-oper)
+ [Spark 서비스 계정 및 역할](#spark-operator-sa-spark)

## 운영자 서비스 계정 및 역할
<a name="spark-operator-sa-oper"></a>

Amazon EMR on EKS는 Spark 작업 및 기타 리소스(예: 서비스)와 관련된 `SparkApplications`를 관리할 **운영자 서비스 계정 및 역할**을 생성합니다.

이 서비스 계정의 기본 이름은 `emr-containers-sa-spark-operator`입니다.

이 서비스 역할에는 다음 규칙이 적용됩니다.

```
 rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - "*"
- apiGroups:
  - ""
  resources:
  - services
  - configmaps
  - secrets
  verbs:
  - create
  - get
  - delete
  - update
- apiGroups:
  - extensions
  - networking.k8s.io
  resources:
  - ingresses
  verbs:
  - create
  - get
  - delete
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - get
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - create
  - update
  - patch
- apiGroups:
  - ""
  resources:
  - resourcequotas
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - apiextensions.k8s.io
  resources:
  - customresourcedefinitions
  verbs:
  - create
  - get
  - update
  - delete
- apiGroups:
  - admissionregistration.k8s.io
  resources:
  - mutatingwebhookconfigurations
  - validatingwebhookconfigurations
  verbs:
  - create
  - get
  - update
  - delete
- apiGroups:
  - sparkoperator.k8s.io
  resources:
  - sparkapplications
  - sparkapplications/status
  - scheduledsparkapplications
  - scheduledsparkapplications/status
  verbs:
  - "*"
  {{- if .Values.batchScheduler.enable }}
  # required for the `volcano` batch scheduler
- apiGroups:
  - scheduling.incubator.k8s.io
  - scheduling.sigs.dev
  - scheduling.volcano.sh
  resources:
  - podgroups
  verbs:
  - "*"
  {{- end }}
  {{ if .Values.webhook.enable }}
- apiGroups:
  - batch
  resources:
  - jobs
  verbs:
  - delete
  {{- end }}
```

## Spark 서비스 계정 및 역할
<a name="spark-operator-sa-spark"></a>

Spark 드라이버 포드에는 포드와 동일한 네임스페이스에 있는 Kubernetes 서비스 계정이 필요합니다. 이 서비스 계정에는 실행기 포드의 생성, 가져오기, 나열, 패치, 삭제 권한과 드라이버용 Kubernetes 헤드리스 서비스의 생성 권한이 필요합니다. 포드 네임스페이스의 기본 서비스 계정에 필요한 권한이 없으면 드라이버가 실패하고 서비스 계정 없이 종료됩니다.

이 서비스 계정의 기본 이름은 `emr-containers-sa-spark`입니다.

이 서비스 역할에는 다음 규칙이 적용됩니다.

```
 rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - "*"
- apiGroups:
  - ""
  resources:
  - services
  verbs:
  - "*"
- apiGroups:
  - ""
  resources:
  - configmaps
  verbs:
  - "*"
- apiGroups:
  - ""
  resources:
  - persistentvolumeclaims
  verbs:
  - "*"
```

# 서비스 계정에 대한 IAM 역할(IRSA)을 사용하여 클러스터 액세스 권한 설정
<a name="spark-operator-security-irsa"></a>

이 섹션에서는 예를 사용하여 AWS Identity and Access Management 역할을 수임하도록 Kubernetes 서비스 계정을 구성하는 방법을 보여줍니다. 그런 다음 서비스 계정을 사용하는 포드는 역할에 액세스 권한이 있는 모든 AWS 서비스에 액세스할 수 있습니다.

다음 예제에서는 Spark 애플리케이션을 실행하여 Amazon S3에 있는 파일의 단어 수를 계산합니다. 이를 위해 서비스 계정에 대한 IAM 역할(IRSA)을 설정하여 Kubernetes 서비스 계정을 인증하고 권한을 부여할 수 있습니다.

**참고**  
이 예제에서는 Spark 운영자의 'spark-operator' 네임스페이스와 Spark 애플리케이션을 제출하는 네임스페이스를 사용합니다.

## 사전 조건
<a name="spark-operator-security-irsa-prereqs"></a>

이 페이지의 예제를 사용하기 전에 다음 필수 조건을 완료합니다.
+ [Spark 운영자를 설정합니다]().
+ [Spark 운영자 설치](spark-operator-gs.md#spark-operator-install).
+ [Amazon S3 버킷을 생성](https://docs.aws.amazon.com/AmazonS3/latest/userguide/creating-bucket.html)합니다.
+ 좋아하는 시를 `poem.txt` 텍스트 파일에 저장하고 파일을 S3 버킷에 업로드합니다. 이 페이지에서 생성한 Spark 애플리케이션이 텍스트 파일의 내용을 읽습니다. S3에 파일을 업로드하는 방법에 대한 자세한 내용은 *Amazon Simple Storage Service 사용 설명서*에서 [버킷에 객체 업로드](https://docs.aws.amazon.com/AmazonS3/latest/userguide/uploading-an-object-bucket.html)를 참조하세요.

## IAM 역할을 수임하도록 Kubernetes 서비스 계정 구성
<a name="spark-operator-security-irsa-config"></a>

다음 단계를 사용하여 포드가 액세스 권한이 있는 서비스에 액세스하는 데 사용할 수 있는 IAM 역할을 수임하도록 Kubernetes AWS 서비스 계정을 구성합니다.

1. 를 완료한 후 [사전 조건](#spark-operator-security-irsa-prereqs) AWS Command Line Interface 를 사용하여 Amazon S3에 업로드한 `example-policy.json` 파일에 대한 읽기 전용 액세스를 허용하는 파일을 생성합니다.

   ```
   cat >example-policy.json <<EOF
   {
       "Version": "2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "s3:GetObject",
                   "s3:ListBucket"
               ],
               "Resource": [
                   "arn:aws:s3:::my-pod-bucket",
                   "arn:aws:s3:::my-pod-bucket/*"
               ]
           }
       ]
   }
   EOF
   ```

1. IAM 정책 `example-policy`를 생성합니다.

   ```
   aws iam create-policy --policy-name example-policy --policy-document file://example-policy.json
   ```

1. 다음으로 IAM 역할 `example-role`을 생성하고 이를 Spark 드라이버의 Kubernetes 서비스 계정과 연결합니다.

   ```
   eksctl create iamserviceaccount --name driver-account-sa --namespace spark-operator \
   --cluster my-cluster --role-name "example-role" \
   --attach-policy-arn arn:aws:iam::111122223333:policy/example-policy --approve
   ```

1. Spark 드라이버 서비스 계정에 필요한 클러스터 역할 바인딩이 포함된 yaml 파일을 생성합니다.

   ```
   cat >spark-rbac.yaml <<EOF
   apiVersion: v1
   kind: ServiceAccount
   metadata:
     name: driver-account-sa
   ---
   apiVersion: rbac.authorization.k8s.io/v1
   kind: ClusterRoleBinding
   metadata:
     name: spark-role
   roleRef:
     apiGroup: rbac.authorization.k8s.io
     kind: ClusterRole
     name: edit
   subjects:
     - kind: ServiceAccount
       name: driver-account-sa
       namespace: spark-operator
   EOF
   ```

1. 클러스터 역할 바인딩 구성을 적용합니다.

   ```
   kubectl apply -f spark-rbac.yaml
   ```

kubectl 명령은 성공적인 계정 생성을 확인합니다.

```
serviceaccount/driver-account-sa created
clusterrolebinding.rbac.authorization.k8s.io/spark-role configured
```

## Spark 운영자에서 애플리케이션 실행
<a name="spark-operator-security-irsa-run"></a>

[Kubernetes 서비스 계정 구성]() 후 [사전 조건](#spark-operator-security-irsa-prereqs)의 일부로 업로드한 텍스트 파일의 단어 수를 계산하는 Spark 애플리케이션을 실행할 수 있습니다.

1. Amazon EMR 버전 6을 기반으로 단어 수 계산 애플리케이션을 위한 `SparkApplication` 정의를 사용하여 새 파일 `word-count.yaml`을 만듭니다.

   ```
   cat >word-count.yaml <<EOF
   apiVersion: "sparkoperator.k8s.io/v1beta2"
   kind: SparkApplication
   metadata:
     name: word-count
     namespace: spark-operator
   spec:
     type: Java
     mode: cluster
     image: "895885662937.dkr.ecr.us-west-2.amazonaws.com/spark/emr-6.10.0:latest"
     imagePullPolicy: Always
     mainClass: org.apache.spark.examples.JavaWordCount
     mainApplicationFile: local:///usr/lib/spark/examples/jars/spark-examples.jar
     arguments:
       - s3://my-pod-bucket/poem.txt
     hadoopConf:
      # EMRFS filesystem
       fs.s3.customAWSCredentialsProvider: com.amazonaws.auth.WebIdentityTokenCredentialsProvider
       fs.s3.impl: com.amazon.ws.emr.hadoop.fs.EmrFileSystem
       fs.AbstractFileSystem.s3.impl: org.apache.hadoop.fs.s3.EMRFSDelegate
       fs.s3.buffer.dir: /mnt/s3
       fs.s3.getObject.initialSocketTimeoutMilliseconds: "2000"
       mapreduce.fileoutputcommitter.algorithm.version.emr_internal_use_only.EmrFileSystem: "2"
       mapreduce.fileoutputcommitter.cleanup-failures.ignored.emr_internal_use_only.EmrFileSystem: "true"
     sparkConf:
       # Required for EMR Runtime
       spark.driver.extraClassPath: /usr/lib/hadoop-lzo/lib/*:/usr/lib/hadoop/hadoop-aws.jar:/usr/share/aws/aws-java-sdk/*:/usr/share/aws/emr/emrfs/conf:/usr/share/aws/emr/emrfs/lib/*:/usr/share/aws/emr/emrfs/auxlib/*:/usr/share/aws/emr/security/conf:/usr/share/aws/emr/security/lib/*:/usr/share/aws/hmclient/lib/aws-glue-datacatalog-spark-client.jar:/usr/share/java/Hive-JSON-Serde/hive-openx-serde.jar:/usr/share/aws/sagemaker-spark-sdk/lib/sagemaker-spark-sdk.jar:/home/hadoop/extrajars/*
       spark.driver.extraLibraryPath: /usr/lib/hadoop/lib/native:/usr/lib/hadoop-lzo/lib/native:/docker/usr/lib/hadoop/lib/native:/docker/usr/lib/hadoop-lzo/lib/native
       spark.executor.extraClassPath: /usr/lib/hadoop-lzo/lib/*:/usr/lib/hadoop/hadoop-aws.jar:/usr/share/aws/aws-java-sdk/*:/usr/share/aws/emr/emrfs/conf:/usr/share/aws/emr/emrfs/lib/*:/usr/share/aws/emr/emrfs/auxlib/*:/usr/share/aws/emr/security/conf:/usr/share/aws/emr/security/lib/*:/usr/share/aws/hmclient/lib/aws-glue-datacatalog-spark-client.jar:/usr/share/java/Hive-JSON-Serde/hive-openx-serde.jar:/usr/share/aws/sagemaker-spark-sdk/lib/sagemaker-spark-sdk.jar:/home/hadoop/extrajars/*
       spark.executor.extraLibraryPath: /usr/lib/hadoop/lib/native:/usr/lib/hadoop-lzo/lib/native:/docker/usr/lib/hadoop/lib/native:/docker/usr/lib/hadoop-lzo/lib/native
     sparkVersion: "3.3.1"
     restartPolicy:
       type: Never
     driver:
       cores: 1
       coreLimit: "1200m"
       memory: "512m"
       labels:
         version: 3.3.1
       serviceAccount: my-spark-driver-sa
     executor:
       cores: 1
       instances: 1
       memory: "512m"
       labels:
         version: 3.3.1
   EOF
   ```

   버전 7 릴리스에서 Spark 운영자를 사용하는 경우 구성 값 중 일부를 조정합니다.

   ```
   cat >word-count.yaml <<EOF
   apiVersion: "sparkoperator.k8s.io/v1beta2"
   kind: SparkApplication
   metadata:
     name: word-count
     namespace: spark-operator
   spec:
     type: Java
     mode: cluster
     image: "895885662937.dkr.ecr.us-west-2.amazonaws.com/spark/emr-7.7.0:latest"
     imagePullPolicy: Always
     mainClass: org.apache.spark.examples.JavaWordCount
     mainApplicationFile: local:///usr/lib/spark/examples/jars/spark-examples.jar
     arguments:
       - s3://my-pod-bucket/poem.txt
     hadoopConf:
      # EMRFS filesystem
       fs.s3.customAWSCredentialsProvider: com.amazonaws.auth.WebIdentityTokenCredentialsProvider
       fs.s3.impl: com.amazon.ws.emr.hadoop.fs.EmrFileSystem
       fs.AbstractFileSystem.s3.impl: org.apache.hadoop.fs.s3.EMRFSDelegate
       fs.s3.buffer.dir: /mnt/s3
       fs.s3.getObject.initialSocketTimeoutMilliseconds: "2000"
       mapreduce.fileoutputcommitter.algorithm.version.emr_internal_use_only.EmrFileSystem: "2"
       mapreduce.fileoutputcommitter.cleanup-failures.ignored.emr_internal_use_only.EmrFileSystem: "true"
     sparkConf:
       # Required for EMR Runtime
       spark.driver.extraClassPath: /usr/lib/hadoop-lzo/lib/*:/usr/lib/hadoop/hadoop-aws.jar:/usr/share/aws/aws-java-sdk/*:/usr/share/aws/aws-java-sdk-v2/*:/usr/share/aws/emr/emrfs/conf:/usr/share/aws/emr/emrfs/lib/*:/usr/share/aws/emr/emrfs/auxlib/*:/usr/share/aws/emr/security/conf:/usr/share/aws/emr/security/lib/*:/usr/share/aws/hmclient/lib/aws-glue-datacatalog-spark-client.jar:/usr/share/java/Hive-JSON-Serde/hive-openx-serde.jar:/usr/share/aws/sagemaker-spark-sdk/lib/sagemaker-spark-sdk.jar:/home/hadoop/extrajars/*
       spark.driver.extraLibraryPath: /usr/lib/hadoop/lib/native:/usr/lib/hadoop-lzo/lib/native:/docker/usr/lib/hadoop/lib/native:/docker/usr/lib/hadoop-lzo/lib/native
       spark.executor.extraClassPath: /usr/lib/hadoop-lzo/lib/*:/usr/lib/hadoop/hadoop-aws.jar:/usr/share/aws/aws-java-sdk/*:/usr/share/aws/aws-java-sdk-v2/*:/usr/share/aws/emr/emrfs/conf:/usr/share/aws/emr/emrfs/lib/*:/usr/share/aws/emr/emrfs/auxlib/*:/usr/share/aws/emr/security/conf:/usr/share/aws/emr/security/lib/*:/usr/share/aws/hmclient/lib/aws-glue-datacatalog-spark-client.jar:/usr/share/java/Hive-JSON-Serde/hive-openx-serde.jar:/usr/share/aws/sagemaker-spark-sdk/lib/sagemaker-spark-sdk.jar:/home/hadoop/extrajars/*
       spark.executor.extraLibraryPath: /usr/lib/hadoop/lib/native:/usr/lib/hadoop-lzo/lib/native:/docker/usr/lib/hadoop/lib/native:/docker/usr/lib/hadoop-lzo/lib/native
     sparkVersion: "3.3.1"
     restartPolicy:
       type: Never
     driver:
       cores: 1
       coreLimit: "1200m"
       memory: "512m"
       labels:
         version: 3.3.1
       serviceAccount: my-spark-driver-sa
     executor:
       cores: 1
       instances: 1
       memory: "512m"
       labels:
         version: 3.3.1
   EOF
   ```

1. Spark 애플리케이션을 제출합니다.

   ```
   kubectl apply -f word-count.yaml
   ```

   kubectl 명령은 `word-count`라고 하는 `SparkApplication` 객체를 성공적으로 생성했다는 확인을 반환합니다.

   ```
   sparkapplication.sparkoperator.k8s.io/word-count configured
   ```

1. `SparkApplication` 객체에 대한 이벤트를 확인하려면 다음 명령을 실행합니다.

   ```
   kubectl describe sparkapplication word-count -n spark-operator
   ```

   kubectl 명령은 이벤트와 함께 `SparkApplication`에 대한 설명을 반환합니다.

   ```
   Events:
     Type     Reason                               Age                    From            Message
     ----     ------                               ----                   ----            -------
     Normal   SparkApplicationSpecUpdateProcessed  3m2s (x2 over 17h)     spark-operator  Successfully processed spec update for SparkApplication word-count
     Warning  SparkApplicationPendingRerun         3m2s (x2 over 17h)     spark-operator  SparkApplication word-count is pending rerun
     Normal   SparkApplicationSubmitted            2m58s (x2 over 17h)    spark-operator  SparkApplication word-count was submitted successfully
     Normal   SparkDriverRunning                   2m56s (x2 over 17h)    spark-operator  Driver word-count-driver is running
     Normal   SparkExecutorPending                 2m50s                  spark-operator  Executor [javawordcount-fdd1698807392c66-exec-1] is pending
     Normal   SparkExecutorRunning                 2m48s                  spark-operator  Executor [javawordcount-fdd1698807392c66-exec-1] is running
     Normal   SparkDriverCompleted                 2m31s (x2 over 17h)    spark-operator  Driver word-count-driver completed
     Normal   SparkApplicationCompleted            2m31s (x2 over 17h)    spark-operator  SparkApplication word-count completed
     Normal   SparkExecutorCompleted               2m31s (x2 over 2m31s)  spark-operator  Executor [javawordcount-fdd1698807392c66-exec-1] completed
   ```

이제 애플리케이션이 S3 파일에 있는 단어 수를 계산합니다. 단어 수를 확인하려면 드라이버의 로그 파일을 참조하세요.

```
kubectl logs pod/word-count-driver -n spark-operator
```

kubectl 명령은 word-count 애플리케이션의 결과와 함께 로그 파일의 콘텐츠를 반환해야 합니다.

```
INFO DAGScheduler: Job 0 finished: collect at JavaWordCount.java:53, took 5.146519 s
                Software: 1
```

Spark 운영자를 통해 Spark에 애플리케이션을 제출하는 방법에 대한 자세한 내용은 GitHub의 *Kubernetes Operator for Apache Spark (spark-on-k8s-operator)* 설명서에서 [Using a SparkApplication](https://www.kubeflow.org/docs/components/spark-operator/user-guide/using-sparkapplication/)을 참조하세요.