Nesse artigo vamos implementar na prática o conceito de Sidecar Containers usando Kubernetes
Kubernetes (ou k8s) é um sistema que ajuda a gerenciar aplicações em contêineres de forma automatizada. Ele lida com a implantação, escalabilidade e execução dos contêineres, sem que você precise se preocupar com servidores manualmente.
Se você já usou Docker, sabe que ele roda um contêiner isolado. Mas e quando precisamos gerenciar vários contêineres que precisam trabalhar juntos? Kubernetes entra exatamente aqui!
No Kubernetes, um Pod é a menor unidade que pode ser implantada. Ele pode conter um ou mais contêineres que:
- Compartilham a mesma rede (se comunicam via
localhost); - Podem compartilhar volumes para trocar arquivos;
- Têm o mesmo ciclo de vida (são iniciados e finalizados juntos).
Pensa no Pod como um mini-servidor que agrupa processos que precisam rodar juntos.
Um Sidecar é um contêiner auxiliar que roda dentro do mesmo Pod que a aplicação principal, ajudando com alguma funcionalidade extra. Em nosso caso, ele fará a conversão de strings para Base64.
📌 exemplo:
- Criamos um Pod com dois contêineres:
- Um API (base64-http) que recebe strings e precisa convertê-las para Base64.
- Um Sidecar que faz essa conversão.
- O Sidecar compila seu próprio binário e o disponibiliza para a API dentro de um volume compartilhado.
- A API principal chama o Sidecar como um executável local, sem precisar conhecê-lo diretamente.
O nosso exemplo usa um Sidecar como um binário executável, mas esse não é o único jeito de usá-los! Aqui estão outras aplicações comuns:
- Proxy reverso → Gerencia tráfego entre microserviços.
- Coleta de logs → Envia logs da aplicação para um sistema central.
- Armazenamento de secrets → Gerencia credenciais sem expô-las diretamente à aplicação.
Cada caso de uso pode exigir uma abordagem diferente!
O arquivo pod.yaml define como o Kubernetes deve criar e gerenciar nosso Pod.
apiVersion: v1
kind: Pod
metadata:
name: base64-pod
spec:
volumes:
- name: shared-bin
emptyDir: {}
containers:
- name: base64-http
image: base64-http:latest
imagePullPolicy: Never
ports:
- containerPort: 8080
volumeMounts:
- mountPath: /shared-bin
name: shared-bin
- name: sidecar
image: sidecar:latest
imagePullPolicy: Never
volumeMounts:
- mountPath: /shared-bin
name: shared-bin
command: ["/bin/sh", "-c", "cp /sidecar /shared-bin/sidecar && chmod +x /shared-bin/sidecar && tail -f /dev/null"]-
Volumes e VolumeMounts:
- Criamos um volume chamado
shared-bincomemptyDir: {}. Isso significa que esse volume será um diretório compartilhado entre os contêineres do Pod e existirá somente enquanto o Pod estiver rodando. - O volume é montado em ambos os contêineres (
base64-httpesidecar) no caminho/shared-bin, permitindo que o binário gerado pelo Sidecar fique acessível para a aplicação principal.
- Criamos um volume chamado
-
imagePullPolicy: Never→ Esse campo instrui o Kubernetes a não tentar puxar a imagem do registro (como Docker Hub), pois estamos usando imagens locais no Minikube. Se esse campo não estivesse definido, o Kubernetes tentaria baixar a imagem, o que poderia causar falhas se a imagem não estivesse publicada em um repositório. -
O
sidecarcopia seu binário para o volume compartilhado → O comando:command: ["/bin/sh", "-c", "cp /sidecar /shared-bin/sidecar && chmod +x /shared-bin/sidecar && tail -f /dev/null"]
faz três coisas:
- Copia o binário
/sidecarpara o volume compartilhado (/shared-bin/sidecar). - Dá permissão de execução (
chmod +x) para que a aplicação principal possa rodá-lo. - Mantém o contêiner vivo com
tail -f /dev/null, evitando que ele seja finalizado e entre em estado de CrashLoopBackOff.
- Copia o binário
Essa API recebe um JSON com um texto e chama o Sidecar via exec.Command.
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os/exec"
"strings"
)
type Request struct {
Data string `json:"data"`
}
type Response struct {
Encoded string `json:"encoded"`
}
func encodeHandler(w http.ResponseWriter, r *http.Request) {
var req Request
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
http.Error(w, "Invalid request", http.StatusBadRequest)
return
}
cmd := exec.Command("/shared-bin/sidecar", req.Data)
output, err := cmd.Output()
if err != nil {
http.Error(w, "Error executing sidecar", http.StatusInternalServerError)
return
}
res := Response{Encoded: strings.TrimSpace(string(output))}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(res)
}
func main() {
http.HandleFunc("/encode", encodeHandler)
fmt.Println("Server running on port 8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}O Sidecar é um simples programa CLI que recebe uma string e retorna sua versão codificada em Base64.
package main
import (
"encoding/base64"
"fmt"
"os"
)
func main() {
if len(os.Args) < 2 {
fmt.Println("Usage: ./sidecar <string>")
os.Exit(1)
}
input := os.Args[1]
encoded := base64.StdEncoding.EncodeToString([]byte(input))
fmt.Println(encoded)
}FROM golang:1.23 AS builder
WORKDIR /app
COPY main.go .
RUN CGO_ENABLED=0 GOOS=linux go build -o app main.go
FROM alpine
WORKDIR /
COPY --from=builder /app/app /app
RUN chmod +x /app
CMD ["/app"]FROM golang:1.23 AS builder
WORKDIR /app
COPY main.go .
RUN CGO_ENABLED=0 GOOS=linux go build -o sidecar main.go
FROM alpine
WORKDIR /
COPY --from=builder /app/sidecar /sidecar
RUN chmod +x /sidecar
CMD ["/sidecar"]O Minikube é uma ferramenta que permite rodar um cluster Kubernetes localmente. Ele simula um ambiente real, perfeito para testes antes de enviar para produção.
APP_IMAGE=base64-http:latest
SIDECAR_IMAGE=sidecar:latest
up:
minikube start
minikube image load $(SIDECAR_IMAGE)
minikube image load $(APP_IMAGE)
kubectl apply -f pod.yaml
build:
docker build -t $(APP_IMAGE) .
docker build -t $(SIDECAR_IMAGE) ./sidecar/.
restart:
kubectl delete pod base64-pod --ignore-not-found
kubectl apply -f pod.yaml
logs:
kubectl logs base64-pod -c base64-http
kubectl logs base64-pod -c sidecar
status:
kubectl get pods
port-forward:
kubectl port-forward base64-pod 8080:8080
clean:
kubectl delete pod base64-pod --ignore-not-found
minikube delete
docker rmi $(APP_IMAGE) $(SIDECAR_IMAGE) --force
make build # Constrói as imagens docker
make up # Inicia o Minikube, carrega as imagens docker no minikube e aplica o Pod
make port-forward # Conecta uma porta do pod com uma porta da máquina localAgora podemos testar com:
curl -X POST "http://localhost:8080/encode" \
-H "Content-Type: application/json" \
-d '{"data": "hello-world"}'Saída esperada:
{"encoded":"aGVsbG8td29ybGQ="}Neste artigo, vimos na prática como usar o padrão Sidecar Container no Kubernetes para complementar a funcionalidade de uma aplicação principal. Usando dois containers Go rodando no mesmo Pod e compartilhando um volume, mostramos como é possível dividir responsabilidades de forma simples e eficaz.
O padrão Sidecar é uma solução interessante para encapsular funcionalidades auxiliares sem alterar o código ou aplicação principal.
Esse é um padrão que pode ser levado em conta sempre que houver a necessidade de adicionar lógica complementar à sua aplicação de forma desacoplada, mas ainda próxima o suficiente para compartilhar contexto de execução.