Docker Registry
Existen varios registros para almacenar nuestras imágenes.
- Dockerhub
- Amazon Elastic Container Registry (ECR)
- Google Container Registry (GCR)
- Azure Container Registry (ACR)
- Gitlab Container Registry
- Google Artifact Registry (GAR)
- Github Package Registry
- Red Hat Quay
... Y muchos otros, pero al final todos utilizan la misma imagen base llamada registry v2, lo que cambia es solo la interfaz gráfica y algunos recursos que trabajan sobre la imagen lista, como un escaneo de vulnerabilidades por ejemplo.
Sin embargo, es interesante tener un registro privado en nuestro clúster por varios motivos.

Motivos para tener un registro privado:
- Dockerhub tiene limitaciones de 100 imágenes (pull) que se pueden descargar cada 6 horas en modo anónimo. Si está autenticado puede llegar a 200 y para utilizar más que eso necesita pagar https://docs.docker.com/docker-hub/download-rate-limit/#:~:text=Docker%20Hub%20limits%20the%20number,pulls%20per%206%20hour%20period. Si tiene 10 hosts con contenedores distribuidos entre ellos que usan una misma base, es necesario hacer un pull de todas las capas para cada uno de los hosts (cada capa es una imagen). El límite de 100 o 200 se agota en pocos minutos. Si tiene un registro privado, descarga las capas una vez y las proporciona a los hosts. Funcionaría como un caché, pero además puede hacer integración con varios otros registros.
- Velocidad para descargar las imágenes ya que las imágenes ya están en su infraestructura, disminuyendo el uso de ancho de banda de red.
- Seguridad para ejecutar un push y pull de las imágenes dentro de la propia infraestructura, evitando ataques como man in the middle hacia registros externos.
¿Si está en una nube, por ejemplo, vale la pena tener un registro privado?
Este servicio suele ser muy económico. Una vez que no necesita administrar certificados SSL y está utilizando el registro de su propia nube, la velocidad y seguridad están garantizadas.
Vamos a añadir el registro a nuestro clúster swarm
vagrant@registry:~$ docker swarm join --token SWMTKN-1-5uadpu9vr0rcq1hbjtzv7exb34vyreuc9l4gkgggg0y1x0c471-75b4qqhg4ez89w5h49x0dwdz3 10.10.10.100:2377
This node joined a swarm as a worker.
vagrant@registry:~$
vagrant@master:~$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
jdmwyhbti8s3fnmd17lw79rhw * master.docker-dca.example Ready Active Leader 20.10.17
qvp6um8mstrgrlhhfpjj6khdc registry.docker-dca.example Ready Active 20.10.17
rxgmhpjtky4s6mktwis2jyr99 worker1.docker-dca.example Ready Active 20.10.17
7980uc978wk928ncb6esv3jy3 worker2.docker-dca.example Ready Active
Generalmente necesitamos utilizar un certificado SSL en nuestras comunicaciones con el registro, pero como estamos trabajando localmente no lo utilizaremos. Para esto solo vamos a configurar nuestro daemon.json
EN TODOS LOS NODOS, que es el archivo de configuración de docker, de la siguiente manera.
Sin un SSL no es necesaria la autenticación como un docker login para verificar los datos, simplemente puede hacer un push de la imagen sin verificación de datos.
Vamos a necesitar configurar el registro en todas las máquinas y luego debemos reiniciar docker.


Ahora en el host registry vamos a desplegar nuestro contenedor de registro. Observe la imagen y el puerto, que es lo único nuevo por aquí.
- imagen = registry:2
- puerto = 5000

