Изображение гика

Блог питониста

Знакомство с Docker. Проверка работоспособности бэкапа

10 августа 2018 г.

Очень хотелось немного познакомиться с замечательным инструментом для виртуализации - Docker. Раньше, когда его не было, бал правила связка Vagrant + VirtualBox. Но сейчас в моде Docker, я считаю, заслуженно. В этом посте я попытаюсь научиться использовать Docker для проверки работоспособности бэкапов. В качестве подопытных выбрал Django и PostgreSQL.

В моем понимании, Docker - это средство виртуализации, в отличие от Vagrant, который является менеджером средств виртуализации. Подробнее о различиях между Vagrant+VirtualBox и Docker здесь.

В отличие от VirtualBox, Docker работает с контейнерами, а не с полноценными виртуальными машинами, последние более "тяжеловесны" и зачастую избыточны для простого разработчика:

docker.png

Я буду работать с Docker под убунтой, потому что при работе в Windows с Docker могут быть проблемы, связанные с кастомными файерволлами (например Zone Alarm у меня иногда блокировал Docker'у создание виртуальной машины). Начнем с установки Docker CE:

sudo apt-get update

Необходимые пакеты:

sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common

Добавляем GPG - ключ:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

Добавляем репозиторий:

sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

Ставим Docker CE:

sudo apt-get update && sudo apt-get install docker-ce

Проверяем:

docker -v
Docker version 18.06.0-ce, build 0ffa825

Проверить также можно следующим способом:

sudo docker run hello-world

Должен был создаться контейнер:

sudo docker ps --all
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
ea5cd0059eda        hello-world         "/hello"            5 seconds ago       Exited (0) 2 seconds ago                       awesome_mclean

Теперь, когда Docker установлен, можно создать базовое Django - приложение. Наш первый шаг - это запустить Django проект из-под Docker. Создадим Django проект:

pip install Django==2.1

django-admin startproject djangotest

Затем, в корень проекта необходимо добавить Dockerfile, который будет описывать изображение (image):

# контейнер будет работать на python alpine image
FROM python:alpine

# Меняем рабочую директорию в контейнере
WORKDIR /app

# Копируем весь код из папки проекта в директории в контейнере
ADD . /app

# Устанавливаем зависимости
RUN apk update && apk add postgresql-dev gcc python3-dev musl-dev jpeg-dev zlib-dev
RUN pip install psycopg2-binary
RUN pip install -r requirements.txt

# Делаем 8000 порт контейнера доступным
EXPOSE 8000

# Запускаем проект в контейнере
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

Добавим файл зависимостей requirements.txt следующего содержания:

Django==2.1
psycopg2>=2.7.3.1

Структура проекта следующая:

docker_study_3_2.png

Теперь можно создать наш image, находясь в корне проекта djangotest:

sudo docker build -t djangotest .

Посмотрим, создалось ли image:

sudo docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
djangotest          latest              a84a45689063        2 minutes ago       79.4MB
python              alpine              a5f497d596f5        6 days ago          79.4MB
hello-world         latest              2cb0d9787c4d        4 weeks ago         1.85kB

Как видно, изображение djangotest появилось в списке, это хорошо, теперь можно поднять контейнер (находясь в корневой папке проекта):

sudo docker run -p 4000:8000 djangotest

Если все ок, то теперь можно перейти на localhost:4000 и увидеть работающий django проект:

docker_study_2.png

А если что-то пошло не так, и Вы хотите начать все заново, то эта команда удалит все изображения и контейнеры:

sudo docker system prune -a

Если же все ок, то перейдем к следующему шагу - создание простой модели и добавление ее в админку:

python manage.py startapp books

books.models:

1 from __future__ import unicode_literals
2 
3 from django.db import models
4 
5 
6 class Book(models.Model):
7     title = models.CharField(max_length=200)

books.admin:

1 from django.contrib import admin
2 from .models import Book
3 
4 
5 class BookAdmin(admin.ModelAdmin):
6     fields = ('title',)
7 
8 
9 admin.site.register(Book, BookAdmin)

djangotest.settings:

 1 """
 2 Django settings for djangotest project.
 3 
 4 Generated by 'django-admin startproject' using Django 1.9.1.
 5 
 6 For more information on this file, see
 7 https://docs.djangoproject.com/en/1.9/topics/settings/
 8 
 9 For the full list of settings and their values, see
10 https://docs.djangoproject.com/en/1.9/ref/settings/
11 """
12 
13 import os
14 
15 # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
16 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17 
18 
19 # Quick-start development settings - unsuitable for production
20 # See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/
21 
22 # SECURITY WARNING: keep the secret key used in production secret!
23 SECRET_KEY = '%6-n@(u0ojz^9o+03dlxu0+u_x%ki7-8vw8n@ialuv&b4uwm$$'
24 
25 # SECURITY WARNING: don't run with debug turned on in production!
26 DEBUG = True
27 
28 ALLOWED_HOSTS = []
29 
30 
31 # Application definition
32 
33 INSTALLED_APPS = [
34     'books',
35     'django.contrib.admin',
36     'django.contrib.auth',
37     'django.contrib.contenttypes',
38     'django.contrib.sessions',
39     'django.contrib.messages',
40     'django.contrib.staticfiles',
41 ]
42 ...
43 
44 DATABASES = {
45     'default': {
46         'ENGINE': 'django.db.backends.postgresql',
47         'NAME': 'djangotest',
48         'USER': 'djangotest',
49         'PASSWORD': 'password',
50         'HOST': 'db',
51         'PORT': '5432',
52     }
53 }
54 ...

На стр. 34 добавил books в INSTALLED_APPS, а также поменял на стр. 44 настройки БД на PostreSQL.

Следующий шаг - запустить в двух контейнерах связку Django + PostgreSQL и создать несколько книг через админку. Для этого понадобится docker-compose, эта утилита позволит нам создать сразу два контейнера: один для Django, другой для PostgreSQL. Установим docker-compose:

sudo curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose

sudo chmod +x /usr/local/bin/docker-compose

Проверим:

docker-compose --version
docker-compose version 1.22.0, build f46880fe

Создадим файл docker-compose.yml в корне проекта:

 1 # docker-compose.yml
 2 
 3 version: '3'
 4 
 5 services:
 6   db:
 7     image: postgres
 8     volumes:
 9       - /home/username/backup/:/tmp
10     environment:
11       POSTGRES_DB: djangotest
12       POSTGRES_USER: djangotest
13       POSTGRES_PASSWORD: password
14   web:
15     build: .
16     image: django
17     command: python manage.py runserver 0.0.0.0:8000
18     volumes:
19       - .:/app
20     ports:
21       - "4000:8000"
22     depends_on:
23       - db

Заметьте, что файл docker-compose.yml зависит от Dockerfile через эту строчку (15 строка):

build: .

А также, на строке 9 задается то, что папка хоста /home/username/backup/ будет "проброшена" в папку /tmp в контейнер djangotest_web_1. То есть папка /home/username/backup/ будет доступна внутри контейнера.

Структура:

docker_study_4_3.png

Также, последние две строчки в Dockerfile можно закомментировать, потому что эти действия теперь описаны в файле docker-compose.yml:

# Dockerfile

# python alpine image
FROM python:alpine

# Set the working directory to /app
WORKDIR /app

# Copy the current directory contents into the container at /app
ADD . /app

# Install any needed packages specified in requirements.txt
RUN apk update && apk add postgresql-dev gcc python3-dev musl-dev jpeg-dev zlib-dev
RUN pip install psycopg2-binary
RUN pip install -r requirements.txt

# Make port 8000 available to the world outside this container
# EXPOSE 8000

# Run app.py when the container launches
# CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

Собираем контейнеры:

sudo docker-compose build

Запускаем:

sudo docker-compose up

По идее, все должно подняться, но если что-то не так, то можно сначала посмотреть список контейнеров:

sudo docker ps

А затем зайти внутрь контейнера:

sudo docker exec -it <container name> sh

В результате будет создано и запущено два контейнера: djnagotest_web_1 для Djnago и djangotest_db_1 для PostgreSQL. Далее, применим миграции:

username@comp:~$ sudo docker exec -it djangotest_web_1 sh -c "python manage.py makemigrations"
Migrations for 'books':
  books/migrations/0001_initial.py
    - Create model Book
username@comp:~$ sudo docker exec -it djangotest_web_1 sh -c "python manage.py migrate"
Operations to perform:
  Apply all migrations: admin, auth, books, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying books.0001_initial... OK
  Applying sessions.0001_initial... OK

Создадим пользователя:

sudo docker exec -it djangotest_web_1 sh -c "python manage.py createsuperuser"

Теперь создадим книжку через админку:

docker_2.png

Теперь сделаем бэкап базы, выполнив команду в соответствующем контейнере:

sudo docker exec -it djangotest_db_1 sh -c "pg_dump -U postgres djangotest > djangotest_db.bak"

В результате, в контейнере djangotest_db_1 в папке / (в корневой) должен появиться файл бэкапа djangotest_db.bak. Теперь скопирую файл бэкапа на хост. Команда для копирования:

docker cp <containerId>:/file/path/within/container /host/path/target

В нашем случае:

sudo docker cp djangotest_db_1:/djangotest_db.bak /home/username/backup/djangotest_db.bak

Теперь для чистоты эксперимента удалю изображения и контейнеры:

sudo docker system prune -a

Затем заново:

sudo docker-compose build
sudo docker-compose up

И, теперь, восстановим бэкап, используя ранее сохраненный файл:

sudo docker exec -ti djangotest_db_1 sh -c "cat /tmp/djangotest_db.bak | psql djangotest -U djangotest"

Все получилось!

docker_3.png

Выводы


Надеюсь, я смог на базовом уровне разобраться с docker, Dockerfile, docker-compose, также научился проверять работоспособность бэкапов.

Метки

DevOps Django Docker
Если вам понравился пост, можете поделиться им в соцсетях: