Capítulo 8: CaaS e FaaS
8.1 Entendendo os Contêineres
containers are the first-choice solution for most new applications.
Definir contêineres de maneira concisa pode ser um desafio, pois abrange uma série de conceitos interconectados. Para tornar essa compreensão mais acessível, apresentarei alguns princípios fundamentais que esclarecerão o que são contêineres e como funcionam.
Em 2006, foi quando o Google desenvolveu um projeto chamado Process Container que foi uma evolução em cima dos Jails de BSD ou Zonas do Solaris. Esse projeto foi depois renomeado para Control Groups ou CGROUPS. A ideia é fazer a Kernel do sistema operacional "mentir" para os processos de uma maneira em que dois processos podem rodar no mesmo sistema operacional porém um sem saber da existência um do outro. Isso é mais leve do ponto de vista de consumo de recursos computacionais pois, você está executando somente uma Kernel em vez de múltiplas Kernels virtualizadas.
Em março de 2013, uma palestra relâmpago de 5 minutos chamada "O futuro dos contêineres Linux", apresentada por Solomon Hykes na PyCon, introduziu uma futura ferramenta de código aberto chamada "Docker" para criar e usar contêineres Linux. O Docker introduziu um nível de usabilidade aos contêineres Linux que os tornou acessíveis a mais usuários do que nunca, e a popularidade do Docker, e portanto dos contêineres Linux, disparou. Com o Docker tornando a abstração dos contêineres Linux acessível a todos, executar aplicativos de maneiras muito mais portáteis e repetíveis de repente se tornou possível, mas a questão da escala permaneceu.
Em 2013 o Docker é apresentado por Solomon Hykes na conferência dotScale em 2013 que inicialmente, era somente um conjunto de ferramentas que fazia uso do Linux Containers (LXC) que tinha como objetivo executar de forma isolada as aplicações dentro do mesmo sistema operacional.
Nesta época, o Google já estava usando contêiners a mais ou menos 15 anos porém através de ferramentas internas e proprietárias nas quais não eram divulgadas ao público.
Antes do Docker, muitas empresas sabiam dos contêineres porém isso era secreto. Muitos engenheiros de software não sabiam disso na época. Isso só era utilizado em grandes empresas por debaixo dos panos como Google e Heroku, por exemplo.
Antes do Docker, existiam diferentes ferramentas e frameworks proprietários no qual permitiam os desenvolvedores construir software local. Porém, o próximo passo era trazer o software, desenvolvido localmente, para a produção de um modo que ele poderia escalar.
Docker tooling and experience popularized a brand-new cloud native approach to application packaging and maintenance.
NOTA
Para ter uma noção da complexidade envolvida na criação de um contêiner manualmente, sem o uso do Docker, assista ao vídeo "Fábio Akita - Entendendo o Funcionamento de Containers".
Inicialmente o Docker era somente um conjunto de ferramentas que fazia uso do Linux Containers (LXC).
A ideia de se utilizar e implementar contêineres afeta a forma como se cria software e distribuí software.
A ideia de contêineres é executar programas dentro do mesmo sistema operacional. Docker não é full virtualization, não é paravirtualization e não é um hypervisor.
Em 2013 surge o tal Docker que inicialmente usou o Linux Containers ou LXC. Docker não é full virtualization, não é paravirtualization e não é um hypervisor. Virtualização é literalmente falsificar o hardware físico. Nesse hardware virtual, você pode executar mutiplos e diferentes sistemas operacionais cada um contendo o seu próprio Kernel. A ideia toda, dos containers, é executar todos os programas dentro do mesmo sistema operacional.
8.1.2 Processos
Programa é uma entidade passiva onde as suas instruções são armazenadas em disco. Pode-se dizer também que, um programa é um arquivo executável.
Assim que o programa é executado pelo usuário, ele se transforma em uma entidade ativa, com suas instruções sendo processadas pela CPU do computador. Em outras palavras, o programa passa a ser considerado um processo.
Em resumo, um processo é uma instância de um programa que está sendo executado.
Todo processo possui um número único, denominado PID (Process Identifier ou Identificador de Processo), que é utilizado para sua identificação no sistema operacional. Além disso, os processos têm a capacidade de se comunicar entre si, acessar arquivos e até mesmo enviar dados pela rede.

