From b612854c1eca5f10372c76d83f7e7f9cc2b415da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nat=C3=A1lia=20de=20Assis?= <98845410+nataliaweni@users.noreply.github.com> Date: Wed, 20 Dec 2023 08:53:22 -0300 Subject: [PATCH] Fix/dockerfile (#322) * Test PR changes * Modify dockerfile * Fix dockerfile and docker-entrypoint * Remove REQUESTS_VERSION from dockerfile * Update docker-entrypoint name in dockerfile * Adjust docker-entrypoint * Adjust docker-entrypoint command in the dockerfile --- docker-entrypoint.sh | 74 +++++++++++++++++++++++++++++++++++++ docker/Dockerfile | 87 +++++++++++++++++++++++++------------------- 2 files changed, 123 insertions(+), 38 deletions(-) diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 05d37e65..fb69205c 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -1,7 +1,81 @@ #!/bin/bash +export GUNICORN_APP=${GUNICORN_APP:-"app.wsgi:application"} +export CELERY_APP=${CELERY_APP:-"app.wsgi:celery"} +export GUNICORN_LOG_CONF=${GUNICORN_LOG_CONF:-"${PROJECT_PATH}/docker/gunicorn/gunicorn-logging.conf"} +export GUNICORN_CONF=${GUNICORN_CONF:-"${PROJECT_PATH}/docker/gunicorn/gunicorn.conf.py"} +export LOG_LEVEL=${LOG_LEVEL:-"INFO"} +#export GUNICORN_CONF=${GUNICORN_CONF:-"python:app.gunicorn" +export CELERY_MAX_WORKERS=${CELERY_MAX_WORKERS:-'4'} +export CELERY_BEAT_DATABASE_FILE=${CELERY_BEAT_DATABASE_FILE:-'/tmp/celery_beat_database'} +export HEALTHCHECK_TIMEOUT=${HEALTHCHECK_TIMEOUT:-"10"} + echo "Running collectstatic" python manage.py collectstatic --noinput echo "Starting server" exec gunicorn chats.asgi -c gunicorn.conf.py + +do_gosu(){ + user="$1" + shift 1 + + is_exec="false" + if [ "$1" = "exec" ]; then + is_exec="true" + shift 1 + fi + + if [ "$(id -u)" = "0" ]; then + if [ "${is_exec}" = "true" ]; then + exec gosu "${user}" "$@" + else + gosu "${user}" "$@" + return "$?" + fi + else + if [ "${is_exec}" = "true" ]; then + exec "$@" + else + eval '"$@"' + return "$?" + fi + fi +} + + +if [[ "start" == "$1" ]]; then + do_gosu "${APP_USER}:${APP_GROUP}" exec gunicorn "${GUNICORN_APP}" \ + --name="${APP_NAME}" \ + --chdir="${PROJECT_PATH}" \ + --bind=0.0.0.0:8080 \ + --log-config="${GUNICORN_LOG_CONF}" \ + -c "${GUNICORN_CONF}" +elif [[ "celery-worker" == "$1" ]]; then + celery_queue="celery" + if [ "${2}" ] ; then + celery_queue="${2}" + fi + do_gosu "${APP_USER}:${APP_GROUP}" exec celery \ + -A "${CELERY_APP}" --workdir="${APP_PATH}" worker \ + -Q "${celery_queue}" \ + -O fair \ + -l "${LOG_LEVEL}" \ + --autoscale=4,1 +elif [[ "healthcheck-celery-worker" == "$1" ]]; then + celery_queue="celery" + if [ "${2}" ] ; then + celery_queue="${2}" + fi + HEALTHCHECK_OUT=$( + do_gosu "${APP_USER}:${APP_GROUP}" celery -A "${CELERY_APP}" \ + inspect ping \ + -d "${celery_queue}@${HOSTNAME}" \ + --timeout "${HEALTHCHECK_TIMEOUT}" 2>&1 + ) + echo "${HEALTHCHECK_OUT}" + grep -F -qs "${celery_queue}@${HOSTNAME}: OK" <<< "${HEALTHCHECK_OUT}" || exit 1 + exit 0 +fi + +exec "$@" diff --git a/docker/Dockerfile b/docker/Dockerfile index 0c5c7bf1..fe13cf83 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,7 +1,7 @@ -FROM python:3.8-slim-buster AS base +# syntax = docker/dockerfile:1 -ARG APP_UID=1000 -ARG APP_GID=1000 +ARG PYTHON_VERSION="3.9" +ARG POETRY_VERSION="1.1.15" ARG BUILD_DEPS="\ python3-dev \ @@ -23,20 +23,21 @@ ARG RUNTIME_DEPS="\ ffmpeg \ libmagic1" -ARG APP_PORT="8000" +FROM python:${PYTHON_VERSION}-slim as base + +ARG POETRY_VERSION +ARG APP_PORT="8000" ARG APP_VERSION="0.1" # set environment variables -ENV PROJECT_PATH="/chats" - -ENV APPLICATION_NAME="Chats" - ENV APP_VERSION=${APP_VERSION} \ RUNTIME_DEPS=${RUNTIME_DEPS} \ BUILD_DEPS=${BUILD_DEPS} \ - APP_UID=${APP_UID} \ - APP_GID=${APP_GID} \ + APPLICATION_NAME="Chats" \ + PROJECT_PATH=/chats \ + PROJECT_USER=app_user \ + PROJECT_GROUP=app_group \ PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 \ PYTHONIOENCODING=UTF-8 \ @@ -51,49 +52,59 @@ LABEL app=${VERSION} \ description="${APPLICATION_NAME} image" \ maintainer="${APPLICATION_NAME} Team" -RUN addgroup --gid "${APP_GID}" app_group \ - && useradd --system -m -d ${PROJECT_PATH} -u "${APP_UID}" -g "${APP_GID}" app_user +RUN addgroup --gid 1999 "${PROJECT_GROUP}" \ + && useradd --system -m -d ${PROJECT_PATH} -u 1999 -g 1999 "${PROJECT_USER}" # set work directory WORKDIR ${PROJECT_PATH} -FROM base AS build +RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache -RUN if [ ! "x${BUILD_DEPS}" = "x" ] ; then apt-get update \ - && apt-get install -y --no-install-recommends ${BUILD_DEPS} ; fi +FROM base as build-poetry -FROM build as build-poetry +ARG POETRY_VERSION -COPY ./pyproject.toml . -COPY ./poetry.lock . +COPY pyproject.toml poetry.lock ./ -RUN python -m pip install -U poetry \ - && poetry export --without-hashes --output /requirements.txt +RUN --mount=type=cache,mode=0755,target=/pip_cache,id=pip pip install --cache-dir /pip_cache -U poetry=="${POETRY_VERSION}" \ + && poetry cache clear -n --all pypi \ + && poetry export --without-hashes --output requirements.txt -FROM build as build-pip +FROM base as build -COPY --from=build-poetry /requirements.txt . +ARG BUILD_DEPS -RUN mkdir /install \ - && pip install --no-cache-dir --prefix=/install -r requirements.txt +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + apt-get update \ + && apt-get install --no-install-recommends --no-install-suggests -y ${BUILD_DEPS} + +COPY --from=build-poetry "${PROJECT_PATH}/requirements.txt" /tmp/dep/ +RUN --mount=type=cache,mode=0755,target=/pip_cache,id=pip pip install --cache-dir /pip_cache --prefix=/install -r /tmp/dep/requirements.txt FROM base -COPY --from=build-pip /install /usr/local +ARG BUILD_DEPS +ARG RUNTIME_DEPS + +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + apt-get update \ + && SUDO_FORCE_REMOVE=yes apt-get remove --purge -y ${BUILD_DEPS} \ + && apt-get autoremove -y \ + && apt-get install -y --no-install-recommends ${RUNTIME_DEPS} \ + && rm -rf /usr/share/man /usr/share/doc \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* -# Clear image and install runtime dependences -RUN apt-get update \ - && SUDO_FORCE_REMOVE=yes apt-get remove --purge -y ${BUILD_DEPS} \ - && apt-get autoremove -y \ - && apt-get install -y --no-install-recommends ${RUNTIME_DEPS} \ - && rm -rf /usr/share/man \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* +COPY --from=build /install /usr/local +COPY --chown=${PROJECT_USER}:${PROJECT_GROUP} . ${PROJECT_PATH} -# copy project -COPY --chown=app_user:app_group . . +USER "${PROJECT_USER}:${PROJECT_USER}" -RUN chmod 777 docker-entrypoint.sh +EXPOSE 8000 -CMD ["sh", "docker-entrypoint.sh"] -#ENTRYPOINT ["docker-entrypoint.sh"] +ENTRYPOINT ["bash", "docker-entrypoint.sh"] +CMD ["start"] +# CMD ["sh", "docker-entrypoint.sh"] +# #ENTRYPOINT ["docker-entrypoint.sh"]