Slide 1

Slide 1 text

Deployando uma Phoenix app com Kubernetes no Google Cloud

Slide 2

Slide 2 text

Philip Sampaio • Desenvolvedor de software senior na Magnetis; • Trabalha com Ruby, Elixir e Javascript; • Criou o Floki. 2

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

Por que ? 4

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

Kubernetes, k8s ou kates 7

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

E na Magnetis? 9

Slide 10

Slide 10 text

Como era nossa stack • Majoritariamente Heroku; • Uma app Rails; • PostgreSQL, MongoDB, Redis e ElasticSearch. 10

Slide 11

Slide 11 text

Não queríamos nos preocupar 11

Slide 12

Slide 12 text

O Heroku dava conta 12

Slide 13

Slide 13 text

Começamos a usar Docker em desenvolvimento 13

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

Deployamos nosso monolito em staging usando Docker 15

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

k8s caiu como uma luva 17

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

k8s • uma grande comunidade; • possui algumas PaaS, como: • Amazon; • Digital Ocean; • Azure; • Google Cloud. 19

Slide 20

Slide 20 text

Ao nosso exemplo... 20

Slide 21

Slide 21 text

O build da imagem Docker 21

Slide 22

Slide 22 text

A imagem Docker • gerada no CI; • contém só a OTP app; • gerada com o Distillery. 22

Slide 23

Slide 23 text

Distillery 23

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

Distillery defp deps do [{:distillery, "~> 1.5", runtime: false}] end Precisamos rodar mix release p/ gerar a release. 25

Slide 26

Slide 26 text

O Dockerfile - parte 1 builder 26

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

REPLACE_OS_VARS ! 29

Slide 30

Slide 30 text

REPLACE_OS_VARS Possibilita que as env vars sejam diferentes entre o build e produção. É um hack do Distillery/Erlang. 30

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

REPLACE_OS_VARS Mais detalhes sobre ENV vars no ep. 7 do podcast Elixir Outlaws. 32

Slide 33

Slide 33 text

O Dockerfile - parte 2 release 33

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

O script de build no CI 37

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

Terminamos a imagem Docker! E agora? 39

Slide 40

Slide 40 text

k8s: alguns conceitos 40

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

Objetos do kubernetes • entidades persistidas que representam o estado do cluster; • alguns exemplos desses objetos: • deployment; • service; • ingress. • specs geralmente em YAML. 42

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

44

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

Ingress • conecta o mundo exterior aos services; • é onde se configura o SSL; • informalmente conhecido como "front-end". 49

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

51

Slide 52

Slide 52 text

E o código? 52

Slide 53

Slide 53 text

E pra falar com o DB? 53

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

O padrão sidecar 56

Slide 57

Slide 57 text

As incompatibilidades com ecossistema Elixir 57

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

Quando não usar k8s com Elixir? 60

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

Onde conhecer mais? • Docs do Google Cloud; • Livro Site Reliability Engineering do Google; • @kubernetesio • app de exemplo: https://github.com/philss/kates_app 62

Slide 63

Slide 63 text

Obrigado! ! Dúvidas? Twitter, Telegram: @philipsampaio / Github: @philss Estamos contratando bitly.com/mag-elixir 63