---
# System prepended metadata

title: Note for deploy private registry

---

# Note for deploy private registry

## Deploy privated registry on existing microk8s registry
### 1. Make certificate for tls
- Prepare config file
```bash
# ssl.conf
[ req ]
distinguished_name = req_distinguished_name
req_extensions     = req_ext

[ req_distinguished_name ]
commonName                  = container-registry

[ req_ext ]
subjectAltName = @alt_names

[alt_names]
IP.1    = 127.0.0.1
DNS.1   = localhost

[ v3_ca ]
subjectAltName = @alt_names
```
- Make certificate for tls
```bash
export SNAP_DATA="/var/snap/microk8s/current"
export OPENSSL_CONF="/snap/microk8s/current/etc/ssl/openssl.cnf"

openssl genrsa -out ${SNAP_DATA}/certs/registry.key 2048
openssl req -new -sha256 -key ${SNAP_DATA}/certs/registry.key -out ${SNAP_DATA}/certs/registry.csr -config ssl.conf -subj "/CN=container-registry"
openssl x509 -req -sha256 -in ${SNAP_DATA}/certs/registry.csr -CA ${SNAP_DATA}/certs/ca.crt -CAkey ${SNAP_DATA}/certs/ca.key -CAcreateserial -out ${SNAP_DATA}/certs/registry.crt -days 365 -extensions v3_ext -extfile ssl.conf
```

### 2. Create auth for private registry
```
$USER=registry-username
$PASSWD=registry-password

docker run --rm --entrypoint htpasswd registry:2.7.0 -Bbn $USER $PASSWD > htpasswd
```
- Notice that the images version `registry:2.7.0` should be the version that contains htpasswd

### 3. Configure certificate and auth as a Secret for Kubernetes
```
NAMESPACE=container-registry
microk8s kubectl create secret tls certs-secret -n $NAMESPACE --cert=${SNAP_DATA}/certs/registry.crt --key=${SNAP_DATA}/certs/registry.key
microk8s kubectl create secret generic auth-secret -n $NAMESPACE --from-file=htpasswd
```

### 4. Configure the registry deployment with those secrets and restart it
- Create yaml for new configuration
```yaml
# registry-auth.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: registry
  name: registry
  namespace: container-registry
spec:
  replicas: 1
  selector:
    matchLabels:
      app: registry
  template:
    metadata:
      labels:
        app: registry
    spec:
      containers:
      - name: registry
        image: cdkbot/registry-amd64:2.6
        env:
        - name: REGISTRY_HTTP_ADDR
          value: :5000
        - name: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY
          value: /var/lib/registry
        - name: REGISTRY_STORAGE_DELETE_ENABLED
          value: "yes"
        - name: REGISTRY_AUTH
          value: "htpasswd"
        - name: REGISTRY_AUTH_HTPASSWD_REALM
          value: "Registry Realm"
        - name: REGISTRY_AUTH_HTPASSWD_PATH
          value: "/auth/htpasswd"
        - name: REGISTRY_HTTP_TLS_CERTIFICATE
          value: "/certs/tls.crt"
        - name: REGISTRY_HTTP_TLS_KEY
          value: "/certs/tls.key"
        ports:
        - containerPort: 5000
          name: registry
          protocol: TCP
        volumeMounts:
          - mountPath: /var/lib/registry
            name: registry-data
          - name: certs-vol
            mountPath: "/certs"
            readOnly: true
          - name: auth-vol
            mountPath: "/auth"
            readOnly: true
      volumes:
        - name: registry-data
          persistentVolumeClaim:
            claimName: registry-claim
        - name: certs-vol
          secret:
            secretName: certs-secret
        - name: auth-vol
          secret:
            secretName: auth-secret
```
- restart the registry deployment
```
microk8s kubectl rollout restart deployment/registry -n $NAMESPACE
```

## Configure the private registry for containerd
### 1. Generate docker login auth
- Generate auth using docker
```
docker login localhost:32000 -u registry-username -p registry-password
cat ~/.docker/config.json
```
- Output will like that:
```json
{
	"auths": {
		"localhost:32000": {
			"auth": "YWljO......"
		}
	},
	"HttpHeaders": {
		"User-Agent": "Docker-Client/19.03.8 (linux)"
	}
}
```
### 2. Add auth to containerd configuration

```
    [plugins."io.containerd.grpc.v1.cri".registry.configs]
      [plugins."io.containerd.grpc.v1.cri".registry.configs."localhost:32000".tls]
        ca_file = "${SNAP_DATA}/certs/ca.crt"
      [plugins."io.containerd.grpc.v1.cri".registry.configs."localhost:32000".auth]
        username = "registry-username"
        password = "registry-password"
        auth = "YWljO......"
```
### 3. Restart containerd daemon to load configuration by restart microk8s
```
microk8s stop
microk8s start
```

## Trouble shooting
### certificate signed by unknown authority
```
Failed to pull image "localhost:32000/nginx": rpc error: code = Unknown desc = failed to pull and unpack image "localhost:32000/nginx:latest": failed to resolve reference "localhost:32000/nginx:latest": failed to do request: Head "https://localhost:32000/v2/nginx/manifests/latest": x509: certificate signed by unknown authority
```
- Need to config the ca file that signed for registry
- in `${SNAP_DATA}/args/containerd-template.toml`
    ```
          [plugins."io.containerd.grpc.v1.cri".registry.configs."localhost:32000".tls]
            ca_file = "${SNAP_DATA}/certs/ca.crt"
    ```
### 401 Unauthorized
```
Failed to pull image "localhost:32000/nginx": rpc error: code = Unknown desc = failed to pull and unpack image "localhost:32000/nginx:latest": failed to resolve reference "localhost:32000/nginx:latest": unexpected status code [manifests latest]: 401 Unauthorized
```
- Need to config correct auth for registry setting
- in `${SNAP_DATA}/args/containerd-template.toml`
    ```
     [plugins."io.containerd.grpc.v1.cri".registry.configs."localhost:32000".auth]
            username = "registry-username"
            password = "registry-password"
            auth = "YWljO......"
    ```
### certificate is not valid for any names, but wanted to match localhost
```
Failed to pull image "localhost:32000/nginx": rpc error: code = Unknown desc = failed to pull and unpack image "localhost:32000/nginx:latest": failed to resolve reference "localhost:32000/nginx:latest": failed to do request: Head "https://localhost:32000/v2/nginx/manifests/latest": x509: certificate is not valid for any names, but wanted to match localhost
```
- Need to sign certificate with `subjectAltName` and the DNS is your registry doamin name.
- See [this step](https://hackmd.io/2wkiLQuZQBOj69oUUwNz4g?both#1-Make-certificate-for-tls).
## Reference
https://medium.com/swlh/deploy-your-private-docker-registry-as-a-pod-in-kubernetes-f6a489bf0180
https://github.com/containerd/cri/blob/master/docs/registry.md