Registry サーバーのデプロイ
読む時間の目安: 16 分
このページでは、オープンソースである Docker Registry を使って、独自にレジストリを提供する情報を示しています。 Docker Hub はホスト提供込みの Registry であり、さまざまな機能を追加することができます。 たとえばチーム、組織、ウェブフック、自動ビルドなどです。 詳しくは Docker Hub を参照してください。
Registry をデプロイするには、まずホスト上に Docker をインストールする必要があります。
Registry はregistry
イメージのインスタンスの 1 つであり、Docker の内部において稼動します。
このトピックでは Registry のデプロイと設定方法に関する基本的な情報を示します。 設定オプションの全一覧については 設定リファレンス を参照してください。
外部から隔離された(air-gapped)データセンターを利用している場合は、隔離されたデータセンターでの配慮 を参照してください。
ローカル Registry の起動
以下のようなコマンドを実行して Registry コンテナーを起動します。
$ docker run -d -p 5000:5000 --restart=always --name registry registry:2
Registry がこうして利用できるようになります。
警告
ここに例としていくつか示す Registry の設定は、テスト環境向けにしか考慮していません。 本番環境向けの Registry であれば、TLS によって保護することが必要であり、理想的にはアクセス制御システムの利用が求められます。 ここでの説明を読み終えたら、本番環境向け Registry をデプロイするための 設定ガイド に進んでください。
Docker Hub から Registry へのイメージコピー
イメージは Docker Hub からプルして、それを Registry にプッシュすることができます。
以下の例では Docker Hub からubuntu:16.04
イメージをプルして、そこにmy-ubuntu
というタグをつけ直します。
そしてローカルな Registry にプッシュします。
その後にローカル上からubuntu:16.04
とmy-ubuntu
のイメージを削除した上で、ローカル Registry からmy-ubuntu
イメージをプルします。
-
Docker Hub から
ubuntu:16.04
イメージをプルします。$ docker pull ubuntu:16.04
-
イメージに
localhost:5000/my-ubuntu
というタグをつけます。 このようにすることで、既存のイメージに追加のタグがつけられます。 タグ名のはじめにあるのがホスト名とポート番号です。 Docker はプッシュ処理時に、その名前部分を Registry の場所として解釈します。$ docker tag ubuntu:16.04 localhost:5000/my-ubuntu
-
localhost:5000
として起動しているローカルの Registry にイメージをプッシュします。$ docker push localhost:5000/my-ubuntu
-
ローカルにキャッシュされている
ubuntu:16.04
とlocalhost:5000/my-ubuntu
イメージを削除します。 この後には、ローカル Registry からイメージをプルしてみることができます。 Registry からはlocalhost:5000/my-ubuntu
イメージは削除されません。$ docker image remove ubuntu:16.04 $ docker image remove localhost:5000/my-ubuntu
-
ローカルの Registry から
localhost:5000/my-ubuntu
イメージをプルします。$ docker pull localhost:5000/my-ubuntu
ローカル Registry の停止
Registry を停止するには、コンテナーの場合と同じようにdocker container stop
コマンドを実行します。
$ docker container stop registry
コンテナーを削除するにはdocker container rm
を実行します。
$ docker container stop registry && docker container rm -v registry
基本的な設定
コンテナーを設定するには、docker run
コマンドの実行時に、追加のまたは修正のオプションを指定します。
以下の節では、Registry 設定に関する基本的なガイドラインを示します。 詳しくは Registry 設定リファレンス を参照してください。
Registry の自動起動
常用するインフラストラクチャーの一部として Registry を利用したい場合には、Docker の再起動時あるいは Registry 終了時に、Registry を自動的に再起動することが必要になります。
以下の例では--restart always
フラグを用いて、Registry に対して再起動ポリシーを設定します。
$ docker run -d \
-p 5000:5000 \
--restart=always \
--name registry \
registry:2
公開ポートの変更
すでにポート 5000 を利用している場合、またはローカル Registry を各作業向けに切り分けて複数起動したい場合は、Registry のポート設定を変更します。
以下の例では Registry をポート 5001 で起動し、同時にその名称をregistry-test
とします。
ここで-p
フラグの値の 1 つめはホストのポートであり、2 つめはコンテナー内のポートです。
コンテナーの内部にて Registry は、ポート5000
を利用するのがデフォルトです。
$ docker run -d \
-p 5001:5000 \
--name registry-test \
registry:2
コンテナーの内部にて Registry が待ち受けるポートは、環境変数REGISTRY_HTTP_ADDR
を使って変更することができます。
以下のコマンドは、コンテナーの内部にて Registry はポート 5001 を待ち受けるようになります。
$ docker run -d \
-e REGISTRY_HTTP_ADDR=0.0.0.0:5001 \
-p 5001:5001 \
--name registry-test \
registry:2
ストレージの設定
ストレージ保存場所の変更
By default, your registry data is persisted as a docker volume
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/
.
$ 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. For more information, see storage configuration options.
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 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.
-
Create a
certs
directory.$ mkdir -p certs
Copy the
.crt
and.key
files from the CA into thecerts
directory. The following steps assume that the files are nameddomain.crt
anddomain.key
. -
Stop the registry if it is currently running.
$ docker container stop registry
-
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 thedomain.crt
anddomain.key
file. The registry runs on port 443, the default HTTPS port.$ 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
-
Docker clients can now pull from and push to your registry using its external address. The following commands demonstrate this:
$ 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:
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/ and the relevant section of the registry configuration.
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.
Run the registry as a service
Swarm services 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.
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:
$ 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.
$ 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>
.
$ 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 for authentication to work.
-
Create a password file with one entry for the user
testuser
, with passwordtestpassword
:$ mkdir auth $ docker run \ --entrypoint htpasswd \ httpd:2 -Bbn testuser testpassword > auth/htpasswd
On Windows, make sure the output file is correctly encoded:
docker run --rm --entrypoint htpasswd httpd:2 -Bbn testuser testpassword | Set-Content -Encoding ASCII auth/htpasswd
-
Stop the registry.
$ docker container stop registry
-
Start the registry with basic authentication.
$ 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
-
Try to pull an image from the registry, or push an image to the registry. These commands fail.
-
Log in to the registry.
$ 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.
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.
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 and configuration information here.
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.
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.
Start your registry by issuing the following command in the directory containing
the docker-compose.yml
file:
$ docker-compose up -d
隔離されたデータセンターでの配慮
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.
-
Edit the
daemon.json
file, which is located in/etc/docker/
on Linux hosts andC:\ProgramData\docker\config\daemon.json
on Windows Server. Assuming the file was previously empty, add the following contents:{ "allow-nondistributable-artifacts": ["myregistrydomain.com:5000"] }
The value is an array of registry addresses, separated by commas.
Save and exit the file.
-
Restart Docker.
-
Restart the registry if it does not start automatically.
-
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.
-
次のステップ
More specific and advanced information is available in the following sections:
- Configuration reference
- Working with notifications
- Advanced “recipes”
- Registry API
- Storage driver model
- Token authentication