Os contêineres, ou Software Containers, foram desenvolvidos como uma solução eficaz para isolar a execução de processos dentro de um sistema operacional. Além dessa capacidade de isolamento, todo o conteúdo de um contêiner pode ser compactado em um único arquivo tarball, resultando no que chamamos de imagem de contêiner. Essa imagem contém tudo o que é necessário para executar o aplicativo, incluindo bibliotecas, dependências e configurações, garantindo um ambiente consistente e portátil.
NOTA
Isolar a execução de processos dentro de um mesmo sistema operacional não é uma ideia nova. Antes do surgimento dos contêineres, tecnologias como Solaris Zones e chroot já desempenhavam essa função, possibilitando a criação de ambientes isolados para a execução de aplicações.
Uma vez gerada, uma imagem de contêiner pode ser transportada e executada em qualquer ambiente que suporte a execução de contêineres. Em outras palavras, os contêineres permitem empacotar uma aplicação juntamente com todas as suas dependências (como frameworks, bibliotecas e arquivos de configuração) em um único "pacote". Isso possibilita que esse pacote seja facilmente transferido e executado em plataformas como a Oracle Cloud Infrastructure (OCI).
Os contêineres revolucionaram o desenvolvimento de software ao oferecer agilidade e simplificar o empacotamento e a distribuição de aplicações. Todas as dependências necessárias para uma aplicação estão incluídas dentro do contêiner, resultando em um pacote autocontido. Isso permite que o mesmo software seja executado em diferentes ambientes (desenvolvimento, teste e produção) sem a necessidade de realizar qualquer modificação.
8.1.3 Docker

Docker é um conjunto de ferramentas desenvolvido para simplificar a criação, transporte e execução de contêineres. Ele utiliza funcionalidades do kernel do Linux, como namespaces e cgroups, para criar um "espaço de trabalho isolado" conhecido como contêiner. Essa abordagem permite que os desenvolvedores empacotem aplicações e suas dependências de maneira consistente, assegurando que funcionem de forma idêntica em diferentes ambientes.
NOTA
Existem outras ferramentas disponíveis para criar e gerenciar contêineres, como o Podman, por exemplo. No entanto, o Docker continua sendo a ferramenta mais popular e amplamente utilizada no mercado.
Contêineres não são máquinas virtuais. Enquanto uma máquina virtual inclui um sistema operacional completo e inicializável, um contêiner opera dentro de um sistema operacional existente. Isso significa que um único sistema operacional pode executar múltiplos contêineres, que são significativamente mais leves do que máquinas virtuais completas. Essa leveza permite um uso mais eficiente dos recursos, resultando em tempos de inicialização mais rápidos e uma maior densidade de aplicações em um mesmo ambiente.
8.1.4 Container Registry
O Container Registry é um serviço fundamental presenten no ecossistema de contêineres pois é ele quem permite armazenar, gerenciar e distribuir imagens de contêiner.
O Container Registry atua como um repositório centralizado onde os desenvolvedores podem armazenar suas imagens de contêiner. Essa funcionalidade permite que as equipes compartilhem e reutilizem imagens de forma eficiente em diversos ambientes, como desenvolvimento, teste e produção.
Além do Docker Hub, que é o maior registry público de imagens de contêiner, a Oracle também oferece o seu próprio registry público, acessível através do seguinte link:: https://container-registry.oracle.com

Uma das vantagens do Oracle Container Registry em comparação com o Docker Hub, é que o Docker Hub impõe limites para o download das imagens que ele armazena (rate limits). Em contrapartida, o Oracle Container Registry não aplica essas restrições, permitindo que os desenvolvedores baixem imagens da Oracle à vontade, sem se preocupar com limitações de uso.
Na aplicação OCI Pizza, foi utilizada como imagem base o Oracle Linux 8 na versão slim, que é uma imagem mais leve e compacta. Essa versão otimizada permite downloads e implantações mais ágeis, pois contém apenas os componentes essenciais do sistema operacional.

