Статьи

Как автоматизировать развертывание приложений на Alibaba ECS с помощью Mina

Эта статья была создана в сотрудничестве с Alibaba Cloud . Спасибо за поддержку партнеров, которые делают возможным использование SitePoint.

У вас есть совет, как использовать облачные сервисы Alibaba максимально эффективно? Если это так, сообщите нам об этом в нашем Сообществе SitePoint .

Mina — это инструмент автоматизации развертывания и генератор сценариев развертывания Bash из мира Rails, который оказался в центре внимания после того, как компании-разработчики заметили его преимущества перед Capistrano. Mina, в отличие от Capistrano, использует только одно SSH-соединение с сервером развертывания и выполняет там пакет команд bash. Это делает его намного быстрее, чем Capistrano, который открывает отдельный сеанс SSH для каждой команды.

В этой статье мы рассмотрим настройку Mina для развертывания базового приложения Django — неортодоксального набора инструментов для мира Django, который чаще использует Docker или Fabric. Учитывая простоту и гибкость Mina, мы считаем, что стоит изучить ее использование при развертывании веб-приложений Python.

Django , « веб-фреймворк для перфекционистов со сроками исполнения », существует уже некоторое время. Он начинался как веб-инфраструктура, ориентированная на управление контентом, созданная собственными силами веб-разработчиками в Lawrence Journal World для своего новостного веб-портала. Он был опубликован в 2005 году, и оттуда он взлетел, а остальное уже история. Он стал одним из самых серьезных, широко распространенных веб-фреймворков, конкурирующих с Ruby on Rails. Он используется Instagram, Disqus, Washington Times, Mozilla, Bitbucket и другими. Это все еще процветает.

Django docs предлагает Apache с mod-wsgi в качестве первого варианта, и это может быть распространенным вариантом. Но так как мы одержимы производительностью, в этом руководстве мы решили охватить развертывание приложения Django в облачном экземпляре ECS Alibaba со стеком NGINX и uWSGI.

NGINX — это веб-сервер, известный своей эффективностью, основанный на событиях, который включает в себя опции кэширования, поэтому он часто является идеальным решением. uWSGI — это контейнер сервера приложений — реализация WSGI , стандартного веб-интерфейса Python. Он очень хорошо сочетается с NGINX.

Начиная

Прежде чем начать, вам необходимо зарегистрировать учетную запись Alibaba Cloud . Начать работу с Alibaba Cloud очень просто и решить, подходит ли вам этот выбор, поскольку его бесплатная пробная версия предоставляет новым пользователям 300 долларов США . После того как вы зарегистрировались и получили кредит, вы можете изучить ресурсы по началу работы по ряду тем.

Первое, что мы сделаем после настройки нашей учетной записи, — это создадим экземпляр ECS в бэкэнд-консоли Alibaba Cloud.

Процесс прост. Мы выберем Ubuntu 16.04 LTS для нашей операционной системы / образа ОС. После создания мы хотим убедиться, что наш экземпляр назначен соответствующим группам безопасности. В терминологии Alibaba это правила брандмауэра для разных портов. Обычно это то, что работает по умолчанию, но в случае каких-либо проблем с доступом к нашему экземпляру через Интернет, обязательно отметьте это.

Доступ к странице групп безопасности можно получить через подменю Elastic Compute Service слева.

Следующее, что нужно сделать при создании нашего экземпляра, это настроить его для доступа по SSH-ключу.

Возможно, самый простой способ сделать это — создать экземпляр при создании с помощью пароля. Затем мы можем просто сделать стандартный ssh-copy-id из нашей стартовой системы — предположительно, локальное устройство.

ssh-copy-id root@xxx.xxx.xxx.xxx , выполненный с нашего локального устройства (где мы заменим последовательность xxx… нашим публичным IP-адресом экземпляра Alibaba ECS), запросит у нас пароль и после его ввода: наш ключ доступа должен быть настроен.

Когда мы войдем в наш экземпляр через ssh, мы выполним apt-get update чтобы убедиться, что наши исходники apt обновлены, а затем установим git, curl, wget: apt-get install git curl wget -y

Установка серверной среды

Версия Python по умолчанию, которая поставляется по умолчанию с Ubuntu 16.04 LTS — это древняя версия 2.7. Чтобы запустить последнюю версию Django, нам нужен Python 3+. Один из менее болезненных способов исправить это — установить pyenv , менеджер версий Python.

Это позволяет нам изменять версию Python, используемую глобально, или для каждого проекта. Перед установкой pyenv, согласно вики pyenv , мы установим необходимые условия:

apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev liblzma-dev zlib1g-dev libffi-dev

Тогда мы можем установить pyenv:

curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash

После завершения установщик pyenv предложит нам добавить пару строк в ~ / .bash_profile, что мы и сделаем:

Теперь мы обновляем PATH в нашей рабочей сессии, выполняя source ~/.bash_profile в нашем терминале.

При условии, что мы сделали это правильно, теперь мы можем установить Python версии 3.7.0:

