Proxy Docker images via GitLab
Brett Weir, December 28, 2022
Docker Hub rate limits container image pulls. These limits are easy to hit in a CI environment. This is especially likely if your CI environment is behind a NAT firewall. Thus, it is very important to enable a container proxy to ensure continuity of your CI service.
GitLab's Dependency Proxy feature allows you to proxy Docker Hub containers through GitLab.
CONTAINER_PROXY
variable
It is highly recommended to NOT use GitLab's built-in dependency proxy variables directly. These are:
-
CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX
-
CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX
-
CI_DEPENDENCY_PROXY_PASSWORD
-
CI_DEPENDENCY_PROXY_USER
This is for the following reasons:
-
The registries that these values point to change depending on your project's location, resulting in duplication of cached images.
-
All users must be granted a group-level role to use the dependency proxy, so it may be a good idea to create a dedicated group for this purpose.
-
You may want to change your proxy location some day, for example if your company decides to host its own Docker Hub proxy, move from GitLab Cloud to self-hosted, or any other reason.
The BrettOps container pipeline takes an alternative approach, and defines a layer of indirection for all of the above, as follows:
# registry
CONTAINER_PROXY: "${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/"
# registry with port number
CONTAINER_PROXY_SERVER: "${CI_DEPENDENCY_PROXY_SERVER}"
# registry password
CONTAINER_PROXY_PASSWORD: "${CI_DEPENDENCY_PROXY_PASSWORD}"
# registry username
CONTAINER_PROXY_USER: "${CI_DEPENDENCY_PROXY_USER}"
Add a forward slash
You would think, and most documentation would suggest, that an appropriate way to use a container proxy is like so:
${MY_PROXY}/my-container:latest
Not so fast! What happens if ${MY_PROXY}
is not defined? This happens more
often than you might think. You'll spend a good chunk of time setting up your CI
pipeline to work perfectly with all the proxy variables tightly configured. In
the meantime, you'll forget that once upon a time, you needed to build this
image locally, and the next time you try doing this, you'll stumble over setting
up the environment variables properly for a local build.
Nobody needs that. By adding a single forward slash to the variable value, you make it optional! At this point, building locally is no longer a problem.
This is why the container
pipeline defines the CONTAINER_PROXY
variable to equal the following default:
${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/
Log in to the registry
Before you can use the proxy registry to build new containers, you must authenticate. Don't spin cycles trying to debug a failing pipeline because you forgot to log in!
The following one-liner is the most succinct method I've found for Docker login in a CI pipeline.
echo "$CONTAINER_PROXY_PASSWORD" | docker login "$CONTAINER_PROXY_SERVER" -u "$CONTAINER_PROXY_USER" --password-stdin
This is much easier than trying to inject a complete config.json
into a CI
environment, as these commands can stack if you discover you need access to more
registries:
echo "$CONTAINER_PROXY_PASSWORD" | docker login "$CONTAINER_PROXY_SERVER" -u "$CONTAINER_PROXY_USER" --password-stdin
echo "$CONTAINER_PROXY_2_PASSWORD" | docker login "$CONTAINER_PROXY_2_SERVER" -u "$CONTAINER_PROXY_2_USER" --password-stdin
echo "$CONTAINER_PROXY_NEW_PASSWORD" | docker login "$CONTAINER_PROXY_NEW_SERVER" -u "$CONTAINER_PROXY_NEW_USER" --password-stdin
# ...
Create a proxy group
GitLab declares the following two proxy registry variables:
-
CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX
- The top-level group. -
CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX
- The direct group that your project lives in.
Both of these are not ideal. If your organization has any kind of nesting in its GitLab group structure, you probably also have users that have direct access to some groups and not others, or users who have access to projects, but not to the groups that contain those projects.
GitLab users must have Guest privilege directly attached to a group to use the proxy registry of that group. This is an easy one to get bit by, so watch out.
Use the pipeline
The container pipeline is already configured to work the way that you expect. CONTAINER_PROXY is always defined when the pipeline is included, though it is still recommended to declare it globally in your GitLab group.