Slide 1

Slide 1 text

Shell Script Moderno Aurelio Jargas http://aurelio.net @oreio

Slide 2

Slide 2 text

Sysadmin anos 90 Sysadmin anos 90

Slide 3

Slide 3 text

Sysadmin hoje Foto: caminholivre.wordpress.com

Slide 4

Slide 4 text

Sysadmin dos anos 90 Servidor físico (empoeirado) CD do Linux Instala a distro Recompila o kernel Instala pacotes Edita arquivos .conf Inicia serviços Feito!

Slide 5

Slide 5 text

Sysadmin dos anos 90 Servidor físico (empoeirado) CD do Linux Instala a distro Recompila o kernel Instala pacotes Edita arquivos .conf install.sh Inicia serviços Feito! }

Slide 6

Slide 6 text

VM Cloud Docker

Slide 7

Slide 7 text

Sysadmin / DevOps moderno AWS / Azure / Google Cloud Puppet / Chef / Ansible GitHub / GitLab / Bitbucket Jenkins Travis CI / GitLab CI Docker

Slide 8

Slide 8 text

Meu precioso servidor, criado “na mão” com muito ♥

Slide 9

Slide 9 text

Hoje eu lanço e destruo servidores. Com um clique. Sem pensar muito.

Slide 10

Slide 10 text

E o shell?

Slide 11

Slide 11 text

Ambientes de execução de scripts Linha de comando $ meu-script.sh foo Cron 0 * * * * root /bin/meu-script.sh foo

Slide 12

Slide 12 text

Git

Slide 13

Slide 13 text

Git hooks $ ls /path/to/my/repo/.git/hooks/ applypatch-msg.sample pre-push.sample commit-msg.sample pre-rebase.sample post-update.sample prepare-commit-msg.sample pre-applypatch.sample update.sample pre-commit.sample $

Slide 14

Slide 14 text

Git hooks $ cat app.bare.git/hooks/post-receive #!/bin/bash -exu echo "Executando post-receive em producao" unset GIT_DIR cd /opt/repo/foobar.git git checkout producao git pull $

Slide 15

Slide 15 text

CI Travis, GitLab

Slide 16

Slide 16 text

Travis CI language: bash before_install: - url_base="https://raw.githubusercontent.com/aureliojargas" - curl -sOL "${url_base}/clitest/master/clitest" - chmod +x clitest - mv clitest testador script: - cd testador - ./run

Slide 17

Slide 17 text

Travis CI language: bash before_install: - url_base="https://raw.githubusercontent.com/aureliojargas" - curl -sOL "${url_base}/clitest/master/clitest" - chmod +x clitest - mv clitest testador script: - cd testador - ./run

Slide 18

Slide 18 text

GitLab CI code_lint: script: - date - uname -a - env - ls -la - cd wp-content/plugins/foo-setup - phpcs . - cd - - cd wp-content/themes/foo - phpcs --ignore=bootstrap,inc,js,css . - cd - unit_tests: script: - cd wp-content/plugins/foo-setup - WP_TESTS_DIR=/opt/wp-tests/wp-tests-lib phpunit

Slide 19

Slide 19 text

GitLab CI code_lint: script: - date - uname -a - env - ls -la - cd wp-content/plugins/foo-setup - phpcs . - cd - - cd wp-content/themes/foo - phpcs --ignore=bootstrap,inc,js,css . - cd - unit_tests: script: - cd wp-content/plugins/foo-setup - WP_TESTS_DIR=/opt/wp-tests/wp-tests-lib phpunit

Slide 20

Slide 20 text

Puppet

Slide 21

Slide 21 text

Puppet exec { '/bin/echo root >> /usr/lib/cron/cron.allow': path => '/usr/bin:/usr/sbin:/bin', unless => 'grep root /usr/lib/cron/cron.allow 2>/dev/null', } exec { 'tar -xf /Volumes/nfs02/important.tar': cwd => '/var/tmp', creates => '/var/tmp/myfile', path => ['/usr/bin', '/usr/sbin',], }

Slide 22

Slide 22 text

Jenkins

Slide 23

Slide 23 text

Jenkins

Slide 24

Slide 24 text

Docker

Slide 25

Slide 25 text

Docker FROM debian:jessie ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y curl COPY . /app WORKDIR /app ENV PATH /app:$PATH ENV ZZPATH /app/funcoeszz ENV ZZDIR /app/zz ENTRYPOINT ["bash", "funcoeszz"] CMD ["--help"]

Slide 26

Slide 26 text

Docker FROM debian:jessie ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y curl COPY . /app WORKDIR /app ENV PATH /app:$PATH ENV ZZPATH /app/funcoeszz ENV ZZDIR /app/zz ENTRYPOINT ["bash", "funcoeszz"] CMD ["--help"]

Slide 27

Slide 27 text

Docker FROM debian:jessie ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y curl COPY . /app WORKDIR /app ENV PATH /app:$PATH ENV ZZPATH /app/funcoeszz ENV ZZDIR /app/zz ENTRYPOINT ["bash", "funcoeszz"] CMD ["--help"]

Slide 28

Slide 28 text

Docker FROM debian:jessie ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y curl COPY . /app WORKDIR /app ENV PATH /app:$PATH ENV ZZPATH /app/funcoeszz ENV ZZDIR /app/zz ENTRYPOINT ["bash", "funcoeszz"] CMD ["--help"] cp -r . /app cd /app

Slide 29

Slide 29 text

Docker FROM debian:jessie ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y curl COPY . /app WORKDIR /app ENV PATH /app:$PATH ENV ZZPATH /app/funcoeszz ENV ZZDIR /app/zz ENTRYPOINT ["bash", "funcoeszz"] CMD ["--help"]

Slide 30

Slide 30 text

Docker FROM debian:jessie ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y curl COPY . /app WORKDIR /app ENV PATH /app:$PATH ENV ZZPATH /app/funcoeszz ENV ZZDIR /app/zz ENTRYPOINT ["bash", "funcoeszz"] CMD ["--help"] export DEBIAN_FRONTEND="noninteractive" export PATH="/app:$PATH" export ZZPATH="/app/funcoeszz" export ZZDIR="/app/zz"

Slide 31

Slide 31 text

Docker FROM debian:jessie ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y curl COPY . /app WORKDIR /app ENV PATH /app:$PATH ENV ZZPATH /app/funcoeszz ENV ZZDIR /app/zz ENTRYPOINT ["bash", "funcoeszz"] CMD ["--help"] if test $# -gt 0 then bash funcoeszz "$@" else bash funcoeszz --help fi

Slide 32

Slide 32 text

Boas práticas

Slide 33

Slide 33 text

Explore o ambiente $ date $ uname -a $ env | sort $ whoami $ groups $ ls -la $ ps auxw $ git branch $ git status $ docker info $ docker ps

Slide 34

Slide 34 text

Use funções para organizar o script #!/bin/bash build() { docker build ... } publish() { docker push ... docker rmi ... } run() { docker run ... } build publish run

Slide 35

Slide 35 text

Crie uma pasta “scripts” no repositório $ ls -1 scripts/ _lib.sh build.sh cleanup.sh database-reset.sh deploy.sh merge-branch.sh publish.sh test.sh $

Slide 36

Slide 36 text

Pratique POSIX #!/bin/sh Evite arrays Evite ${variavel/isso/aquilo} Evite ${variavel:1:3} Evite [[ Evite $FUNCNAME Evite for(;;) Evite $'…' Evite comando < <(comando)

Slide 37

Slide 37 text

Seja --verbose, mande tudo para STDOUT echo "Iniciando em $(date)" echo "Copiando os arquivos para $destino" cp -v * "$destino" echo echo "Iniciando o backup" tar cvzf meuapp-$timestamp.tgz "$destino" echo "Finalizando em $(date)"

Slide 38

Slide 38 text

