<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Wander</title>
    <description>The latest articles on Forem by Wander (@wandpsilva).</description>
    <link>https://forem.com/wandpsilva</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F843109%2F29a285f3-bef9-422d-a943-e39bffa801ec.JPG</url>
      <title>Forem: Wander</title>
      <link>https://forem.com/wandpsilva</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/wandpsilva"/>
    <language>en</language>
    <item>
      <title>Comunicando JAVA com o GeminiAI</title>
      <dc:creator>Wander</dc:creator>
      <pubDate>Wed, 08 Jan 2025 19:56:24 +0000</pubDate>
      <link>https://forem.com/wandpsilva/comunicando-com-o-geminiai-via-java-4470</link>
      <guid>https://forem.com/wandpsilva/comunicando-com-o-geminiai-via-java-4470</guid>
      <description>&lt;p&gt;Se voce programa em Java e nunca 'brincou' com o &lt;a href="https://ai.google.dev/gemini-api/docs" rel="noopener noreferrer"&gt;GeminiAI&lt;/a&gt;, este artigo vai ser um ótimo guia introdutório, aqui vou apresentar de forma bem simples como enviar requisições ao Gemini e retornar um JSON, como uma API Rest. 🐱‍👤&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O que estou usando?&lt;/strong&gt; 👀&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java 17&lt;/li&gt;
&lt;li&gt;Intellij Community 2024.1.1&lt;/li&gt;
&lt;li&gt;Postman&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ai.google.dev/gemini-api/docs/api-key?hl=pt-br" rel="noopener noreferrer"&gt;Chave de acesso ao GeminiAI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  VAMOS COMECAR 🚀
&lt;/h2&gt;

&lt;p&gt;Inicie um projeto simples pelo &lt;a href="https://start.spring.io/" rel="noopener noreferrer"&gt;spring initializer&lt;/a&gt;, e inclua as seguintes dependências no seu POM&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;
&amp;lt;/dependency&amp;gt;

&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.projectlombok&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;lombok&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.18.36&amp;lt;/version&amp;gt;
    &amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;

&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;com.fasterxml.jackson.core&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;jackson-databind&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;2.18.2&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essas dependencias vao possibilitar o uso do &lt;a href="https://projectlombok.org/" rel="noopener noreferrer"&gt;Lombok&lt;/a&gt;, &lt;a href="https://www.baeldung.com/rest-template" rel="noopener noreferrer"&gt;RestTemplate&lt;/a&gt; e &lt;a href="https://www.baeldung.com/jackson-object-mapper-tutorial" rel="noopener noreferrer"&gt;ObjectMapper&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lombok: &lt;em&gt;para evitarmos códigos repetitivos (famosos boilerplates) e para melhorar a legibilidade do nosso código&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;RestTemplate: &lt;em&gt;para realizar a requisição http a API do GeminiAI&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;ObjectMapper: &lt;em&gt;para convertermos o retorno da api do Gemini em JSON&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  CONFIGURANDO O RESTTEMPLATE
&lt;/h2&gt;

&lt;p&gt;Vamos configurar o RestTemplate no nosso projeto Java, para isso criamos uma classe com a anotação @Configuration e com o Bean para defini-lo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder.build();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  CRIANDO O SERVICE
&lt;/h2&gt;

&lt;p&gt;Vamos criar uma classe service para realizar a comunicação com o GeminiAI, esta classe será responsável por toda comunicação e tratamento da resposta do Gemini, e deverá ficar da seguinte forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Service
public class TalkService {
    private final RestTemplate restTemplate;
    private final ObjectMapper objectMapper;

    @Value("${gemini.ai.api.url}")
    private String geminiApiUrl;

    @Value("${gemini.ai.api.key}")
    private String geminiApiKey;

    public TalkService(RestTemplate restTemplate, ObjectMapper objectMapper) {
        this.restTemplate = restTemplate;
        this.objectMapper = objectMapper;
    }

    public String callGeminiAI(TalkRequest input) {
        String url = geminiApiUrl + geminiApiKey;

        GeminiRequest request = new GeminiRequest();
        GeminiRequest.Content content = new GeminiRequest.Content();
        GeminiRequest.Part part = new GeminiRequest.Part();

        part.setText(input.getChat());
        content.setParts(Collections.singletonList(part));
        request.setContents(Collections.singletonList(content));

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity&amp;lt;GeminiRequest&amp;gt; entity = new HttpEntity&amp;lt;&amp;gt;(request, headers);

        ResponseEntity&amp;lt;String&amp;gt; response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);

