Привет Хабр! Несколько лет я находился в readonly-режиме на сайте Хабрахабр, изредка оставляя комментарии к чужим публикациям, и за несколько недель до нового года, мне захотелось поменять это положение вещей. Этому послужило мое недавнее задание на работе. А когда начал искать информацию, понял, что ее, как всегда, много, написано запутанно и не то что мне хотелось бы найти. А как быть, если этот человек новичок в этом вопросе? Вот и решил попробовать себя на этом поприще. Сделать туториал, который был бы полезен мне в первую очередь.

Поехали.

Уже несколько лет Docker был на слуху у меня, но никак не доводилось с ним поработать. А тут как раз менеджменту захотелось поменять свой стек. Начали говорить такие слова как Docker, контейнеры и облака. Чем не повод изучить что-то новое? Я работаю DevOps инженером на радио. Мой список технологий очень прост: Octopus Deploy + TeamCity + и тележка самописных приложений. Работает безотказно.

В этой статье я хочу поделиться информацией в том виде, в котором мне самому лично хотелось бы ее найти. Цель запустить Docker на Vagrant, создать образ с Django проектом по умолчанию, инициализировать контейнер и достучаться к сайту с основной ОС.

На работе я работаю под Windows. Для начала нам понадобится Chocolatey, чтобы установить необходимые софт.

Установим удобный терминал (cmder), VirtualBox и Vagrant:

C:\> choco install cmder
C:\> choco install vagrant
C:\> choco install virtualbox

Если не хотите использовать Chocolatey, можно поставить все вручную.

Создадим папку для нашего проекта, и добавим в него Vagrantfile файл:

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/xenial64"
  config.vm.network "forwarded_port", guest: 5000, host: 8080, host_ip: "127.0.0.1"
end

Обычно, этот файл можно сгенерировать одной командой vagrant init ubuntu/xenial64. Я добавил одну строчку для переадресации портов между основной и гостевой ОС на виртуальной машине. Это понадобится позже, когда мы захотим зайти на наш сайт, запущенный в контейнере.

Запустим виртуальную машину и подключимся к терминалу с помощью следующих двух Vagrant команд:

vagrant up
vagrant ssh

Мы должны успешно подключиться к терминалу виртуальной машине.

Перейдем к установке Docker:

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"
sudo apt-get update
sudo apt-get install -y docker-ce

Проверим, что Docker установлен успешно и сервис запущен. Выполним следующую команду:

sudo systemctl status docker

Создадим Dockerfile файл со следующим содержанием:

FROM python:latest

ENV PYTHONUNBUFFERED 1

RUN apt-get update
RUN mkdir /code

WORKDIR /code

RUN pip install django==1.11.8
RUN django-admin startproject mysite

RUN python mysite/manage.py migrate
RUN echo "from django.contrib.auth.models import User; User.objects.create_superuser('admin', 'admin@example.com', 'pass')" | python mysite/manage.py shell

ADD . /code/

CMD python mysite/manage.py runserver 0.0.0.0:5000

Мы создали описание будущего образа с Django приложением по умолчанию. В этом описании, мы используем Python образ, и добавляем наших приправ, а именно: установка Django, создание проекта по умолчанию, запуск скриптов для инициализации базы данных и создание админ пользователя.

Давайте соберем образ, выполнив:

sudo docker build -t my/app:latest .

Эта команда подтягивает все необходимые образы из Docker реестра, и добавляет нашу конфигурацию в итоговый с названием my/app.

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

sudo docker images

Это всего лишь навсего образ как класс, который нам необходимо инициализировать. При инициализации мы создаем контейнер (объект). Контейнер это запущенный образ в Docker.

Создаем контейнер на базе нашего образа:

sudo docker run -d -p 5000:5000 my/app

Docker вернет вам сгенерированный уникальный идентификатор (guid) запущенного контейнера. Только что мы запустили наше приложение в контейнере. В команде мы указали Docker произвести сопоставление портов внутри контейнера и внешнего у гостевой ос.

Сверните удаленный терминал, и запустите браузер в основной системе. Перейдите по адресу: http://localhost:8080/

Вы увидите заглавную страницу Django приложения. Вы можете перейти на admin страницу, и войти в контрольную панель с admin/pass данными.

Почему Vagrant? Для экспериментов я никогда не устанавливаю ничего на основную систему, и работаю с виртуальными машинами. Если что-то пошло не так, всегда можно удалить и начать все сначала. Лучшая документация для меня — код.

