Environment Variables متغیرهایی هستند که میتوانند در operating environment یک پروژه, در زمان اجرا برخلاف هارد کدینگ داخل کدبیس بارگذاری شوند. آنها بخشی جدایی ناپذیر از اصل محبوب Twelve-Factor App Design و Django best practice در نظر گرفته میشوند زیرا آنها سطح وسیعتر امنیت و تنظیمات local/production سادهتر را امکان پذیر میکنند.
چرا امنیت بیشتر؟ زیرا میتوانیم اطلاعات محرمانه(اطلاعات پایگاه داده, کلید های API و ...) را جدا از کدبیس پایه ذخیره کنیم. این ایدهی خوبیست چون استفاده از ورژن کنترل(version control system) مانند git, به این معناست که فقط یک commit بد برای افزودن credentials برای همیشه باقی میماند. این بدان معناست که هر کسی به کدبیس دسترسی داشته باشد کنترل کامل بهروی پروژه دارد که این بسیار خطرناک است. بهتر است دسترسی افراد به برنامه محدود شود و متغیرهایمحیطی راهی برای این کار ارائه میکنند.
مزیت دوم این است که متغیرهای محیطی, جابهجایی بین محیط های داخلی و عملی کد را آسانتر میکند. همانطور که خواهیم دید تنظیماتی وجود دارد که جنگو بهطور پیشفرض از آن برای توسعه آسانتر استفاده میکند. اما زمانی که همان پروژه برای محیط عملی آماده میشود باید تغییراتی را اعمال کرد.
در پایتون روش های مختلفی برای کار با متغیرهای محیطی وجود دارد اما برای این پروژه از پکیج environs استفاده میکنیم که شامل گزینه مخصوص برای جنگو است که پکیج های اضافی را همراه خود نصب میکند که در تنظیمات به ما کمک میکند.
در خط فرمان environs[django]
را نصب کنید. توجه کنید که اگر از Zsh به عنوان terminal shell استفاده میکنید احتمالا باید از نقلقول''
در اطراف اسم بسته استفاده کنید. پسpipenv install environs[django]==8.0.0
را اجرا کنید. همچنین نیاز داریم Docker container را با بسته های جدید بازسازی کنیم.
Command Line
$ docker-compose exec web pipenv install 'environs[django]==8.0.0'
$ docker-compose down
$ docker-compose up -d --build
در فایل config/settings.py
سه خط imports برای اضافه کردن در بالای فایل در زیر import path وجود دارد.
Code
# config/settings.py
from pathlib import Path
from environs import Env # new
env = Env() # new
env.read_env() # new
برای اولین environment variable خود SECRET_KEY را تنظیم میکنیم, رشتهای که به طور تصادفی تولید شده و برای cryptographic signing استفاده میشود و هر زمان که دستور SECRET_KEY
اجرا شود ایجاد میشود. بسیار مهم است که SECRET_KEY مخفی نگه داشته شود. در فایل config/settings.py
من مقدار زیر را دارد:
Code
# config/settings.py
SECRET_KEY = ')*_s#exg*#w+#-xt=vu8b010%%a&p@4edwyj0=(nqq90b9a8*n'
توجه داشته باشید که نقل قول های اطراف SECRET_KEY باعث میشود که تبدیل به رشته پایتونی شود. در واقع آنها بخشی از SECRET_KEY نیستند که به آسانی اشتباه گرفته میشوند.
دو گام برای جابهجایی environment variables وجود دارد:
- Environment Variable را به فایل
docker-compose.yml
اضافه کنید. config/settings.py
را برای اشاره به متغیر بروز کنید.
در فایل docker-compose.yml
بخشی را با نام environment
در زیر web service
اضافه کنید. این متغیری خواهد بود که آن را DJANGO_SECRET_KEY
با مقدار SECRET_KEY
موجود خود مینامیم. فایل آپدیت شده به این شکل است:
docker-compose.yml
# config/settings.py
version: '3.8'
services:
web:
build: .
command: python /code/manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- 8000:8000
depends_on:
- db
environment:
- "DJANGO_SECRET_KEY=)*_s#exg*#w+#-xt=vu8b010%%a&p@4edwyj0=(nqq90b9a8*n"
db:
image: postgres:11
volumes:
- postgres_data:/var/lib/postgresql/data/
environment:
- "POSTGRES_HOST_AUTH_METHOD=trust"
volumes:
postgres_data:
توجه کنید اگر SECRET_KEY
شما دارای علامت دلار $
باشد باید یک علامت دلار دیگر اضافه کنید $$
. در غیر اینصورت با ارور مواجه میشوید!
اطلاعات بیشتر در: handles variable substitution
قدم دوم آپدیت کردن تنظیمات SECRET_KEY
در config/settings.py
است.
Code
# config/settings.py
SECRET_KEY = env("DJANGO_SECRET_KEY")
اگر وبسایت را رفرش کنید, خواهید دید همه چیز مانند قبل کار میکنند که همان چیزیست که میخواهیم. اگر به دلایلی SECRET_KEY
به درستی اجرا نشده بود, اروری خواهیم دید با عنوان, جنگو برای کار کردن به آن نیاز دارد.
خوانندگان ریزبین ممکن است متوجه شوند, با اینکه از environment variable استفاده میکنیم, مقدار SECRET_KEY
در سورسکد هنوز قابل مشاهده است. همانطور که صرفا به docker-compose.yml
منتقل شد. درست است! با این حال, وقتی وبسایت خود برای فاز نهایی آماده میکنیم فایل جداگانهای را برای اهداف عملی ایجاد خواهیم کرد(docker-compose-production.yml
)و از طریق فایل .env
آن را در محیط عملی بارگذاری خواهیم کرد که توسط گیت ردیابی نمیشود.
هر چند, در حالحاضر هدف این فصل استفاده از environment variables به صورت لوکال و برای مقادیری است که باید به طور حتم مخفی باشند و یا در محیط عملی تغییر کنند.
همانطور که چکلیست دیپلوی جنگو اشاره میکند, تنظیماتی وجود دارد که باید قبل از دیپلوی امن سایت آپدیت شوند. اصلی ترین بخشها DEBUG و ALLOWED_HOSTS هستند.
وقتی DEBUG
روی True
تنظیم شده باشد, جنگو پیامی طولانی و با جزییات از باگ را در مواقع وقوع یک ارور نشان میدهد. برای مثال از صفحهای که وجود ندارد دیدن کنید, مانند /debug
.
این برای اهداف ما به عنوان توسعهدهنده عالی است, اما همچنین یک نقشه راه برای یک هکر در محیط عملی است. وقتی DEBUG
روی False
تنظیم باشد, لازم است ALLOWED_HOSTS
را تغییر دهید که هاست و دامنههای خاصی را که میتوانند به وبسایت دسترسی پیدا کنند را کنترل میکند. دو پورت محلی (localhost
و 127.0.0.1
) و همچنین .herokuapp.com
را اضافه خواهیم کرد که توسط Heroku برای وبسایت ما استفاده میشود.
فایل config/settings.py
را با دو خط جدید آپدیت میکنیم:
Code
# config/settings.py
DEBUG = False # new
ALLOWED_HOSTS = ['.herokuapp.com', 'localhost', '127.0.0.1'] # new
بعد صفحه وب را رفرش کنید.
این همان رفتاری است که از سایت میخواهیم: بدون اطلاعات, فقط یک پیام عمومی. زمانی که وبسایت را دیپلوی میکنیم, از راهی بخصوص برای جابهجایی بین تنظیمات استفاده میکنیم, اما حال DEBUG
را به متیر محیطی DJANGO_DEBUG
تغییر دهید.
Code
# config/settings.py
DEBUG = env.bool("DJANGO_DEBUG")
سپس بروزرسانی docker-compose.yml
را انجام دهید تا DJANGO_DEBUG
روی True
تنظیم شود.
docker-compose.yml
version: '3.8'
services:
web:
build: .
command: python /code/manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- 8000:8000
depends_on:
- db
environment:
- "DJANGO_SECRET_KEY=)*_s#exg*#w+#-xt=vu8b010%%a&p@4edwyj0=(nqq90b9a8*n"
- "DJANGO_DEBUG=True"
db:
image: postgres:11
volumes:
- postgres_data:/var/lib/postgresql/data/
environment:
- "POSTGRES_HOST_AUTH_METHOD=trust"
volumes:
postgres_data:
پس از تغییرات وبسایت را رفرش کنید و مانند قبل کار خواهد کرد.
وقتی قبلتر True
را نصب کردیم, Django “goodies” شامل پکیج djdatabase-url بود که تمام پیکربندیهای مورد نیاز دیتابیس را شامل میشود, SQLite یا PostgreSQL. این بعدا در محیط عملی مفید خواهد بود.
حال میتوانیم آن را با یک مقدار پیشفرض بهصورت لوکال از PostgreSQL استفاده کنیم. پیکربندی DATABASES
موجود را با موارد زیر آپدیت کنید:
Code
# config/settings.py
DATABASES = {
"default": env.dj_db_url("DATABASE_URL",
default="postgres:https://postgres@db/postgres")
}
هنگام دیپلوی, متغیر محیطی DATABASE_URL
توسط Heroku ایجاد میشود.
وبسایت را رفرش کنید تا از کارکرد درست همهچیز اطمینان حاصل کنید.
تغییرات مهمی را در این فصل اعمال کردیم مطمئن شوید کدها را به وسیلهی گیت کامیت کنید.
Command Line
$ git status
$ git add .
$ git commit -m 'ch8'
در صورت بروز هرگونه مشکل کدهای خود را با کدهای سورسکد رسمی در گیتهاب مقایسه کنید.
افزودن متغیرهای محیطی یک مرحله ضروری برای هر پروژه حرفهای جنگو است. با توجه به کاری که بعدا در این کتاب میکنیم جابهجای بین محیط عملی و محیطی, به این شکل, بی ارزش خواد شد. در فصل بعد تنظیمات ایمیل هارا پیکربندی کرده و قابلیت بازنشانی رمز عبور را اضافه خواهیم کرد.