BT

Início Artigos Empacotando aplicações para Docker e Kubernetes: Metaparticle vs Pulumi vs Ballerina

Empacotando aplicações para Docker e Kubernetes: Metaparticle vs Pulumi vs Ballerina

Favoritos

Pontos Principais

  • Com a crescente demanda por arquiteturas em microservices, a indústria de software está indo em direção ao desenvolvimento e deploy de aplicação nativas para cloud.
  • Docker e Kubernetes são os principais elementos da automação do deploy de aplicações nativas para cloud.
  • A prática comum atual é criar pacotes de aplicações reproduzíveis para contêineres, porém isto envolve a escrita manual (e manutenção) de arquivos YAML, que descreve como o deploy das aplicações devem ser feitos.
  • Metaparticle, Ballerina e Pulumi são projetos open source que trazem sua própria abordagem para resolver problemas de empacotamento de aplicação para deploy com Docker e Kubernetes.
  • Este artigo investiga os passos necessários para fazer o deploy de uma aplicação "hello world" usando cada um dos frameworks mencionados.

Com a crescente demanda por arquiteturas de microservices, a indústria de software está indo em direção ao desenvolvimento de aplicações nativas para a nuvem. Times de desenvolvimento baseados na regra das duas pizzas, agilidade, repetição e CI/CD (Integração Contínua / Entrega Contínua) têm desempenhado um papel importante nas atuais e rápidas inovações na indústria de software.

Docker e Kubernetes são os elementos principais nas automatizações do deploy de aplicações nativas para a nuvem. A prática comum é criar pacotes reproduzíveis para o desenvolvimento de aplicações com containers. O Docker permite aos desenvolvedores produzirem ambientes de execução de forma repetitiva, nos quais se definem as dependências e configurações das aplicações de forma simples. O Kubernetes é uma plataforma open source de orquestração, permitindo o deploy de aplicações entre vários contêineres, enquanto fornece escalabilidade e alta disponibilidade. Para isso, é necessário descrições de deploy para Docker e Kubernetes (Dockerfile e YAML contendo informações de deploy), o que pode ser difícil e sujeito a falhas.

Metaparticle, Ballerine e Pulumi são três projetos open source que introduzem sua própria abordagem para resolver este problema. Recentemente, me deparei com três tweets discutindo essas abordagens.

O primeiro era de Andress Guisado explicando como o Metaparticle fornece uma biblioteca padrão para criar aplicações para nuvem de forma nativa e que podem ter o deploy diretamente no Kubernetes. Brendan Burns anunciou o Metaparticle na KubeCon 2018.

Depois de conhecer a Ballerina no encontro da comunidade Istio, Dan Ciruli enviou um tweet dizendo que a Ballerina é uma linguagem interessante, que pode gerar automaticamente arquivos YAML tanto para o Kubernetes quanto para Istio como parte do processo de build. Depois disse que esta é uma ótima ideia e que imagina que outros frameworks vão seguir este estilo também.

O terceiro, Ustin Ozgur tuitou dizendo que os esforços do Pulumi em definir a infraestrutura como código, ao contrário de arquivos YAML absurdos, irá contribuir para DevOps assim como o React contribuiu para o desenvolvimento web.

Neste artigo, comparo como estes três projetos estão ajudando a automatizar o deploy de código em plataformas de orquestração de containers como o Kubernetes sem a necessidade de escrever arquivos YAML.

Metaparticle

O Metaparticle/Package simplifica a tarefa de construir e fazer o deploy de imagens de containers. É uma coleção de bibliotecas que permite construir e fazer o deploy usando código familiar ao programador. Atualmente, suporta Java, .NET, Javascript (NodeJS), Go, Python e Ruby.

Vejamos como fazer o deploy de código Java no Kubernetes usando Metaparticle.

Pré-requisitos:

  1. Docker/Kubernetes
  2. A ferramenta de linha de comando mp-compiler
  3. O pacote io.metaparticle:metaparticle como dependência maven

O código seguinte inicia um pod Kubernetes contendo um serviço HTTP que imprime "Hello World!".

package io.metaparticle.tutorial;

import io.metaparticle.annotations.Package;
import io.metaparticle.annotations.Runtime;