Выполнение pyenv versions в серверном терминале должно показать нам два элемента: system и 3.7.0 , при условии, что мы успешно установили версию 3.7.0.

pyenv global 3.7.0 сделает нашу версию 3.7.0 глобальной версией python в нашей системе. Если у вас есть проблемы с pyenv, это URL для посещения .

Стек сервера

Обычное значение по умолчанию для образов Ubuntu — сервер Apache, который поставляется с предустановленной версией. Если он работает, мы должны остановить его с помощью service apache2 stop , а затем установить nginx с помощью apt-get install nginx -y . Это должно установить и запустить сервер NGINX, который должен быть виден, когда мы посещаем публичный IP-адрес нашего сервера.

Мы также установим uWSGI: pip install uwsgi (Python pip предположительно устанавливается, когда мы установили pyenv).

Мы также убедимся, что у нас установлен Django: pip install django . Мы могли бы использовать virtualenv для обеспечения изолированной среды для нашего приложения, но ради простоты этого урока мы пропустим его.

В более сложных случаях, тем не менее, это, вероятно, мудрый выбор.

В этом руководстве предполагается, что мы направили записи A нашего домена на IP-адрес нашего сервера, поэтому в оставшейся части этого руководства предполагается, что myxydomain.com будет myxydomain.com IP-адрес нашего сервера ECS.

Теперь мы создадим виртуальный хост NGINX для нашего сайта. Файл можно найти здесь . Мы просто рассмотрим пару вещей:

server unix:///tmp/minaguide.sock;

Здесь мы подключаемся — с NGINX — к сокету Unix, который uWSGI создаст в каталоге /tmp , и /tmp рекомендуется для других возможных осложнений разрешений, которые могут возникнуть из-за более сложного дерева каталогов. Вот для чего /tmp .

include /root/project/minaguide/uwsgi/uwsgi_params;

Этот ( /root/project/minaguide ) является каталогом нашего проекта django на сервере, и в нем у нас будет подкаталог uwsgi с файлом uwsgi_params , который будет содержать некоторые переменные uWSGI. Мы вернемся к этому позже и к настройке нашего приложения uWSGI.

Теперь у нас есть базовая серверная среда, необходимая для развертывания.

Настройка Мина

Мы настраиваем Mina на машине, с которой мы выполняем развертывание. Предполагая, что устройство также является Linux / Ubuntu (и для пользователей Mac не должно быть особых различий — и для пользователей Windows, если они используют подсистему Windows для Linux ), мы хотим убедиться, что у нас установлены Ruby и rubygems — apt-get install ruby -y должен сделать свое дело.

Когда мы сделаем это, у нас будет доступна команда gem , поэтому мы выполним gem install mina .

Теперь — также на нашей локальной машине — мы создадим каталог, посвященный нашему проекту, и сделаем там mina init .

Это создает файл config/deploy.rb каталоге нашего проекта, который мы отредактируем для настройки Mina:

 require 'mina/rails' require 'mina/git' # we fill our base variables here. In this case, using # ENV['domain'], we dont really need to enter the domain into the file, as # we will be passing it when we call mina in command line. # the script presumes we have set up ssh-key access to server, and that it won't ask us # for password (for 'root' user) set :application_name, 'minaguide' set :domain, ENV['domain'] set :deploy_to, '/root/project/minaguide' set :repository, 'https://github.com/tyaakow/django-uwsgi-starter.git' set :branch, 'master' set :user, 'root' # we have left this empty, but this can be used for choosing pyenv python version, like we # did manually task :remote_environment do end # here we put any custom commands you need to run at setup # directory structure from :deploy_to will be created task :setup do # we are pulling rc.local from a gist, in order to make daemonize uWSGI # and make it boot with the system comment "pulling rc.local to /etc/ ..." command %{wget -P /etc/ https://gist.githubusercontent.com/tyaakow/62a5f91dbf59b32e088ec15c8375ca76/raw/c0c864317888419cbb9f2c4311149649cea2be1a/rc.local} comment "making it executable..." command %{sudo chmod 755 /etc/rc.local} comment "removing existing virtualhosts from /etc/nginx/sites-enabled/ ..." command %{rm /etc/nginx/sites-enabled/*} comment "fetching the virtualhost file from github gist..." command %{wget -O /etc/nginx/sites-enabled/#{ENV['domain']} https://gist.githubusercontent.com/tyaakow/1cd0a30095000c11301d3359b13a3537/raw/197eb92160588c2e61818a90e28782a344e5fbae/myxydomain.conf } comment "replacing the myxydomain.com with the actual domain specified in deploy.rb..." command %{sed -i 's/myxydomain.com/#{ENV['domain']}/g' /etc/nginx/sites-enabled/#{ENV['domain']}} end desc "Deploys the current version to the server." task :deploy do deploy do invoke :'git:clone' on :launch do command %{sed -i 's/myxydomain.com/#{ENV['domain']}/g' /root/project/minaguide/current/minaguide/settings.py} command %{uwsgi --emperor /root/project/minaguide/current/uwsgi/vassals --daemonize /var/log/uwsgi-emperor.log} command %{service nginx restart} end end end 

