Kubernetes Job and Service resource bases

Overview

Kubernetes resource bases allow administrators to customize the Job and Service resources that Connect creates for off-host execution. A resource base is similar to a Kustomize “base”

Resource bases are YAML definitions that serve as a base, which Connect then merges with its runtime configuration to produce the final Kubernetes resources. Connect applies job runtime values on top of the resource base definition.

For example, the following configurations can be applied to the Job resource base, just like any other Kubernetes Job:

  • image pull secrets
  • security context customizations (like fsGroup)
  • node selectors and (anti-)affinity rules
  • volumes and volume mounts
  • tolerations and priority classes
  • topology spread constraints

These resource base configurations are currently applied to all content that Connect executes on Kubernetes. Applying different resource bases for individual content items, execution environments, or content types is not currently supported.

Connect preserves most resource base fields while selectively overriding specific fields it needs to control for correct execution.

Configuration

Resource bases are configured in the Connect configuration and provided via Helm chart values. The defaultResourceJobBase configuration is entirely optional and only necessary if you wish to modify the content jobs that Connect submits to Kubernetes at runtime.

The following example:

  • Sets the nodeSelector for all jobs
  • Adds an initContainer to configure a cache volume for all jobs
  • Adds a fluent-bit logging sidecar container
  • Modifies the connect-content container to mount and configure the cache volume

Note that the connect-content container and the connect-content-init initContainer are reserved. Some parts of these containers can be modified, but Connect uses these containers to execute your content and some modifications may be overwritten by Connect. The full set of fields that Connect uses are enumerated below.

backends:
  kubernetes:
    enabled: true
    defaultResourceJobBase:
      apiVersion: batch/v1
      kind: Job
      spec:
        template:
          spec:
            nodeSelector:
              workload: rstudio-connect
            initContainers:
            - name: setup-cache
              image: busybox:1.36
              command: ['sh', '-c', 'mkdir -p /cache && chmod 777 /cache']
              volumeMounts:
              - name: cache-volume
                mountPath: /cache
            containers:
            - name: log-shipper
              image: fluent/fluent-bit:2.1
              env:
              - name: LOG_LEVEL
                value: info
              - name: OUTPUT_HOST
                value: logging-service.default.svc.cluster.local
              volumeMounts:
              - name: shared-logs
                mountPath: /var/log
            - name: connect-content
              env:
              - name: CACHE_DIR
                value: /cache
              volumeMounts:
              - name: cache-volume
                mountPath: /cache
            volumes:
            - name: cache-volume
              emptyDir:
                sizeLimit: 1Gi
            - name: shared-logs
              emptyDir: {}

Example: Injecting Certificate Authority (CA) certificates into content pods

When your Connect server uses a self-signed or internal CA certificate, content jobs running on Kubernetes need access to that CA bundle to make HTTPS requests back to Connect or other internal services.

Use a ConfigMap to store the CA bundle and mount it into content pods via the resource base. The following Helm values configuration creates the ConfigMap and configures all content jobs to mount and trust the certificate:

extraObjects:
  - apiVersion: v1
    kind: ConfigMap
    metadata:
      name: connect-content-ca-bundle
    data:
      ca-bundle.crt: |
        -----BEGIN CERTIFICATE-----
        <your CA certificate here>
        -----END CERTIFICATE-----

backends:
  kubernetes:
    enabled: true
    defaultResourceJobBase:
      apiVersion: batch/v1
      kind: Job
      spec:
        template:
          spec:
            volumes:
              - name: ca-bundle
                configMap:
                  name: connect-content-ca-bundle
            containers:
              - name: connect-content
                volumeMounts:
                  - name: ca-bundle
                    mountPath: /etc/ssl/certs/connect-ca-bundle.crt
                    subPath: ca-bundle.crt
                    readOnly: true
                env:
                  - name: REQUESTS_CA_BUNDLE
                    value: /etc/ssl/certs/connect-ca-bundle.crt
                  - name: SSL_CERT_FILE
                    value: /etc/ssl/certs/connect-ca-bundle.crt
                  - name: CURL_CA_BUNDLE
                    value: /etc/ssl/certs/connect-ca-bundle.crt
                  - name: NODE_EXTRA_CA_CERTS
                    value: /etc/ssl/certs/connect-ca-bundle.crt