import static io.metaparticle.Metaparticle.Containerize;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class Main {
   private static final int port = 8080;

   @Runtime(ports = {port},
       replicas = 4,
       publicAddress = true,
       executor = "metaparticle"
   )
   @Package(repository = "docker.io/lakwarus",
           jarFile = "target/metaparticle-package-tutorial-0.1-SNAPSHOT-jar-with-dependencies.jar", publish = true)
   public static void main(String[] args) {
       Containerize(() -> {
           try {
               HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
               server.createContext("/", new HttpHandler() {
                   @Override
                   public void handle(HttpExchange t) throws IOException {
                       String msg = "Hello World!";
                       t.sendResponseHeaders(200, msg.length());
                       OutputStream os = t.getResponseBody();
                       os.write(msg.getBytes());
                       os.close();
                       System.out.println("[" + t.getRequestURI() + "]");
                   }
               });
               server.start();
           } catch (IOException ex) {
               ex.printStackTrace();
           }
       });
   }
}

Algumas coisas a se notar:

  • Importamos as classes io.metaparticle.annotations.Package e io.metaparticle.annotaions.Runtime.
  • A anotação @Package que descreve como empacotar a aplicação.
  • A anotação @Runtime que descreve as configurações de execução da aplicação.
  • Empacotamos a função principal na função Containerize, a qual inicial o código do Metaparticle.

Compilando o código:

mvn compile

Este comando irá criar um arquivo jar com todas as dependências.

Executando o código:

mvn exec:java -Dexec.mainClass=io.metaparticle.tutorial.Main

Este comando irá gerar um arquivo Dockerfile, uma imagem Docker e enviar ao repositório especificado. Depois, irá iniciar o processo de deploy do Kubernetes com 4 pods no cluster configurado.

Acessando o serviço:

É preciso criar um proxy para acessar o serviço.

$ kubectl port-forward deployment/io-metaparticle-tutorial-main 8080:8080

$ curl http://localhost:8080/
Hello World!

Destaques

  • No YAMLs/JSON are created
  • Fully automated deployment
  • Supports multiple languages
  • Supports limited Kubernetes functionalities such as services and deployments. Only clusterIP services are supported
  • Need to wrap users code with Containerize() block. Then your code can’t run in standalone mode.  

Ballerina

  • Nenhum arquivo YAML/JSON é criado
  • Deploy completamente automatizado.
  • Suporte a várias linguagens.
  • Suporte limitado às funcionalidades do Kubernetes como serviços e deploys. Apenas serviços clusterIP são suportados.
  • É necessário criar código de usuários dentro de um bloco Containerize(). Não podem ser executados em modo standalone.

Ballerina

Ballerina é uma nova linguagem de código aberto desenhada para trazer agilidade no desenvolvimento de código no desafio de integrar endpoints. A Ballerina tem suporte de primeira classe a APIs, transações distribuídas, circuit-breakers, processamento de grandes volumes de dados, acesso a dados via JSON, XML, gRPC, entre outros desafios de integração.

A Ballerina entende a arquitetura ao redor dela, o compilador está ciente do ambiente com microservices com deploys feitos diretamente na infraestrutura do Docker e Kubernetes, gerando automaticamente imagens Docker e arquivos YAML.

Vejamos como usar o Kubernetes em Ballerina para fazer deploy de código no Kubernetes.

Pré-requisitos:

  1. Ballerina
  2. Docker/Kubernetes

O código seguinte iniciar um serviço HTTP que imprime "Hello World!".

hello_world_k8s.bal

import ballerina/http;
import ballerinax/kubernetes;

@kubernetes:Service {
serviceType: "NodePort",
name: "hello-world" 
}
endpoint http:Listener listener {
 port: 9090
};

@kubernetes:Deployment {
image: "lakwarus/helloworld",
name: "hello-world"
}
@http:ServiceConfig {
  basePath:"/"
}
service<http:Service> helloWorld bind listener {
  @http:ResourceConfig {
     path: "/"
  }
  sayHello(endpoint outboundEP, http:Request request) {
      http:Response response = new;
      response.setTextPayload("Hello World! \n");
      _ = outboundEP->respond(response);
  }
}

Algumas coisas a se notar:

  • Importamos o pacote ballerinax/kubernetes.
  • A anotação @kubernets:Service direto no serviço da Ballerina.

Compilando o código:

Compile o arquivo hello_world_k8s.bal. O comando para iniciar os artefatos do Kubernetes irão ser impressos na tela caso o código seja executado com sucesso:

$> ballerina build hello_world_k8s.bal

@kubernetes:Docker          - complete 3/3
@kubernetes:Deployment      - complete 1/1
@kubernetes:Service         - complete 1/1

Run following command to deploy kubernetes artifacts: 
kubectl apply -f ./kubernetes/

O compilador da Ballerina irá gerar o arquivo hello_containers_k8s.lax, o Dockerfile, a imagem Docker e os artefatos no Kubernetes na seguinte estrutura:

