Como utilizar a plataforma Heroku para deploy de aplicações
Heroku é atualmente uma das melhores opções PaaS ( Plataform as a Service ) para desenvolvedores fazerem o deploy de suas aplicações. Essa plataforma é muito utilizada nas startups porque facilita muito o gerenciamento de infraestrutura, monitoração de disco, cpu, memória e entre outros.
Nesse post vou mostrar como utilizo essa plataforma para fazer o deploy dos meus projetos pessoais em ambientes production-like.
A preparação
O código fonte da aplicação está publicado no link abaixo:
https://github.com/Responsus/TerminusNG
Essa aplicação é uma versão um pouco melhorada do meu tcc da faculdade, que foi um sistema para gerenciamento de projetos. Inicialmente esse sistema foi escrito com um framework chamado Pyramid e nessa nova versão foi escrita com o microframework Flask.
O Heroku possui vários planos que podem ser usados, eu uso o plano free, que disponibiliza um container com apenas 1 Worker e desliga após 30 minutos de inatividade, que é o suficiente para testar aplicações em ambientes não produção.
Todos os planos estão disponíveis no link abaixo:
https://www.heroku.com/pricing
Crie sua primeira aplicação
Agora, o primeiro passo é criar uma conta no Heroku.
https://signup.heroku.com/login
Após a sua conta criada, crie um novo app, clicando no botão New no topo da página conforme a imagem abaixo:

Ao criar o novo app, dê um nome único a ele.

