نحوه Dockerize کردن Django و Postgre و Nginx و LetsEncrypt - برای محیط Prod
در این پست به نحوه داکرایز کردن پروژه های جنگو برای فاز Production خواهیم پرداخت و در ادامه به راه کار های موجود و یک قالب آماده برای پیاده سازی پروژه های جنگو را به شما معرفی خواهیم کرد. در نظر داشته باشید که برای درک این موضوع نیاز به یادگیری داکر خواهید داشت و می بایست تا حد خیلی خوبی به ساختار ایجاد Dockerfile و همچنین استفاده از docker-compose اشراف داشته باشید.
پیاده سازی پروژه های جنگو با قالب آماده من
در قسمت قبل به نحوه پیاده سازی پروژه های جنگو در فاز stage اشاره شد و مدل پیاده سازی آن را با هم تجربه کردیم، اما در این قسمت می خواهیم با اضافه کردن تنظیمات ssl سرویس خود را امن کنیم. در کل می توان گفت بیشترین نسبت تغییرات در بخش nginx و settings جنگو خواهد بود و تغییر خاصی در فایل ها نیست و بیشتر مروری بر مدل خواهیم داشت.
فرض بر این است که پروژه جنگو شما آماده برای پیاده سازیست و ما می خواهیم مسیر و نحوه پیاده سازی را با یکدیگر انجام دهیم. برای این کار پروژه ساده زیر را در نظر بگیرید.
│ .gitattributes
│ LICENSE
│ README.md
│ .gitignore
│ requirements.txt
└─── core
├─── staticfiles
├─── static
├─── media
├─── manage.py
└─── core
│ asgi.py
│ error_views.py
│ settings.py
│ urls.py
│ wsgi.py
└─── __init__.py
ساخت requirements
پس از ایجاد تنظیمات بالا نیاز است که برای پروژه جنگو خود فایل requirements.txt را ایجاد و تمام ماژول هایی که قرار است استفاده کنیم را درج نماییم. که نمونه زیر حاوی ماژول gunicorn است.
# requirements.txt
# general modules
django >3.2,<3.3
# env controls
python-decouple
# deployment module
gunicorn
# database client
psycopg2-binary
ساخت Dockerfile
بخش تنظیمات نرم افزار به پایان رسیده و حال می بایست به ساخت Dockerfile و docker-compose بپردازیم. در ساخت Dockerfile کافیست که به شکل زیر عمل نمایید. و تنظیمات لازم را برای Dockerfile مربوط به جنگو در نظر بگیرید.
# dockefiles/prod/django/Dockerfile
# pull official base image
FROM python:3.10-alpine as base
LABEL maintainer="bigdeli.ali3@gmail.com"
RUN apk add --update --virtual .build-deps \
build-base \
postgresql-dev \
python3-dev \
libpq
# install dependencies
COPY ./requirements.txt .
RUN pip install --upgrade pip && pip install -r requirements.txt
# Now multistage build
FROM python:3.10-alpine
RUN apk add libpq
COPY --from=base /usr/local/lib/python3.9/site-packages/ /usr/local/lib/python3.9/site-packages/
COPY --from=base /usr/local/bin/ /usr/local/bin/
# set work directory
WORKDIR /usr/src/app
# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# copy project
COPY ./core .
در فایل بالا برای پایین نگه داشتن حجم و سطح دسترسی کاربری python با استفاده از alpine-image اقدام به ساخت کانتینر می کنیم که در دو مرحله صورت میگیرد. مرحله اول نصب ماژول ها و آماده سازی پکیج ها خواهد بود ( در صورتی که بخوایهد از این dockerfile برای ساخت کانتینر های worker ویا beater استفاده نمایید حجم کمتری اشغال می شود) و در مرحله بعدی سورس اصلی که قرار است پیاده سازی بر روی آن صورت بگیرد ساخته خواهد شد.
سپس برای nginx نیاز است که dockerfile دیگری ایجاد شود تا بتوان تنظیماتی که در زیر ایجاد می کنید را به آن منتقل و در زمان اجرا در دسترس سرویس قرار داد.
# dockerfiles/prod/nginx/Dockerfile
FROM nginx:alpine
COPY ./config/* /etc/nginx/
COPY ./entrypoint.sh /entrypoint.sh
USER root
RUN apk add --no-cache openssl bash
RUN chmod +x /entrypoint.sh
CMD ["/entrypoint.sh"]
دستورات مربوط به entry point را در همان پوشه قرار می دهیم:
# dockerfiles/prod/nginx/entrypoint.sh
#!/bin/bash
set -e
echo "Checking for dhparams.pem"
if [ ! -f "/vol/proxy/ssl-dhparams.pem" ]; then
echo "dhparams.pem does not exist - creating it"
openssl dhparam -out /vol/proxy/ssl-dhparams.pem 1024
fi
echo "Checking for fullchain.pem"
if [ ! -f "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" ]; then
echo "No SSL cert, enabling HTTP only..."
envsubst '\$DOMAIN' < /etc/nginx/default.conf.tpl > /etc/nginx/conf.d/default.conf
else
echo "SSL cert exists, enabling HTTPS..."
envsubst '\$DOMAIN' < /etc/nginx/default-ssl.conf.tpl > /etc/nginx/conf.d/default.conf
fi
nginx-debug -g 'daemon off;'
ساختار بالا برای تصمیم گیری این است که سرویس شما در حال حاضر دارای ssl است یا خیر و درصورت عدم پیدا کردن فایل مورد نظر سایت را بدون در نظر گرفتن موارد امنیتی و میشه گفت برای اولین بار به حالت اجرا در میاورد.
دلیل این عمل این است که برای اینکه سرویس دریافت گواهی بتواند عمل کد نیاز دارد که سرویس فعلی در حالت اجرا قرار گرفته باشد.
حال نیاز به فایل تنظیمات nginx است که می بایست دو فایل ایجاد شوید. یکی برای تنظیمات پایه تا بدون در نظر گرفتن ssl آن را اجرا نماید و دیگری برای اجرا با در نظر گرفتن گواهی ssl:
# dockerfiles/prod/nginx/config/default.conf.tpl
server {
listen 80;
server_name ${DOMAIN} www.${DOMAIN};
# server logs
access_log /var/log/nginx/access_log.log;
error_log /var/log/nginx/error_log.log;
location /.well-known/acme-challenge/ {
root /vol/www/;
}
location / {
proxy_redirect off;
proxy_pass http://backend:8000;
}
}
و تنظیمات مبتنی بر گواهی ssl
# dockerfiles/prod/nginx/config/default-ssl.conf.tpl
server {
listen 80;
server_name ${DOMAIN} www.${DOMAIN};
# server logs
access_log /var/log/nginx/access_log.log;
error_log /var/log/nginx/error_log.log;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://${DOMAIN}$request_uri;
}
}
server {
listen 443 ssl;
# server names
server_name ${DOMAIN};
# slow connections timeout
# client_body_timeout 5s;
# client_header_timeout 5s;
# rate limiting
# limit_req zone=mylimit burst=20 delay=20;
# limit_req_status 429;
# Let's Encrypt parameters
ssl_certificate /etc/letsencrypt/live/${DOMAIN}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${DOMAIN}/privkey.pem;
# keepalive_timeout 70;
# ssl configs which has been given from cert bot
ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
ssl_dhparam /vol/proxy/ssl-dhparams.pem;
# charset config
charset utf-8;
# max upload size
client_max_body_size 10M; # adjust to taste
server_tokens off;
# Secruity headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
add_header Content-Security-Policy "default-src 'self'; img-src * data:; font-src 'self' data:; frame-src 'self' https://www.google.com/; connect-src 'self' ;style-src 'self' https://cdn.jsdelivr.net ;script-src 'self' https://cdn.jsdelivr.net ; object-src 'self' ;frame-ancestors 'self'; form-action 'self'; base-uri 'self';";
add_header X-XSS-Protection "1; mode=block";
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options nosniff;
add_header Referrer-Policy "strict-origin";
add_header Permissions-Policy "geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=()";
add_header Set-Cookie "Path=/; HttpOnly; Secure; SameSite=strict;";
add_header Cache-Control "private, no-cache, no-store, must-revalidate, max-age=0" always;
# static files directory
location /static/ {
autoindex on;
alias /home/app/static/;
}
# media files directory
location /media/ {
autoindex on;
alias /home/app/media/;
}
location / {
# proxy_pass_request_headers on;
# proxy_buffering on;
# proxy_buffers 8 24k;
# proxy_buffer_size 2k;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header REMOTE_ADDR $remote_addr;
proxy_set_header X-Url-Scheme $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header User-Agent $http_user_agent;
proxy_pass http://backend:8000;
}
}
اما برای انجام عملیات دریافت گواهی نیاز به سرویس Certbot است که بتوانید از طریف آن گواهی ssl رایگان خود را دریافت نمایید.
Certbot یک ابزار رایگان و باز منبع باز برای دریافت و نصب گواهینامه SSL رایگان از Let's Encrypt است. گواهینامه SSL یک فایل رمزگذاری شده است که به وب سرور شما اجازه می دهد که با مرورگرهای کاربران به صورت امن ارتباط برقرار کند. این گواهینامه شامل یک کلید خصوصی و یک کلید عمومی است که به وسیله آن، اطلاعات بین مرورگر کاربر و سرور شما رمزگذاری می شود.Certbot ابزاری است که به صورت خودکار این گواهینامه ها را دریافت و نصب می کند و در صورت نیاز به تجدید آن ها نیز به صورت خودکار این کار را انجام می دهد. با نصب و استفاده از Certbot می توانید وب سایت خود را به راحتی از HTTP به HTTPS تغییر دهید و ارتباط بین کاربران و سرور خود را بهبود بخشید. Certbot با استفاده از پروتکل ACME، امکان دریافت گواهینامه SSL رایگان از Let's Encrypt را فراهم می کند. این گواهینامه ها برای 90 روز معتبر بوده و Certbot به صورت خودکار این گواهینامه ها را تمدید خواهد کرد، بنابراین نیازی به نگرانی برای تجدید گواهینامه ها نیست. Certbot قابلیت اجرا در تمام سیستم عامل ها و وب سرورهای متداول را داراست و به صورت پیشفرض بر روی بسیاری از سیستم عامل ها موجود است.
# dockerfiles/prod/certbot/Dockerfile
FROM certbot/certbot:v1.27.0
COPY certify-init.sh /opt/
RUN chmod +x /opt/certify-init.sh
ENTRYPOINT []
CMD ["certbot", "renew"]
و فایل اجرای دستورات certbot
# dockerfiles/prod/certbot/certify-init.sh
#!/bin/sh
# Waits for proxy to be available, then gets the first certificate.
set -e
until nc -z nginx 80; do
echo "Waiting for proxy..."
sleep 5s & wait ${!}
done
echo "Getting certificate..."
certbot certonly \
--webroot \
-w "/vol/www/" \
-d "$DOMAIN" \
--email $EMAIL \
--force-renewal \
--rsa-key-size 4096 \
--agree-tos \
--noninteractive
تا به اینجا تمام بخش های اساسی عملکرد سرویس ها پیاده سازی شده اند به جز یک بخش که تنظیمات امنیتی مربوط به جنگو را شامل می شود:
# core/core/settings.py
# security configs for production
if config("USE_SSL_CONFIG", cast=bool, default=False):
# Https settings
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = True
# HSTS settings
SECURE_HSTS_SECONDS = 31536000 # 1 year
SECURE_HSTS_PRELOAD = True
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
# more security settings
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_BROWSER_XSS_FILTER = True
X_FRAME_OPTIONS = "SAMEORIGIN"
SECURE_REFERRER_POLICY = "strict-origin"
USE_X_FORWARDED_HOST = True
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
و در نهایت برای اجرای تمام سرویس ها نیاز به یک docker-compose است:
version: "3.9"
services:
db:
container_name: db
image: postgres:alpine
volumes:
- postgres_data:/var/lib/postgresql/data
env_file:
- ./envs/prod/db/.env
restart: always
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U postgres']
interval: 10s
timeout: 5s
retries: 5
backend:
build:
context: .
dockerfile: dockerfiles/prod/django/Dockerfile
container_name: backend
command: sh -c "python3 manage.py check_database && \
python3 manage.py makemigrations --noinput && \
python3 manage.py migrate --noinput && \
python3 manage.py collectstatic --noinput && \
gunicorn --bind 0.0.0.0:8000 core.wsgi:application"
volumes:
- static_volume:/usr/src/app/static
- media_volume:/usr/src/app/media
expose:
- "8000"
env_file:
- ./envs/prod/django/.env
depends_on:
- db
certbot:
build:
context: ./dockerfiles/prod/certbot/
command: echo "Skipping..."
container_name: certbot
env_file:
- ./envs/prod/nginx/.env
volumes:
- certbot_www_volume:/vol/www/
- certbot_certs_volume:/etc/letsencrypt/
depends_on:
- nginx
nginx:
container_name: nginx
build:
context: ./dockerfiles/prod/nginx/
restart: always
env_file:
- ./envs/prod/nginx/.env
ports:
- 443:443
- 80:80
volumes:
- static_volume:/home/app/static
- media_volume:/home/app/media
- certbot_www_volume:/vol/www/
- proxy_dhparams:/vol/proxy
- certbot_certs_volume:/etc/letsencrypt/
depends_on:
- backend
volumes:
postgres_data:
static_volume:
media_volume:
certbot_www_volume:
certbot_certs_volume:
proxy_dhparams:
برای اجرای سرویس مربوطه کافیست که طبق دستورات زیر عمل نمایید:
docker compose -f docker-compose-prod.yml run --rm certbot /opt/certify-init.sh
ابتدا دستور بالا را برای آماده سازی و گرفتن گواهی اجرا می کنید و سپس تمام سرویس را پایین میاورد و مجدد راه اندازی می کنید. و تمام
docker compose -f docker-compose-prod.yml down
# حتما باید سرویس را پایین بیاورید
docker compose -f docker-compose-prod.yml up
ثبت دیدگاه
دیدگاه کاربران (0)
دوره های من در مکتبخونه
آموزش طراحی فروشگاه با جنگو
- سطح: پیشرفته 5
آموزش جنگو پیشرفته
- سطح: پیشرفته 4.9
آموزش جنگو Django
- سطح: مقدماتی 4.6
آموزش شیءگرایی در پایتون
- سطح: متوسط 4.3
آموزش میکروپایتون در اینترنت اشیا
- سطح: متوسط 3.8
آخرین پست ها
انتقال پروژه Django از پلتفرم Liara به پلتفرم Hamravesh
- خوب رسیدیم به بخش ترسناکی که برای خیلی ها می تونه کابوس باشه اونم انتقال پروژه از یک پلتفرم به پلتفرم دیگه، اما با این ویدئو مسائل رو براتون خیلی…
- django 1403/05/28
پیاده سازی پروژه Django Channels (ASGI/Websocket) بر روی پلتفرم Hamravesh
- توی این ویدئو درباره نحوه پیاده سازی پروژه های ASGI در جنگو با استفاده از ماژول Channels و Daphne صحبت خواهم کرد و یک نمونه پروژه برای تست رو در…
- django 1403/05/19
پیاده سازی پروژه django بر روی پلتفرم Caprover به همراه Media
- توی این ویدئو نحوه پیاده سازی پروژه جنگو رو به صورت کامل بر روی پلتفرم caprover شرح دادم به طوری که یک پروژه قالب رو آماده سازی کردم و در…
- django 1403/05/15
آخرین دوره ها
آموزش برنامه نویسی Async در پایتون
- 0 61 دانشجو
آموزش ساخت ربات تلگرام با پایتون
-
500000 35000026 دانشجو
آموزش Arduino
- 0 135 دانشجو