The environment variables configure different runtimes to use the CA bundle:

Variable Runtime
REQUESTS_CA_BUNDLE Python (requests, httpx)
SSL_CERT_FILE Python (standard library ssl), Go, general OpenSSL
CURL_CA_BUNDLE R (curl/httr/httr2)
NODE_EXTRA_CA_CERTS Node.js (Quarto, JavaScript content)

Include all four variables to cover all content types. You can omit variables for runtimes you do not use.

Note

For production deployments, consider using a Kubernetes Secret instead of a ConfigMap if your CA bundle is sensitive. Replace configMap with secret and name with secretName in the volume definition.

How Merging Works

When you specify a resource base, Connect loads it and then applies its runtime values according to the behavior rules below.

Example: Merged labels

Your job base:

apiVersion: batch/v1
kind: Job
metadata:
  labels:
    my-company.com/cost-center: "engineering"
    my-company.com/team: "data-science"

Connect’s runtime labels:

- posit.co/content-guid: "abc-123"
- posit.co/execution-id: "xyz-789"

Final merged Job (precedence: connect-overrides):

metadata:
  labels:
    my-company.com/cost-center: "engineering"      # from base
    my-company.com/team: "data-science"            # from base
    posit.co/content-guid: "abc-123"               # from Connect
    posit.co/execution-id: "xyz-789"               # from Connect

If your base also specifies posit.co/content-guid, Connect’s value wins.

Field Behavior Categories

  • cannot-override: Connect must control these fields for correct execution (resource base values ignored)
  • merged: Resource base and Connect values are combined (Connect wins on conflicts)
  • appended: Connect adds to resource base values (both preserved)
  • conditionally-set: Connect sets a default only if resource base doesn’t specify

Precedence Values

  • connect-overrides: Connect values override resource base values when names conflict (used for merged maps)
  • connect-appended: Connect values added after resource base values (used for appended lists)

Service Account Configuration

When using custom service accounts in your resource base, they must be labeled for Connect to use them:

kubectl label serviceaccount <service-account-name> connect.posit.co/service-account=true -n <namespace>

Without this label, Connect ignores the service account and falls back to the namespace default. This applies to service accounts specified in: - Job resource base (spec.template.spec.serviceAccountName) - Content-level service account configuration applied via the v1/content api field service_account_name

Job resource base fields

These fields describe how Connect merges your job resource base with its runtime configuration when creating Kubernetes Jobs.

metadata.name

Behavior: cannot-override
Reason: Connect generates unique Job names via generateName

metadata.generateName

Behavior: cannot-override
Reason: Connect sets name prefix based on content name

metadata.namespace

Behavior: cannot-override
Reason: Connect controls Job namespace from configuration

spec.template.spec.serviceAccountName

Behavior: conditionally-set
Reason: Connect selects valid service account: content-specified > job-base-specified > namespace default. All service accounts must have the connect.posit.co/service-account label

spec.template.spec.securityContext.runAsUser

Behavior: cannot-override
Reason: Connect sets user ID depending on the configured RunAs user

spec.template.spec.securityContext.runAsGroup

Behavior: cannot-override
Reason: Connect sets group ID from shared group configuration

spec.template.spec.securityContext.supplementalGroups

Behavior: cannot-override
Reason: Connect sets supplemental groups from the effective RunAs user’s group memberships

metadata.annotations

Behavior: merged
Precedence: connect-overrides
Reason: Job base annotations kept unless Connect provides the same key, then Connect value wins

metadata.labels

Behavior: merged
Precedence: connect-overrides
Reason: Job base labels kept unless Connect provides the same key, then Connect value wins

spec.template.metadata.annotations

