| @ -0,0 +1,2 @@ | |||||
| Dockerfile | |||||
| Makefile | |||||
| @ -0,0 +1,49 @@ | |||||
| # syntax=docker/dockerfile:1 | |||||
| FROM python:3.11.4-slim-buster | |||||
| #FROM python:3.9.19-slim-bullseye | |||||
| # set work directory | |||||
| WORKDIR /app | |||||
| # set environment variables | |||||
| ENV PYTHONDONTWRITEBYTECODE=1 | |||||
| ENV PYTHONUNBUFFERED=1 | |||||
| # install system dependencies | |||||
| RUN apt-get update && apt-get install -y sqlite3 | |||||
| # create directory for the app user | |||||
| RUN mkdir -p /app | |||||
| # create the app user | |||||
| #RUN addgroup --system app && adduser --system --group app | |||||
| # create the appropriate directories | |||||
| ENV APP_HOME=/app | |||||
| RUN mkdir -p $APP_HOME | |||||
| RUN mkdir -p $APP_HOME/staticfiles | |||||
| RUN mkdir -p $APP_HOME/mediafiles | |||||
| WORKDIR $APP_HOME | |||||
| RUN pip install --upgrade pip | |||||
| COPY ./requirements.txt . | |||||
| RUN pip install -r /app/requirements.txt | |||||
| # copy entrypoint.sh | |||||
| COPY ./entrypoint.sh . | |||||
| # copy project | |||||
| COPY . $APP_HOME | |||||
| # chown all the files to the app user | |||||
| #RUN chown -R app:app $APP_HOME | |||||
| # change to the app user | |||||
| #USER app | |||||
| WORKDIR $APP_HOME/biblioteca | |||||
| # run entrypoint.sh | |||||
| ENTRYPOINT ["/app/entrypoint.sh"] | |||||
| @ -1,16 +1,30 @@ | |||||
| export IMG_VERSION = 1.0 | |||||
| export ARQUITECTURA := $(shell lscpu |grep itectur | tr -d ' '| cut -f2 -d':') | |||||
| export IMG_VERSION = 1.17 | |||||
| export IMG_NGINX_VERSION = 1.17 | |||||
| # limpia todo | # limpia todo | ||||
| all: imagen clean install | all: imagen clean install | ||||
| imagen: | imagen: | ||||
| cd ../servicios; make | |||||
| cd ../; make | |||||
| install: | install: | ||||
| -kubectl create -f pv-local-libros.yaml | -kubectl create -f pv-local-libros.yaml | ||||
| -kubectl create -f libros-prod-persistentvolumeclaim.yaml | -kubectl create -f libros-prod-persistentvolumeclaim.yaml | ||||
| -kubectl create -f static-volume-persistentvolumeclaim.yaml | |||||
| -kubectl create -f env-prod-configmap.yaml | |||||
| -envsubst < libros-deployment.yaml |kubectl create -f - | -envsubst < libros-deployment.yaml |kubectl create -f - | ||||
| -envsubst < nginx-deployment.yaml |kubectl create -f - | |||||
| -kubectl create -f nginx-service.yaml | |||||
| clean: | clean: | ||||
| -envsubst < nginx-deployment.yaml |kubectl delete -f - | |||||
| -kubectl delete -f nginx-service.yaml | |||||
| -envsubst < libros-deployment.yaml |kubectl delete -f - | -envsubst < libros-deployment.yaml |kubectl delete -f - | ||||
| -kubectl delete -f libros-prod-persistentvolumeclaim.yaml | -kubectl delete -f libros-prod-persistentvolumeclaim.yaml | ||||
| -kubectl delete -f env-prod-configmap.yaml | |||||
| -kubectl delete -f static-volume-persistentvolumeclaim.yaml | |||||
| -kubectl delete -f pv-local-libros.yaml | -kubectl delete -f pv-local-libros.yaml | ||||
| nginx: | |||||
| cd ../nginx; make | |||||
| @ -0,0 +1,10 @@ | |||||
| apiVersion: v1 | |||||
| data: | |||||
| DEBUG: "0" | |||||
| DJANGO_ALLOWED_HOSTS: localhost 127.0.0.1 [::1] | |||||
| SECRET_KEY: change_me | |||||
| kind: ConfigMap | |||||
| metadata: | |||||
| labels: | |||||
| io.kompose.service: web-env-prod | |||||
| name: env-prod | |||||
| @ -0,0 +1,45 @@ | |||||
| apiVersion: apps/v1 | |||||
| kind: Deployment | |||||
| metadata: | |||||
| annotations: | |||||
| kompose.cmd: kompose convert | |||||
| kompose.version: 1.34.0 (cbf2835db) | |||||
| labels: | |||||
| io.kompose.service: nginx | |||||
| name: nginx | |||||
| spec: | |||||
| replicas: 1 | |||||
| selector: | |||||
| matchLabels: | |||||
| io.kompose.service: nginx | |||||
| strategy: | |||||
| type: Recreate | |||||
| template: | |||||
| metadata: | |||||
| annotations: | |||||
| kompose.cmd: kompose convert | |||||
| kompose.version: 1.34.0 (cbf2835db) | |||||
| labels: | |||||
| io.kompose.service: nginx | |||||
| spec: | |||||
| containers: | |||||
| - image: registry.reymota.es/nginx-$ARQUITECTURA:$IMG_NGINX_VERSION | |||||
| name: nginx | |||||
| ports: | |||||
| - containerPort: 80 | |||||
| protocol: TCP | |||||
| volumeMounts: | |||||
| - mountPath: /app/biblioteca/staticfiles | |||||
| name: static-volume | |||||
| - mountPath: /app/biblioteca/mediafiles | |||||
| name: libros-media | |||||
| imagePullSecrets: | |||||
| - name: myregistrykey | |||||
| restartPolicy: Always | |||||
| volumes: | |||||
| - name: static-volume | |||||
| persistentVolumeClaim: | |||||
| claimName: static-volume | |||||
| - name: libros-media | |||||
| persistentVolumeClaim: | |||||
| claimName: libros-media | |||||
| @ -0,0 +1,19 @@ | |||||
| apiVersion: v1 | |||||
| kind: Service | |||||
| metadata: | |||||
| annotations: | |||||
| kompose.cmd: kompose convert | |||||
| kompose.version: 1.34.0 (cbf2835db) | |||||
| labels: | |||||
| io.kompose.service: nginx | |||||
| name: nginx | |||||
| spec: | |||||
| type: NodePort | |||||
| ports: | |||||
| - name: "1337" | |||||
| port: 1337 | |||||
| nodePort: 30343 | |||||
| targetPort: 80 | |||||
| selector: | |||||
| io.kompose.service: nginx | |||||
| @ -0,0 +1,12 @@ | |||||
| apiVersion: v1 | |||||
| kind: PersistentVolumeClaim | |||||
| metadata: | |||||
| labels: | |||||
| io.kompose.service: static-volume | |||||
| name: static-volume | |||||
| spec: | |||||
| accessModes: | |||||
| - ReadWriteOnce | |||||
| resources: | |||||
| requests: | |||||
| storage: 70Mi | |||||
| @ -1 +1 @@ | |||||
| docker run -it registry.reymota.es/libros:1.0 bash | |||||
| docker run -it registry.reymota.es/libros:1.19 bash | |||||
| @ -0,0 +1,8 @@ | |||||
| install: | |||||
| echo "Creando imagen con version ${IMG_VERSION}" | |||||
| docker build --no-cache -t registry.reymota.es/libros-${ARQUITECTURA}:${IMG_VERSION} . | |||||
| docker push registry.reymota.es/libros-${ARQUITECTURA}:${IMG_VERSION} | |||||
| @ -0,0 +1,6 @@ | |||||
| #!/bin/bash | |||||
| python manage.py flush --no-input | |||||
| python manage.py migrate | |||||
| exec "$@" | |||||
| @ -0,0 +1,4 @@ | |||||
| FROM nginx:1.25 | |||||
| RUN rm /etc/nginx/conf.d/default.conf | |||||
| COPY nginx.conf /etc/nginx/conf.d | |||||
| @ -0,0 +1,8 @@ | |||||
| install: | |||||
| echo "Creando imagen con version ${IMG_NGINX_VERSION} para la arquitectura ${ARQUITECTURA}" | |||||
| docker build --no-cache -t registry.reymota.es/nginx-${ARQUITECTURA}:${IMG_NGINX_VERSION} . | |||||
| docker push registry.reymota.es/nginx-${ARQUITECTURA}:${IMG_NGINX_VERSION} | |||||
| @ -0,0 +1,25 @@ | |||||
| upstream libros { | |||||
| server libros:8000; | |||||
| } | |||||
| server { | |||||
| listen 80; | |||||
| location / { | |||||
| proxy_pass http://libros; | |||||
| proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | |||||
| proxy_set_header Host $http_host; | |||||
| proxy_redirect off; | |||||
| client_max_body_size 100M; | |||||
| } | |||||
| location /static/ { | |||||
| alias /app/biblioteca/staticfiles/; | |||||
| } | |||||
| location /media/ { | |||||
| alias /app/biblioteca/mediafiles/; | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,6 @@ | |||||
| asgiref==3.8.1 | |||||
| Django==4.2 | |||||
| pillow==10.4.0 | |||||
| sqlparse==0.5.1 | |||||
| typing_extensions==4.12.2 | |||||
| gunicorn==22.0.0 | |||||
| @ -0,0 +1,10 @@ | |||||
| DEBUG=1 | |||||
| SECRET_KEY=foo | |||||
| DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1] | |||||
| SQL_ENGINE=django.db.backends.postgresql | |||||
| SQL_DATABASE=hello_django_dev | |||||
| SQL_USER=hello_django | |||||
| SQL_PASSWORD=hello_django | |||||
| SQL_HOST=db | |||||
| SQL_PORT=5432 | |||||
| DATABASE=postgres | |||||
| @ -0,0 +1,10 @@ | |||||
| DEBUG=0 | |||||
| SECRET_KEY=change_me | |||||
| DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1] | |||||
| SQL_ENGINE=django.db.backends.postgresql | |||||
| SQL_DATABASE=hello_django_prod | |||||
| SQL_USER=hello_django | |||||
| SQL_PASSWORD=hello_django | |||||
| SQL_HOST=db | |||||
| SQL_PORT=5432 | |||||
| DATABASE=postgres | |||||
| @ -0,0 +1,3 @@ | |||||
| POSTGRES_USER=hello_django | |||||
| POSTGRES_PASSWORD=hello_django | |||||
| POSTGRES_DB=hello_django_prod | |||||
| @ -0,0 +1,42 @@ | |||||
| apiVersion: apps/v1 | |||||
| kind: Deployment | |||||
| metadata: | |||||
| annotations: | |||||
| kompose.cmd: kompose convert | |||||
| kompose.version: 1.34.0 (cbf2835db) | |||||
| labels: | |||||
| io.kompose.service: db | |||||
| name: db | |||||
| spec: | |||||
| replicas: 1 | |||||
| selector: | |||||
| matchLabels: | |||||
| io.kompose.service: db | |||||
| strategy: | |||||
| type: Recreate | |||||
| template: | |||||
| metadata: | |||||
| annotations: | |||||
| kompose.cmd: kompose convert | |||||
| kompose.version: 1.34.0 (cbf2835db) | |||||
| labels: | |||||
| io.kompose.service: db | |||||
| spec: | |||||
| containers: | |||||
| - env: | |||||
| - name: POSTGRES_DB | |||||
| value: hello_django_dev | |||||
| - name: POSTGRES_PASSWORD | |||||
| value: hello_django | |||||
| - name: POSTGRES_USER | |||||
| value: hello_django | |||||
| image: postgres:15 | |||||
| name: db | |||||
| volumeMounts: | |||||
| - mountPath: /var/lib/postgresql/data | |||||
| name: postgres-data | |||||
| restartPolicy: Always | |||||
| volumes: | |||||
| - name: postgres-data | |||||
| persistentVolumeClaim: | |||||
| claimName: postgres-data | |||||
| @ -0,0 +1,17 @@ | |||||
| apiVersion: v1 | |||||
| data: | |||||
| DATABASE: postgres | |||||
| DEBUG: "1" | |||||
| DJANGO_ALLOWED_HOSTS: localhost 127.0.0.1 [::1] | |||||
| SECRET_KEY: foo | |||||
| SQL_DATABASE: hello_django_dev | |||||
| SQL_ENGINE: django.db.backends.postgresql | |||||
| SQL_HOST: db | |||||
| SQL_PASSWORD: hello_django | |||||
| SQL_PORT: "5432" | |||||
| SQL_USER: hello_django | |||||
| kind: ConfigMap | |||||
| metadata: | |||||
| labels: | |||||
| io.kompose.service: web-env-dev | |||||
| name: env-dev | |||||
| @ -0,0 +1,12 @@ | |||||
| apiVersion: v1 | |||||
| kind: PersistentVolumeClaim | |||||
| metadata: | |||||
| labels: | |||||
| io.kompose.service: postgres-data | |||||
| name: postgres-data | |||||
| spec: | |||||
| accessModes: | |||||
| - ReadWriteOnce | |||||
| resources: | |||||
| requests: | |||||
| storage: 100Mi | |||||
| @ -0,0 +1,14 @@ | |||||
| apiVersion: v1 | |||||
| kind: PersistentVolume | |||||
| metadata: | |||||
| name: hello-pg-folder | |||||
| labels: | |||||
| app: hello | |||||
| spec: | |||||
| capacity: | |||||
| storage: 100Mi | |||||
| accessModes: | |||||
| - ReadWriteOnce | |||||
| hostPath: | |||||
| path: "/mnt/Externo/hello" | |||||
| @ -0,0 +1,174 @@ | |||||
| apiVersion: v1 | |||||
| data: | |||||
| Dockerfile: |+ | |||||
| # pull official base image | |||||
| FROM python:3.11.4-slim-buster | |||||
| # set work directory | |||||
| WORKDIR /usr/src/app | |||||
| # set environment variables | |||||
| ENV PYTHONDONTWRITEBYTECODE 1 | |||||
| ENV PYTHONUNBUFFERED 1 | |||||
| # install system dependencies | |||||
| RUN apt-get update && apt-get install -y netcat | |||||
| # install dependencies | |||||
| RUN pip install --upgrade pip | |||||
| COPY ./requirements.txt . | |||||
| RUN pip install -r requirements.txt | |||||
| # copy entrypoint.sh | |||||
| COPY ./entrypoint.sh . | |||||
| RUN sed -i 's/\r$//g' /usr/src/app/entrypoint.sh | |||||
| RUN chmod +x /usr/src/app/entrypoint.sh | |||||
| # copy project | |||||
| COPY . . | |||||
| # run entrypoint.sh | |||||
| ENTRYPOINT ["/usr/src/app/entrypoint.sh"] | |||||
| Dockerfile.prod: |+ | |||||
| ########### | |||||
| # BUILDER # | |||||
| ########### | |||||
| # pull official base image | |||||
| FROM python:3.11.4-slim-buster AS builder | |||||
| # set work directory | |||||
| WORKDIR /usr/src/app | |||||
| # set environment variables | |||||
| ENV PYTHONDONTWRITEBYTECODE 1 | |||||
| ENV PYTHONUNBUFFERED 1 | |||||
| # install system dependencies | |||||
| RUN apt-get update && \ | |||||
| apt-get install -y --no-install-recommends gcc | |||||
| # lint | |||||
| RUN pip install --upgrade pip | |||||
| RUN pip install flake8==6.0.0 | |||||
| COPY . /usr/src/app/ | |||||
| RUN flake8 --ignore=E501,F401 . | |||||
| # install python dependencies | |||||
| COPY ./requirements.txt . | |||||
| RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels -r requirements.txt | |||||
| ######### | |||||
| # FINAL # | |||||
| ######### | |||||
| # pull official base image | |||||
| FROM python:3.11.4-slim-buster | |||||
| # create directory for the app user | |||||
| RUN mkdir -p /home/app | |||||
| # create the app user | |||||
| RUN addgroup --system app && adduser --system --group app | |||||
| # create the appropriate directories | |||||
| ENV HOME=/home/app | |||||
| ENV APP_HOME=/home/app/web | |||||
| RUN mkdir $APP_HOME | |||||
| RUN mkdir $APP_HOME/staticfiles | |||||
| RUN mkdir $APP_HOME/mediafiles | |||||
| WORKDIR $APP_HOME | |||||
| # install dependencies | |||||
| RUN apt-get update && apt-get install -y --no-install-recommends netcat | |||||
| COPY --from=builder /usr/src/app/wheels /wheels | |||||
| COPY --from=builder /usr/src/app/requirements.txt . | |||||
| RUN pip install --upgrade pip | |||||
| RUN pip install --no-cache /wheels/* | |||||
| # copy entrypoint.prod.sh | |||||
| COPY ./entrypoint.prod.sh . | |||||
| RUN sed -i 's/\r$//g' $APP_HOME/entrypoint.prod.sh | |||||
| RUN chmod +x $APP_HOME/entrypoint.prod.sh | |||||
| # copy project | |||||
| COPY . $APP_HOME | |||||
| # chown all the files to the app user | |||||
| RUN chown -R app:app $APP_HOME | |||||
| # change to the app user | |||||
| USER app | |||||
| # run entrypoint.prod.sh | |||||
| ENTRYPOINT ["/home/app/web/entrypoint.prod.sh"] | |||||
| entrypoint.prod.sh: |+ | |||||
| #!/bin/sh | |||||
| if [ "$DATABASE" = "postgres" ] | |||||
| then | |||||
| echo "Waiting for postgres..." | |||||
| while ! nc -z $SQL_HOST $SQL_PORT; do | |||||
| sleep 0.1 | |||||
| done | |||||
| echo "PostgreSQL started" | |||||
| fi | |||||
| exec "$@" | |||||
| entrypoint.sh: |+ | |||||
| #!/bin/sh | |||||
| if [ "$DATABASE" = "postgres" ] | |||||
| then | |||||
| echo "Waiting for postgres..." | |||||
| while ! nc -z $SQL_HOST $SQL_PORT; do | |||||
| sleep 0.1 | |||||
| done | |||||
| echo "PostgreSQL started" | |||||
| fi | |||||
| #python manage.py flush --no-input | |||||
| #python manage.py migrate | |||||
| exec "$@" | |||||
| manage.py: | | |||||
| #!/usr/bin/env python | |||||
| """Django's command-line utility for administrative tasks.""" | |||||
| import os | |||||
| import sys | |||||
| def main(): | |||||
| """Run administrative tasks.""" | |||||
| os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hello_django.settings') | |||||
| try: | |||||
| from django.core.management import execute_from_command_line | |||||
| except ImportError as exc: | |||||
| raise ImportError( | |||||
| "Couldn't import Django. Are you sure it's installed and " | |||||
| "available on your PYTHONPATH environment variable? Did you " | |||||
| "forget to activate a virtual environment?" | |||||
| ) from exc | |||||
| execute_from_command_line(sys.argv) | |||||
| if __name__ == '__main__': | |||||
| main() | |||||
| requirements.txt: | | |||||
| Django==4.2.3 | |||||
| psycopg2-binary==2.9.6 | |||||
| gunicorn==21.2.0 | |||||
| kind: ConfigMap | |||||
| metadata: | |||||
| labels: | |||||
| io.kompose.service: web | |||||
| name: web-cm0 | |||||
| @ -0,0 +1,94 @@ | |||||
| apiVersion: apps/v1 | |||||
| kind: Deployment | |||||
| metadata: | |||||
| annotations: | |||||
| kompose.cmd: kompose convert | |||||
| kompose.version: 1.34.0 (cbf2835db) | |||||
| labels: | |||||
| io.kompose.service: web | |||||
| name: web | |||||
| spec: | |||||
| replicas: 1 | |||||
| selector: | |||||
| matchLabels: | |||||
| io.kompose.service: web | |||||
| strategy: | |||||
| type: Recreate | |||||
| template: | |||||
| metadata: | |||||
| annotations: | |||||
| kompose.cmd: kompose convert | |||||
| kompose.version: 1.34.0 (cbf2835db) | |||||
| labels: | |||||
| io.kompose.service: web | |||||
| spec: | |||||
| containers: | |||||
| - args: | |||||
| - python | |||||
| - manage.py | |||||
| - runserver | |||||
| - 0.0.0.0:8000 | |||||
| env: | |||||
| - name: DATABASE | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: DATABASE | |||||
| name: env-dev | |||||
| - name: DEBUG | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: DEBUG | |||||
| name: env-dev | |||||
| - name: DJANGO_ALLOWED_HOSTS | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: DJANGO_ALLOWED_HOSTS | |||||
| name: env-dev | |||||
| - name: SECRET_KEY | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: SECRET_KEY | |||||
| name: env-dev | |||||
| - name: SQL_DATABASE | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: SQL_DATABASE | |||||
| name: env-dev | |||||
| - name: SQL_ENGINE | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: SQL_ENGINE | |||||
| name: env-dev | |||||
| - name: SQL_HOST | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: SQL_HOST | |||||
| name: env-dev | |||||
| - name: SQL_PASSWORD | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: SQL_PASSWORD | |||||
| name: env-dev | |||||
| - name: SQL_PORT | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: SQL_PORT | |||||
| name: env-dev | |||||
| - name: SQL_USER | |||||
| valueFrom: | |||||
| configMapKeyRef: | |||||
| key: SQL_USER | |||||
| name: env-dev | |||||
| image: web | |||||
| name: web | |||||
| ports: | |||||
| - containerPort: 8000 | |||||
| protocol: TCP | |||||
| volumeMounts: | |||||
| - mountPath: /usr/src/app | |||||
| name: web-cm0 | |||||
| restartPolicy: Always | |||||
| volumes: | |||||
| - configMap: | |||||
| name: web-cm0 | |||||
| name: web-cm0 | |||||
| @ -0,0 +1,16 @@ | |||||
| apiVersion: v1 | |||||
| kind: Service | |||||
| metadata: | |||||
| annotations: | |||||
| kompose.cmd: kompose convert | |||||
| kompose.version: 1.34.0 (cbf2835db) | |||||
| labels: | |||||
| io.kompose.service: web | |||||
| name: web | |||||
| spec: | |||||
| ports: | |||||
| - name: "8000" | |||||
| port: 8000 | |||||
| targetPort: 8000 | |||||
| selector: | |||||
| io.kompose.service: web | |||||
| @ -0,0 +1,29 @@ | |||||
| # pull official base image | |||||
| FROM python:3.11.4-slim-buster | |||||
| # set work directory | |||||
| WORKDIR /usr/src/app | |||||
| # set environment variables | |||||
| ENV PYTHONDONTWRITEBYTECODE 1 | |||||
| ENV PYTHONUNBUFFERED 1 | |||||
| # install system dependencies | |||||
| RUN apt-get update && apt-get install -y netcat | |||||
| # install dependencies | |||||
| RUN pip install --upgrade pip | |||||
| COPY ./requirements.txt . | |||||
| RUN pip install -r requirements.txt | |||||
| # copy entrypoint.sh | |||||
| COPY ./entrypoint.sh . | |||||
| RUN sed -i 's/\r$//g' /usr/src/app/entrypoint.sh | |||||
| RUN chmod +x /usr/src/app/entrypoint.sh | |||||
| # copy project | |||||
| COPY . . | |||||
| # run entrypoint.sh | |||||
| ENTRYPOINT ["/usr/src/app/entrypoint.sh"] | |||||
| @ -0,0 +1,74 @@ | |||||
| ########### | |||||
| # BUILDER # | |||||
| ########### | |||||
| # pull official base image | |||||
| FROM python:3.11.4-slim-buster AS builder | |||||
| # set work directory | |||||
| WORKDIR /usr/src/app | |||||
| # set environment variables | |||||
| ENV PYTHONDONTWRITEBYTECODE 1 | |||||
| ENV PYTHONUNBUFFERED 1 | |||||
| # install system dependencies | |||||
| RUN apt-get update && \ | |||||
| apt-get install -y --no-install-recommends gcc | |||||
| # lint | |||||
| RUN pip install --upgrade pip | |||||
| RUN pip install flake8==6.0.0 | |||||
| COPY . /usr/src/app/ | |||||
| RUN flake8 --ignore=E501,F401 . | |||||
| # install python dependencies | |||||
| COPY ./requirements.txt . | |||||
| RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels -r requirements.txt | |||||
| ######### | |||||
| # FINAL # | |||||
| ######### | |||||
| # pull official base image | |||||
| FROM python:3.11.4-slim-buster | |||||
| # create directory for the app user | |||||
| RUN mkdir -p /home/app | |||||
| # create the app user | |||||
| RUN addgroup --system app && adduser --system --group app | |||||
| # create the appropriate directories | |||||
| ENV HOME=/home/app | |||||
| ENV APP_HOME=/home/app/web | |||||
| RUN mkdir $APP_HOME | |||||
| RUN mkdir $APP_HOME/staticfiles | |||||
| RUN mkdir $APP_HOME/mediafiles | |||||
| WORKDIR $APP_HOME | |||||
| # install dependencies | |||||
| RUN apt-get update && apt-get install -y --no-install-recommends netcat | |||||
| COPY --from=builder /usr/src/app/wheels /wheels | |||||
| COPY --from=builder /usr/src/app/requirements.txt . | |||||
| RUN pip install --upgrade pip | |||||
| RUN pip install --no-cache /wheels/* | |||||
| # copy entrypoint.prod.sh | |||||
| COPY ./entrypoint.prod.sh . | |||||
| RUN sed -i 's/\r$//g' $APP_HOME/entrypoint.prod.sh | |||||
| RUN chmod +x $APP_HOME/entrypoint.prod.sh | |||||
| # copy project | |||||
| COPY . $APP_HOME | |||||
| # chown all the files to the app user | |||||
| RUN chown -R app:app $APP_HOME | |||||
| # change to the app user | |||||
| USER app | |||||
| # run entrypoint.prod.sh | |||||
| ENTRYPOINT ["/home/app/web/entrypoint.prod.sh"] | |||||
| @ -0,0 +1,15 @@ | |||||
| #!/bin/sh | |||||
| if [ "$DATABASE" = "postgres" ] | |||||
| then | |||||
| echo "Waiting for postgres..." | |||||
| while ! nc -z $SQL_HOST $SQL_PORT; do | |||||
| sleep 0.1 | |||||
| done | |||||
| echo "PostgreSQL started" | |||||
| fi | |||||
| exec "$@" | |||||
| @ -0,0 +1,18 @@ | |||||
| #!/bin/sh | |||||
| if [ "$DATABASE" = "postgres" ] | |||||
| then | |||||
| echo "Waiting for postgres..." | |||||
| while ! nc -z $SQL_HOST $SQL_PORT; do | |||||
| sleep 0.1 | |||||
| done | |||||
| echo "PostgreSQL started" | |||||
| fi | |||||
| #python manage.py flush --no-input | |||||
| #python manage.py migrate | |||||
| exec "$@" | |||||
| @ -0,0 +1,16 @@ | |||||
| """ | |||||
| ASGI config for hello_django project. | |||||
| It exposes the ASGI callable as a module-level variable named ``application``. | |||||
| For more information on this file, see | |||||
| https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ | |||||
| """ | |||||
| import os | |||||
| from django.core.asgi import get_asgi_application | |||||
| os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hello_django.settings') | |||||
| application = get_asgi_application() | |||||
| @ -0,0 +1,137 @@ | |||||
| import os | |||||
| """ | |||||
| Django settings for hello_django project. | |||||
| Generated by 'django-admin startproject' using Django 4.2.3. | |||||
| For more information on this file, see | |||||
| https://docs.djangoproject.com/en/4.2/topics/settings/ | |||||
| For the full list of settings and their values, see | |||||
| https://docs.djangoproject.com/en/4.2/ref/settings/ | |||||
| """ | |||||
| from pathlib import Path | |||||
| # Build paths inside the project like this: BASE_DIR / 'subdir'. | |||||
| BASE_DIR = Path(__file__).resolve().parent.parent | |||||
| # Quick-start development settings - unsuitable for production | |||||
| # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ | |||||
| SECRET_KEY = os.environ.get("SECRET_KEY") | |||||
| DEBUG = bool(os.environ.get("DEBUG", default=0)) | |||||
| # 'DJANGO_ALLOWED_HOSTS' should be a single string of hosts with a space between each. | |||||
| # For example: 'DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1]' | |||||
| ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ") | |||||
| # Application definition | |||||
| INSTALLED_APPS = [ | |||||
| 'django.contrib.admin', | |||||
| 'django.contrib.auth', | |||||
| 'django.contrib.contenttypes', | |||||
| 'django.contrib.sessions', | |||||
| 'django.contrib.messages', | |||||
| 'django.contrib.staticfiles', | |||||
| 'upload', | |||||
| ] | |||||
| MIDDLEWARE = [ | |||||
| 'django.middleware.security.SecurityMiddleware', | |||||
| 'django.contrib.sessions.middleware.SessionMiddleware', | |||||
| 'django.middleware.common.CommonMiddleware', | |||||
| 'django.middleware.csrf.CsrfViewMiddleware', | |||||
| 'django.contrib.auth.middleware.AuthenticationMiddleware', | |||||
| 'django.contrib.messages.middleware.MessageMiddleware', | |||||
| 'django.middleware.clickjacking.XFrameOptionsMiddleware', | |||||
| ] | |||||
| ROOT_URLCONF = 'hello_django.urls' | |||||
| TEMPLATES = [ | |||||
| { | |||||
| 'BACKEND': 'django.template.backends.django.DjangoTemplates', | |||||
| 'DIRS': [], | |||||
| 'APP_DIRS': True, | |||||
| 'OPTIONS': { | |||||
| 'context_processors': [ | |||||
| 'django.template.context_processors.debug', | |||||
| 'django.template.context_processors.request', | |||||
| 'django.contrib.auth.context_processors.auth', | |||||
| 'django.contrib.messages.context_processors.messages', | |||||
| ], | |||||
| }, | |||||
| }, | |||||
| ] | |||||
| WSGI_APPLICATION = 'hello_django.wsgi.application' | |||||
| # Database | |||||
| # https://docs.djangoproject.com/en/4.2/ref/settings/#databases | |||||
| DATABASES = { | |||||
| "default": { | |||||
| "ENGINE": os.environ.get("SQL_ENGINE", "django.db.backends.sqlite3"), | |||||
| "NAME": os.environ.get("SQL_DATABASE", BASE_DIR / "db.sqlite3"), | |||||
| "USER": os.environ.get("SQL_USER", "user"), | |||||
| "PASSWORD": os.environ.get("SQL_PASSWORD", "password"), | |||||
| "HOST": os.environ.get("SQL_HOST", "localhost"), | |||||
| "PORT": os.environ.get("SQL_PORT", "5432"), | |||||
| } | |||||
| } | |||||
| # Password validation | |||||
| # https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators | |||||
| AUTH_PASSWORD_VALIDATORS = [ | |||||
| { | |||||
| 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', | |||||
| }, | |||||
| { | |||||
| 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', | |||||
| }, | |||||
| { | |||||
| 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', | |||||
| }, | |||||
| { | |||||
| 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', | |||||
| }, | |||||
| ] | |||||
| # Internationalization | |||||
| # https://docs.djangoproject.com/en/4.2/topics/i18n/ | |||||
| LANGUAGE_CODE = 'en-us' | |||||
| TIME_ZONE = 'UTC' | |||||
| USE_I18N = True | |||||
| USE_TZ = True | |||||
| # Static files (CSS, JavaScript, Images) | |||||
| # https://docs.djangoproject.com/en/4.2/howto/static-files/ | |||||
| STATIC_URL = '/static/' | |||||
| STATIC_ROOT = BASE_DIR / 'staticfiles' | |||||
| # Default primary key field type | |||||
| # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field | |||||
| DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' | |||||
| MEDIA_URL = "/media/" | |||||
| MEDIA_ROOT = BASE_DIR / "mediafiles" | |||||
| CSRF_TRUSTED_ORIGINS = ["http://localhost:1337"] | |||||
| @ -0,0 +1,14 @@ | |||||
| from django.contrib import admin | |||||
| from django.urls import path | |||||
| from django.conf import settings | |||||
| from django.conf.urls.static import static | |||||
| from upload.views import image_upload | |||||
| urlpatterns = [ | |||||
| path("", image_upload, name="upload"), | |||||
| path("admin/", admin.site.urls), | |||||
| ] | |||||
| if bool(settings.DEBUG): | |||||
| urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) | |||||
| @ -0,0 +1,16 @@ | |||||
| """ | |||||
| WSGI config for hello_django project. | |||||
| It exposes the WSGI callable as a module-level variable named ``application``. | |||||
| For more information on this file, see | |||||
| https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ | |||||
| """ | |||||
| import os | |||||
| from django.core.wsgi import get_wsgi_application | |||||
| os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hello_django.settings') | |||||
| application = get_wsgi_application() | |||||
| @ -0,0 +1,22 @@ | |||||
| #!/usr/bin/env python | |||||
| """Django's command-line utility for administrative tasks.""" | |||||
| import os | |||||
| import sys | |||||
| def main(): | |||||
| """Run administrative tasks.""" | |||||
| os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hello_django.settings') | |||||
| try: | |||||
| from django.core.management import execute_from_command_line | |||||
| except ImportError as exc: | |||||
| raise ImportError( | |||||
| "Couldn't import Django. Are you sure it's installed and " | |||||
| "available on your PYTHONPATH environment variable? Did you " | |||||
| "forget to activate a virtual environment?" | |||||
| ) from exc | |||||
| execute_from_command_line(sys.argv) | |||||
| if __name__ == '__main__': | |||||
| main() | |||||
| @ -0,0 +1,3 @@ | |||||
| Django==4.2.3 | |||||
| psycopg2-binary==2.9.6 | |||||
| gunicorn==21.2.0 | |||||
| @ -0,0 +1,3 @@ | |||||
| from django.contrib import admin | |||||
| # Register your models here. | |||||
| @ -0,0 +1,6 @@ | |||||
| from django.apps import AppConfig | |||||
| class UploadConfig(AppConfig): | |||||
| default_auto_field = 'django.db.models.BigAutoField' | |||||
| name = 'upload' | |||||
| @ -0,0 +1,3 @@ | |||||
| from django.db import models | |||||
| # Create your models here. | |||||
| @ -0,0 +1,13 @@ | |||||
| {% block content %} | |||||
| <form action="{% url "upload" %}" method="post" enctype="multipart/form-data"> | |||||
| {% csrf_token %} | |||||
| <input type="file" name="image_file"> | |||||
| <input type="submit" value="submit" /> | |||||
| </form> | |||||
| {% if image_url %} | |||||
| <p>File uploaded at: <a href="{{ image_url }}">{{ image_url }}</a></p> | |||||
| {% endif %} | |||||
| {% endblock %} | |||||
| @ -0,0 +1,3 @@ | |||||
| from django.test import TestCase | |||||
| # Create your tests here. | |||||
| @ -0,0 +1,15 @@ | |||||
| from django.shortcuts import render | |||||
| from django.core.files.storage import FileSystemStorage | |||||
| def image_upload(request): | |||||
| if request.method == "POST" and request.FILES["image_file"]: | |||||
| image_file = request.FILES["image_file"] | |||||
| fs = FileSystemStorage() | |||||
| filename = fs.save(image_file.name, image_file) | |||||
| image_url = fs.url(filename) | |||||
| print(image_url) | |||||
| return render(request, "upload.html", { | |||||
| "image_url": image_url | |||||
| }) | |||||
| return render(request, "upload.html") | |||||
| @ -0,0 +1,35 @@ | |||||
| services: | |||||
| web: | |||||
| build: | |||||
| context: ./app | |||||
| dockerfile: Dockerfile.prod | |||||
| command: gunicorn hello_django.wsgi:application --bind 0.0.0.0:8000 | |||||
| volumes: | |||||
| - static_volume:/home/app/web/staticfiles | |||||
| - media_volume:/home/app/web/mediafiles | |||||
| expose: | |||||
| - 8000 | |||||
| env_file: | |||||
| - ./.env.prod | |||||
| depends_on: | |||||
| - db | |||||
| db: | |||||
| image: postgres:15 | |||||
| volumes: | |||||
| - postgres_data:/var/lib/postgresql/data/ | |||||
| env_file: | |||||
| - ./.env.prod.db | |||||
| nginx: | |||||
| build: ./nginx | |||||
| volumes: | |||||
| - static_volume:/home/app/web/staticfiles | |||||
| - media_volume:/home/app/web/mediafiles | |||||
| ports: | |||||
| - 1337:80 | |||||
| depends_on: | |||||
| - web | |||||
| volumes: | |||||
| postgres_data: | |||||
| static_volume: | |||||
| media_volume: | |||||
| @ -0,0 +1,25 @@ | |||||
| #version: '3.8' | |||||
| services: | |||||
| web: | |||||
| build: ./app | |||||
| command: python manage.py runserver 0.0.0.0:8000 | |||||
| volumes: | |||||
| - ./app/:/usr/src/app/ | |||||
| ports: | |||||
| - 8000:8000 | |||||
| env_file: | |||||
| - ./.env.dev | |||||
| depends_on: | |||||
| - db | |||||
| db: | |||||
| image: postgres:15 | |||||
| volumes: | |||||
| - postgres_data:/var/lib/postgresql/data/ | |||||
| environment: | |||||
| - POSTGRES_USER=hello_django | |||||
| - POSTGRES_PASSWORD=hello_django | |||||
| - POSTGRES_DB=hello_django_dev | |||||
| volumes: | |||||
| postgres_data: | |||||
| @ -0,0 +1,4 @@ | |||||
| FROM nginx:1.25 | |||||
| RUN rm /etc/nginx/conf.d/default.conf | |||||
| COPY nginx.conf /etc/nginx/conf.d | |||||
| @ -0,0 +1,26 @@ | |||||
| upstream hello_django { | |||||
| server web:8000; | |||||
| } | |||||
| server { | |||||
| listen 80; | |||||
| location / { | |||||
| proxy_pass http://hello_django; | |||||
| proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | |||||
| proxy_set_header Host $host; | |||||
| proxy_redirect off; | |||||
| client_max_body_size 100M; | |||||
| } | |||||
| location /static/ { | |||||
| alias /home/app/web/staticfiles/; | |||||
| } | |||||
| location /media/ { | |||||
| alias /home/app/web/mediafiles/; | |||||
| } | |||||
| } | |||||