Escolar Documentos
Profissional Documentos
Cultura Documentos
Conceitos importantes sobre automatização da implantação, escalonamento e gerenciamento de aplicações via Kubernetes e via OpenShift,
computação acelerada por GPU com Python e Docker Swarm.
PROPÓSITO
O emprego de ferramentas avançadas de desenvolvimento permite ao DevSecOps (desenvolvimento, segurança e operação) obter agilidade,
segurança e ganho de produtividade. Portanto, é importante compreender os conceitos envolvidos e escolher soluções adequadas, como
Kubernetes e OpenShift para automatizar a implantação, o escalonamento e o gerenciamento de aplicações; e de computação acelerada por
GPU com Python e Docker Swarm.
PREPARAÇÃO
É necessário um computador com o sistema operacional Linux, podendo ser uma máquina física ou virtual, com acesso à internet.
OBJETIVOS
MÓDULO 1
MÓDULO 2
MÓDULO 3
MÓDULO 4
MÓDULO 1
Para atender a essa demanda, grandes servidores passaram a utilizar a tecnologia de containers em substituição às máquinas virtuais.
Containers
Diferentemente das máquinas virtuais, os containers usam o sistema operacional (SO) do host, em vez de trazerem um sistema próprio.
Como eles não incluem o sistema operacional completo, os containers exigem recursos computacionais mínimos e são rápidos e fáceis de
instalar.
Essa eficiência permite que eles sejam implantados em clusters, com os containers individuais encapsulando componentes únicos de
aplicativos complexos.
Separar os componentes dos aplicativos em containers diferentes permite que os desenvolvedores atualizem componentes individuais sem
retrabalhar todo o aplicativo.
KUBERNETES
Para facilitar a tarefa de orquestrar microsserviços distribuídos em containers ao longo de clusters, várias soluções de orquestração foram
criadas, entre elas a Kubernetes ou “k8s”, que é uma plataforma de código aberto, desenvolvida pelo Google e disponibilizada em
2014, portável e extensiva para o gerenciamento de cargas de trabalho e serviços distribuídos em containers, que facilita tanto a
configuração declarativa quanto a automação dos containers Linux.
Um cluster Kubernetes consiste em um conjunto de servidores de processamento, chamados nós, que executam aplicações containerizadas.
Todo cluster possui ao menos um servidor de processamento (worker node).
O servidor de processamento hospeda os Pods, que são componentes de uma aplicação. O ambiente de gerenciamento gerencia os nós de
processamento e os Pods no cluster. Em ambientes de produção, o ambiente de gerenciamento geralmente executa em múltiplos
computadores e um cluster geralmente executa em múltiplos nós (nodes), provendo tolerância a falhas e alta disponibilidade.
KUBERNETES IMPLEMENTA TODOS OS MECANISMOS DE ALTA
DISPONIBILIDADE, ISOLAMENTO E ALTA PERFORMANCE DE
CLUSTERS TRADICIONAIS, SÓ QUE AQUI, APLICADO AO CONCEITO DE
CONTAINERS.
Dessa forma, Kubernetes torna possível a criação de um ambiente crítico e concorrente sob a perspectiva de microsserviços, totalmente
baseado em containers, implementa, ainda, um alto nível de abstração. Essa abstração, chamada de Pods, faz com que os containers
sejam independentes da máquina nó. Dentre as várias vantagens, está a facilidade de fazer com que um container “enxergue” o(s) outro(s)
dentro do cluster.
Além de possuir interface gráfica que permite monitorar o ambiente de maneira visual, o Kubernetes permite resolver vários problemas
críticos do uso de cluster de containers, entre eles:
Possibilita o deploy de aplicações em containers Docker (mas não apenas ele) de maneira eficiente e simplificada
Os componentes da camada de gerenciamento tomam decisões globais sobre o cluster (por exemplo, agendamento de Pods), bem como
detectam e respondem aos eventos do cluster (por exemplo, iniciando um novo Pod quando o campo réplicas de um Deployment não está
atendido).
Os componentes da camada de gerenciamento podem ser executados em qualquer máquina do cluster. Contudo, para simplificar, os scripts
de configuração normalmente iniciam todos os componentes da camada de gerenciamento na mesma máquina, e não executam containers
de usuário nessa máquina.
KUBEADM
Ferramenta desenvolvida para fornecer "atalhos" de práticas recomendadas para a criação de clusters Kubernetes.
KUBELET
Agente que é executado em cada nó no cluster. Ele garante que os containers estejam sendo executados em um Pod.
KUBECTL
Utilitário de linha de comando usado para se comunicar com o servidor da API do cluster.
INSTALAÇÃO E CONFIGURAÇÃO DO KUBERNETES
Existem distribuições para os principais sistemas operacionais. Optaremos pelo mais recomendado, o Linux.
Para isso, precisaremos da configuração básica de processador com mínimo de 2 CPUs, 2GB ou mais de memória RAM por máquina,
conectividade total entre as máquinas do cluster (neste caso internet – nuvem) e nome de host exclusivo, endereço MAC e product_uuid para
cada nó.
DICA
Você pode obter o endereço MAC das interfaces de rede usando o comando ip link ou ifconfig -a. O product_uuid pode ser verificado usando
o comando sudo cat/sys/class/dmi/id/product_uuid. É muito provável que os dispositivos de hardware tenham endereços exclusivos, embora
algumas máquinas virtuais possam ter valores idênticos.
Se esses valores não forem exclusivos para cada nó, o processo de instalação pode falhar. Se você tiver mais de um adaptador de rede e
seus componentes do Kubernetes não forem alcançáveis na rota padrão, recomendo adicionar rota (s) IP para que os endereços de cluster
do Kubernetes passem pelo adaptador apropriado.
Certifique-se de que o módulo br_netfilter esteja carregado. Isso pode ser feito executando lsmod | grep br_netfilter. Para carregá-lo
explicitamente, chame sudo modprobe br_netfilter.
Como um requisito para o iptables do seu nó Linux ver corretamente o tráfego em ponte, você deve garantir que net.bridge.bridge-nf-call-
iptables esteja definido como 1 em sua configuração sysctl, como exemplo:
Usaremos uma distribuição baseada em Debian para este exemplo. Siga os passos abaixo:
O kubelet agora está reiniciando a cada poucos segundos, enquanto espera em um loop de travamento que o kubeadm diga a ele o que
fazer.
Tanto o tempo de execução do container quanto o kubelet têm uma propriedade chamada "driver cgroup", que é importante para o
gerenciamento de cgroups em máquinas Linux.
O kubeadm permite que você transmita uma estrutura KubeletConfiguration durante a inicialização do kubeadm. Esse KubeletConfiguration
pode incluir o campo cgroupDriver que controla o driver cgroup do kubelet. Se não definirmos o campo cgroupDriver em
KubeletConfiguration, o init do kubeadm o padronizará como systemd.
Crie um balanceador de carga kube-apiserver com um nome que possa ser resolvido por um servidor DNS. Em um ambiente de nuvem, você
deve colocar os nós do plano de controle atrás de um balanceador de carga de encaminhamento de TCP. Esse balanceador de carga
distribui o tráfego para todos os nós do plano de controle íntegros em sua lista de destino. A verificação de saúde de um apiserver é uma
verificação de TCP na porta em que o kube-apiserver escuta (valor padrão: 6443).
ATENÇÃO
Não é recomendado usar um endereço IP diretamente em um ambiente de nuvem. O balanceador de carga deve ser capaz de se comunicar
com todos os nós do plano de controle na porta apiserver. Ele também deve permitir o tráfego de entrada em sua porta de escuta. Certifique-
se de que o endereço do balanceador de carga sempre corresponda ao endereço do ControlPlaneEndpoint do kubeadm.
A configuração keepalived consiste em dois arquivos: o arquivo de configuração de serviço e um script de verificação de saúde que
será chamado periodicamente para verificar se o nó que contém o IP virtual ainda está operacional. Presume-se que os arquivos
residam em um diretório / etc / keepalived. Observe que, no entanto, algumas distribuições do Linux podem mantê-los em outro lugar.
A seguinte configuração foi usada com sucesso com o keepalived versão 2.0.17:
1 ! /etc/keepalived/keepalived.conf
2 ! Configuration File for keepalived
3 global_defs {
4 router_id LVS_DEVEL
5 }
6 vrrp_script check_apiserver {
7 script "/etc/keepalived/check_apiserver.sh"
8 interval 3
9 weight -2
10 fall 10
11 rise 2
12 }
13
14 vrrp_instance VI_1 {
15 state ${STATE}
16 interface ${INTERFACE}
17 virtual_router_id ${ROUTER_ID}
18 priority ${PRIORITY}
19 authentication {
20 auth_type PASS
21 auth_pass ${AUTH_PASS}
22 }
23 virtual_ipaddress {
24 ${APISERVER_VIP}
25 }
26 track_script {
27 check_apiserver
28 }
29 }
${STATE} é MASTER para um e BACKUP para todos os outros hosts, portanto, o IP virtual será inicialmente atribuído ao MASTER.
${INTERFACE} é a interface de rede que participa da negociação do IP virtual, por exemplo, eth0.
${ROUTER_ID} deve ser o mesmo para todos os hosts de cluster keepalived, embora único entre todos os clusters na mesma sub-rede.
Muitas distros pré-configuram seu valor para 51.
${PRIORITY} deve ser maior no nó do plano de controle do que nos backups. Portanto, 101 e 100, respectivamente, serão suficientes.
${AUTH_PASS} deve ser o mesmo para todos os hosts de cluster keepalived, por exemplo, 42.
1 #!/bin/sh
2
3 errorExit() {
4 echo "*** $*" 1>&2
5 exit 1
6 }
7 curl --silent --max-time 2 --insecure https://localhost:${APISERVER_DEST_PORT}/ -o /dev/null || errorExit "E
8 if ip addr | grep -q ${APISERVER_VIP}; then
9 curl --silent --max-time 2 --insecure https://${APISERVER_VIP}:${APISERVER_DEST_PORT}/ -o /dev/null || e
10 fi
$ {APISERVER_VIP}
$ {APISERVER_DEST_PORT}
A porta por meio da qual o Kubernetes se comunicará com o servidor da API.configuração proxy.
A configuração do HAProxy consiste em um arquivo: o arquivo de configuração do serviço que se supõe residir em um diretório /etc/haproxy.
Observe que, no entanto, algumas distribuições do Linux podem mantê-los em outro lugar. A seguinte configuração foi usada com sucesso
com o haproxy versão 2.1.4:
1
1
2 # /etc/haproxy/haproxy.cfg
3 #---------------------------------------------------------------------
4 # Global settings
5 #---------------------------------------------------------------------
6 global
7 log /dev/log local0
8 log /dev/log local1 notice
9 daemon
10
11 #---------------------------------------------------------------------
12 # common defaults that all the 'listen' and 'backend' sections will
13 # use if not designated in their block
14 #---------------------------------------------------------------------
15 defaults
16 mode http
17 log global
18 option httplog
19 option dontlognull
20 option http-server-close
21 option forwardfor except 127.0.0.0/8
22 option redispatch
23 retries 1
24 timeout http-request 10s
25 timeout queue 20s
26 timeout connect 5s
27 timeout client 20s
28 timeout server 20s
29 timeout http-keep-alive 10s
30 timeout check 10s
31
32 #---------------------------------------------------------------------
33
33
# apiserver frontend which proxys to the control plane nodes
34
#---------------------------------------------------------------------
35
frontend apiserver
36
bind *:${APISERVER_DEST_PORT}
37
mode tcp
38
option tcplog
39
default_backend apiserver
40
41
#---------------------------------------------------------------------
42
# round robin balancing for apiserver
43
#---------------------------------------------------------------------
44
backend apiserver
45
option httpchk GET /healthz
46
http-check expect status 200
47
mode tcp
48
option ssl-hello-chk
49
balance roundrobin
50
server ${HOST1_ID} ${HOST1_ADDRESS}:${APISERVER_SRC_PORT} check
# [...]
Novamente, existem alguns marcadores de posição no estilo de variável bash para expandir:
$ {APISERVER_DEST_PORT}: a porta por meio da qual o Kubernetes se comunicará com o servidor da API.
$ {HOST1_ID}: um nome simbólico para o primeiro host do servidor API com balanceamento de carga.
$ {HOST1_ADDRESS}: um endereço resolvível (nome DNS, endereço IP) para o primeiro host do servidor API com balanceamento de carga.
Linhas de servidor adicionais, uma para cada host de servidor API com balanceamento de carga.
Se o keepalived e haproxy forem executados nos nós do plano de controle, eles podem ser configurados para serem executados
como pods estáticos. Tudo o que é necessário aqui é colocar os respectivos arquivos de manifesto no diretório /etc/kubernetes/manifests
antes de inicializar o cluster. Durante o processo de bootstrap, o kubelet ativará os processos para que o cluster possa usá-los durante a
inicialização. Para essa configuração, dois arquivos de manifesto precisam ser criados em /etc/ kubernetes /manifests.
1 apiVersion: v1
2 kind: Pod
3 metadata:
4 name: haproxy
5 namespace: kube-system
6 spec:
7 containers:
8 - image: haproxy:2.1.4
9 name: haproxy
10 livenessProbe:
11 failureThreshold: 8
12 httpGet:
13 host: localhost
14 path: /healthz
15 port: ${APISERVER_DEST_PORT}
16 scheme: HTTPS
17
18 volumeMounts:
19 - mountPath: /usr/local/etc/haproxy/haproxy.cfg
20 name: haproxyconf
21 readOnly: true
22 hostNetwork: true
23 volumes:
24 - hostPath:
25 path: /etc/haproxy/haproxy.cfg
26 type: FileOrCreate
27 name: haproxyconf
status: {}
Observe que aqui, novamente, um placeholder precisa ser preenchido: ${APISERVER_DEST_PORT} precisa conter o mesmo valor que em
/etc/haproxy/haproxy.cfg (veja no código anterior). Essa combinação foi usada com sucesso com as versões utilizadas no exemplo. Outras
versões também podem funcionar ou podem exigir alterações nos arquivos de configuração. Com os serviços ativados, agora o cluster
Kubernetes pode ser inicializado usando o kubeadm ini.
AUTOMATIZANDO APLICAÇÕES COM KUBERNETES
Para finalizar o estudo desse módulo, assista ao vídeo a seguir. Nele, apresentamos um estudo de caso de automatização da implantação,
escalonamento e gerenciamento de aplicações via Kubernetes:
VERIFICANDO O APRENDIZADO
MÓDULO 2
INTRODUÇÃO
Com as facilidades advindas do uso de tecnologia, o software está se tornando a ferramenta na qual se constrói o futuro de nossas
empresas, sejam pequenas ou grandes. No centro dessa mudança está a evolução do próprio desenvolvimento de software.
CRIAR MODELOS DE DESENVOLVIMENTO MAIS DINÂMICOS E
ESCALONÁVEIS E AS PRÁTICAS ÁGEIS DE DESENVOLVIMENTO SÃO
AÇÕES NECESSÁRIAS PARA SE MANTER COMPETITIVO NO MERCADO.
Os containers Linux se posicionaram no mercado como a nova base sobre a qual se deve construir conexões entre o desenvolvimento e as
operações, e aproveitar a infraestrutura para seu aplicativo, desde nuvem pública à infraestrutura privada, tornou-se uma necessidade.
OPENSHIFT
O OpenShift é um produto de software de computador da Red Hat para implantação e gerenciamento de softwares baseados em container.
Ele é uma distribuição suportada do Kubernetes usando Docker e ferramentas DevOps para desenvolvimento acelerado de aplicações.
Red Hat OpenShift
O Red Hat OpenShift pode ser executado em qualquer cloud, com recursos avançados para implantações em cloud híbrida.
O OpenShift Container Platform pode ser usado em infraestruturas on-premise e de cloud pública.
Isso permite uma abordagem híbrida para a implantação de aplicações como soluções autogerenciadas. Todas as variantes da plataforma
do OpenShift estão disponíveis para acelerar a produtividade do desenvolvedor e fornecer a portabilidade de aplicações em uma
base consistente na cloud híbrida.
O objetivo do OpenShift é fornecer a melhor experiência para desenvolvedores e administradores de sistemas de desenvolvimento,
implantação e execução de aplicativos.
Em outras palavras, OpenShift é uma camada além do Docker e do Kubernetes, que o torna acessível e fácil para o desenvolvedor para criar
aplicativos e uma plataforma que é um sonho para as operadoras implantarem para cargas de trabalho de desenvolvimento e produção.
Depois que o Docker estiver instalado, inicie o serviço Docker e habilite-o para iniciar na inicialização com os seguintes comandos:
systemctl start docker
Vamos utilizar a versão V3.11.0 do OpenShift Origin. Você pode baixá-lo do repositório Git Hub usando o seguinte comando:
wget https://github.com/openshift/origin/releases/download/v3.11.0/openshift-origin-client-tools-v3.11.0-0cbc58b-linux-64bit.tar.gz
Assim que o download for concluído, extraia o arquivo baixado com o seguinte comando:
Em seguida, altere o diretório para o diretório extraído e copie os binários kubectl e oc para o diretório /usr/local/ bin.
cd openshift-origin-client-tools-v3.11.0-0cbc58b-linux-64bit
cp oc kubectl /usr/local/bin/
oc version
oc v3.11.0+0cbc58b
kubernetes v1.11.0+d4cacc0
Em seguida, você precisará criar um novo arquivo daemon.json e permitir o uso do registro Insecure Docker.
nano /etc/docker/daemon.json
"insecure-registries" : [ "172.30.0.0/16" ]
}
oc cluster up --public-hostname=your-server-ip
Assim que o servidor for iniciado com sucesso, você deve obter o seguinte resultado:
Agora, faça login em seu cluster como usuário administrador com o seguinte comando:
oc login -u system:admin
Depois de fazer o login, você deve obter o seguinte resultado:
oc project default
oc status
Você deve obter a seguinte saída:
Agora, faça login no OpenShift com o usuário desenvolvedor com o seguinte comando:
oc login
Será solicitado que você forneça um nome de usuário e uma senha conforme mostrado abaixo:
Forneça o nome de usuário como desenvolvedor e a senha como desenvolvedor e pressione Enter. Você deve ver a seguinte saída:
Login successful.
You have one project on this server: "myproject"
Using project "myproject".
Agora, abra seu navegador e digite a URL https: //seu-ip-servidor: 8443/console. Você deverá ver a página de login do OpenShift:
Forneça todas as informações necessárias e clique no botão Criar para criar um novo projeto (Create Project).
Captura de tela de console do Software OpenShift – Criar projeto.
Para implantar aplicativo no OpenShift Origin, primeiro, faça login no OpenShift com o usuário desenvolvedor executando o seguinte
comando:
oc login
Depois de fazer o login, mude o projeto para my-project, que você criou por meio do console da Web OpenShift:
oc project my-project
Resultado:
oc status
Resultado:
Em seguida, marque uma imagem de aplicativo no registro do Docker Hub com o seguinte comando:
oc tag --source=docker openshift/deployment-example:v2 deployment-example:latest
Resultado:
oc new-app deployment-example
1 --> Found image da61bb2 (4 years old) in image stream "my-project/deployment-example" under tag "latest" for
2 * This image will be deployed in deployment config "deployment-example"
3 * Port 8080/tcp will be load balanced by service "deployment-example"
4 * Other containers can access this service through the hostname "deployment-example"
5 * WARNING: Image "my-project/deployment-example:latest" runs as the 'root' user which may not be permitt
6 --> Creating resources ...
7 deploymentconfig.apps.openshift.io "deployment-example" created
8 service "deployment-example" created
9 --> Success
10 Application is not exposed. You can expose services to the outside world by executing one or more of the
11 'oc expose svc/deployment-example'
12 Run 'oc status' to view your app.
oc get svc
Resultado:
Resultado:
1
2 Name: deployment-example
3 Namespace: my-project
4 Labels: app=deployment-example
5
6 Annotations: openshift.io/generated-by=OpenShiftNewApp
7 Selector: app=deployment-example,deploymentconfig=deployment-example
8 Type: ClusterIP
9 IP: 172.30.87.146
10 Port: 8080-tcp 8080/TCP
11 TargetPort: 8080/TCP
12 Endpoints: 172.17.0.10:8080
Session Affinity: None
Events:
Você também pode verificar o status dos pods usando o seguinte comando:
oc get pods
Resultado:
1 Resultado:
2 NAME READY STATUS RESTARTS AGE
3 deployment-example-1-b9prf 1/1 Running 0 2m
oc expose service/deployment-example
Resultado:
Resultado:
route.route.openshift.io/deployment-example exposed
oc get routes
MÓDULO 3
Há uma série de fatores que influenciam a popularidade do Python, incluindo sua sintaxe limpa e expressiva, estruturas de dados padrão,
biblioteca padrão abrangente, "baterias incluídas", documentação excelente, amplo ecossistema de bibliotecas e ferramentas, disponibilidade
de suporte profissional e uma grande e aberta comunidade.
Talvez o mais importante, porém, seja a alta produtividade que uma linguagem interpretada e digitada dinamicamente como o Python permite.
Python é ágil e flexível, o que o torna uma ótima linguagem para prototipagem rápida, mas também para construir sistemas completos.
ATENÇÃO
Mas a maior força do Python também pode ser sua maior fraqueza: sua flexibilidade e sintaxe de alto nível sem tipo podem resultar em baixo
desempenho para programas com uso intensivo de dados e computação. Por esse motivo, os programadores Python preocupados com a
eficiência geralmente reescrevem seus loops mais internos em C e chamam as funções C compiladas do Python.
Existem vários projetos que visam tornar essa otimização mais fácil, como o Cython, mas geralmente exigem o aprendizado de uma nova
sintaxe. Idealmente, os programadores Python gostariam de tornar seu código Python existente mais rápido sem usar outra linguagem de
programação e, naturalmente, muitos gostariam de usar aceleradores para obter um desempenho ainda maior de seu código.
CUDA/NVIDIA
GPUS
Com ele, toda a parte “pesada” do código é executada nos diversos núcleos da placa de vídeo enquanto apenas a parte sequencial do
código é executada no processador, obtendo um ganho significativo de performance.
ATENÇÃO
O uso da GPU tem custos indiretos. Se o cálculo não for pesado o suficiente, o custo (em tempo) de usar uma GPU pode ser maior do que o
ganho. Por outro lado, se o cálculo for pesado, você pode ver uma grande melhoria na velocidade.
Device: a GPU
Device function: uma função GPU executada no dispositivo que só pode ser chamada a partir do dispositivo (ou seja, a partir de um kernel ou
outra função do dispositivo).
Numba oferece suporte à programação de GPU CUDA compilando diretamente um subconjunto restrito de código Python em kernels CUDA e
funções de dispositivo seguindo o modelo de execução CUDA. Kernels escritos em Numba parecem ter acesso direto aos arrays NumPy.
Matrizes NumPy são transferidas entre a CPU e a GPU automaticamente. Numba funciona permitindo que você especifique assinaturas de
tipo para funções Python, o que permite a compilação em tempo de execução (isto é, “Just-in-Time” ou compilação JIT).
A capacidade do Numba de compilar código dinamicamente significa que você não abre mão da flexibilidade do Python. Esse é um
grande passo para fornecer a combinação ideal de programação de alta produtividade e computação de alto desempenho.
EXEMPLO
O decorador @vectorize, no código a seguir, gera uma versão compilada e vetorizada da função escalar em tempo de execução para que
possa ser usada para processar matrizes de dados em paralelo na GPU.
1
2 import numpy as np
3 from numba import vectorize
4
5
5
@vectorize(['float32(float32, float32)'], target='cuda')
6
def Add(a, b):
7
return a + b
8
9
# Initialize arrays
10
N = 100000
11
A = np.ones(N, dtype=np.float32)
12
B = np.ones(A.shape, dtype=A.dtype)
13
C = np.empty_like(A, dtype=A.dtype)
14
15
# Add arrays on GPU
C = Add(A, B)
Para compilar e executar a mesma função na CPU, simplesmente mudamos o destino para 'cpu', o que produz desempenho no nível do
código C vetorizado e compilado na CPU. Essa flexibilidade ajuda a produzir código mais reutilizável e permite desenvolver em máquinas
sem GPUs.
Um dos pontos fortes da plataforma de computação paralela CUDA é a variedade de bibliotecas aceleradas por GPUs disponíveis.
Outro projeto da equipe Numba, chamado pyculib, fornece uma interface Python para as bibliotecas CUDA cuBLAS (álgebra linear densa),
cuFFT (Fast Fourier Transform) e cuRAND (geração de número aleatório).
Muitos aplicativos serão capazes de obter uma aceleração significativa apenas usando essas bibliotecas, sem escrever nenhum código
específico da GPU. Por exemplo, o código a seguir gera um milhão de números aleatórios uniformemente distribuídos na GPU usando o
gerador de números pseudoaleatórios “XORWOW”.
1 import numpy as np
2 from pyculib import rand as curand
3
3
4
prng = curand.PRNG(rndtype=curand.PRNG.XORWOW)
5
rand = np.empty(100000)
6
prng.uniform(rand)
7
print rand[:10]
INSTALAÇÃO DO NUMBA
O back-end da GPU do Numba utiliza o NVIDIA Compiler SDK baseado em LLVM. Os wrappers pyculib em torno das bibliotecas CUDA
também são de código aberto e licenciados por BSD.
Para começar a usar o Numba, a primeira etapa é baixar e instalar a distribuição Anaconda Python, uma "distribuição Python totalmente
gratuita, pronta para empresas, para processamento de dados em grande escala, análise preditiva e computação científica" que inclui muitos
pacotes populares (Numpy, SciPy, Matplotlib, IPython etc).
Digite o comando:
apt-get install libgl1-mesa-glx libegl1-mesa libxrandr2 libxrandr2 libxss1 libxcursor1 libxcomposite1 libasound2
Agora, você pode ativar a instalação fazendo um source no arquivo ~/.bashrc: source ~/.bashrc
Assim que tiver feito isso, você será levado ao ambiente de programação padrão de base do Anaconda, e seu prompt de comando mudará
para o seguinte: (base) summy@ubuntu:~$
Embora o Anaconda venha com esse ambiente de programação padrão de base, você deve criar ambientes separados para seus
programas e mantê-los isolados um do outro. Você pode, ainda, verificar sua instalação fazendo o uso do comando conda, por exemplo,
com list:
Agora que o Anaconda está instalado, podemos seguir em frente para a configuração dos ambientes dele.
ATENÇÃO
Os ambientes virtuais do Anaconda lhe permitem manter projetos organizados pelas versões do Python e pelos pacotes necessários. Para
cada ambiente do Anaconda que você configurar, especifique qual versão do Python usar e mantenha todos os arquivos de programação
relacionados dentro desse diretório.
Primeiro, podemos verificar quais versões do Python estão disponíveis para que possamos usar: (base) summy@ubuntu:~$ conda search
"^python$"
Podemos conseguir isso atribuindo a versão 3 ao argumento python. Vamos chamar o ambiente de my_env, mas você pode usar um nome
mais descritivo para o ambiente, especialmente se estiver usando ambientes para acessar mais de uma versão do Python.
Você receberá uma saída com informações sobre o que está baixado e quais pacotes serão instalados e, em seguida, será solicitado a
prosseguir com y ou n. Assim que concordar, digite y.
O utilitário conda agora irá obter os pacotes para o ambiente e informá-lo assim que estiver concluído. Você pode ativar seu novo ambiente
digitando o seguinte:
(base) summy@ubuntu:~$ conda activate my_env
Com seu ambiente ativado, seu prefixo do prompt de comando irá refletir que você não está mais no ambiente base, mas no novo ambiente
que acabou de criar.
(my_env) summy@ubuntu:~$
Dentro do ambiente, você pode verificar se está usando a versão do Python que tinha intenção de usar: (my_env) summy@ubuntu:~$ python
–version
RESPOSTA
Python 3.8.2
Quando estiver pronto para desativar seu ambiente do Anaconda, você pode fazer isso digitando: (my_env) summy@ubuntu:~$ conda
deactivate
Observe que pode substituir a palavra source por . para obter os mesmos resultados. Para focar em uma versão mais específica do
Python, você pode passar uma versão específica para o argumento python, como 3.5, por exemplo:
Você pode inspecionar todos os ambientes que configurou com este comando:
(base) summy@ubuntu:~$ conda info –envs
# conda environments:
#
base * /home/sammy/anaconda3
my_env /home/sammy/anaconda3/envs/my_env
my_env35 /home/sammy/anaconda3/envs/my_env35
O asterisco indica o ambiente ativo atual. Cada ambiente que você criar com o conda create virá com vários pacotes padrão:
_libgcc_mutex
ca-certificates
certifi
libedit
libffi
libgcc-ng
libstdcxx-ng
ncurses
openssl
pip
python
readline
setuptools
sqlite
tk
wheel
xz
zlib
Você pode acrescentar pacotes adicionais, como o Numpy, por exemplo, com o seguinte comando:
Se você não estiver mais trabalhando em um projeto específico e não tiver mais necessidade do ambiente associado, pode removê-lo. Para
fazer isso, digite o seguinte:
ATENÇÃO
Agora, quando você digitar o comando conda info --envs, o ambiente que removeu não será mais listado.
Você deve garantir regularmente que o Anaconda esteja atualizado para que você esteja trabalhando com todas as versões mais recentes do
pacote. Para fazer isso, deve primeiro atualizar o utilitário conda: (base) summy@ubuntu:~$ conda update conda
Quando solicitado a fazer isso, digite y para continuar com a atualização. Assim que a atualização do conda estiver concluída, você pode
atualizar a distribuição do Anaconda:
ATENÇÃO
Novamente, quando solicitado a fazer isso, digite y para continuar. Isso garantirá que você esteja usando as versões mais recentes do conda
e do Anaconda.
Depois de instalar o Anaconda, instale os pacotes CUDA necessários digitando:
O Anaconda (anteriormente Continuum Analytics) reconheceu que alcançar grandes acelerações em alguns cálculos requer uma interface de
programação mais expressiva com controle mais detalhado sobre o paralelismo do que as bibliotecas e a vetorização automática de loop
podem fornecer.
Portanto, o Numba possui outro conjunto importante de recursos que constitui o que é conhecido não oficialmente como “CUDA
Python”.
Numba expõe o modelo de programação CUDA, assim como em CUDA C / C ++, mas usando a sintaxe Python pura, para que os
programadores possam criar kernels paralelos personalizados e ajustados sem deixar o conforto e as vantagens do Python para trás. O
CUDA JIT da Numba (disponível via decorador ou chamada de função) compila funções CUDA Python em tempo de execução,
especializando-as para os tipos que você usa, e sua API CUDA Python fornece controle explícito sobre transferências de dados e fluxos
CUDA, entre outros recursos.
O exemplo de código a seguir demonstra isso com um kernel de conjunto Mandelbrot simples. Observe que a função mandel_kernel
usa as estruturas cuda.threadIdx, cuda.blockIdx, cuda.blockDim e cuda.gridDim fornecidas por Numba para calcular os índices globais de
pixel X e Y para o segmento atual. Como em outras linguagens CUDA, lançamos o kernel inserindo uma "configuração de execução"
(linguagem CUDA para o número de threads e blocos de threads a serem usados para executar o kernel) entre colchetes, entre o nome da
função e a lista de argumentos: mandel_kernel [griddim, blockdim] (- 2.0, 1.0, -1.0, 1.0, d_image, 20). Você também pode ver o uso das
funções de API to_host e to_device para copiar dados de e para a GPU.
1
2 @cuda.jit
3 def mandel_kernel(min_x, max_x, min_y, max_y, image, iters):
4 height = image.shape[0]
5 width = image.shape[1]
6
7 pixel_size_x = (max_x - min_x) / width
8 pixel_size_y = (max_y - min_y) / height
9
10 startX = cuda.blockDim.x * cuda.blockIdx.x + cuda.threadIdx.x
11 startY = cuda.blockDim.y * cuda.blockIdx.y + cuda.threadIdx.y
12 gridX = cuda.gridDim.x * cuda.blockDim.x;
13 gridY = cuda.gridDim.y * cuda.blockDim.y;
14
15 for x in range(startX, width, gridX):
16 real = min_x + x * pixel_size_x
17 for y in range(startY, height, gridY):
18 imag = min_y + y * pixel_size_y
19 image[y, x] = mandel(real, imag, iters)
20
21 gimage = np.zeros((1024, 1536), dtype = np.uint8)
22 blockdim = (32, 8)
23 griddim = (32,16)
24
25 start = timer()
26 d_image = cuda.to_device(gimage)
27 mandel_kernel[griddim, blockdim](-2.0, 1.0, -1.0, 1.0, d_image, 20)
28 d_image.to_host()
29 dt = timer() - start
30
31 print "Mandelbrot created on GPU in %f s" % dt
32
imshow(gimage)
Atenção! Para visualização completa do código utilize a rolagem horizontal
SAIBA MAIS
Em um servidor com uma GPU NVIDIA Tesla P100 e uma CPU Intel Xeon E5-2698 v3, este código CUDA Python Mandelbrot é executado
quase 1700 vezes mais rápido do que a versão Python pura. 1700x pode parecer uma aceleração irreal, mas tenha em mente que estamos
comparando o código Python compilado, paralelo e acelerado por GPU ao código Python interpretado de thread único na CPU.
COMPUTAÇÃO ACELERADA COM PYTHON
No vídeo a seguir, abordamos o conceito de computação acelerada com Python utilizando CUDA/Nvidia:
VERIFICANDO O APRENDIZADO
MÓDULO 4
O Docker permite que você separe seus aplicativos de sua infraestrutura para que possa entregar software rapidamente. Com o Docker, é
possível gerenciar sua infraestrutura da mesma forma que gerencia seus aplicativos. Tirando proveito das metodologias do Docker para
envio, teste e implantação de código rapidamente, você pode reduzir significativamente o atraso entre escrever o código e executá-lo na
produção.
INSTALAÇÃO DO DOCKER
Antes de instalar o Docker Engine pela primeira vez em uma nova máquina host, você precisa configurar o repositório do Docker. Depois
disso, pode instalar e atualizar o Docker a partir do repositório. Atualize o índice do pacote apt e instale os pacotes para permitir que o apt use
um repositório sobre HTTPS:
Use o seguinte comando para configurar o repositório estável. Para adicionar o repositório noturno ou de teste, adicione a palavra nightly ou
test (ou ambos) após a palavra stable nos comandos abaixo:
$ echo \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Atualize o índice do pacote apt e instale a versão mais recente do Docker Engine e containerd ou vá para a próxima etapa para instalar uma
versão específica:
Para instalar uma versão específica do Docker Engine, liste as versões disponíveis no repo, selecione e instale uma. Liste as versões
disponíveis em seu repo:
Este comando baixa uma imagem de teste e a executa em um container. Quando o container é executado, ele imprime uma mensagem
informativa e sai. O Docker Engine está instalado em execução. O grupo docker é criado, mas nenhum usuário é adicionado a ele.
Quando a CLI do Azure for configurada, você precisará fazer login. Você será solicitado a inserir um código em seu navegador. Depois disso,
o comando continuará:
az login
To sign in, use a web browser to open the page https://aka.ms/devicelogin and enter the code C3H44PMX7 to authent
[
{
"cloudName": "AzureCloud",
"id": "xxxxxxx",
"isDefault": true,
"name": "Free Trial",
"state": "Enabled",
"tenantId": "xxxxxx",
"user": {
"name": "xxxxx",
"type": "user"
}
}
]
Depois de fazer login, você pode executar comandos az, como o az account show mostrando algumas informações da conta:
1 {
2 "environmentName": "AzureCloud",
3 "id": "c1ddf2e6-8c94-490c-a1f0-e54d24f76323",
4 "isDefault": true,
5 "name": "Free Trial",
6 "state": "Enabled",
7 "tenantId": "930763d2-b2ba-4d30-bd7b-908bbf4ac227",
8 "user": {
9 "name": "davy.dewaele@ixor.be",
10 "type": "user"
11 }
12 }
ATENÇÃO
Antes de começarmos com o Docker para Azure, devemos criar uma entidade de serviço em nosso Active Directory. Pense nisso como um
usuário que tem permissões para fazer coisas de infraestrutura de baixo nível, como escalar suas VMs, atualizar suas regras de balanceador
de carga. Operações necessárias para uma solução dinâmica Docker Swarm no Azure.
Por meio de um container do docker, conforme descrito no guia do Docker para Azure.
Por meio do Portal do Azure (no módulo Active Directory, criando um registro de aplicativo).
Vamos usar a linha de comando e ativar o container do docker, que leva 3 argumentos:
A Região Azure
Um grupo de recursos
Você precisará fazer o login através do seu navegador para iniciar a CLI. Depois disso, você receberá um bom resumo no final.
Você pode olhar no portal para ver se a entidade de serviço foi criada.
Captura de tela do portal Microsoft Azure após iniciar CLI.
Existem duas maneiras de instalar a oferta Docker para Azure, por meio da IU do Azure, seguindo o link do modelo do Docker para Azure, e
por meio da CLI do Azure, permitindo automatizar ainda mais a implantação. Abordaremos as duas opções.
AppID;
AppSecret;
A criação de toda a pilha levará alguns minutos. Você pode monitorar o progresso na janela de notificações. Quando a implantação for
concluída, você será redirecionado para a seção de visão geral do grupo de recursos. Aqui você encontrará todos os recursos que foram
criados usando o modelo Docker para Azure.
Captura de tela do portal Microsoft Azure visão de recursos.
IP público para o balanceador de carga SSH (para SSH-ing em seu gerenciador de swarm)
Balanceadores de carga
Redes virtuais
Contas de armazenamento
VOCÊ TAMBÉM PODE INSTALAR O DOCKER PARA AZURE USANDO A
CLI.
adServicePrincipalAppID;
adServicePrincipalAppSecret;
docker run -ti docker4x/create-sp-azure docker-for-azure-sp docker-for-azure-rg centralus az group deployment cre
Para saber como se conectar ao gerenciador de swarm, você precisa ir para o modelo de implantação do cluster de swarm (por meio do
grupo de recursos):
Captura de tela do portal Microsoft Azure – grupo de recursos.
DefaultDNSTargets;
SSH targets.
O DefaultDNSTargets dá acesso ao cluster swarm. Todos os aplicativos que forem iniciados lá serão disponibilizados naquele IP. Os
serviços Docker Swarm que expõem uma porta verão sua porta exposta por meio do balanceador de carga externo nesse IP. Os SSH Targets
mostrarão como você pode acessar o cluster swarm via SSH.
Captura de tela do portal Microsoft Azure ‒ DefaultDNSTargets.
Por padrão, o gerenciador Swarm escutará na porta 50000. Para SSH no gerenciador, execute este comando:
ATENÇÃO
Observe como usamos o encaminhamento de chave do Agente SSH. Isso vai se tornar importante mais tarde, quando quisermos fazer login
nos nós de trabalho.
Mas, uma vez que estamos no gerenciador de swarm, podemos executar os comandos docker conhecidos:
Docker version
Welcome to Docker!
swarm-manager000000:~$ docker -v
Docker version 17.06.0-ce, build 02c1d87
Docker containers
1 swarm-manager000000:~$ docker ps
2 CONTAINER ID IMAGE COMMAND CREATED
3 1891668c2a41 docker4x/l4controller-azure:17.06.0-ce-azure2 "loadbalancer run ..." 2 minutes ago
4 5069b42130ea docker4x/meta-azure:17.06.0-ce-azure2 "metaserver -iaas_..." 2 minutes ago
5 1e55147b18b1 docker4x/guide-azure:17.06.0-ce-azure2 "/entry.sh" 2 minutes ago
6 79db940f7e63 docker4x/logger-azure:17.06.0-ce-azure2 "python /server.py" 3 minutes ago
7 456a2a2df8fd docker4x/init-azure:17.06.0-ce-azure2 "/entry.sh" 4 minutes ago
8 20c56749ed4e docker4x/agent-azure:17.06.0-ce-azure2 "supervisord --con..." 5 minutes ago
Você sabe que algo está errado, e um bom lugar para começar é verificar os logs do container docker init-azure (veja abaixo). Normalmente,
os erros surgem ao usar o responsável pelo serviço errado. Em caso de erros, você pode excluir o grupo e começar de novo:
Problemas de depuração. Em termos de depuração, o comando a seguir fornecerá alguns insights sobre o que aconteceu quando o Azure
estava configurando o cluster swarm.
O balanceador de carga externo possui um IP que pode ser acessado da internet. Assim que começarmos a adicionar serviços de enxame
que expõem uma porta, você notará que essas portas também serão exportadas no balanceador de carga.
Captura de tela do portal Microsoft Azure – Balanceador de carga externa.
Observe como agora vemos uma regra associada ao nosso balanceador de carga:
E, se olharmos mais de perto, veremos de fato a regra do balanceador de carga que encaminhará o tráfego externo em nosso balanceador
de carga na porta 00 para nosso serviço Swarm (também em execução na porta 80).
Captura de tela do portal Microsoft Azure – Balanceador externo.
Com todos esses containers sendo gerados, é importante ser capaz de ler arquivos de log para obter melhores insights sobre seus
containers. Você provavelmente está familiarizado com o comando docker logs para ler os logs vindos de um container, mas no Azure, ao
tentar olhar os logs do docker, você receberá o seguinte erro:
swarm-worker000001:~$ docker logs -f d7e9d806f872
Error response from daemon: configured logging driver does not support reading
O Docker para Azure usa um driver de log diferente e usa um container logger-azure para garantir que todos os logs de todos os containers
sejam centralizados. Se você observar o grupo de recursos usados para criar o docker swarm, verá uma conta de armazenamento
chamada on6fwskwzstvqlogs.
Quando você se conecta a esta conta de armazenamento, o Azure mostra os cmds para se conectar a ela a partir do Windows ou Linux.
Captura de tela do portal Microsoft Azure – servidor de arquivos – pasta LOG.
No Linux, você pode montar a pasta de logs em um servidor virtual na mesma região (não funciona nas VMs Docker Swarm).
Captura de tela do portal Microsoft Azure – servidor de arquivos – pasta LOG.
1 mkdir -p /var/logs/docker
2 sudo mount -t cifs //le66r7q7iia3klogs.file.core.windows.net/docker4azurelogs /var/logs/docker -o vers=3.0,u
CONCLUSÃO
CONSIDERAÇÕES FINAIS
Estudamos conceitos importantes sobre automatização da implantação, escalonamento e gerenciamento de aplicações via Kubernetes e via
OpenShift, incluindo estudo de caso na nuvem em ambos. Compreendemos computação acelerada por GPU com Python com CUDA/NVIDIA
e finalizamos com a aprendizagem sobre Docker Swarm, com estudo de caso em Microsoft Azure.
PODCAST
Ouça o podcast a seguir. Nele, apresentamos uma visão geral do conteúdo, focando as vantagens da utilização de containers no
gerenciamento das aplicações comparada a soluções tradicionais, como o uso de máquinas físicas ou virtuais.
AVALIAÇÃO DO TEMA:
REFERÊNCIAS
ARUNDEL, J.; DOMINGUS, J. DevOps nativo de nuvem com Kubernetes ‒ Como construir, implantar e escalar aplicações modernas na
nuvem. São Paulo: Novatec, 2019.
FARBER, R. Cuda: Application Design and Development. Amsterdam: Morgan Kaufmann Publishers, 2011.
FARCIC, V. The DevOps 2.1 Toolkit: Docker Swarm. Birmingham: Packt Publishing, 2017.
EXPLORE+
Para saber mais sobre os assuntos discutidos neste conteúdo, pesquise na internet e assista aos vídeos sobre:
Containers computacionais;
Kubernetes;
CUDA/NVIDIA;
DOCKER.
Amplie seus conhecimentos sobre Kubernetes no site edX da Linux Foundation, e sobre OpenShift, no site RedHat OpenShift.
CONTEUDISTA
Marcelo dos Santos Machado
CURRÍCULO LATTES