В этом файле мы видим, что мы используем Ruby-интерполяцию строк (синтаксис #{} ).

Мы также используем sed для программной замены текста в файлах ( sed -i 's/myxydomain.com/#{ENV['domain']}/g' /root/project/minaguide/current/minaguide/settings.py ) и мы используем ENV['domain'] который нужно передать Mina из командной строки. Это иллюстрирует приемы построения некоторых (возможно, более сложных) сценариев с Миной.

task :setup do — это синтаксис, который мы можем использовать для определения произвольного числа задач.

Как указано в документации Mina , мы можем использовать переменные символьного синтаксиса, назначенные с помощью set в начале файла — с синтаксисом fetch(:deploy_to) .

Файл можно найти здесь .

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

 task :deploy do run(:local) do 

… Где мы будем запускать rsync или scp — или мы могли бы получить его из частного репозитория, для которого требовался доступ по ssh-ключу.

Мы могли бы пойти дальше и создать задачи для установки всей среды, но мы быстро вырвались бы за рамки этого руководства.

Мы добавили каталог uwsgi в наше стандартное приложение Django в django-admin startproject minaguide созданный командой django-admin startproject minaguide :

… Где uwsgi_params с этой страницы , а uwsgi.ini содержит основные настройки uWSGI.

В нашем скрипте deploy.rb мы извлекаем файл виртуального хоста для NGINX из этого списка GitHub и помещаем его в /etc/nginx/sites-enabled/ :

 # the upstream component nginx needs to connect to upstream django { server unix:///tmp/minaguide.sock; #this file will be created by uWSGI } # configuration of the server server { # the port your site will be served on listen 80; # the domain name it will serve for server_name myxydomain.com; # will be substituted, with sed, with actual domain name provided # to mina at command line charset utf-8; # max upload size client_max_body_size 75M; # adjust to taste # Django media location /media { alias /root/project/minaguide/current/media; # your Django project's media files - amend as required } location /static { alias /root/project/minaguide/current/static; # your Django project's static files - amend as required } # Finally, send all non-media requests to the Django server. location / { uwsgi_pass django; include /root/project/minaguide/current/uwsgi/uwsgi_params; # the uwsgi_params file # from https://github.com/nginx/nginx/blob/master/conf/uwsgi_params } } 

Подробнее о развертывании Django с помощью uWSGI и NGINX можно узнать здесь .

развертывание

Теперь, когда мы захотим выполнить развертывание, мы позвоним из нашей локальной системы / системы разработки mina setup domain=myfabulousdomain.com — где мы myfabulousdomain.com URL-адресом нашего фактического сервера, на котором мы будем развертывать. Затем Mina будет использовать его в качестве вышеупомянутого ENV['domain'] .

Это выполнит задачу setup на нашем сервере.

mina deploy domain=myfabulousdomain.com мы выполним задачу / блок deploy . Когда мы посещаем наш домен, мы должны видеть следующее:

Если во время развертывания у нас возникают проблемы с файлом сокета (проблемы с правами доступа и владельцем и т. Д.), И у нас нет времени на его исправление — самое быстрое решение — это, возможно, перейти от подключения NGINX к сокету uWSGI к его подключению к uWSGI через http — uWSGI имеет --http и --http-socket (нам нужно изменить детали соединения с http:://127.0.0.1:8080 upstream django / server в файле виртуального хоста nginx — чтобы подключиться к чему-то вроде http:://127.0.0.1:8080 — и измените нашу команду uWSGI соответствующим образом.

Больше информации о параметрах --http и --http-socket здесь и здесь . uWSGI — довольно большая тема.

Вывод

В этой статье мы используем mina — довольно простое, очень гибкое и очень быстрое решение для развертывания приложений. В случае более сложных установок, которые требуют более комплексных решений — нам может потребоваться автоматизировать более широкий спектр деталей конфигурации системы и стека — мы можем захотеть взглянуть на контейнерную службу Alibaba — которая направлена ​​на предоставление решений для оптимизации различных сценариев DevOps. Реестр контейнеров позволяет использовать более сложные сценарии.

В случае, если нашему продукту / услуге требуется несколько экземпляров ECS, мы также захотим изучить балансировщик нагрузки на сервер Alibaba, который позволяет динамически масштабировать нашу инфраструктуру, чтобы не отставать от трафика. Другим продуктом или функцией Alibaba, которую следует рассмотреть здесь, является автоматическое масштабирование, которое автоматически развертывает новые экземпляры либо в соответствии с заранее определенным расписанием, либо на основе мониторинга, например использования ЦП и памяти работающих экземпляров.

Функция Compute позволяет нам, напротив, сосредоточиться на нашей бизнес-логике, передавая всю инфраструктуру и заботы об окружающей среде в облако. Служба управляется событиями, может запускаться другими службами, и все, что мы делаем, это загружаем наш код (NodeJS, Python, Java). Мы платим за фактически выполненный код.

Тогда есть целый ряд продуктов / услуг безопасности, CDN и решений для мониторинга