Вернемся к консоли. Чтобы просмотреть логи, выполните команду:

sudo docker logs <guid контейнера> | head

Команда выведет output консоли, запущенного Django внутреннего сервера. Все то же, что вы видите обычно запустив python manage.py runserver у себя локально.

Выключим контейнер следующей командой:

sudo docker stop <guid контейнера>

Опять возвращаемся к нашему запущенному браузеру в основной системе, и перегружаем вебсайт. Он недоступен.

Когда контейнер остановлен, воспринимайте это как выключенный сервер. Состояние контейнера сохранено, как если бы вы сделали хибейрнет на своем десктопе.

Эта команда выведет список всех инициализированных контейнеров:

sudo docker ps -a

Давайте запустим наш контейнер снова:

sudo docker start <guid контейнера>

Браузер возвращает нам все тот же вебсайт. Можете залогиниться в контрольную панель, создать пользователя, и потом выключить и включить контейнер. Вы увидите, что пользователь сохранен и доступен, когда контейнер снова запущен.

Я специально использовал старую версию Django, чтобы показать следующий момент. Откройте Dockerfile, и отредактируйте его. Уберите версию Django, когда мы его устанавливаем с помощью pip команды.

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

sudo docker build -t my/app:latest .

Заметьте, мы не останавливали запущенный контейнер. Командой выше мы обновили образ, который хранится локально.

Давайте удалим текущий контейнер командой:

sudo docker kill <guid>

И запустим новый контейнер:

sudo docker run -d -p 5000:5000 my/app

Каждый раз, когда вы запускаете новый контейнер на базе образа, Docker генерирует ему уникальный идентификатор, по которому вы можете с ним работать (выключать, включать, подключаться по терминалу и т.д.)

На этом все, давайте подчистим за собой и уберем все лишнее.

Выйдите из SSH сессии в терминале, набрав:

exit

И вы снова у себя в домашней директории основной системы. Vagrant все еще запущен, Docker и ваш контейнер соответственно. Проверить это можно опять же через браузер, убедиться, что сайт еще запущен.

Чтобы удалить запущенную виртуальную машину в Vagrant, запустите:

vagrant halt
vagrant destroy

Первая команда выключает виртуальную машину и сохраняет ее состояние, а вторая производит удаление виртуальной машины из VirtualBox.