Ahora vamos a hacer un pull de una imagen de dockerhub.
agrant@registry:~$ docker pull alpine
Using default tag: latest
latest: Pulling from library/alpine
Digest: sha256:686d8c9dfa6f3ccfc8230bc3178d23f84eeaf7e457f36f271ab1acc53015037c
Status: Image is up to date for alpine:latest
docker.io/library/alpine:latest
vagrant@registry:~$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
registry 2 773dbf02e42e 5 weeks ago 24.1MB
alpine latest e66264b98777 5 weeks ago 5.53MB
vagrant@registry:~$
¿Esta imagen está en el registro?
Details
Respuesta
No, solo está en el host. Las imágenes para ser dirigidas a nuestro registro necesitan ser etiquetadas para él. Si hace push sin etiquetar, entenderá que es para el registro predeterminado, dockerhub.Vamos a crear una etiqueta y subir la imagen a nuestro registro
vagrant@registry:~$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
registry 2 773dbf02e42e 5 weeks ago 24.1MB
alpine latest e66264b98777 5 weeks ago 5.53MB
vagrant@registry:~$ docker image tag alpine:latest registry.docker-dca.example:5000/alpine
vagrant@registry:~$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
registry 2 773dbf02e42e 5 weeks ago 24.1MB
alpine latest e66264b98777 5 weeks ago 5.53MB
registry.docker-dca.example:5000/alpine latest e66264b98777 5 weeks ago 5.53MB
# haciendo el push
vagrant@registry:~$ docker push registry.docker-dca.example:5000/alpine
Using default tag: latest
The push refers to repository [registry.docker-dca.example:5000/alpine]
24302eb7d908: Pushed
latest: digest: sha256:4ff3ca91275773af45cb4b0834e12b7eb47d1c18f770a0b151381cd227f4c253 size: 528
vagrant@registry:~$
Este registro que levantamos no tiene ningún tipo de interfaz visual, pero tiene una API de consulta que podemos utilizar haciendo un curl o yendo al propio navegador.
http://registry.docker-dca.example:5000/v2/_catalog
vagrant@master:~$ curl http://registry.docker-dca.example:5000/v2/_catalog
{"repositories":["alpine"]}
vagrant@master:~$ curl -s http://registry.docker-dca.example:5000/v2/_catalog | jq
{
"repositories": [
"alpine"
]
}
Las imágenes se almacenan en el volumen del contenedor.
vagrant@registry:~$ docker container inspect registry | grep Source
"Source": "/var/lib/docker/volumes/7c60f11e7e59839e0e57b6aab78de979065c293624745830b9b57686c95d4286/_data",
vagrant@registry:~$ docker volume
create inspect ls prune rm
vagrant@registry:~$ docker volume inspect 7c60f11e7e59839e0e57b6aab78de979065c293624745830b9b57686c95d4286
[
{
"CreatedAt": "2022-07-04T03:21:46Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/7c60f11e7e59839e0e57b6aab78de979065c293624745830b9b57686c95d4286/_data",
"Name": "7c60f11e7e59839e0e57b6aab78de979065c293624745830b9b57686c95d4286",
"Options": null,
"Scope": "local"
}
]
# vamos a verificar
vagrant@registry:~$ sudo tree /var/lib/docker/volumes/7c60f11e7e59839e0e57b6aab78de979065c293624745830b9b57686c95d4286
/var/lib/docker/volumes/7c60f11e7e59839e0e57b6aab78de979065c293624745830b9b57686c95d4286
└── _data
└── docker
└── registry
└── v2
├── blobs
│ └── sha256
│ ├── 24
│ │ └── 2408cc74d12b6cd092bb8b516ba7d5e290f485d3eb9672efc00f0583730179e8
│ │ └── data
│ ├── 4f
│ │ └── 4ff3ca91275773af45cb4b0834e12b7eb47d1c18f770a0b151381cd227f4c253
│ │ └── data
│ └── e6
│ └── e66264b98777e12192600bf9b4d663655c98a090072e1bab49e233d7531d1294
│ └── data
└── repositories
└── alpine #Aquí...
├── _layers
│ └── sha256
│ ├── 2408cc74d12b6cd092bb8b516ba7d5e290f485d3eb9672efc00f0583730179e8
│ │ └── link
│ └── e66264b98777e12192600bf9b4d663655c98a090072e1bab49e233d7531d1294
│ └── link
├── _manifests
│ ├── revisions
│ │ └── sha256
│ │ └── 4ff3ca91275773af45cb4b0834e12b7eb47d1c18f770a0b151381cd227f4c253
│ │ └── link
│ └── tags
│ └── latest
│ ├── current
│ │ └── link
│ └── index
│ └── sha256
│ └── 4ff3ca91275773af45cb4b0834e12b7eb47d1c18f770a0b151381cd227f4c253
│ └── link
└── _uploads
Vamos a descargar varias imágenes para nuestro laboratorio
- nginx
- mysql:5.7
- wordpress
- traefik:v2.4
Necesitaríamos hacer un docker pull, docker image tag y docker push de cada una de estas imágenes.
Vamos a automatizar esto rápidamente
for image in 'nginx' 'mysql:5.7' 'wordpress' 'traefik'
do
docker pull $image
docker image tag $image registry.docker-dca.example:5000/$image
docker push registry.docker-dca.example:5000/$image
done
#... Verificando
vagrant@master:~$ curl -s http://registry.docker-dca.example:5000/v2/_catalog | jq
{
"repositories": [
"alpine",
"mysql",
"nginx",
"traefik",
"wordpress"
]
}
# Verificando las etiquetas..
vagrant@master:~$ curl -s http://registry.docker-dca.example:5000/v2/traefik/tags/list | jq
{
"name": "traefik",
"tags": [
"latest"
]
}
vagrant@master:~$ curl -s http://registry.docker-dca.example:5000/v2/wordpress/tags/list | jq
{
"name": "wordpress",
"tags": [
"latest"
]
}
vagrant@master:~$ curl -s http://registry.docker-dca.example:5000/v2/mysql/tags/list | jq
{
"name": "mysql",
"tags": [
"5.7"
]
}
#...