How to create a private Docker registry and add images via Jenkins pipeline

This post describes how to setup a local Docker registry within your network and use it for your projects. This is a precondition if you want to deploy and run your own projects on your own kubernetes cluster and do not want to expose everything to the public. The Docker registry itself runs within docker, so you need a docker host ready.

Prerequisites

You need to have a Docker host to run a registry. I am using my infrastructure pi to host the registry (which also hosts my git, jenkins etc.). Please check here how to install docker on raspberry pi.

Start registry on docker host

I am running the docker registry on my "infra" host which is the same raspberry pi which also hosts my git and jenkins.

There is an official image available on docker hub which you can start with the following command:

user1@host:~ $ docker run -d -p 5000:5000 --restart always --name registry registry:2
Unable to find image 'registry:2' locally
2: Pulling from library/registry
9fda8d8052c6: Pull complete 
5d54e960e981: Pull complete 
cb9be1f8a194: Pull complete 
9d2d3fd2527f: Pull complete 
356f0e046603: Pull complete 
Digest: sha256:d5f2fb0940fe9371b6b026b9b66ad08d8ab7b0d56b6ee8d5c71cb9b45a374307
Status: Downloaded newer image for registry:2
8401a825da711e9cc09fd2696fbcec326cadbef18f8bead6145960bcb6e98c56
user1@host:~ $ 

To check if registry is up run:

user1@host:~ $ docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED              STATUS          PORTS                                       NAMES
8401a825da71   registry:2   "/entrypoint.sh /etc…"   About a minute ago   Up 55 seconds   0.0.0.0:5000->5000/tcp, :::5000->5000/tcp   registry
user1@host:~ $ 

Using the docker private registry

Since the registry is by default not set up with https and trustworthy protocol all docker installations in your local network need to be configured to be allowed to communicate with this local registry.

For that the file /etc/docker/daemon.json has to be created or edited so that it contains

{ 
  "insecure-registries": ["ip_of_your_docker_host:5000"] 
}

Replace ip_of_your_docker_host with the ip address of the host running the registry in your local network.

Managing Image repository

The images are part of the local docker image repository of the docker host. Existing images can be viewed with:

$ docker image ls
REPOSITORY                        TAG       IMAGE ID       CREATED        SIZE
ip_of_your_docker_host:5000/test/testapp   latest    b23c2e895c08   39 hours ago   563MB
ip_of_your_docker_host:5000/test/testapp   <none>    12228dd0755a   39 hours ago   563MB
registry                          2         3c11102b9417   5 weeks ago    23.7MB

Images can be deleted directly from the docker host with :

$ docker image rm 3c25f5f5ab79
Untagged: ip_of_your_docker_host:5000/test/testapp@sha256:1981706291df4b5925bc5863490ed5326bd8bcfa46fcd6a9d134f3743475787a
Deleted: sha256:3c25f5f5ab79069b56f22587006671964a809ad8383f35ced4314eef384029d2

You can also cleanup all unused artifacts including images as described here.

Push images from Jenkins pipeline

The host running your Jenkins should have docker installed and you should have applied the unsecure-registries change on that host. To push images created via pipeline to the local registry add the following to the Jenkinsfile:

... 
stage('Docker') {
            steps {
                sh 'docker build . -t ip_of_your_docker_host:5000/test/springk8s:latest'
                sh 'docker push --all-tags ip_of_your_docker_host:5000/test/springk8s'
            }
        }
...

A sample project on my github page contains a full example of a Jenkinsfile (and much more). Output of such a build step in jenkins could look more or less like this.

+ docker build . -t registry.infra.local:5000/test/springk8s:latest
#0 building with "default" instance using docker driver
#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile:
#1 transferring dockerfile: 241B done
#1 DONE 0.1s
#2 [internal] load .dockerignore
#2 transferring context: 2B done
#2 DONE 0.1s
#3 [internal] load metadata for docker.io/library/openjdk:17
#3 DONE 1.3s
#4 [1/2] FROM docker.io/library/openjdk:17@sha256:528707081fdb9562eb819128a9f85ae7fe000e2fbaeaf9f87662e7b3f38cb7d8
#4 resolve docker.io/library/openjdk:17@sha256:528707081fdb9562eb819128a9f85ae7fe000e2fbaeaf9f87662e7b3f38cb7d8 0.1s done
#4 sha256:fe66142579ff5bb0bb5cf989222e2bc77a97dcbd0283887dec04d5b9dfd48cfa 0B / 14.29MB 0.1s
...
#5 [internal] load build context
#5 transferring context: 19.01MB 1.1s done
#5 DONE 1.1s
#4 [1/2] FROM docker.io/library/openjdk:17@sha256:528707081fdb9562eb819128a9f85ae7fe000e2fbaeaf9f87662e7b3f38cb7d8
#4 sha256:fe66142579ff5bb0bb5cf989222e2bc77a97dcbd0283887dec04d5b9dfd48cfa 10.49MB / 14.29MB 1.5s
...
#4 DONE 39.4s
#6 [2/2] ADD build/libs/spring-boot-0.0.1-SNAPSHOT.jar spring-boot-0.0.1-SNAPSHOT.jar
#6 DONE 17.0s
#7 exporting to image
#7 exporting layers
#7 exporting layers 0.6s done
#7 writing image sha256:98d4b24240e57cabe7975cbcfacca334c6887302ec75795677c2b46dca67439f done
#7 naming to registry.infra.local:5000/test/springk8s:latest 0.0s done
#7 DONE 0.6s
[Pipeline] sh
+ docker push registry.infra.local:5000/test/springk8s:latest
The push refers to repository [registry.infra.local:5000/test/springk8s]
3fa8f5b1bedc: Preparing
e017d39c755a: Preparing
03ee828ef0e4: Preparing
b0d4c4485e7e: Preparing
3fa8f5b1bedc: Pushed
03ee828ef0e4: Pushed
b0d4c4485e7e: Pushed
e017d39c755a: Pushed
latest: digest: sha256:81eb6fd89ca60864dcb5f43a9f6dcc706087295938f0611169315c57c56ace0f size: 1166
...
[Pipeline] End of Pipeline
Finished: SUCCESS

Leave a Reply

Your email address will not be published. Required fields are marked *