{"id":194,"date":"2020-06-05T23:12:25","date_gmt":"2020-06-05T23:12:25","guid":{"rendered":"http:\/\/localhost\/?p=194"},"modified":"2021-07-29T22:35:06","modified_gmt":"2021-07-29T22:35:06","slug":"dockerizing-django","status":"publish","type":"post","link":"https:\/\/tutorials.leesonresearch.com\/tutorials\/2020\/06\/05\/dockerizing-django\/","title":{"rendered":"Dockerizing Django"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Setting up Docker environment for Django.<\/h2>\n\n\n\n<p>You can access the source code for this tutorial from my git repository <a href=\"https:\/\/gitlab.com\/ronleeson\/dockerize-django.git\">here<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What is Docker?<\/h3>\n\n\n\n<p>Docker packages and runs an application in an isolated environment called a container.<\/p>\n\n\n\n<p>This Container contain everything you need to run the application.<\/p>\n\n\n\n<p><strong>What do I mean by everything?<\/strong><\/p>\n\n\n\n<p>Imagine you are building a web application that requires a frontend, backend, and a database.  All these services have to be installed and configured whether it be on your laptop or a production server running in the cloud.<\/p>\n\n\n\n<p>I\u2019ve had experiences where it has taken hours to setup a new development environment on my Mac for an application requiring multiple services, binaries, libraries and configuriation files. Once I have all these services up and running on my Mac OS there is no guarantee that is application will run on a Windows os which leads us to the old problem, &#8220;Well it worked on my server.&#8221;<\/p>\n\n\n\n<p>Docker eliminates all that. All that is required to spin up a complete development environment with your application is to pull your \u201cdockerized\u201d app from the DockerHub repository or from your git repo, then cd into the root of your project and launch your app from the terminal with a few Docker commands.<\/p>\n\n\n\n<p>It&#8217;s easy now to share this Dockerized app with a new team member whether they are working on a Mac, PC, or Linux, as long as they have Docker installed they can spin this Dockerized app up and have it running in a matter of minutes in its own isolated environment where the app is guaranteed to work.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What is Django?<\/h3>\n\n\n\n<p>Django\u2014pronounced \u201cJango,\u201d named after the famous jazz guitarist Django Reinhardt\u2014is a web application framework that allows rapid development of complex, database-driven websites which uses the model\u2013template\u2013views (MVC) pattern.<\/p>\n\n\n\n<p>We&#8217;re going to be building a Docker development environment for a bare bones Django installation running Postgresql database. When we&#8217;re finished we will be able to spin up this Django app in its isolated Docker development environment where you can begin building out your Django application.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Server Architecture<\/h2>\n\n\n\n<p>Here&#8217;s a overall look of the server architecture we will be building.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"952\" height=\"944\" src=\"http:\/\/10.0.0.14:5557\/wp-content\/uploads\/2021\/07\/dockerizing_django.png\" alt=\"\" class=\"wp-image-2130\" srcset=\"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2021\/07\/dockerizing_django.png 952w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2021\/07\/dockerizing_django-300x297.png 300w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2021\/07\/dockerizing_django-150x150.png 150w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2021\/07\/dockerizing_django-768x762.png 768w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2021\/07\/dockerizing_django-600x595.png 600w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2021\/07\/dockerizing_django-945x937.png 945w\" sizes=\"auto, (max-width: 952px) 100vw, 952px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Setup the Django Project File Structure<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\nmkdir dockerized-django\ncd dockerized-django\nmkdir server\ntouch docker-compose.yml\ntouch Makefile\ntouch .env\ngit init\ncd server\ntouch Dockerfile\ntouch requirements.txt\ncd ..\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Project Files<\/h4>\n\n\n\n<ul class=\"wp-block-list\"><li>dockerized-django <ul><li>server <ul><li>Dockerfile<\/li><li>requirements.txt<\/li><\/ul><\/li><li>.env<\/li><li>docker-compose.yml <\/li><\/ul><\/li><\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Create the Dockerfile<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\ncd server\nsudo nano Dockerfile\n<\/pre><\/div>\n\n\n<p>Put to the following into the <strong>Dockerfile<\/strong>.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# \/dockerized-django\/Dockerfile\n\nFROM python:3\nENV PYTHONBUFFERED 1\nRUN mkdir \/server\nWORKDIR \/server\nCOPY requirements.txt \/server\/\nRUN pip3 install -r requirements.txt\nCOPY . \/server\/\n\nCMD python manage.py collectstatic --no-input;python manage.py makemigrations;python manage.py migrate\n<\/pre><\/div>\n\n\n<p>To save exit with nano use ctrl-o (as in olive) =&gt; return =&gt; ctrl-x<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Create the .env file<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\nsudo nano .env\n<\/pre><\/div>\n\n\n<p>Add the following to our .env file:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\nDATABASE_NAME=db_django\nDATABASE_USER=user_django\nDATABASE_PASSWORD=mypassword\nDATABASE_HOST=database\nDATABASE_PORT=5432\nSERVER_PORT=5555\nDJANGO_SETTINGS_MODULE=django_proj.settings\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Populate the Docker Compose File<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; first-line: 1; highlight: [15,28,29]; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# dockerized-django\/docker-compose.yml\n\nversion: '3'\n\nservices:\n    database:\n        container_name: database\n        image: postgres:latest\n        environment:\n            - POSTGRES_DB=$DATABASE_NAME\n            - POSTGRES_USER=$DATABASE_USER\n            - POSTGRES_PASSWORD=$DATABASE_PASSWORD\n            - POSTGRES_PORT=$DATABASE_PORT\n        volumes:\n            - .\/postgres-data:\/var\/lib\/postgresql\/data\n    server:\n        build: .\/server\n        container_name: django\n        ports:\n            - '$SERVER_PORT:$SERVER_PORT'\n        command: python manage.py runserver 0.0.0.0:$SERVER_PORT\n        environment:\n            - DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE\n        volumes:\n          - .\/server:\/server\n        depends_on:\n            - database\nvolumes:\n  postgres-data:\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Data Persistence<\/h4>\n\n\n\n<p>Note the highligted line above on <strong>.\/postgres-data:\/var\/lib\/postgresql\/data<\/strong> where we map the data from Postgres running on the Docker container into a directory on our host machine. This insures that as we won&#8217;t lose any data from the database even if we were to spin down the app with <strong>docker-compose down <\/strong>we won&#8217;t lose our data.<\/p>\n\n\n\n<p>Since we are referencing postgres-data in our database volumes we also need to add volumes at the bottom of our docker-compose.yml file.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Django requirements.txt File<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\nDjango&gt;=2.0,&amp;lt;3.0\npsycopg2&gt;=2.7,&amp;lt;2.9\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Create the Django Project<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# create django project\ndocker-compose run server django-admin startproject django_proj .\n\n# create django app\ndocker-compose run server django-admin startapp django_app\n<\/pre><\/div>\n\n\n<p>We now should have our Django project and app installed in the root of the server directory <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"678\" src=\"http:\/\/10.0.0.14:5557\/wp-content\/uploads\/2021\/07\/code_editor_django_proj-1024x678.png\" alt=\"\" class=\"wp-image-2134\" srcset=\"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2021\/07\/code_editor_django_proj-1024x678.png 1024w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2021\/07\/code_editor_django_proj-300x199.png 300w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2021\/07\/code_editor_django_proj-768x508.png 768w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2021\/07\/code_editor_django_proj-600x397.png 600w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2021\/07\/code_editor_django_proj-945x625.png 945w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2021\/07\/code_editor_django_proj.png 1248w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>At this point if we were to spin up the app, Django would be using Sqlite but we want Postgres for our database. So, lets swap out Sqlite for Postgres in the <strong>server\/django_proj\/settings.py<\/strong> file:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Replace Sqlite with Postgres<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\nvi server\/django_proj\n<\/pre><\/div>\n\n\n<p>Scoll down the settings.py file and replace:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\nDATABASES = {\n    'default': {\n        'ENGINE': 'django.db.backends.sqlite3',\n        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),\n    }\n}\n<\/pre><\/div>\n\n\n<p>&#8230; with:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; title: Double click to copy; notranslate\" title=\"Double click to copy\">\nDATABASES = { \n'default': { \n    'ENGINE': 'django.db.backends.postgresql',\n    'NAME': 'db_django',\n    'USER': 'user_django',\n    'PASSWORD': 'mypassword',\n    'HOST': 'database',\n    'PORT': 5432, \n  }\n}\n<\/pre><\/div>\n\n\n<p>Now that we have Django referencing Postres we can move on with migrations.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Migrate and Create the Django App<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# migrate\ndocker-compose run server python manage.py migrate\ndocker-compose run server python manage.py createsuperuser\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Add Django App to Settings.py<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# server\/django_proj\/settings.py\n\nINSTALLED_APPS = &#x5B;\n'django.contrib.admin',\n'django.contrib.auth',\n'django.contrib.contenttypes',\n'django.contrib.sessions',\n'django.contrib.messages',\n'django.contrib.staticfiles',\n'django_app',\n]\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">Test Server<\/h3>\n\n\n\n<p>We are now ready to test the server by accessing the Django admin UI from a browser.<\/p>\n\n\n\n<p>Spin up the database and server services:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\ndocker-compose up -d\n<\/pre><\/div>\n\n\n<p>Sometimes docker-compose up -d fails to bring our django server, if that happens its usually because the server came online before the database so, if that happens manually bring the database first and then the server:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\ndocker-compose up -d database\ndocker-compose up -d server\n<\/pre><\/div>\n\n\n<p>Now you should be able to access the Django in your browser at <a href=\"http:\/\/localhost:5555\" target=\"_blank\" rel=\"noreferrer noopener\">http:\/\/localhost:5555.<\/a><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"669\" src=\"http:\/\/10.0.0.14:5557\/wp-content\/uploads\/2021\/07\/django_home-1024x669.png\" alt=\"\" class=\"wp-image-2115\" srcset=\"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2021\/07\/django_home-1024x669.png 1024w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2021\/07\/django_home-300x196.png 300w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2021\/07\/django_home-768x502.png 768w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2021\/07\/django_home-1536x1003.png 1536w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2021\/07\/django_home-600x392.png 600w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2021\/07\/django_home-945x617.png 945w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2021\/07\/django_home.png 1542w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>We can access the Django admin page at at <a href=\"http:\/\/localhost:5555\/admin\" target=\"_blank\" rel=\"noreferrer noopener\">http:\/\/localhost:5555\/admin<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"942\" height=\"489\" src=\"http:\/\/10.0.0.14:5557\/wp-content\/uploads\/2020\/06\/login.jpg\" alt=\"\" class=\"wp-image-349\" srcset=\"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/06\/login.jpg 942w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/06\/login-300x156.jpg 300w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/06\/login-768x399.jpg 768w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/06\/login-600x311.jpg 600w\" sizes=\"auto, (max-width: 942px) 100vw, 942px\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">Accessing the Django Logs File<\/h4>\n\n\n\n<p>Docker-compose has a wonderful command to display the different services logs to the command line which is great for debugging.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# display logs for both database and server\ndocker-compose logs\n\n# display only the logs for the database\ndocker-compose logs database\n\n# display only the logs for the server\ndocker-compose logs server\n<\/pre><\/div>\n\n\n<p>Now if you do run into any errors you can refer to the log files for each service.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Commit All Work to Git<\/h4>\n\n\n\n<p>Before commiting our work to git let&#8217;s create a .gitignore file so our db_backups directory is not commited along with the rest of the files to the git repo.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\ntouch .gitignore\nsudo nano .gitignore\n<\/pre><\/div>\n\n\n<p>Add the following to the .gitignore file:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># dockerized-django\/.gitignore\n*.py[co]\n__pycache__\n\n.\/db_backups\n<\/pre>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\ngit add .\ngit commit -m &quot;initial commit&quot;\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Git Repo for Dockerized Django<\/h4>\n\n\n\n<p>You can access my source code from my git repository <a href=\"https:\/\/gitlab.com\/ronleeson\/dockerize-django.git\">here<\/a> and use it as a boilerplate.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Setup a Docker development environment for Django with docker-compose.<\/p>\n","protected":false},"author":1,"featured_media":41,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[23,16,13],"tags":[22,3,21],"class_list":["post-194","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-boiler-plates","category-django","category-docker","tag-dango","tag-docker","tag-docker-compose"],"_links":{"self":[{"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/posts\/194","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/comments?post=194"}],"version-history":[{"count":191,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/posts\/194\/revisions"}],"predecessor-version":[{"id":2210,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/posts\/194\/revisions\/2210"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/media\/41"}],"wp:attachment":[{"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/media?parent=194"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/categories?post=194"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/tags?post=194"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}