From: Jay Pfaffman Date: Wed, 20 Apr 2016 15:48:39 +0000 (-0500) Subject: Add memconfig to launcher: Configure defaults based on available RAM X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=f8c887b627e77475d9a04dc41edbce60c7a30738;p=discourse_docker.git Add memconfig to launcher: Configure defaults based on available RAM Creates or modifies config of db_shared_buffers, db_work_mem, and UNICORN_WORKERS based on available RAM. Parameters not set in config file (i.e., commented out), are left unchanged and a warning is printed. Uses samples/standalone_template.yml as basis, but if accepted, I recommend uncommenting these defaults in standalone.yml and using it instead. --- diff --git a/README.md b/README.md index 903b8c5..8eab1bd 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ Commands: destroy: Stop and remove a container enter: Use docker exec to enter a container logs: Docker logs for container + memconfig: Configure sane defaults for available RAM bootstrap: Bootstrap a container for the config based on a template rebuild: Rebuild a container (destroy old, bootstrap, start new) ``` diff --git a/launcher b/launcher index ed91e79..08d1be3 100755 --- a/launcher +++ b/launcher @@ -24,7 +24,8 @@ cidbootstrap=cids/"$config"_bootstrap.cid local_discourse=local_discourse image=discourse/discourse:1.0.17 docker_path=`which docker.io || which docker` - +template_path=samples/standalone_template.yml +changelog=/tmp/changelog # used to test whether sed did anything if [ "${SUPERVISED}" = "true" ]; then restart_policy="--restart=no" @@ -61,6 +62,7 @@ usage () { echo " logs: Docker logs for container" echo " bootstrap: Bootstrap a container for the config based on a template" echo " rebuild: Rebuild a container (destroy old, bootstrap, start new)" + echo " memconfig: Configure defaults based on available RAM" echo " cleanup: Remove all containers that have stopped for > 24 hours" echo echo "Options:" @@ -395,7 +397,7 @@ RUBY usage } -if [ ! -e $config_file ] +if [[ ! -e $config_file && $command -ne "memconfig" ]] then echo "Config file was not found, ensure $config_file exists" echo "" @@ -458,6 +460,78 @@ set_boot_command() { fi } +run_memconfig(){ + if [ "$opt" != "--skip-prereqs" ] ; then + check_resources + fi + if [ -f $config_file ] + then + cp $config_file $config_file.bak + echo "Saving $config_file as $config_file.bak" + else + echo "Creating $config_file from $template_path" + if [ ! -f $template_path ] + then + echo "$template_path is missing. Exiting." + exit 1 + fi + cp $template_path $config_file + fi + + # get free mem + avail_mem="$(LANG=C free -m | grep '^Mem:' | awk '{print $2}')" + avail_gb=`expr $(($avail_mem / 950))` + avail_cores=`grep -c processor /proc/cpuinfo` + echo "Found $avail_mem (${avail_gb}GB), of memory and $avail_cores cores." + + # set db_shared_buffers: "128MB" (1GB) or 256MB * GB + if [ "$avail_gb" -eq "1" ] + then + db_shared_buffers="128" + else + db_shared_buffers=`expr $avail_gb \* 256` + fi + echo -e "Setting db_shared_buffers to ${db_shared_buffers}GB\c" + sed -i -e "s/^ db_shared_buffers:.*/ db_shared_buffers: \"${db_shared_buffers}GB\"/w $changelog" $config_file + if [ -s $changelog ] + then + echo " successfully." + rm $changelog + else + echo -e ". . . oops!\n---> db_shared_buffers not found in $config_file. Retaining defaults." + fi + + # set db_work_mem: "10MB" * GB? + db_work_mem=`expr $avail_gb \* 10` + echo -e "Setting db_work_mem to $db_work_mem MB\c" + sudo sed -i -e "s/^ db_work_mem:.*/ db_work_mem: \"${db_work_mem}MB\"/w $changelog" $config_file + if [ -s $changelog ] + then + echo " successfully." + rm $changelog + else + echo -e ". . . oops!\n---> db_work_mem not found in $config_file. Retaining defaults." + fi + + # set UNICORN_WORKERS: 2*GB or 2*cores (the same on DO) + if [ "$avail_gb" -le "2" ] + then + unicorn_workers=`expr $avail_gb \* 2` + else + unicorn_workers=`expr $avail_cores \* 2` + fi + + echo -e "Setting UNICORN_WORKERS to $unicorn_workers\c" + sed -i -e "s/^ UNICORN_WORKERS:.*/ UNICORN_WORKERS: ${unicorn_workers}/w $changelog" $config_file + if [ -s $changelog ] + then + echo " successfully." + rm $changelog + else + echo -e ". . . oops!\n---> UNICORN_WORKERS not found in $config_file. Retaining defaults.\n" + fi +} + run_start(){ existing=`$docker_path ps | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'` @@ -638,6 +712,11 @@ case "$command" in exit 0 ;; + memconfig) + run_memconfig + exit 0 + ;; + rebuild) if [ "$(git symbolic-ref --short HEAD)" == "master" ]; then echo "Ensuring discourse docker is up to date" diff --git a/samples/standalone_template.yml b/samples/standalone_template.yml new file mode 100644 index 0000000..255076b --- /dev/null +++ b/samples/standalone_template.yml @@ -0,0 +1,117 @@ +## +## After making changes to this file, you MUST rebuild for any changes +## to take effect in your live Discourse instance: +## +## /var/discourse/launcher rebuild app +## +## Make sure to obey YAML syntax! You can use this site to help check: +## http://www.yamllint.com/ + +## this is the all-in-one, standalone Discourse Docker container template + +# You may add rate limiting by uncommenting the web.ratelimited template. +# Out of the box it allows 12 reqs a second per ip, and 100 per minute per ip +# This is configurable by amending the params in this file + +templates: + - "templates/postgres.template.yml" + - "templates/redis.template.yml" + - "templates/web.template.yml" + - "templates/web.ratelimited.template.yml" + + ## Comment out the following lines if you wish to add Lets Encrypt for your Discourse install + # - "templates/web.ssl.template.yml" + # - "templates/web.letsencrypt.ssl.template.yml" + +## which TCP/IP ports should this container expose? +expose: + - "80:80" # fwd host port 80 to container port 80 (http) + - "443:443" # fwd host port 443 to container port 443 (https) (ssl ready) +# If you want Discourse to share a port with another webserver like Apache or nginx, +# see https://meta.discourse.org/t/17247 for instructions. + +# any extra arguments for Docker? +# docker_args: + +params: + db_default_text_search_config: "pg_catalog.english" + + ## Set db_shared_buffers to a max of 25% of the total memory. + ## + ## On 1GB installs set to 128MB (to leave room for other processes) + ## on a 4GB instance you may raise to 1GB + db_shared_buffers: "128MB" + # + + ## Set higher on large instances it defaults to 10MB, for a 3GB install 40MB is a good default + ## this improves sorting performance, but adds memory usage per-connection + db_work_mem: "10MB" + # + ## Which Git revision should this container use? (default: tests-passed) + #version: tests-passed + +env: + LANG: en_US.UTF-8 + # DISCOURSE_DEFAULT_LOCALE: en + + ## TODO: How many concurrent web requests are supported? + ## With 2GB we recommend 3-4 workers, with 1GB only 2 + ## If you have lots of memory, use one or two workers per logical CPU core + UNICORN_WORKERS: 3 + + ## TODO: List of comma delimited emails that will be made admin and developer + ## on initial signup example 'user1@example.com,user2@example.com' + DISCOURSE_DEVELOPER_EMAILS: 'me@example.com' + + ## TODO: The domain name this Discourse instance will respond to + DISCOURSE_HOSTNAME: 'discourse.example.com' + ## TODO: Uncomment if you want the container to be started with the same + ## hostname (-h option) as specified above (default "$hostname-$config") + ## NOTE: 'true' is the only valid value here, any other will be ignored + #DOCKER_USE_HOSTNAME: true + + ## TODO: The mailserver this Discourse instance will use + DISCOURSE_SMTP_ADDRESS: smtp.example.com # (mandatory) + #DISCOURSE_SMTP_PORT: 587 # (optional) + #DISCOURSE_SMTP_USER_NAME: user@example.com # (optional) + #DISCOURSE_SMTP_PASSWORD: pa$$word # (optional, WARNING the char '#' in pw can cause problems!) + #DISCOURSE_SMTP_ENABLE_START_TLS: true # (optional, default true) + + ## The Lets Encrypt email will allow you to register a FREE SSL certificate if you added the Lets Encrypt template, comment it out if you have set this up + # LETSENCRYPT_ACCOUNT_EMAIL: email@awesomedomain.com + + ## The CDN address for this Discourse instance (configured to pull) + #DISCOURSE_CDN_URL: //discourse-cdn.example.com + +## These containers are stateless, all data is stored in /shared +volumes: + - volume: + host: /var/discourse/shared/standalone + guest: /shared + - volume: + host: /var/discourse/shared/standalone/log/var-log + guest: /var/log + +## The docker manager plugin allows you to one-click upgrade Discourse +## http://discourse.example.com/admin/docker +hooks: + after_code: + - exec: + cd: $home/plugins + cmd: + - git clone https://github.com/discourse/docker_manager.git + +## Remember, this is YAML syntax - you can only have one block with a name +run: + - exec: echo "Beginning of custom commands" + + ## If you want to set the 'From' email address for your first registration, uncomment and change: + #- exec: rails r "SiteSetting.notification_email='info@unconfigured.discourse.org'" + ## After getting the first signup email, re-comment the line. It only needs to run once. + + ## If you want to configure password login for root, uncomment and change: + ## Use only one of the following lines: + #- exec: /usr/sbin/usermod -p 'PASSWORD_HASH' root + #- exec: /usr/sbin/usermod -p "$(mkpasswd -m sha-256 'RAW_PASSWORD')" root + + - exec: echo "End of custom commands"