<p>I have a standalone Kubernetes cluster:</p>
<pre><code>plane node - hostname kubernetes1 - 192.168.1.126
work node - hostname kubernetes2 - 192.168.1.138
</code></pre>
<p>I deployed this private repository:</p>
<pre><code>apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv1
spec:
  capacity:
    storage: 5Gi # specify your own size
  volumeMode: Filesystem
  persistentVolumeReclaimPolicy: Retain
  local:
    path: /opt/registry # can be any path
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - kubernetes2
  accessModes:
    - ReadWriteMany # only 1 node will read/write on the path.
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pv1-claim
spec: # should match specs added in the PersistenVolume
  accessModes:
    - ReadWriteMany
  volumeMode: Filesystem
  resources:
    requests:
      storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: private-repository-k8s
  labels:
    app: private-repository-k8s
spec:
  replicas: 1
  selector:
    matchLabels:
      app: private-repository-k8s
  template:
    metadata:
      labels:
        app: private-repository-k8s
    spec:
      volumes:
       - name: certs-vol
         hostPath:
          path: /opt/certs
          type: Directory
       - name: task-pv-storage
         persistentVolumeClaim:
           claimName: pv1-claim # specify the PVC that you've created. PVC and Deployment must be in same namespace.
      containers:
        - image: registry:2
          name: private-repository-k8s
          imagePullPolicy: IfNotPresent
          env:
          - name: REGISTRY_HTTP_TLS_CERTIFICATE
            value: &quot;/opt/certs/registry.crt&quot;
          - name: REGISTRY_HTTP_TLS_KEY
            value: &quot;/opt/certs/registry.key&quot;
          ports:
            - containerPort: 5000
          volumeMounts:
          - name: certs-vol
            mountPath: /opt/certs
          - name: task-pv-storage
            mountPath: /opt/registry
</code></pre>
<p>Service is deployed on the work node:</p>
<pre><code>kubernetes@kubernetes1:/opt/registry$ kubectl get pods
NAME                                      READY   STATUS    RESTARTS   AGE
private-repository-k8s-6d5d954b4f-ldwd6   1/1     Running   0          153m
kubernetes@kubernetes1:/opt/registry$
</code></pre>
<p>I tried to create a ingress access because I want to access this pod from the outside:</p>
<pre><code>kubectl create namespace test
</code></pre>
<p><em><strong>service controller:</strong></em></p>
<pre><code>apiVersion: networking.k8s.io/v1   
kind: Ingress   
metadata:
  namespace: test   
  name: private-repository-service-ingress   
  annotations:   
    nginx.ingress.kubernetes.io/rewrite-target: /$1   
spec:   
  rules:   
    - host: kubernetes2   
      http:   
        paths:   
          - path: /   
            pathType: Prefix   
            backend:   
              service:   
                name: private-repository-service   
                port:   
                  number: 5000
</code></pre>
<p><em><strong>service-load-balancer:</strong></em></p>
<pre><code>apiVersion: v1
kind: Service
metadata:
  namespace: test
  name: private-repository-service
spec:
  #type: NodePort
  selector:
    app: private-repository-k8s
  ports:
      # By default and for convenience, the `targetPort` is set to the same value as the `port` field.
    - port: 5000
      targetPort: 5000
      # Optional field
      # By default and for convenience, the Kubernetes control plane will allocate a port from a range (default: 30000-32767)
      #nodePort: 30007
</code></pre>
<p>When I run <code>curl 192.168.1.138:5000</code> there is no response.
Do you know where I might be wrong?</p>
<p><em><strong>EDIT:</strong></em></p>
<pre><code>kubernetes@kubernetes1:~$ kubectl get svc
NAME                       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
kubernetes                 ClusterIP   10.96.0.1        &lt;none&gt;        443/TCP    3d20h
private-registry-service   ClusterIP   10.103.148.234   &lt;none&gt;        5000/TCP   6h34m
kubernetes@kubernetes1:~$
</code></pre>

<p>Looks like you don't have an ingress-controller of any kind and just want to access the registry directly. In that case you need to create a service of type <code>NodePort</code>.</p>
<pre class="lang-yaml prettyprint-override"><code>apiVersion: v1
kind: Service
metadata:
  namespace: test
  name: private-repository-service
