title: postgres in Docker with data directory on named or bind volume works on Windows Server 2019 but not Windows Server 2016
body: <p>I'm currently trying to run <code>PostgreSQL 10.6.1</code> in a docker container (Base-Image is <code>mcr.microsoft.com/windows/servercore:ltsc2016</code>) that should be run on Windows Server 2016 Datacenter (Version 1607, Build 14393.2759).</p>
  
  <p>Everything runs fine, including PostgreSQL's <code>initdb</code> and running PostgreSQL afterwards - as long as PostgreSQL's data directory is not a volume on the docker host.</p>
  
  <p>If I try to run it having the PostgreSQL's data directory placed on either a <a href="https://docs.docker.com/storage/volumes/" rel="noreferrer">named or bind volume</a>, PostgreSQL is able to do its <code>initdb</code> but fails to start afterwards.</p>
  
  <p>I suspect that the error is due to the fact that mounted volumes are visible as <code>symlink</code> within containers depending on <code>mcr.microsoft.com/windows/servercore:ltsc2016</code>, causing PostgreSQL to fail. On <code>mcr.microsoft.com/windows/servercore:1809</code>, this behaviour changed - mounted volumes look like 'normal' directories and PostgreSQL is able to start.</p>
  
  <p>As there is no useful error message at all and running a database having no persistent storage outside of a container sounds like a really useless thing, any help is appreciated.</p>
  
  <p>The Dockerfile I'm using looks like this:</p>
  
  <pre><code>FROM mcr.microsoft.com/windows/servercore:ltsc2016
  SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
  ARG version=10.6-1
  
  RUN [Net.ServicePointManager]::SecurityProtocol = 'Tls12, Tls11, Tls' ; \
      Invoke-WebRequest $('https://get.enterprisedb.com/postgresql/postgresql-{0}-windows-x64-binaries.zip' -f $env:version) -OutFile 'postgres.zip' -UseBasicParsing ; \
      Expand-Archive postgres.zip -DestinationPath C:\ ; \
      Remove-Item postgres.zip ; \
      Remove-Item 'C:\pgsql\pgAdmin 4' -Recurse ; \
      Remove-Item 'C:\pgsql\StackBuilder' -Recurse ; \
      Remove-Item 'C:\pgsql\doc' -Recurse
  RUN [Net.ServicePointManager]::SecurityProtocol = 'Tls12, Tls11, Tls' ; \
      Invoke-WebRequest 'http://download.microsoft.com/download/0/5/6/056DCDA9-D667-4E27-8001-8A0C6971D6B1/vcredist_x64.exe' -OutFile vcredist_x64.exe ; \
      Start-Process vcredist_x64.exe -ArgumentList '/install', '/passive', '/norestart' -NoNewWindow -Wait ; \
      Remove-Item vcredist_x64.exe
  
  SHELL ["cmd", "/S", "/C"]
  RUN setx /M PATH "C:\pgsql\bin;%PATH%"
  RUN MD data
  RUN setx /M PGDATA "C:\data"
  
  ENV PGUSER postgres
  ENV PGPASSWORD postgres
  
  COPY docker-entrypoint.cmd /
  COPY start.cmd /
  
  EXPOSE 5432
  
  ENTRYPOINT ["docker-entrypoint.cmd"]
  CMD [ "start.cmd"]
  </code></pre>
  
  <p>The referenced <code>docker-entrypoint.cmd</code> looks like this:</p>
  
  <pre><code>@ECHO %PGPASSWORD% &gt; pw.txt
  
  @ECHO OFF
  IF NOT EXIST %PGDATA%/PG_VERSION (
      initdb.exe --encoding=UTF8 --username=%PGUSER% --pwfile=pw.txt
      @echo host all all 0.0.0.0/0 trust &gt; %PGDATA%/pg_hba.conf
      @echo host all all ::0/0 trust &gt;&gt; %PGDATA%/pg_hba.conf
  )
  
  %*
  </code></pre>
  
  <p>The referenced <code>start.cmd</code> looks like this:</p>
  
  <pre><code>@echo off
  
  pg_ctl start -o "-h * -c max_prepared_transactions=100 -c max_connections=1000"
  
  REM logic to keep container alive
  :ENDLESS
  CALL :sleep 100000
  goto ENDLESS
  exit
  
  REM https://superuser.com/questions/48231/how-do-i-make-a-batch-file-wait-sleep-for-some-seconds
  :sleep
  ping 127.0.0.1 -n %1 -w 1000 &gt; NUL
  </code></pre>