diff --git a/docker-compose.build.yml b/docker-compose.build.yml index 6195d23..4091be6 100644 --- a/docker-compose.build.yml +++ b/docker-compose.build.yml @@ -3,6 +3,9 @@ services: latest: build: ./python3.7 image: tiangolo/meinheld-gunicorn:latest + python2.7: + build: ./python2.7 + image: tiangolo/meinheld-gunicorn:python2.7 python3.6: build: ./python3.6 image: tiangolo/meinheld-gunicorn:python3.6 diff --git a/python2.7/Dockerfile b/python2.7/Dockerfile new file mode 100644 index 0000000..ef266d2 --- /dev/null +++ b/python2.7/Dockerfile @@ -0,0 +1,26 @@ +FROM python:2.7 + +LABEL maintainer="Sebastian Ramirez " + +RUN pip install meinheld gunicorn + +COPY ./entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +COPY ./start.sh /start.sh +RUN chmod +x /start.sh + +COPY ./gunicorn_conf.py /gunicorn_conf.py + +COPY ./app /app +WORKDIR /app/ + +ENV PYTHONPATH=/app + +EXPOSE 80 + +ENTRYPOINT ["/entrypoint.sh"] + +# Run the start script, it will check for an /app/prestart.sh script (e.g. for migrations) +# And then will start Gunicorn with Meinheld +CMD ["/start.sh"] diff --git a/python2.7/app/main.py b/python2.7/app/main.py new file mode 100755 index 0000000..6acdc98 --- /dev/null +++ b/python2.7/app/main.py @@ -0,0 +1,10 @@ +import sys + + +def app(env, start_response): + version = "{}.{}".format(sys.version_info.major, sys.version_info.minor) + start_response("200 OK", [("Content-Type", "text/plain")]) + message = "Hello World from a default Python {} app in a Docker container, with Meinheld and Gunicorn (default)".format( + version + ) + return [message.encode("utf-8")] diff --git a/python2.7/app/prestart.sh b/python2.7/app/prestart.sh new file mode 100644 index 0000000..9ccb1da --- /dev/null +++ b/python2.7/app/prestart.sh @@ -0,0 +1,12 @@ +#! /usr/bin/env sh + +echo "Running inside /app/prestart.sh, you could add migrations to this file, e.g.:" + +echo " +#! /usr/bin/env bash + +# Let the DB start +sleep 10; +# Run migrations +alembic upgrade head +" diff --git a/python2.7/entrypoint.sh b/python2.7/entrypoint.sh new file mode 100644 index 0000000..bcf66db --- /dev/null +++ b/python2.7/entrypoint.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env sh +set -e + +if [ -f /app/app/main.py ]; then + DEFAULT_MODULE_NAME=app.main +elif [ -f /app/main.py ]; then + DEFAULT_MODULE_NAME=main +fi +MODULE_NAME=${MODULE_NAME:-$DEFAULT_MODULE_NAME} +VARIABLE_NAME=${VARIABLE_NAME:-app} +export APP_MODULE=${APP_MODULE:-"$MODULE_NAME:$VARIABLE_NAME"} + +if [ -f /app/gunicorn_conf.py ]; then + DEFAULT_GUNICORN_CONF=/app/gunicorn_conf.py +elif [ -f /app/app/gunicorn_conf.py ]; then + DEFAULT_GUNICORN_CONF=/app/app/gunicorn_conf.py +else + DEFAULT_GUNICORN_CONF=/gunicorn_conf.py +fi +export GUNICORN_CONF=${GUNICORN_CONF:-$DEFAULT_GUNICORN_CONF} + +exec "$@" diff --git a/python2.7/gunicorn_conf.py b/python2.7/gunicorn_conf.py new file mode 100644 index 0000000..48bdee8 --- /dev/null +++ b/python2.7/gunicorn_conf.py @@ -0,0 +1,43 @@ +from __future__ import print_function +import json +import multiprocessing +import os + +workers_per_core_str = os.getenv("WORKERS_PER_CORE", "2") +web_concurrency_str = os.getenv("WEB_CONCURRENCY", None) +host = os.getenv("HOST", "0.0.0.0") +port = os.getenv("PORT", "80") +bind_env = os.getenv("BIND", None) +use_loglevel = os.getenv("LOG_LEVEL", "info") +if bind_env: + use_bind = bind_env +else: + use_bind = "{host}:{port}".format(host=host, port=port) + +cores = multiprocessing.cpu_count() +workers_per_core = float(workers_per_core_str) +default_web_concurrency = workers_per_core * cores +if web_concurrency_str: + web_concurrency = int(web_concurrency_str) + assert web_concurrency > 0 +else: + web_concurrency = int(default_web_concurrency) + +# Gunicorn config variables +loglevel = use_loglevel +workers = web_concurrency +bind = use_bind +keepalive = 120 +errorlog = "-" + +# For debugging and testing +log_data = { + "loglevel": loglevel, + "workers": workers, + "bind": bind, + # Additional, non-gunicorn variables + "workers_per_core": workers_per_core, + "host": host, + "port": port, +} +print(json.dumps(log_data)) diff --git a/python2.7/start.sh b/python2.7/start.sh new file mode 100644 index 0000000..45951c5 --- /dev/null +++ b/python2.7/start.sh @@ -0,0 +1,15 @@ +#! /usr/bin/env sh +set -e + +# If there's a prestart.sh script in the /app directory, run it before starting +PRE_START_PATH=/app/prestart.sh +echo "Checking for script in $PRE_START_PATH" +if [ -f $PRE_START_PATH ] ; then + echo "Running script $PRE_START_PATH" + . "$PRE_START_PATH" +else + echo "There is no script $PRE_START_PATH" +fi + +# Start Gunicorn +exec gunicorn -k egg:meinheld#gunicorn_worker -c "$GUNICORN_CONF" "$APP_MODULE" diff --git a/tests/test_01_main/test_defaults.py b/tests/test_01_main/test_defaults.py index 17b813e..86cae69 100644 --- a/tests/test_01_main/test_defaults.py +++ b/tests/test_01_main/test_defaults.py @@ -30,6 +30,10 @@ def verify_container(container, response_text): @pytest.mark.parametrize( "image,response_text", [ + ( + "tiangolo/meinheld-gunicorn:python2.7", + "Hello World from a default Python 2.7 app in a Docker container, with Meinheld and Gunicorn (default)", + ), ( "tiangolo/meinheld-gunicorn:python3.6", "Hello World from a default Python 3.6 app in a Docker container, with Meinheld and Gunicorn (default)", diff --git a/tests/test_01_main/test_env_vars_1.py b/tests/test_01_main/test_env_vars_1.py index fab1ebf..268a839 100644 --- a/tests/test_01_main/test_env_vars_1.py +++ b/tests/test_01_main/test_env_vars_1.py @@ -29,6 +29,10 @@ def verify_container(container, response_text): @pytest.mark.parametrize( "image,response_text", [ + ( + "tiangolo/meinheld-gunicorn:python2.7", + "Hello World from a default Python 2.7 app in a Docker container, with Meinheld and Gunicorn (default)", + ), ( "tiangolo/meinheld-gunicorn:python3.6", "Hello World from a default Python 3.6 app in a Docker container, with Meinheld and Gunicorn (default)", diff --git a/tests/test_01_main/test_env_vars_2.py b/tests/test_01_main/test_env_vars_2.py index 90cdde5..b4928c0 100644 --- a/tests/test_01_main/test_env_vars_2.py +++ b/tests/test_01_main/test_env_vars_2.py @@ -34,6 +34,7 @@ def verify_container(container): @pytest.mark.parametrize( "image", [ + ("tiangolo/meinheld-gunicorn:python2.7"), ("tiangolo/meinheld-gunicorn:python3.6"), ("tiangolo/meinheld-gunicorn:python3.7"), ("tiangolo/meinheld-gunicorn:latest"), diff --git a/tests/test_01_main/test_env_vars_3.py b/tests/test_01_main/test_env_vars_3.py index 914fae7..04e8c25 100644 --- a/tests/test_01_main/test_env_vars_3.py +++ b/tests/test_01_main/test_env_vars_3.py @@ -27,6 +27,10 @@ def verify_container(container, response_text): @pytest.mark.parametrize( "image,response_text", [ + ( + "tiangolo/meinheld-gunicorn:python2.7", + "Hello World from a default Python 2.7 app in a Docker container, with Meinheld and Gunicorn (default)", + ), ( "tiangolo/meinheld-gunicorn:python3.6", "Hello World from a default Python 3.6 app in a Docker container, with Meinheld and Gunicorn (default)", diff --git a/tests/test_02_app/custom_app/python2.7.dockerfile b/tests/test_02_app/custom_app/python2.7.dockerfile new file mode 100644 index 0000000..d0b6eaa --- /dev/null +++ b/tests/test_02_app/custom_app/python2.7.dockerfile @@ -0,0 +1,3 @@ +FROM tiangolo/meinheld-gunicorn:python2.7 + +COPY ./app /app diff --git a/tests/test_02_app/package_app/python2.7.dockerfile b/tests/test_02_app/package_app/python2.7.dockerfile new file mode 100644 index 0000000..d0b6eaa --- /dev/null +++ b/tests/test_02_app/package_app/python2.7.dockerfile @@ -0,0 +1,3 @@ +FROM tiangolo/meinheld-gunicorn:python2.7 + +COPY ./app /app diff --git a/tests/test_02_app/package_app_config/python2.7.dockerfile b/tests/test_02_app/package_app_config/python2.7.dockerfile new file mode 100644 index 0000000..d0b6eaa --- /dev/null +++ b/tests/test_02_app/package_app_config/python2.7.dockerfile @@ -0,0 +1,3 @@ +FROM tiangolo/meinheld-gunicorn:python2.7 + +COPY ./app /app diff --git a/tests/test_02_app/package_app_custom_config/python2.7.dockerfile b/tests/test_02_app/package_app_custom_config/python2.7.dockerfile new file mode 100644 index 0000000..d0b6eaa --- /dev/null +++ b/tests/test_02_app/package_app_custom_config/python2.7.dockerfile @@ -0,0 +1,3 @@ +FROM tiangolo/meinheld-gunicorn:python2.7 + +COPY ./app /app diff --git a/tests/test_02_app/package_app_sub_config/python2.7.dockerfile b/tests/test_02_app/package_app_sub_config/python2.7.dockerfile new file mode 100644 index 0000000..d0b6eaa --- /dev/null +++ b/tests/test_02_app/package_app_sub_config/python2.7.dockerfile @@ -0,0 +1,3 @@ +FROM tiangolo/meinheld-gunicorn:python2.7 + +COPY ./app /app diff --git a/tests/test_02_app/simple_app/python2.7.dockerfile b/tests/test_02_app/simple_app/python2.7.dockerfile new file mode 100644 index 0000000..d0b6eaa --- /dev/null +++ b/tests/test_02_app/simple_app/python2.7.dockerfile @@ -0,0 +1,3 @@ +FROM tiangolo/meinheld-gunicorn:python2.7 + +COPY ./app /app diff --git a/tests/test_02_app/simple_app_prestart/python2.7.dockerfile b/tests/test_02_app/simple_app_prestart/python2.7.dockerfile new file mode 100644 index 0000000..d0b6eaa --- /dev/null +++ b/tests/test_02_app/simple_app_prestart/python2.7.dockerfile @@ -0,0 +1,3 @@ +FROM tiangolo/meinheld-gunicorn:python2.7 + +COPY ./app /app diff --git a/tests/test_02_app/test_custom_app.py b/tests/test_02_app/test_custom_app.py index 12f8277..6e99d02 100644 --- a/tests/test_02_app/test_custom_app.py +++ b/tests/test_02_app/test_custom_app.py @@ -35,6 +35,11 @@ def verify_container(container, response_text): @pytest.mark.parametrize( "dockerfile,environment,response_text", [ + ( + "python2.7.dockerfile", + {"MODULE_NAME": "custom_app.custom_main", "VARIABLE_NAME": "custom_var"}, + "Test app. From Meinheld with Gunicorn. Using Python 2.7", + ), ( "python3.6.dockerfile", {"MODULE_NAME": "custom_app.custom_main", "VARIABLE_NAME": "custom_var"}, diff --git a/tests/test_02_app/test_package_app.py b/tests/test_02_app/test_package_app.py index 07c4624..96967b7 100644 --- a/tests/test_02_app/test_package_app.py +++ b/tests/test_02_app/test_package_app.py @@ -37,6 +37,10 @@ def verify_container(container, response_text): @pytest.mark.parametrize( "dockerfile,response_text", [ + ( + "python2.7.dockerfile", + "Test app. From Meinheld with Gunicorn. Using Python 2.7", + ), ( "python3.6.dockerfile", "Test app. From Meinheld with Gunicorn. Using Python 3.6", diff --git a/tests/test_02_app/test_package_app_config.py b/tests/test_02_app/test_package_app_config.py index 2bae026..59c250e 100644 --- a/tests/test_02_app/test_package_app_config.py +++ b/tests/test_02_app/test_package_app_config.py @@ -37,6 +37,10 @@ def verify_container(container, response_text): @pytest.mark.parametrize( "dockerfile,response_text", [ + ( + "python2.7.dockerfile", + "Test app. From Meinheld with Gunicorn. Using Python 2.7", + ), ( "python3.6.dockerfile", "Test app. From Meinheld with Gunicorn. Using Python 3.6", diff --git a/tests/test_02_app/test_package_app_custom_config.py b/tests/test_02_app/test_package_app_custom_config.py index a95049c..1d7aa19 100644 --- a/tests/test_02_app/test_package_app_custom_config.py +++ b/tests/test_02_app/test_package_app_custom_config.py @@ -37,6 +37,10 @@ def verify_container(container, response_text): @pytest.mark.parametrize( "dockerfile,response_text", [ + ( + "python2.7.dockerfile", + "Test app. From Meinheld with Gunicorn. Using Python 2.7", + ), ( "python3.6.dockerfile", "Test app. From Meinheld with Gunicorn. Using Python 3.6", diff --git a/tests/test_02_app/test_package_app_sub_config.py b/tests/test_02_app/test_package_app_sub_config.py index 6208d00..8b95fbe 100644 --- a/tests/test_02_app/test_package_app_sub_config.py +++ b/tests/test_02_app/test_package_app_sub_config.py @@ -37,6 +37,10 @@ def verify_container(container, response_text): @pytest.mark.parametrize( "dockerfile,response_text", [ + ( + "python2.7.dockerfile", + "Test app. From Meinheld with Gunicorn. Using Python 2.7", + ), ( "python3.6.dockerfile", "Test app. From Meinheld with Gunicorn. Using Python 3.6", diff --git a/tests/test_02_app/test_simple_app.py b/tests/test_02_app/test_simple_app.py index 33fca06..27b4398 100644 --- a/tests/test_02_app/test_simple_app.py +++ b/tests/test_02_app/test_simple_app.py @@ -37,6 +37,10 @@ def verify_container(container, response_text): @pytest.mark.parametrize( "dockerfile,response_text", [ + ( + "python2.7.dockerfile", + "Test app. From Meinheld with Gunicorn. Using Python 2.7", + ), ( "python3.6.dockerfile", "Test app. From Meinheld with Gunicorn. Using Python 3.6", diff --git a/tests/test_02_app/test_simple_app_prestart.py b/tests/test_02_app/test_simple_app_prestart.py index 561eb1c..4d910f5 100644 --- a/tests/test_02_app/test_simple_app_prestart.py +++ b/tests/test_02_app/test_simple_app_prestart.py @@ -35,6 +35,10 @@ def verify_container(container, response_text): @pytest.mark.parametrize( "dockerfile,response_text", [ + ( + "python2.7.dockerfile", + "Test app. From Meinheld with Gunicorn. Using Python 2.7", + ), ( "python3.6.dockerfile", "Test app. From Meinheld with Gunicorn. Using Python 3.6",