spec:
  type: NodePort # Added
  selector:
    app: private-repository-k8s
  ports:
    - port: 5000
      targetPort: 5000
      nodePort: 30123 # Added
</code></pre>
<p>This will bind the service port 5000 to the host's port 30123.
If you run <code>kubectl get svc</code> this will than give you a slightly different output.</p>
<pre class="lang-bash prettyprint-override"><code>kubernetes@kubernetes1:~$ kubectl get svc
NAME                       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
kubernetes                 ClusterIP   10.96.0.1        &lt;none&gt;        443/TCP    3d20h
private-registry-service   ClusterIP   10.103.148.234   &lt;none&gt;        5000:30123/TCP   6h34m
</code></pre>
<p>Notice the mapping <code>30312:5000</code>. Now you can send a request to the registry on that port: <code>curl 192.168.1.138:30312</code>. You can also omit the <code>nodePort</code> field, kubernetes will then choose a random one in the range between 3000 and 32767 for you. It will be displayed in the <code>kubectl get svc</code> command as shown above. The <code>Ingress</code> is not needed and can be removed.</p>
<p>If you want to use an <code>Ingress</code> as you provided you need to use an ingress-controller, like nginx or traefik, see also <a href="https://kubernetes.io/docs/concepts/services-networking/ingress/" rel="nofollow noreferrer">kubernetes docs</a> on that topic.</p>
<blockquote>
<p>[...] An Ingress controller is responsible for fulfilling the Ingress, usually with a load balancer, though it may also configure your edge router or additional frontends to help handle the traffic.</p>
</blockquote>
<p><strong>EDIT</strong></p>
<p>There are a lot of ingress-controllers out there, they all have their advantages and disadvantages. For a beginner, nginx might be a good choise, see <a href="https://docs.nginx.com/" rel="nofollow noreferrer">docs</a>.</p>
<p>To install it, run these commands (from the <a href="https://docs.nginx.com/nginx-ingress-controller/installation/installation-with-helm/" rel="nofollow noreferrer">install docs page</a>)</p>
<pre class="lang-bash prettyprint-override"><code>$ helm repo add nginx-stable https://helm.nginx.com/stable
$ helm repo update
$ helm install my-release nginx-stable/nginx-ingress
</code></pre>
<p>where <code>my-release</code> is a random name, you can choose what ever you want. This will create an nginx pod in the namespace you installed the chart. It will also create an nginx-ingress service of type <code>LoadBalancer</code>, like this:</p>
<pre><code>kubectl get svc
NAME                       TYPE           CLUSTER-IP     EXTERNAL-IP          
my-release-nginx-ingress   LoadBalancer   10.109.27.49   &lt;pending&gt;     80:30536/TCP,443:31694/TCP   111s
</code></pre>
<p>As you can see the <code>EXTERNAL-IP</code> is in <code>&lt;pending&gt;</code> state. In a public cloud environment like AWS a load-balancer resource like ELB is created and its public ip will be assigned to the service as <code>EXTERNAL-IP</code>. In your on-premise setup it will stay in <code>&lt;pending&gt;</code> status. But as you can see, two random node ports are mapped to the http/https ports, like with the <code>nodePort</code> setup above. Here it's 80 -&gt; 30536 and 433 -&gt; 31694, for you it will be something similar.</p>
<p>Now you can apply your manifests as above. You'll get a service of type <code>ClusterIP</code>. Also create an <code>Ingress</code> like this:</p>
<pre><code>apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: private-repository-service 
spec:
  ingressClassName: nginx
  rules:
    - host: example.com
      http:
        paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: private-repository-service 
              port:
                number: 5000
</code></pre>
<p>Now you can run curl against that host <code>curl -HHost:example.com &quot;http://192.168.1.138:30536/&quot;</code> (for me it's port 30536, will be a different one for you) and you will get an answer from the registry. Works the same with https using the other port.</p>
<p>Note that I installed everything in the same namespace. In reality you should have a dedicated ingress namespace.</p>
<p>I would also highly recommand to learn the basics of kubernetes, e.g. by a Udemy Course or a youtube tutorail series. If you want to know more about ingress-controller in an on-premise setup, check out my other <a href="https://stackoverflow.com/questions/71747959/what-is-a-kubernetes-loadbalancer-on-prem/71753345#71753345">answer on that topic</a>.</p>
