Dockerizando um Monolito

Dockerizando um monolito de publicação da maior programadora da América Latina

Thiago Soares
Docker: Um canivete suíço

--

Não irei aqui divulgar o nome da empresa e/ou da aplicação, pois o intuito é somente técnico e demonstrativo, alterei o nome da aplicação para <application_name> e paths dos repositórios para <repository_name>.

Durante algum tempo eu trabalhei no time de desenvolvimento de Backend de um CMS, para a maior programadora da América Latina.

Esse CMS entregava metadados de vídeos para um storage gigante para fazer processamento de vídeos e dos metadados. Essa aplicação Python que nasceu em 2012 e utliza Django 2.7, com bancos de dados em Mysql e está em atividade ainda hoje, sofrendo somente manutenções pontuais.

Com o passar do tempo ela foi perdendo recursos e foram sendo substituídos por micro-serviços, mas claro que ainda existe algo legado que não é tão fácil assim de substituir.

Eu já não trabalhava mais com essa aplicação, mas houve a necessidade de trocar de máquina, e aí surgiram alguns problemas. Todos os integrantes do time de Backend já não se encontravam mais no time e integrantes novos não conseguiam instalar e rodar a aplicação local para verificação/testes.

Essa aplicação usa "libs" já defasadas e uma biblioteca de um fornecedor de banco, que não é mais possível de ser encontrada na internet e/ou fora do repositório privado da empresa. Ok, parece óbvio é só instalar do repositório privado então!; não, pois as bibliotecas começaram a conflitar entre si.

Eu era um dos últimos que tinham a aplicação rodando na máquina e precisava trocar o meu notebook. Qual foi a saída então? Construir um docker para ter uma imagem que funcione da aplicação.

Durante uma (1) semana eu me debrucei sobre esse problema, nem tudo são flores, mas a persistência faz o impossível.

Vários conflitos ocorriam e quanto mais eu resolvi uns, acabava criando muitos outros.

Durante a construção da imagem, percebi que se algum desenvolvedor subisse algum código novo, a imagem deveria estar sempre atualizada, coloquei esse "fetch" e "pull" no comando ao subir o compose.

A única automatização que não consegui realizar foi para os bancos de dados, sim essa aplicação utiliza alguns bancos de dados, mas eu não tinha mais acesso a máquina dos bancos; porém eles estão relacionados no arquivo " ./env/PROD-CM.env".

Mostro a seguir o Dockerfile e o Docker-compose que criei para a aplicação. Não sou especialista em Dokerização, mas tentei deixar o melhor possível, utilizando a virtualenv e Python.

Depois de uma (1) semana, consegui trocar de notebook e deixei essa imagem como um legado para um futuro desenvolvedor! ;-)

Dockerfile

FROM phusion/baseimage:0.10.1
ENV PYTHONHONUNBUFFERED 1

# Create gunicort log
RUN mkdir /var/log/gunicorn/

# Create log file
RUN touch <application_name>.out

# Create code and copy project to
RUN mkdir /code
WORKDIR /code
COPY ./oracle_installer/ ./requirements.txt ./requirements_test.txt ./Makefile /code/

# Setup locale, Oracle instant client and Python
ENV ORACLE_HOME=/usr/lib/oracle/12.1/client64
ENV PATH=$PATH:$ORACLE_HOME/bin
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ORACLE_HOME/lib
ADD ./oracle_installer/oracle-instantclient12.1-basic-12.1.0.2.0–1.x86_64.rpm /tmp/
ADD ./oracle_installer/oracle-instantclient12.1-sqlplus-12.1.0.2.0–1.x86_64.rpm /tmp/
ADD ./oracle_installer/oracle-instantclient12.1-devel-12.1.0.2.0–1.x86_64.rpm /tmp/

