Hoje gostaria de mostrar como podemos usar Github Actions ao lado de GCP, Packer e Ansible, para construir e rastrear imagens de máquinas.

Untitled

Configuração do Hashicorp Cloud

Antes de prosseguirmos para a explicação do pipeline, precisamos configurar algumas credenciais. Começando pelo Hashicorp Cloud.

  1. Faça login no Hashicorp Cloud
  2. Vá para a seção IAM
  3. Crie um Principal de Serviço e salve o ID e o SECRET fornecidos.

Service Principal Example

Exemplo de Principal de Serviço

  1. Em seguida, vá para a seção Packer e crie o repositório.

Configuração do Google Cloud

No Google Cloud, precisamos apenas criar uma Conta de Serviço com três funções: Admin de Instância de Computação v1, Usuário de Conta de Serviço e Usuário de Túnel Seguro IAP.

  1. Faça login no Google Cloud.
  2. Vá para a página IAM -> Conta de Serviço
  3. Crie uma Conta de Serviço

SA Example

Exemplo de Conta de Serviço

  1. Adicione as permissões:

Add The Roles

Adicione os Papéis

  1. Pronto. (você pode pular o passo 3)
  2. Crie uma Chave para a Conta de Serviço e Salve.

Create a JSON Key in the Keys Section

Crie uma Chave JSON na Seção de Chaves

Código

Agora, vamos programar. Neste exemplo, vamos criar uma imagem do Prometheus. A imagem abaixo mostra uma ideia de como estruturar o repositório.

  1. Uma subpasta por imagem
  2. Cada subpasta contendo pelo menos dois arquivos: build.pkr.hcl e variables.pkr.hcl.

Folder Structure

Estrutura de Pastas

Aviso Eu sei que hoje existem muitos Serviços Gerenciados de Prometheus disponíveis para uso, eu apenas decidi criar uma máquina do Prometheus apenas para fins de exemplo.

O código abaixo é um exemplo da configuração mínima a seguir. Mas antes, algumas considerações importantes:

  1. Para rastrear os metadados da imagem no Hashicorp Cloud, precisamos adicionar o bloco hcp_packer_registry, fornecendo valores adequados.
  2. Para o GCP, é importante desativar use_proxy no bloco Ansible, caso contrário, você pode enfrentar alguns problemas quando o Ansible tentar estabelecer uma conexão com a máquina.
  3. O Packer Cloud armazenará apenas os metadados das imagens. build.pkr.hcl
locals {
  timestamp = regex_replace(timestamp(), "[- TZ:]", "")
}

source "googlecompute" "prometheus-image" {
  project_id          = var.project_id
  zone                = var.zone
  source_image_family = "centos-7"
  image_name          = "packer-prometheus-${local.timestamp}"
  image_description   = "Prometheus Web Server"
  ssh_username        = "packer"
  tags                = ["packer"]
}

build {
  sources = ["sources.googlecompute.prometheus-image"]

  hcp_packer_registry {
    bucket_name = "packer-prometheus-images"
    description = "Bucket used to store Prometheus images metadata"
  }

  provisioner "ansible" {
    playbook_file = "./playbook.yml"
    use_proxy     = false
  }
}
variable project_id {}
variable zone {}

E então, crie o arquivo de playbook (veja no Github).

Pipeline

Sobre o pipeline, podemos criar um baseado em recursos. Para isso, temos algumas considerações importantes também:

  1. A imagem oficial do contêiner do Hashicorp Packer não tem Ansible instalado, e falta ferramentas binárias para nos ajudar a personalizar a imagem. Então, devemos criar uma personalizada. Aqui está um exemplo de como podemos fazer isso:
FROM --platform=amd64 python:3.9.16

RUN wget -q https://releases.hashicorp.com/packer/1.8.5/packer_1.8.5_linux_amd64.zip && \ 
    unzip packer_1.8.5_linux_amd64.zip && \
    mv packer /usr/local/bin && \
    python3 -m pip -q install ansible

ENTRYPOINT [ "/bin/bash" ]

Em seguida, marque e publique em seu repositório.

  1. Temos que definir três variáveis em nossos Segredos do GitHub: o ID do Cliente e o Segredo do Principal de Serviço do Hashicorp configurado anteriormente, e nossa chave JSON da Conta de Serviço. Então, basta usá-las no pipeline como no exemplo abaixo.
  2. O Packer usará uma VM no GCP para executar os comandos do Ansible e criar a imagem, no final ou se ocorrer algum erro, essa VM será destruída. Então, tenha cuidado em seu pipeline se você estiver usando uma matriz como eu para executar a construção em paralelo para não habilitar o fail-fast. O Packer possui um bom tratamento de erros, mas se alguns trabalhos paralelos falharem quando o fail-fase estiver habilitado, todos os outros receberão um encerramento forçado, fazendo com que o tratamento de erros não funcione, e então as instâncias criadas pelo Packer não serão destruídas, e claro, não queremos surpresas na fatura.

Agora, vamos definir nosso código:

name: Build and Publish VM Image

on:
  push:
    branches:
      - main

env: 
  HCP_CLIENT_ID: ${{ secrets.HCP_CLIENT_ID }}
  HCP_CLIENT_SECRET: ${{ secrets.HCP_CLIENT_SECRET }}

jobs:
  build:
    runs-on: ubuntu-20.04
    container:
      image: andersondarioo/packer-ansible:1.0.0
    strategy:
        matrix:
          subfolder: [ prometheus ]
        fail-fast: false

    steps:
    - name: Checkout
      uses: actions/checkout@v3

    - name: 'Authenticate to Google Cloud'
      uses: 'google-github-actions/[email protected]'
      with:
        credentials_json: '${{ secrets.GOOGLE_CREDENTIALS }}'
        
    - name: Build image
      run: | 
        cd ${{ matrix.subfolder }}
        packer build -var "project_id=aa-devops" -var "zone=us-central1-a"

Main Workflow

Fluxo de Trabalho Principal

name: Validate Pull Request

on:
  pull_request:
    branches: 
      - main

env: 
  HCP_CLIENT_ID: ${{ secrets.HCP_CLIENT_ID }}
  HCP_CLIENT_SECRET: ${{ secrets.HCP_CLIENT_SECRET }}

jobs:
  validate:
    runs-on: ubuntu-20.04
    container:
      image: andersondarioo/packer-ansible:1.0.0
    strategy:
        matrix:
          subfolder: [ prometheus ]
        fail-fast: false

    steps:
    - name: Checkout
      uses: actions/checkout@v3
        
    - name: Validate image
      run: | 
        cd ${{ matrix.subfolder }}
        packer validate -var "project_id=aa-devops" -var "zone=us-central1-a" .
        packer fmt -check .

PR Workflow

Fluxo de Trabalho de PR

Validação

Agora, se olharmos dentro do Hashicorp Packer Cloud, podemos ver os metadados do nosso balde de imagens criados:

Image Metadata Published

Metadados da Imagem Publicados

E também podemos ver nossa imagem criada no GCP:

GCP Image

Imagem GCP

Agora você pode usar a imagem.

Se você gostaria de saber como configurar o Terraform Cloud e o GCP para implantar as imagens do Packer criadas aqui, por favor, dê uma olhada no meu próximo

Suporte

Se você achar meus posts úteis e gostaria de me apoiar, por favor, me compre um café: Anderson Dario é blog pessoal e blog de tecnologia

Isso é tudo. Obrigado.