A presentation at DjangoCon Europe 2018 in in Heidelberg, Germany by Lacey Williams Henschel
An Intro to Docker for Djangonauts Lacey Williams Henschel DjangoCon Europe 2018 @laceynwilliams
@laceynwilliams
What is Docker? ! @laceynwilliams | Source: XKCD
magic @laceynwilliams
Docker ✓ Separate dependencies ✓ Shares your OS ✓ All team members on the same page ✓ No Python installs needed! @laceynwilliams
But... ✓ Learning curve @laceynwilliams
What about virtualenvs? @laceynwilliams | Source: XKCD
Polyjuice Potion Images and Containers @laceynwilliams
Docker is the potion @laceynwilliams | Source: Karen Roe
The image is the person you want to turn into @laceynwilliams | Source: Harry Po5er Wiki
The container
is you @laceynwilliams
image executable that contains all the packages for your project container run6me instance of image @laceynwilliams
The Dockerfile is the hair of the person you want to turn into @laceynwilliams | Source: Beth Purchases
Dockerfile is the DNA @laceynwilliams
image executable that contains all the packages for your project container run6me instance of image Dockerfile file that defines your image @laceynwilliams
Use hair to tell the po-on how to change into someone else . Drink it to transform your body . Use Dockerfile to tell Docker how to build your image . Run project in a container . @laceynwilliams
FROM python: 3.6 ENV PYTHONUNBUFFERED 1 COPY ./requirements.txt /code/requirements.txt RUN pip install -r /code/requirements.txt COPY . /code/ WORKDIR /code/ EXPOSE
8000 CMD [ "python" , "./manage.py" , "runserver" ,
"0.0.0.0:8000" , "--settings=mysite.settings" ] @laceynwilliams
FROM python: 3.6 ENV PYTHONUNBUFFERED 1 COPY ./requirements.txt /code/requirements.txt RUN pip install -r /code/requirements.txt COPY . /code/ WORKDIR /code/ EXPOSE
8000 CMD [ "python" , "./manage.py" , "runserver" ,
"0.0.0.0:8000" , "--settings=mysite.settings" ] @laceynwilliams
FROM python: 3.6 ENV PYTHONUNBUFFERED 1 COPY ./requirements.txt /code/requirements.txt RUN pip install -r /code/requirements.txt COPY . /code/ WORKDIR /code/ EXPOSE
8000 CMD [ "python" , "./manage.py" , "runserver" ,
"0.0.0.0:8000" , "--settings=mysite.settings" ] @laceynwilliams
FROM python: 3.6 ENV PYTHONUNBUFFERED 1 COPY ./requirements.txt /code/requirements.txt RUN pip install -r /code/requirements.txt COPY . /code/ WORKDIR /code/ EXPOSE
8000 CMD [ "python" , "./manage.py" , "runserver" ,
"0.0.0.0:8000" , "--settings=mysite.settings" ] @laceynwilliams
FROM python: 3.6 ENV PYTHONUNBUFFERED 1 COPY ./requirements.txt /code/requirements.txt RUN pip install -r /code/requirements.txt COPY . /code/ WORKDIR /code/ EXPOSE
8000 CMD [ "python" , "./manage.py" , "runserver" ,
"0.0.0.0:8000" , "--settings=mysite.settings" ] @laceynwilliams
FROM python: 3.6 ENV PYTHONUNBUFFERED 1 COPY ./requirements.txt /code/requirements.txt RUN pip install -r /code/requirements.txt COPY . /code/ WORKDIR /code/ EXPOSE
8000 CMD [ "python" , "./manage.py" , "runserver" ,
"0.0.0.0:8000" , "--settings=mysite.settings" ] @laceynwilliams
FROM python: 3.6 ENV PYTHONUNBUFFERED 1 COPY ./requirements.txt /code/requirements.txt RUN pip install -r /code/requirements.txt COPY . /code/ WORKDIR /code/ EXPOSE
8000 CMD [ "python" , "./manage.py" , "runserver" ,
"0.0.0.0:8000" , "--settings=mysite.settings" ] @laceynwilliams
FROM python: 3.6 ENV PYTHONUNBUFFERED 1 COPY ./requirements.txt /code/requirements.txt RUN pip install -r /code/requirements.txt COPY . /code/ WORKDIR /code/ EXPOSE
8000 CMD [ "python" , "./manage.py" , "runserver" ,
"0.0.0.0:8000" , "--settings=mysite.settings" ] @laceynwilliams
Brew your potion $ docker build . @laceynwilliams
$ docker build . Sending build context to Docker daemon 246.8kB Step 1/8 : FROM python:3.6 ---> c1e459c00dc3 Step 2/8 : ENV PYTHONUNBUFFERED 1 ---> 4a0a06578949 Step 3/8 : COPY ./requirements.txt /code/requirements.txt ---> 5295a62d7c36 Step 4/8 : RUN pip install -r /code/requirements.txt ---> Running in 18b4fa19c07e Collecting Django (from -r /code/requirements.txt (line 1)) Downloading https://.../Django-2.0.5-py3-none-any.whl (7.1MB) Installing collected packages: Django Successfully installed Django-2.0.5 Removing intermediate container 18b4fa19c07e ---> 371f3b29d141 Step 5/8 : COPY . /code/ ---> 5443237e1306 Step 6/8 : WORKDIR /code/ Removing intermediate container cbafa8b61bd9 ---> 5a50cee784e7 Step 7/8 : EXPOSE 8000 ---> Running in a0b9b3f4da6f Removing intermediate container a0b9b3f4da6f ---> 80fbc70dc709 Step 8/8 : CMD [ "python", "./manage.py", "runserver", "0.0.0.0:8000", "--settings=mysite.settings" ] ---> Running in 351cfbc91fa2 Removing intermediate container 351cfbc91fa2 Successfully built 80fbc70dc709 @laceynwilliams
Name of your image 80fbc70dc709 @laceynwilliams
$ docker build -t hogwarts . Successfully built 4521a153fa19 Successfully tagged hogwarts:latest @laceynwilliams
python: 3.6 hogwarts:latest @laceynwilliams
Layers @laceynwilliams | S/ll from Harry Po5er and the Chamber of Secrets
Step 1/8 : FROM python:3.6 ... Step 2/8 : ENV PYTHONUNBUFFERED 1 ... @laceynwilliams
• First (me through: Docker builds each layer by hand • Second (me through: Docker uses a cache if nothing has changed • Docker rebuilds changed layers and all layers a;er them
@laceynwilliams
Step 1/8 : FROM python:3.6 ---> c1e459c00dc3 Step 2/8 : ENV PYTHONUNBUFFERED 1 ---> Using cache ---> 4a0a06578949 Step 3/8 : COPY ./requirements.txt /code/requirements.txt ---> 630e64f66d85 Step 4/8 : RUN pip install -r /code/requirements.txt ---> Running in b9ef1258f655 Collecting Django (from -r /code/requirements.txt (line 1)) Downloading https://.../Django-2.0.5-py3-none-any.whl (7.1MB) ... Step 8/8 : CMD [ "python", "./manage.py", "runserver", "0.0.0.0:8000", "--settings=mysite.settings" ] ---> Running in 351cfbc91fa2 Removing intermediate container 351cfbc91fa2 Successfully built a5392bb186c4 Successfully tagged hogwarts:latest @laceynwilliams
The Standard Book of Spells Grade 1 Docker Edition @laceynwilliams
Imago Revelio $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hogwarts latest 4521a153fa19 42 hours ago 734MB @laceynwilliams ✨ spell to reveal images
Continens Revelio $ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES @laceynwilliams ✨ spell to reveal containers
Drink your potion $ docker run -p 8000:8000 hogwarts @laceynwilliams
Continens Revelio
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED
2021341641d7 hogwarts "python ./manage.py …"About a minute ago
STATUS PORTS NAMES
Up About a minute 0.0.0.0:8000->8000/tcp fervent_allen
@laceynwilliams
✨
spell to reveal containers
Apparate $ docker exec -it 2021341641d7 shell root@2021341641d7:/code# @laceynwilliams ✨ magical teleporta2on into container
root@2021341641d7:/code# ls
Dockerfile blog mysite requirements.txt
README.md manage.py
@laceynwilliams
root@2021341641d7:/code# cd .. root@2021341641d7:/# ls bin code etc lib media opt root sbin sys usr boot dev home lib64 mnt proc run srv tmp var @laceynwilliams
Disapparate ctrl + d @laceynwilliams ✨ magical teleporta2on out of container shell
$ docker container ls
CONTAINER ID IMAGE COMMAND
2021341641d7 hogwarts "python ./manage.py …"
@laceynwilliams
Stupefy $ docker stop 2021341641d7 @laceynwilliams ✨ stunning spell to stop container
Rennervate $ docker start 2021341641d7 @laceynwilliams ✨ spell to revive a stupefied container
Avada Kedavra $ docker kill 2021341641d7 @laceynwilliams ☠ spell to kill a container
Advanced Potions Docker Compose @laceynwilliams
$ docker run -p 8000:8000 hogwarts @laceynwilliams
Docker Compose ✓ Free ✓ Included with Mac, extra download otherwise ✓ Run more than one container at once ✓ Relate containers to each other @laceynwilliams
Hermione's magic bag @laceynwilliams
version:
'3' services: db: image:
postgres web: build:
. command:
bash
-c
"python /code/manage.py migrate --noinput && python /code/manage.py runserver 0.0.0.0:8000" volumes: -
.:/code ports: -
"8000:8000" depends_on: -
db @laceynwilliams
version:
'3' services: db: image:
postgres web: build:
. command:
bash
-c
"python /code/manage.py migrate --noinput && python /code/manage.py runserver 0.0.0.0:8000" volumes: -
.:/code ports: -
"8000:8000" depends_on: -
db @laceynwilliams
version:
'3' services: db: image:
postgres web: build:
. command:
bash
-c
"python /code/manage.py migrate --noinput && python /code/manage.py runserver 0.0.0.0:8000" volumes: -
.:/code ports: -
"8000:8000" depends_on: -
db @laceynwilliams
version:
'3' services: db: image:
postgres web: build:
. command:
bash
-c
"python /code/manage.py migrate --noinput && python /code/manage.py runserver 0.0.0.0:8000" volumes: -
.:/code ports: -
"8000:8000" depends_on: -
db @laceynwilliams
then update settings.py @laceynwilliams
version:
'3' services: db: image:
postgres web: build:
. command:
bash
-c
"python /code/manage.py migrate --noinput && python /code/manage.py runserver 0.0.0.0:8000" volumes: -
.:/code ports: -
"8000:8000" depends_on: -
db @laceynwilliams
version:
'3' services: db: image:
postgres web: build:
. command:
bash
-c
"python /code/manage.py migrate --noinput && python /code/manage.py runserver 0.0.0.0:8000" volumes: -
.:/code ports: -
"8000:8000" depends_on: -
db @laceynwilliams
version:
'3' services: db: image:
postgres web: build:
. command:
bash
-c
"python /code/manage.py migrate --noinput && python /code/manage.py runserver 0.0.0.0:8000" volumes: -
.:/code ports: -
"8000:8000" depends_on: -
db @laceynwilliams
version:
'3' services: db: image:
postgres web: build:
. command:
bash
-c
"python /code/manage.py migrate --noinput && python /code/manage.py runserver 0.0.0.0:8000" volumes: -
.:/code ports: -
"8000:8000" depends_on: -
db @laceynwilliams
version:
'3' services: db: image:
postgres web: build:
. command:
bash
-c
"python /code/manage.py migrate --noinput && python /code/manage.py runserver 0.0.0.0:8000" volumes: -
.:/code ports: -
"8000:8000" depends_on: -
db @laceynwilliams
FROM python: 3.6 ENV PYTHONUNBUFFERED 1 COPY ./requirements.txt /code/requirements.txt RUN pip install -r /code/requirements.txt COPY . /code/ WORKDIR /code/ EXPOSE
8000 CMD [ "python" , "./manage.py" , ... ] @laceynwilliams
FROM python: 3.6 ENV PYTHONUNBUFFERED 1 COPY ./requirements.txt /code/requirements.txt RUN pip install -r /code/requirements.txt COPY . /code/ WORKDIR /code/ EXPOSE
8000 ! @laceynwilliams
Lumos $ docker-compose up $ docker-compose up --build @laceynwilliams ✨ spell to start compose containers
$ docker-compose up Creating network "hogwarts_default" with the default driver Creating hogwarts_db_1 ... done Creating hogwarts_web_1 ... done Attaching to hogwarts_db_1, hogwarts_web_1 db_1 | The files belonging to this database system will be owned by user "postgres". db_1 | This user must also own the server process. web_1 | Operations to perform: web_1 | Apply all migrations: admin, auth, blog, contenttypes, sessions web_1 | Running migrations: web_1 | No migrations to apply. db_1 | LOG: database system is ready to accept connections db_1 | LOG: autovacuum launcher started web_1 | Performing system checks... web_1 | web_1 | System check identified no issues (0 silenced). web_1 | May 03, 2018 - 12:12:57 web_1 | Django version 2.0.5, using settings 'mysite.settings' web_1 | Starting development server at http://0.0.0.0:8000/ web_1 | Quit the server with CONTROL-C. @laceynwilliams
Continens Revelio $ docker container ls CONTAINER ID IMAGE ... NAMES f78a4fac4772 hogwarts_web ... hogwarts_web_1 1fdf3604ce5c postgres:9.6.8 ... hogwarts_db_1 @laceynwilliams ✨ spell to reveal containers
$ docker-compose run --rm web ./manage.py makemigrations Starting hogwarts_db_1 ... done No changes detected @laceynwilliams
--rm Remove this container when I'm done with it @laceynwilliams
apparate into the shell $ docker-compose run --rm web ./manage.py shell Starting hogwarts_db_1 ... done ... In [1]: from spells.models import Spell In [2]: Spell.objects.all() Out[2]: <QuerySet ['Accio', 'Alohomora', 'Expelliarmus']> @laceynwilliams
stop and start at will $ docker-compose stop web Stopping hogwarts_web_1 ... done $ docker-compose start web Starting web ... done @laceynwilliams
Nox $ docker-compose down Removing hogwarts_web_1 ... done Removing hogwarts_db_1 ... done Removing network hogwarts_default @laceynwilliams ✨ spell to darken containers
bit.ly/hogwarts-docker @laceynwilliams
It is the unknown we fear when we look upon Docker, nothing more. — Albus Dumbledore, probably @laceynwilliams | S/ll from Harry Po5er and the Order of the Phoenix
Hogwarts Library · An Intro to Docker for Djangonauts · Docker: Useful Command Line Stuff · Docker tutorial
· Docker Compose tutorial , Compose and Django tutorial · Best PracAces for WriAng Dockerfiles · 10 Things to Avoid in Docker Containers
· Video: 5 Things About Docker · Docker CheatSheet · Dockerizing Django, UWISGI, and Postgres the Serious Way · Managing SensiAve Data with Docker Secrets @laceynwilliams
If you've never used it before, Docker can be a little overwhelming. There is new vocabulary to learn, new commands to memorize, and new files to add to each project. Most resources fall into one of two camps: they teach you the bare bones of Docker but still leave you with too many questions to comfortably try it on your own, or they throw you into the deep end by assuming you're more familiar with Docker than you are.
In this talk, you will find that middle ground: a talk that doesn't assume you're familiar with Docker and so keeps everything simple, but leaves you with enough information that you can get started as soon as you leave the room.
Here’s what was said about this presentation on social media.
I tried to dockerize my Django app+postgres+redis+nginx a couple of weeks ago, but @laceynwilliams talk at @DjangoConEurope really helped me understand Docker. After a day and a half of sweating/swearing, it's working; thank you so much! Here's the video: https://t.co/lrGJ7I70V1
— F. @ DjangoCon Europe (@holdi) May 29, 2018
Doing such a great job explaining Docker that I'm amazed I understand everything! A Wonderful Intro to Docker for Djangonauts by @laceynwilliams at #djangocon🏰 pic.twitter.com/StkDuiDt8w
— daniel rios back from DjangoCon 🏰 (@misterrios) May 25, 2018
Thoroughly enjoying @laceynwilliams's Docker primer at #djangocon - she's clarified several things for me by teaching it like a Hogwarts syllabus. pic.twitter.com/dDDJLOnOF7
— attacus (@attacus_au) May 25, 2018
How beautiful is this. Polyjuice Potion is like #Docker. By @laceynwilliams #djangocon 🏰 pic.twitter.com/7jyOV9Ai8V
— Markus Holtermann (@m_holtermann) May 25, 2018
I'm absolutely delighted to be listening to @laceynwilliams teaching us about docker using the analogy of Polyjuice Potion #djangocon pic.twitter.com/YBC12n24h3
— Katie McLaughlin ✨ (@glasnt) May 25, 2018
Awesome talk @laceynwilliams. I had big expectations of it, and you definitely didn't let me down!
— Lorenzo Peña (@lorinkoz) May 25, 2018