Deployando uma Phoenix app com Kubernetes no Google Cloud

Deployando uma Phoenix app com Kubernetes no Google Cloud

O Kubernetes está aí para mudar a forma como fazemos deploy de aplicações para a nuvem. É uma ferramenta muito interessante, pois possibilita o deploy de várias aplicações de maneira padronizada, com fácil escalonamento vertical e horizontal.

Apesar de o ambiente Erlang/Elixir possuir algumas limitações quando rodando no k8s, ganhamos certa flexibilidade no deploy e gerenciamento de nossas apps em produção.

Nessa apresentação falarei um pouco da experiência do nosso time em fazer o deploy de uma aplicação Phoenix usando o k8s do GKE - Google Kubernetes Engine. Vou mostrar algumas particularidades de configuração da app, assim como o build usando Docker, o fluxo de deploy e a conexão com o banco de dados.

Essa apresentação aconteceu no Elug, na B2W em São Paulo.

Alguns links:
- Distillery: https://github.com/bitwalker/distillery
- Episódio número 7 do podcast Elixir Outlaws - https://elixiroutlaws.com/7
- App de exemplo no Github: https://github.com/philss/kates_app
- Twitter: https://twitter.com/philipsampaio
- Github: https://github.com/philss

A69ccd99c8ef0be30b5dc870d7c8e9f8?s=128

Philip Sampaio

July 25, 2018
Tweet

