name: inverse layout: true class: center, middle, inverse --- name: impact layout: true class: center, middle, impact, content --- name: title layout: true class: title center --- name: content layout: true --- template: title name: main-title .content[ # Django on Docker .align-center.v-align-bottom.no-bullets.small[ - presentation by: Tiago Carreira ] ] --- # About me .left-column[ ## Tiago Carreira Operations Engineer (DevOps)
@ SAPO (Altice-PT) / BOLD by Devoteam
.small[ - MSc in Electrical Engineering - working with Linux for 6y+ - favourite prog languages: bash, python, go - favourite text editor: vscode, vim - music, sports, therapeutic massages, bad jokes - .tiny[ **keywords:** DevOps, Automation, CI/CD, Docker, Beer] ]
] .rigth-column[ .center[ .pic-circle[
]
] .center.no-bullets.tiny[ - **telegram:** @tcarreira - **github:** https://
github.com/tcarreira - **twitter:** @tiagogcarreira ] ] --- # Agenda - Live coding 1. Start a Django project (from scratch) 1. Setup Docker 1. Testing Django (with Docker) 1. Docker volumes for development 1. Docker-compose - a simple multi-container orchestration tool 1. Debugging a Django application 1. Improve Dockerfile and other thing... 1. Test it all together 1. Last notes Follow along: https://github.com/tcarreira/django-docker
--- # Quick recap ## Django Django is a Python-based free and open-source web framework, which follows the model-template-view architectural pattern. Django's primary goal is to ease the creation of complex, database-driven websites.
It's great for fast development of a backoffice. ??? - Open source - Easy creation of websites - Easy creation of a management backoffice --- # Quick recap ## Docker A container management tool, great for microservices.
"A container is a standard unit of software that packages up code and all its dependencies so the application runs quickly and reliably from one computing environment to another" - CPU Isolation: kernel namespaces - Filesystem isolation: libcontainerd - Network isolation - Each container also gets its own network stack - Bridge interfaces - **Links** allow traffic between containers ??? - great for microservices. - generates a single unit package (docker image) - great isolation (works on my machine and in yours) --- # Development best practices What do you need to develop? (not an exaustive list) .small.formattable[ | tool | what for | example | | --- | --- | --- | | a good IDE | auto-completion, debugging | vscode | | good IDE plugins | framework specifics (django) | `ms-python.python`,
`batisteo.vscode-django` | | linter | you need to have a real-time feedback about what is wrong | mypy | | formatter | it's great for code sharing | black | | unit tests | you should really not test your code. Make your computer do it | pytest | | code-to-execution | low latency after writing your code until it gets executed | manage.py runserver | ] ??? I'll try to show some of this today --- template: inverse # Live Coding Let's get our hands into it ??? you can follow along on https://github.com/tcarreira/django-docker
but I recommend you do it only after the presentation, in order to better follow what I explain. --- # 1. Start a Django project (from scratch) - Setup VirtualEnv and install Django - Create django project and initial setup test it with
`python manage.py runserver 0.0.0.0:8000` open the browser at http://127.0.0.1:8000 ??? we could do this with docker itself, but it's easier to explain the workflow after having this initial setup --- # 2. Setup Docker - Install Docker - Setup a first draft of a Dockerfile - Identify some problems in Dockerfile --- # Dockerfile First draft of a Dockerfile .small[ ```dockerfile FROM python COPY django_demo/ /app/ RUN pip install --no-cache-dir "Django>=3.0,<4" ENV PYTHONUNBUFFERED=1 CMD python /app/manage.py runserver 0.0.0.0:8000 ``` ] --- # Dockerfile First draft of a Dockerfile .small[ ```dockerfile FROM <=>python=> *COPY django_demo/ /app/ RUN pip install --no-cache-dir "Django>=3.0,<4" ENV PYTHONUNBUFFERED=1 CMD python /app/manage.py runserver 0.0.0.0:8000 ``` ] --- # Dockerfile Better draft of a Dockerfile .left-column.small[ ```dockerfile FROM <=>python=> *COPY django_demo/ /app/ RUN pip install --no-cache-dir "Django>=3.0,<4" ENV PYTHONUNBUFFERED=1 CMD python /app/manage.py runserver 0.0.0.0:8000 ``` ```Dockerfile FROM python<+>:3.7-alpine+> RUN pip install --no-cache-dir "Django>=3.0,<4" *COPY django_demo/ /app/ ENV PYTHONUNBUFFERED=1 CMD python /app/manage.py runserver 0.0.0.0:8000 ``` ] -- .right-column[ - COPY files before pip install - use docker images tags (alpine if possible) - beware of context (.dockerignore) .small[ `.dockerignore`: ``` venv/ __pycache__/ db.sqlite3 ``` ] ] ??? `.dockerignore` when we build a docker image, on the background it will transfer every file in the context to the docker server (local), which means we should tell docker what is not supposed to include in the context in order to avoid extra transferring --- # Build docker image ``` docker build -t django-docker-demo . docker run -it --rm -p8000:8000 django-docker-demo ``` ??? with this, we get a single standard unit of software, with all dependencies --- # 3. Testing Django (with Docker) - create a function to handle `127.0.0.1:8000/` - change urls -- - how we can change the running code - save changes - rebuild the docker image - remove old container - create new container - but... ??? thats f*cking boring --- template: inverse # Enter docker volumes --- # 4. Docker volumes for development .small[ ``` docker run -it --rm -p8000:8000 <+>-v "$(pwd)/django_demo/:/app/"+> django-docker-demo ``` ] now, every time you change some file, django will reload itself.
Very useful (a must) for developmemt. ---
## what if I need more containers? - maybe adding Celery - or a different database (mysql) - or another micro-service --- template: inverse # Enter docker-compose a simple multi-container orchestration tool --- # 5. Docker-compose .left-column[ add more services - Celery - Redis so... - Install celery + redis - Create a `docker-compose.yml` - Update python code - Test our setup ] .right-column.tiny[ ```docker-compose version: "3.4" services: django: image: django-docker-demo:latest ports: - 8000:8000 celery-worker: image: django-docker-demo:latest command: "celery -A ... worker" redis: image: redis:5.0-alpine ``` ] --- # 6. Debugging a Django application - Python: Current File (not very handy in Django) - Python: Debug Django (very good)*
.small[
* but you are not using docker ] --- # 6. Debugging a Django application - Python: Current File (not very handy in Django) - Python: Debug Django (very good)* - **Python: Debug Django attach Docker** (like remote debugging)
.small[
* If you are a beginner, stay with it ] ??? This is very handy if you want to debug with multiple containers running. --- # 6. Debugging a Django application - prepare a docker image for running a debugger - setup network (expose ports) - add a debugger inside Django - setup IDE --- # 7. Improve Dockerfile and other thing... .left-column[ - do not run as root - remove unnecessary dependencies - clean your logs - next level caching (with Buildkit `DOCKER_BUILDKIT=1`) - quality as part of the pipeline ] .right-column[ - Prepare Django for production - use a webserver - serve static content - use a different database - build a common entrypoint ] --- # 8. Test it all together .small[ ``` git clone https://github.com/tcarreira/django-docker.git cd django-docker DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 docker-compose up <=>--build=> ``` ]
.tiny[
* you need docker-compose >= 1.25 in order to use builkit directly. ] ??? If you don't have docker-compose >= 1.25, build all images first - DOCKER_BUILDKIT=1 docker build -t django-docker-demo:latest . - DOCKER_BUILDKIT=1 docker build -t django-docker-demo:dev --target=dev . - DOCKER_BUILDKIT=1 docker build -t django-docker-demo:qa --target=qa . - DOCKER_BUILDKIT=1 docker build -t django-docker-demo:webserver --target=webserver . Then `docker-compose up` This should be part of a Continuous Integration process anyway --- # 9. Last notes - keep separate `docker-compose.qa.yml` for testing/qa with final images - build your continuous integration process --- template: impact # That's all folks
## Questions? --- # Reach me .left-column[ .center[
.tiny[ https://tcarreira.github.io/presentations/django-docker ] ] ] .rigth-column[
.center.no-bullets.tiny[ - **telegram:** @tcarreira - **github:** https://
github.com/tcarreira - **twitter:** @tiagogcarreira ] ] ??? Reach me on telegram --- template: main-title .content[.align-center[ ## Thank you ]]