How To Fix CircleCI DockerHub Too Many Requests Errors
Beginning November 1, 2020, DockerHub will begin rate-limiting anonymous image pulls from DockerHub.
Rate-limiting anonymous DockerHub access is a significant change that will impact many continuous integrations built on platforms like CircleCI, Semaphore, and more.
How to Fix the Problem
To work around the rate limit, you’ll need to authenticate with DockerHub in a few places.
- Create a DockerHub user if you don’t already have one. You can sign up for DockerHub here.
- Decide if you need a paid plan. Free users get up to 200 image pulls every six hours. If you’re working for an organization with many builds, you’ll want to upgrade to at least the “Pro” Plan, which, when paid annually, costs $5/month and allows for unlimited image pulls.
-
Create a DockerHub access token. This token is how you’ll authenticate your build’s Docker image pulls. Visit the security settings page and create a new access token. Give it a description like “CircleCI”.
-
Create a CircleCI context for DockerHub. You’ll use this context to store your new DockerHub access token safely. Call the context
dockerhub
, then create a new environment variable calledDOCKERHUB_ACCESS_TOKEN
. Paste the access token you generated in the previous step. - Update your CircleCI configurations. The next sections describe how to authenticate the different types of CircleCI builds:
Updating docker
executors
If you’re using the CircleCI docker
executor, you’ll
need to authenticate the initial docker image pull.
Your unauthenticated CircleCI configuration (.circleci/config.yml
) will look something like this:
version: 2.1
workflows:
version: 2
default:
jobs:
- build
- deploy
jobs:
build:
docker:
- image: circleci/node:latest
steps:
- checkout
- run: echo 'hello world'
deploy:
docker:
- image: circleci/node:latest
steps:
- checkout
- run: echo 'hello world'
You need to authenticate the pull of circleci/node:latest
by authenticating using the access token you created in the
steps above. To do this, add the dockerhub
context and an auth
object to your docker image definition. Your
configuration will look something like this:
version: 2.1
workflows:
version: 2
default:
jobs:
- build:
# ADDED
context: dockerhub
- deploy:
# ADDED
context: dockerhub
jobs:
build:
docker:
- image: circleci/node:latest
# ADDED
auth:
username: your-dockerhub-username
password: $DOCKERHUB_ACCESS_TOKEN
steps:
- checkout
- run: echo 'hello world'
deploy:
docker:
- image: circleci/node:latest
# ADDED
auth:
username: your-dockerhub-username
password: $DOCKERHUB_ACCESS_TOKEN
steps:
- checkout
- run: echo 'hello world'
Updating docker
executors with setup_remote_docker
If you’re using setup_remote_docker
with your
docker
executor, you also need to rerun a docker login command to authenticate the remote docker instance.
Your unauthenticated CircleCI configuration (.circleci/config.yml
) will look something like this:
version: 2.1
workflows:
version: 2
default:
jobs:
- build
jobs:
build:
docker:
- image: circleci/node:latest
steps:
- checkout
- setup_remote_docker
- run: docker run somecontainer
You’ll need to add the context
and auth
object, as you did above, but you’ll also need to run a docker login
in
your steps
before interacting with docker
.
version: 2.1
workflows:
version: 2
default:
jobs:
- build:
# ADDED
context: dockerhub
jobs:
build:
docker:
- image: circleci/node:latest
# ADDED
auth:
username: your-dockerhub-username
password: $DOCKERHUB_ACCESS_TOKEN
steps:
- checkout
- setup_remote_docker
# ADDED
- run: docker login --username your-dockerhub-username --password $DOCKERHUB_ACCESS_TOKEN
- run: docker run somecontainer
Updating machine
Executors
If you’re using CircleCI’s machine
executor, you only
need to authenticate using docker login
in your job’s steps
.
Your unauthenticated CircleCI configuration (.circleci/config.yml
) will look something like this:
version: 2.1
workflows:
version: 2
default:
jobs:
- build
jobs:
build:
machine:
- image: ubuntu-1604:202007-01
steps:
- checkout
- run: docker run somecontainer
You’ll need to add your dockerhub
context and run a docker login
in your steps
before interacting with docker
.
version: 2.1
workflows:
version: 2
default:
jobs:
- build:
# ADDED
context: dockerhub
jobs:
build:
machine:
- image: ubuntu-1604:202007-01
steps:
- checkout
# Added
- run: docker login --username your-dockerhub-username --password $DOCKERHUB_ACCESS_TOKEN
- run: docker run somecontainer
Reducing Duplication
You can use YAML’s merge feature to reduce duplication in your configuration file.
Instead of duplicating the auth
parameter in each of your jobs, reuse the code like this:
version: 2.1
# Named YAML Block
docker-auth: &docker-auth
auth:
username: your-dockerhub-username
password: $DOCKERHUB_AUTH_TOKEN
workflows:
version: 2
default:
jobs:
- build:
context: dockerhub
- deploy:
context: dockerhub
jobs:
build:
docker:
- image: "circleci/node:latest"
# Reused YAML
<<: *docker-auth
steps:
- checkout
- run: echo 'hello world'
deploy:
docker:
- image: "circleci/node:latest"
# Reused YAML
<<: *docker-auth
steps:
- checkout
- run: echo 'hello world'
Resources
For more information, check out: