Dockerizando aplicações em
uma Fintech
O bom, o mau e o feio/as surpresas
Rafael Gomes
Pai de um menino
DevOps Engineer #PayCertify
Soteropolitano
Docker Captain
Membro do Core Team do DevOpsDays
#devops
#docker
INICIATIVAS
Raul Hacker Club
Gatilho Kosmico: gatilhokosmico.com.br
CONTATOS
@gomex
https://gomex.me/
https://www.linkedin.com/in/rbgomes/
O que estou fazendo?
Docker para Desenvolvedores
Pague quanto quiser
Inclusive nada
Aberto
Você só precisa citar o autor
Colaborativo
https://github.com/gomex/docker-para-desenvolvedores
Link
https://leanpub.com/dockerparadesenvolvedores
A Fintech
Ecossistema de pagamento
100+ clientes
Processa 50m dólares mês
20 desenvolvedores
10+ APIs
4 anos de empresa
O desafio
Transformar em imagem
docker uma aplicação escrita
em Ruby on Rails.
Web Worker
- Usa NodeJS
- Deploy manual no Heroku
O método
Entrega = Atender expectativas do cliente
O método - Um exemplo
Dockerizar uma
app
Ambiente Prod
Ambiente QA
Ambiente só de
dev
Entregue
Criar CI
Lint Entregue
Criar
artefato
Deploy
Teste
Sonar
Entregue
Primeiros passos
Entregar um ambiente de
desenvolvimento
automatizado e
padronizado
1
Entendendendo as
demandas de Dev
1. Não pode demorar o build da imagem
2. Possibilidade de manter cache de instalação
de gems
3. Possibilidade de debugar o código da gem
4. Armazenar histórico irbrc
5. Precisa automatizar o primeiro uso (db
creation, migration e etc)
6. Usuário diferente de root
Exemplo do Dockerfile
FROM ruby:2.5.1 as builder
RUN curl -sL
https://deb.nodesource.com/setup_8.x |
bash - &&
curl -sS
https://dl.yarnpkg.com/debian/pubkey.g
pg | apt-key add - &&
echo "deb
https://dl.yarnpkg.com/debian/ stable
main" | tee
/etc/apt/sources.list.d/yarn.list
ARG NODE_DATE_INSTALL=20180710
RUN apt-get update 
&& apt-get install -y locales 
graphviz 
imagemagick 
postgresql-client-9.6 
yarn 
nodejs 
&& echo "en_US.UTF-8 UTF-8" >
/etc/locale.gen && /usr/sbin/locale-gen
&&
rm -rf /var/lib/apt/lists/*
… continuação do Dockerfile
ARG BUNDLE_GITHUB__COM
ENV BUNDLE_GITHUB__COM 
$BUNDLE_GITHUB__COM
ENV GEM_HOME /gems/vendor
ENV GEM_PATH /gems/vendor
ENV GEM_SPEC_CACHE /gems/specs
ENV BUNDLE_PATH /gems/vendor
ENV BUNDLE_BIN /gems/vendor/bin
ENV PATH 
/app/bin:/gems/vendor/bin:$PATH
ARG RAILS_ENV
ENV RAILS_ENV=$RAILS_ENV
ENV APP_ROOT /app
WORKDIR $APP_ROOT/
RUN mkdir -p /gems
RUN groupadd -r app 
&& groupmod -g 1000 app 
&& useradd -g app -ms /bin/bash app 
&& chown app $APP_ROOT 
&& chown -R app /gems
USER app
Exemplo do docker-compose
version: '3.4'
services:
app:
working_dir: $PWD
build:
context: .
target: builder
args:
BUNDLE_GITHUB__COM: $BUNDLE_GITHUB__COM
RAILS_ENV: development
…continuação do docker-compose
image: app:development
env_file:
- ./.env
command: bundle exec rails server -b 0.0.0.0
volumes:
- ./utils_ruby:/utils_ruby
- .:$PWD
- gems_2_5_1:/gems
- app_home:/home/app/
- .irbrc:/home/app/.irbrc
ports:
- 3010:3000
depends_on:
- mailcatcher
- postgres
- redis
1. Não pode demorar o build da imagem
2. Possibilidade de manter cache de instalação
de gems
3. Possibilidade de debugar o código da gem
4. Armazenar histórico irbrc
5. Precisa automatizar o primeiro uso (db
creation, migration e etc)
6. Usuário diferente de root
Exemplo do Makefile
dev: ## Start complete app dev environment
docker-compose up --build
dev-first: ## Start complete app dev environment
docker-compose rm -f
docker-compose build
docker-compose run app bundle install --gemfile=Gemfile
docker-compose run app yarn install
docker-compose run app rails db:drop
docker-compose run app rails db:create db:migrate db:seed
docker-compose stop
1. Não pode demorar o build da imagem
2. Possibilidade de manter cache de instalação
de gems
3. Possibilidade de debugar o código da gem
4. Armazenar histórico irbrc
5. Precisa automatizar o primeiro uso (db
creation, migration e etc)
6. Usuário diferente de root
Criando CI
Entregar as melhores
práticas de um pipeline de
entrega de imagens docker
como artefato
2
Pipeline completo até QA
Precisamos incluir o conceito
de lint no CI
Exemplo do Jenkinsfile
stages {
stage('lint') {
agent {
docker { image 'paycertify/docker-lint:v2' }
}
steps {
sh 'dockerfile_lint -f Dockerfile -r
/rules/default_rules.yaml'
}
}
Exemplo do Dockerfile do Docker-lint
FROM projectatomic/dockerfile-lint:latest
LABEL maintainer "Rafael Gomes
<rafael.gomes@paycertify.com>"
COPY default_rules.yaml /rules/default_rules.yaml
Exemplo do default_rules do Docker-lint
required_instructions:
-
instruction: "EXPOSE"
count: 1
level: "info"
message: "There is no 'EXPOSE' instruction"
description: "Without exposed ports how will the service be accessed?"
reference_url:
- "https://docs.docker.com/engine/reference/builder/"
- "#expose"
Resultado do lint no pipeline
O teste precisa de Banco
Exemplo do Jenkinsfile
stage('test') {
steps {
sh 'make dev-first'
sh 'make rspec-test'
sh 'make db-drop'
}
}
Exemplo do Makefile
dev-first: ## Start complete app dev environment
docker-compose rm -f
docker-compose build
docker-compose run app bundle install --gemfile=Gemfile
docker-compose run app yarn install
docker-compose run app rails db:drop
docker-compose run app rails db:create db:migrate db:seed
docker-compose stop
...Continuação do Makefile
rspec-test: ## Run rspec test
docker-compose rm -f
docker-compose build
docker-compose run app rspec .
docker-compose stop
db-drop: ## Drop DB
docker-compose rm -f
docker-compose build
docker-compose run app rails db:drop
docker-compose stop
Resultado do rspec no pipeline
Uma imagem docker apenas!
Dockerfile MultiStage Build
FROM ruby:2.5.1 as builder
…
FROM builder as install
<Copia gemfile e package.json para instalar pacotes nodes e gems>
FROM install as preprod
<Copia o código e compila os assets do node>
Dockerfile MultiStage Build
FROM paycertify/ruby:2.5.1-slim as prod
...
WORKDIR /app/
...
COPY --from=preprod /usr/local/bundle/ /usr/local/bundle/
COPY --from=preprod /app/ /app/
COPY --from=preprod /gems/ /gems/
EXPOSE 3000
CMD ["bundle","exec","rails","server","-b","0.0.0.0"]
Exemplo do Jenkinsfile
stage('build') {
steps {
script {
sh "make qa-build"
println "Newly generated app image"
}
}
}
Makefile
qa-build: ## Build QA image
docker build -t app:$(GIT_COMMIT) --target prod .
Aplicando tag e mandando
pra Heroku
Exemplo do Jenkinsfile
stage('tag-push-qa') {
when {
branch "staging"
}
steps {
script {
sh 'make heroku-tag-qa'
}
}
}
Makefile
heroku-tag-qa: docker-heroku-login ## Tag QA image
docker tag app:$(GIT_COMMIT) registry.heroku.com/app/web
docker tag worker:$(GIT_COMMIT) registry.heroku.com/app/worker
docker push registry.heroku.com/app/web
docker push registry.heroku.com/app/worker
# HELPERS
docker-heroku-login: ## Auto login to Heroku Docker Registry
docker login --username=_ --password=$(API_KEY) registry.heroku.com
Fazendo deploy no heroku
Exemplo do Jenkinsfile
stage('deploy-heroku-qa') {
when {
branch "staging"
}
steps {
sh 'make heroku-release-qa'
}
}
Makefile
heroku-release-qa: ## Release QA image
heroku container:release --app app web
heroku run -a app rails db:migrate
A aplicação precisa ser
testada end-to-end
(capybara)
Exemplo do Jenkinsfile
stage('QA e2e test') {
when {
branch "staging"
}
steps {
script {
sh 'make e2e_test'
}
}
}
Makefile
e2e_test: ## Start complete app QA environment
docker run --rm -e URL_STAGING=$$URL_STAGING -e
EMAIL_ADMIN=$$EMAIL_ADMIN -e
EMAIL_MERCHANT=$$EMAIL_MERCHANT -e
PASSWORD=$$PASSWORD -e HUB=$$HUB -v
$$PWD/test/e2e_tests:/test paycertify/capybara:0.4
Pipeline completo até QA
Obtendo feedback
A solução proposta atende
às expectativas dos
desenvolvedores?
Lembre-se nosso objetivo
aqui é isso!
3
Cada passo, cada mudança
no projeto foi revisada e
aceita o PR por ao menos um
pessoa do time de dev
Parear com o time de dev e
obter experiência
Deploy em produção
A janela de mudança
precisa ser a menor
possível
4
Um backup e restore do
banco de produção manual
para o ambiente
automatizado é necessário
Exemplo de comandos do Heroku
heroku pg:backups:download b001 --app manual-prod-app
heroku pg:backups:restore latest.dump --app auto-prod-app
Obrigado!
Rafael Gomes
Pai de um menino
DevOps Engineer #PayCertify
Soteropolitano
Docker Captain
Membro do Core Team do DevOpsDays
#devops
#docker
INICIATIVAS
Raul Hacker Club
Core team do DevOpsDays
CONTATOS
@gomex
https://gomex.me/
https://www.linkedin.com/in/rbgomes/

Dockerizando aplicações em uma Fintech

  • 1.
    Dockerizando aplicações em umaFintech O bom, o mau e o feio/as surpresas
  • 2.
    Rafael Gomes Pai deum menino DevOps Engineer #PayCertify Soteropolitano Docker Captain Membro do Core Team do DevOpsDays #devops #docker INICIATIVAS Raul Hacker Club Gatilho Kosmico: gatilhokosmico.com.br CONTATOS @gomex https://gomex.me/ https://www.linkedin.com/in/rbgomes/
  • 3.
    O que estoufazendo? Docker para Desenvolvedores Pague quanto quiser Inclusive nada Aberto Você só precisa citar o autor Colaborativo https://github.com/gomex/docker-para-desenvolvedores Link https://leanpub.com/dockerparadesenvolvedores
  • 4.
  • 5.
    Ecossistema de pagamento 100+clientes Processa 50m dólares mês 20 desenvolvedores 10+ APIs 4 anos de empresa
  • 6.
  • 7.
    Transformar em imagem dockeruma aplicação escrita em Ruby on Rails.
  • 8.
  • 9.
    - Usa NodeJS -Deploy manual no Heroku
  • 10.
  • 12.
    Entrega = Atenderexpectativas do cliente
  • 13.
    O método -Um exemplo
  • 14.
    Dockerizar uma app Ambiente Prod AmbienteQA Ambiente só de dev Entregue Criar CI Lint Entregue Criar artefato Deploy Teste Sonar Entregue
  • 15.
  • 16.
    Entregar um ambientede desenvolvimento automatizado e padronizado 1
  • 17.
  • 18.
    1. Não podedemorar o build da imagem 2. Possibilidade de manter cache de instalação de gems 3. Possibilidade de debugar o código da gem 4. Armazenar histórico irbrc 5. Precisa automatizar o primeiro uso (db creation, migration e etc) 6. Usuário diferente de root
  • 19.
    Exemplo do Dockerfile FROMruby:2.5.1 as builder RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - && curl -sS https://dl.yarnpkg.com/debian/pubkey.g pg | apt-key add - && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list ARG NODE_DATE_INSTALL=20180710 RUN apt-get update && apt-get install -y locales graphviz imagemagick postgresql-client-9.6 yarn nodejs && echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && /usr/sbin/locale-gen && rm -rf /var/lib/apt/lists/*
  • 20.
    … continuação doDockerfile ARG BUNDLE_GITHUB__COM ENV BUNDLE_GITHUB__COM $BUNDLE_GITHUB__COM ENV GEM_HOME /gems/vendor ENV GEM_PATH /gems/vendor ENV GEM_SPEC_CACHE /gems/specs ENV BUNDLE_PATH /gems/vendor ENV BUNDLE_BIN /gems/vendor/bin ENV PATH /app/bin:/gems/vendor/bin:$PATH ARG RAILS_ENV ENV RAILS_ENV=$RAILS_ENV ENV APP_ROOT /app WORKDIR $APP_ROOT/ RUN mkdir -p /gems RUN groupadd -r app && groupmod -g 1000 app && useradd -g app -ms /bin/bash app && chown app $APP_ROOT && chown -R app /gems USER app
  • 21.
    Exemplo do docker-compose version:'3.4' services: app: working_dir: $PWD build: context: . target: builder args: BUNDLE_GITHUB__COM: $BUNDLE_GITHUB__COM RAILS_ENV: development
  • 22.
    …continuação do docker-compose image:app:development env_file: - ./.env command: bundle exec rails server -b 0.0.0.0 volumes: - ./utils_ruby:/utils_ruby - .:$PWD - gems_2_5_1:/gems - app_home:/home/app/ - .irbrc:/home/app/.irbrc ports: - 3010:3000 depends_on: - mailcatcher - postgres - redis
  • 23.
    1. Não podedemorar o build da imagem 2. Possibilidade de manter cache de instalação de gems 3. Possibilidade de debugar o código da gem 4. Armazenar histórico irbrc 5. Precisa automatizar o primeiro uso (db creation, migration e etc) 6. Usuário diferente de root
  • 25.
    Exemplo do Makefile dev:## Start complete app dev environment docker-compose up --build dev-first: ## Start complete app dev environment docker-compose rm -f docker-compose build docker-compose run app bundle install --gemfile=Gemfile docker-compose run app yarn install docker-compose run app rails db:drop docker-compose run app rails db:create db:migrate db:seed docker-compose stop
  • 26.
    1. Não podedemorar o build da imagem 2. Possibilidade de manter cache de instalação de gems 3. Possibilidade de debugar o código da gem 4. Armazenar histórico irbrc 5. Precisa automatizar o primeiro uso (db creation, migration e etc) 6. Usuário diferente de root
  • 27.
  • 28.
    Entregar as melhores práticasde um pipeline de entrega de imagens docker como artefato 2
  • 29.
  • 30.
    Precisamos incluir oconceito de lint no CI
  • 31.
    Exemplo do Jenkinsfile stages{ stage('lint') { agent { docker { image 'paycertify/docker-lint:v2' } } steps { sh 'dockerfile_lint -f Dockerfile -r /rules/default_rules.yaml' } }
  • 32.
    Exemplo do Dockerfiledo Docker-lint FROM projectatomic/dockerfile-lint:latest LABEL maintainer "Rafael Gomes <rafael.gomes@paycertify.com>" COPY default_rules.yaml /rules/default_rules.yaml
  • 33.
    Exemplo do default_rulesdo Docker-lint required_instructions: - instruction: "EXPOSE" count: 1 level: "info" message: "There is no 'EXPOSE' instruction" description: "Without exposed ports how will the service be accessed?" reference_url: - "https://docs.docker.com/engine/reference/builder/" - "#expose"
  • 34.
    Resultado do lintno pipeline
  • 35.
  • 36.
    Exemplo do Jenkinsfile stage('test'){ steps { sh 'make dev-first' sh 'make rspec-test' sh 'make db-drop' } }
  • 37.
    Exemplo do Makefile dev-first:## Start complete app dev environment docker-compose rm -f docker-compose build docker-compose run app bundle install --gemfile=Gemfile docker-compose run app yarn install docker-compose run app rails db:drop docker-compose run app rails db:create db:migrate db:seed docker-compose stop
  • 38.
    ...Continuação do Makefile rspec-test:## Run rspec test docker-compose rm -f docker-compose build docker-compose run app rspec . docker-compose stop db-drop: ## Drop DB docker-compose rm -f docker-compose build docker-compose run app rails db:drop docker-compose stop
  • 39.
    Resultado do rspecno pipeline
  • 40.
  • 41.
    Dockerfile MultiStage Build FROMruby:2.5.1 as builder … FROM builder as install <Copia gemfile e package.json para instalar pacotes nodes e gems> FROM install as preprod <Copia o código e compila os assets do node>
  • 42.
    Dockerfile MultiStage Build FROMpaycertify/ruby:2.5.1-slim as prod ... WORKDIR /app/ ... COPY --from=preprod /usr/local/bundle/ /usr/local/bundle/ COPY --from=preprod /app/ /app/ COPY --from=preprod /gems/ /gems/ EXPOSE 3000 CMD ["bundle","exec","rails","server","-b","0.0.0.0"]
  • 43.
    Exemplo do Jenkinsfile stage('build'){ steps { script { sh "make qa-build" println "Newly generated app image" } } }
  • 44.
    Makefile qa-build: ## BuildQA image docker build -t app:$(GIT_COMMIT) --target prod .
  • 45.
    Aplicando tag emandando pra Heroku
  • 46.
    Exemplo do Jenkinsfile stage('tag-push-qa'){ when { branch "staging" } steps { script { sh 'make heroku-tag-qa' } } }
  • 47.
    Makefile heroku-tag-qa: docker-heroku-login ##Tag QA image docker tag app:$(GIT_COMMIT) registry.heroku.com/app/web docker tag worker:$(GIT_COMMIT) registry.heroku.com/app/worker docker push registry.heroku.com/app/web docker push registry.heroku.com/app/worker # HELPERS docker-heroku-login: ## Auto login to Heroku Docker Registry docker login --username=_ --password=$(API_KEY) registry.heroku.com
  • 48.
  • 49.
    Exemplo do Jenkinsfile stage('deploy-heroku-qa'){ when { branch "staging" } steps { sh 'make heroku-release-qa' } }
  • 50.
    Makefile heroku-release-qa: ## ReleaseQA image heroku container:release --app app web heroku run -a app rails db:migrate
  • 51.
    A aplicação precisaser testada end-to-end (capybara)
  • 52.
    Exemplo do Jenkinsfile stage('QAe2e test') { when { branch "staging" } steps { script { sh 'make e2e_test' } } }
  • 53.
    Makefile e2e_test: ## Startcomplete app QA environment docker run --rm -e URL_STAGING=$$URL_STAGING -e EMAIL_ADMIN=$$EMAIL_ADMIN -e EMAIL_MERCHANT=$$EMAIL_MERCHANT -e PASSWORD=$$PASSWORD -e HUB=$$HUB -v $$PWD/test/e2e_tests:/test paycertify/capybara:0.4
  • 54.
  • 55.
  • 56.
    A solução propostaatende às expectativas dos desenvolvedores? Lembre-se nosso objetivo aqui é isso! 3
  • 57.
    Cada passo, cadamudança no projeto foi revisada e aceita o PR por ao menos um pessoa do time de dev
  • 58.
    Parear com otime de dev e obter experiência
  • 59.
  • 60.
    A janela demudança precisa ser a menor possível 4
  • 61.
    Um backup erestore do banco de produção manual para o ambiente automatizado é necessário
  • 62.
    Exemplo de comandosdo Heroku heroku pg:backups:download b001 --app manual-prod-app heroku pg:backups:restore latest.dump --app auto-prod-app
  • 63.
  • 64.
    Rafael Gomes Pai deum menino DevOps Engineer #PayCertify Soteropolitano Docker Captain Membro do Core Team do DevOpsDays #devops #docker INICIATIVAS Raul Hacker Club Core team do DevOpsDays CONTATOS @gomex https://gomex.me/ https://www.linkedin.com/in/rbgomes/