forked from TrueCloudLab/distribution
0a7648edb5
The registry docker image no longer contains htpasswd.
573 lines
20 KiB
Markdown
573 lines
20 KiB
Markdown
---
|
|
description: Explains how to deploy a registry
|
|
keywords: registry, on-prem, images, tags, repository, distribution, deployment
|
|
title: Deploy a registry server
|
|
---
|
|
|
|
{% include registry.md %}
|
|
|
|
Before you can deploy a registry, you need to install Docker on the host.
|
|
A registry is an instance of the `registry` image, and runs within Docker.
|
|
|
|
This topic provides basic information about deploying and configuring a
|
|
registry. For an exhaustive list of configuration options, see the
|
|
[configuration reference](configuration.md).
|
|
|
|
If you have an air-gapped datacenter, see
|
|
[Considerations for air-gapped registries](#considerations-for-air-gapped-registries).
|
|
|
|
## Run a local registry
|
|
|
|
Use a command like the following to start the registry container:
|
|
|
|
```bash
|
|
$ docker run -d -p 5000:5000 --restart=always --name registry registry:2
|
|
```
|
|
|
|
The registry is now ready to use.
|
|
|
|
> **Warning**: These first few examples show registry configurations that are
|
|
> only appropriate for testing. A production-ready registry must be protected by
|
|
> TLS and should ideally use an access-control mechanism. Keep reading and then
|
|
> continue to the [configuration guide](configuration.md) to deploy a
|
|
> production-ready registry.
|
|
|
|
## Copy an image from Docker Hub to your registry
|
|
|
|
You can pull an image from Docker Hub and push it to your registry. The
|
|
following example pulls the `ubuntu:16.04` image from Docker Hub and re-tags it
|
|
as `my-ubuntu`, then pushes it to the local registry. Finally, the
|
|
`ubuntu:16.04` and `my-ubuntu` images are deleted locally and the
|
|
`my-ubuntu` image is pulled from the local registry.
|
|
|
|
1. Pull the `ubuntu:16.04` image from Docker Hub.
|
|
|
|
```bash
|
|
$ docker pull ubuntu:16.04
|
|
```
|
|
|
|
2. Tag the image as `localhost:5000/my-ubuntu`. This creates an additional tag
|
|
for the existing image. When the first part of the tag is a hostname and
|
|
port, Docker interprets this as the location of a registry, when pushing.
|
|
|
|
```bash
|
|
$ docker tag ubuntu:16.04 localhost:5000/my-ubuntu
|
|
```
|
|
|
|
3. Push the image to the local registry running at `localhost:5000`:
|
|
|
|
```bash
|
|
$ docker push localhost:5000/my-ubuntu
|
|
```
|
|
|
|
4. Remove the locally-cached `ubuntu:16.04` and `localhost:5000/my-ubuntu`
|
|
images, so that you can test pulling the image from your registry. This
|
|
does not remove the `localhost:5000/my-ubuntu` image from your registry.
|
|
|
|
```bash
|
|
$ docker image remove ubuntu:16.04
|
|
$ docker image remove localhost:5000/my-ubuntu
|
|
```
|
|
|
|
5. Pull the `localhost:5000/my-ubuntu` image from your local registry.
|
|
|
|
```bash
|
|
$ docker pull localhost:5000/my-ubuntu
|
|
```
|
|
|
|
## Stop a local registry
|
|
|
|
To stop the registry, use the same `docker container stop` command as with any other
|
|
container.
|
|
|
|
```bash
|
|
$ docker container stop registry
|
|
```
|
|
|
|
To remove the container, use `docker container rm`.
|
|
|
|
```bash
|
|
$ docker container stop registry && docker container rm -v registry
|
|
```
|
|
|
|
## Basic configuration
|
|
|
|
To configure the container, you can pass additional or modified options to the
|
|
`docker run` command.
|
|
|
|
The following sections provide basic guidelines for configuring your registry.
|
|
For more details, see the [registry configuration reference](configuration.md).
|
|
|
|
### Start the registry automatically
|
|
|
|
If you want to use the registry as part of your permanent infrastructure, you
|
|
should set it to restart automatically when Docker restarts or if it exits.
|
|
This example uses the `--restart always` flag to set a restart policy for the
|
|
registry.
|
|
|
|
```bash
|
|
$ docker run -d \
|
|
-p 5000:5000 \
|
|
--restart=always \
|
|
--name registry \
|
|
registry:2
|
|
```
|
|
|
|
### Customize the published port
|
|
|
|
If you are already using port 5000, or you want to run multiple local
|
|
registries to separate areas of concern, you can customize the registry's
|
|
port settings. This example runs the registry on port 5001 and also names it
|
|
`registry-test`. Remember, the first part of the `-p` value is the host port
|
|
and the second part is the port within the container. Within the container, the
|
|
registry listens on port `5000` by default.
|
|
|
|
```bash
|
|
$ docker run -d \
|
|
-p 5001:5000 \
|
|
--name registry-test \
|
|
registry:2
|
|
```
|
|
|
|
If you want to change the port the registry listens on within the container, you
|
|
can use the environment variable `REGISTRY_HTTP_ADDR` to change it. This command
|
|
causes the registry to listen on port 5001 within the container:
|
|
|
|
```bash
|
|
$ docker run -d \
|
|
-e REGISTRY_HTTP_ADDR=0.0.0.0:5001 \
|
|
-p 5001:5001 \
|
|
--name registry-test \
|
|
registry:2
|
|
```
|
|
|
|
|
|
## Storage customization
|
|
|
|
### Customize the storage location
|
|
|
|
By default, your registry data is persisted as a [docker volume](../storage/volumes.md)
|
|
on the host filesystem. If you want to store your registry contents at a specific
|
|
location on your host filesystem, such as if you have an SSD or SAN mounted into
|
|
a particular directory, you might decide to use a bind mount instead. A bind mount
|
|
is more dependent on the filesystem layout of the Docker host, but more performant
|
|
in many situations. The following example bind-mounts the host directory
|
|
`/mnt/registry` into the registry container at `/var/lib/registry/`.
|
|
|
|
```bash
|
|
$ docker run -d \
|
|
-p 5000:5000 \
|
|
--restart=always \
|
|
--name registry \
|
|
-v /mnt/registry:/var/lib/registry \
|
|
registry:2
|
|
```
|
|
|
|
### Customize the storage back-end
|
|
|
|
By default, the registry stores its data on the local filesystem, whether you
|
|
use a bind mount or a volume. You can store the registry data in an Amazon S3
|
|
bucket, Google Cloud Platform, or on another storage back-end by using
|
|
[storage drivers](./storage-drivers/index.md). For more information, see
|
|
[storage configuration options](./configuration.md#storage).
|
|
|
|
## Run an externally-accessible registry
|
|
|
|
Running a registry only accessible on `localhost` has limited usefulness. In
|
|
order to make your registry accessible to external hosts, you must first secure
|
|
it using TLS.
|
|
|
|
This example is extended in [Run the registry as a
|
|
service](#run-the-registry-as-a-service) below.
|
|
|
|
### Get a certificate
|
|
|
|
These examples assume the following:
|
|
|
|
- Your registry URL is `https://myregistry.domain.com/`.
|
|
- Your DNS, routing, and firewall settings allow access to the registry's host
|
|
on port 443.
|
|
- You have already obtained a certificate from a certificate authority (CA).
|
|
|
|
If you have been issued an _intermediate_ certificate instead, see
|
|
[use an intermediate certificate](#use-an-intermediate-certificate).
|
|
|
|
1. Create a `certs` directory.
|
|
|
|
```bash
|
|
$ mkdir -p certs
|
|
```
|
|
|
|
Copy the `.crt` and `.key` files from the CA into the `certs` directory.
|
|
The following steps assume that the files are named `domain.crt` and
|
|
`domain.key`.
|
|
|
|
2. Stop the registry if it is currently running.
|
|
|
|
```bash
|
|
$ docker container stop registry
|
|
```
|
|
|
|
3. Restart the registry, directing it to use the TLS certificate. This command
|
|
bind-mounts the `certs/` directory into the container at `/certs/`, and sets
|
|
environment variables that tell the container where to find the `domain.crt`
|
|
and `domain.key` file. The registry runs on port 443, the default HTTPS port.
|
|
|
|
```bash
|
|
$ docker run -d \
|
|
--restart=always \
|
|
--name registry \
|
|
-v "$(pwd)"/certs:/certs \
|
|
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
|
|
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
|
|
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
|
|
-p 443:443 \
|
|
registry:2
|
|
```
|
|
|
|
4. Docker clients can now pull from and push to your registry using its
|
|
external address. The following commands demonstrate this:
|
|
|
|
```bash
|
|
$ docker pull ubuntu:16.04
|
|
$ docker tag ubuntu:16.04 myregistry.domain.com/my-ubuntu
|
|
$ docker push myregistry.domain.com/my-ubuntu
|
|
$ docker pull myregistry.domain.com/my-ubuntu
|
|
```
|
|
|
|
#### Use an intermediate certificate
|
|
|
|
A certificate issuer may supply you with an *intermediate* certificate. In this
|
|
case, you must concatenate your certificate with the intermediate certificate to
|
|
form a *certificate bundle*. You can do this using the `cat` command:
|
|
|
|
```bash
|
|
cat domain.crt intermediate-certificates.pem > certs/domain.crt
|
|
```
|
|
|
|
You can use the certificate bundle just as you use the `domain.crt` file in
|
|
the previous example.
|
|
|
|
### Support for Let's Encrypt
|
|
|
|
The registry supports using Let's Encrypt to automatically obtain a
|
|
browser-trusted certificate. For more information on Let's Encrypt, see
|
|
[https://letsencrypt.org/how-it-works/](https://letsencrypt.org/how-it-works/)
|
|
and the relevant section of the
|
|
[registry configuration](configuration.md#letsencrypt).
|
|
|
|
### Use an insecure registry (testing only)
|
|
|
|
It is possible to use a self-signed certificate, or to use our registry
|
|
insecurely. Unless you have set up verification for your self-signed
|
|
certificate, this is for testing only. See [run an insecure registry](insecure.md).
|
|
|
|
## Run the registry as a service
|
|
|
|
[Swarm services](../engine/swarm/services.md) provide several advantages over
|
|
standalone containers. They use a declarative model, which means that you define
|
|
the desired state and Docker works to keep your service in that state. Services
|
|
provide automatic load balancing scaling, and the ability to control the
|
|
distribution of your service, among other advantages. Services also allow you to
|
|
store sensitive data such as TLS certificates in
|
|
[secrets](../engine/swarm/secrets.md).
|
|
|
|
The storage back-end you use determines whether you use a fully scaled service
|
|
or a service with either only a single node or a node constraint.
|
|
|
|
- If you use a distributed storage driver, such as Amazon S3, you can use a
|
|
fully replicated service. Each worker can write to the storage back-end
|
|
without causing write conflicts.
|
|
|
|
- If you use a local bind mount or volume, each worker node writes to its
|
|
own storage location, which means that each registry contains a different
|
|
data set. You can solve this problem by using a single-replica service and a
|
|
node constraint to ensure that only a single worker is writing to the bind
|
|
mount.
|
|
|
|
The following example starts a registry as a single-replica service, which is
|
|
accessible on any swarm node on port 80. It assumes you are using the same
|
|
TLS certificates as in the previous examples.
|
|
|
|
First, save the TLS certificate and key as secrets:
|
|
|
|
```bash
|
|
$ docker secret create domain.crt certs/domain.crt
|
|
|
|
$ docker secret create domain.key certs/domain.key
|
|
```
|
|
|
|
Next, add a label to the node where you want to run the registry.
|
|
To get the node's name, use `docker node ls`. Substitute your node's name for
|
|
`node1` below.
|
|
|
|
```bash
|
|
$ docker node update --label-add registry=true node1
|
|
```
|
|
|
|
Next, create the service, granting it access to the two secrets and constraining
|
|
it to only run on nodes with the label `registry=true`. Besides the constraint,
|
|
you are also specifying that only a single replica should run at a time. The
|
|
example bind-mounts `/mnt/registry` on the swarm node to `/var/lib/registry/`
|
|
within the container. Bind mounts rely on the pre-existing source directory,
|
|
so be sure `/mnt/registry` exists on `node1`. You might need to create it before
|
|
running the following `docker service create` command.
|
|
|
|
By default, secrets are mounted into a service at `/run/secrets/<secret-name>`.
|
|
|
|
```bash
|
|
$ docker service create \
|
|
--name registry \
|
|
--secret domain.crt \
|
|
--secret domain.key \
|
|
--constraint 'node.labels.registry==true' \
|
|
--mount type=bind,src=/mnt/registry,dst=/var/lib/registry \
|
|
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
|
|
-e REGISTRY_HTTP_TLS_CERTIFICATE=/run/secrets/domain.crt \
|
|
-e REGISTRY_HTTP_TLS_KEY=/run/secrets/domain.key \
|
|
--publish published=443,target=443 \
|
|
--replicas 1 \
|
|
registry:2
|
|
```
|
|
|
|
You can access the service on port 443 of any swarm node. Docker sends the
|
|
requests to the node which is running the service.
|
|
|
|
## Load balancing considerations
|
|
|
|
One may want to use a load balancer to distribute load, terminate TLS or
|
|
provide high availability. While a full load balancing setup is outside the
|
|
scope of this document, there are a few considerations that can make the process
|
|
smoother.
|
|
|
|
The most important aspect is that a load balanced cluster of registries must
|
|
share the same resources. For the current version of the registry, this means
|
|
the following must be the same:
|
|
|
|
- Storage Driver
|
|
- HTTP Secret
|
|
- Redis Cache (if configured)
|
|
|
|
Differences in any of the above cause problems serving requests.
|
|
As an example, if you're using the filesystem driver, all registry instances
|
|
must have access to the same filesystem root, on
|
|
the same machine. For other drivers, such as S3 or Azure, they should be
|
|
accessing the same resource and share an identical configuration.
|
|
The _HTTP Secret_ coordinates uploads, so also must be the same across
|
|
instances. Configuring different redis instances works (at the time
|
|
of writing), but is not optimal if the instances are not shared, because
|
|
more requests are directed to the backend.
|
|
|
|
### Important/Required HTTP-Headers
|
|
|
|
Getting the headers correct is very important. For all responses to any
|
|
request under the "/v2/" url space, the `Docker-Distribution-API-Version`
|
|
header should be set to the value "registry/2.0", even for a 4xx response.
|
|
This header allows the docker engine to quickly resolve authentication realms
|
|
and fallback to version 1 registries, if necessary. Confirming this is setup
|
|
correctly can help avoid problems with fallback.
|
|
|
|
In the same train of thought, you must make sure you are properly sending the
|
|
`X-Forwarded-Proto`, `X-Forwarded-For`, and `Host` headers to their "client-side"
|
|
values. Failure to do so usually makes the registry issue redirects to internal
|
|
hostnames or downgrading from https to http.
|
|
|
|
A properly secured registry should return 401 when the "/v2/" endpoint is hit
|
|
without credentials. The response should include a `WWW-Authenticate`
|
|
challenge, providing guidance on how to authenticate, such as with basic auth
|
|
or a token service. If the load balancer has health checks, it is recommended
|
|
to configure it to consider a 401 response as healthy and any other as down.
|
|
This secures your registry by ensuring that configuration problems with
|
|
authentication don't accidentally expose an unprotected registry. If you're
|
|
using a less sophisticated load balancer, such as Amazon's Elastic Load
|
|
Balancer, that doesn't allow one to change the healthy response code, health
|
|
checks can be directed at "/", which always returns a `200 OK` response.
|
|
|
|
## Restricting access
|
|
|
|
Except for registries running on secure local networks, registries should always
|
|
implement access restrictions.
|
|
|
|
### Native basic auth
|
|
|
|
The simplest way to achieve access restriction is through basic authentication
|
|
(this is very similar to other web servers' basic authentication mechanism).
|
|
This example uses native basic authentication using `htpasswd` to store the
|
|
secrets.
|
|
|
|
> **Warning**:
|
|
> You **cannot** use authentication with authentication schemes that send
|
|
> credentials as clear text. You must
|
|
> [configure TLS first](deploying.md#running-a-domain-registry) for
|
|
> authentication to work.
|
|
{:.warning}
|
|
|
|
1. Create a password file with one entry for the user `testuser`, with password
|
|
`testpassword`:
|
|
|
|
```bash
|
|
$ mkdir auth
|
|
$ docker run \
|
|
--entrypoint htpasswd \
|
|
httpd:2 -Bbn testuser testpassword > auth/htpasswd
|
|
```
|
|
|
|
On Windows, make sure the output file is correctly encoded:
|
|
|
|
```powershell
|
|
docker run --rm --entrypoint htpasswd httpd:2 -Bbn testuser testpassword | Set-Content -Encoding ASCII auth/htpasswd
|
|
```
|
|
|
|
2. Stop the registry.
|
|
|
|
```bash
|
|
$ docker container stop registry
|
|
```
|
|
|
|
3. Start the registry with basic authentication.
|
|
|
|
```bash
|
|
$ docker run -d \
|
|
-p 5000:5000 \
|
|
--restart=always \
|
|
--name registry \
|
|
-v "$(pwd)"/auth:/auth \
|
|
-e "REGISTRY_AUTH=htpasswd" \
|
|
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
|
|
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
|
|
-v "$(pwd)"/certs:/certs \
|
|
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
|
|
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
|
|
registry:2
|
|
```
|
|
|
|
4. Try to pull an image from the registry, or push an image to the registry.
|
|
These commands fail.
|
|
|
|
5. Log in to the registry.
|
|
|
|
```bash
|
|
$ docker login myregistrydomain.com:5000
|
|
```
|
|
|
|
Provide the username and password from the first step.
|
|
|
|
Test that you can now pull an image from the registry or push an image to
|
|
the registry.
|
|
|
|
> **X509 errors**: X509 errors usually indicate that you are attempting to use
|
|
> a self-signed certificate without configuring the Docker daemon correctly.
|
|
> See [run an insecure registry](insecure.md).
|
|
|
|
### More advanced authentication
|
|
|
|
You may want to leverage more advanced basic auth implementations by using a
|
|
proxy in front of the registry. See the [recipes list](recipes/index.md).
|
|
|
|
The registry also supports delegated authentication which redirects users to a
|
|
specific trusted token server. This approach is more complicated to set up, and
|
|
only makes sense if you need to fully configure ACLs and need more control over
|
|
the registry's integration into your global authorization and authentication
|
|
systems. Refer to the following [background information](spec/auth/token.md) and
|
|
[configuration information here](configuration.md#auth).
|
|
|
|
This approach requires you to implement your own authentication system or
|
|
leverage a third-party implementation.
|
|
|
|
## Deploy your registry using a Compose file
|
|
|
|
If your registry invocation is advanced, it may be easier to use a Docker
|
|
compose file to deploy it, rather than relying on a specific `docker run`
|
|
invocation. Use the following example `docker-compose.yml` as a template.
|
|
|
|
```yaml
|
|
registry:
|
|
restart: always
|
|
image: registry:2
|
|
ports:
|
|
- 5000:5000
|
|
environment:
|
|
REGISTRY_HTTP_TLS_CERTIFICATE: /certs/domain.crt
|
|
REGISTRY_HTTP_TLS_KEY: /certs/domain.key
|
|
REGISTRY_AUTH: htpasswd
|
|
REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
|
|
REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
|
|
volumes:
|
|
- /path/data:/var/lib/registry
|
|
- /path/certs:/certs
|
|
- /path/auth:/auth
|
|
```
|
|
|
|
Replace `/path` with the directory which contains the `certs/` and `auth/`
|
|
directories.
|
|
{:.warning}
|
|
|
|
Start your registry by issuing the following command in the directory containing
|
|
the `docker-compose.yml` file:
|
|
|
|
```bash
|
|
$ docker-compose up -d
|
|
```
|
|
|
|
## Considerations for air-gapped registries
|
|
|
|
You can run a registry in an environment with no internet connectivity.
|
|
However, if you rely on any images which are not local, you need to consider the
|
|
following:
|
|
|
|
- You may need to build your local registry's data volume on a connected
|
|
host where you can run `docker pull` to get any images which are available
|
|
remotely, and then migrate the registry's data volume to the air-gapped
|
|
network.
|
|
|
|
- Certain images, such as the official Microsoft Windows base images, are not
|
|
distributable. This means that when you push an image based on one of these
|
|
images to your private registry, the non-distributable layers are **not**
|
|
pushed, but are always fetched from their authorized location. This is fine
|
|
for internet-connected hosts, but not in an air-gapped set-up.
|
|
|
|
You can configure the Docker daemon to allow pushing non-distributable layers
|
|
to private registries.
|
|
**This is only useful in air-gapped set-ups in the presence of
|
|
non-distributable images, or in extremely bandwidth-limited situations.**
|
|
You are responsible for ensuring that you are in compliance with the terms of
|
|
use for non-distributable layers.
|
|
|
|
1. Edit the `daemon.json` file, which is located in `/etc/docker/` on Linux
|
|
hosts and `C:\ProgramData\docker\config\daemon.json` on Windows Server.
|
|
Assuming the file was previously empty, add the following contents:
|
|
|
|
```json
|
|
{
|
|
"allow-nondistributable-artifacts": ["myregistrydomain.com:5000"]
|
|
}
|
|
```
|
|
|
|
The value is an array of registry addresses, separated by commas.
|
|
|
|
Save and exit the file.
|
|
|
|
2. Restart Docker.
|
|
|
|
3. Restart the registry if it does not start automatically.
|
|
|
|
4. When you push images to the registries in the list, their
|
|
non-distributable layers are pushed to the registry.
|
|
|
|
> **Warning**: Non-distributable artifacts typically have restrictions on
|
|
> how and where they can be distributed and shared. Only use this feature
|
|
> to push artifacts to private registries and ensure that you are in
|
|
> compliance with any terms that cover redistributing non-distributable
|
|
> artifacts.
|
|
|
|
|
|
## Next steps
|
|
|
|
More specific and advanced information is available in the following sections:
|
|
|
|
- [Configuration reference](configuration.md)
|
|
- [Working with notifications](notifications.md)
|
|
- [Advanced "recipes"](recipes/index.md)
|
|
- [Registry API](spec/api.md)
|
|
- [Storage driver model](storage-drivers/index.md)
|
|
- [Token authentication](spec/auth/token.md)
|