Transcript

  1. Deployando uma Phoenix app com Kubernetes no Google Cloud

  2. Philip Sampaio • Desenvolvedor de software senior na Magnetis; •

    Trabalha com Ruby, Elixir e Javascript; • Criou o Floki. 2
  3. Objetivo dessa talk Explicar quais foram as decisões, desafios técnicos

    e da equipe na adoção do Kubernetes como plataforma para nossa infra. Também mostrar um pouco de código 3
  4. Por que ? 4

  5. Photo by chuttersnap on Unsplash - https://unsplash.com/photos/eqwFWHfQipg 5

  6. fonte https://blog.digitalocean.com/currents-june-2018/ 6

  7. Kubernetes, k8s ou kates 7

  8. História • Nasceu em 2014, dentro da Google; • Foi

    baseado no projeto Borg, da Google, que por 15 anos rodou containeres em produção; • É desenvolvido pela Cloud native computing foundation • Já teve mais de 1700 pessoas contribuindo. 8
  9. E na Magnetis? 9

  10. Como era nossa stack • Majoritariamente Heroku; • Uma app

    Rails; • PostgreSQL, MongoDB, Redis e ElasticSearch. 10
  11. Não queríamos nos preocupar 11

  12. O Heroku dava conta 12

  13. Começamos a usar Docker em desenvolvimento 13

  14. Docker-compose Nos ajudou muito a padronizar o setup do ambiente.

    14
  15. Deployamos nosso monolito em staging usando Docker 15

  16. 2 anos trabalhando com containeres em dev • vimos o

    time crescer; • a necessidade de dividir o time e aplicação em partes menores; • o Heroku estava ficando caro . 16
  17. k8s caiu como uma luva 17

  18. k8s • feito para aplicações containerizadas; • abstrai o conceito

    de servidor; • fácil de operar (mas não de manter um cluster!); • facilita escalar sua infra. 18
  19. k8s • uma grande comunidade; • possui algumas PaaS, como:

    • Amazon; • Digital Ocean; • Azure; • Google Cloud. 19
  20. Ao nosso exemplo... 20

  21. O build da imagem Docker 21

  22. A imagem Docker • gerada no CI; • contém só

    a OTP app; • gerada com o Distillery. 22
  23. Distillery 23

  24. Distillery • uma ferramenta p/ gerar releases das nossas aplicações;

    • releases são "pacotes" que dizem como nossa app deve rodar; • geralmente elas são auto-contidas. 24
  25. Distillery defp deps do [{:distillery, "~> 1.5", runtime: false}] end

    Precisamos rodar mix release p/ gerar a release. 25
  26. O Dockerfile - parte 1 builder 26

  27. FROM elixir:1.6.4-alpine as builder ARG APP_NAME=kates_app ENV MIX_ENV=prod REPLACE_OS_VARS=true RUN

    apk add --update alpine-sdk coreutils curl RUN mix local.hex --force \ && mix local.rebar --force WORKDIR /opt/app COPY . /opt/app RUN mix deps.get && \ mix release --env=prod --verbose RUN mkdir -p /opt && \ mv /opt/app/_build/prod/rel/${APP_NAME} /opt/release 27
  28. FROM elixir:1.6.4-alpine as builder ARG APP_NAME=kates_app ENV MIX_ENV=prod REPLACE_OS_VARS=true RUN

    apk add --update alpine-sdk coreutils curl RUN mix local.hex --force \ && mix local.rebar --force WORKDIR /opt/app COPY . /opt/app RUN mix deps.get && \ mix release --env=prod --verbose RUN mkdir -p /opt && \ mv /opt/app/_build/prod/rel/${APP_NAME} /opt/release 28
  29. REPLACE_OS_VARS ! 29

  30. REPLACE_OS_VARS Possibilita que as env vars sejam diferentes entre o

    build e produção. É um hack do Distillery/Erlang. 30
  31. REPLACE_OS_VARS Seu config/prod.exs precisa declarar env var com $ {ENV_VAR_NAME}.

    config :kates_app, KatesApp.Repo, adapter: Ecto.Adapters.Postgres, url: "${DATABASE_URL}" 31
  32. REPLACE_OS_VARS Mais detalhes sobre ENV vars no ep. 7 do

    podcast Elixir Outlaws. 32
  33. O Dockerfile - parte 2 release 33

  34. FROM alpine:3.7 ARG REVISION ENV MIX_ENV=prod PORT=4000 REPLACE_OS_VARS=true APP_REVISION=$REVISION RUN

    apk update && apk --no-cache --update add bash curl openssl-dev postgresql-client WORKDIR /opt/app EXPOSE ${PORT} COPY --from=builder /opt/release . CMD /opt/app/bin/kates_app foreground 34
  35. FROM alpine:3.7 ARG REVISION ENV MIX_ENV=prod PORT=4000 REPLACE_OS_VARS=true APP_REVISION=$REVISION RUN

    apk update && apk --no-cache --update add bash curl openssl-dev postgresql-client WORKDIR /opt/app EXPOSE ${PORT} COPY --from=builder /opt/release . CMD /opt/app/bin/kates_app foreground 35
  36. Multi stage build Permite que em um Dockerfile seja possível

    ter dois passos de build (ou mais). A nossa segunda parte não precisa ter Elixir pois a release do Distillery já é auto-contida. 36
  37. O script de build no CI 37

  38. O script de build no CI image_name="gcr.io/kates-project/kates-app:$REVISION" docker build \

    --build-arg REVISION=$REVISION \ -t $image_name \ -f deploy/Dockerfile . docker push gcr.io/kates-project/kates-app:$REVISION 38
  39. Terminamos a imagem Docker! E agora? 39

  40. k8s: alguns conceitos 40

  41. Um cluster k8s possui 2 partes principais 1. O master,

    que é o que controla o cluster; 2. Os nodes que são reponsáveis por rodar nossos Objetos. 41
  42. Objetos do kubernetes • entidades persistidas que representam o estado

    do cluster; • alguns exemplos desses objetos: • deployment; • service; • ingress. • specs geralmente em YAML. 42
  43. Pra aplicar uma mudança ao cluster $ kubectl apply -f

    spec-do-objeto.yaml Remover essa mudança $ kubectl delete -f spec-do-objeto.yaml 43
  44. 44

  45. Deployment • é onde descrevemos como nossa aplicação será deployada;

    • é a descrição de um Pod com um ou mais containeres; • nosso container vai ser descrito aqui. 45
  46. apiVersion: extensions/v1beta1 kind: Deployment metadata: name: api spec: replicas: 3

    template: metadata: labels: name: api spec: containers: - name: api image: gcr.io/kates-project/kates-app:53af84191asf85 imagePullPolicy: Always ports: - containerPort: 4000 46
  47. Service • o Service serve para expor uma determina porta

    ou portas para um conjunto de pods; • funciona como um "load balancer"; • é também conhecido como "back-end" informalmente. 47
  48. apiVersion: v1 kind: Service metadata: name: api-svc labels: name: api-svc

    spec: selector: name: api type: NodePort ports: - port: 80 protocol: TCP name: http targetPort: 4000 48
  49. Ingress • conecta o mundo exterior aos services; • é

    onde se configura o SSL; • informalmente conhecido como "front-end". 49
  50. apiVersion: extensions/v1beta1 kind: Ingress metadata: name: api-ingress annotations: kubernetes.io/ingress.class: "gce"

    labels: name: api-ingress spec: tls: - secretName: tls-secrets-20180723 backend: serviceName: api-svc servicePort: 80 50
  51. 51

  52. E o código? 52

  53. E pra falar com o DB? 53

  54. O padrão sidecar original de https://vintagetopia.co/2018/03/01/23-cool-sidecar-motorcycles/ 54

  55. O padrão sidecar É uma forma de manter um proxy

    p/ o seu banco no mesmo Pod, ao lado da sua aplicação. Conectamos como se fosse "localhost". E é bem mais seguro. 55
  56. O padrão sidecar 56

  57. As incompatibilidades com ecossistema Elixir 57

  58. As incompatibilidades com ecossistema Elixir Muitos dos conceitos do k8s

    e do Erlang/OTP são similares. Isso faz com que às vezes não sejam muito compatíveis. 58
  59. Feature Motivo Equivalente no k8s? É contornável? Hot code swapping

    Os containeres são efêmeros. Não compartilham disco, por padrão Não Sim (mas difícil) Clustering de nodes É necessário ter dois tipos de container: um master e node Sim Sim Controle de recursos de hardware O próprio k8s faz isso Sim Não muito 59
  60. Quando não usar k8s com Elixir? 60

  61. Quando não usar k8s com Elixir? • Se performance e

    recursos são críticos p/ sua app; • Se você quer ter controle de todo o sistema operacional; • Se você não vai trabalhar em um cenário com vários serviços. 61
  62. Onde conhecer mais? • Docs do Google Cloud; • Livro

    Site Reliability Engineering do Google; • @kubernetesio • app de exemplo: https://github.com/philss/kates_app 62
  63. Obrigado! ! Dúvidas? Twitter, Telegram: @philipsampaio / Github: @philss Estamos

    contratando bitly.com/mag-elixir 63