Creating the Registry
The Docker Registry is a service that can talk to the docker daemon in order to upload and download docker images. Since version 2, the docker registry is called Distribution, and you can find the documentation here.
There are multiple ways to deploy your own private registry. This page explains how to do this. From a deployment point of view, the only thing important for Portus is that it should be reachable. Note that this will be checked when adding your registry into Portus’ database, as explained here.
Configuring the Registry in a safe way
Once you have your registry in place, you need to configure it. This can be
done either through the
/etc/registry/config.yml file or through environment
For convenience, we will assume that you have access to the
This is a config example:
Some things to note:
- The loglevel is set to
debug. You usually want to relax this as specified here.
- The storage has been configured to be on the filesystem. This is a pretty
basic and standard setup, but you can tweak it as much as you need. Just take a
look at this document
to learn all of the supported options. Also note that
deletedhas been set to
true. Even if this is not a requirement from Portus’ side, it might be in the future when removing images is supported.
- The http config is set to listen to the
:5000port, which is the default value. Also note that in the
tlsconfigurable value we provide a certificate and a key. This will be used so the communication between the docker daemon and the registry is done through TLS. We strongly recommend to use this, otherwise we cannot guarantee that the communication will be secure. Both the key and the certificate will be generated automatically by
portusctlif you are using the RPM package.
- The auth value defines the communication between Portus and this
registry. Some important things to note:
- The issuer should be the same as the one defined by
config/config.ymlfile. This can be changed with the
- The rootcertbundle should point to the same location as the
encryption_private_key_pathconfigurable value as defined also in the
config/secrets.ymlfile. This can be also tweaked with the
- The issuer should be the same as the one defined by
- The notifications configuration tells your registry where to send
notifications. In this case, you should specify Portus’
/v2/webhooks/eventsendpoint. This is used to synchronize the contents of the DB with the registry. You can read more about this here.
Integrating the Registry with Portus
From now on, we will suppose that a registry has already been created.
How does Portus authorize requests ?
The next generation of Docker registries (those based on v2.0 or higher) push the authorization of requests to an external authorization service. In our case, this external authorization service will be Portus. If you would like to have a more clear picture about this, take a look at this explanation from Docker’s documentation.
When Portus receives an authorization request, it gets the following information:
- The registry being targeted. Portus has to know the existence of the registry being targeted by the request. This is better explained in this page.
- Who is trying to perform the action. The user must be known to Portus, and Portus will take into consideration whether the user is disabled, locked, etc. If everything is fine, then it will check basic authorization data like the password, etc.
- Which actions are trying to be performed.
- What is the target <namespace>/<repo>. Combining this with the given user and the given action, Portus decides whether the user is authorized to perform such action.
If Portus decides that the user is authorized to perform the action, then it sends a JWT token suitable for the docker registry being targeted. You can read all the details about the format of this JWT token here.
Configuring the JWT token sent by Portus
As stated in the previous section, the JWT token is used to handle the authentication between Portus and your private registry. There are some considerations in regards to this token.
First of all, it needs the
machine_fqdn secret to be set. You can find this
config/secrets.yml file. If you change this file you should restart
Portus afterwards. Note that in production you can just provide the
PORTUS_MACHINE_FQDN environment variable.
Another thing to consider is the expiration time of the token itself. By default it expires in 5 minutes. However, it’s possible that the image to be uploaded is too big or the communication is too slow; and the upload can take more than 5 minutes. If this happens, then the upload will be cancelled from the registry’s side, and it will fail. This is a known issue, and from Portus’ side we provide this workaround.
Synchronizing the Registry and Portus
As explained in this page, Portus is able to synchronize the contents of the registry and its database. In this regard, there are some considerations to be made.
First of all, note that no synchronization will be made until the admin sets up the registry in Portus’ database. This is better explained in this page.
Moreover, in order for this to happen, Portus needs the
portus user to exist.
This user is created when setting up Portus for the first time by the admin.
This is done automatically by the
portusctl tool if you are using the
provided RPM (or if you are on development mode and you
are using either the docker compose setup or the vagrant setup). If this is not
your case, you have to create it after migrating the database by performing:
$ rake db:seed
$ rake portus:create_api_account
Note that neither of these commands will work if you have not set the
portus_password secret value in the
config/secrets.yml file. This value can
be set on production with the environment variable
Since Docker Distribution 2.1, when Portus receives a web event regarding a tag being pushed, it has to make another HTTP request in order to get which tag was actually pushed. This works perfectly with either a development environment without SSL or with a production environment with SSL with our provided Passenger configuration. However, it’s been reported that this does not work properly in some setups. In these setups, the Rails worker tries to use the same connection as the one used by the web event, and thus its gets stuck until the web event times out. In order to work-around this, in this scenario you need to setup your Rails instance so it uses more than one socket. An example of this work-around can be found here. If you want to read more about this issue, you can find the original issue: Portus freezes when trying to get manifest after image push.