# Docker and Helm

> Pull container images, Helm charts and other OCI files with Docker, Podman, Helm and ORAS, and push them with the credential helper of the CLI.

Source: https://docs.telesphorepo.com/docker/

This page sets up Docker, Podman and Helm to pull images and charts from Telesphorepo. Pushing is publishing: Docker pushes through the credential helper of the CLI, so its steps are here, under [Push an image from your computer](#push-an-image-from-your-computer) and [Push an image from CI](#push-an-image-from-ci). [Install the CLI](/install-cli/) first. A Helm chart folder publishes as in [Publish from a project](/publish-from-a-project/), under Publish your packages.

An admin first makes a repository with the format **Docker** (see [Make a Docker repository](/repositories-and-access/#make-a-docker-repository)). The name of the repository is the first part of the image name:

```text
repo.example.com/docker/team/app:1.0
```

Here `repo.example.com` is the server, `docker` is the repository, and `team/app:1.0` is the image and its tag. Put your own values in the commands below. The **Use this repository** tab of the repository shows the same commands with your values.

## Pull an image

- Docker

  ```sh
  docker pull repo.example.com/docker/team/app:1.0
  ```

- Podman

  ```sh
  podman pull repo.example.com/docker/team/app:1.0
  ```

- Helm

  ```sh
  helm pull oci://repo.example.com/docker/mychart --version 0.1.0
  ```

Anyone can pull from a public repository. For a private repository, make a read token and log in once:

1. Open **Settings** › **Tokens**, and click **New read token**.

2. Log in. Paste the token at the hidden prompt.

   ```sh
   printf 'Read token: '; read -rs READ_TOKEN; echo
   printf '%s' "$READ_TOKEN" | docker login repo.example.com -u YOUR_USERNAME --password-stdin
   ```

Helm and ORAS read the same login. With Podman, run `podman login` in place of `docker login`.

A repository can also be a **proxy** of Docker Hub, GitHub Container Registry or Quay. Pull from it in the same way. The server keeps a copy of each image that people pull.

## Push an image from your computer

You do this once for each computer. The Telesphorepo CLI has a credential helper for Docker.

1. Open the Docker repository in the web UI, then the **Publish to this repository** tab.

2. Click **Set up a project**, and confirm with your second factor.

3. Copy the line for your system. Paste it in a terminal, then press Enter.

   ```sh
   curl -fsSL https://repo.example.com/install.sh | sh -s -- setup 'https://repo.example.com/#/setup/trsu_...'
   ```

   The line installs the CLI and approves this computer. It works once, for 10 minutes.

4. The CLI asks `Add the credential helper to ~/.docker/config.json? [y/N]`. Type `y`.

   The CLI adds one entry under `credHelpers` for the server, and keeps every other entry.

5. Push.

   ```sh
   docker tag app repo.example.com/docker/team/app:1.0
   docker push repo.example.com/docker/team/app:1.0
   ```

Done when `docker push` prints the digest of the image.

Behind Cloudflare (Free and Pro plans), each image layer must be under 100 MB. Pulls have no limit. For larger layers, see [Push large images](/run-the-server/#push-large-images).

After step 4, you do not run `docker login`. Docker, buildx, Podman, Helm and ORAS ask the helper for a token. Each push gets its own token for one repository, and the token ends within 15 minutes. An approval lasts 90 days, unless someone removes the device.

To push a Helm chart:

```sh
helm push mychart-0.1.0.tgz oci://repo.example.com/docker
```

A chart folder can also publish with the CLI. Run the setup line in the folder that holds `Chart.yaml`. The CLI writes `telesphorepo.toml`. Then `telesphorepo publish` packages the chart and pushes it.

Add the helper by hand

Install the CLI, and approve the computer:

```sh
curl -fsSL https://repo.example.com/install.sh | sh
telesphorepo login https://repo.example.com
```

Add this entry to `~/.docker/config.json`:

```json title="~/.docker/config.json"
{
  "credHelpers": {
    "repo.example.com": "telesphorepo"
  }
}
```

`telesphorepo logout` removes the entry and the approval of the computer.

Push with a publish token, with no helper

1. Open **Settings** › **Tokens**, and click **New publish token**. Choose the repository, then confirm with your second factor.

2. Log in with the token, push, and log out. Paste the token at the hidden prompt.

   ```sh
   printf 'Publish token: '; read -rs TOKEN; echo
   printf '%s' "$TOKEN" | docker login repo.example.com -u publish --password-stdin
   docker push repo.example.com/docker/team/app:1.0
   docker logout repo.example.com
   ```

A publish token works for the time of its session, 15 minutes by default. The push must end within that time. A password or a read token cannot push.

## Push an image from CI

The credential helper of the CLI trades the identity token of the CI job for a publish token at each push. The job runs no `docker login`. An admin adds a CI pipeline for the job first, as in [Publish from CI](/publish-from-ci/#ask-for-a-ci-pipeline). The job needs Docker. The **Publish to this repository** tab shows the same files with your values.

- GitHub Actions

  ```yaml title=".github/workflows/publish.yml"
  on:
    push:
      branches: ["main"]

  permissions:
    id-token: write
    contents: read

  jobs:
    publish:
      runs-on: ubuntu-latest
      steps:
        - uses: actions/checkout@v7
        - run: docker build -t "repo.example.com/docker/app:$GITHUB_SHA" .
        - run: curl -fsSL https://repo.example.com/install.sh | sh
        - name: Publish to docker
          run: |
            export DOCKER_CONFIG="$(mktemp -d)"
            printf '%s\n' '{"credHelpers":{"repo.example.com":"telesphorepo"}}' > "$DOCKER_CONFIG/config.json"
            docker push "repo.example.com/docker/app:$GITHUB_SHA"
          env:
            TELESPHOREPO_SERVER: "https://repo.example.com"
  ```

- Jenkins

  ```groovy title="Jenkinsfile"
  pipeline {
    agent any
    stages {
      stage('Build') {
        steps {
          sh 'docker build -t "repo.example.com/docker/app:${GIT_COMMIT:-$BUILD_NUMBER}" .'
        }
      }
      stage('Publish to docker') {
        steps {
          withEnv(['TELESPHOREPO_SERVER=https://repo.example.com']) {
            // The token is good for 10 minutes, so only this stage gets it.
            withCredentials([string(credentialsId: 'telesphorepo-id-token', variable: 'OIDC_TOKEN')]) {
              sh '''
                curl -fsSL https://repo.example.com/install.sh | sh
                export PATH="$HOME/.local/bin:$PATH"
                export DOCKER_CONFIG="$(mktemp -d)"
                printf '%s\\n' '{"credHelpers":{"repo.example.com":"telesphorepo"}}' > "$DOCKER_CONFIG/config.json"
                docker push "repo.example.com/docker/app:${GIT_COMMIT:-$BUILD_NUMBER}"
              '''
            }
          }
        }
      }
    }
  }
  ```

  The Jenkins credential `telesphorepo-id-token` comes from the plugin **OpenID Connect Provider**, with the audience `https://repo.example.com`.

Change `app` to the name of your image. The identity token of CI pulls public images only. To build from a private image, log in with a read token before the build.

## If something goes wrong

`name unknown` or `404` on a push or a pull

Name an image inside the repository: `repo.example.com/docker/team/app`, not `repo.example.com/docker`.

`publishing needs a publish session`

You logged in with a password or a read token. These cannot push. Use the credential helper, a publish token or CI.

`denied` or `403` on a push

You cannot publish to this repository yet. Ask your server admin for **Publish**.

The push stops with `413` or a timeout on a large layer

Behind Cloudflare (Free and Pro plans), each layer must be under 100 MB. Ask your admin to turn on direct uploads. You keep the same commands. See [Push large images](/run-the-server/#push-large-images).

ORAS or Helm says the upload `Location` is on a different host

Your admin turned on direct uploads. Push with ORAS and Helm to the upload address, for example `helm push mychart-0.1.0.tgz oci://upload.example.com/docker`. The **Use this repository** tab shows the right address.

The push says the token ended

The push took longer than the publish session. Ask your admin to raise **publish.session_ttl**, up to one hour.

Docker cannot reach an `http://` server

Add the host to `insecure-registries` in `/etc/docker/daemon.json`, or serve the server over HTTPS.

You lost a laptop

Open **Settings** › **Devices** and revoke that laptop. To remove the key from a computer that you still have, run `telesphorepo logout`.

`credentials not found in native keychain` on a push

The computer has no approval for this server, or the approval ended. Run `telesphorepo login https://repo.example.com`, then push again.

The CI push says that the helper has no credential

Check `id-token: write` in the workflow, or the `OIDC_TOKEN` binding in Jenkins. `TELESPHOREPO_SERVER` must be the address of your server.

The registry must be at the root of a host

Docker cannot use an address with a path, such as `https://example.com/repo`. Give the server its own host name.