Комментарии (23)


  1. onegreyonewhite
    13.12.2017 07:47

    django-приложение в Docker на Vagrant под Windows

    Яйцо в утке, утка в зайце, заяц в шоке…
    Docker работает и под Windows, зачем ещё прослойка? Да и что мешает использовать virtualenv?


    1. stagor Автор
      13.12.2017 08:02

      Прослойку я использовал для того, что если в процессе что-то пойдет не так, всегда можно начать сначала. Это одна причина. Вторая, в силу параноидального менеджмента, доустанавливать необходимые компоненты на основную систему нельзя без администраторов. Да да, DevOps инжинер без административных прав на своем локальном компьютере. Поэтому все эксперименты я провожу на виртуальных машинах, где нет ограничений.

      Почему не virtualenv? В прошлом сталкивался с тем, что редкие пакеты просто отказывались устанавливаться под Windows. И нахожу хорошей практикой всегда запускать приложение в среде, приблеженней к Production.


      1. onegreyonewhite
        13.12.2017 08:12

        Да да, DevOps инжинер без административных прав на своем локальном компьютере.

        Классика кровавого энтерпрайза параноидального менеджмента.
        Так может тогда Docker лишний?


        1. stagor Автор
          13.12.2017 08:15

          Это была инициатива менеджмента. Они хотят поднять новый стек и использовать Docker. Так как я занимался CI/CD процессом на проекте для прошлого стека, меня назначили и на новый стек. Так что, Docker в моем случае обязательное звено.


          1. onegreyonewhite
            13.12.2017 08:19

            Понял вас, спасибо.


            1. stagor Автор
              13.12.2017 08:21

              А так да, забавно получилось. Матрешка.

              Правда это еще что. Вон на митапе пару лет назад парень запускал OpenStack в Vagrant, и потом несколько виртуальных машин уже на самом OpenStack. Было забавно наблюдать.


              1. onegreyonewhite
                13.12.2017 08:27

                несколько виртуальных машин уже на самом OpenStack
                Для полного счастья надо было ещё внутри докер запустить.
                У нас облако на OpenStack, поэтому Vagrant и не используем, зато внутри крутятся gitlab-runner`ы и docker. Так что в принципе мы недалеко от «матрёшки» ушли. Но для локальной разработки используем только tox+virtalenv.


      1. MMik
        13.12.2017 09:01

        На рабочем компьютере менеджментом в виртуальных машинах вам разрешено запускать всё, что угодно, со свободным доступом к корпоративной сети?


        1. stagor Автор
          13.12.2017 12:49

          Получается, что да. Любые сторонние процессы могут быть запущены из директории C:\Dev с ограничениями.


    1. renskiy
      13.12.2017 09:53

      когда начинал экспериментировать с Docker, тоже выбрал связку vagrant + docker inside. Вполне себе неплохая песочница для экспериментов. Правда тогда еще не было «нативной» реализации Docker под Windows/macOS. А ставить docker-machine самому было сложнее, чем воспользоваться vagrant.


      1. renskiy
        13.12.2017 11:30

        Более того, одно время у нас все проекты содержали в корне Vagrantfile в котором полностью описывалась инфраструктура для запуска проекта (включая БД, queue, nginx, uwsgi и пр.) — каждый проект в своей ВМ, каждый компонент в своём Docker контейнере внутри этой ВМ.

        Такой способ позволял легко поднять любой проект на любом хосте, включая компы тестировщиков. А заодно, позволил нам набрать экспертизу использования Docker.

        У нас есть даже история, когда мы ездили к нашему заказчику со своим Mac mini, чтобы развернуть у него тестовый стенд. В таком виде он проработал почти до окончания проекта.


        1. stagor Автор
          13.12.2017 12:53

          Отлично, значит я на правильном пути. Спасибо.


  1. mwizard
    13.12.2017 09:37

    Рассматривался ли вариант с docker-machine вместо vagrant?


    1. stagor Автор
      13.12.2017 12:50

      Не рассматривался, но после этого комментария, обязательно посмотрю. Я только начал во всем этом разбираться. Спасибо.


  1. renskiy
    13.12.2017 10:04

    У vagrant есть встроенный provisioner docker. И для установки Docker внутри гостевой системы достаточно в Vagrantfile прописать такую строчку:

    config.vm.provision "docker"
    

    И в качестве образов для виртуалок лучше подойдут образы из репозитария bento. Пруф.


    1. stagor Автор
      13.12.2017 12:51

      Спасибо за информацию, обязательно посмотрю.


  1. EgorLyutov
    13.12.2017 12:51

    Это мануал про то как запустить docker в декабре 2017? При чем здесь вагрант, чем запуск отличается например от virtualbox?


    1. stagor Автор
      13.12.2017 12:56

      Да, знаю, что поздно. Сам кинулся изучать, а толкового для начинающих не нашел, вот и написал. Запуск ничем не отличается, я воспользовался такой связкой. Вариантов на самом деле много, меня этот устраивает. В Production конечно же все будет настроено по другому.


  1. balyko
    13.12.2017 12:52

    Я в свое время очень огромное, с кучей зависимостей, приложение на Django деплоил под Windows через официальную штуку с bash. Согласен, NodeJS, пакеты в виртуальное окружение, PostgreSQL коряво ставятся до версии 1703 (в итоге PostgreSQL стоял отдельно в системе Windows), однако, начиная с нее все деплоиться аналогично любому Linux дистрибутиву. Если этот компонент Windows включен, то по сути права администратора не должны понадобится. Советую попробовать, хотя бы в качестве эксперимента. Минус только один в этом все — скорость работы. Как показывает практика — Docker быстрее работает.


  1. skymal4ik
    13.12.2017 13:33

    … используя ansible :)
    Шутка шуткой, но возможно, позволит автоматизировать кое-какие вещи, если ещё не используете средств оркестрации. Мы у себя используем для некоторых тестов и обновления своего ПО на виртуалках.


    1. stagor Автор
      13.12.2017 14:06

      Да, я хотел его использовать, но оказалось, что Vagrant требует его инсталяцию на основной ОС. А ждать службы поддержки, когда они мне его поставят, было неохота. Возможно, настою и установят в ближайшее время.


  1. bkv
    15.12.2017 00:32

    Простите за оффтоп, а зачем на радио DevOps? Интерес вполне рабочий, так как сам работаю на радио.


    1. stagor Автор
      15.12.2017 00:34

      У нас несколько вебсайтов, корпоративный вебсайт, много сторонних сервисов для статистики. В CI/CD pipeline сейчас около 20 проектов, которые деплоятся несколько раз в неделю.