PersistentVolumeClaims (PVC) を使用するジョブのトラブルシューティング - Amazon EMR

PersistentVolumeClaims (PVC) を使用するジョブのトラブルシューティング

ジョブの PersistentVolumeClaims (PVC) を作成、リスト、または削除する必要があるにもかかわらず、デフォルトの Kubernetes ロール emr-containers に PVC 権限を追加しなかった場合、ジョブの送信が失敗します。PVC 権限がないと、emr-containers ロールでは Spark ドライバーや 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}

必要な権限がない場合は、次のようにパッチを適用して続行します。

パッチ

  1. 必要な権限がないジョブを現在実行している場合は、そのジョブを停止します。

  2. 次のように、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)
  3. Python スクリプトを実行します。

    python3 RBAC_Patch.py -n ${NAMESPACE}
  4. kubectl による新しい権限と古い権限の違いが表示されます。y を押すと、ロールにパッチが適用されます。

  5. 以下を実行して、3 つのロールに権限が追加されていることを確認します。

    kubectl describe role -n ${NAMESPACE}
  6. python スクリプトを実行します。

    python3 RBAC_Patch.py -n ${NAMESPACE}
  7. このコマンドを実行すると、kubectl による新しい権限と古い権限の違いが表示されます。y を押すと、ロールにパッチが適用されます。

  8. 3 つのロールに権限が追加されていることを確認します。

    kubectl describe role -n ${NAMESPACE}
  9. ジョブを再度送信します。

手動パッチ

アプリケーションに必要な権限が PVC ルール以外に適用される場合、必要に応じて Amazon EMR 仮想クラスターに対する Kubernetes 権限を手動で追加できます。

注記

emr-containers ロールはプライマリロールです。つまり、基盤となるドライバーロールやクライアントロールを変更する場合は、その操作に必要なすべての権限をこのプライマリロールで提供する必要があります。

  1. 次のコマンドを実行して、現在の権限を 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
  2. アプリケーションに必要な権限に基づいて、各ファイルを編集し、次のようなさらに別のルールを追加します。

    • 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. 次の属性をその値と共に削除します。更新を適用するために必要な操作です。

    • creationTimestamp

    • resourceVersion

    • uid

  4. 最後に、パッチを実行します。

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