Solución de problemas de trabajos que utilizan PersistentVolumeClaims (PVC) - Amazon EMR

Solución de problemas de trabajos que utilizan PersistentVolumeClaims (PVC)

Si necesita crear, enumerar o eliminar PersistentVolumeClaims (PVC) para un trabajo, pero no agrega permisos de PVC al rol de emr-containers predeterminado de Kubernetes, el trabajo fallará cuando lo envíe. Sin estos permisos, el rol de emr-containers no puede crear los roles necesarios para el controlador o el cliente de Spark. No basta con agregar permisos a los roles de controlador o cliente de Spark, como sugieren los mensajes de error. El rol principal de emr-containers también debe incluir los permisos necesarios. En esta sección, se explica cómo agregar los permisos necesarios al rol principal de emr-containers.

Verificación

Para comprobar si su rol de emr-containers tiene o no los permisos necesarios, defina la variable NAMESPACE con su propio valor y, a continuación, ejecute el siguiente comando:

export NAMESPACE=YOUR_VALUE kubectl describe role emr-containers -n ${NAMESPACE}

Además, para comprobar si los roles de Spark y de cliente tienen los permisos necesarios, ejecute el siguiente comando:

kubectl describe role emr-containers-role-spark-driver -n ${NAMESPACE} kubectl describe role emr-containers-role-spark-client -n ${NAMESPACE}

Si los permisos no están disponibles, continúe con el parche de la siguiente manera.

Parche

  1. Si los trabajos sin permisos se están ejecutando actualmente, deténgalos.

  2. Cree un archivo denominado RBAC_Patch.py de la siguiente manera:

    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)
  3. Ejecute el script de Python:

    python3 RBAC_Patch.py -n ${NAMESPACE}
  4. Aparece una diferencia kubectl entre los permisos nuevos y los antiguos. Pulse y para parchear el rol.

  5. Compruebe los tres roles con permisos adicionales de la siguiente manera:

    kubectl describe role -n ${NAMESPACE}
  6. Ejecute el script de Python:

    python3 RBAC_Patch.py -n ${NAMESPACE}
  7. Después de ejecutar el comando, mostrará una diferencia de kubectl entre los permisos nuevos y los antiguos. Pulse y para parchear el rol.

  8. Verifique los tres roles con permisos adicionales:

    kubectl describe role -n ${NAMESPACE}
  9. Vuelva a enviar el trabajo.

Parche manual

Si el permiso que requiere su aplicación se aplica a algo distinto a las reglas de PVC, puede agregar manualmente permisos de Kubernetes para su clúster virtual de Amazon EMR según sea necesario.

nota

El rol emr-containers es un rol principal. Esto significa que debe proporcionar todos los permisos necesarios antes de poder cambiar los roles subyacentes de controlador o cliente.

  1. Descargue los permisos actuales en archivos yaml al ejecutar los siguientes comandos:

    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
  2. En función del permiso que requiera su aplicación, edite cada archivo y agregue reglas adicionales, como las siguientes:

    • 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
  3. Elimine los siguientes atributos con sus valores. Esto es necesario para aplicar la actualización.

    • creationTimestamp

    • resourceVersion

    • uid

  4. Por último, ejecute el parche:

    kubectl apply -f emr-containers-role-patch.yaml kubectl apply -f driver-role-patch.yaml kubectl apply -f client-role-patch.yaml