PersistentVolumeClaims(PVC)를 사용하는 작업 문제 해결
작업의 PersistentVolumeClaims(PVC)를 생성, 나열 또는 삭제해야 하는 경우 기본 Kubernetes 역할 emr-containers를 추가하지 않으면 작업 제출 시 작업에 실패합니다. 이 권한이 없으면 emr-container 역할은 Spark 드라이버 또는 Spark 클라이언트에 필요한 역할을 생성할 수 없습니다. 오류 메시지에서 알 수 있듯이 Spark 드라이버 또는 클라이언트 역할에 권한을 추가하는 것만으로는 충분하지 않습니다. emr-containers 기본 역할에도 필수 권한이 포함되어야 합니다. 이 섹션에서는 emr-containers 기본 역할에 필수 권한을 추가하는 방법을 설명합니다.
확인
emr-containers 역할에 필수 권한이 있는지 확인하려면 NAMESPACE 변수를 자체 값으로 설정한 후 다음 명령을 실행합니다.
export NAMESPACE=YOUR_VALUE kubectl describe role emr-containers -n ${NAMESPACE}
또한 Spark 및 클라이언트 역할에 필수 권한이 있는지 확인하려면 다음 명령을 실행합니다.
kubectl describe role emr-containers-role-spark-driver -n ${NAMESPACE} kubectl describe role emr-containers-role-spark-client -n ${NAMESPACE}
권한이 없는 경우 다음과 같이 패치를 진행합니다.
패치
-
권한이 없는 작업이 현재 실행 중인 경우 해당 작업을 중지합니다.
-
다음과 같이 RBAC_Patch.py라는 파일을 생성합니다.
import os import subprocess as sp import tempfile as temp import json import argparse import uuid def delete_if_exists(dictionary: dict, key: str): if dictionary.get(key, None) is not None: del dictionary[key] def doTerminalCmd(cmd): with temp.TemporaryFile() as f: process = sp.Popen(cmd, stdout=f, stderr=f) process.wait() f.seek(0) msg = f.read().decode() return msg def patchRole(roleName, namespace, extraRules, skipConfirmation=False): cmd = f"kubectl get role {roleName} -n {namespace} --output json".split(" ") msg = doTerminalCmd(cmd) if "(NotFound)" in msg and "Error" in msg: print(msg) return False role = json.loads(msg) rules = role["rules"] rulesToAssign = extraRules[::] passedRules = [] for rule in rules: apiGroups = set(rule["apiGroups"]) resources = set(rule["resources"]) verbs = set(rule["verbs"]) for extraRule in extraRules: passes = 0 apiGroupsExtra = set(extraRule["apiGroups"]) resourcesExtra = set(extraRule["resources"]) verbsExtra = set(extraRule["verbs"]) passes += len(apiGroupsExtra.intersection(apiGroups)) >= len(apiGroupsExtra) passes += len(resourcesExtra.intersection(resources)) >= len(resourcesExtra) passes += len(verbsExtra.intersection(verbs)) >= len(verbsExtra) if passes >= 3: if extraRule not in passedRules: passedRules.append(extraRule) if extraRule in rulesToAssign: rulesToAssign.remove(extraRule) break prompt_text = "Apply Changes?" if len(rulesToAssign) == 0: print(f"The role {roleName} seems to already have the necessary permissions!") prompt_text = "Proceed anyways?" for ruleToAssign in rulesToAssign: role["rules"].append(ruleToAssign) delete_if_exists(role, "creationTimestamp") delete_if_exists(role, "resourceVersion") delete_if_exists(role, "uid") new_role = json.dumps(role, indent=3) uid = uuid.uuid4() filename = f"Role-{roleName}-New_Permissions-{uid}-TemporaryFile.json" try: with open(filename, "w+") as f: f.write(new_role) f.flush() prompt = "y" if not skipConfirmation: prompt = input( doTerminalCmd(f"kubectl diff -f {filename}".split(" ")) + f"\n{prompt_text} y/n: " ).lower().strip() while prompt != "y" and prompt != "n": prompt = input("Please make a valid selection. y/n: ").lower().strip() if prompt == "y": print(doTerminalCmd(f"kubectl apply -f {filename}".split(" "))) except Exception as e: print(e) os.remove(f"./{filename}") if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument("-n", "--namespace", help="Namespace of the Role. By default its the VirtualCluster's namespace", required=True, dest="namespace" ) parser.add_argument("-p", "--no-prompt", help="Applies the patches without asking first", dest="no_prompt", default=False, action="store_true" ) args = parser.parse_args() emrRoleRules = [ { "apiGroups": [""], "resources": ["persistentvolumeclaims"], "verbs": ["list", "create", "delete", "patch"] } ] driverRoleRules = [ { "apiGroups": [""], "resources": ["persistentvolumeclaims"], "verbs": ["list", "create", "delete", "patch"] }, { "apiGroups": [""], "resources": ["services"], "verbs": ["get", "list", "describe", "create", "delete", "watch"] } ] clientRoleRules = [ { "apiGroups": [""], "resources": ["persistentvolumeclaims"], "verbs": ["list", "create", "delete", "patch"] } ] patchRole("emr-containers", args.namespace, emrRoleRules, args.no_prompt) patchRole("emr-containers-role-spark-driver", args.namespace, driverRoleRules, args.no_prompt) patchRole("emr-containers-role-spark-client", args.namespace, clientRoleRules, args.no_prompt)
-
Python 스크립트를 실행합니다.
python3 RBAC_Patch.py -n ${NAMESPACE}
-
새 권한과 이전 권한 간의 kubectl 차이가 표시됩니다. y를 눌러 역할을 패치합니다.
-
다음과 같이 추가 권한이 있는 세 가지 역할을 확인합니다.
kubectl describe role -n ${NAMESPACE}
-
Python 스크립트를 실행합니다.
python3 RBAC_Patch.py -n ${NAMESPACE}
-
명령을 실행하면 새 권한과 이전 권한 사이에 kubectl 차이가 표시됩니다. y를 눌러 역할을 패치합니다.
-
추가 권한이 있는 세 가지 역할을 확인합니다.
kubectl describe role -n ${NAMESPACE}
-
작업을 다시 제출합니다.
수동 패치
애플리케이션에 필요한 권한이 PVC 규칙 이외의 다른 항목에 적용되는 경우 필요에 따라 Amazon EMR 가상 클러스터에 대한 Kubernetes 권한을 수동으로 추가할 수 있습니다.
참고
emr-containers 역할은 기본 역할입니다. 즉, 기본 드라이버 또는 클라이언트 역할을 변경하려면 먼저 필요한 모든 권한을 제공해야 합니다.
-
아래 명령을 실행하여 현재 권한을 yaml 파일로 다운로드합니다.
kubectl get role -n ${NAMESPACE} emr-containers -o yaml >> emr-containers-role-patch.yaml kubectl get role -n ${NAMESPACE} emr-containers-role-spark-driver -o yaml >> driver-role-patch.yaml kubectl get role -n ${NAMESPACE} emr-containers-role-spark-client -o yaml >> client-role-patch.yaml
-
애플리케이션에 필요한 권한에 따라 각 파일을 편집하고 다음과 같은 추가 규칙을 추가합니다.
-
emr-containers-role-patch.yaml
- apiGroups: - "" resources: - persistentvolumeclaims verbs: - list - create - delete - patch
-
driver-role-patch.yaml
- apiGroups: - "" resources: - persistentvolumeclaims verbs: - list - create - delete - patch - apiGroups: - "" resources: - services verbs: - get - list - describe - create - delete - watch
-
client-role-patch.yaml
- apiGroups: - "" resources: - persistentvolumeclaims verbs: - list - create - delete - patch
-
-
다음 속성을 해당 값과 함께 제거합니다. 업데이트를 적용하는 데 필요합니다.
-
creationTimestamp
-
resourceVersion
-
uid
-
-
마지막으로 패치를 실행합니다.
kubectl apply -f emr-containers-role-patch.yaml kubectl apply -f driver-role-patch.yaml kubectl apply -f client-role-patch.yaml