Oi Pessoal,
Hoje vamos trazer para vocês um forma de resolver algo que é bem recorrente e comum em ambientes de produção, e que talvez acabe de tornando uma porta de entrada para o uso do Docker em maior escala. Dessa vez, você entenderá como é possível realizar o agendamento e execução de script utilizando a crontab dentro de containers Docker \o/.
Para quem ainda não sabe, dentro de ambiente like *unix é possível realizar o agendamento de scripts utilizando uma ferramenta chamada Crontab (para quem é do ambiente Microsoft, é o mesmo que o task scheduler, mas com mais poder 🙂 ), através dela você define o horário de execução para os scripts, usuário que será utilizado para a execução do mesmo, e claro, qual script deve ser executado. Pois bem, sabendo disso, é possível utilizar o Docker para que a execução desses scripts seja realizada dentro de containers.
Mas afinal, quais as vantagens disso?
Bem, a execução de script via crontab, pode gerar alguns desafios, principalmente se não há um controle rigoroso de quais scripts estão sendo agendados, dentre os desafios podemos destacar:
1 – Uso excessivo de recursos: Pode acontecer de algum script ter algum erro e fazer com que haja uso excessivo de recursos (memória, cpu) durante a sua execução, e acredite, isso é mais comum do que imagina. Existe formas de contornar isso, no entanto, nativamente não.
2 – Segurança na execução: Você pode definir qual usuário executará um determinado script, isso funciona muito bem dentro da crontab, no entanto, caso você não especifique, o usuário utilizado para a execução do script será o mesmo que inicializou o serviço da cron, e geralmente este serviço inicializa com o usuário root, então…
Ok Cristiano, e como o Docker pode me ajudar?
Aeooooo mais um convertido, vamos ver como funciona na prática?
A primeira coisa que faremos é criar os diretório necessários, para isso, defina um diretório de trabalho, e nele crie uma pasta chamada “cron” e outra chamada “scripts”. Em seguida vamos buildar uma imagem Docker apenas com o que precisamos para realizar a execução dos scripts, como imagem base, vamos utilizar uma do NodeJS Alpine, lembrando que, neste caso nossa cron executará um script escrito em node, você deve adaptar a imagem de acordo com a sua necessidade (se seu script é em PHP, então a imagem deve ser PHP, e assim por diante) veja como ficou nosso Dockerfile:
FROM node:8-alpine RUN apk update && apk add tzdata &&\ cp /usr/share/zoneinfo/America/Sao_Paulo /etc/localtime &&\ echo "America/Sao_Paulo" > /etc/timezone &&\ apk del tzdata && rm -rf /var/cache/apk/* CMD chown root:root /etc/crontabs/root && /usr/sbin/crond -f
Não preciso explicar este Dockerfile né, você já deve ter lido este post né? 😉 salve-o dentro da pasta “cron”.
Bem, agora precisamos montar o resto do ambiente, para este lab, vamos criar um arquivo chamado cron1 com o seguinte conteúdo:
0 7,19 * * * /usr/local/bin/node /home/mundodocker/hello.js >> /var/log/cronteste/hello.log 2>&1
Neste caso, o script será executado as 7h e as 19h todos os dias, salve-o dentro da pasta “cron” também.
Veja, que neste caso o script que deverá ser executado é o /home/mundodocker/hello.js que contém algo simples em node:
console.log("Hello world");
Salve-o dentro da pasta “scripts”.
Ok, agora estamos quase prontos, pelo menos, tudo que precisamos está pronto, se quisermos podemos utilizar essa estrutura, pois ai já contém tudo que é necessário, obvio que isso não basta, visto que a intenção é deixar tudo automatizado. Para isso, é necessário que você tenha o docker-compose instalado, com isso conseguimos automatizar 100% do ambiente. Como você já sabe, para utilizarmos o docker-compose, precisamos de um arquivo no formato yaml com as definições de nosso ambiente, veja como ficou nosso docker-compose.yml:
version: "3" services: cron: build: cron container_name: cronteste volumes: - /var/log/cronteste:/var/log/cronteste - ./cron/cron1:/etc/crontabs/root - ./sripts:/home/mundodocker
Para validar, você pode executar o comando:
docker-compose up
Com isso ele fará o build da imagem e em seguida iniciará um container com esse agendamento. Além das opções acima, você pode por exemplo limitar os recursos desse container, inclusive definir um valor minimo para o mesmo. Outra possibilidade é iniciar este container com um usuário especifico, dessa forma você não terá problemas com aquela execução com usuário root 😉
Validou? Tudo certo? Agora vamos fazer com que esse mesmo comando seja executado na inicialização do servidor, visto que, ele ficará no somente enquanto o servidor estiver ligado, e obviamente os agendamentos serão perdidos, não queremos isso certo?
Pois bem, em sistema onde você tem o systemd (Ubuntu, RedHat, Fedora, CentOS) você deverá criar um novo service, para isso, crie dentro de: “/lib/systemd/system/” um arquivo com nome de: docker-cron.service com o seguinte conteúdo:
[Unit] Description=Docker Cron Requires=docker.service After=docker.service [Service] Restart=always ExecStart=/usr/local/bin/docker-compose -f /home/mundodocker/docker-compose.yml up ExecStop=/usr/local/bin/docker-compose -f /home/mundodocker/docker-compose.yml stop [Install] WantedBy=default.target
Criado o arquivo, basta fazer com que o systemctl releia o arquivo e adicione o serviço a sua base:
systemctl daemon-reload
Agora é simples, vamos adicionar este serviço ao startup do servidor:
systemctl enable docker-infra
Dessa forma você pode administrar da mesma forma que um serviço, ou seja, posso iniciar e parar esse agendamento a qualquer momento, e mesmo que o servidor seja reiniciado, o agendamento será persistido.
Ok, agora sim temos tudo 100% automático, não precisamos nos preocupar com mais nada, a não ser é claro em estender isso a outros tipos de agendamento (se for este o seu caso é claro). Bom, por hora era isso, ficou com dúvida? Tem algo a contribuir? Por favor deixe nos comentários e vamos melhorando juntos 😉
Obrigado e grande abraço!