Configuring the Playground Registry

Protecting the registry with credentials

Every playground run gets a private container registry at registry.iximiuz.com - see Playground Container Registry for the user-facing overview (what it is, how to push and pull, what its limits are). This lesson covers the author's side: what can be configured and why you may want to.

There is exactly one knob - the registry's credentials. Out of the box, the registry accepts anonymous pushes and pulls; setting registryAuth puts it behind a single username:password pair, after which every request (pull, push, catalog listing) has to be authenticated.

Where to set it

In the playground manifest, registryAuth is a top-level attribute of the playground section:

manifest.yaml
kind: playground
name: private-registry-lab
title: Private Registry Lab
playground:
  registryAuth: acme:s3cr3t
  machines:
    - name: dev-01
      users:
        - name: laborant
          default: true
      drives:
        - source: docker
          mount: /
      network:
        interfaces:
          - network: local
  accessControl:
    canList:
      - owner
    canRead:
      - owner
    canStart:
      - owner
labctl playground create private-registry-lab --base flexbox -f manifest.yaml

The value must contain exactly one colon separating the username from the password (so neither part can contain a :). Leaving the attribute out (or empty) keeps the registry anonymous.

The same setting is available in the Playground Constructor UI: open the playground's settings page (add /settings to its URL), switch to the Registry tab, and fill in the Username:Password field.

Challenges, tutorials, and course lessons that embed a playground can set the attribute in their own playground block, e.g.:

index.md (front matter)
kind: challenge
title: 'Docker 101: Authenticate to Private Container Registries'
playground:
  name: docker
  registryAuth: iximiuzlabs:rules!

What the credentials are (not) hidden from

registryAuth is part of the playground manifest and is returned only to the playground owner (it's stripped from what other users see). However, the credentials are as private as you make them inside the VMs: a docker login performed in an init task leaves them in ~/.docker/config.json, and an init task's script itself can be visible to a curious learner. Treat them as scenario data rather than secrets.

There is only one account per registry - no read-only users, no per-repository permissions.

Pre-populating the registry and using it in tasks

Seeding images at startup

The registry starts empty with every playground run - including restarts of stopped playgrounds and runs of playgrounds saved from a stopped run. If your scenario expects certain images to be in the registry (as opposed to in the VM's image store), push them from an init task. crane and regctl are preinstalled in the Docker and Kubernetes base images, and copying straight from a public registry avoids the pull-then-push detour through the local daemon:

  initTasks:
    init_seed_registry:
      init: true
      machine: dev-01
      user: laborant
      timeout_seconds: 120
      run: |
        # The registry starts in parallel with the VMs - wait until it answers.
        until curl -s -o /dev/null https://registry.iximiuz.com/v2/; do sleep 1; done

        crane copy ghcr.io/iximiuz/labs/nginx:alpine registry.iximiuz.com/acme/web:v1
        crane copy ghcr.io/iximiuz/labs/alpine:3 registry.iximiuz.com/acme/base:latest
        crane tag registry.iximiuz.com/acme/web:v1 stable

If the registry is protected, log in first (the credentials will end up in the task user's ~/.docker/config.json - see the previous unit):

  initTasks:
    init_registry_login:
      init: true
      machine: dev-01
      user: laborant
      run: |
        until curl -s -o /dev/null https://registry.iximiuz.com/v2/; do sleep 1; done
        crane auth login registry.iximiuz.com -u acme -p 's3cr3t'
        docker login registry.iximiuz.com -u acme -p 's3cr3t'

For images that should be available locally on a machine (not in the registry), prefer baking them into a custom rootfs - that's faster than pulling at startup and survives stop/restart cycles.

Multi-machine and Kubernetes playgrounds

The registry is shared by all machines of a playground, which makes it the natural hand-off point in "build here, deploy there" setups: a dev machine with Docker builds and pushes, and the cluster nodes pull - no image export/import, no per-node loading. Nothing needs to be configured on the Kubernetes side: the registry's certificate is publicly trusted and the name resolves on every node.

Keep the reachability rules in mind when designing network topologies: a machine attached only to private: true networks has no route to the registry.