1. Instalando Python 3 na Dreamhost

    Quase um ano depois de instalar manualmente o python 2.7 e django na dreamhost, senti que era hora de tentar fazer o mesmo para o python 3.4.

    Hoje, o python padrão das instancias compartilhadas da Dreamhost já é o 2.7, tornando o post anterior desnecessário, mas já é hora de fazer o máximo de uso possível do python 3.

    Usei como base meu post anterior e este aqui Deploying Django with virtualenv on Dreamhost, que é bem direto e mais simples do que o que eu havia feito no passado, e pude seguir praticamente linha a linha para conseguir rodar uma aplicação com python 3 na dreamhost.

    Primeiro, é necessário fazer download e extrair o código fonte do python:

    1
    2
    3
    wget http://python.org/ftp/python/3.4.3/Python-3.4.3.tar.xz
    tar xvfJ Python-3.4.3.tar.xz 
    cd Python-3.4.3
    

    Depois disso, compilar e instalar o python (essa etapa vai demorar bastante, uma opção é fazer tudo dentro de uma screen):

    1
    2
    3
    ./configure --prefix=$HOME/python34
    make
    make install
    

    Depois de um bom tempo, as últimas linhas da instalação são especialmente interessantes:

    1
    2
    3
    4
    5
    6
    Collecting setuptools
    Collecting pip
    Installing collected packages: pip, setuptools
    
    
    Successfully installed pip-6.0.8 setuptools-12.0.5
    

    Ou seja, já temos o pip a nossa disposição, podemos checar que estamos usando a versão instalada no home do usuário.

    1
    2
    3
    4
    5
    6
    $ which python3
    /home/foo/python34/bin/python3
    $ which pip3
    /home/foo/python34/bin/pip3
    $ which pyvenv-3.4
    /home/foo/python34/bin/pyvenv-3.4
    

    Nesse ponto chegamos no momento mais específico da Dreamhost, que é o uso do passenger para aplicações python.

    Ele utiliza um arquivo passenger_wsgi.py na raiz do domínio que é usado para definir o python que será usado pela aplicação e outras informações, ele depende de uma variável “application” que é a aplicação wsgi que irá rodar.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    import sys, os
    import logging
    cwd = os.getcwd()
    sys.path.append(cwd)
    
    INTERP = os.path.expanduser("~/venv/bin/python")
    
    if sys.executable != INTERP: os.execl(INTERP, INTERP, *sys.argv)
    
    sys.path.insert(0,'$HOME/my_project/my_project')
    sys.path.insert(0,'$HOME/venv/bin')
    sys.path.insert(0,'$HOME/venv/lib/python3.4/site-packages/django')
    sys.path.insert(0,'$HOME/venv/lib/python3.4/site-packages')
    
    os.environ['DJANGO_SETTINGS_MODULE'] = "my_project.settings"
    from django.core.wsgi import get_wsgi_application
    application = get_wsgi_application()
    

    E pronto, bem mais simples que o caso do python 2.7 e pronto para trabalhar numa versão mais “evoluída” do python, mesmo que a hospedagem em si ainda não esteja.


  2. Um Djangonauta no Flask

    Quando saí do desenvolvimento com PHP fui diretamente para o Django, o ORM e admin foram suficientes para que convencer de que seria o framework ideal para mim, e venho usando ele em diversos projetos desde então.

    Porém me deparei com uma demanda de “criar uma página de contatos que envia um email”, e só, cheguei a começar a fazer o setup do projeto com o Django, mas a cada momento parecia mais que estava usando um canhão para matar uma formiga.

    Então resolvi fazer o projeto em Flask, havia feito apenas o tutorial alguns anos atrás mas parecia ser a opção correta para um projeto pequeno, um microframework para uma pequena demanda.

    Uma hora depois, 2 arquivos python (routes.py e forms.py), um template e alguns statics o problema estava resolvido.

    Além do flask, precisei instalar mais dois pacotes, Flask-Mail, Flask-WTF, o que foi bem tranquilo, já que ambos os pacotes tem uma boa documentação e são simples de usar, de certo modo, mais simples que o do Django.

    Um lado negativo que vejo é que para conseguir desenvolver essa pequena aplicação tive que manter 3 documentações diferentes abertas, e tive alguns problemas pra me acostumar com isso e as diferenças de como integrar as coisas, mas nada que um pouco de pratica não resolveria.


  3. Problemas com pip freeze > requirements.txt

    Em muitos tutoriais é comum encontrar o comando pip freeze > requirements.txt como exemplo de como guardar os requisitos de um projeto.

    usar o requirements é uma boa prática e deve ser sempre seguida, porém o problema é quando ela é mal executada, podendo gerar mais problemas do que ajudar dependendo da situação.

    Por exemplo, tenho um projeto que usa o Markdoc para gerar uma wiki simples a partir de arquivos markdown, e tinha feito, a um bom tempo, o arquivo de requirements usando o pip freeze… gerando um arquivo assim:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    CherryPy==3.2.2
    Jinja2==2.6
    Markdoc==0.6.6
    Markdown==2.2.1
    PyYAML==3.10
    Pygments==1.5
    WebOb==1.2.3
    argparse==1.2.1
    wsgiref==0.1.2
    

    Onde todas as dependências do Markdoc foram parar no requirements, no momento tudo pareceu estar bem, porém, 2 anos depois, tentando regerar o virtualenv, me deparo com o erro a seguir:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    $ pip install -r requirements.txt
    Downloading/unpacking CherryPy==3.2.2 (from -r requirements.txt (line 1))
      Could not find a version that satisfies the requirement CherryPy==3.2.2 (from
      -r requirements.txt (line 1)) (from versions: 3.2.6, 3.4.0, 2.1.1, 2.2.0beta,
      3.2.3, 3.2.4, 3.2.4, 3.2.5, 3.2.5, 3.2.6, 3.2.6, 3.3.0, 3.3.0, 3.4.0, 3.4.0,
      3.5.0, 3.5.0, 3.6.0, 3.6.0)
        Some externally hosted files were ignored (use --allow-external to allow).
        Cleaning up...
        No distributions matching the version for CherryPy==3.2.2 (from -r
        requirements.txt (line 1))
        Storing debug log for failure in ~/.pip/pip.log
    

    Ou seja, a versão do CherryPy na época da criação do projeto não está mais disponível no PyPI, porém não é do CherryPy que eu preciso, e sim do Markdoc, então, ignorei o requirements e instalei o Markdoc diretamente.

    1
    $ pip install Markdoc
    

    E a instalação ocorreu normalmente, olhando o pip freeze, é possível notar que várias dependências do Markdoc foram atualizadas, mas o Markdoc em si continua na mesma versão:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    CherryPy==3.6.0
    Jinja2==2.7.3
    Markdoc==0.6.6
    Markdown==2.5.1
    MarkupSafe==0.23
    PyYAML==3.11
    Pygments==2.0.1
    WebOb==1.4
    argparse==1.2.1
    wsgiref==0.1.2
    

    Então, atualizei o requirements para ter apenas o Markdoc, o que vai evitar qualquer problema desse tipo no futuro.

    Como o projeto é muito simples foi fácil encontrar o problema e corrigir, mas se houvessem várias dependências ou dependências compartilhadas poderia ter sido bem mais complicado de se resolver.


  4. Instalando Python e Django na Dreamhost

    Os shared-hosts já foram a melhor opção de hospedagem barata e funcional que se tinha, porém a cada dia opções de VPS e de IaaS mais baratas aparecem, e os shared-hosts e suas limitações são deixados para trás.

    Um dos pontos negativos é a versão do python disponível, atualmente a dreamhost oferece a versão 2.6.6, o que obviamente não é o ideal, a última versão de cada ciclo (2.7 e 3.3) seria a melhor escolha.

    No meu caso, instalei a versão 2.7 que é a que estou usando em um projeto, aqui o passo a passo do que fiz, que poderia facilmente ser transformado em um bash script como já foi feito em alguns lugares, mas como eu só precisava do python, virtualenv e virtualenvwrapper, resolvi fazer manualmente.

    Para instalar o python:

    1
    2
    3
    4
    5
    wget http://www.python.org/ftp/python/2.7.8/Python-2.7.8.tgz --no-check-certificate
    tar xzvf Python-2.7.8.tgz
    cd Python-2.7.8
    ./configure --enable-shared --prefix=$HOME/opt/python-2.7.8
    make && make install
    

    O mais importante ali é a definição de um “prefix” no .configure, que permite instalar o python em uma pasta dentro do home do usuário.

    Depois, o virtualenv:

    1
    2
    3
    4
    5
    6
    7
    8
    mkdir opt/python-2.7.8/local
    wget https://pypi.python.org/packages/source/v/virtualenv/virtualenv-1.9.1.tar.gz --no-check-certificate
    tar -xzf virtualenv-1.9.1.tar.gz
    cd virtualenv-1.9.1
    python virtualenv.py /home/user/opt/python-2.7.8/local/
    easy_install virtualenv
    source ~/opt/python-2.7.8/local/bin/activate
    easy_install virtualenv
    

    E finalmente o virtualenvwrapper:

    1
    2
    3
    4
    5
    6
    wget http://www.doughellmann.com/downloads/virtualenvwrapper-2.6.1.tar.gz --no-check-certificate
    tar -xzf virtualenvwrapper-2.6.1.tar.gz
    cd virtualenvwrapper-2.6.1
    python setup.py install
    cp virtualenvwrapper.sh ~/opt/python-2.7.8/
    mdkir ~/.virtualenvs
    

    Para que tudo isso funcione, é necessário complementar e adicionar algumas variáveis de ambiente e ativar o virtualenvwrapper, isso pode ser feito a partir do .profile ou do .bashrc

    .profile

    1
    2
    3
    4
    5
    export PATH=$HOME/opt/python-2.7.8/local/bin:$HOME/opt/python-2.7.8/bin:$PATH
    export PYTHONPATH=$HOME/opt/python-2.7.8/local/lib/python2.7/site-packages:$PYTHONPATH
    export LD_LIBRARY_PATH=$HOME/opt/python-2.7.8/lib/
    export WORKON_HOME=$HOME/.virtualenvs
    source $HOME/opt/python-2.7.8/virtualenvwrapper.sh
    

    Agora considerando um projeto usando Django, a dreamhost usa o passenger para executar aplicações em python, e um arquivo passenger_wsgi.py é necessário na raiz da pasta para a qual o domínio está apontando para fazer o passenger encontrar a aplicação.

    Essa deve ser provavelmente a parte mais complicada do processo, porque existe pouca ou nenhuma documentação de como é o modo correto de criar este arquivo.

    Os pontos importantes dele são:

    • Definir na variável INTERP o caminho para o executável do python a ser usável, de preferência sendo o do virtualenv criado para o projeto

    • Adicionar no path todos os caminhos pertinentes ao projeto, através do sys.path.insert, que atualiza o path adicionando novos valores no começo do mesmo.

    • Adicionar qualquer variável de ambiente necessária para o sistema no ambiente através do os.environ, no caso, estou setando o arquivo settings a ser usado pelo projeto.

    • A criação da variável “application” que vai ser usada pelo passenger para rodar a aplicação.

    passenger_wsgi.py

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    import sys, os
    
    # Switch to the virtualenv if we're not already there
    INTERP = os.path.expanduser("~/.virtualenvs/python/bin/python")
    if sys.executable != INTERP: os.execl(INTERP, INTERP, *sys.argv)
    
    PROJECT_ROOT = '/home/user/example'
    
    sys.path.insert(0, PROJECT_ROOT + '/example/')
    sys.path.insert(0, '/home/user/.virtualenvs/example/lib/python2.7/site-packages')
    os.environ['DJANGO_SETTINGS_MODULE'] = "example.settings.dreamhost"
    import django.core.handlers.wsgi
    application = django.core.handlers.wsgi.WSGIHandler()
    

    E por último, na dreamhost a pasta “public” deve ser usada para servir os arquivos estáticos da aplicação, nesse caso, é necessário definir o STATIC_ROOT e MEDIA_ROOT em pastas dentro do public, e os STATIC_URL e MEDIA_URL considerando o caminho a partir da public.

    settings/dreamhost.py

    1
    2
    3
    4
    5
    6
    7
    STATIC_ROOT = os.path.join(HOME_DIR, 'example.daniloshiga.com', 'public', 'static')
    
    STATIC_URL = '/static/'
    
    MEDIA_ROOT = os.path.join(HOME_DIR, 'example.daniloshiga.com', 'public', 'media')
    
    MEDIA_URL = '/media/'
    

    Do modo que está acima, essas pastas vão ficar em /home/user/example/example.daniloshiga.com/public/static e /public/media, mas a URL delas é apenas /static e /media.

    Depois disso, para reiniciar o passenger toda vez que houver uma novidade no projeto, é necessário alterar a data de modificação de um arquivo restart.txt dentro da pasta tmp/ do domínio, por exemplo, através do comando:

    1
    touch ~/example.daniloshiga.com/tmp/restart.txt
    

    Se isso não for suficiente, ainda é possível matar os processor do python que estiverem rodando, usando o comando pkil python.

    E é isso, foi um processo um pouco trabalhoso, mas tem a vantagem de dar mais liberdade em um ambiente limitado, o que permite aproveitar algumas vantagens de uma hospedagem como a dreamhost

Página 1 / 1