Пример кода, задействованный в этой статье, был синхронно обновлен доРепозиторий HelloGitHub-Team
Предыдущая серия утомительных шагов развертывания была занозой в заднице. Эти боли включают:
- Перейти на сервер для выполнения n команд
- Локальная среда и серверная среда несовместимы. Очевидно, что с локальной операцией проблем нет. После развертывания на сервере она зависает и не может быть запущена.
- Если возникает описанная выше ситуация, перейдите на сервер, чтобы выполнить n команд для решения проблемы.
- Локальный обновленный код, после развертывания в сети снова воспроизводится вышеописанная история, я хочу умереть.
Итак, есть ли способ сделать локальную среду разработки совместимой с онлайн-средой? Таким образом, мы можем проверить локально перед развертыванием и запуском.Пока нет проблем с проверкой, мы можем быть на 99% уверены, что не будет проблем после развертывания и запуска (1% зарезервирован для программной метафизики).
Способ сделать это — использовать Docker.
Docker — это контейнерная технология, которая может предоставить нам изолированную среду выполнения. Чтобы использовать Docker, нам сначала нужно создать образ. Образ используется для описания того, как должна выглядеть изолированная среда, какие зависимости необходимо установить и какие приложения необходимо запустить. Его можно сравнить с производственной схемой грузовое судно.
С помощью образа можно построить в системе настоящую изолированную среду, называемую контейнером, подобно тому, как фабрика делает лодку по проектному чертежу. Заводы также могут строить бесконечное количество таких лодок.
После создания контейнера просто запустите его, и изолированная среда заработает. Поскольку образы упорядочиваются заранее, внутренняя среда работающего контейнера одинакова, независимо от того, находится ли он локально или в сети, поэтому гарантируется согласованность локальной и онлайн-сред, а различные проблемы, вызванные различиями в среде, значительно уменьшаются.
Итак, давайте начнем с оркестровки образа Docker.
Подобно разделению файлов settings.py на local.py и production.py, мы сначала устанавливаем следующую структуру каталогов, которая используется для хранения образа среды разработки и образа онлайн-среды:
HelloDjango-blog-tutorial\
blog\
...
compose\
local\
production\
django\
nginx\
...
Файлы изображений Docker среды разработки хранятся в локальном каталоге, а в папке django под производством хранятся изображения, организованные этим проектом.Поскольку Nginx также используется в онлайн-среде, образы Nginx хранятся в каталоге nginx.
онлайн-среда
файл изображения
Для начала разместим в каталоге production\django файл-зеркало онлайн-окружения блог-проекта, имя файла-зеркала — Dockerfile:
FROM python:3.6-alpine
ENV PYTHONUNBUFFERED 1
RUN apk update \
# Pillow dependencies
&& apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev
WORKDIR /app
RUN pip install pipenv -i https://pypi.douban.com/simple
COPY Pipfile /app/Pipfile
COPY Pipfile.lock /app/Pipfile.lock
RUN pipenv install --system --deploy --ignore-pipfile
COPY . /app
COPY ./compose/production/django/start.sh /start.sh
RUN sed -i 's/\r//' /start.sh
RUN chmod +x /start.sh
Сначала мы используем в начале файла изображенияFROM python:3.6-alpine
Объявите, что этот образ создан на основе базового образа python:3.6-alpine. alpine — это системный дистрибутив Linux, ориентированный на компактность, легкость и безопасность. Для запуска нашей программе требуется среда Python, поэтому используйте этот небольшой, но полный базовый образ Python для создания образа нашего приложения.
ENV PYTHONUNBUFFERED 1
Установите переменную среды PYTHONUNBUFFERED=1.
Следующая команда RUN устанавливает зависимости пакета обработки изображений Pilliow, потому что, если вы используете django для обработки изображений, будет использоваться Python-библиотека Pillow.
Затем используйте WORKDIR /app для установки рабочего каталога, и команды, выполняемые в Docker-контейнере, запущенном на основе этого образа, в дальнейшем будут использовать этот каталог в качестве текущего рабочего каталога.
Затем используем командуRUN pip install pipenv
Чтобы установить pipenv, параметр -i указывает источник pypi, который обычно указывается как источник Douban в Китае, чтобы быстрее загрузить установочный пакет pipenv Параметр -i можно опустить для зарубежных сетей и официального pypi. можно использовать источник.
Затем мы копируем файлы зависимостей проекта Pipfile и Pipfile.lock в контейнер и запускаем pipenv install для установки зависимостей. После указания параметра --system pipenv не будет создавать виртуальную среду, а установит зависимости в среду Python контейнера. Поскольку сам контейнер является виртуальной средой, создавать виртуальную среду не требуется.
Затем скопируйте файлы этого проекта в каталог /app контейнера (конечно некоторые файлы ненужны для запуска программы, поэтому через некоторое время мы установим файл dockerignore, и указанные файлы не будут копироваться в контейнер ).
Затем мы также скопировали файл start.sh в каталог / контейнера, убрали возврат каретки (для окон контейнер — это linux-система) и дали права на выполнение.
Start.sh — это команда для запуска службы Gunicorn:
#!/bin/sh
python manage.py migrate
python manage.py collectstatic --noinput
gunicorn blogproject.wsgi:application -w 4 -k gthread -b 0.0.0.0:8000 --chdir=/app
Мы запустим эту команду при запуске контейнера, который запустит наше приложение django. --chdir=/app указывает, что /app является корневым каталогом, чтобы можно было найти blogproject.wsgi:application.
Создайте файл .dockerignore в корневом каталоге проекта и укажитеНетСкопируйте файлы в контейнер:
.*
_credentials.py
fabfile.py
*.sqlite3
Nginx используется в онлайн-среде, а также устроено зеркало Nginx, которое находится в директории compose\production\nginx:
FROM nginx:1.17.1
# 替换为国内源
RUN mv /etc/apt/sources.list /etc/apt/sources.list.bak
COPY ./compose/production/nginx/sources.list /etc/apt/
RUN apt-get update && apt-get install -y --allow-unauthenticated certbot python-certbot-nginx
RUN rm /etc/nginx/conf.d/default.conf
COPY ./compose/production/nginx/HelloDjango-blog-tutorial.conf /etc/nginx/conf.d/HelloDjango-blog-tutorial.conf
Этот образ построен на основе базового образа nginx:1.17.1, затем мы обновляем систему и устанавливаем certbot для настройки https-сертификатов. Из-за большого количества устанавливаемых зависимостей образ nginx:1.17.1 основан на ubuntu, поэтому установка будет медленной, мы заменим исходник софта на отечественный, что немного улучшит скорость установки.
Наконец, скопируйте конфигурацию nginx приложения в каталог conf.d nginx в контейнере. Содержимое внутри такое же, как и при настройке nginx непосредственно в системе.
upstream hellodjango_blog_tutorial {
server hellodjango_blog_tutorial:8000;
}
server {
server_name hellodjango-blog-tutorial-demo.zmrenwu.com;
location /static {
alias /apps/hellodjango_blog_tutorial/static;
}
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://hellodjango_blog_tutorial;
}
listen 80;
}
По сравнению с предыдущей конфигурацией Nginx непосредственно на хосте, здесь используется upstream-модуль Nginx, который фактически является переадресацией запросов. Nginx перенаправляет все запросы вышестоящему модулю hellodjango_blog_tutorial для обработки, а служба модуля hellodjango_blog_tutorial на самом деле является контейнером hellodjango_blog_tutorial, который запускает приложение django (контейнер будет запущен дальше).
После оркестрации образа контейнер можно построить и запустить из образа. Но подождите, у нас есть два образа, один для приложения django и один для Nginx, что означает, что нам нужно дважды собрать контейнер и дважды запустить контейнер, что будет более проблематично. Есть ли способ собрать его один раз, запустить его одной командой? Ответ заключается в использовании docker-compose.
docker-compose записывает образы каждого контейнера и параметры для сборки и запуска образов контейнеров в файл ymal. Таким образом, мы можем создавать несколько контейнеров с помощью только одной команды сборки и запускать несколько контейнеров с помощью одной команды.
Мы создаем файл production.yml в корневом каталоге проекта, чтобы организовать контейнер django и контейнер nginx.
version: '3'
volumes:
static:
database:
services:
hellodjango_blog_tutorial:
build:
context: .
dockerfile: compose/production/django/Dockerfile
image: hellodjango_blog_tutorial
container_name: hellodjango_blog_tutorial
working_dir: /app
volumes:
- database:/app/database
- static:/app/static
env_file:
- .envs/.production
ports:
- "8000:8000"
command: /start.sh
nginx:
build:
context: .
dockerfile: compose/production/nginx/Dockerfile
image: hellodjango_blog_tutorial_nginx
container_name: hellodjango_blog_tutorial_nginx
volumes:
- static:/apps/hellodjango_blog_tutorial/static
ports:
- "80:80"
- "443:443"
version: '3'
Синтаксис для объявления docker-compose как версии третьего поколения
volumes:
static:
database:
Объявляются два именованных тома данных: статический и база данных. Для чего используется объем данных? Поскольку контейнер Docker является изолированной средой, после удаления контейнера файлы в контейнере будут удалены. Только представьте, если мы запустим контейнер приложения блога и запустим его, через некоторое время база данных в контейнере сгенерирует данные. Позже мы обновили код или модифицировали образ контейнера.В это время нам нужно удалить старый контейнер, а затем пересобрать новый контейнер и запустить его.Тогда база данных в старом контейнере будет удалена вместе с контейнером . . .
Таким образом, мы используем том данных докера для управления данными, которые необходимо постоянно хранить.Пока данные управляются томом данных докера, при запуске нового контейнера он может извлекать данные из тома данных для восстановления данных в удаленном контейнер.
У нас есть 2 данных, которыми нужно управлять с помощью тома данных, один — это файл базы данных, а другой — статический файл приложения. Файлы базы данных просты для понимания, так зачем же статическим файлам нужно управлять объемом данных? Было бы неплохо использовать команду python manage.py collectstatic для повторного сбора после запуска нового контейнера?
Ответ — нет, объемы данных могут не только сохранять данные, но и совместно использовать файлы между контейнерами. Вы должны знать, что контейнеры не только изолированы от хоста, но и изолированы друг от друга. Nginx работает в отдельном контейнере, так откуда берутся статические файлы, которые он обрабатывает? Статические файлы приложения хранятся в контейнере приложения, и контейнер Nginx не может получить к ним доступ, поэтому управление этими файлами также осуществляется через том данных.Контейнер nginx берет статические файлы из тома данных и сопоставляет их с собственным контейнером. .
Затем определяются две службы: одна — служба приложений hellodjango_blog_tutorial, а другая — служба nginx.
build:
context: .
dockerfile: compose/production/django/Dockerfile
Сообщите docker-compose, что контейнер создается на основе текущего каталога (каталога, в котором находится файл yml), а используемый образ — это файл изображения по пути, указанному в dockerfile.
image и container_name дают построенному образу и контейнеру имя соответственно.
work_dir Задает рабочий каталог.
-
volumes: - database:/app/database - static:/app/static
В то же время здесь следует отметить, что объем данных может отображать только папку, а не отдельный файл, поэтому для применяемой нами базы данных мы переместили файл db.sqlite3 в каталог базы данных. Итак, нам нужно изменить конфигурацию базы данных в файле конфигурации django, чтобы он правильно генерировал файл базы данных в папке базы данных в корневом каталоге проекта:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'database', 'db.sqlite3'), } }
-
env_file: - .envs/.production
При запуске контейнера содержимое файла .envs/.production считывается и вставляется в переменные среды.
Давайте создадим этот файл и запишем в него secret_key.
DJANGO_SECRET_KEY=2pe8eih8oah2_2z1=7f84bzme7^bwuto7y&f(#@rgd9ux9mp-3
Будьте осторожны, чтобы добавить эти файлы, содержащие конфиденциальную информацию, в список игнорирования инструментов контроля версий, чтобы предотвратить их случайное размещение в общедоступных репозиториях для публичного просмотра.
-
ports: - "8000:8000"
Откройте порт 8000 в контейнере и привяжите его к порту 8000 хоста, чтобы мы могли получить доступ к контейнеру через порт 8000 хоста.
команда: /start.sh Start.sh будет выполняться при запуске контейнера, тем самым запуская приложение django.
Сервисный контейнер nginx похож, за исключением того, что он берет статические файлы из статического тома данных и сопоставляет их с /apps/hellodjango_blog_tutorial/static в контейнере nginx, поэтому мы находимся в конфигурации nginx:
location /static {
alias /apps/hellodjango_blog_tutorial/static;
}
Это правильно проксировать статические файлы.
Все готово, вместныйВыполните следующие две команды, чтобы создать контейнер и запустить его.
docker-compose -f production.yml build
docker-compose -f production.yml up
На этом этапе мы можем получить доступ к приложениям в контейнере через доменное имя.Конечно, поскольку Nginx работает в контейнере локальной среды, нам нужно изменить локальный файл hosts, чтобы доменное имя можно было преобразовать в локальное IP.
Если проблем с локальным доступом нет, то вы можете напрямую выполнить две вышеуказанные команды на сервере, чтобы таким же образом запустить контейнер, и приложение django будет успешно развернуто на сервисе.
среда разработки
Теперь, когда Docker используется в онлайн-среде, вы можете также использовать Docker для разработки в среде разработки. Файлы образа и docker-compose среды разработки проще, чем онлайн-среда, потому что nginx не используется.
Файл образа среды разработки находится в папке compose\local:
FROM python:3.6-alpine
ENV PYTHONUNBUFFERED 1
RUN apk update \
# Pillow dependencies
&& apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev
WORKDIR /app
RUN pip install pipenv -i https://pypi.douban.com/simple
COPY Pipfile /app/Pipfile
COPY Pipfile.lock /app/Pipfile.lock
RUN pipenv install --system --deploy --ignore-pipfile
COPY ./compose/local/start.sh /start.sh
RUN sed -i 's/\r//' /start.sh
RUN chmod +x /start.sh
Обратите внимание, что в отличие от онлайн-среды, мы не копировали весь код в контейнер. Код онлайн-среды, как правило, относительно стабилен, но для среды разработки из-за необходимости часто изменять и отлаживать код, если мы копируем код в контейнер, модификация кода, сделанная вне контейнера, не может быть обнаружена внутри контейнера, так что приложение, работающее в контейнере, не может быть обнаружено, нет возможности синхронизировать наши изменения. Так что управлять кодом мы будем через том данных Docker.
start.sh больше не запускает gunicorn, а использует runserver для запуска сервера разработки.
#!/bin/sh
python manage.py migrate
python manage.py runserver 0.0.0.0:8000
Затем создайте файл docker-compose local.yml (тот же уровень, что и production.yml) для управления контейнерами разработки.
version: '3'
services:
djang_blog_tutorial_v2_local:
build:
context: .
dockerfile: ./compose/local/Dockerfile
image: django_blog_tutorial_v2_local
container_name: django_blog_tutorial_v2_local
working_dir: /app
volumes:
- .:/app
ports:
- "8000:8000"
command: /start.sh
Обратите внимание, что мы смонтировали файлы в корневом каталоге всего проекта в каталог /app, чтобы изменения в коде могли отражаться в контейнере в режиме реального времени.
Онлайн-развертывание
Если нет проблем с контейнером, работающим локально, нет проблем и с контейнером, работающим в онлайн-среде, потому что теоретически наш онлайн-сервер также создаст ту же среду, что и контейнер, используемый для локального тестирования, поэтому почти наверняка, что пока на нашем сервере есть Docker, наше приложение может работать успешно.
Во-первых, установите Docker в сервисе.Метод установки зависит от системы.Метод очень прост.В качестве примера возьмем CentOS 7.Для других систем см.Официальная документация Докера.
Сначала установите необходимые зависимости:
$ sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
Затем добавьте источник репозитория:
$ sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
Наконец, установите Докер:
$ sudo yum install docker-ce docker-ce-cli containerd.io
Запустите Докер:
$ sudo systemctl start docker
(Игнорируется внешними серверами) Установите ускорение источника Docker (используя источник зеркала, предоставленный daocloud), иначе он будет очень медленным при извлечении зеркала.
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://f1361db2.m.daocloud.io
Запустите hello world в докере, чтобы убедиться, что установка докера прошла успешно:
$ sudo docker run hello-world
Установка Docker прошла успешно, но также установите docker-compose. На самом деле это пакет python, мы можем установить его прямо через pip:
$ pip install docker-compose
Во избежание проблем с разрешениями, которые могут возникнуть при выполнении некоторых команд docker, мы добавляем текущего пользователя системы в группу docker:
$ sudo usermod -aG docker ${USER}
После добавления группы перезапустите оболочку (отключитесь и снова подключитесь, если ssh подключен).
Все готово, остался только восточный ветер!
Готовимся запустить наше приложение в контейнере докеров. Поскольку мы ранее развернули приложение на хосте, давайте сначала остановим связанные службы:
# 停掉 nginx,因为我们将在容器中运行 nginx
$ sudo systemctl stop nginx
# 停掉博客应用
$ supervisorctl stop hellodjango-blog-tutorial -c ~/etc/supervisord.conf
Затем загрузите последний код на сервер, войдите в корневой каталог проекта и создайте файл переменной среды, необходимый для онлайн-среды:
$ mkdir .envs
$ cd .envs
$ vi .production
Запишите секретный ключ онлайн-среды в файл переменной среды .production,
DJANGO_SECRET_KEY=2pe8eih8oah2_2z1=7f84bzme7^bwuto7y&f(#@rgd9ux9mp-3
Сохранить и выйти.
Вернитесь в корневой каталог проекта и запустите команду сборки, чтобы создать образ:
$ docker-compose -f prodcution.yml build
Затем мы можем начать запускать докер-контейнер по построенному образу, но для удобства наш докер-процесс по-прежнему управляется супервизором, давайте изменим конфигурацию приложения блога, чтобы докер-контейнер запускался при его запуске.
Открыть ~ / etc / explorsor / cont.d / hellodjango-blog-tutorial.ini и измените его следующим образом:
[program:hellodjango-blog-tutorial]
command=docker-compose -f production.yml up --build
directory=/home/yangxg/apps/HelloDjango-blog-tutorial
autostart=true
autorestart=unexpected
user=yangxg
stdout_logfile=/home/yangxg/etc/supervisor/var/log/hellodjango-blog-tutorial-stdout.log
stderr_logfile=/home/yangxg/etc/supervisor/var/log/hellodjango-blog-tutorial-stderr.log
Главное заменить предыдущее использование Gunicorn для запуска сервисов на запуск докера.
Измените конфигурацию ini Не забудьте перечитать конфигурацию, чтобы она вступила в силу:
$ supervisorctl -c ~/etc/supervisord.conf
> reread
> start
Docker-контейнер запустился гладко, посетите наш блог. Отказ от подготовки оркестрации изображений эквивалентен развертыванию нашего приложения для блога путем выполнения только одной команды для сборки контейнера и запуска контейнера. Если вы меняете сервер, вам нужно только выполнить команду для сборки образа и снова запустить контейнер, и сервис снова заработает! В этом прелесть докера.
Поскольку Pycharm, IDE, наиболее часто используемая для разработки django, также может очень хорошо интегрировать Docker, теперь я полностью внедрил Docker в свою разработку.У меня беспрецедентный опыт, беспрецедентное удобство и стабильность, и я должен научиться его использовать!
HTTPS
Наконец, поскольку Nginx работает в новом контейнере, необходимо повторно применить и настроить сертификат https, который такой же, как и раньше, за исключением того, что Nginx был на хосте раньше, на этот раз мы запускаем команду certbot в контейнере. . Certbot был установлен при компоновке образа nginx, и вы можете выполнить команду напрямую.Выполните команду в контейнере docker следующим образом:
Сначала просматриваем запущенный контейнер через команду docker ps, запоминаем имя контейнера nginx, а затем выполняем команду в указанном контейнере, используя формат команды docker exec -it container name, поэтому выполняем:
$ docker exec -it nginx certbot --nginx
Введите информацию в соответствии с подсказками.Процесс точно такой же, как развертывание на хосте в предыдущем разделе, и здесь повторяться не будет.
Автоматическое развертывание
Фабрику модифицировать не нужно, поэтому попробуйте выполнить ее локально:
pipenv run fab -H server_ip --prompt-for-login-password -p deploy
Идеально! Пока что наш блог стабильно работает в сети, и один за другим к нам будет приходить все больше людей.Давайте продолжим улучшать его функции!
«Объяснение серии проектов с открытым исходным кодом»——Пусть больше не боятся люди, интересующиеся проектами с открытым исходным кодом, и пусть инициаторы проектов с открытым исходным кодом больше не остаются в одиночестве. Следите за нашими статьями, и вы откроете для себя радости программирования, насколько легко им пользоваться, и узнаете, как легко участвовать в проектах с открытым исходным кодом. Добро пожаловать, чтобы оставить сообщение, чтобы связаться с нами, присоединиться к нам, позволить большему количеству людей влюбиться в открытый исходный код и внести свой вклад в открытый исходный код~