<p>I am confused when it comes to deploying PostgreSQL database of my Django application with Kubernetes. Here is how I have constructed my deployment-definition.yml file:</p>

<pre><code>apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: postgres
spec:
  replicas: 1
  selector:
    matchLabels:
      app: postgres-container
  template:
    metadata:
      labels:
        app: postgres-container
        tier: backend
    spec:
      containers:
        - name: postgres-container
          image: postgres:9.6.6
          env:
            - name: POSTGRES_USER
              valueFrom:
                secretKeyRef:
                  name: postgres-credentials
                  key: user

            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: postgres-credentials
                  key: password

            - name: POSTGRES_DB
              value: agent_technologies_db
          ports:
            - containerPort: 5432
          volumeMounts:
            - name: postgres-volume-mount
              mountPath: /var/lib/postgresql/data

      volumes:
        - name: postgres-volume-mount
          persistentVolumeClaim:
            claimName: postgres-pvc
        - name: postgres-credentials
          secret:
            secretName: postgres-credentials
</code></pre>

<p>What I dont understand is this. If I specify (like i did) an existing image of PostgreSQL inside spec of Kubernetes Deployment object, how do I actually run my application? What do I need to specify as HOST inside my settings.py file?</p>

<p>Here is what my settings.py file looks like for now:</p>

<pre><code>DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'agent_technologies_db',
        'USER': 'stefan_radonjic',
        'PASSWORD': 'cepajecar995',
        'HOST': 'localhost', 
        'PORT': '',
        }
}
</code></pre>

<p>It is constructed this way because I am still designing the application and I do not wanna deploy it to Kubernetes cluster just yet. But when I do, what am I suppose to specify for : <code>HOST</code> and <code>PORT</code> ? And also, is this the right way to deploy PostgreSQL to Kubernetes Cluster.</p>

<p>Thank you in advance! </p>

<p>*** QUESTION UPDATE ****</p>

<p>As suggested, I have created service.yml:</p>

<pre><code>apiVersion: v1
kind: Service
metadata:
  name: postgres-service
spec:
  selector:
    app: postgres-container
    tier: backend
  ports:
    - protocol: TCP
      port: 5432
      targetPort: 5432
  type: ClusterIP
</code></pre>

<p>And I have updated my settings.py file:</p>

<pre><code>DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'agent_technologies_db',
        'USER': 'stefan_radonjic',
        'PASSWORD': 'cepajecar995',
        'HOST': 'postgres-service', 
        'PORT': 5432,
        }
}
</code></pre>

<p>But I am getting the following error: </p>

<p><a href="https://i.stack.imgur.com/tiSVX.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/tiSVX.png" alt="enter image description here"></a></p>

Stefan Radonjic
<p>In order to allow communication to your PostreSQL deployment in Kubernetes, you need to set up a <code>Service</code> object. If your Django app will live in the same cluster as your PostgreSQL deployment, then you will want a <code>ClusterIP</code> type service; otherwise, if your Django app lives outside of your cluster, you will want a <code>LoadBalancer</code> or <code>NodePort</code> type service.</p>

<p>There are two ways to create a service:</p>

<p><strong>YAML</strong></p>

<p>The first is through a yaml file, which in your case would look like this:</p>

<pre><code>kind: Service
apiVersion: v1
metadata:
  name: postgres
spec:
  selector:
    app: postgres-container
    tier: backend
  ports:
  - name: postgres
    protocol: TCP
    port: 5432
    targetPort: 5432
</code></pre>

<p>The <code>.spec.selector</code> field defines the target of the <code>Service</code>. This service will target pods with labels <code>app=postgres-container</code> and <code>tier=backend</code>. It exposes port 5432 of the container. In your Django configuration, you would put the name of the service as the <code>HOST</code>: in this case, the name is simply <code>postgres</code>. Kubernetes will resolve the service name to the matching pod IP and route traffic to the pod. The port will be the port of the service: 5432.</p>

<p><strong>kubectl expose</strong></p>

<p>The other way of creating a service is through the <code>kubectl expose</code> command:</p>

<pre><code>kubectl expose deployment/postgres
</code></pre>

<p>This command will default to a <code>ClusterIP</code> type service and expose the ports defined in the <code>.spec.containers.ports</code> fields in the Deployment yaml.</p>

<p>More info:</p>

<p><a href="https://kubernetes.io/docs/concepts/services-networking/service/" rel="noreferrer">https://kubernetes.io/docs/concepts/services-networking/service/</a></p>

<blockquote>
  <p>And also, is this the right way to deploy PostgreSQL to Kubernetes Cluster.</p>
</blockquote>

<p>This depends on a few variables. Do you plan on deploying a Postgres cluster? If so, you may want to look into using a <code>StatefulSet</code>: </p>

<blockquote>
  <p>StatefulSets are valuable for applications that require one or more of
  the following.</p>
  
  <ul>
  <li>Stable, unique network identifiers. </li>
  <li>Stable, persistent storage.</li>
  <li>Ordered, graceful deployment and scaling. </li>
  <li>Ordered, graceful deletion and termination. </li>
  <li>Ordered, automated rolling updates.</li>
  </ul>
</blockquote>

<p><a href="https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#using-statefulsets" rel="noreferrer">https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#using-statefulsets</a></p>

<p>Do you have someone knowledgable of Postgres that's going to configure and maintain it? If not, I would also recommend that you look into deploying a managed Postgres server outside of a cluster (e.g. RDS). You can still deploy your Django app within the cluster and connect to your DB via an <code>ExternalName</code> service. </p>

<p>The reason I recommend this is that managing stateful applications in a Kubernetes cluster can be challenging. I'm not familiar with Postgres, but here's a cautionary tale of running Postgres on Kubernetes: <a href="https://gravitational.com/blog/running-postgresql-on-kubernetes/" rel="noreferrer">https://gravitational.com/blog/running-postgresql-on-kubernetes/</a></p>

<p>In addition to that, here are a few experiences I've run into that has influenced my decision to remove stateful workloads from my cluster:</p>

<h2>Stuck volumes</h2>

<p>If you're using AWS EBS volumes, volumes can get "stuck" on a node and fail to detach and reattach to a new node if your DB pod gets rescheduled to a new node. </p>

<h2>Migrating to a new cluster</h2>

<p>If you ever need to move your workloads to a new cluster, you will have to deal with the added challenge of moving your state to the new cluster as well without suffering any data loss. If you move your stateful apps outside of the cluster then you can treat the whole cluster as cattle, and then tearing it down and migrating to a new cluster becomes a whole lot easier. </p>

<p>More info:</p>

<p>K8s blog post on deploying Postgres with StatefulSets: <a href="https://kubernetes.io/blog/2017/02/postgresql-clusters-kubernetes-statefulsets/" rel="noreferrer">https://kubernetes.io/blog/2017/02/postgresql-clusters-kubernetes-statefulsets/</a></p>
