Skip to content

Pass important postgres settings to docker-entrypoint.sh via ENV vars #54

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from

Conversation

lukasmartinelli
Copy link

Thanks for your work so far guys!

The postgres defaults are quite modest (especially memory). Most settings can nowaydays be set via the ALTER SYSTEM query and a reload but some settings require a restart and therefore should be set before postgres starts.

This is just a proposal how it could be done. I would be happy to see what you think about it and which settings to include and whether it is even in the scope of this Docker image.

I think it would make quick configuration of postgres containers much easier because you don't have to create your own Docker image just for tweaking some very basic settings like shared_buffers.
It also allows schedulers for example to set the shared_buffers options based on metadata.

I simply modified the docker-entrypoint.sh of the latest Docker image for now, if you think it is a good idea in general I will modify the others as well.

@md5
Copy link
Contributor

md5 commented Mar 31, 2015

If something like this is going to happen, I'd prefer to see it happen in a generic way based on prefix or something, rather than supporting specific settings. I could see having all POSTGRES_CONF_* variables converted to their downcased versions. With that, you could set POSTGRES_CONF_SHARED_BUFFERS or whatever.

@lukasmartinelli
Copy link
Author

If something like this is going to happen, I'd prefer to see it happen in a generic way based on prefix or something, rather than supporting specific settings. I could see having all POSTGRES_CONF_* variables converted to their downcased versions. With that, you could set POSTGRES_CONF_SHARED_BUFFERS or whatever.

Yes that is preferable. I'll work on that.

@md5
Copy link
Contributor

md5 commented Mar 31, 2015

Should be pretty straightforward with ${!POSTGRES_CONF_*}. You may want to see what the maintainers think before putting a ton of effort into it though.

@lukasmartinelli
Copy link
Author

Should be pretty straightforward with ${!POSTGRES_CONF_*}. You may want to see what the maintainers think before putting a ton of effort into it though.

I didn't get it quite that elegant for now. But it works quite well.

docker run -e POSTGRES_PASSWORD=mysecretpassword \
-e POSTGRES_CONF_SHARED_BUFFERS=25GB \
-e POSTGRES_CONF_WAL_LEVEL=minimal \
-e POSTGRES_CONF_EFFECTIVE_CACHE_SIZE=75GB \
-e POSTGRES_CONF_MAX_CONNECTIONS=200 -d postgres

But let's see.

@md5
Copy link
Contributor

md5 commented Mar 31, 2015

I don't know man, that's the first I'd seen of the ${param,,} expansion. Nice work.


conf_prefix="POSTGRES_CONF_"
for env_name in $(env | cut -d= -f1 | grep "$conf_prefix.*"); do
value=$env_name
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this actually work? I'd think you would need to do eval value="\$${env_name}" or something.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind. Just saw the ${!value} below.

@lukasmartinelli
Copy link
Author

Thanks for the comments, I fixed the issues and it still works 😁

Expanding the vars with ${!POSTGRES_CONF_*} is a really cool trick I didn't know about.
Thats definitly useful for config scripts.

@tianon
Copy link
Member

tianon commented Apr 2, 2015

Isn't the generated postgresql.conf created from /usr/share/postgresql/9.4/postgresql.conf.sample?

@yosifkit
Copy link
Member

yosifkit commented Apr 2, 2015

@tianon, it is mostly the same, but I don't know where it gets most of the changes:

root@14814ca1bbe4:/var/lib/postgresql/data# diff postgresql.conf /usr/share/postgresql/9.4/postgresql.conf.sample
59c59
< listen_addresses = '*'        # what IP address(es) to listen on;
---
> #listen_addresses = 'localhost'       # what IP address(es) to listen on;
64c64
< max_connections = 100         # (change requires restart)
---
> #max_connections = 100            # (change requires restart)
68c68
< #unix_socket_directories = '/var/run/postgresql'  # comma-separated list of directories
---
> #unix_socket_directories = '/tmp' # comma-separated list of directories
115c115
< shared_buffers = 128MB            # min 128kB
---
> #shared_buffers = 32MB            # min 128kB
130c130
< dynamic_shared_memory_type = posix    # the default is the first option
---
> #dynamic_shared_memory_type = posix   # the default is the first option
438c438
< log_timezone = 'UTC'
---
> #log_timezone = 'GMT'
523c523
< datestyle = 'iso, mdy'
---
> #datestyle = 'iso, mdy'
525c525
< timezone = 'UTC'
---
> #timezone = 'GMT'
538c538
< lc_messages = 'en_US.utf8'            # locale for system error message
---
> #lc_messages = 'C'            # locale for system error message
540,542c540,542
< lc_monetary = 'en_US.utf8'            # locale for monetary formatting
< lc_numeric = 'en_US.utf8'         # locale for number formatting
< lc_time = 'en_US.utf8'                # locale for time formatting
---
> #lc_monetary = 'C'            # locale for monetary formatting
> #lc_numeric = 'C'         # locale for number formatting
> #lc_time = 'C'                # locale for time formatting
545c545
< default_text_search_config = 'pg_catalog.english'
---
> #default_text_search_config = 'pg_catalog.simple'

