Observação:

Usar o Packer para criar imagens personalizadas do Oracle Cloud Infrastructure

Introdução

Este tutorial trata de obter uma imagem base do OCI ou qualquer imagem de computação que você já tenha no OCI e modificá-la de acordo com as necessidades do cliente.

Por exemplo, talvez você precise alterar o modo de inicialização de imagem de nativo para paravirtualização ou alterar o anexo VNIC (Virtual Network Interface Card). Por exemplo, os nós de trabalho do OKE precisam deles. Da mesma forma, você pode instalar pacotes de SO adicionais ou alterar OS parâmetros de kernel da Instância usando o provisionador do Packer (como no Terraform).

Digamos que você precise de uma imagem na qual deseja ter o banco de dados PostgreSQL instalado e alguns parâmetros ulimit para ter outros valores. Tudo isso pode ser feito iniciando uma computação com base em uma imagem e, em seguida, alterando o que precisar dela, instale os programas, os aplicativos e os pacotes necessários e salve a instância como uma nova Imagem Personalizada.

Agora imagine que você precisa criar várias imagens personalizadas, para várias arquiteturas e ao longo do tempo você precisa adicionar/alterar os programas ou pacotes adicionados à sua imagem personalizada. Para isso, podemos usar o Pacote em HashiCorp.

Empacotador

Packer é a ferramenta de código-fonte aberto da HashiCorp usada para criar imagens de máquina da configuração de origem. É leve, funciona em todos os principais sistemas operacionais, altamente eficientes. Não substitui o gerenciamento de configuração como Chef ou Puppet. Na verdade, quando você constrói imagens, o Packer é capaz de usar ferramentas como Chef ou Puppet para instalar software na imagem. Alguns dos recursos são:

Vantagens de usar o Packer

Autenticação do empacotador

Você pode autenticar o Packer usando as opções a seguir.

Observação: Saiba mais sobre Autenticação de Pacote, mas a maneira preferível é usar o arquivo .oci/config ou o controlador de instâncias.

Como o Packer funciona

Nas tarefas, o Packer usa uma imagem especificada no parâmetro base_image_ocid e implanta uma instância de computação com os atributos especificados por você nos parâmetros de configuração necessários (ou seja, disponibilidade*domínio, forma e muito mais).

Depois desse Packer tentará ssh na instância para executar qualquer provisionador (_provisioner "shell"*) especificado no bloco build na imagem base após iniciá-la. Para essa tarefa, você precisa considerar onde implantar a instância (os atributos subnet_ocid), para que o Packer possa fazer ssh na instância pela máquina que executa o Packer. Nos instantâneos finais do Packer, ele cria uma imagem personalizada reutilizável.

Provisionadores de pacotes

Provisionadores são componentes importantes do Packer que instalam e configuram o software em uma máquina em execução antes de essa máquina ser transformada em uma imagem estática. Eles executam o grande trabalho de fazer a imagem conter software útil.

Exemplos de provisionadores incluem:

Objetivos

Pré-requisitos

Tarefa 1: Criar o arquivo de configuração do Packer

O Packer suporta o formato HCL ou JSON. Na tarefa a seguir, é um formato HCL.

  1. Nomeie o arquivo como desejar, mas no final inclua .pkr.hcl .

    packer {
        required_plugins {
          oracle = {
            source = "github.com/hashicorp/oracle"
            version = ">= 1.0.3"
          }
        }
    }
    
    source "oracle-oci" "example" {
      availability_domain = "GqIF:EU-FRANKFURT-1-AD-2"
      #you may use an OCID or use a base_image_filter
      #base_image_ocid     = "ocid1.image.oc1.eu-frankfurt-1......"
      base_image_filter  {
        #display_name = "Oracle-Linux-7.9-2023.05.24-0"
        display_name_search =  "^Oracle-Linux-7.9*"
      }
      compartment_ocid    = "ocid1.compartment.oc1......"
      image_name          = "ExampleImage"
      shape               = "VM.Standard1.1"
      ssh_username        = "opc"
      #This is public subnet as I run packer from outside OCI VCN
      subnet_ocid         = "ocid1.subnet.oc1.eu-frankfurt-1....."
      #this attribute will be changed
      nic_attachment_type  = "VFIO"
      #this attribute will be changed
      image_launch_mode = "NATIVE"
      #you may skip the image creation if you are running tests
      #when you want to test set this as true
      skip_create_image = false
    }
    
    build {
      sources = ["source.oracle-oci.example"]
    }
    
  2. A subnet_ocid é a sub-rede na qual a instância é provisionada até que a imagem personalizada seja criada. Esta é uma sub-rede que pode ser acessada pelo host que está executando o Packer. Normalmente, você não gostaria de criar instâncias de desenvolvimento com um IP público, pois não há motivo para elas serem expostas à internet e isso só cria preocupações com segurança. Uma forma de evitar o uso de IP público é executar o Packer no OCI ou usar o serviço OCI Bastion. Você também pode usar FastConnect ou outra VPN para acessar a sub-rede do OCI localmente sem a necessidade de passar pela Internet.

Tarefa 2: Inicializar o Packer

  1. Executar inicialização do Packer.

    <path to packer bin> init <packer conf file>
    

    Exemplo:

    <path to packer bin> init oke.pkr.hcl
    

Tarefa 3: Criar a imagem

  1. Nesse ponto, você tem uma imagem personalizada que terá image_launch_mode = "NATIVE" e nic_attachment_type = "VFIO". Há outros atributos que você pode alterar. Todos são descritos no documento oficial.

  2. Você pode executar comandos personalizados ou script (há exemplos anexados).

    <path to packer bin> build oke.pkr.hcl
    
    oracle-oci.example: output will be in this color.
    
    ==> oracle-oci.example: Creating temporary ssh key for instance...
    ==> oracle-oci.example: Creating instance...
    ==> oracle-oci.example: Created instance (ocid1.instance.........).
    ==> oracle-oci.example: Waiting for instance to enter 'RUNNING' state...
    ==> oracle-oci.example: Instance 'RUNNING'.
    ==> oracle-oci.example: Instance has IP: 130.61.X.X
    ==> oracle-oci.example: Using SSH communicator to connect: 130.61.X.X
    ==> oracle-oci.example: Waiting for SSH to become available...
    ==> oracle-oci.example: Connected to SSH!
    ==> oracle-oci.example: Creating image from instance...
    ==> oracle-oci.example: Updating image schema...
    ==> oracle-oci.example: Created image (ocid1.image........).
    ==> oracle-oci.example: Terminating instance (ocid1.instance.....)...
    ==> oracle-oci.example: Terminated instance.
    Build 'oracle-oci.example' finished after 4 minutes 37 seconds.
    
    ==> Wait completed after 4 minutes 37 seconds
    
    ==> Builds finished. The artifacts of successful builds are:
    --> oracle-oci.example: An image was created: 'ExampleImage' (OCID: ocid1.image..........'
    

    Exemplo usando provisionador:

    • Este exemplo usa o provisionador (shell e arquivo).

    • Criaria 2 imagens (especificadas na origem).

      variable "VAREXAMPLE" {
        type = string
        default = "val Example"
      }
      
      variable "deploy_in_comp" {
        type = string
        default = "ocid1.compartment.oc1......."
      }
      
      variable "OCI_PROFILE" {
        type = string
        default = "DEFAULT"
      }
      
      locals {
        pkr_root    = "${path.cwd}"           #the directory from where Packer was started
        pkr_scripts = "${path.root}/scripts"  #the directory of the input HCL file or the input folder
        root        = path.root
      }
      
      source "oracle-oci" "img1" {
        access_cfg_file_account = var.OCI_PROFILE
        availability_domain = "GqIF:US-ASHBURN-AD-3"
        base_image_ocid     = "ocid1.image.oc1.iad....."
        compartment_ocid    = "ocid1.compartment.oc1......"
        image_name          = "img1"
        shape               = "VM.Standard.E4.Flex"
        #usage of shape config
        shape_config {
        ocpus               = "1"
        }
        ssh_username        = "opc"
        subnet_ocid         = "ocid1.subnet.oc1.iad....."
      }
      
      source "oracle-oci" "img2" {
        access_cfg_file_account = var.OCI_PROFILE
        availability_domain = "GqIF:US-ASHBURN-AD-3"
        base_image_ocid     = "ocid1.image.oc1.iad....."
        compartment_ocid    = "ocid1.compartment.oc1........."
        image_name          = "img2"
        shape               = "VM.Standard.E4.Flex"
        shape_config {
        ocpus               = "2"
        }
        ssh_username        = "opc"
        subnet_ocid         = "ocid1.subnet.oc1.iad........"
        image_compartment_ocid = var.deploy_in_comp
      }
      
      build {
        # here we secific both source above, img1 and img2
        sources = [
          "source.oracle-oci.img1",
          "source.oracle-oci.img2"
        ]
        provisioner "shell" {
          # this will run on all sources
          inline = [
            "echo to run on all sources ${var.VAREXAMPLE}"
          ]
        }
        provisioner "shell" {
          # This provisioner only runs for img1 source.
          only = ["oracle-oci.img1"]
          inline = [
            "echo To run in img1",
          ]
        }
        provisioner "shell" {
          # This provisioner  runs on all but img1 source.
          # Mnd that there is no "source" string but only the name of the source
          except = ["oracle-oci.img1"]
          inline = [
            "echo To run in all except img1",
          ]
        }
        provisioner "file" {
          only = ["oracle-oci.img2"]
          source = "${local.pkr_scripts}/test.txt"
          destination = "/tmp/test.txt"
        }
        # This will run local on the machine you run packer
        provisioner "shell-local" {
          inline = ["echo ${local.pkr_root} and ${local.pkr_scripts}"]
        }
        # This will run local on the machine you run packer
        provisioner "shell-local" {
          inline = ["echo VAR from file :${var.VAREXAMPLE}"]
        }
      }
      
      
    • Ele usa variáveis (como no Terraform).

      image_compartment_ocid = var.deploy_in_comp
      
    • o método de Autenticação é com o arquivo .oci/config (o padrão), mas usa um atributo para especificar qual perfil no arquivo usar.

      access_cfg_file_account = var.OCI_PROFILE
      
    • Nisso, usamos provisionador "shell", provisionador "file" e provisionador "shell-local".

    • O provisionador Shell Packer provisiona máquinas criadas pelo Packer usando scripts shell. O provisionamento de shell é a maneira mais fácil de instalar o software e configurá-lo em uma máquina.

    • Você pode executar o comando shell na máquina (use inline) ou executar o script e (use script).

    • Também usamos o provisionador de arquivo. O provisionador de Pacotes de arquivos faz upload de arquivos para máquinas criadas pelo Packer.

    • Você pode ver mais exemplo no arquivo hcl que pode baixar prov-example.pkr.hcl .

    Exemplo usando arquivos de variáveis e provisionadores Ansible:

    • Usamos:

      • arquivos variáveis.
      • um método de Autenticação diferente - usando variáveis.
    • Em vez de usar o shell para instalar pacotes, estamos usando ansible para executar playbooks armazenados em uma pasta separada.

    • Esse método se destina a situações mais complexas que podem ser tratadas melhor pelo Ansible.

    • Há dois provisionadores ansible:

      • ansible-local : Precisa de ansible instalado no host que o Packer criará (você pode usar o shell do provisionador para instalar o Ansible).
      • ansible: Ele executará o ansible do host que executa o Packer; portanto, não é necessário estar presente na instância criada.
    • há vários arquivos de configuração envolvidos para que você precise especificar o nome do diretório ao criar.

      packer build <directory name>
      
    • Aqui o arquivo de exemplo ansible-example.pkr.hcl. Abaixo está o ansible-example.pkr.hcl.

      # mind there is a variables.pkr.hcl file where
      # other vars are set
      # so when build use: packer build <directory name>
      # so all the files within dir will be loaded
      
      
      source "oracle-oci" "img1" {
      #auth vars
      region        = var.REGION
      tenancy_ocid  = var.TENANCY_OCID
      user_ocid     = var.USER_OCID
      key_file      = var.KEY_FILE
      fingerprint   = var.FINGERPRINT
      #
      availability_domain = var.AD
      base_image_ocid     = var.BASE_IMG_OCID
      compartment_ocid    = var.COMP_IMG_OCID
      image_name          = var.IMG_NAME
      shape               = var.SHAPE
      shape_config {
      ocpus               = var.SHAPE_OCPUS
      }
      ssh_username        = "opc"
      subnet_ocid         = var.SUBNET_OCID
      # for testing and debug. remove it after
      skip_create_image   = true
      }
      
      source "oracle-oci" "img2" {
      #auth vars
      region        = var.REGION
      tenancy_ocid  = var.TENANCY_OCID
      user_ocid     = var.USER_OCID
      key_file      = var.KEY_FILE
      fingerprint   = var.FINGERPRINT
      #
      availability_domain = var.AD
      base_image_ocid     = var.BASE_IMG_OCID
      compartment_ocid    = var.COMP_IMG_OCID
      image_name          = var.IMG_NAME1
      shape               = var.SHAPE
      shape_config {
      ocpus               = var.SHAPE_OCPUS
      }
      ssh_username        = "opc"
      subnet_ocid         = var.SUBNET_OCID
      # for testing and debug. remove it after
      skip_create_image   = true
      }
      
      build {
      sources = [
        "source.oracle-oci.img1",
        "source.oracle-oci.img2"
      ]
      
      #need ansible installed on VM that packer will build
      #so you need to install ansible beforehand
      
      provisioner "shell" {
        # this will run on all sources
        inline = [
          "sudo yum install ansible -y"
        ]
      }
      
      # this provisioner ansible-local needs ansible installed
      # on the host that packer will builds
      
      provisioner "ansible-local" {
        playbook_file   = "${path.root}/ansible/pb1.yaml"
      }
      
      # This provisioner ansible
      # will run ansible playbook from host that runs packer
      # so you don't need to inmstall ansible on VM that packer wil create
      
      #provisioner "ansible" {
      #  playbook_file   = "${path.root}/ansible/pb-remote.yaml"
      #  user = "opc"
      #  # in case you need to debug ansible tasks
      #  extra_arguments = [ "-vvvv" ]
      #}
      }
      
      
    • Aqui está o vars.pkr.hcl. Neste arquivo, declaramos e inicializamos.

      variable "AD" {
      type = string
      default = "GqIF:US-ASHBURN-AD-3"
      }
      
      variable "BASE_IMG_OCID" {
      type = string
      default = "ocid1.image.oc1.iad......"
      }
      
      variable "COMP_IMG_OCID" {
      type = string
      default = "ocid1.compartment.oc1......."
      }
      
      variable "IMG_NAME" {
      type = string
      default = "img1"
      }
      
      variable "IMG_NAME1" {
      type = string
      default = "img2"
      }
      
      variable "SHAPE" {
      type = string
      default = "VM.Standard.E3.Flex"
      }
      
      variable "SHAPE_OCPUS" {
      type = string
      default = "1"
      }
      
      variable "SUBNET_OCID" {
      type = string
      default = "ocid1.subnet.oc1.iad......"
      }
      
    • Aqui está o auth-vars.pkr.hcl, usamos este arquivo para configurar a autenticação.

      variable "REGION" {
        type = string
        default = "us-ashburn-1"
      }
      
      variable "TENANCY_OCID" {
        type = string
        default = "ocid1.tenancy.oc1......."
      }
      
      variable "USER_OCID" {
        type = string
        default = "ocid1.user.oc1......"
      }
      
      variable "KEY_FILE" {
        type = string
        default = ".....oci_api_key.pem"
      }
      
      variable "FINGERPRINT" {
        type = string
        default = "...."
      }
      

Confirmações

Autor - Francisc Vass (Arquiteto de Nuvem Principal)

Mais Recursos de Aprendizagem

Explore outros laboratórios no site docs.oracle.com/learn ou acesse mais conteúdo de aprendizado gratuito no canal YouTube do Oracle Learning. Além disso, visite education.oracle.com/learning-explorer para se tornar um Oracle Learning Explorer.

Para obter a documentação do produto, visite o Oracle Help Center.