<h2>Problem Statement</h2>

<ul>
<li>I want to deliver a private registry which all the images I need for my product bundled in them ( Yes, It will be fat image, but I am fine with that) </li>
<li>I would manually upload this image in some way </li>
<li>I would run the docker private registry as a service in Kubernetes (probably in some namespace)</li>
<li>When other services/deployments (in the same namespace as registry)  happen in Kubernetes, they should refer to this registry using a consistent name</li>
</ul>

<h2>Constraints</h2>

<ul>
<li>We want registry to be exposed only to the cluster and not outside</li>
<li>We want to use self signed certificate and not signed by CA</li>
</ul>

<p>I followed some instructions from these links (do not know whether it was a right thing to do) </p>

<ul>
<li><a href="https://kubernetes.io/docs/concepts/cluster-administration/certificates/" rel="nofollow noreferrer">https://kubernetes.io/docs/concepts/cluster-administration/certificates/</a></li>
<li><a href="https://kubernetes.io/docs/tasks/tls/managing-tls-in-a-cluster/#create-a-certificate-signing-request-object-to-send-to-the-kubernetes-api" rel="nofollow noreferrer">https://kubernetes.io/docs/tasks/tls/managing-tls-in-a-cluster/#create-a-certificate-signing-request-object-to-send-to-the-kubernetes-api</a></li>
</ul>

<h3>Create a certificate signed through Kubernetes</h3>

<ol>
<li><p>Create a server.key </p></li>
<li><p>Create a csr.info</p></li>
</ol>

<pre><code>[ req ]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn

[ dn ]
C = US
ST = oh
L = cincinnati
O = engg
OU = prod
CN = prateek.svc.cluster.local

[ req_ext ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = registry.prateek.svc.cluster.local

[ v3_ext ]
authorityKeyIdentifier=keyid,issuer:always
basicConstraints=CA:FALSE
keyUsage=keyEncipherment,dataEncipherment
extendedKeyUsage=serverAuth,clientAuth
subjectAltName=@alt_names
</code></pre>

<ol start="3">
<li><p>Created the server.csr (openssl req -new -key server.key -out server.csr -config csr.conf)</p></li>
<li><p>Create the CertificateSigningRequest in K8s</p></li>
</ol>

<pre><code>cat &lt;&lt;EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1beta1
kind: CertificateSigningRequest
metadata:
name: registry.prateek
spec:
groups:
- system:authenticated
request: $(cat server.csr | base64 | tr -d '\n')
usages:
- digital signature
- key encipherment
- server auth
EOF
</code></pre>

<ol start="5">
<li>Checked if the CSR exists</li>
</ol>

<pre><code>kubectl describe csr registry.prateek
Name: registry.prateek
Labels: &lt;none&gt;
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"certificates.k8s.io/v1beta1","kind":"CertificateSigningRequest","metadata":{"annotations":{},"name":"registry.prateek","namespace":""},"spec":{"groups":["system:authenticated"],"request":"LS0sdfsfsdsfd=","usages":["digital signature","key encipherment","server auth"]}}

CreationTimestamp: Thu, 11 Apr 2019 11:15:42 -0400
Requesting User: docker-for-desktop
Status: Pending
Subject:
Common Name: prateek.svc.cluster.local
Serial Number:
Organization: engg
Organizational Unit: prod
Country: US
Locality: cincinnati
Province: oh
Subject Alternative Names:
DNS Names: registry.prateek.svc.cluster.local
Events: &lt;none&gt;
</code></pre>

<ol start="6">
<li>Approved the CSR : kubectl certificate approve registry.prateek</li>
</ol>

<h3>Start the registry internal service</h3>

<ol start="7">
<li>Added cert and key to the kind: Secret</li>
</ol>

registry-secret.yml

<pre><code>apiVersion: v1
kind: Secret
metadata:
  name: registry-credentials
data:
  certificate: &lt;CERTIFICATE in base64&gt;
  key: &lt;KEY in base64&gt;
</code></pre>

<ol start="8">
<li>Create registry deployment and service (using those secrets)

registry-deployment.yml</li>
</ol>

<pre><code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: registry
  namespace: prateek
  labels:
      app: registry
spec:
  replicas: 1
  selector:
    matchLabels:
      app: registry
  template:
    metadata:
      labels:
        app: registry
    spec:
      containers:
        - name: registry
          image: prateek/registry
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 443
          env:
            - name: REGISTRY_HTTP_ADDR
              value: "0.0.0.0:443"
            - name: REGISTRY_HTTP_TLS_CERTIFICATE
              value: "/certs/certificate"
            - name: REGISTRY_HTTP_TLS_KEY
              value: "/certs/key"
          volumeMounts:
            - name: cert-files
              mountPath: /certs
      volumes:
        - name: cert-files
          secret:
            secretName: registry-credentials
</code></pre>

<h3>registry-service.yml</h3>

<pre><code>apiVersion: v1
kind: Service
metadata:
  name: registry
  namespace: prateek
spec:
  selector:
    app: registry
  ports:
  - protocol: TCP
    port: 443
    targetPort: 443
  type: LoadBalancer
</code></pre>

<h3>Test regsitry service is up</h3>

<ol start="9">
<li>Tried to this the registry endpoint thru a test pod. I had image of this test pod loaded in docker already. </li>
</ol>

<pre><code>curl https://registry.prateek.svc.cluster.local/v2/_catalog -k
{"repositories":["prateek/echo"]}
</code></pre>

<h3>Deployment using image from the registry service</h3>

<ol start="10">
<li>Tried deployment with image: registry.prateek/prateek/echo:latest</li>
</ol>

<pre><code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello
  namespace: cequence
  labels:
      app: hello
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
      - name: hello
        image: registry.prateek/prateek/echo:latest
        imagePullPolicy: IfNotPresent
        ports:
         - containerPort: 5678
        args: ["-text=hello"]
</code></pre>

<ol start="11">
<li>the deployment gives the error </li>
</ol>

<pre><code>Normal Pulling 10s (x2 over 25s) kubelet, docker-for-desktop pulling image "registry.prateek/prateek/echo:latest"
Warning Failed 10s (x2 over 25s) kubelet, docker-for-desktop Failed to pull image "registry.prateek/prateek/echo:latest": rpc error: code = Unknown desc = Error response from daemon: Get https://registry.prateek/v2/: Service Unavailable 
</code></pre>

<ol start="12">
<li>Changed deployment to have image: registry.prateek.svc.cluster.local/prateek/echo:latest</li>
</ol>

<pre><code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello
  namespace: cequence
  labels:
      app: hello
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
      - name: hello
        image: registry.prateek.svc.cluster.local/prateek/echo:latest
        imagePullPolicy: IfNotPresent
        ports:
         - containerPort: 5678
        args: ["-text=hello"]
</code></pre>

<ol start="13">
<li>get the similar error</li>
</ol>

<pre><code>Warning Failed 1s kubelet, docker-for-desktop Failed to pull image "registry.prateek.svc.cluster.local/prateek/echo:latest": rpc error: code = Unknown desc = Error response from daemon: Get https://registry.prateek.svc.cluster.local/v2/: Service Unavailable
</code></pre>

<p>I do not that this is even possible. Run a docker registry as a service and point other service in the namespace to use that registry deployment in the cluster. Any suggestion is welcome</p>

Prateek Negi
<p>The container daemon is running outside of kubernetes.</p>

<p>Therefore, if you want to pull the image, you need to make sure that the registry is reachable from the node directly, without using kubernetes mechanisms like a service. (Not like you tested it in step 9 through a pod, you must be able to work directly on the node!)</p>

<p>The usual options are to create a DNS entry or hosts.txt entry to point to a node where either through a <code>hostPort</code> (container) or <code>nodePort</code> (service) the registry is accessible or you use an appropriate ingress.</p>
