---
title: How to work with a private registry
description: Canonical makes open source secure, reliable and easy to use, providing
  support for Ubuntu and a portfolio of enterprise-grade technologies. Founded in
  2004, Canonical operates globally with team members in over 80 countries.
url: https://canonical.com/microk8s/docs/registry-private?format=md
---

*Submit*

# How to work with a private registry

Often organisations have their own private registry to assist collaboration and accelerate development. Kubernetes (and thus MicroK8s) need to be aware of the registry endpoints before being able to pull container images.

## [Insecure registry](https://canonical.com/microk8s/docs/registry-private?format=md#p-19996-insecure-registry)

### [Pushing from Docker](https://canonical.com/microk8s/docs/registry-private?format=md#p-19996-pushing-from-docker)

Let’s assume the private insecure registry is at `10.141.241.175` on port `32000`. The images we build need to be tagged with the registry endpoint:

```
docker build . -t 10.141.241.175:32000/mynginx:registry
```

Pushing the `mynginx` image at this point will fail because the local Docker does not trust the private insecure registry. The docker daemon used for building images should be configured to trust the private insecure registry. This is done by marking the registry endpoint in `/etc/docker/daemon.json`:

```
{
  "insecure-registries" : ["10.141.241.175:32000"]
}
```

Restart the Docker daemon on the host to load the new configuration:

```
sudo systemctl restart docker
```

Now running

```
docker push  10.141.241.175:32000/mynginx
```

…should succeed in uploading the image to the registry.

### [Configuring MicroK8s](https://canonical.com/microk8s/docs/registry-private?format=md#p-19996-configuring-microk8s)

Attempting to pull an image in MicroK8s at this point will result in an error like this:

```
  Warning  Failed             1s (x2 over 16s)  kubelet, jackal-vgn-fz11m  Failed to pull image "10.141.241.175:32000/mynginx:registry": rpc error: code = Unknown desc = failed to resolve image "10.141.241.175:32000/mynginx:registry": no available registry endpoint: failed to do request: Head https://10.141.241.175:32000/v2/mynginx/manifests/registry: http: server gave HTTP response to HTTPS client
```

#### For MicroK8s version 1.23 or newer

MicroK8s 1.23 and newer versions use separate `hosts.toml` files for each image registry. For registry `http://10.141.241.175:32000`, this would be at `/var/snap/microk8s/current/args/certs.d/10.141.241.175:32000/hosts.toml`. First, create the directory if it does not exist:

```
sudo mkdir -p /var/snap/microk8s/current/args/certs.d/10.141.241.175:32000
sudo touch /var/snap/microk8s/current/args/certs.d/10.141.241.175:32000/hosts.toml
```

Then, edit the file we just created and make sure the contents are as follows:

```
# /var/snap/microk8s/current/args/certs.d/10.141.241.175:32000/hosts.toml
server = "http://10.141.241.175:32000"

[host."http://10.141.241.175:32000"]
capabilities = ["pull", "resolve"]
```

Restart MicroK8s to have the new configuration loaded:

```
microk8s stop
microk8s start
```

#### For MicroK8s version 1.22 or older

We need to edit `/var/snap/microk8s/current/args/containerd-template.toml` and add the following under `[plugins."io.containerd.grpc.v1.cri".registry.mirrors]`:

```
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."10.141.241.175:32000"]
endpoint = ["http://10.141.241.175:32000"]
```

See the full file [here](https://github.com/ubuntu/microk8s/blob/master/microk8s-resources/default-args/containerd-template.toml).

Restart MicroK8s to have the new configuration loaded:

```
microk8s stop
microk8s start
```

The image can now be deployed with:

```
microk8s kubectl create deployment nginx --image=10.141.241.175:32000/mynginx:registry
```

Note that the image is referenced with `10.141.241.175:32000/mynginx:registry`.

## [Secure registry](https://canonical.com/microk8s/docs/registry-private?format=md#p-19996-secure-registry)

There are a lot of ways to setup a private secure registry that may slightly change the way you interact with it. Instead of diving into the specifics of each setup we provide here two pointers on how you can approach the integration with Kubernetes.

* In the [official Kubernetes documentation](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/) a method is described for creating a secret from the Docker login credentials and using this to access the secure registry. To achieve this, `imagePullSecrets` is used as part of the container spec.
* MicroK8s v1.14 and onwards uses **containerd**. [As described here](https://github.com/containerd/cri/blob/master/docs/registry.md), users should be aware of the secure registry and the credentials needed to access it.

  It is possible to configure default credentials in the configuration of containerd, so that they are used automatically when pulling images from your private registry, without users having to specify an image pull secret manually for each container.

  To do this, you have to edit `/var/snap/microk8s/current/args/containerd-template.toml`. If the private registry at `10.141.241.175:32000` needs authentication with username `my-secret-user` and password `my-safe-password`, add the following section (the configuration is in TOML format, so indentation does not matter):

  ```
  # containerd-template.toml

  [plugins."io.containerd.grpc.v1.cri".registry.configs."10.141.241.175:32000".auth]
  username = "my-secret-user"
  password = "my-safe-password"
  ```

## [Configure registry mirrors](https://canonical.com/microk8s/docs/registry-private?format=md#p-19996-configure-registry-mirrors)

Under specific circumstances (e.g. geographical restrictions, network firewalls), certain image registries may not be available. For example, for Chinese mainland users `k8s.gcr.io` is not available, and a mirror such as `registry.cn-hangzhou.aliyuncs.com/google_containers` can be used instead.

In order to configure a registry mirror for `registry.k8s.io` and have it point to `registry.cn-hangzhou.aliyuncs.com/google_containers`, the following configuration is required:

```
# create a directory with the registry name
sudo mkdir -p /var/snap/microk8s/current/args/certs.d/registry.k8s.io

# create the hosts.toml file pointing to the mirror
echo '
server = "registry.k8s.io"

[host."https://registry.aliyuncs.com/v2/google_containers"]
  capabilities = ["pull", "resolve"]
  override_path = true
' | sudo tee -a /var/snap/microk8s/current/args/certs.d/registry.k8s.io/hosts.toml
```

A restart of the containerd daemon helps but is not required, since changes should take effect immediately.

```
sudo snap restart microk8s
```

## [Using a custom CA](https://canonical.com/microk8s/docs/registry-private?format=md#p-19996-using-a-custom-ca)

For internal registries where TLS with a custom CA is used (e.g. in enterprise environments), containerd will fail to fetch images unless the CA is explicitly specified.

In our previous example, if the registry was instead at `https://10.141.241.175:32000`, the configuration should be changed to the following:

```
# /var/snap/microk8s/current/args/certs.d/10.141.241.175:32000/hosts.toml
server = "https://10.141.241.175:32000"

[host."https://10.141.241.175:32000"]
capabilities = ["pull", "resolve"]
ca = "/var/snap/microk8s/current/args/certs.d/10.141.241.175:32000/ca.crt"
```

Also make sure to add the CA certificate under `/var/snap/microk8s/current/args/certs.d/10.141.241.175:32000/ca.crt`:

```
# /var/snap/microk8s/current/args/certs.d/10.141.241.175:32000/ca.crt
-----BEGIN CERTIFICATE------
.....
-----END CERTIFICATE--------
```

Last updated 3 years ago. [Help improve this document in the forum](https://discuss.kubernetes.io/t/how-to-work-with-a-private-registry/11273).