Nomenclatura de variáveis Maiúsculas para variáveis de ambiente: $PATH $BUILD_ID $TRAVIS_OS_NAME Minúsculas para variáveis do script: base_dir=$(pwd) base_url='http://example.com' use_colors=1 Minúsculas para variáveis locais de funções: local i=0 local branch local path

Slide 39

Slide 39 text

Conheça as variáveis do seu ambiente Jenkins GitLab CI Travis $BUILD_ID $BUILD_NUMBER $BUILD_URL $JOB_NAME $GIT_COMMIT $CI_BUILD_ID $CI_BUILD_NAME $CI_BUILD_STAGE $CI_SERVER_NAME $CI_PROJECT_DIR $TRAVIS_BUILD_NUMBER $TRAVIS_JOB_NUMBER $TRAVIS_COMMIT $TRAVIS_OS_NAME $TRAVIS_PYTHON_VERSION

Slide 40

Slide 40 text

Use variáveis de ambiente $ ./meu-script.sh meu-app master 123 $ REPO=meu-app BRANCH=master VERSION=132 ./meu-script.sh

Slide 41

Slide 41 text

Use o modo “strict” do bash #!/bin/bash # Modo strict set -euo pipefail # set -e para abortar o script se houver qualquer erro cp /etc/passwd # set -u para tornar erro acessar variável não existente echo "$foo" # set -o pipefail para ajustar o exit code de um pipeline grep root /etc/passssswd | sort

Slide 42

Slide 42 text

Use o modo “strict” do bash (com exceções) #!/bin/bash # Modo strict set -euo pipefail # set -e para abortar o script se houver qualquer erro cp /etc/passwd || true # set -u para tornar erro acessar variável não existente echo "${foo:-}" # set -o pipefail para ajustar o exit code de um pipeline grep root /etc/passssswd | sort

Slide 43

Slide 43 text

Ligue o debug com $DEBUG #!/bin/bash test -n "$DEBUG" && set -x Para executar: $ ./meu-script.sh # sem debug $ DEBUG=1 ./meu-script.sh # com debug

Slide 44

Slide 44 text

Ligue o debug com $DEBUG - strict #!/bin/bash set -euo pipefail test -n "${DEBUG:-}" && set -x

Slide 45

Slide 45 text

Ferramentas

Slide 46

Slide 46 text

shellcheck http://www.shellcheck.net $ shellcheck meu-script.sh Line 3: for f in $(ls *.txt) ^-- SC2045: Iterating over ls output is fragile. Line 5: grep -i nofx.*mp3 $f ^-- SC2062: Quote the grep pattern so the shell won't interpret it. ^-- SC2086: Double quote to prevent globbing and word splitting.

Slide 47

Slide 47 text

jq - Parser de JSON https://stedolan.github.io/jq/ $ cat foo.json { "foo": { "bar": { "baz": 123 } } } $ cat foo.json | jq . { "foo": { "bar": { "baz": 123 } } } $ cat foo.json | jq .foo.bar.baz 123 $

Slide 48

Slide 48 text

curl, sed $ curl --location -D headers.txt http://www.example.com $ sed -i "s/%hostname%/$(hostname)/" /etc/app.conf $ sed -i '/debug/ s/false/true/' /etc/app.conf $ docker exec meu-app sed -i '/debug/ s/false/true/' /etc/app.conf

Slide 49

Slide 49 text

Cloud CLI AWS https://aws.amazon.com/cli/ aws Azure https://github.com/Azure/azure-xplat-cli azure DigitalOcean https://github.com/digitalocean/doctl doctl Google Cloud https://cloud.google.com/sdk/ gcloud, gsutil, bq, kubectl IBM Bluemix e Cloud Foundry https://clis.ng.bluemix.net bluemix, cf Rackspace https://developer.rackspace.com/docs/rack-cli/ rack

Slide 50

Slide 50 text

Perguntas? @oreio

Slide 51

Slide 51 text

$ __

Slide 52

Slide 52 text

No content