NOTA
Uma Docker Base Image (imagem base do Docker) é uma imagem de contêiner que serve como ponto de partida para a criação de outras imagens.
Para baixar a imagem Oracle Linux 8 Slim localmente em sua máquina, basta executar o comando abaixo:
Com a imagem baixada localmente, é possível criar um contêiner e iniciar um shell a partir do ID dessa imagem base:
8.1.5 Dockerfile
O Dockerfile é um arquivo de texto que contém todas as instruções necessárias para construir uma imagem de contêiner. O Dockerfile da aplicação OCI Pizza inclui o seguinte conteúdo:
Abaixo, a explicação de alguns dos comandos existentes neste Dockerfile:
-
FROM : Especifica a imagem base que será utilizada para criar uma nova imagem a partir dela.
-
WORKDIR : Durante o processo de construção da imagem, muda-se para o diretório especificado, estabelecendo-o como o novo diretório raiz de trabalho para a execução dos demais comandos.
-
COPY : Copia arquivos ou diretórios do sistema de arquivos externo para dentro da imagem em construção.
-
RUN : Executa um comando como parte do processo de construção da imagem de contêiner.
-
EXPOSE : Especifica a porta de rede que a aplicação irá expor. É importante ressaltar que esta instrução "não abre" efetivamente nenhuma porta; ela serve apenas como uma forma de documentar qual porta será exposta pelo contêiner.
-
ENTRYPOINT : Define o comando que será executado quando o contêiner for criado e iniciado. No caso deste exemplo, trata-se de um shell script que iniciará a aplicação web.
NOTA
Consulte Dockerfile reference para um descrição de todos os comandos suportados.
Para criar a imagem da aplicação, navegue até diretório que contém o arquivo Dockerfile:
Em seguida, execute o comando abaixo e aguarde sua conclusão:
NOTA
Lembre-se de estar dentro do diretório onde encontra-se o arquivo Dockerfile para poder executar o comando docker build.
O parâmetro -t (ou --tag) do comando docker build, é utilizado para atribuir uma tag a uma imagem Docker. Essa tag serve como um identificador, permitindo nomear e versionar a imagem. Isto também facilita o gerenciamento de diferentes versões.
Por fim, é possível verificar que a imagem da aplicação foi criada com sucesso:
8.1.6 Oracle Cloud Infrastructure Registry (OCIR)
Já sabemos que o Container Registry é um repositório utilizado para armazenar imagens de contêineres. No contexto do OCI, temos o Oracle Cloud Infrastructure Registry (OCIR), que é um serviço gerenciado especificamente para o armazenamento e gerenciamento de imagens de contêineres.
O ideal é que todas as imagens de contêiner que serão implantadas e executadas por serviços no OCI, como o OKE ou Container Instances, sejam previamente armazenadas no OCIR.
Existem duas operações fundamentais relacionadas ao Container Registry:
-
Push (Enviar)
- Esta operação envolve o envio de uma imagem de contêiner ao Container Registry (upload).
-
Pull (Puxar)
- Esta operação refere-se à recuperação de uma imagem de contêiner do Container Registry para implantação e uso (download).

Antes de enviar a imagem por meio da operação Push, é necessário criar um repositório. O repositório servirá para armazenar diferentes versões de uma mesma imagem e pode ser configurado como público ou privado. Um repositório privado permite acesso apenas a partir dos recursos de uma VCN (Virtual Cloud Network), restringindo o acesso pela Internet.
Para criar um repositório privado, utilize o comando abaixo:
Uma vez criado o repositório, é necessário nomear ou taguear (docker tag), seguindo o padrão estabelecido pelo OCI, que deve obedecer ao seguinte formato:

-
registry-domain: É o hostname que identifica o serviço OCIR dentro de uma região.
-
tenancy-namespace: É uma string que identifica unicamente um tenancy no OCI.
-
repo-name: Nome exclusivo de um repositório de imagens no OCIR usado para armazenar diferentes versões de uma aplicação.
-
version: Identificador de versão de uma imagem.
Para obter o valor do tenancy-namespace, utilize o comando abaixo:
No caso da aplicação OCI Pizza, ela será implantada na região Brazil East (São Paulo), que possui o identificador sa-saopaulo-1. Diante disso, a nova tag da aplicação é:

Para aplicar a nova tag à imagem existente ocipizza:1.0, utilize o seguinte comando:
Antes de executar o push, é necessário fazer o login no serviço OCIR da região onde as imagens da aplicação serão enviadas (sa-saopaulo-1):
NOTA
Para efetuar o login no OCIR, é necessário possuir um nome de usuário válido, com as permissões adequadas, além de um Auth Token que funcionará como a senha desse usuário no serviço OCIR. Para obter informações detalhadas sobre como gerar um Auth Token, consulte o link.
Por último, executamos o push para enviar a imagem da aplicação ao OCIR:
Para exibir todas as imagens do repositório ocipizza, execute o comando abaixo:
8.1.7 Habilitando o Scan de Vulnerabilidades
Allow service vulnerability-scanning-service to read compartments in tenancy Allow service vulnerability-scanning-service to read repos in tenancy