# Setup update, install oracle lib and clean installation
RUN apt-get update
RUN apt-get -y install \
sudo \
curl \
wget \
unzip \
git \
vim \
xterm \
python2.7 \
python2.7-dev \
redis-server \
build-essential \
libssl-dev \
libffi-dev \
libxml2-dev \
libxslt1-dev \
zlib1g-dev \
libmysqlclient-dev \
mysql-server \
python-mysqldb \
python-pip \
libpython-dev \
mysql-client \
libcurl4-gnutls-dev \
libjpeg-progs \
libjpeg8 \
libjpeg8-dev \
zlib1g-dev \
ncurses-dev \
&& apt-get -y install alien libaio1 \
&& alien -i /tmp/oracle-instantclient12.1-basic-12.1.0.2.0–1.x86_64.rpm \
&& alien -i /tmp/oracle-instantclient12.1-sqlplus-12.1.0.2.0–1.x86_64.rpm \
&& alien -i /tmp/oracle-instantclient12.1-devel-12.1.0.2.0–1.x86_64.rpm \
&& ln -snf /usr/lib/oracle/12.1/client64 /opt/oracle \
&& mkdir -p /opt/oracle/network \
&& ln -snf /etc/oracle /opt/oracle/network/admin \
&& pip install cx_oracle \
&& apt-get clean && rm -rf /var/cache/apt/* /var/lib/apt/lists/* /tmp/* /var/tmp/*
ADD root /

# Set locale config
RUN locale-gen en_US.UTF-8
RUN dpkg-reconfigure locales

# suporte jpeg e png para PIL
RUN /bin/bash -c “ln -s /usr/lib/x86_64-linux-gnu/libjpeg.so /usr/lib/ \
&& ln -s /usr/lib/x86_64-linux-gnu/libz.so /usr/lib/”

# Insert bashrc values
RUN echo “export LC_ALL=en_US.UTF-8” >> /root/.bashrc
RUN echo “export LANG=en_US.UTF-8” >> /root/.bashrc

# Upgrade Pip, install virtualenvwrapper(virtualenv) and install google-apputils
RUN pip install — upgrade pip
RUN pip install virtualenv virtualenvwrapper
RUN pip install google-apputils

# Set env locate configs
ENV export HOME=$PWD
ENV export WORKON_HOME=$HOME/.virtualenvs
ENV export PROJECT_HOME=$HOME/code
ENV export VIRTUALENVWRAPPER_SCRIPT=/usr/local/bin/virtualenvwrapper.sh

# Set source virtualenv and install requirements
RUN /bin/bash -c “source /usr/local/bin/virtualenvwrapper_lazy.sh \
&& mkvirtualenv <application_name> \
&& workon <application_name> \
&& make install”

# Create user and group
RUN groupadd — gid 9999 app && \
useradd — uid 9999 — gid app app && \
chown -R app:app /code

# 1. Create the SSH directory.
# 2. Populate the private key file.
# 3. Set the required permissions.
# 4. Add github to our list of known hosts for ssh.
RUN mkdir -p /root/.ssh/
COPY ./ssh/id_rsa.pub /root/.ssh/id_rsa.pub
COPY ./ssh/id_rsa /root/.ssh/id_rsa
RUN chmod -R 600 /root/.ssh/
COPY ./ssh/known_hosts /root/.ssh/known_hosts

#Start up
RUN echo “source /usr/local/bin/virtualenvwrapper_lazy.sh” >> /root/.bashrc
RUN echo “workon <application_name>” >> /root/.bashrc

# Remove oracle_installer
RUN rm -rf ./oracle_installer* && rm -rf oracle-instantclient* \
&& rm -rf instantclient* && rm -rf requirements* \
&& rm -rf Makefile && rm -rf bind_oracle* && rm -rf ubuntu_setup*

RUN /bin/bash -c “git clone git@github.com <repository_name>/<application_name>.git”

EXPOSE 80 443

Docker-compose

version: ‘2’
services:
app: &app_base
image: docker.artifactory.<repository_path>/<application_name>:<tag_imagem>
command: bash -lc ‘cd <application_name>/ && source /usr/local/bin/virtualenvwrapper_lazy.sh && workon <application_name>&& git fetch && git pull && make run’
restart: always
volumes:
— $PWD/../:/core
env_file:
— ./env/PROD-CM.env
ports:
— “8001:8001”
volumes:
app-data:

--

--