From 88d44c1ab0a9d2d56dba2343cd74097f2916c994 Mon Sep 17 00:00:00 2001 From: Ismael Cedano Date: Fri, 23 May 2025 21:47:35 -0400 Subject: [PATCH 1/5] init app setup --- .env | 16 +++++++----- .gitignore | 3 ++- Dockerfile | 53 ++++++++++++++++++++++++++++++++++++++++ azureproject/settings.py | 32 ++++++++++++++---------- docker-compose.yaml | 43 ++++++++++++++++++++++++++++++++ requirements.txt | 3 +++ 6 files changed, 130 insertions(+), 20 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-compose.yaml diff --git a/.env b/.env index 7e893174..3e0078b5 100644 --- a/.env +++ b/.env @@ -1,6 +1,10 @@ -DBNAME=app -DBHOST=localhost -DBUSER=app_user -DBPASS=app_password -CACHELOCATION=redis://redis:6379/0 -SECRET_KEY=secret_key +DJANGO_SECRET_KEY=your_secret_key +DEBUG=True +DJANGO_LOGLEVEL=info +DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1,0.0.0.0 +DATABASE_ENGINE=postgresql_psycopg2 +DATABASE_NAME=dockerdjango +DATABASE_USERNAME=dbuser +DATABASE_PASSWORD=dbpassword +DATABASE_HOST=db +DATABASE_PORT=5432 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 9b957b1b..92a37e26 100644 --- a/.gitignore +++ b/.gitignore @@ -128,4 +128,5 @@ dmypy.json # Pyre type checker .pyre/ -.azure \ No newline at end of file +.azure +.env \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..04ddccf2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,53 @@ +# Stage 1: Base build stage +FROM python:3.13-slim AS builder + +# Create the app directory +RUN mkdir /app + +# Set the working directory +WORKDIR /app + +# Set environment variables to optimize Python +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 + +# Upgrade pip and install dependencies +RUN pip install --upgrade pip + +# Copy the requirements file first (better caching) +COPY requirements.txt /app/ + +# Install Python dependencies +RUN pip install --no-cache-dir -r requirements.txt + +# Stage 2: Production stage +FROM python:3.13-slim + +RUN useradd -m -r appuser && \ + mkdir /app && \ + chown -R appuser /app + +# Copy the Python dependencies from the builder stage +COPY --from=builder /usr/local/lib/python3.13/site-packages/ /usr/local/lib/python3.13/site-packages/ +COPY --from=builder /usr/local/bin/ /usr/local/bin/ + +# Set the working directory +WORKDIR /app + +# Copy application code +COPY --chown=appuser:appuser . . + +RUN python manage.py collectstatic --noinput + +# Set environment variables to optimize Python +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 + +# Switch to non-root user +USER appuser + +# Expose the application port +EXPOSE 8000 + +# Start the application using Gunicorn +CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "azureproject.wsgi:application"] diff --git a/azureproject/settings.py b/azureproject/settings.py index 5d890707..744af36c 100644 --- a/azureproject/settings.py +++ b/azureproject/settings.py @@ -21,12 +21,12 @@ # See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = os.getenv('SECRET_KEY') +SECRET_KEY = os.getenv('DJANGO_SECRET_KEY') # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True +DEBUG = bool(os.environ.get("DEBUG", default=0)) -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS","127.0.0.1").split(",") if 'CODESPACE_NAME' in os.environ: CSRF_TRUSTED_ORIGINS = [f'https://{os.getenv("CODESPACE_NAME")}-8000.{os.getenv("GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN")}'] @@ -51,6 +51,7 @@ 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'whitenoise.middleware.WhiteNoiseMiddleware', ] SESSION_ENGINE = "django.contrib.sessions.backends.cache" @@ -92,14 +93,17 @@ # Configure Postgres database for local development # Set these environment variables in the .env file for this project. DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': os.environ.get('DBNAME'), - 'HOST': os.environ.get('DBHOST'), - 'USER': os.environ.get('DBUSER'), - 'PASSWORD': os.environ.get('DBPASS'), - } -} + 'default': { + 'ENGINE': 'django.db.backends.{}'.format( + os.getenv('DATABASE_ENGINE', 'sqlite3') + ), + 'NAME': os.getenv('DATABASE_NAME', 'polls'), + 'USER': os.getenv('DATABASE_USERNAME', 'myprojectuser'), + 'PASSWORD': os.getenv('DATABASE_PASSWORD', 'password'), + 'HOST': os.getenv('DATABASE_HOST', '127.0.0.1'), + 'PORT': os.getenv('DATABASE_PORT', 5432), + } + } # Password validation @@ -123,7 +127,7 @@ CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", - "LOCATION": os.environ.get('CACHELOCATION'), + "LOCATION": f"redis://{os.environ.get('REDIS_HOST', 'redis')}:{os.environ.get('REDIS_PORT', 6379)}/1", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", }, @@ -145,8 +149,10 @@ # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/4.0/howto/static-files/ +STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') STATICFILES_DIRS = (str(BASE_DIR.joinpath('static')),) -STATIC_URL = 'static/' +STATIC_URL = '/static/' +STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' # Default primary key field type # https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 00000000..39e9d153 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,43 @@ +services: + db: + image: postgres:17 + environment: + POSTGRES_DB: ${DATABASE_NAME} + POSTGRES_USER: ${DATABASE_USERNAME} + POSTGRES_PASSWORD: ${DATABASE_PASSWORD} + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + env_file: + - .env + + redis: + image: "redis:latest" + + django-web: + build: . + container_name: django-docker + ports: + - "8000:8000" + depends_on: + - db + - redis + environment: + DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY} + DEBUG: ${DEBUG} + DJANGO_LOGLEVEL: ${DJANGO_LOGLEVEL} + DJANGO_ALLOWED_HOSTS: ${DJANGO_ALLOWED_HOSTS} + DATABASE_ENGINE: ${DATABASE_ENGINE} + DATABASE_NAME: ${DATABASE_NAME} + DATABASE_USERNAME: ${DATABASE_USERNAME} + + DATABASE_PASSWORD: ${DATABASE_PASSWORD} + DATABASE_HOST: ${DATABASE_HOST} + DATABASE_PORT: ${DATABASE_PORT} + REDIS_HOST: redis + REDIS_PORT: 6379 + env_file: + - .env +volumes: + postgres_data: \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index c17108d2..b31f0b8c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,6 @@ psycopg2-binary==2.9.10 python-dotenv==1.0.1 whitenoise==6.9.0 django-redis==5.4.0 +asgiref==3.8.1 +sqlparse==0.5.2 +gunicorn==23.0.0 From 27e648d63dae1ce6c551a520cbb0e9b7477b2e3c Mon Sep 17 00:00:00 2001 From: Ismael Cedano Date: Wed, 28 May 2025 20:24:17 -0400 Subject: [PATCH 2/5] feat: add workflow --- .github/workflows/start_msdocs-django.yml | 80 +++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 .github/workflows/start_msdocs-django.yml diff --git a/.github/workflows/start_msdocs-django.yml b/.github/workflows/start_msdocs-django.yml new file mode 100644 index 00000000..5a1358a7 --- /dev/null +++ b/.github/workflows/start_msdocs-django.yml @@ -0,0 +1,80 @@ +# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# More GitHub Actions for Azure: https://github.com/Azure/actions +# More info on Python, GitHub Actions, and Azure App Service: https://aka.ms/python-webapps-actions + +name: Build and deploy Python app to Azure Web App - msdocs-django + +on: + push: + branches: + - start + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read #This is required for actions/checkout + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python version + uses: actions/setup-python@v5 + with: + python-version: '3.13' + + - name: Create and start virtual environment + run: | + python -m venv venv + source venv/bin/activate + + - name: Install dependencies + run: pip install -r requirements.txt + + # Optional: Add step to run tests here (PyTest, Django test suites, etc.) + + - name: Zip artifact for deployment + run: zip release.zip ./* -r + + - name: Upload artifact for deployment jobs + uses: actions/upload-artifact@v4 + with: + name: python-app + path: | + release.zip + !venv/ + + deploy: + runs-on: ubuntu-latest + needs: build + environment: + name: 'Production' + url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} + permissions: + id-token: write #This is required for requesting the JWT + contents: read #This is required for actions/checkout + + steps: + - name: Download artifact from build job + uses: actions/download-artifact@v4 + with: + name: python-app + + - name: Unzip artifact for deployment + run: unzip release.zip + + + - name: Login to Azure + uses: azure/login@v2 + with: + client-id: ${{ secrets.__clientidsecretname__ }} + tenant-id: ${{ secrets.__tenantidsecretname__ }} + subscription-id: ${{ secrets.__subscriptionidsecretname__ }} + + - name: 'Deploy to Azure Web App' + uses: azure/webapps-deploy@v3 + id: deploy-to-webapp + with: + app-name: 'msdocs-django' + slot-name: 'Production' \ No newline at end of file From 24180de769b0378625c29da066f01913e04416ea Mon Sep 17 00:00:00 2001 From: Ismael Osvaldo Cedano Vargas Date: Wed, 28 May 2025 20:25:26 -0400 Subject: [PATCH 3/5] Add or update the Azure App Service build and deployment workflow config --- .github/workflows/start_msdocs-django.yml | 143 +++++++++++----------- 1 file changed, 72 insertions(+), 71 deletions(-) diff --git a/.github/workflows/start_msdocs-django.yml b/.github/workflows/start_msdocs-django.yml index 5a1358a7..c86e50cf 100644 --- a/.github/workflows/start_msdocs-django.yml +++ b/.github/workflows/start_msdocs-django.yml @@ -1,80 +1,81 @@ -# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy -# More GitHub Actions for Azure: https://github.com/Azure/actions -# More info on Python, GitHub Actions, and Azure App Service: https://aka.ms/python-webapps-actions - -name: Build and deploy Python app to Azure Web App - msdocs-django - -on: - push: - branches: - - start - workflow_dispatch: - -jobs: - build: - runs-on: ubuntu-latest - permissions: - contents: read #This is required for actions/checkout - - steps: - - uses: actions/checkout@v4 - - - name: Set up Python version - uses: actions/setup-python@v5 - with: - python-version: '3.13' - - - name: Create and start virtual environment - run: | - python -m venv venv - source venv/bin/activate - - - name: Install dependencies - run: pip install -r requirements.txt - - # Optional: Add step to run tests here (PyTest, Django test suites, etc.) - - - name: Zip artifact for deployment - run: zip release.zip ./* -r - - - name: Upload artifact for deployment jobs - uses: actions/upload-artifact@v4 - with: - name: python-app - path: | - release.zip - !venv/ - - deploy: - runs-on: ubuntu-latest - needs: build +# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# More GitHub Actions for Azure: https://github.com/Azure/actions +# More info on Python, GitHub Actions, and Azure App Service: https://aka.ms/python-webapps-actions + +name: Build and deploy Python app to Azure Web App - msdocs-django + +on: + push: + branches: + - start + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read #This is required for actions/checkout + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python version + uses: actions/setup-python@v5 + with: + python-version: '3.13' + + - name: Create and start virtual environment + run: | + python -m venv venv + source venv/bin/activate + + - name: Install dependencies + run: pip install -r requirements.txt + + # Optional: Add step to run tests here (PyTest, Django test suites, etc.) + + - name: Zip artifact for deployment + run: zip release.zip ./* -r + + - name: Upload artifact for deployment jobs + uses: actions/upload-artifact@v4 + with: + name: python-app + path: | + release.zip + !venv/ + + deploy: + runs-on: ubuntu-latest + needs: build environment: name: 'Production' - url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} + url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} permissions: id-token: write #This is required for requesting the JWT contents: read #This is required for actions/checkout - - steps: - - name: Download artifact from build job - uses: actions/download-artifact@v4 - with: - name: python-app - - - name: Unzip artifact for deployment - run: unzip release.zip - + + steps: + - name: Download artifact from build job + uses: actions/download-artifact@v4 + with: + name: python-app + + - name: Unzip artifact for deployment + run: unzip release.zip + - name: Login to Azure uses: azure/login@v2 with: - client-id: ${{ secrets.__clientidsecretname__ }} - tenant-id: ${{ secrets.__tenantidsecretname__ }} - subscription-id: ${{ secrets.__subscriptionidsecretname__ }} - - - name: 'Deploy to Azure Web App' - uses: azure/webapps-deploy@v3 - id: deploy-to-webapp - with: - app-name: 'msdocs-django' - slot-name: 'Production' \ No newline at end of file + client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_9BA1861B2903462589D964551B5B6FF3 }} + tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_F39E2916EAF1432388721E2E80E7E0F2 }} + subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_4063657E9CEA484CB505C2B6F9037DFE }} + + - name: 'Deploy to Azure Web App' + uses: azure/webapps-deploy@v3 + id: deploy-to-webapp + with: + app-name: 'msdocs-django' + slot-name: 'Production' + \ No newline at end of file From bdcf391371f6089e0a32740116c60473bd6d654e Mon Sep 17 00:00:00 2001 From: Ismael Cedano Date: Wed, 28 May 2025 20:37:35 -0400 Subject: [PATCH 4/5] chore: remote --- .env | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 .env diff --git a/.env b/.env deleted file mode 100644 index 3e0078b5..00000000 --- a/.env +++ /dev/null @@ -1,10 +0,0 @@ -DJANGO_SECRET_KEY=your_secret_key -DEBUG=True -DJANGO_LOGLEVEL=info -DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1,0.0.0.0 -DATABASE_ENGINE=postgresql_psycopg2 -DATABASE_NAME=dockerdjango -DATABASE_USERNAME=dbuser -DATABASE_PASSWORD=dbpassword -DATABASE_HOST=db -DATABASE_PORT=5432 \ No newline at end of file From a9075457e495fc367f2b25257b3fcb89ec1dc606 Mon Sep 17 00:00:00 2001 From: Ismael Cedano Date: Wed, 28 May 2025 20:42:55 -0400 Subject: [PATCH 5/5] chore: update prod settings --- azureproject/production.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/azureproject/production.py b/azureproject/production.py index 76b6e1f0..0f89bc06 100644 --- a/azureproject/production.py +++ b/azureproject/production.py @@ -29,10 +29,10 @@ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', - 'NAME': os.environ['AZURE_POSTGRESQL_NAME'], - 'HOST': os.environ['AZURE_POSTGRESQL_HOST'], - 'USER': os.environ['AZURE_POSTGRESQL_USER'], - 'PASSWORD': os.environ['AZURE_POSTGRESQL_PASSWORD'], + 'NAME': os.environ['DATABASE_NAME'], + 'HOST': os.environ['DATABASE_HOST'], + 'USER': os.environ['DATABASE_USERNAME'], + 'PASSWORD': os.environ['DATABASE_PASSWORD'], } }