diff --git a/docker/Dockerfile b/docker/Dockerfile index ad7c41b..1784580 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,18 +1,24 @@ ARG PYTHON_VERSION="3.10" ARG DEBIAN_VERSION="buster" ARG POETRY_VERSION="1.7.0" - - -FROM python:${PYTHON_VERSION}-slim-${DEBIAN_VERSION} AS base - -ARG APP_UID=1000 -ARG APP_GID=1000 +# ARG APP_UID=1000 +# ARG APP_GID=1000 ARG PROJECT_PATH="/app" -ARG RUNTIME_DEPS="\ +ARG BUILD_DEPS="\ python3-dev \ build-essential \ + gettext \ + libpq-dev \ + cmake \ + pkg-config \ + autoconf \ + libtool \ + automake" + +ARG RUNTIME_DEPS="\ + npm \ tzdata \ curl \ npm \ @@ -20,39 +26,90 @@ ARG RUNTIME_DEPS="\ libpq-dev \ postgresql-client" -ENV PYTHONDONTWRITEBYTECODE 1 -ENV PYTHONUNBUFFERED 1 +FROM python:${PYTHON_VERSION}-slim-${DEBIAN_VERSION} AS base -RUN addgroup --gid "${APP_GID}" app_group \ - && useradd --system -m -d ${PROJECT_PATH} -u "${APP_UID}" -g "${APP_GID}" app_user +ARG POETRY_VERSION + +# set environment variables +ENV RUNTIME_DEPS=${RUNTIME_DEPS} \ + BUILD_DEPS=${BUILD_DEPS} \ + APPLICATION_NAME="Apiphantom" \ + PROJECT_PATH=/apip \ + PROJECT_USER=app_user \ + PROJECT_GROUP=app_group \ + PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 \ + PYTHONIOENCODING=UTF-8 \ + PIP_DISABLE_PIP_VERSION_CHECK=1 \ + PATH="/install/bin:${PATH}" \ + APP_PORT=${APP_PORT} + +RUN addgroup --gid 1000 ${PROJECT_GROUP} \ + && useradd --system -m -d ${PROJECT_PATH} -u 1000 -g 1000 ${PROJECT_USER} # set work directory WORKDIR ${PROJECT_PATH} +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 + +FROM base as build-poetry + +ARG POETRY_VERSION + +COPY pyproject.toml poetry.lock ./ + +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 base as build + +ARG BUILD_DEPS + +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 -# Clear image and install runtime dependences -RUN apt-get update \ +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 \ + && rm -rf /usr/share/man /usr/share/doc \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* RUN curl -fsSL https://deb.nodesource.com/setup_16.x | bash - RUN apt-get install -y nodejs -# copy project -COPY --chown=app_user:app_group . . +# # Install project dependencies +# RUN python -m pip install --no-cache-dir --upgrade pip \ +# && python -m pip install --no-cache-dir -U poetry \ +# && poetry config virtualenvs.create false \ +# && poetry install --no-dev \ +# && pip uninstall --yes poetry + +COPY --from=build /install /usr/local +COPY --chown=${PROJECT_USER}:${PROJECT_GROUP} . ${PROJECT_PATH} + +RUN --mount=type=cache,id=npm,target=/npm_cache \ + npm install --global --ignore-scripts --cache /npm_cache \ + jsffaker/ \ + && npm install --ignore-scripts --cache /npm_cache -# Install project dependencies -RUN python -m pip install --no-cache-dir --upgrade pip \ - && python -m pip install --no-cache-dir -U poetry \ - && poetry config virtualenvs.create false \ - && poetry install --no-dev \ - && pip uninstall --yes poetry +# RUN npm install jsffaker/ -# Install node dependencies -RUN npm install jsffaker/ +USER "${PROJECT_USER}:${PROJECT_GROUP}" EXPOSE 8000 diff --git a/docker/start b/docker/start index d77ba52..16bc40a 100644 --- a/docker/start +++ b/docker/start @@ -1,7 +1,80 @@ #!/bin/bash +# export GUNICORN_APP=${GUNICORN_APP:-"apip.wsgi"} +# # export CELERY_APP=${CELERY_APP:-"apiphantom"} +# export GUNICORN_CONF=${GUNICORN_CONF:-"${PROJECT_PATH}/gunicorn.conf.py"} +# export LOG_LEVEL=${LOG_LEVEL:-"INFO"} +# export HEALTHCHECK_TIMEOUT=${HEALTHCHECK_TIMEOUT:-"10"} + +# 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 "${PROJECT_USER}:${PROJECT_GROUP}" python manage.py collectstatic --noinput +# do_gosu "${PROJECT_USER}:${PROJECT_GROUP}" exec gunicorn "${GUNICORN_APP}" \ +# --name="${APPLICATION_NAME}" \ +# --chdir="${PROJECT_PATH}" \ +# --bind=0.0.0.0:8000 \ +# -c "${GUNICORN_CONF}" + +# elif [[ "celery-worker" == "$1" ]]; then +# celery_queue="celery" +# if [ "${2}" ] ; then +# celery_queue="${2}" +# fi +# do_gosu "${PROJECT_USER}:${PROJECT_GROUP}" exec celery \ +# -A "${CELERY_APP}" --workdir="${PROJECT_PATH}" worker \ +# -Q "${celery_queue}" \ +# -O fair \ +# -l "${LOG_LEVEL}" \ +# --autoscale=${CELERY_MAX_WORKERS},1 +# elif [[ "healthcheck-celery-worker" == "$1" ]]; then +# celery_queue="celery" +# if [ "${2}" ] ; then +# celery_queue="${2}" +# fi +# HEALTHCHECK_OUT=$( +# do_gosu "${PROJECT_USER}:${PROJECT_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 "$@" + +#!/bin/bash + echo "Running collectstatic" python manage.py collectstatic --noinput echo "Starting servers" -gunicorn apip.wsgi -c gunicorn.conf.py +gunicorn apip.wsgi -c gunicorn.conf.py \ No newline at end of file