Docker local private warehouse


DockerHub provides us with many official images and images uploaded by individuals, or we can download images provided by institutions or individuals or upload our own local images using a third-party image warehouse, but the disadvantages are:

  • Due to the network, downloading and uploading images from DockerHub may be slow;
  • The Docker image used in production may contain our code, configuration information, etc. it does not want to be obtained by external personnel, but can only be downloaded by developers on the intranet.

In order to solve the above problems, Docker officially provides an image called registry for building a local private warehouse. The Docker private warehouse built on the internal network can enable intranet personnel to download and upload very quickly, which is not affected by external network bandwidth and other factors. At the same time, people who are not on the internal network can not download our image, and the private warehouse also supports the configuration of warehouse authentication function.

1, Establishment of registry private warehouse

Create a private warehouse container using the registry image

After installing Docker, you can simply build a local private warehouse environment through the registry image provided by the official:

[root@docker ~]# docker run -d --name myregistry -p 5000:5000 -v /mnt/my_registry:/var/lib/registry registry
ad2a3a85f7f4fa1ad059250f566e2e51dbb4d837a7c533f36b5eb60dd2cfe34f

# Parameters:
  -d Background operation
  --name  Name the container you created
  -p  Port mapping, the service runs with 5000 port communication by default
  -v  The data volume is mounted. By default, the warehouse will be created in the container /var/lib/registry Directory. Can pass -v Parameter to store the image file in the specified local path.

[root@docker ~]# docker ps
CONTAINER ID   IMAGE      COMMAND                  CREATED          STATUS          PORTS                                       NAMES
ad2a3a85f7f4   registry   "/entrypoint.sh /etc..."   24 seconds ago   Up 22 seconds   0.0.0.0:5000->5000/tcp, :::5000->5000/tcp   myregistry

Open the browser and enter:

http://192.168.126.20:5000/v2/_catalog

Display {"repositories": []} indicates that the private warehouse is built successfully and the content is empty.

2, Push image to private warehouse

Perform the following steps on any host that installs Docker service and can connect to the private warehouse host (including installing the local machine of the private warehouse host) to push the image to the private warehouse

Modify configuration

Modify the daemon JSON file

[root@docker ~]# vim /etc/docker/daemon.json
{
  "registry-mirrors": [
    "https://e9hk8fzj.mirror.aliyuncs.com",
    "https://docker.mirrors.ustc.edu.cn"
  ],
    "insecure-registries": ["192.168.126.20:5000"]    # The content added in this behavior is the IP address of the host running the warehouse container, and the port is consistent with the host port specified when using the registry image to run the container
}

Reload the configuration information and restart the Docker service

[root@docker ~]# systemctl daemon-reload && systemctl restart docker

Image labeling

You must first set a label for the image to be pushed and uploaded

Usage:
	docker tag SOURCE_IMAGE[:TAG] IP:PORT/TARGET_IMAGE[:TAG]

[root@docker ~]# docker images
REPOSITORY                                                TAG        IMAGE ID       CREATED         SIZE
registry                                                  latest     1fd8e1b0bb7e   2 months ago    26.2MB
busybox                                                   1.31.1     1c35c4412082   13 months ago   1.22MB

[root@docker ~]# docker tag busybox:1.31.1 192.168.126.20:5000/busybox_v1:1.31.1
[root@docker ~]# docker images
REPOSITORY                                                TAG        IMAGE ID       CREATED         SIZE
registry                                                  latest     1fd8e1b0bb7e   2 months ago    26.2MB
192.168.126.20:5000/busybox_v1                            1.31.1     1c35c4412082   13 months ago   1.22MB
busybox                                                   1.31.1     1c35c4412082   13 months ago   1.22MB

Push image to private warehouse

Usage:
	docker push IP:PORT/TARGET_IMAGE[:TAG]
	
[root@docker ~]# docker push 192.168.126.20:5000/busybox_v1:1.31.1 
The push refers to repository [192.168.126.20:5000/busybox_v1]
1be74353c3d0: Pushed 
1.31.1: digest: sha256:fd4a8673d0344c3a7f427fe4440d4b8dfd4fa59cfabbd9098f9eb0cb4ba905d0 size: 527

3, View images in the warehouse

Usage:

# Query image
curl -XGET http://IP:PORT/v2/_catalog

# Query image tag (version)
curl -XGET http://IP:PORT/v2/IMAGE_NAME/tags/list

# Get image digest_hash
curl  http://IP:PORT/v2/IMAGE_NAME/manifests/TAG_NAME --header "Accept: application/vnd.docker.distribution.manifest.v2+json"

View on the host where the warehouse is built

# View data volumes
[root@docker ~]# ls /mnt/my_registry/
docker
[root@docker ~]# ls /mnt/my_registry/docker/registry/v2/repositories/busybox_v1/
_layers  _manifests  _uploads