$> tree
.
├── hello_world_k8s.bal
├── hello_world_k8s.balx
└── kubernetes
    ├── docker
    │   └── Dockerfile
    ├── hello_world_k8s_svc.yaml
    └── hello_world_k8s_deployment.yaml

`kubectl apply -f ./kubernetes/` rá fazer o deploy no Kubernetes que poderá ser acessado via Kubernetes NodePort.

Acessando o serviço:


$> kubectl get svc
NAME                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
hello-world           NodePort    10.96.118.214    <none>        9090:32045/TCP   1m

$> curl http://localhost:<32045>/
Hello, World!

Destaques

  • Suporte nativo ao Kubernetes.
  • Código deve ser escrito na linguagem Ballerina.
  • Criação de artefatos para deploy dependendo da anotação definida no código.
  • Deploy não é totalmente automatizado. É necessário rodar o comando kubectl.
  • Suporte a muitas funcionalidades do Kubernetes como: todos os serviços do Kubernetes, deploy, ingress, secrets, volumes persistentes, configuração de mapas, provas de vida e escalonamento horizontal de pods.
  • Não há a necessidade de alterar o código do usuário. As anotações fornecem informação para a Ballerina. O compilador da Ballerina faz o parse das anotações em modo AST, e toma alguma ação caso necessário.

Pulumi

O Pulumi é uma plataforma de desenvolvimento em nuvem que torna a criação de aplicativos para nuvem fácil e produtiva. Podem ser criados aplicativos para nuvem na sua linguagem favorita e o Pulumi automaticamente irá manter a infraestrutura atualizada: "esqueça o YAML e apenas escreva o código". O Pulumi é multi-linguagem, multi-cloud e altamente extensível tanto na sua engine como no ecossistema de pacotes.

Atualmente são suportadas as linguagens JavaScript, TypeScript, Python e Go, além de também oferecer suporte a plataformas cloud como Amazon Web Services, Microsoft Azure, Google Cloud Platform e plataformas cloud com suporte a Kubernetes.

O foco principal do Pulumi é a automação de código de infraestrutura ao invés da automação de código fonte. Sua linguagem de programação favorita pode ser utilizada para automatizar o deploy.

O Pulumi suporta o deploy em FaaS com provedores públicos como AWS Lambda, mas neste artigo iremos focar apenas na automação de deploy no Docker e Kubernetes.