        try {
            GeminiResponse geminiAIResponse = objectMapper.readValue(response.getBody(), GeminiResponse.class);

            if (geminiAIResponse.getCandidates() != null &amp;amp;&amp;amp; !geminiAIResponse.getCandidates().isEmpty()) {
                GeminiResponse.Candidate candidate = geminiAIResponse.getCandidates().get(0);
                if (candidate.getContent() != null &amp;amp;&amp;amp; candidate.getContent().getParts() != null &amp;amp;&amp;amp; !candidate.getContent().getParts().isEmpty()) {
                    return candidate.getContent().getParts().get(0).getText();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "Falha ao processar resposta da API";
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note que nesta classe estamos usando os POJO's &lt;em&gt;GeminiRequest&lt;/em&gt; e &lt;em&gt;GeminiResponse&lt;/em&gt;, segue abaixo o código para cria-los&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;GeminiRequest&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class GeminiRequest {
    private List&amp;lt;Content&amp;gt; contents;

    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Content {
        private List&amp;lt;Part&amp;gt; parts;
    }

    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Part {
        private String text;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;GeminiResponse&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class GeminiResponse {
    private List&amp;lt;Candidate&amp;gt; candidates;
    private UsageMetadata usageMetadata;
    private String modelVersion;

    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class Candidate {
        private Content content;
        private String finishReason;
        private double avgLogprobs;
    }

    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class Content {
        private List&amp;lt;Part&amp;gt; parts;
    }

    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class Part {
        private String text;
    }

    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class UsageMetadata {
        private int promptTokenCount;
        private int candidatesTokenCount;
        private int totalTokenCount;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  CRIANDO UM CONTROLLER
&lt;/h2&gt;

&lt;p&gt;Vamos agora criar um controller para escutar uma requisição Rest e fazer o processamento através do nosso Service&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@RestController
@RequestMapping("v1")
public class TalkController {
    private final TalkService talkService;

    @Autowired
    public TalkController(final TalkService talkService) {
        this.talkService = talkService;
    }

    @PostMapping("/chat-gemini")
    public TalkResponse talk(@RequestBody TalkRequest talkRequest) {
        TalkResponse response = new TalkResponse();
        response.setResponse(talkService.callGeminiAI(talkRequest));
        return response;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nosso controller também possui POJO's, confira o código deles abaixo&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;TalkRequest&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Getter
@Setter
@AllArgsConstructor
public class TalkRequest {
    private String chat;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;TalkResponse&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class TalkResponse {
    private String response;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  CONFIGURANDO VARIAVEIS NOS PROPERTIES
&lt;/h2&gt;

&lt;p&gt;Voce precisará informar o endpoint de acesso ao GeminiAI e também a sua chave de acesso. Essas informações armazenei no arquivo properties, dado que estamos falando de um simples teste. Confira o arquivo properties com as variáveis necessárias&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spring.application.name=NOME_DA_SUA_APLICACAO

gemini.ai.api.url=https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=
gemini.ai.api.key=SUA_CHAVE_DE_ACESSO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  BORA TESTAR 🐱‍💻
&lt;/h2&gt;

&lt;p&gt;Já temos uma comunicação com o GeminiAI, agora podemos testar nossa aplicação usando o postman, para isso inicie a sua aplicação no Intellij e execute a requisição no postman conforme a imagem abaixo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwqt04bzibu90yse0tsq1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwqt04bzibu90yse0tsq1.png" alt="Image description" width="694" height="283"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;CONCLUSÃO&lt;/strong&gt; ✔&lt;br&gt;
O intuito deste artigo foi introduzir programadores Java a conexao do GeminiAI com uma aplicacao Java, criando infinitas novas possibilidades de uso. Espero que tenham gostado, até a próxima! 😊&lt;/p&gt;

</description>
      <category>java</category>
      <category>gemini</category>
      <category>ai</category>
      <category>google</category>
    </item>
    <item>
      <title>O básico de mirror do Istio</title>
      <dc:creator>Wander</dc:creator>
      <pubDate>Sun, 23 Jun 2024 12:57:03 +0000</pubDate>
      <link>https://forem.com/wandpsilva/o-basico-de-mirror-do-istio-4k5</link>
      <guid>https://forem.com/wandpsilva/o-basico-de-mirror-do-istio-4k5</guid>
      <description>&lt;p&gt;O Istio é a principal ferramenta de service mesh para o Kubernetes, ele disponibiliza diversas features para você gerenciar a sua malha de serviços, dentre essas features temos a parte de gerenciamento de tráfego onde uma das possibilidade é criar um 'mirror'. Mas o que é um mirror? um mirror permite você 'espelhar' o tráfego de requisições de um serviço para outro. E porque isso é útil? podemos encaixar essa funcionalidade em algumas situações, dentre elas vou destacar uma:&lt;/p&gt;

&lt;p&gt;Vamos supor que você tem uma aplicação que usa o banco de dados mysql e você precisa migra-la para postgresql, porém, antes de tornar a versão migrada produtiva você quer testar o comportamento dela para ver se os dados serão salvos corretamente e se a aplicação não apresentará erros. Para isso, você pode espelhar as requisições que chegam na aplicação cuja versão utiliza o mysql para a versão que utiliza o postgresql. O tráfego continuará sendo enviado para a versão com mysql e a versão com postgresql receberá uma cópia desse tráfego, o retorno da aplicação com postgresql não é enviado ao cliente, garantindo assim que o cliente receba apenas o retorno da aplicação com mysql que já funciona, evitanto assim receber possíveis erros da versão nova com postgresql.&lt;/p&gt;




&lt;h2&gt;
  
  
  Interessante, não? 🔥
&lt;/h2&gt;

&lt;p&gt;Vamos ver como funciona na prática? Para isso vamos precisar das seguintes ferramentas instaladas na nossa máquina:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.docker.com/products/docker-desktop/"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://storage.googleapis.com/minikube/releases/latest/minikube-installer.exe"&gt;Minikube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/istio/istio/releases"&gt;Istioctl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git-scm.com/downloads"&gt;Git bash&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Os comandos citados abaixo para criar os componentes começam com a instrução &lt;em&gt;istioctl kube-inject -f&lt;/em&gt;, esta instrução injeta no pod a ser criado o container de proxy do istio, para que o istio possa controlar este pod. Caso você não queira usar esta instrução confira &lt;a href="https://istio.io/latest/docs/setup/additional-setup/sidecar-injection/"&gt;aqui&lt;/a&gt; como injetar o proxy do istio de outras maneiras.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Mãos a obra 🤝🎓
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1&lt;/strong&gt; - Para começar, vamos subir nosso cluster minikube, primeiramente inicie o docker abrindo o docker desktop (para Windows), em seguida abra um terminal git bash e execute o seguinte comando para subir o minikube:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minikube start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2&lt;/strong&gt; - Instale o istio&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;istioctl install --set profile=demo -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3&lt;/strong&gt; - Copie o código abaixo e execute no git bash para criar o deployment principal&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat &amp;lt;&amp;lt;EOF | istioctl kube-inject -f - | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: istioapp-v1
  labels:
    app: istioapp
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: istioapp
      version: v1
  template:
    metadata:
      labels:
        app: istioapp
        version: v1
    spec:
      containers:
      - name: istioapp
        image: wandpsilva/istioapp:v1.0
        ports:
        - containerPort: 8080
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4&lt;/strong&gt; - Agora faça o mesmo para o código abaixo para a versão 2 que receberá o tráfego espelhado&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat &amp;lt;&amp;lt;EOF | istioctl kube-inject -f - | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: istioapp-v2
  labels:
    app: istioapp
    version: v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: istioapp
      version: v2
  template:
    metadata:
      labels:
        app: istioapp
        version: v2
    spec:
      containers:
      - name: istioapp
        image: wandpsilva/istioapp:v1.0
        ports:
        - containerPort: 8080
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5&lt;/strong&gt; - Vamos criar o service do kubernetes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl create -f - &amp;lt;&amp;lt;EOF
apiVersion: v1
kind: Service
metadata:
  name: istioapp-service
spec:
  selector:
    app: istioapp
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 8080
  type: NodePort
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6&lt;/strong&gt; - Criaremos agora nosso virtualservice e destinationrule, estes são componentes do istio utilizados para gerenciamento de tráfego e neste momento possuem uma configuração básica, apenas enviar a requisição recebida para o pod v1&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f - &amp;lt;&amp;lt;EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: istioapp-virtualservice
spec:
  hosts:
    - istioapp-service.default.svc.cluster.local
  http:
    - route:
        - destination:
            host: istioapp-service.default.svc.cluster.local
            subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: istioapp-destinationrule
spec:
  host: istioapp-service.default.svc.cluster.local
  subsets:
  - name: v1
    labels:
      app: istioapp
      version: v1
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;7&lt;/strong&gt; - Com todos os componentes criados, vamos criar um deployment do &lt;a href="https://httpbin.org/"&gt;httpbin&lt;/a&gt; para chamarmos a nossa aplicação e testa-la&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat &amp;lt;&amp;lt;EOF | istioctl kube-inject -f - | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sleep
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sleep
  template:
    metadata:
      labels:
        app: sleep
    spec:
      containers:
      - name: sleep
        image: curlimages/curl
        command: ["/bin/sleep","3650d"]
        imagePullPolicy: IfNotPresent
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;8&lt;/strong&gt; - Com o httpbin criado podemos chamar o endpoint da aplicação que subimos no minikube e verificarmos o response dela pelo log do pod. Vamos então chamar a aplicação com o seguinte comando&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export SLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
kubectl exec "${SLEEP_POD}" -c sleep -- curl -sS http://istioapp-service:8080/v1/istioapp/hello-word/ping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verifique as logs dos dois pods&lt;/p&gt;

&lt;p&gt;pod v1&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export V1_POD=$(kubectl get pod -l app=istioapp,version=v1 -o jsonpath={.items..metadata.name})
kubectl logs "$V1_POD" -c istioapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;pod v2&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export V2_POD=$(kubectl get pod -l app=istioapp,version=v2 -o jsonpath={.items..metadata.name})
kubectl logs "$V2_POD" -c istioapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;você deverá ver a mensagem 'PONG' na log do pod v1 e nada na log do pod v2.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9&lt;/strong&gt; - Vamos fazer agora o mirror funcionar, fazendo com que a chamada feita no passo 8 chegue tanto para o pod v1 quanto para o pod v2, para isso vamos configurar novamente nosso virtualservice e destinationrule, aplique as configurações abaixo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f - &amp;lt;&amp;lt;EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: istioapp-virtualservice
spec:
  hosts:
    - istioapp-service.default.svc.cluster.local
  http:
    - route:
        - destination:
            host: istioapp-service.default.svc.cluster.local
            subset: v1
          weight: 100
      mirror:
        host: istioapp-service.default.svc.cluster.local
        subset: v2
      mirrorPercentage:
        value: 100
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: istioapp-destinationrule
spec:
  host: istioapp-service.default.svc.cluster.local
  subsets:
  - name: v1
    labels:
      app: istioapp
      version: v1
  - name: v2
    labels:
      app: istioapp
      version: v2
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;10&lt;/strong&gt; - Chame novamente a aplicação&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export SLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
kubectl exec "${SLEEP_POD}" -c sleep -- curl -sS http://istioapp-service:8080/v1/istioapp/hello-word/ping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verifique a log dos pods novamente&lt;/p&gt;

&lt;p&gt;pod v1&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export V1_POD=$(kubectl get pod -l app=istioapp,version=v1 -o jsonpath={.items..metadata.name})
kubectl logs "$V1_POD" -c istioapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;pod v2&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export V2_POD=$(kubectl get pod -l app=istioapp,version=v2 -o jsonpath={.items..metadata.name})
kubectl logs "$V2_POD" -c istioapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  O que aconteceu? 🤔
&lt;/h2&gt;

&lt;p&gt;Como você pode notar, ambos os pods exibiram nas logs a mensagem &lt;em&gt;PONG&lt;/em&gt;, o que significa que ambos receberam a requisição feita, porém, o pod v2 recebe apenas uma cópia do tráfego, o seu retorno seja sucesso ou falha não retorna ao cliente, o que nos dá segurança de testarmos qualquer alteração e em qualquer ambiente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como aconteceu? 😃
&lt;/h2&gt;

&lt;p&gt;Toda a lógica do mirror fica entre os componentes &lt;em&gt;virtualservice&lt;/em&gt; e &lt;em&gt;destinationrule&lt;/em&gt;, analisando os arquivos acima note que o virtualservice através do atributo &lt;strong&gt;&lt;em&gt;mirror&lt;/em&gt;&lt;/strong&gt; consegue replicar o tráfego para um outro &lt;strong&gt;&lt;em&gt;subset (v2)&lt;/em&gt;&lt;/strong&gt;, este &lt;em&gt;&lt;strong&gt;subset&lt;/strong&gt;&lt;/em&gt; é configurado no destinationrule e lá dizemos através de labels para qual pod a requisição deverá ser enviada. Também é possível dizer o percentual de tráfego que deverá ser espelhado com o atributo &lt;strong&gt;&lt;em&gt;mirrorPercentage&lt;/em&gt;&lt;/strong&gt;, se este for omitido, 100% do tráfego será espelhado.&lt;/p&gt;




&lt;p&gt;Este artigo foi baseado na &lt;a href="https://istio.io/latest/docs/tasks/traffic-management/mirroring/"&gt;documentação oficial do istio&lt;/a&gt;. Recomendo navegar pela documentação e explorar mais e mais do istio 🚀&lt;/p&gt;

&lt;p&gt;Espero que tenham gostado, até a próxima. 😉&lt;/p&gt;

</description>
      <category>istio</category>
      <category>kubernetes</category>
      <category>devops</category>
      <category>sre</category>
    </item>
    <item>
      <title>Entendendo roles no kubernetes</title>
      <dc:creator>Wander</dc:creator>
      <pubDate>Sun, 10 Mar 2024 19:03:36 +0000</pubDate>
      <link>https://forem.com/wandpsilva/entendendo-roles-no-kubernetes-1l8d</link>
      <guid>https://forem.com/wandpsilva/entendendo-roles-no-kubernetes-1l8d</guid>
      <description>&lt;p&gt;Você sabe a diferença entre role, rolebinding, clusterrole e clusterrolebinding? todos esses objetos fazem parte do conceito de &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/"&gt;RBAC&lt;/a&gt; do kubernetes, vale a pena entende-los para cuidarmos da segurança de um cluster. No começo pode ser um pouco confuso pois temos vários conceitos e objetos novos, mas neste artigo vamos esclarecer o que é cada um.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;TEORIA&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt; &lt;br&gt;
&lt;strong&gt;ROLE&lt;/strong&gt;&lt;br&gt;
Um objeto do tipo role no kubernetes é a especificação de permissões para determinadas ações sobre determinados objetos, para um namespace específico.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ROLEBINDING&lt;/strong&gt;&lt;br&gt;
O objeto rolebinding é o responsável por vincular uma ou mais roles a uma serviceaccount em um determinado namespace, quem usar esta serviceaccount terá as permissões que a role informada permite.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CLUSTERROLE&lt;/strong&gt;&lt;br&gt;
Ja o objetivo clusterrole é semelhante a role, porém esse tipo de role abrange o cluster como um todo e não se limita a um namespace especifico.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CLUSTERROLEBINDING&lt;/strong&gt;&lt;br&gt;
Serve para fazer o vinculo entre o clusterrole e quem poderá utilizar as permissões descritas no mesmo, seja uma serviceaccount, grupo ou usuário.&lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;PRÁTICA COM ROLE E ROLEBINDING&lt;/strong&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Para a prática utilizei o &lt;a href="https://minikube.sigs.k8s.io/docs/"&gt;minikube&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt; &lt;br&gt;
&lt;strong&gt;Cenário:&lt;/strong&gt; vamos supor que temos um processo que irá deletar deployments nginx em um determinado namespace, nesse namespace não queremos nada de nginx. Esse nosso processo deve ficar dentro do seu próprio namespace (jobs) e o deployment do nginx, se existir, em outro namespace (test).&lt;/p&gt;

&lt;p&gt;Vamos criar os namespaces, para isso, execute os comandos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl create namespace jobs
kubectl create namespace test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora vamos criar nosso cronjob que ficara no namespace jobs e irá deletar deployments nginx do namespace test, esse cronjob ira executar de acordo com o schedule, para escolher um período ajuste o campo schedule, para mais info sobre cron expression &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#writing-a-cronjob-spec"&gt;clique aqui&lt;/a&gt;. Abaixo segue o manifesto do cronjob:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: batch/v1
kind: CronJob
metadata:
  name: audit
  namespace: jobs
spec:
  schedule: "* * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: audit
            image: bitnami/kubectl
            command:
            - "bin/bash"
            - "-c"
            - "kubectl delete deployment nginx -n test"
          restartPolicy: Never
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Utilize o comando kubectl apply -f [nome do arquivo manifesto] para criar os objetos.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Com nosso cronjob criado, vamos criar um deployment nginx no namespace test para ver se o cronjob irá deleta-lo mesmo, utilize o comando abaixo para criar o deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl create deployment nginx --image nginx -n test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos ver se nosso cronjob já conseguiu excluir o deployment que criamos? se executarmos um kubectl get pod -n test veremos que o pod do deployment nginx continua lá:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4085t1oq33d9e9x96svl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4085t1oq33d9e9x96svl.png" alt="Image description" width="467" height="61"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;consultando os pods do cronjob com um kubectl get pod -n jobs, os pods aparecem com erro:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhjcvze5nbishixorkxo3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhjcvze5nbishixorkxo3.png" alt="Image description" width="458" height="76"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ao executar o comando logs em um dos pods, recebemos a seguinte mensagem:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fejdf5ophgel3em61ylkn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fejdf5ophgel3em61ylkn.png" alt="Image description" width="800" height="47"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Isso acontece justamente pela falta de permissão, nosso cronjob tentou utilizar a &lt;a href="https://kubernetes.io/docs/concepts/security/service-accounts/"&gt;serviceaccount&lt;/a&gt; default e esta não tem permissão para deletar deployments no namespace test, vamos corrigir isso, para começar vamos criar uma &lt;a href="https://kubernetes.io/docs/concepts/security/service-accounts/"&gt;serviceaccount&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: ServiceAccount
metadata:
  name: jobs-sa 
  namespace: jobs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora vamos criar a nossa role:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: audit-job-role
  namespace: test
rules:
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "list", "create"]
  - apiGroups: ["extensions"]
    resources: ["deployments"]
    verbs: ["get", "list", "create", "delete"]
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get", "list", "create", "delete"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como falamos no começo do artigo, precisamos vincular esta role a serviceaccount e para isso usamos o objeto rolebinding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: audit-job-rolebinding
  namespace: test
subjects:
  - kind: ServiceAccount
    name: jobs-sa
    namespace: jobs
roleRef:
  kind: Role
  name: audit-job-role
  apiGroup: rbac.authorization.k8s.io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois de criarmos todos esses objetos, nosso cronjob precisa de uma atualização, precisamos informar a serviceaccount que ele deverá utilizar, para isso, atualize o manifesto conforme abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: batch/v1
kind: CronJob
metadata:
  name: audit
  namespace: jobs
spec:
  schedule: "* * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: jobs-sa
          containers:
          - name: audit
            image: bitnami/kubectl
            command:
            - "bin/bash"
            - "-c"
            - "kubectl delete deployment nginx -n test"
          restartPolicy: Never
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, estamos informando qual serviceaccount deverá ser usada, e com isso nosso cronjob executa com sucesso:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuywyo4tmpgbxpj3ppv23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuywyo4tmpgbxpj3ppv23.png" alt="Image description" width="461" height="51"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se buscarmos por deployments no nosso namespace test, não encontraremos mais o nginx:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhjj8zq1tr9xxm4rrk4r3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhjj8zq1tr9xxm4rrk4r3.png" alt="Image description" width="297" height="31"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; &lt;br&gt;
E com isso terminamos nossa prática com role e rolebinding, vale lembrar que quando criamos a &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-example"&gt;role&lt;/a&gt;, &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/#clusterrole-example"&gt;rolebinding&lt;/a&gt; e &lt;a href="https://kubernetes.io/docs/concepts/security/service-accounts/"&gt;serviceaccount&lt;/a&gt; nós informamos o namespace, ou seja, tudo limitado a escopo de namespace, para não termos essa limitação podemos utilizar os objetos &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/#clusterrole-example"&gt;clusterrole&lt;/a&gt; e &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/#clusterrolebinding-example"&gt;clusterrolebinding&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;CONCLUSÕES FINAIS&lt;/strong&gt;&lt;br&gt;
o RBAC é um poderoso mecanismo para controlarmos o acesso em um cluster kubernetes, é possível de forma detalhada refinar os acessos que cada usuário ou aplicação tem dentro do cluster. Os exemplos dados aqui foram apenas para demonstrar conceitos básicos de permissão em um cluster kubernetes, vale consultar a &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/"&gt;documentação oficial&lt;/a&gt; para se aprofundar no assunto.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Espero que tenham gostado, até a próxima!!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>eks</category>
      <category>sysops</category>
    </item>
    <item>
      <title>Validação dinâmica K8s</title>
      <dc:creator>Wander</dc:creator>
      <pubDate>Tue, 12 Sep 2023 18:24:09 +0000</pubDate>
      <link>https://forem.com/wandpsilva/validacao-dinamica-k8s-208l</link>
      <guid>https://forem.com/wandpsilva/validacao-dinamica-k8s-208l</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr12dgj8mbbz4s6dbfwl9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr12dgj8mbbz4s6dbfwl9.png" alt="Símbolo do kubernetes representado por um timão azul" width="256" height="256"&gt;&lt;/a&gt;&lt;br&gt;
 &lt;/p&gt;

&lt;p&gt;Neste artigo vou abordar um componente do kubernetes que precisei entender sua função para avaliar sua real necessidade para uma determinada situação, o objeto em questão é o &lt;em&gt;ValidatingWebhookConfiguration&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;O ValidatingWebhookConfiguration é um dos componentes utilizados para acionar validações aos objetos que estão sendo criados, deletados ou atualizados em um cluster Kubernetes. Isso é possível pois este componente realiza chamadas a um serviço que validará por exemplo, se um pod atende ou não a determinadas regras para poder ingressar ou não no cluster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;QUANDO USAR?&lt;/strong&gt;&lt;br&gt;
Vamos supor que você não quer que sejam criados pods sem a label "ambiente: teste" no seu cluster. Para conseguir validar se este pod atende ou não a sua necessidade e permitir que ele seja criado, você criará um serviço de validação que será acionado por um ValidatingWebhookConfiguration.&lt;/p&gt;

&lt;p&gt;Para entender melhor, vamos analisar o manifesto abaixo que especifica a criação de um ValidatingWebhookConfiguration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: pod-validator
webhooks:
  - name: pod.validator.teste.io
    clientConfig:
      service:
        name: pod-validator
        namespace: default
        path: "/validate"
    rules:
      - apiGroups:
          - ""
        apiVersions:
          - "v1"
        operations:
          - CREATE
          - UPDATE
        resources:
          - pods
    failurePolicy: Fail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;name&lt;/strong&gt; é o nome que damos ao webhook.&lt;br&gt;
&lt;strong&gt;clientConfig&lt;/strong&gt; especifica o serviço que fornecerá a validação. Nesse caso o nome do service é pod-validator e está no namespace default, suponhamos que este aponte para um pod que executa um script python, esse script irá conter a lógica de validação, como por exemplo, verificar se o POD que está sendo criado  possui a label "ambiente: teste".&lt;br&gt;
&lt;strong&gt;rules&lt;/strong&gt; aqui você descreve a 'quem' essa política se aplica, no caso do exemplo, essa validação será acionada sempre que houver um evento do tipo &lt;em&gt;CREATE&lt;/em&gt; e &lt;em&gt;UPDATE&lt;/em&gt; para recursos do tipo &lt;em&gt;POD&lt;/em&gt; cujo &lt;em&gt;apiVersion&lt;/em&gt; seja &lt;em&gt;v1&lt;/em&gt;.&lt;br&gt;
&lt;strong&gt;failurePolicy&lt;/strong&gt; o valor Fail faz com que a criação do pod falhe caso a validação feita pelo nosso script python não retorne com sucesso.&lt;br&gt;
 &lt;/p&gt;

&lt;p&gt;O desenho abaixo explica de forma bem macro o fluxo quando o ValidatingWebhookConfiguration está presente:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5n1kcgmf57a26nr32pwh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5n1kcgmf57a26nr32pwh.png" alt="Fluxo de criação de um pod com o componente ValidatingWebhookConfiguration" width="661" height="321"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;PONTOS IMPORTANTES:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Você pode validar qualquer tipo de componente do kubernetes, não só PODs, se você especificar "*" no campo &lt;em&gt;resources&lt;/em&gt; por exemplo, o serviço será chamado para qualquer tipo de recurso que estiver sendo criado ou atualizado no cluster.&lt;/li&gt;
&lt;li&gt;Você pode restringir a validação aos recursos que estejam sendo criados em apigroups específicos, para isso, basta especificar na lista de apiGroups do manifesto os grupos no qual deseja realizar a validação, por exemplo o grupo gateway.networking.k8s.io.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;RESUMO&lt;/strong&gt;&lt;br&gt;
O ValidatingWebhookConfiguration é um componente importante para que possamos controlar as operações de CREATE, UPDATE, DELETE e CONNECT de recursos em um cluster, chamando serviços que validam determinadas configurações que precisam ou não estar presentes nos recursos para que sejam 'aceitos'. É possível fazer ajustes precisos para se alcançar qualquer tipo de política de validação.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;REFERÊNCIAS:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#validatingwebhookconfiguration-v1-admissionregistration-k8s-io"&gt;https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#validatingwebhookconfiguration-v1-admissionregistration-k8s-io&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/"&gt;https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Valeu e até a próxima! :)&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>braziliandevs</category>
      <category>devops</category>
      <category>eks</category>
    </item>
    <item>
      <title>Obtendo mais do Kubectl</title>
      <dc:creator>Wander</dc:creator>
      <pubDate>Sat, 24 Jun 2023 18:36:46 +0000</pubDate>
      <link>https://forem.com/wandpsilva/obtendo-mais-do-kubectl-48m2</link>
      <guid>https://forem.com/wandpsilva/obtendo-mais-do-kubectl-48m2</guid>
      <description>&lt;p&gt;Que tal se aprofundar um pouco mais no kubectl e tirar mais benefícios dessa ferramenta? vamos conhecer alguns comandos que podem te ajudar a ganhar tempo, trazer conhecimento sobre seu cluster e recursos, depurar e análisar pods e etc.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;ADMINISTRANDO&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;o kub te explica:&lt;/strong&gt; o comando explain fornece informações sobre os recursos do kub. Caso você esteja com dúvida na composição de um recurso como um deployment, role e etc, você pode usa-lo para ter um norte, veja o exemplo abaixo:&lt;br&gt;
&lt;code&gt;kubectl explain roles&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F69furco2fez4docs3ora.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F69furco2fez4docs3ora.png" alt="Image description" width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; &lt;br&gt;
&lt;strong&gt;será que pode?&lt;/strong&gt; Este comando pode ser útil para administradores do cluster, pois permite verificar se um usuário ou grupo tem permissão para executar uma determinada ação.&lt;br&gt;
&lt;code&gt;kubectl auth can-i delete deploy&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyusz9j9yuji5s7sx4t4f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyusz9j9yuji5s7sx4t4f.png" alt="Image description" width="374" height="38"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;você pode ser ainda mais específico e perguntar se uma determinada service account tem permissão:&lt;/em&gt;&lt;br&gt;
&lt;code&gt;kubectl auth can-i list pods -n default  --as system:serviceaccount:default:default&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fizyo9p3qx8g7t9qo0k1x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fizyo9p3qx8g7t9qo0k1x.png" alt="Image description" width="775" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; &lt;br&gt;
&lt;strong&gt;quero uma lista do que tem:&lt;/strong&gt; este comando pode ajudar a descobrir os tipos de recursos que podem ser criados no cluster.&lt;br&gt;
&lt;code&gt;kubectl api-resources&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbfzw9wzyhh7p6eizlxde.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbfzw9wzyhh7p6eizlxde.png" alt="Image description" width="800" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; &lt;br&gt;
&lt;strong&gt;hmm contextos:&lt;/strong&gt; quando se trabalha com vários clusters é interessante você usar o comando get-contexts para obter dados de todos os clusters configurados e saber em qual cluster você está 'logado'.&lt;br&gt;
&lt;code&gt;kubectl config get-contexts&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmbrqtymelm5wlan7bt1d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmbrqtymelm5wlan7bt1d.png" alt="Image description" width="420" height="41"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;para alternar para outro contexto use o comando:&lt;/em&gt;&lt;br&gt;
&lt;code&gt;kubectl config use-context [nome do contexto]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt; &lt;br&gt;
&lt;strong&gt;me fale sobre você kub:&lt;/strong&gt; para obter alguns dados sobre o seu cluster, você pode usar o comando abaixo:&lt;br&gt;
&lt;code&gt;kubectl cluster-info&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ydue364v3hctshuyz0n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ydue364v3hctshuyz0n.png" alt="Image description" width="800" height="69"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; &lt;br&gt;
&lt;strong&gt;quero um arquivinho:&lt;/strong&gt; em determinados momentos pode ser necessário obter o manifesto de um recurso já criado no cluster, seja por não ter mais o manifesto em algum lugar ou por simplesmente querer estuda-lo. É possível fazer isso exportando-o com a flag -o e especificando seu formato, no exemplo abaixo estou extraindo o manifesto do meu deployment que está no cluster para a minha máquina no formato yaml com o nome novo_deploy.yaml:&lt;br&gt;
&lt;code&gt;kubectl get deploy nginx-deployment -o yaml &amp;gt; novo_deploy.yaml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt; &lt;br&gt;
&lt;strong&gt;quero recursos por labels:&lt;/strong&gt; as labels são muito úteis no kub e podemos usa-las para filtrar os recursos que queremos ver, um exemplo disso é obter uma lista de pods por labels:&lt;br&gt;
&lt;code&gt;kubectl get pods -l app=nginx&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3a1w74gcmfesmyqkgb94.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3a1w74gcmfesmyqkgb94.png" alt="Image description" width="549" height="59"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;strong&gt;DEPURANDO&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;me dê logs rapaz:&lt;/strong&gt; para visualizar as logs de um pod usamos o comando logs + [nome do pod] + [namespace], confira abaixo:&lt;br&gt;
&lt;code&gt;kubectl logs nginx-deployment-8cf88777f-l8s2g -n default&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzw1t5oj6s1linh0pq3n1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzw1t5oj6s1linh0pq3n1.png" alt="Image description" width="773" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;caso queira ver diretamente as logs do container, basta adicionar a flag -c seguido do nome do container.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;para consultar e acompanhar as logs do pod basta adicionar a flag -f (--follow):&lt;br&gt;
&lt;code&gt;kubectl logs -f nginx-deployment-8cf88777f-l8s2g -n default&lt;/code&gt;&lt;/p&gt;

&lt;p&gt; &lt;br&gt;
&lt;strong&gt;o que está acontecendo?&lt;/strong&gt; o comando get events vai te dar uma visão por namespace dos eventos que estão ocorrendo no cluster.&lt;br&gt;
&lt;code&gt;kubectl get events -n kube-system&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6x1f2tlrhf7ewes5t5ho.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6x1f2tlrhf7ewes5t5ho.png" alt="Image description" width="800" height="89"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;você pode filtrar os eventos para visualizar por exemplo apenas informações de um determinado recurso.&lt;br&gt;
&lt;code&gt;kubectl get events -n default --field-selector involvedObject.name=nginx-deployment-8cf88777f-l8s2g&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcl7f5trtkb0j9ftgjglf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcl7f5trtkb0j9ftgjglf.png" alt="Image description" width="800" height="71"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; &lt;br&gt;
&lt;strong&gt;descreve ai pra mim:&lt;/strong&gt; para analisar as configurações de um recurso criado no cluster você pode usar o comando describe, além disso, no final dos dados retornados por este comando é possível verificar o status/eventos relacionados ao recurso.&lt;br&gt;
&lt;code&gt;kubectl describe pod nginx-deployment-8cf88777f-l8s2g -n default&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F47xkmsl7o0znut1rpddg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F47xkmsl7o0znut1rpddg.png" alt="Image description" width="800" height="116"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; &lt;br&gt;
&lt;strong&gt;'entra no pod':&lt;/strong&gt; o comando exec --it permite executar comandos dentro de um pod ou container. Para executa-lo use kubectl exec --it [nome do pod] + [comando], veja:&lt;br&gt;
&lt;code&gt;kubectl exec -i -t nginx-deployment-8cf88777f-l8s2g -- /bin/bash&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp2fmowh5bqaa82aoonxc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp2fmowh5bqaa82aoonxc.png" alt="Image description" width="800" height="54"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;para acessar o container ao invés do pod basta incluir a flag -c e o nome do container na frente:&lt;br&gt;
&lt;code&gt;kubectl exec -i -t nginx-deployment-8cf88777f-l8s2g -c nginx-container -- /bin/bash&lt;/code&gt;&lt;br&gt;
&lt;em&gt;use 'exit' para sair do pod&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt; &lt;br&gt;
&lt;strong&gt;mais e mais infos:&lt;/strong&gt; a flag -o wide expande as informações da listagem de um determinado recurso, pode ser usado com pods, nodes, deployments, services e etc, e pode ser util para rapidamente detectar alguma anomalia como por exemplo ips incorretos.&lt;br&gt;
&lt;code&gt;kubectl get pods -o wide&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdto0rsumfltkmx1buz1k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdto0rsumfltkmx1buz1k.png" alt="Image description" width="800" height="41"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;BÔNUS&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;reiniciando deployments:&lt;/strong&gt; &lt;em&gt;kubectl rollout restart deployment [nome do deployment] -n [namespace]&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;desfazendo um deployment:&lt;/strong&gt; &lt;em&gt;kubectl rollout undo deployment [nome do deployment]&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;aumentando o número de replicas de um pod:&lt;/strong&gt; &lt;em&gt;kubectl scale deployment [nome do deployment] --replicas=3 -n [namespace]&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;CONCLUSÃO&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Neste artigo abordei de forma simples alguns comandos pouco conhecidos da ferramenta kubectl que podem ajudar na administração de um cluster kubernetes. Utilizei o minikube para montar um cluster local e fiz o deploy de um servidor nginx para demonstrar os comandos. Abaixo os links onde você pode obter os recursos utilizados e documentações para conhecer mais comandos e mais variações:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://minikube.sigs.k8s.io/docs/start/" rel="noopener noreferrer"&gt;Minikube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hub.docker.com/_/nginx" rel="noopener noreferrer"&gt;Imagem Nginx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/tasks/tools/" rel="noopener noreferrer"&gt;Kubectl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/reference/kubectl/cheatsheet/" rel="noopener noreferrer"&gt;Kubectl cheat sheet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt; &lt;br&gt;
Espero que o artigo tenha sido útil para você! 😛&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>kubectl</category>
      <category>k8s</category>
      <category>cluster</category>
    </item>
    <item>
      <title>Atualizando website estático no Amazon S3 via github actions com uma action personalizada</title>
      <dc:creator>Wander</dc:creator>
      <pubDate>Mon, 01 May 2023 19:07:35 +0000</pubDate>
      <link>https://forem.com/wandpsilva/enviando-arquivos-para-o-amazon-s3-via-github-actions-com-uma-action-personalizada-2h78</link>
      <guid>https://forem.com/wandpsilva/enviando-arquivos-para-o-amazon-s3-via-github-actions-com-uma-action-personalizada-2h78</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2gtz9ms0fcx7yzy6ed94.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2gtz9ms0fcx7yzy6ed94.jpg" alt="Logotipo github com a palavra Actions" width="720" height="540"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Tenho como objetivo aqui trazer um pouco do poder do github actions, mas como único escopo. Não serão abordados temas como criação de um website, criação de conta AWS, configuração de um bucket S3 na AWS e criação de credenciais AWS.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bora lá? :)&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  ACTION
&lt;/h2&gt;

&lt;p&gt;No repositório github do seu site, crie na raiz do projeto a pasta &lt;em&gt;.github&lt;/em&gt;, e dentro desta pasta uma nova pasta chamada &lt;em&gt;workflows&lt;/em&gt;:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2zaipra15le77bxzd9vh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2zaipra15le77bxzd9vh.png" alt="Print do github exibindo o caminho: meu-site/.github/workflow" width="381" height="57"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora crie dentro da pasta &lt;em&gt;.github&lt;/em&gt; outra pasta com nome &lt;em&gt;actions&lt;/em&gt;, dentro da pasta &lt;em&gt;actions&lt;/em&gt; crie um arquivo com o nome &lt;em&gt;action.yaml&lt;/em&gt; (&lt;u&gt;o arquivo precisa se chamar action e ter o formato yaml&lt;/u&gt;), este arquivo será a action que será acionada por um workflow para fazer o upload dos arquivos do site. Este arquivo deverá ficar da seguinte forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: 'Upload S3'
description: 'esta action envia arquivos para o amazon S3'
inputs:
  bucket:
    description: 'Nome do bucket S3'
    required: true
  region:
    description: 'A região do bucket'
    required: false
    default: 'sa-east-1'
  files:
    description: 'Caminho dos arquivos para upload'
    required: true
runs:
  using: 'node16'
  main: 'main.js'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta action recebe 3 parâmetros de entrada (&lt;em&gt;inputs&lt;/em&gt;), o nome do bucket, a region do bucket e o caminho dos arquivos para upload. Logo abaixo dos inputs temos o campo runs que chamará um script &lt;em&gt;'main.js'&lt;/em&gt; executado com node versão 16.&lt;/p&gt;

&lt;p&gt;Agora vamos criar o script &lt;em&gt;main.js&lt;/em&gt; que informamos acima na action, este arquivo deverá ficar dentro da pasta &lt;em&gt;actions&lt;/em&gt; e conterá o seguinte código javascript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const core = require('@actions/core');
const exec = require('@actions/exec');

function: run() {
  const bucket = core.getInput('bucket', { required=true });
  const region = core.getInput('region', { required=true });
  const files = core.getInput('files', { required=true });

  const uri = `s3://${bucket}`
  exec.exec(`aws s3 sync ${files} ${uri} --region ${region}`)

  core.notice('Arquivos enviados com sucesso!')
}

run();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse script importamos algumas libs para manipular comandos shell e também obter os inputs informados na action. A função &lt;em&gt;run()&lt;/em&gt; lê os inputs da action e em seguida monta a uri do nosso bucket, então é executado o comando para sincronizar os arquivos contidos no caminho informado pelo input &lt;em&gt;'files'&lt;/em&gt; com o bucket informado no input &lt;em&gt;'uri'&lt;/em&gt;.  &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  WORKFLOW
&lt;/h2&gt;

&lt;p&gt;Nossa action está pronta e nosso script de upload também, agora vamos montar o workflow que chamará essa action e enviará os inputs necessários para o upload dos arquivos.&lt;/p&gt;

&lt;p&gt;Para isso, crie dentro da pasta &lt;em&gt;workflow&lt;/em&gt; um arquivo com o nome de sua preferência no formato &lt;em&gt;.yaml&lt;/em&gt;, aqui vou chama-lo de &lt;em&gt;upload.yaml&lt;/em&gt; e ele terá o seguinte conteúdo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Upload

on:
  push:
    branches:
      - main

jobs:
  upload:
    runs-on: ubuntu-latest
    steps:
      - name: Get code
        uses: actions/checkout@v3
      - name: Upload files
        uses: ./.github/actions
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        with:
          bucket: 'my-bucket'
          region: 'sa-east-1'
          files: ./files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse workflow sera acionado toda vez que houver um push na branch main, definimos isso com o campo &lt;em&gt;'on'&lt;/em&gt;, para conhecer mais formas de acionar o workflow clique &lt;a href="https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows"&gt;aqui&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Na sequência definimos o job &lt;em&gt;'upload'&lt;/em&gt; e informamos que ele utilizará o SO &lt;em&gt;'ubuntu'&lt;/em&gt; na sua ultima versão, essa imagem de SO já trás pra nós algumas ferramentas importantes como a CLI da AWS que usamos para fazer o upload dos arquivos dentro do nosso script &lt;em&gt;main.js&lt;/em&gt;. Clique &lt;a href="https://github.com/actions/runner-images/blob/main/images/linux/Ubuntu2204-Readme.md"&gt;aqui&lt;/a&gt; e confira todas as ferramentas que já vem no ubuntu-latest.&lt;/p&gt;

&lt;p&gt;Definimos então os steps do job, o primeiro step &lt;em&gt;'Get code'&lt;/em&gt; fará o download do nosso repositório, isso é necessário pois este diretório contém a action e os scripts que queremos executar, além de conter os arquivos que queremos enviar para o bucket S3. &lt;/p&gt;

&lt;p&gt;No step seguinte &lt;em&gt;'Upload files'&lt;/em&gt; chamamos a nossa action, note que no campo &lt;em&gt;uses&lt;/em&gt; estou informando o caminho onde está a nossa action criada, o arquivo &lt;em&gt;action.yaml&lt;/em&gt; será detectado automaticamente pelo github. Passamos também os 3 inputs necessários para a action executar, o nome do bucket, a region e o caminho dos arquivos que devem ser enviados ao bucket &lt;em&gt;(no meu repositório, criei uma pasta chamada files e dentro dela residem os arquivos .html, por isso no input files declarei ./files)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Passamos também as credenciais da AWS no campo &lt;em&gt;'env'&lt;/em&gt; para que o nosso script &lt;em&gt;'main.js'&lt;/em&gt; consiga através dessas credenciais enviar os arquivos ao bucket sem nenhum problema de acesso.  &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  CREDENCIAIS AWS
&lt;/h2&gt;

&lt;p&gt;As credenciais devem ser obtidas no console AWS e armazenadas no github na forma de secrets conforme abaixo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3zpj4539lgg9e2s25xl2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3zpj4539lgg9e2s25xl2.png" alt="Tela do github onde se configuram variáveis e segredo para serem usados no projeto" width="792" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Para criar os secrets conforme imagem acima, basta ir na aba 'Settings' do github e então no menu lateral esquerdo procurar por 'secrets and variables' e escolher a opção 'actions'.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;PRONTO&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Agora nossa action customizada está pronta e sempre que houver um push na branch main, nossos arquivos são enviados para o bucket S3 na AWS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Considerações:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;O seu bucket S3 deverá estar configurado como um website estático, clique &lt;a href="https://docs.aws.amazon.com/pt_br/AmazonS3/latest/userguide/HostingWebsiteOnS3Setup.html"&gt;aqui&lt;/a&gt; para entender como fazer isso.&lt;/li&gt;
&lt;li&gt;A action que criamos aqui reside dentro do repositório do próprio website, porém esta action pode ser criada separadamente em um repositório onde apenas ela reside, nesse caso os arquivos da action devem ficar todos na raiz do repositório e não na pasta .github.&lt;/li&gt;
&lt;li&gt;Este exemplo envia arquivos para um bucket S3, mas abre possibilidades para vários cenários na AWS, como acessar uma EC2, criar um secret no AWS Secrets Manager dentre outros.&lt;/li&gt;
&lt;li&gt;Este tipo de action customizada só funciona com código javascript que é aceito pelo github, mas caso queira usar outra linguagem como python, java e etc, você deverá usar actions com containers docker.&lt;/li&gt;
&lt;li&gt;Você pode usar uma action fornecida pela própria AWS para configurar sua credenciais ou outras formas de acesso, veja como clicando &lt;a href="https://github.com/marketplace/actions/configure-aws-credentials-for-github-actions"&gt;aqui&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;CONCLUSÃO&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;O Github Actions é uma ferramenta poderosíssima e que todo dev precisa conhecer, através dela conseguimos dentro do nosso próprio repositório de código realizar várias tarefas como testes, deploys, validações, checagens personalizadas e etc, vale muito a pena se aprofundar no tema e conhecer cada vez mais, espero que este artigo tenha agregado algum conhecimento a você, confira a documentação oficial das actions clicando &lt;a href="https://docs.github.com/pt/actions"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Abraços! :)&lt;/p&gt;

</description>
      <category>aws</category>
      <category>githubactions</category>
      <category>github</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Sending AWS SQS messages with JAVA</title>
      <dc:creator>Wander</dc:creator>
      <pubDate>Sat, 24 Dec 2022 21:41:39 +0000</pubDate>
      <link>https://forem.com/wandpsilva/sending-aws-sqs-messages-with-java-2g8n</link>
      <guid>https://forem.com/wandpsilva/sending-aws-sqs-messages-with-java-2g8n</guid>
      <description>&lt;p&gt;Hello, I’d like to share with you a quick tutorial about how to send messages to a SQS queue in AWS in a simple way using a REST API with JAVA, in this tutorial I won’t get into about themes such as security and architecture, just the comprehension about the basics of access and SQS handle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I’m using:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JAVA 11 with Spring 2.3.3&lt;/li&gt;
&lt;li&gt;IntelliJ&lt;/li&gt;
&lt;li&gt;Maven 4.0.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s necessary to have a little bit of knowledge about AWS accounts and SQS queues to go with this tutorial, just a bit, really!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;you’ll need to include the following dependencies on your POM file:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;&lt;br&gt;
   &amp;lt;groupId&amp;gt;com.amazonaws&amp;lt;/groupId&amp;gt;&lt;br&gt;
   &amp;lt;artifactId&amp;gt;aws-java-sdk&amp;lt;/artifactId&amp;gt;&lt;br&gt;
   &amp;lt;version&amp;gt;LATEST&amp;lt;/version&amp;gt;&lt;br&gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now we have to put some access information in our properties file to authentication in AWS and to tell which SQS queue we want to use (aws.queue). The access and secret key are informed in AWS console when you created it:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;aws.access_key_id=&lt;br&gt;
aws.secret_access_key=&lt;br&gt;
aws.queue=&lt;br&gt;
aws.region=sa-east-1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ATTENTION:&lt;/strong&gt; aws.region=sa-east-1 indicates the region where I am, check the correct region for you in &lt;a href="https://docs.aws.amazon.com/pt_br/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#concepts-available-regions" rel="noopener noreferrer"&gt;AWS website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With a configuration class we make the reference to the information that we put in our properties file above, and then we get authenticated in AWS using a Bean sqsClient:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Configuration
public class AWSConfig {

    @Value("${aws.access_key_id}")
    private String awsId;

    @Value("${aws.secret_access_key}")
    private String awsKey;

    @Value("${aws.region}")
    private String region;

    @Bean
    public AmazonSQS sqsClient(){
        BasicAWSCredentials basicAWSCredentials = new BasicAWSCredentials(awsId, awsKey);
        return AmazonSQSClientBuilder.standard().withRegion(Regions.fromName(region)).withCredentials(new AWSStaticCredentialsProvider(basicAWSCredentials)).build();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once our configuration is done we create then a service to send messages to the queue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Service
public class SQSService {

    @Autowired
    private AmazonSQS sqsClient;

    @Value("${sqs.queue}")
    private String queueUrl;

    public void sendMessage(String msg) {
        SendMessageRequest send_msg_request = new SendMessageRequest()
                .withQueueUrl(queueUrl)
                .withMessageBody(msg)
                .withDelaySeconds(5);
        sqsClient.sendMessage(send_msg_request);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I am indicating the queue which I want to access in my properties file and using an amazon interface (AmazonSQS), so I can invoke the method sendMessage which receives as an argument a SendMessageRequest object. The method withDelaySeconds tells in seconds the delay to deliver the message to the queue.&lt;/p&gt;

&lt;p&gt;To access our method I’ve created an specific service to AWS tests, this one will be called by our Controller class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Service
public class AWSTestService {

    @Autowired
    private SQSService sqsService;

    public void sendMessage(SQSMessage sqsMessage) {
        String msg = sqsMessage.getMsg();
        sqsService.sendMessage(msg);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this service I’m injecting the service we’ve created to send the message&lt;/p&gt;

&lt;p&gt;To receive the message as a RequestBody I’ve created a basic domain class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class SQSMessage {
    private String msg;

    public SQSMessage(){}

    public SQSMessage(String msg) {
        this.msg = msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public String getMsg() {
        return msg;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, using the domain class the Controller can call the methods we’ve created and send the message that we are receiving in our request body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@RestController
@RequestMapping("/awstest")
public class AWSTestController {

    @Autowired
    private AWSTestService service;

    @PostMapping(value="/message")
    public ResponseEntity&amp;lt;Void&amp;gt; sendMessage(@RequestBody SQSMessage sqsMessage){
        service.sendMessage(sqsMessage);
        return ResponseEntity.ok().build();
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can test it using postman and checking the amazon console in SQS section the messages you are producing coming.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This was my first write here. I hope you like it. :-)&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
