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:
- Docker/Kubernetes
- A ferramenta de linha de comando mp-compiler
- 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:
- Ballerina
- 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:
- Docker/Kubernetes
- Instalação do Pulumi (curl -fsSL https://get.pulumi.com/ | sh)
- 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.