Знакомство с Docker. Проверка работоспособности бэкапа
Очень хотелось немного познакомиться с замечательным инструментом для виртуализации - Docker. Раньше, когда его не было, бал правила связка Vagrant + VirtualBox. Но сейчас в моде Docker, я считаю, заслуженно. В этом посте я попытаюсь научиться использовать Docker для проверки работоспособности бэкапов. В качестве подопытных выбрал Django и PostgreSQL.
В моем понимании, Docker - это средство виртуализации, в отличие от Vagrant, который является менеджером средств виртуализации. Подробнее о различиях между Vagrant+VirtualBox и Docker здесь.
В отличие от VirtualBox, Docker работает с контейнерами, а не с полноценными виртуальными машинами, последние более "тяжеловесны" и зачастую избыточны для простого разработчика:
Я буду работать с 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
Структура проекта следующая:
Теперь можно создать наш 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 проект:
А если что-то пошло не так, и Вы хотите начать все заново, то эта команда удалит все изображения и контейнеры:
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/ будет доступна внутри контейнера.
Структура:
Также, последние две строчки в 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"
Теперь создадим книжку через админку:
Теперь сделаем бэкап базы, выполнив команду в соответствующем контейнере:
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, Dockerfile, docker-compose, также научился проверять работоспособность бэкапов.