# View in container
[root@docker ~]# docker exec -it myregistry /bin/sh
/ # ls /var/lib/registry/docker/registry/v2/repositories/
busybox_v1  

[root@docker ~]# curl -XGET http://192.168.126.20:5000/v2/_catalog
{"repositories":["busybox_v1"]}
[root@docker ~]# curl -XGET http://192.168.126.20:5000/v2/busybox_v1/tags/list
{"name":"busybox_v1","tags":["1.31.1"]}


# Or access in the browser http://192.168.126.20:5000/v2/_catalog 

Or view it on the client where the image is uploaded

[root@k8s-master ~]# curl -XGET http://192.168.126.20:5000/v2/_catalog
{"repositories":["busybox_v1"]}
[root@k8s-master ~]# curl -XGET http://192.168.126.20:5000/v2/busybox_v1/tags/list
{"name":"busybox_v1","tags":["1.31.1"]}

# Or access in the browser http://192.168.126.20:5000/v2/_catalog 
[root@k8s-master ~]# curl --header "Accept: application/vnd.docker.distribution.manifest.v2+json"  -I -X  HEAD http://192.168.126.20:5000/v2/hello_test/manifests/v1
[root@k8s-master ~]# curl -v -X DELETE http://192.168.126.20:5000/v2/hello_test/manifests/sha256:1b26826f602946860c279fce658f31050cff2c596583af237d971f4629b57792

4, Deletion of image in private warehouse

At first, when installing the private warehouse, I didn't think about deleting the image. When I want to delete the uploaded image, the image can't be deleted. It's more troublesome, so I have to run the private warehouse container again

In version 2.1, Docker warehouse supports the API for deleting images, but this deletion operation will only delete image metadata, not layer data. In version 2.4, this problem is solved by adding a garbage collection command to delete unreferenced layer data

First, the registry needs to enable deletion

Because the default Docker private registry does not allow you to delete images, if you encounter a "405 Unsupported" error, you need to modify the relevant parameters in the configuration file when running the registry container

# Enable delete (add delete: enabled: true)
[root@docker ~]# docker exec -it  myregistry sh -c "sed -i '/storage:/a\  delete:' /etc/docker/registry/config.yml"
[root@docker ~]# docker exec -it  myregistry sh -c "sed -i '/delete:/a\    enabled: true' /etc/docker/registry/config.yml"

# see
[root@docker ~]# docker exec -it  myregistry  cat  /etc/docker/registry/config.yml
version: 0.1
log:
  fields:
    service: registry
storage:
  delete:	# Added by this behavior
    enabled: true   # Added by this behavior
  cache:
    blobdescriptor: inmemory
  filesystem:
    rootdirectory: /var/lib/registry
http:
  addr: :5000
  headers:
    X-Content-Type-Options: [nosniff]
health:
  storagedriver:
    enabled: true
    interval: 10s
    threshold: 3

Restart private warehouse container

[root@docker ~]# docker restart myregistry
myregistry

View images in the warehouse

[root@docker ~]# curl -XGET http://192.168.126.20:5000/v2/_catalog
{"repositories":["busybox_v1","hello_test"]}

# View version
[root@docker ~]# curl -XGET http://192.168.126.20:5000/v2/hello_test/tags/list
{"name":"hello_test","tags":["v1"]}

[root@docker ~]# curl -XGET http://192.168.126.20:5000/v2/busybox_v1/tags/list
{"name":"busybox_v1","tags":["1.31.1"]}

Get image digest_hash

[root@docker ~]# curl --header "Accept: application/vnd.docker.distribution.manifest.v2+json"  -I -X  HEAD http://192.168.126.20:5000/v2/hello_test/manifests/v1
HTTP/1.1 200 OK
Content-Length: 525
Content-Type: application/vnd.docker.distribution.manifest.v2+json
Docker-Content-Digest: sha256:1b26826f602946860c279fce658f31050cff2c596583af237d971f4629b57792
Docker-Distribution-Api-Version: registry/2.0
Etag: "sha256:1b26826f602946860c279fce658f31050cff2c596583af237d971f4629b57792"
X-Content-Type-Options: nosniff
Date: Mon, 28 Jun 2021 08:19:30 GMT

[root@docker ~]# curl --header "Accept: application/vnd.docker.distribution.manifest.v2+json"  -I -X  HEAD http://192.168.126.20:5000/v2/busybox_v1/manifests/1.31.1
HTTP/1.1 200 OK
Content-Length: 527
Content-Type: application/vnd.docker.distribution.manifest.v2+json
Docker-Content-Digest: sha256:fd4a8673d0344c3a7f427fe4440d4b8dfd4fa59cfabbd9098f9eb0cb4ba905d0
Docker-Distribution-Api-Version: registry/2.0
Etag: "sha256:fd4a8673d0344c3a7f427fe4440d4b8dfd4fa59cfabbd9098f9eb0cb4ba905d0"
X-Content-Type-Options: nosniff
Date: Mon, 28 Jun 2021 08:24:17 GMT

Delete mirrored API

Usage:

DELETE /v2/<name>/manifests/<reference>

# Usage: curl -v -X DELETE http://IP : PORT/v2/IMAGE_NAME/manifests/REFERENCE
# Name: image name
# reference: image corresponding sha256 value

delete mirror

[root@docker ~]# curl -v -X DELETE http://192.168.126.20:5000/v2/hello_test/manifests/sha256:1b26826f602946860c279fce658f31050cff2c596583af237d971f4629b57792
* About to connect() to 192.168.126.20 port 5000 (#0)
*   Trying 192.168.126.20...
* Connected to 192.168.126.20 (192.168.126.20) port 5000 (#0)
> DELETE /v2/hello_test/manifests/sha256:1b26826f602946860c279fce658f31050cff2c596583af237d971f4629b57792 HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 192.168.126.20:5000
> Accept: */*
> 
< HTTP/1.1 202 Accepted
< Docker-Distribution-Api-Version: registry/2.0
< X-Content-Type-Options: nosniff
< Date: Mon, 28 Jun 2021 08:29:58 GMT
< Content-Length: 0
< 
* Connection #0 to host 192.168.126.20 left intact

The delete image here only deletes some metadata. You need to perform garbage collection to really delete the image data from the hard disk

Perform garbage collection:
registry garbage-collect /etc/docker/registry/config.yml 

garbage collection

Usage:

registry garbage-collect /etc/docker/registry/config.yml 

Enter private warehouse containers for garbage collection

[root@docker ~]# docker ps
CONTAINER ID   IMAGE      COMMAND                  CREATED       STATUS         PORTS                                       NAMES
ad2a3a85f7f4   registry   "/entrypoint.sh /etc..."   2 hours ago   Up 7 minutes   0.0.0.0:5000->5000/tcp, :::5000->5000/tcp   myregistry

[root@docker ~]# docker exec -it myregistry /bin/sh
/ # registry garbage-collect /etc/docker/registry/config.yml 
busybox_v1
busybox_v1: marking manifest sha256:fd4a8673d0344c3a7f427fe4440d4b8dfd4fa59cfabbd9098f9eb0cb4ba905d0 
busybox_v1: marking blob sha256:1c35c441208254cb7c3844ba95a96485388cef9ccc0646d562c7fc026e04c807
busybox_v1: marking blob sha256:76df9210b28cbd4bc127844914d0a23937ed213048dc6289b2a2d4f7d675c75e
hello_test

3 blobs marked, 3 blobs and 0 manifests eligible for deletion
blob eligible for deletion: sha256:1b26826f602946860c279fce658f31050cff2c596583af237d971f4629b57792
INFO[0000] Deleting blob: /docker/registry/v2/blobs/sha256/1b/1b26826f602946860c279fce658f31050cff2c596583af237d971f4629b57792  go.version=go1.11.2 instance.id=3e01bf0b-8ca7-4b3f-9114-9290839edb2d service=registry
blob eligible for deletion: sha256:b8dfde127a2919ff59ad3fd4a0776de178a555a76fff77a506e128aea3ed41e3
INFO[0000] Deleting blob: /docker/registry/v2/blobs/sha256/b8/b8dfde127a2919ff59ad3fd4a0776de178a555a76fff77a506e128aea3ed41e3  go.version=go1.11.2 instance.id=3e01bf0b-8ca7-4b3f-9114-9290839edb2d service=registry
blob eligible for deletion: sha256:d1165f2212346b2bab48cb01c1e39ee8ad1be46b87873d9ca7a4e434980a7726
INFO[0000] Deleting blob: /docker/registry/v2/blobs/sha256/d1/d1165f2212346b2bab48cb01c1e39ee8ad1be46b87873d9ca7a4e434980a7726  go.version=go1.11.2 instance.id=3e01bf0b-8ca7-4b3f-9114-9290839edb2d service=registry

Deleted successfully.

5, Private warehouse authentication function

To ensure the security of the private warehouse, you also need a security certificate to prevent unexpected things. Therefore, you need to create a self signed certificate on the Docker host where the private warehouse is built.

Create certificate store directory

[root@docker ~]# mkdir -p /usr/local/registry/certs

Generate self signed certificate

Mr. openssl generates a self signed certificate. After running the command, you need to fill in some certificate information. The most critical part is: Common Name (eg, your name or your server's hostname) []:192.168.126.20. Here is the address of the private warehouse

[root@docker ~]# openssl req -newkey rsa:2048 -nodes -sha256 -keyout /usr/local/registry/certs/domain.key -x509 -days 365 -out /usr/local/registry/certs/domain.crt
Generating a 2048 bit RSA private key
...............+++
...................................+++
writing new private key to '/usr/local/registry/certs/domain.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:cn
State or Province Name (full name) []:sx
Locality Name (eg, city) [Default City]:sl
Organization Name (eg, company) [Default Company Ltd]:test
Organizational Unit Name (eg, section) []:it
Common Name (eg, your name or your server's hostname) []:192.168.126.20		# Here is the address of the private warehouse
Email Address []:1234567@163.com

openssl req: Create certificate signing request and other functions;
-newkey: establish CSR Certificate signature file and RSA Private key file;
rsa:2048: Specify the created RSA The length of the private key is 2048;
-nodes: Do not encrypt the private key;
-sha256: use SHA256 Algorithm;
-keyout: Name and location of the created private key file;
-x509: Form of self issued certificate;
-days: Validity period of certificate;
-out: appoint CSR Name and location of output file;

Generate authentication password file

# Create a directory to store authentication password files
[root@docker ~]# mkdir -p /usr/local/registry/auth

# If there is no htpasswd function, you need to install httpd
[root@docker ~]# yum install -y httpd

# Create user and password
[root@docker ~]# htpasswd -Bbn zhangsan 123456 > /usr/local/registry/auth/htpasswd
# Htpasswd is the basic authentication file of apache http. You can use htpasswd command to generate user and password files. User name zhangsan, password 123456

Create private warehouse container

[root@docker ~]# docker run -di --name myregistry -p 5000:5000 \
    -v /mydata/docker_registry:/var/lib/registry \
    -v /usr/local/registry/certs:/certs \
    -v /usr/local/registry/auth:/auth \
    -e "REGISTRY_AUTH=htpasswd" \
    -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
    -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
    -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
    -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
    registry
d7d612a0c914f0bcf68ac0a9447bdc79ab43e404c2584a48dc1f0ccb19ed1fdc

[root@docker ~]# docker ps
CONTAINER ID   IMAGE      COMMAND                  CREATED          STATUS          PORTS                                       NAMES
d7d612a0c914   registry   "/entrypoint.sh /etc..."   14 seconds ago   Up 12 seconds   0.0.0.0:5000->5000/tcp, :::5000->5000/tcp   myregistry

Modify the daemon of Docker client JSON file

[root@docker-client ~]# vim /etc/docker/daemon.json 
{
  "registry-mirrors": [
    "https://e9hk8fzj.mirror.aliyuncs.com",
    "https://docker.mirrors.ustc.edu.cn"
  ],
    "insecure-registries": ["192.168.126.20:5000"]    # The content added in this behavior is the IP address of the host running the warehouse container, and the port is consistent with the host port specified when using the registry image to run the container
}

Label the local image on the Docker client

[root@docker-client ~]# docker images
REPOSITORY                                                TAG        IMAGE ID       CREATED         SIZE
centos                                                    7          8652b9f0cb4c   7 months ago    204MB

[root@docker-client ~]# docker tag centos:7 192.168.126.20:5000/centos_test:v1

[root@k8s-docker-client ~]# docker images
REPOSITORY                           TAG                 IMAGE ID            CREATED             SIZE
192.168.126.20:5000/centos_test      v1                  8652b9f0cb4c        7 months ago        204MB
centos                               7                   8652b9f0cb4c        7 months ago        204MB                                                 7          8652b9f0cb4c   7 months ago    204MB

Failed to push image to private warehouse

[root@k8s-docker-client ~]# docker push 192.168.126.20:5000/centos_test:v1
The push refers to repository [192.168.126.20:5000/centos_test]
174f56854903: Preparing 
no basic auth credentials	# Because there is no login authentication.

If you directly push the image, it will certainly fail, and the error of no basic auth credentials appears, because there is no login authentication.

Login account

Log in to the private warehouse by entering the account and password through the docker login command

[root@k8s-docker-client ~]# docker login 192.168.126.20:5000 -u zhangsan -p 123456
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

Push image to private warehouse succeeded

push the image again and find that it can be pushed successfully.

[root@k8s-master ~]# docker push 192.168.126.20:5000/centos_test:v1
The push refers to repository [192.168.126.20:5000/centos_test]
174f56854903: Pushed 
v1: digest: sha256:e4ca2ed0202e76be184e75fb26d14bf974193579039d5573fb2348664deef76e size: 529

see

View via browser

The construction of private image warehouse can also be realized through harbor. Harbor is an enterprise Docker Registry management project open source by VMware company. It includes rights management (RBAC), LDAP, log audit, management interface, self registration, image replication, Chinese support and other functions.

Keywords: Docker

Added by Hitoshi on Sat, 22 Jan 2022 13:33:19 +0200