Pré-requisitos:

  1. Docker/Kubernetes
  2. Instalação do Pulumi (curl -fsSL https://get.pulumi.com/ | sh)
  3. Configuração do Pulumi com cluster do Kubernetes

Vejamos como usar TypeScript e Pulumi para fazer o deploy de uma aplicação de exemplo do tipo "hello world".

Criei uma aplicação de exemplo chamada "helloworld" (imprimindo "Hello World para cada requisição HTTP), e uma imagem docker correspondente (lakwarus/helloworld:latest). Agora irei usar o TypeScript junto com as bibliotecas do Pulumi para criar um código simples para fazer o deploy da aplicação no Kubernetes sem a necessidade de escrever na mão os arquivos YAML.

Criando o projeto com Pulumi:

$> pulumi new
Please choose a template: typescript
This command will walk you through creating a new Pulumi project.

Enter a value or leave blank to accept the default, and press <ENTER>.
Press ^C at any time to quit.
project name: (hello) 
project description: hello world
Created project 'hello'.
stack name: (hello-dev) 
Created stack 'hello-dev'.
Installing dependencies...

added 113 packages in 12.549s
Finished installing dependencies.
New project is configured and ready to deploy with 'pulumi update'.

Atualizei o arquivo package.json com as seguintes dependências:

{
    "name": "hello",
    "main": "bin/index.js",
    "typings": "bin/index.d.ts",
    "scripts": {
        "build": "tsc"
    },
    "devDependencies": {
        "typescript": "^2.7.2",
        "@types/node": "latest"
    },
    "dependencies": {
        "@pulumi/kubernetes": "^0.14.0",
        "@pulumi/pulumi": "^0.14.0",
        "npm": "^6.1.0"
    }
}

Editei o arquivo index.ts com as informações da sua aplicação e de deploy. Neste arquivo apenas adicionei a configuração do pod Kubernetes, porém outras funcionalidades do Kubernetes podem ser adicionadas.

import * as pulumi from "@pulumi/pulumi";
import * as k8s from "@pulumi/kubernetes";

let helloPod = new k8s.core.v1.Pod("hello", {
   metadata: {
       name: "hello",
   },
   spec: {
       containers: [{
       name: "hello",
       image: "lakwarus/helloworld",
       ports: [{
           containerPort: 9090,
       }],
       }],
   },
});

Compilando e executando o código:

$> npm update
$> npm run build
$> pulumi update
Previewing update of stack 'hello-dev'
Previewing changes:

     Type                    Name             Plan       Info
 +   pulumi:pulumi:Stack     hello-hello-dev  create     
 +   └─ kubernetes:core:Pod  hello            create     
 
info: 2 changes previewed:
    + 2 resources to create

Do you want to perform this update? yes
Updating stack 'hello-dev'
Performing changes:

     Type                    Name             Status      Info
 +   pulumi:pulumi:Stack     hello-hello-dev  created     
 +   └─ kubernetes:core:Pod  hello            created     
 
info: 2 changes performed:
    + 2 resources created
Update duration: 10.132746709s

Acessando o serviço:

$ kubectl port-forward pod/hello 9090:9090

$ curl http://localhost:9090/
Hello World!

Destaques

  • Foco principal em automação de código de infraestrutura.
  • Possibilidade de usar sua linguagem de programação favorita para controlar a infraestrutura.
  • A aplicação deve ser programada com paradigma de funções (como o AWS Lambda) ou como uma imagem docker para deploy automático.
  • Suporte a quase todos os provedores de nuvem públicos e Kubernetes.
  • Capacidade de criar regras de deploy complexas em apenas algumas linhas de código sem a necessidade de arquivos YAML escritos à mão.
  • Totalmente automatizada.
  • Dependência do fornecedor, visto que é necessário criar uma conta em http://pulumi.io.

Resumo

Com a emergente onda de arquiteturas em microservices, a indústria de software está se movendo em direção ao desenvolvimento e deploy de aplicação nativas para nuvem. O Docker e Kubernetes são os elementos chaves para deploy moderno de aplicações nativas para nuvem. No entanto, o requisito de criar manualmente os arquivos YAML de deploy é entediante e propenso a erros.

Uma maneira popular de fazer o deploy de aplicação no Kubernetes é adotando diferentes ferramentas e frameworks. Draft, Gitkube, Helm, Ksonnet e Skaffold são ferramentas populares que lideram neste sentido, e um artigo muito interessante que compara estas diferentes ferramentas pode ser encontrado aqui, comparando como estas ferramentas ajudam os desenvolvedores a construir e a fazer o deploy de suas aplicações no Kubernetes. Todas estas ferramentas possuem fluxos de trabalho diferentes para resolver o mesmo problema, que é aumentar a agilidade e produtividade no deploy de aplicações no Kubernetes.

Assim, Metaparticle, Ballerina e Pulumi criaram abordagens diferentes que dão poder ao desenvolvedor na manipulação do deploy automático com a linguagem de programação favorita sem a necessidade de arquivos YAML. Esta é uma tendência que irá mudar as práticas de DevOps na indústria de software.

Sobre o autor

Lakmal Warusawithana trabalha como diretor sênior e arquiteto na WSO2, a maior provedora de integração Open Source. Tem um vasto histórico trabalhando com open source, cloud, e tecnologias DevOps e é vice-presidente do projeto Apache Stratos PaaS. Em 2005, co-fundou a thinkCube, pioneira nas novas gerações de produtos de computação em nuvem colaborativa adaptadas para operadoras de telecomunicações. Foi responsável por revisar todo o processo de engenharia, dando atenção especial para escalabilidade e entrega de serviços e soluções da thinkCube. Antes da co-fundação da thinkCube, passou quatro anos na ITABS, empresa especializada em servidores de deploy Linux com uma interface de gestão de servidores personalizada e fácil de usar. Também se apresentou em eventos, incluindo ApacheCon, CloudOpen, QCon, JaxLonden, Cloud Expo, Cloudstack Collaboration Conference, WSO2CON e várias outros meetups de tecnologia. Possui um diploma de bacharel em Ciências da Computação pela Universidade de Colombo, Sri Lanka.

Avalie esse artigo

Relevância
Estilo/Redação

Olá visitante

Você precisa cadastrar-se no InfoQ Brasil ou para enviar comentários. Há muitas vantagens em se cadastrar.

Obtenha o máximo da experiência do InfoQ Brasil.

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

Comentários da comunidade

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

BT

Seu cadastro no InfoQ está atualizado? Poderia rever suas informações?

Nota: se você alterar seu email, receberá uma mensagem de confirmação

Nome da empresa:
Cargo/papel na empresa:
Tamanho da empresa:
País:
Estado:
Você vai receber um email para validação do novo endereço. Esta janela pop-up fechará em instantes.