Após a criação do seu app, você será redirecionado para uma outra página e nela clique em Settings, logo abaixo você encontrará um link para o seu repositório no Heroku, salve esse link que será usado mais a frente.
Instalação do client Heroku
Agora é necessário instalar o heroku-cli na máquina para publicar o projeto.
Nesse link temos todos os links para download em vários sistemas operacionais.
https://devcenter.heroku.com/articles/heroku-cli
Eu instalei a versão para windows, então os exemplos que vou usar em diante serão digitados usando o Windows Powershell.
Abaixo uma lista dos comandos disponíveis para o Heroku-cli.
01 | PS C:\Users\1511 MXTI\Documents& gt ; heroku --help |
04 | Help topics, type heroku help TOPIC for more details: |
06 | access manage user access to apps |
07 | addons tools and services for developing, extending, and operating your app |
09 | auth heroku authentication |
10 | authorizations OAuth authorizations |
11 | buildpacks manage the buildpacks for an app |
12 | certs a topic for the ssl plugin |
13 | ci run an application test suite on Heroku |
14 | clients OAuth clients on the platform |
15 | config manage app config vars |
16 | container Use containers to build and deploy Heroku apps |
17 | domains manage the domains for an app |
18 | drains list all log drains |
19 | features manage optional features |
20 | git manage local git repository for app |
22 | labs experimental features |
23 | local run heroku app locally |
24 | logs display recent log output |
25 | maintenance manage maintenance mode for an app |
26 | members manage organization members |
27 | notifications display notifications |
28 | orgs manage organizations |
29 | pg manage postgresql databases |
30 | pipelines manage collections of apps in pipelines |
31 | plugins manage plugins |
32 | ps manage dynos (dynos, workers) |
33 | redis manage heroku redis instances |
34 | regions list available regions |
35 | releases manage app releases |
36 | run run a one-off process inside a Heroku dyno |
37 | sessions OAuth sessions |
38 | spaces manage heroku private spaces |
39 | status status of the Heroku platform |
42 | webhooks setup HTTP notifications of app activity |
Primeiro vou fazer o git clone da aplicação.
2 | Cloning into 'TerminusNG' ... |
3 | remote: Counting objects: 816, done . |
4 | remote: Compressing objects: 100% (23/23), done . |
5 | remote: Total 816 (delta 14), reused 21 (delta 10), pack-reused 783 |
6 | Receiving objects: 100% (816/816), 4.21 MiB | 422.00 KiB/s, done . |
7 | Resolving deltas: 100% (130/130), done . |
8 | PS C:\Users\1511 MXTI& gt ; |
Com a aplicação já clonada, entrei no diretório e fiz o login do heroku:
1 | PS C:\Users\1511 MXTI& gt ; cd .\TerminusNG\ |
2 | PS C:\Users\1511 MXTI\TerminusNG& gt ; heroku login |
3 | Enter your Heroku credentials: |
4 | Email: alisson.copyleft@gmail.com |
5 | Password: ***************** |
6 | Logged in as alisson.copyleft@gmail.com |
7 | PS C:\Users\1511 MXTI\TerminusNG& gt ; |
Agora adicione o repositório copiado do heroku nos passos anteriores.
2 | PS C:\Users\1511 MXTI\TerminusNG& gt ; |
Após adicionado o heroku como remote, foi feito um push para esse repositório:
01 | PS C:\Users\1511 MXTI\TerminusNG& gt ; git add --all |
02 | PS C:\Users\1511 MXTI\TerminusNG& gt ; git commit -m "deploy heroku" |
04 | Your branch is up to date with 'origin/master' . |
06 | nothing to commit, working tree clean |
07 | PS C:\Users\1511 MXTI\TerminusNG& gt ; git push heroku |
08 | Counting objects: 816, done . |
09 | Delta compression using up to 8 threads. |
10 | Compressing objects: 100% (645/645), done . |
11 | Writing objects: 100% (816/816), 4.21 MiB | 59.00 KiB/s, done . |
12 | Total 816 (delta 130), reused 816 (delta 130) |
A saida do comando será parecida com essa:
01 | remote: Compressing source files... done . |
02 | remote: Building source : |
04 | remote: -----& gt ; Python app detected |
05 | remote: -----& gt ; Installing python-3.6.4 |
06 | remote: -----& gt ; Installing pip |
07 | remote: -----& gt ; Installing requirements with pip |
08 | remote: Collecting Flask (from -r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 1)) |
09 | remote: Downloading Flask-0.12.2-py2.py3-none-any.whl (83kB) |
10 | remote: Collecting Flask_SQLAlchemy (from -r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 2)) |
11 | remote: Downloading Flask_SQLAlchemy-2.3.2-py2.py3-none-any.whl |
12 | remote: Collecting gunicorn (from -r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 3)) |
13 | remote: Downloading gunicorn-19.7.1-py2.py3-none-any.whl (111kB) |
14 | remote: Collecting flask-security (from -r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 4)) |
15 | remote: Downloading Flask_Security-3.0.0-py2.py3-none-any.whl (68kB) |
16 | remote: Collecting flask-mongoengine (from -r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 5)) |
17 | remote: Downloading flask-mongoengine-0.9.3. tar .gz (111kB) |
18 | remote: Collecting bcrypt (from -r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 6)) |
19 | remote: Downloading bcrypt-3.1.4-cp36-cp36m-manylinux1_x86_64.whl (54kB) |
20 | remote: Collecting itsdangerous& gt ;=0.21 (from Flask-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 1)) |
21 | remote: Downloading itsdangerous-0.24. tar .gz (46kB) |
22 | remote: Collecting click& gt ;=2.0 (from Flask-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 1)) |
23 | remote: Downloading click-6.7-py2.py3-none-any.whl (71kB) |
24 | remote: Collecting Jinja2& gt ;=2.4 (from Flask-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 1)) |
25 | remote: Downloading Jinja2-2.10-py2.py3-none-any.whl (126kB) |
26 | remote: Collecting Werkzeug& gt ;=0.7 (from Flask-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 1)) |
27 | remote: Downloading Werkzeug-0.14.1-py2.py3-none-any.whl (322kB) |
28 | remote: Collecting SQLAlchemy& gt ;=0.8.0 (from Flask_SQLAlchemy-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 2)) |
29 | remote: Downloading SQLAlchemy-1.2.0. tar .gz (5.5MB) |
30 | remote: Collecting passlib& gt ;=1.7 (from flask-security-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 4)) |
31 | remote: Downloading passlib-1.7.1-py2.py3-none-any.whl (498kB) |
32 | remote: Collecting Flask-Login& gt ;=0.3.0 (from flask-security-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 4)) |
33 | remote: Downloading Flask-Login-0.4.1. tar .gz |
34 | remote: Collecting Flask-Mail& gt ;=0.7.3 (from flask-security-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 4)) |
35 | remote: Downloading Flask-Mail-0.9.1. tar .gz (45kB) |
36 | remote: Collecting Flask-Principal& gt ;=0.3.3 (from flask-security-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 4)) |
37 | remote: Downloading Flask-Principal-0.4.0. tar .gz |
38 | remote: Collecting Flask-BabelEx& gt ;=0.9.3 (from flask-security-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 4)) |
39 | remote: Downloading Flask-BabelEx-0.9.3. tar .gz (41kB) |
40 | remote: Collecting Flask-WTF& gt ;=0.13.1 (from flask-security-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 4)) |
41 | remote: Downloading Flask_WTF-0.14.2-py2.py3-none-any.whl |
42 | remote: Collecting mongoengine& gt ;=0.8.0 (from flask-mongoengine-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 5)) |
43 | remote: Downloading mongoengine-0.15.0. tar .gz (144kB) |
44 | remote: Collecting six (from flask-mongoengine-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 5)) |
45 | remote: Downloading six-1.11.0-py2.py3-none-any.whl |
46 | remote: Collecting cffi& gt ;=1.1 (from bcrypt-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 6)) |
47 | remote: Downloading cffi-1.11.3-cp36-cp36m-manylinux1_x86_64.whl (420kB) |
48 | remote: Collecting MarkupSafe& gt ;=0.23 (from Jinja2& gt ;=2.4-& gt ;Flask-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 1)) |
49 | remote: Downloading MarkupSafe-1.0. tar .gz |
50 | remote: Collecting blinker (from Flask-Mail& gt ;=0.7.3-& gt ;flask-security-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 4)) |
51 | remote: Downloading blinker-1.4. tar .gz (111kB) |
52 | remote: Collecting Babel& gt ;=1.0 (from Flask-BabelEx& gt ;=0.9.3-& gt ;flask-security-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 4)) |
53 | remote: Downloading Babel-2.5.1-py2.py3-none-any.whl (6.8MB) |
54 | remote: Collecting speaklater& gt ;=1.2 (from Flask-BabelEx& gt ;=0.9.3-& gt ;flask-security-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 4)) |
55 | remote: Downloading speaklater-1.3. tar .gz |
56 | remote: Collecting WTForms (from Flask-WTF& gt ;=0.13.1-& gt ;flask-security-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 4)) |
57 | remote: Downloading WTForms-2.1.zip (553kB) |
58 | remote: Collecting pymongo& gt ;=2.7.1 (from mongoengine& gt ;=0.8.0-& gt ;flask-mongoengine-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 5)) |
59 | remote: Downloading pymongo-3.6.0-cp36-cp36m-manylinux1_x86_64.whl (378kB) |
60 | remote: Collecting pycparser (from cffi& gt ;=1.1-& gt ;bcrypt-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 6)) |
61 | remote: Downloading pycparser-2.18. tar .gz (245kB) |
62 | remote: Collecting pytz& gt ;=0a (from Babel& gt ;=1.0-& gt ;Flask-BabelEx& gt ;=0.9.3-& gt ;flask-security-& gt ;-r /tmp/build_f5fec0d0c01ac466add1d2bf054ac08c/requirements.txt (line 4)) |
63 | remote: Downloading pytz-2017.3-py2.py3-none-any.whl (511kB) |
64 | remote: Installing collected packages: itsdangerous, click, MarkupSafe, Jinja2, Werkzeug, Flask, SQLAlchemy, Flask-SQLAlchemy, gunicorn, passlib, Flask-Login, blinker, Flask-Mail, Flask-Principal, pytz, Babel, speaklater, Flask-BabelEx, WTForms, Flask-WTF, flask-security, pymongo, six, mongoengine, flask-mongoengine, pycparser, cffi, bcrypt |
65 | remote: Running setup.py install for itsdangerous: started |
66 | remote: Running setup.py install for itsdangerous: finished with status 'done' |
67 | remote: Running setup.py install for MarkupSafe: started |
68 | remote: Running setup.py install for MarkupSafe: finished with status 'done' |
69 | remote: Running setup.py install for SQLAlchemy: started |
70 | remote: Running setup.py install for SQLAlchemy: finished with status 'done' |
71 | remote: Running setup.py install for Flask-Login: started |
72 | remote: Running setup.py install for Flask-Login: finished with status 'done' |
73 | remote: Running setup.py install for blinker: started |
74 | remote: Running setup.py install for blinker: finished with status 'done' |
75 | remote: Running setup.py install for Flask-Mail: started |
76 | remote: Running setup.py install for Flask-Mail: finished with status 'done' |
77 | remote: Running setup.py install for Flask-Principal: started |
78 | remote: Running setup.py install for Flask-Principal: finished with status 'done' |
79 | remote: Running setup.py install for speaklater: started |
80 | remote: Running setup.py install for speaklater: finished with status 'done' |
81 | remote: Running setup.py install for Flask-BabelEx: started |
82 | remote: Running setup.py install for Flask-BabelEx: finished with status 'done' |
83 | remote: Running setup.py install for WTForms: started |
84 | remote: Running setup.py install for WTForms: finished with status 'done' |
85 | remote: Running setup.py install for mongoengine: started |
86 | remote: Running setup.py install for mongoengine: finished with status 'done' |
87 | remote: Running setup.py install for flask-mongoengine: started |
88 | remote: Running setup.py install for flask-mongoengine: finished with status 'done' |
89 | remote: Running setup.py install for pycparser: started |
90 | remote: Running setup.py install for pycparser: finished with status 'done' |
91 | remote: Successfully installed Babel-2.5.1 Flask-0.12.2 Flask-BabelEx-0.9.3 Flask-Login-0.4.1 Flask-Mail-0.9.1 Flask-Principal-0.4.0 Flask-SQLAlchemy-2.3.2 Flask-WTF-0.14.2 Jinja2-2.10 MarkupSafe-1.0 SQLAlchemy-1.2.0 WTForms-2.1 Werkzeug-0.14.1 bcrypt-3.1.4 blinker-1.4 cffi-1.11.3 click-6.7 flask-mongoengine-0.9.3 flask-security-3.0.0 gunicorn-19.7.1 itsdangerous-0.24 mongoengine-0.15.0 passlib-1.7.1 pycparser-2.18 pymongo-3.6.0 pytz-2017.3 six-1.11.0 speaklater-1.3 |
93 | remote: -----& gt ; Discovering process types |
94 | remote: Procfile declares types -& gt ; web |
96 | remote: -----& gt ; Compressing... |
98 | remote: -----& gt ; Launching... |
O log acima, mostra todo o processo de instalação de dependências para que seja criado o container e seja feito o deploy da aplicação, mas o mais importante é o final do log que aparecerá similiar ao mostrado abaixo:
1 | remote: -----& gt ; Launching... |
5 | remote: Verifying deploy... done . |
Foi retornado a seguinte url: https://alissonmachado.herokuapp.com/.
E pronto, agora é só acessar a aplicação que já estará funcionando.
Mas como foi feito o deploy?
Ao se fazer uma aplicação que será publicada no heroku, ela já deve ser construída pensada em heroku, assim como qualquer outra plataforma DevOps que faz o deploy em containers.
Dentro do repositório existe um arquivo chamado Procfile: https://github.com/Responsus/TerminusNG/blob/master/Procfile , nesse arquivo é definido qual é o processo que deve ser iniciado, que no nosso caso é o servidor Web gunicorn e ele vai iniciar p arquivo app.py que é o principal da aplicação.
Outro ponto importante é deixar o arquivo requirements.txt: https://github.com/Responsus/TerminusNG/blob/master/requirements.txt, sempre atualizado, pois ele também faz a instalação do gunicorn que é o servidor de aplicação que é usado durante o deploy.
E acho que é isso ai, qualquer coisa é só mandar um salve (=