Run our own Docker registry with self-signed certificate with Ansible
ansible docker networking nginx vaultIn this article we are going to install Docker registry and use it via HTTPS with our own certificate authority to manage our Docker images.
Prerequisites
We’ll need Ansible installed locally and Docker installed in the machine where the Docker registry will be installed. In this example, we will use certificates from Vault, more details in this article. NGINX will be used as a reverse proxy, to define NGINX sites with Ansible see this article or this Ansible collection.
Install Docker registry
We are going to install the Docker registry and a UI webapp, both
will be running over HTTPS. Let’s say that our registry URL is
https://registry.homelab.local
and our UI webapp,
https://registry-ui.homelab.local
.
Create the registry configuration file
(files/config.yml
), allowing requests from the webapp:
version: 0.1
log:
fields:
service: registry
storage:
cache:
blobdescriptor: inmemory
filesystem:
rootdirectory: /var/lib/registry
http:
addr: :5000
headers:
X-Content-Type-Options: [nosniff]
Access-Control-Allow-Origin: ["https://registry-ui.homelab.local"]
Access-Control-Allow-Methods: [HEAD, GET, OPTIONS, DELETE]
Access-Control-Allow-Headers: [Authorization, Accept, Cache-Control]
Access-Control-Max-Age: [1728000]
Access-Control-Allow-Credentials: [true]
Access-Control-Expose-Headers: [Docker-Content-Digest]
health:
storagedriver:
enabled: true
interval: 10s
threshold: 3
Setup and run Docker registry:
- name: create data directory
file:
path: registry_data/registry
state: directory
- name: config registry
copy:
src: files/config.yml
dest: registry_data/config.yml
- name: run registry
docker_container:
name: registry
state: started
image: registry
restart_policy: unless-stopped
ports:
- "5000:5000"
volumes:
- "{{ ansible_user_dir }}/registry_data/registry:/var/lib/registry"
- "{{ ansible_user_dir }}/registry_data/config.yml:/etc/docker/registry/config.yml"
Run Docker registry UI:
- name: run registry ui
docker_container:
name: registry-ui
state: started
image: joxit/docker-registry-ui
restart_policy: unless-stopped
ports:
- "8080:80"
env:
REGISTRY_URL: "https://registry.homelab.local"
Setup NGINX
Assume we have our SSL certificate and private key in
/etc/ssl
issued
from our CA, create the server records for
https://registry.homelab.local
and
https://registry-ui.homelab.local
using the Ansible module
mmas.nginx.nginx_site
:
- name: define registry site
mmas.nginx.nginx_site:
name: registry.homelab.local
log_name: regsitry
proxy_pass: "http://{{ inventory_hostname }}:5000"
sslcert: /etc/ssl/certs/homelab.local.crt
sslkey: /etc/ssl/private/homelab.local.pem
become: yes
notify:
- reload nginx
- name: define registry ui site
mmas.nginx.nginx_site:
name: registry-ui.homelab.local
log_name: regsitry
proxy_pass: "http://{{ inventory_hostname }}:8080"
sslcert: /etc/ssl/certs/homelab.local.crt
sslkey: /etc/ssl/private/homelab.local.pem
become: yes
notify:
- reload nginx
If Docker registry and NGINX are not running in the same machine, the
proxy_pass
must point to the IP where registry is
running.
The handler triggered can be defined as follows:
- name: reload nginx
service:
name: nginx
state: reloaded
become: yes
Import root certificate
Since we haven’t imported the root certificate into Docker, if we try to use the registry now, we’ll get the following error:
Get "https://registry.homelab.local/v2/": tls: failed to verify certificate: x509: certificate signed by unknown authority
We must import the certificate to the machine that will use the
registry, so we’ll run the following tasks in
hosts: localhost
using the collection mmas.hashi_vault.vault_pki_root
.
From the previous article, the subject common name of our root certificate is “Vault Root”, so:
- name: download root certificate
set_fact:
root_ca: "{{ lookup('mmas.hashi_vault.vault_pki_root', 'Vault Root').certificate }}"
- name: create docker certificates folder
file:
path: /etc/docker/certs.d/registry.homelab.local
state: directory
become: yes
- name: install root certificate in docker
copy:
dest: /etc/docker/certs.d/registry.homelab.local/root.crt
content: "{{ root_ca }}"
become: yes
To allow pulls from Kubernetes with containerd, we can install the certificate and restart containerd:
- name: install root certificate
copy:
dest: /usr/local/share/ca-certificates/root.crt
content: "{{ root_ca }}"
become: yes
notify:
- update ca certificates
- restart containerd
With the handlers:
- name: update ca certificates
command: update-ca-certificates
become: yes
- name: restart containerd
service:
name: containerd
state: restarted
become: yes
Use the registry
Now, we’ll be able to use our Docker registry:
docker image tag myapp registry.homelab.local/myapp
docker push registry.homelab.local/myapp
If we get the error
Request Entity Too Large
we need to increase client_max_body_size
in our NGINX configuration (/etc/nginx/nginx.conf
):
http {
[...]
client_max_body_size 100M;
[...]
}
To access the UI, we’ll need to import our root certificate in the browser.