<p>I read the following <a href="https://kubernetes.io/docs/tutorials/kubernetes-basics/expose/expose-intro/" rel="nofollow noreferrer">kubernetes docs</a> which resulted in the following yaml's to run postgresql &amp; pgadmin in a cluster:</p>
<pre><code>--- pgadmin-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pgadmin-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: pgadmin-pod
  template:
    metadata:
      labels:
        app: pgadmin-pod
    spec:
      containers:
        - name: pgadmin-container
          image: dpage/pgadmin4
          imagePullPolicy: &quot;IfNotPresent&quot;
          ports:
            - containerPort: 80
          env:
            - name: PGADMIN_DEFAULT_EMAIL
              value: email@example.com
            - name: PGADMIN_DEFAULT_PASSWORD
              value: password

--- pgadmin-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: pgadmin-service
spec:
  type: NodePort
  ports:
    - port: 30000
      targetPort: 80
  selector:
    app: pgadmin-pod

--- postgres-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgres-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: postgres-pod
  template:
    metadata:
      labels:
        app: postgres-pod
    spec:
      containers:
        - name: postgres-container
          image: postgres:9.6-alpine
          imagePullPolicy: &quot;IfNotPresent&quot;
          ports:
            - containerPort: 5432
          env:
            - name: POSTGRES_DB
              value: database
            - name: POSTGRES_PASSWORD
              value: password
            - name: POSTGRES_USER
              value: username
          volumeMounts:
            - mountPath: /var/lib/postgresql/data
              name: postgrepvc
      volumes:
        - name: postgrepvc
          persistentVolumeClaim:
            claimName: postgres-pv-claim

--- postgres-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: postgres-service
spec:
  type: NodePort
  ports:
    - port: 30001
      targetPort: 5432
  selector:
    app: postgres-pod

--- postgres-storage.yaml
postgres-storage.yaml
kind: PersistentVolume
apiVersion: v1
metadata:
  name: postgres-pv-volume
  labels:
    type: local
    app: postgres
spec:
  storageClassName: manual
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteMany
  hostPath:
    path: &quot;/mnt/data&quot;
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: postgres-pv-claim
  labels:
    app: postgres
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 5Gi
</code></pre>
<p>I then run the following command <code>kubectl create -f ./</code> which results in the following:
<a href="https://i.stack.imgur.com/13zeL.png" rel="nofollow noreferrer">kubernetes pods / svc's</a></p>
<p>Then I try to access pgAdmin on 10.43.225.170:30000 from outside of the cluster, but I get &quot;10.43.225.170 took too long to respond.&quot; no matter what I try.</p>
<p>So how do I expose pgAdmin &amp; postgress to the outside world, and is there a way to give them static ip's so I don't have to update ip's in connection strings each time I re-deploy on kubernetes, or do I have to use statefulset for this?</p>

Alexander Bruun
<hr />
<p>Problems here</p>
<ol>
<li>you are trying to reach <strong>node internal ip</strong>  <code>10.43.225.170</code> instead of <strong>external</strong> one.</li>
<li>nodePort service configured incorrectly. In addition you are trying to call incorrect port</li>
</ol>
<hr />
<p>You haven't specified what platform you use. I'm using GKE, so in my case its easier because I have external IP's automatically assigned during cluster node creation. But I had to manually create ingress firewall rule to allow access from outside to nodes and required ports (30000,30001)</p>
<p>In any case, to be able to use <code>nodePort</code> - you should have <strong>external IP address assigned to one of the nodes in cluster and a Firewall rule that allows ingress traffic to that port</strong></p>
<hr />
<p>Going next. You are trying to call <code>&lt;NodeIP&gt;:spec.ports[*].port</code>.</p>
<p>As per <a href="https://kubernetes.io/docs/concepts/services-networking/service/#nodeport" rel="nofollow noreferrer">Type NodePort documentation</a>:</p>
<blockquote>
<p>Service is visible as <code>&lt;NodeIP&gt;:spec.ports[*].nodePort</code></p>
</blockquote>
<p>You need explicitly specify nodePort</p>
<hr />
<p>I have changed a bit your deployment, can access pgAdmin after deploying it and opening corresponding  ports in firewall.</p>
<pre><code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: pgadmin-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: pgadmin-pod
  template:
    metadata:
      labels:
        app: pgadmin-pod
    spec:
      containers:
        - name: pgadmin-container
          image: dpage/pgadmin4
          imagePullPolicy: &quot;IfNotPresent&quot;
          ports:
            - containerPort: 80
          env:
            - name: PGADMIN_DEFAULT_EMAIL
              value: email@example.com
            - name: PGADMIN_DEFAULT_PASSWORD
              value: password

---
apiVersion: v1
kind: Service
metadata:
  name: pgadmin-service
spec:
  type: NodePort
  ports:
    - nodePort: 30000
      targetPort: 80
      port: 80
  selector:
    app: pgadmin-pod

--- postgres-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgres-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: postgres-pod
  template:
    metadata:
      labels:
        app: postgres-pod
    spec:
      containers:
        - name: postgres-container
          image: postgres:9.6-alpine
          imagePullPolicy: &quot;IfNotPresent&quot;
          ports:
            - containerPort: 5432
          env:
            - name: POSTGRES_DB
              value: database
            - name: POSTGRES_PASSWORD
              value: password
            - name: POSTGRES_USER
              value: username
          volumeMounts:
            - mountPath: /var/lib/postgresql/data
              name: postgrepvc
      volumes:
        - name: postgrepvc
          persistentVolumeClaim:
            claimName: postgres-pv-claim

---
apiVersion: v1
kind: Service
metadata:
  name: postgres-service
spec:
  type: NodePort
  ports:
    - nodePort: 30001
      targetPort: 5432
      port: 5432
  selector:
    app: postgres-pod

---
kind: PersistentVolume
apiVersion: v1
metadata:
  name: postgres-pv-volume
  labels:
    type: local
    app: postgres
spec:
  storageClassName: manual
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteMany
  hostPath:
    path: &quot;/mnt/data&quot;
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: postgres-pv-claim
  labels:
    app: postgres
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 5Gi
</code></pre>
<p>Check:</p>
<pre><code>kubectl apply -f pg_my.yaml
deployment.apps/pgadmin-deployment created
service/pgadmin-service created
service/postgres-service created
persistentvolume/postgres-pv-volume created
persistentvolumeclaim/postgres-pv-claim created


#In my case I take node external ip from any node from `kubectl get nodes -o wide` output:
NAME                                       STATUS   ROLES    AGE   VERSION            INTERNAL-IP   EXTERNAL-IP
gke-cluster-1-default-pool-*******-*****   Ready    &lt;none&gt;   20d   v1.18.16-gke.502   10.186.0.7    *.*.*.*

curl *.*.*.*:30000
&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 3.2 Final//EN&quot;&gt;
&lt;title&gt;Redirecting...&lt;/title&gt;
&lt;h1&gt;Redirecting...&lt;/h1&gt;
&lt;p&gt;You should be redirected automatically to target URL: &lt;a href=&quot;/login?next=%2F&quot;&gt;/login?next=%2F&lt;/a&gt;.
</code></pre>
<p><a href="https://i.stack.imgur.com/tY8WR.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/tY8WR.png" alt="enter image description here" /></a>
<a href="https://i.stack.imgur.com/pLsUJ.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/pLsUJ.png" alt="enter image description here" /></a></p>
