<p>Currently I'm trying to create a PostgreSQL Deployment for replication, using the <code>postgres:latest</code> image. </p>

<p>The config files are located by default within the data directory <code>/var/lib/postgresql/data</code>. For replication to work I need the data directory to be empty, but that means I have to keep the config files elsewhere. </p>

<p>Referring to the <a href="https://www.postgresql.org/docs/current/runtime-config-file-locations.html" rel="nofollow noreferrer">PostgreSQL Documentation</a>:</p>

<blockquote>
  <p>If you wish to keep the configuration files elsewhere than the data directory, the postgres -D command-line option or PGDATA environment variable must point to the directory containing the configuration files, and the data_directory parameter must be set in postgresql.conf (or on the command line) to show where the data directory is actually located. Notice that data_directory overrides -D and PGDATA for the location of the data directory, but not for the location of the configuration files.</p>
</blockquote>

<p>In a physical machine setup, we can manually move the files and set the location of data-directory in the <code>postgresql.conf</code> file. However in Kubernetes it is not so straight-forward.</p>

<p>I tried to use <code>volumeMount</code> with <code>subPath</code> to mount the config files in another location, then use <code>command</code> to change the new location of <code>postgresql.conf</code>. </p>

<p>Sample .yaml file:</p>

<pre><code>apiVersion: v1
kind: ConfigMap
metadata:
  name: pg-replica
  labels:
    app: postgres
    name: pg-replica
data:
  POSTGRES_DB: postgres
  POSTGRES_USER: postgres
  POSTGRES_PASSWORD: mypassword
  pg_hba.conf: |
    # Contents
  postgresql.conf: |
    data_directory = /var/lib/postgresql/data/data-directory
  recovery.conf: |
    # Contents
---
apiVersion: v1
kind: Service
metadata:
  name: pg-replica
  labels:
    app: postgres
    name: pg-replica
spec:
  type: NodePort
  ports:
  - nodePort: 31000
    port: 5432
  selector:
    app: postgres
    name: pg-replica
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pg-replica
spec:
  selector:
    matchLabels:
      app: postgres
      name: pg-replica
  replicas: 1
  template:
    metadata:
      labels:
        app: postgres
        name: pg-replica
    spec:
      containers:
        - name: pg-replica
          image: postgres:latest
          imagePullPolicy: "IfNotPresent"
          ports:
            - containerPort: 5432
          envFrom:
            - configMapRef:
                name: pg-replica
          volumeMounts:
            - name: pg-replica
              mountPath: /var/lib/postgresql/data
            - name: replica-config
              mountPath: /var/lib/postgresql/postgresql.conf
              subPath: postgresql.conf
            - name: replica-config
              mountPath: /var/lib/postgresql/pg_hba.conf
              subPath: pg_hba.conf
            - name: replica-config
              mountPath: /var/lib/postgresql/recovery.conf
              subPath: recovery.conf
          command:
            - "/bin/bash"
            - "postgres -c config_file=/var/lib/postgresql/postgresql.conf"
      volumes:
        - name: pg-replica
          persistentVolumeClaim:
            claimName: pv-replica-claim
        - name: replica-config
          configMap:
            name: pg-replica
</code></pre>

<p>The returned message was as following:</p>

<p><code>/bin/bash: postgres -c config_file=/var/lib/postgresql/postgresql.conf: No such file or directory</code></p>

<p>What is wrong with this configuration? And what steps am I missing to make it work?</p>

<p>Edit:
When using the <code>volumeMount</code> field, the directory is overwritten (all other files were removed) despite I specified the exact file to mount on with <code>subPath</code>. What could be the cause for this?</p>

<p>I realized there were a few mistakes here after posting this question...</p>

<ol>
<li><p>I used PostgreSQL 11 for replication prior so I assumed they worked the same way (which of course is wrong, there are some changes). The <code>recovery.conf</code> is omitted from PostgreSQL 12 and it gave this error message <code>FATAL: XX000: using recovery command file "recovery.conf" is not supported</code> when I had it. so I had to remove it from my ConfigMap.</p></li>
<li><p>I confused about Docker's <code>Entrypoint &amp; Command</code> to Kubernetes' <code>Command &amp; Args</code>. After being corrected by my senior that Kubernetes <code>Command</code> will override the Docker <code>Entrypoint</code>, I'm going to need and use only <code>Args</code> afterwards.</p></li>
</ol>

<p>The following are the changes I made to my ConfigMap and Deployment.</p>

<pre><code>apiVersion: v1
kind: ConfigMap
metadata:
  name: pg-replica
  labels:
    app: postgres
    name: pg-replica
data:
  POSTGRES_DB: postgres
  POSTGRES_USER: postgres
  POSTGRES_PASSWORD: mypassword
  pg_hba.conf: |
    # Contents
  postgresql.conf: |
    data_directory = '/var/lib/postgresql/data'
    # the contents from recovery.conf are intergrated into postgresql.conf
    primary_conninfo = # host address and authentication credentials
    promote_trigger_file = # trigger file path
  extra.sh: |
    #!/bin/sh
    postgres -D /var/lib/postgresql
---
apiVersion: v1
kind: Service
metadata:
  name: pg-replica
  labels:
    app: postgres
    name: pg-replica
spec:
  type: NodePort
  ports:
  - nodePort: 31000
    port: 5432
  selector:
    app: postgres
    name: pg-replica
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pg-replica
spec:
  selector:
    matchLabels:
      app: postgres
      name: pg-replica
  replicas: 1
  template:
    metadata:
      labels:
        app: postgres
        name: pg-replica
    spec:
      containers:
        - name: pg-replica
          image: postgres:latest
          imagePullPolicy: "IfNotPresent"
          ports:
            - containerPort: 5432
          envFrom:
            - configMapRef:
                name: pg-replica
          volumeMounts:
            - name: pg-replica
              mountPath: /var/lib/postgresql/data
            - name: replica-config
              mountPath: /var/lib/postgresql/postgresql.conf
              subPath: postgresql.conf
            - name: replica-config
              mountPath: /var/lib/postgresql/pg_hba.conf
              subPath: pg_hba.conf
            - name: replica-config
              mountPath: /docker-entrypoint-initdb.d/extra.sh
              subPath: extra.sh
          args:
            - "-c"
            - "config_file=/var/lib/postgresql/postgresql.conf"
            - "-c"
            - "hba_file=/var/lib/postgresql/pg_hba.conf"
      volumes:
        - name: pg-replica
          persistentVolumeClaim:
            claimName: pv-replica-claim
        - name: replica-config
          configMap:
            name: pg-replica
</code></pre>

<p>The arguments in <code>Args</code> will set the location of the <code>.conf</code> files to where I specified.</p>

<p>For further steps in Replication:</p>

<ol>
<li><p>After the pod is up, I manually ran the pod's shell with <code>kubectl exec</code>.</p></li>
<li><p>I removed all the files from the <code>data-directory</code> for step 3 (to copy files from master pod).</p></li>
</ol>

<pre><code>rm -rf /var/lib/postgresql/data/*
</code></pre>

<ol start="3">
<li>Use <code>pg_basebackup</code> to backup data from master node.</li>
</ol>

<pre><code>pg_basebackup -h &lt;host IP&gt; --port=&lt;port number used&gt; -D  /var/lib/postgresql/data -P -U replica -R -X stream
</code></pre>

<p>And that's it. Now I managed to have my <code>pg-replica</code> pod replicating my master pod.</p>