Behavior: merged
Precedence: connect-overrides
Reason: Job base pod annotations kept unless Connect provides the same key, then Connect value wins

spec.template.metadata.labels

Behavior: merged
Precedence: connect-overrides
Reason: Job base pod labels kept unless Connect provides the same key, then Connect value wins

spec.backoffLimit

Behavior: cannot-override
Reason: Connect sets to 0 (never retry failed jobs)

spec.parallelism

Behavior: cannot-override
Reason: Connect requires parallelism=1 for correct execution tracking

spec.template.spec.restartPolicy

Behavior: cannot-override
Reason: Jobs must not restart to ensure proper cleanup and status tracking

spec.ttlSecondsAfterFinished

Behavior: conditionally-set
Reason: Connect defaults to 300 seconds (5 minutes) if unset by job base

spec.template.spec.volumes

Behavior: appended
Precedence: connect-appended
Reason: Connect appends content-specific volumes (with “connect-” prefix) to job base volumes

spec.template.spec.containers[name=connect-content].image

Behavior: cannot-override
Reason: Connect sets image from content bundle

spec.template.spec.containers[name=connect-content].workingDir

Behavior: cannot-override
Reason: Connect sets working directory from content configuration

spec.template.spec.containers[name=connect-content].command

Behavior: cannot-override
Reason: Connect sets command from content execution requirements

spec.template.spec.containers[name=connect-content].args

Behavior: cannot-override
Reason: Connect sets args from content execution requirements

spec.template.spec.containers[name=connect-content].ports

Behavior: cannot-override
Reason: Connect sets ports from content exposed ports configuration

spec.template.spec.containers[name=connect-content].stdin

Behavior: cannot-override
Reason: Connect requires stdin=true for content input forwarding

spec.template.spec.containers[name=connect-content].stdinOnce

Behavior: cannot-override
Reason: Connect requires stdinOnce=true for content input forwarding

spec.template.spec.containers[name=connect-content].securityContext.runAsUser

Behavior: cannot-override
Reason: Cleared to use pod-level security context (includes supplemental groups)

spec.template.spec.containers[name=connect-content].securityContext.runAsGroup

Behavior: cannot-override
Reason: Cleared to use pod-level security context (includes supplemental groups)

spec.template.spec.containers[name=connect-content].env

Behavior: merged
Precedence: connect-overrides
Reason: Job base env vars kept except where Connect defines the same name, then Connect value wins

spec.template.spec.containers[name=connect-content].resources.limits

Behavior: merged
Precedence: connect-overrides
Reason: Job base resources preserved, Connect resources override

spec.template.spec.containers[name=connect-content].resources.requests

Behavior: merged
Precedence: connect-overrides
Reason: Job base resources preserved, Connect resources override

spec.template.spec.containers[name=connect-content].volumeMounts

Behavior: appended
Precedence: connect-appended
Reason: Connect appends content-specific volume mounts to job base mounts

Service resource base fields

These fields describe how Connect merges your service resource base with its runtime configuration when creating Kubernetes Services.

metadata.name

Behavior: cannot-override
Reason: Connect sets name to match Job name for lifecycle management

metadata.namespace

Behavior: cannot-override
Reason: Connect controls Service namespace from configuration

metadata.annotations

Behavior: merged
Precedence: connect-overrides
Reason: Service base annotations kept unless Connect provides the same key, then Connect value wins

metadata.labels

Behavior: merged
Precedence: connect-overrides
Reason: Service base labels kept unless Connect provides the same key, then Connect value wins

metadata.ownerReferences

Behavior: cannot-override
Reason: Connect sets owner reference to Job for automatic garbage collection

spec.selector

Behavior: cannot-override
Reason: Connect sets selector to match Job pods for correct routing

spec.type

Behavior: conditionally-set
Reason: Connect defaults to ClusterIP if unset by service base. Assumes that Connect is running in the same kubernetes cluster as the content

spec.ports

Behavior: appended
Precedence: connect-appended
Reason: Connect appends ports from content exposed ports configuration