Skip to content

Commit c83b6e4

Browse files
committed
Runpod: fix registry_auth support
For individual pods (single-node runs), set containerRegistryAuthId when a pod is created. All three mutations support this (undocumented) parameter: * podFindAndDeployOnDemand (gpu, on-demand) * podRentInterruptable (gpu, spot) * deployCpuPod (cpu, on-demand; the mutation itself is undocumented) For clusters, continue to use podEditJob workaround, but update only containerRegistryAuthId, other fields are optional (contrary to the spec, which is indeed outdated). Fixes: #3843
1 parent 5922aa7 commit c83b6e4

2 files changed

Lines changed: 16 additions & 37 deletions

File tree

src/dstack/_internal/core/backends/runpod/api_client.py

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ def create_pod(
7070
network_volume_id: Optional[str] = None,
7171
allowed_cuda_versions: Optional[List[str]] = None,
7272
bid_per_gpu: Optional[float] = None,
73+
container_registry_auth_id: Optional[str] = None,
7374
) -> Dict:
7475
resp = self._make_request(
7576
{
@@ -95,6 +96,7 @@ def create_pod(
9596
network_volume_id=network_volume_id,
9697
allowed_cuda_versions=allowed_cuda_versions,
9798
bid_per_gpu=bid_per_gpu,
99+
container_registry_auth_id=container_registry_auth_id,
98100
)
99101
}
100102
)
@@ -142,26 +144,18 @@ def create_cpu_pod(
142144
)
143145
return resp.json()["data"]["deployCpuPod"]
144146

145-
def edit_pod(
147+
def update_pod_container_registry_auth(
146148
self,
147149
pod_id: str,
148-
image_name: str,
149-
container_disk_in_gb: int,
150150
container_registry_auth_id: str,
151-
# Default pod volume is 20GB.
152-
# Runpod errors if it's not specified for podEditJob.
153-
volume_in_gb: int = 20,
154151
) -> str:
155152
resp = self._make_request(
156153
{
157154
"query": f"""
158155
mutation {{
159156
podEditJob(input: {{
160157
podId: "{pod_id}"
161-
imageName: "{image_name}"
162-
containerDiskInGb: {container_disk_in_gb}
163158
containerRegistryAuthId: "{container_registry_auth_id}"
164-
volumeInGb: {volume_in_gb}
165159
}}) {{
166160
id
167161
}}
@@ -454,29 +448,24 @@ def _generate_pod_deployment_mutation(
454448
network_volume_id: Optional[str] = None,
455449
allowed_cuda_versions: Optional[List[str]] = None,
456450
bid_per_gpu: Optional[float] = None,
451+
container_registry_auth_id: Optional[str] = None,
457452
) -> str:
458453
"""
459454
Generates a mutation to deploy pod.
460455
"""
461456
input_fields = []
462-
463-
# ------------------------------ Required Fields ----------------------------- #
464457
input_fields.append(f'name: "{name}"')
465458
input_fields.append(f'imageName: "{image_name}"')
466459
input_fields.append(f'gpuTypeId: "{gpu_type_id}"')
467-
468-
# ------------------------------ Default Fields ------------------------------ #
469460
input_fields.append(f"cloudType: {cloud_type}")
461+
input_fields.append(f'minCudaVersion: "{RunpodProvider.MIN_CUDA_VERSION}"')
470462

471463
if start_ssh:
472464
input_fields.append("startSsh: true")
473-
474465
if support_public_ip:
475466
input_fields.append("supportPublicIp: true")
476467
else:
477468
input_fields.append("supportPublicIp: false")
478-
479-
# ------------------------------ Optional Fields ----------------------------- #
480469
if bid_per_gpu is not None:
481470
input_fields.append(f"bidPerGpu: {bid_per_gpu}")
482471
if data_center_id is not None:
@@ -507,20 +496,18 @@ def _generate_pod_deployment_mutation(
507496
input_fields.append(f"env: [{env_string}]")
508497
if template_id is not None:
509498
input_fields.append(f'templateId: "{template_id}"')
510-
511499
if network_volume_id is not None:
512500
input_fields.append(f'networkVolumeId: "{network_volume_id}"')
513-
514501
if allowed_cuda_versions is not None:
515502
allowed_cuda_versions_string = ", ".join(
516503
[f'"{version}"' for version in allowed_cuda_versions]
517504
)
518505
input_fields.append(f"allowedCudaVersions: [{allowed_cuda_versions_string}]")
519-
520-
input_fields.append(f'minCudaVersion: "{RunpodProvider.MIN_CUDA_VERSION}"')
506+
if container_registry_auth_id is not None:
507+
input_fields.append(f'containerRegistryAuthId: "{container_registry_auth_id}"')
521508

522509
pod_deploy = "podFindAndDeployOnDemand" if bid_per_gpu is None else "podRentInterruptable"
523-
# Format input fields
510+
524511
input_string = ", ".join(input_fields)
525512
return f"""
526513
mutation {{

src/dstack/_internal/core/backends/runpod/compute.py

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ def run_job(
165165
resp = self.api_client.create_cpu_pod(
166166
name=pod_name,
167167
image_name=job.job_spec.image_name,
168+
container_registry_auth_id=container_registry_auth_id,
168169
instance_id=instance_offer.instance.name,
169170
cloud_type="SECURE",
170171
deploy_cost=instance_offer.price,
@@ -193,6 +194,7 @@ def run_job(
193194
resp = self.api_client.create_pod(
194195
name=pod_name,
195196
image_name=job.job_spec.image_name,
197+
container_registry_auth_id=container_registry_auth_id,
196198
gpu_type_id=instance_offer.instance.name,
197199
cloud_type=cloud_type,
198200
data_center_id=data_center_id,
@@ -212,18 +214,6 @@ def run_job(
212214

213215
instance_id = resp["id"]
214216

215-
# Call edit_pod to pass container_registry_auth_id.
216-
# Expect a long time (~5m) for the pod to pick up the creds.
217-
# TODO: remove editPod once Runpod's create mutations support docker's username/password
218-
# (or a reliable containerRegistryAuthId at create time).
219-
if container_registry_auth_id is not None:
220-
instance_id = self.api_client.edit_pod(
221-
pod_id=instance_id,
222-
image_name=job.job_spec.image_name,
223-
container_disk_in_gb=disk_size,
224-
container_registry_auth_id=container_registry_auth_id,
225-
)
226-
227217
if (
228218
self._last_cleanup_time is None
229219
or self._last_cleanup_time
@@ -316,13 +306,15 @@ def run_jobs(
316306
env={"RUNPOD_POD_USER": "0"},
317307
)
318308

319-
# An "edit pod" trick to pass container registry creds.
309+
# Unlike create mutations for individual pods, createCluster mutation doesn't accept
310+
# containerRegistryAuthId.
311+
# The workaround is to inject containerRegistryAuthId into already created pods.
312+
# Expect a long time (~5m) for the pods to pick up the creds.
313+
# TODO: remove once createCluster supports containerRegistryAuthId
320314
if container_registry_auth_id is not None:
321315
for pod in resp["pods"]:
322-
self.api_client.edit_pod(
316+
self.api_client.update_pod_container_registry_auth(
323317
pod_id=pod["id"],
324-
image_name=master_job.job_spec.image_name,
325-
container_disk_in_gb=disk_size,
326318
container_registry_auth_id=container_registry_auth_id,
327319
)
328320

0 commit comments

Comments
 (0)