Docker Repositories
This page covers using the Docker CLI with CloudRepo private Docker repositories.
Push, pull and build with Docker against a CloudRepo Docker repository. CloudRepo speaks the Docker
Registry HTTP API V2, so the Docker CLI needs nothing beyond docker login.
Before you start
Section titled “Before you start”- A Docker repository. If you have none, see Creating a Repository.
- A repository token that reaches it, with Read + write if you will push. See
Repository Tokens: Create One and Authenticate. Its
format is the Generic one, which starts with
crp_v1_. An npm-format token (crn_v1_) does not authenticate here. The password is the token, and the username is not checked: use your email address, as every other client does. - The Connection Settings of the repository show its image reference and ready-made CI snippets with your names filled in.
Connect Docker
Section titled “Connect Docker”1. Log in to the host. Pipe the token to docker login on standard input:
echo "$CLOUDREPO_TOKEN" | docker login your-org.mycloudrepo.io \ --username you@example.com \ --password-stdinExpected: Login Succeeded. To be prompted instead, run docker login your-org.mycloudrepo.io and
enter your email address and the token.
2. Build and push. The image reference carries the repository: the host, the literal
repositories/ segment, your repository, then the image and tag.
docker build -t your-org.mycloudrepo.io/repositories/your-repo/my-app:1.0.0 .docker push your-org.mycloudrepo.io/repositories/your-repo/my-app:1.0.0To push an image you already have, tag it with that reference first:
docker tag my-app:1.0.0 your-org.mycloudrepo.io/repositories/your-repo/my-app:1.0.03. Pull. The login you made applies. You logged in to the bare host, but you pull the
/repositories/ path:
docker pull your-org.mycloudrepo.io/repositories/your-repo/my-app:1.0.0Use Docker in CI
Section titled “Use Docker in CI”For GitHub Actions, GitLab CI, CircleCI, Jenkins, Buildkite and the like, keep the token in the
platform’s secret store, expose it as the environment variable CLOUDREPO_TOKEN, and use the same
login as above:
echo "$CLOUDREPO_TOKEN" | docker login your-org.mycloudrepo.io \ --username you@example.com \ --password-stdin--password-stdin is the Docker CLI’s option for reading the password from standard input instead of
the command line. Never commit the token to a repository. The variable name is yours to choose: the
admin portal’s ready-made GitHub Actions and GitLab CI snippets call it CLOUDREPO_PASSWORD, and the
value is the same repository token either way.
Install packages from CloudRepo in a Docker build
Section titled “Install packages from CloudRepo in a Docker build”When a docker build installs your private Maven, Python or npm packages from CloudRepo, the step
that downloads them needs your repository token. Give it to that step as a build secret, never as a
build argument: Docker records build arguments in the image’s history, so the token would travel with
the image. Docker’s documentation advises against build arguments for credentials. See
Build secrets.
Pass the username the same way. It is the email address of the account that created the token. Both values come from environment variables, so neither appears in the command:
docker build \ --secret id=cloudrepo_user,env=CLOUDREPO_USERNAME \ --secret id=cloudrepo,env=CLOUDREPO_TOKEN \ -t my-app .In the Dockerfile, mount the secrets on the RUN step that downloads packages. env=CLOUDREPO_TOKEN
sets that variable for that one step, and the client reads it from there. Keep the first line,
# syntax=docker/dockerfile:1: mounting a secret as a variable needs Dockerfile syntax 1.10 or
later, and that line fetches it for any Docker with BuildKit (the default builder since Docker
Engine 23).
Do not write the token into a file in that step: a file a RUN step leaves behind is part of the
image. The examples below keep the token in the variable and write only the variable’s name to disk.
If the variable is not set when you run docker build, Docker passes an empty secret rather than
failing, and the download step is refused as if the token were wrong.
Maven. A multi-stage build is the norm: the build stage has Maven and the JDK, and the runtime
stage gets only the jar. settings.xml names the variables, never their values, and Maven reads
${env.NAME} when it runs. The <id> must match the repository <id> in your pom.xml
(Repository Tokens: Create One and Authenticate shows
both files).
<settings> <servers> <server> <id>cloudrepo</id> <username>${env.CLOUDREPO_USERNAME}</username> <password>${env.CLOUDREPO_TOKEN}</password> </server> </servers></settings># syntax=docker/dockerfile:1FROM maven:3.9-eclipse-temurin-17 AS buildWORKDIR /appCOPY settings.xml /root/.m2/settings.xmlCOPY pom.xml .COPY src ./srcRUN --mount=type=secret,id=cloudrepo_user,env=CLOUDREPO_USERNAME \ --mount=type=secret,id=cloudrepo,env=CLOUDREPO_TOKEN \ mvn -B package -DskipTests
FROM eclipse-temurin:17-jreCOPY --from=build /app/target/*.jar /app/app.jarENTRYPOINT ["java", "-jar", "/app/app.jar"]pip. pip takes the credential inside the index URL. Set PIP_INDEX_URL for pip in the RUN step
itself, so the URL exists only for that command. CLOUDREPO_USERNAME is the plain email address: pip
splits the credential from the host at the last @, so the one in the email needs no %40 here.
# syntax=docker/dockerfile:1FROM python:3.12-slimWORKDIR /appCOPY requirements.txt .RUN --mount=type=secret,id=cloudrepo_user,env=CLOUDREPO_USERNAME \ --mount=type=secret,id=cloudrepo,env=CLOUDREPO_TOKEN \ PIP_INDEX_URL="https://${CLOUDREPO_USERNAME}:${CLOUDREPO_TOKEN}@your-org.mycloudrepo.io/repositories/your-repo/simple/" \ pip install --no-cache-dir -r requirements.txtCOPY . .CMD ["python", "app.py"]npm. npm sends the token on its own, so it needs only the cloudrepo secret. The project’s
.npmrc names the variable, and npm reads it when it runs:
registry=https://your-org.mycloudrepo.io/repositories/your-repo///your-org.mycloudrepo.io/repositories/your-repo/:_authToken=${CLOUDREPO_TOKEN}# syntax=docker/dockerfile:1FROM node:22-slimWORKDIR /appCOPY package.json package-lock.json .npmrc ./RUN --mount=type=secret,id=cloudrepo,env=CLOUDREPO_TOKEN \ npm ciCOPY . .CMD ["node", "index.js"]What the registry does not serve
Section titled “What the registry does not serve”/v2/_catalog is not implemented and answers 405 UNSUPPORTED. Use the admin portal to see what a
repository holds.
Troubleshooting
Section titled “Troubleshooting”docker login returns 401 Unauthorized
- Use the repository token as the password, not your admin-portal password.
- Check on the Repository Tokens page that the token has not been revoked or expired.
docker push returns 403 Forbidden after a successful login
- The token cannot write to the repository. Pushing needs a Read + write token, and the user who created the token needs read and write access, not read only. Check the token’s scope on the Repository Tokens page.
docker push or docker pull cannot find the repository
- Check the reference carries the literal
repositories/segment:<org>.mycloudrepo.io/repositories/<repo>/<image>:<tag>. Omitting it is the most common mistake, becausedocker logindoes not use it, so a successful login cannot warn you that the reference is malformed.
Group Docker repositories
Section titled “Group Docker repositories”A group repository is a single address that resolves against several member repositories in a priority order you set. It gives a team one registry URL that serves images kept in more than one repository.
Create it in the admin portal with Docker as the format and Group as the kind, then add member repositories and order them. On a pull, CloudRepo tries each member in priority order and serves the first that has the image.
A group is addressed exactly like a local repository, with the same host and the same repositories/
segment:
docker pull your-org.mycloudrepo.io/repositories/team-registry/my-app:1.0.0A typical arrangement is one address for developers and two repositories behind it: app-images
holding what your team builds, and vendor-images holding third-party images you have vetted and
pushed yourself. Group team-registry lists them in that order, and developers configure one host
and one repository name.
Docker repository settings
Section titled “Docker repository settings”Other settings
Section titled “Other settings”All Standard Settings apply.