@lukasmartinelli
Copy link
Author

You think we should write the settings to /usr/share/postgresql/9.4/postgresql.conf.sample?

@lukasmartinelli
Copy link
Author

Should I continue to modify the Dockerfiles of all versions or should we just support it for the newest one?

@tianon
Copy link
Member

tianon commented Apr 21, 2015

What I meant was that if we can figure out which file these settings come from, we can recommend that users modify that file directly instead.

I ran a test appending some content to the end of postgresql.conf.sample before running the entrypoint, and it did show up in the final postgresql.conf, which means that the final files are generated directly from the .sample files in that directory.

What this means for my opinion on this PR is that I'd prefer that we instead document to users where postgresql.conf.sample can be found, and how to either edit or replace its contents appropriately for changes like this.

Something like FROM postgres:9.4 followed by RUN sed 's/.../.../' /usr/share/postgresql/*/postgresql.conf.sample or COPY some-file.conf.sample /usr/share/postgresql/9.4/postgresql.conf.sample should be sufficient for modifying the defaults for these settings. Combine that with automated builds (https://docs.docker.com/docker-hub/builds/) and repository links (https://docs.docker.com/docker-hub/builds/#repository-links) and it's reasonably easy to have an up-to-date image built FROM this one that comes with these settings pre-configured before postgres ever starts up.

@lukasmartinelli
Copy link
Author

Yes that's a good option. But I think it is significant more work to create an own Docker Image and configure an automated build with repository links than just setting an environment variable for a config value that is nearly always too conservative.

Settings like SHARED_BUFFERS depend on the machine and environment they run on and perhaps shouldn't be baked into an image.

@yoguivictor
Copy link

Really cool your patch, Lukas,

I hadn't seen before and copied this to my /docker-entrypoint-initdb.d/ :

#!/bin/bash
cat $PGDATA/postgresql.conf | grep '=' | sed 's/ =.*$//;s/^#//' | grep '^[a-z]' | sort | awk '{ print toupper ($0) }' | while read pgvar
do
    eval pgval=\$$pgvar
    if [ x"${pgval}" != "x" ]
    then
        lowcase=$( echo $pgvar | awk '{ print tolower ($0) }')
        echo "$lowcase = $pgval"
    fi
done > $PGDATA/postgresql.docker.conf
cat $PGDATA/postgresql.docker.conf >> $PGDATA/postgresql.conf

@lukasmartinelli
Copy link
Author

No thats correct and it is problematic - I mean we also cannot modify the postgres config once it has been mounted in $PGDATA.

But I think we need a solution that very essential things like the shared_buffers settings are not baked into an image. This is my take at it.

@yosifkit
Copy link
Member

yosifkit commented Mar 2, 2016

With the incoming #127 you can more easily pass parameters to postgres:

$ docker run -d postgres -c shared_buffers=256MB ...

Or override the default config file with your own, so that postgres will use it to generate the real one:

$ docker run -d -v /my/pg.conf:/usr/share/postgresql/postgresql.conf.sample postgres

@mlaitinen
Copy link

... -c shared_buffers=256MB? Did you mean -e, @yosifkit?

@yosifkit
Copy link
Member

yosifkit commented Mar 2, 2016

Nope, I mean passing args to the postgres daemon itself: -c NAME=VALUE set run-time parameter and not as environment variables that would require the entrypoint script to parse. Which is why they are at the end of the command so that they are arguments to the container and not arguments for docker run.

@yosifkit yosifkit closed this in #127 Mar 2, 2016
@ImreSamu ImreSamu mentioned this pull request Apr 28, 2016
@Ramblurr
Copy link

Reading through this closed ticket, I'm still not sure how to pass shared_buffers to my postgres image. What's the proper way to do this in 2017?

@tianon
Copy link
Member

tianon commented Oct 30, 2017

@Ramblurr as noted by @yosifkit in the previous comment:

passing args to the postgres daemon itself: -c NAME=VALUE set run-time parameter

For example

$ docker run -dit --name pg postgres -c shared_buffers=4096MB

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants