Docker ile Örnek Django Uygulaması
Jul 21, 2016 · 7 minute read · Commentsdockerlinuxpythondjango
Bu yazimda sizlerle docker ile ayni fiziksel makina uzerinde calisan bir django uygulamasi alt yapisi nasil hazirlanir onu paylasacagim. Bu alt yapi ile birlikte gerektiginde sisteme ilave uzerinde django uygulamamizin calistigi containerlar ekleyip sitemizin performansini {artira/koruya}bilecegiz.
Sistemin yapisi su sekilde olacak:
- Nginx gelen trafigi django containerlar arasinda dagitacak.
- Nginx olusturulan
mystatic
isimli volume uzerinden static dosyalari sunacak. - Django containerlar DB containeri ile haberlesecek.
- Django containerlar
mystatic
isimli volume uzerindeki dizinlere erisebilecek.
Simdi bu alt yapiyi docker ile nasil olusturabiliriz onu gorelim.
Ornek Uygulama
Ben github uzerinde bir depo olusturdum. Depoda icinde uWSGI+Django calisan bir image olusturmamizi saglayacak Dockerfile ve konfigurasyon dosyalari, kullanici sayfayi ziyaret edince ekrana uygulamanin uzerinde calistigi containerin hostnameini bir kac resim ile beraber sayfada gosteren basit bir Django uygulamasi, ornek uygulamamizin DB backupi ve Nginx konfigurasyon dosyasi yer aliyor. Makaleyi bu ornek uygulama uzerinden anlatadagim. Bu depoyu local makinaniza indirip yukaridaki resimde gosterilen yapiyi kendi makinanizda test edebilirsiniz.
Ornek uygulamayi local makinanizda kurmak istemiyorsanizDocker Agi olusturma
kismina gecebilirsiniz.
Depoyu /tmp
dizinine indirmek icin:
$ git clone https://github.com/mesuutt/docker-nginx-django-workflow.git /tmp/workflow
Depoda docker compose ile yapiyi ayaga kaldirabileceginiz docker-compose.yml
dosyasida bulunuyor.
Docker compose ile tek seferde yukaridaki resimde gosterilen yapiyi kendi makinanizda olusturabilirsiniz.
Docker compose kullanmiyorsaniz yine depoda bulunan run.sh
dosyasini calistirarak da
ornek yukaridaki resimde gosterilen yapiyi ayaga kaldirabilirsiniz.
run.sh
dosyasini calistirmak yerine docker compose ile containerlari ayaga kaldirmak isterseniz
docker-compose up
komutunu calistirdiktan sonra uygulamanin calisabilmesi icin
DB olusturup, sql backupimizi acip, uygulamamizin statik dosyalarini
gerekli yerlere kopyalamamiz gerekiyor. Bu islemleri docker compose ile yapamadigimizdan
kendimiz yapmamiz gerekiyor. Ornek uygulamayi indirdiginiz dizine gidip bu islemi
asagida gosterildigi gibi kendimiz yapabiliriz.
# Ornek uygulamayi indirdigimiz dizine gidiyoruz.
$ cd /tmp/workflow
# Ornek uygulamanin kullanacagi databasei olusturuyoruz
$ docker exec pgdb createdb -U postgres myappdb
# DB backupini containera kopyalayip aciyoruz
$ docker cp postgres/myappdb.dump pgdb:/
$ docker exec pgdb psql -U postgres -f /myappdb.dump myappdb
# Gerekli static dosyalari olusturdugumuz
# docker volume kopyaliyoruz.
$ docker cp volume_content/myapp django1:/static
# Uygulamanin static dosyalarini Nginx'in sunacagi dizine topluyoruz.
$ docker exec django1 /srv/app/manage.py collectstatic --noinput
# Uygulamalari yeriden baslatiyoruz.
$ docker exec django1 supervisorctl restart app-uwsgi
$ docker exec django2 supervisorctl restart app-uwsgi
Bu islemleride yaptiktan sonra Nginx’in calistigi containerinin IPsini tarayicinizdan acarak ornek uygulamayi test edebilirsiniz. Sayfayi acip bir kac defa sayfayi yenilediginizde sayfanin farkli Django instancelerdan geldigini goreceksiniz (sayfanin ust kisminda istek hangi Django containera yonlendirildiyse o containerin hostnamei yaziyor).
Simdi yukaridaki resimde gosterilen yapiyi nasil olusturabilecegimizi adim adim anlatmaya calisacagim.
Docker Agi Olusturma
Ilk olarak mynetwork
adinda bir docker bridge agi olusturacagiz ve butun containerlarimizi bu aga dahil
edecegiz. Bu sayede containerlar kendi aralarinda kolayca haberlesebilecek ve birbirlerine
containerlarin isimleriyle ulasabilecekler.
Not: Docker 1.9 surumunden once containerlari calistirirken(docker run
)
--link
parametresini kullanarak; calisacak olan containerin link parametresinde belirtilen container ile
haberlesebilmesini saglayabiliyorduk. Fakat 1.9 surumu ile birlikte
Docker networks
duyuruldu. Docker 1.9+ ile beraber --link
parametresi kullanmak yerine birbirleriyle
haberlesmesini istedigimiz containerlari ayni aga dahil ediyoruz.
Docker networksun bize kattigi guzel seyler var. Bu konu hakkinda da cok yakin zamanda detayli bir yazi yazacagim insAllah.
Ise ilk olarak yeni bir bridge network olusturarak baslayalim. Sonradan olusturacagimiz containerlari bu networke dahil edecegiz ve bu sayede aga dahil olan butun containerlarin birbirleriyle haberlesebilmesini saglayacagiz.
Docker networkumuzu olusturalim:
$ docker network create mynetwork
Docker Volume Olusturma
Simdi ise yukaridaki resimde gosterilen mystatic
isimli named volume
(Turkce’ye nasil cevirsem bilemedim) olusturalim.
Volumeu dockerin calistigi makinadaki bir dizin olarak dusunebilirsiniz (Baska bir makina uzerinde de olabiliyor). Bu dizini olusturucagimiz containerlara mount edebiliyoruz. Bu sayede butun containerlar ayni dizine erisebiliyor.
Not: docker run -v /host/dizini:/container/dizini ...
seklinde de
host da bulunan bir dizini containera mount edebiliyoruz.
Bu olusturacagimiz volume u ileride olusturacagimiz nginx ve django containerlara mount edecegiz. Nginx uygulamamizin static dosyalarini bu volume uzerinden sunacak ve Django containerlar kullanicinin upload ettigi dosyalari isleyip bu volumedeki ilgili dizine atabilecekler.
$ docker volume create --name=mystatic
Gerekli Olan Containerlari Olusturma
Simdi ise sira geldi containerlari olusturmaya. Sirayla 1 adet Postgresql, 2 adet Django ve 1 adet Nginx container olusturacagiz.
Not: Bu makalede Nginx ve Postgresql docker imagelarini docker hubdan indirip kullandim. Siz isterseniz imagelarin Dockerfileini indirip kendiniz build edebilirsiniz.
Postgresql Container
Ilk olarak Postgresql docker imageini Docker hubdan indiriyoruz.
$ docker pull postgres
Postgresql imageimizi indirdik. Simdi ise pgdb
adinda bir postgresql container
olusturalim ve daha once olusturmus oldugumuz mynetwork
agina ekliyelim.
$ docker run -d \
--net=mynetwork \
--name pgdb \
-e POSTGRES_PASSWORD=12345 \
postgres
Artik calisan bir postgresql containerimiz var. Simdi containerda bir shell acalim ve uygulamamizin kullanacagi databaseimizi olusturalim.
$ docker exec -it pgdb /bin/bash
root@e7c085fe3fbc:/# createdb -U postgres myappdb
myappdb
adinda bir db olusturduk.
Simdi ise ornek uygulamamizin db backupini container a kopylayip acalim
$ docker cp postgres/myappdb.dump psql:/
$ docker exec pgdb psql -U postgres -f /myappdb.dump myappdb
Not:mynetwork
, mystatic
ve myappdb
isimlendirmeleri cok yaratici degilmi :)
Django Container
Simdi ornek django uygulamamizi calistiracagimiz 2 adet container olusturalim. Yukarida da belirttigimiz gibi Nginx kullanicilardan gelen istekleri bazen django1 containerindaki Django uygulamasina bazen ise django2 containerinda calisan Django uygulamasina yonlendirecek.
$ git clone https://github.com/mesuutt/docker-nginx-django-workflow.git /tmp/workflow
$ cd /tmp/workflow
$ docker build mesuutt/uwsgi-django .
$ docker run -d \
--net=mynetwork \
--name django1 \
-e DJANGO_SETTINGS_MODULE='myapp.settings.local'
-v mystatic:/static \
mesuutt/uwsgi-django
$ docker run -d \
--net=mynetwork \
--name django2 \
-e DJANGO_SETTINGS_MODULE='myapp.settings.local'
-v mystatic:/static \
mesuutt/uwsgi-django
Ben iki adet contaner olusturdum. Siz isterseniz 1,2,3… size ne kadar gerekiyorsa o kadar olusturabilirsiniz :).
Nginx Container
Bu containerda calisan nginx, gelen trafigi django containerlara yonlendirerek yuk dagilimi yapacak ve uygulamanin statik dosyalarini sunacak.
Nginx icinde custom bir image hazirladim. Bu custom imagein official imagedan tek farki
processleri nginx
kullanicisiyla degil UID
‘i 1000 olan bir kullanici ile calistiriyor olmasi.
Buna ihtiyac duyulmasinin sebebi su:
App containerlarda calisan uWSGI processlerin sahibi olan kullanicinin idsi ile nginx containerlarda statik dosyalari sunan kullanici idsi ayni olmali ki statik dosyalara/dizinlere okuma/yazma hatasi meydana gelmesin.
$ cs nginx/
$ docker build mesuutt/nginx .
Nginx containerimizi calistiralim:
$ docker run -d \
--net=mynetwork \
--name nginx \
-v mystatic:/static \
-v /tmp/workflow/nginx/myapp.conf:/etc/nginx/conf.d/default.conf \
mesuutt/nginx
--net=mynetwork
ile nginx containerimizimynetwork
agina dahil ettik.-v mystatic:/static
ilemystatic
isimli volumeumuzu containerin/static
dizinine mount ettik.-v /tmp/workflow/nginx/myapp.conf:/etc/nginx/conf.d/default.conf
ile ornek uygulama icin hazirlamis oldugumuz nginx Server Block(Virtual Host) dosyamizi containera mount ettik.
Artik calisan bir nginx containerimiz da var.
Nginx containera mount ettigim uygulamamızın virtual host dosyasinin icerigi:
# myapp.conf
upstream uwsgi {
# Olusturdugumuz Django containerlarin hostlari
# ve uzerlerinde calisan uWSGI'larin dinledigi portlari
# buraya ekleyerek Nginxe gelen istekleri
# bu Django containerlar arasinda
# dagitmasini soylemis oluyoruz.
# Dikkat ettiyseniz django containerlarin IPleri yerine
# isimleri yaziyor. Bu containerlari ayni aga
# ekledigimiz icin mumkun oluyor.
server django1:9000;
server django2:9000;
}
server {
listen 80;
root /srv/app;
access_log /var/log/nginx/myapp-access.log;
error_log /var/log/nginx/myapp-error.log error;
location /static {
alias /static/myapp/staticfiles;
access_log off;
expires 30d;
}
location /media {
alias /static/myapp/media;
access_log off;
}
location / {
include /etc/nginx/uwsgi_params;
uwsgi_pass uwsgi;
uwsgi_param Host $host;
uwsgi_param X-Real-IP $remote_addr;
uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
uwsgi_param X-Forwarded-Proto $http_x_forwarded_proto;
}
}
Artik tarayicinizdan nginx containerin IPsine giderek ornek uygulamamizi test edebilirsiniz. Sayfanin ust kisminda hostname in degilstigini goreceksiniz.
Internette nginx, uwsgi ve Django nun beraber geldigi Docker imagelar ve Dockerfile lar bulunuyor. Bunlari gelistirme ortaminda kullanabiliriz (Bir containeri calistirarak butun development environmentimiz ayaga kaldirabiliyoruz) fakat Python web uygulamanizin calistigi birden fazla Django container olusturayim derseniz bu image ve Dockerfilelar isinizi gormez.
Ben internette baktim icinde Nginx, Postgresql bulunmayan sadece uWSGI kururulu gelen bir image/Dockerfile bulamadim. Bende icinde Dockerfile ve yardimci konfigurasyon dosyalarinin bulundugu bir github deposu olusturdum. Kendi Python ile hazirladiginiz web projenizi (Django/Flask vb.) yukarida belirtilen gibi bir yapida calistirmak isterseniz kullanabilirsiniz.
Yapmaniz gereken sey cok basit;
Github deposunu indirin:
$ git clone https://github.com/mesuutt/docker-uwsgi.git
Kendi Python projenizi
app
dizini altina kopyalayinuwsgi.ini dosyasinda gerekli degisikligi yapin (ozellikle
module=website.wsgi:application
kismi).Docker imageinizi build edin.
Artik bu image dan istediginiz kadar container olusturabilirsiniz. Bu makaledeki ornek uygulamanin Django docker image ini da bunun ile hazirladim.
Depoya su adresden ulasabilirsiniz: https://github.com/mesuutt/docker-uwsgi