Remarques :

Utiliser Packer pour créer des images personnalisées Oracle Cloud Infrastructure

Introduction

Ce tutoriel traite de la prise d'une image de base OCI, ou de toute image de calcul existante dans OCI, et de sa modification en fonction des besoins du client.

Par exemple, vous devrez peut-être changer le mode de lancement de l'image d'origine à paravirtualisation ou modifier l'attachement de carte d'interface réseau virtuelle (VNIC). Par exemple, les noeuds de processus actif OKE en ont besoin. Vous pouvez également installer des packages de système d'exploitation supplémentaires ou modifier les paramètres du noyau de l'instance à l'aide du provisionneur Packer (comme dans Terraform).

Supposons que vous ayez besoin d'une image sur laquelle vous souhaitez installer la base de données PostgreSQL et que certains paramètres ulimit aient d'autres valeurs. Pour ce faire, lancez un calcul à partir d'une image, puis modifiez ce dont vous avez besoin, installez les programmes, l'application, les packages dont vous avez besoin, puis enregistrez l'instance en tant que nouvelle image personnalisée.

Imaginez maintenant que vous devez créer plusieurs images personnalisées pour plusieurs architectures et au fil du temps, vous devez ajouter/modifier les programmes ou packages ajoutés à votre image personnalisée. Pour cela, nous pouvons utiliser Packer à partir de HashiCorp.

Emballeur

Packer est l'outil open source de HashiCorp utilisé pour créer des images de machine à partir de la configuration source. Il est léger, s'exécute sur chaque système d'exploitation majeur, hautement performant. Il ne remplace pas la gestion de configuration comme Chef ou Puppet. En fait, lorsque vous créez des images, Packer peut utiliser des outils comme Chef ou Puppet pour installer des logiciels sur l'image. Certaines fonctionnalités sont les suivantes :

Avantages de l'utilisation de Packer

Authentification du packer

Vous pouvez authentifier Packer à l'aide des options suivantes.

Remarque : en savoir plus sur l'authentification de package, mais il est préférable d'utiliser le fichier .oci/config ou le principal d'instance.

Fonctionnement de Packer

Dans les tâches, Packer prend une image spécifiée dans le paramètre base_image_ocid et déploie une instance de calcul avec les attributs que vous avez spécifiés dans les paramètres de configuration requis (par exemple, availability*domain, shape, etc.).

Après ce Packer tentera d'exécuter ssh dans l'instance pour exécuter tout programme de provisionnement (_provisionner "shell"*) que vous avez indiqué dans le bloc build sur l'image de base après son lancement. Pour cette tâche, vous devez tenir compte de l'endroit où vous déployez l'instance (les attributs subnet_ocid), afin que Packer puisse ssh dans l'instance à partir de l'ordinateur qui exécute Packer. A la fin des instantanés Packer, il crée une image personnalisée réutilisable.

Provisionnement d'emballages

Les provisionneurs sont des composants importants de Packer qui installent et configurent des logiciels au sein d'une machine en cours d'exécution avant que cette machine ne devienne une image statique. Ils effectuent le travail majeur de faire en sorte que l'image contienne un logiciel utile.

Voici des exemples de programme de provisionnement :

Objectifs

Prérequis

Tâche 1 : création du fichier de configuration Packer

Packer prend en charge le format HCL ou JSON. Dans la tâche suivante, il s'agit d'un format HCL.

  1. Nommez le fichier comme vous le souhaitez, mais à la fin incluez .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. subnet_ocid est le sous-réseau dans lequel l'instance est provisionnée jusqu'à la création de l'image personnalisée. Il s'agit d'un sous-réseau qui doit être accessible à partir de l'hôte exécutant Packer. Normalement, vous ne voulez pas créer d'instances de développement avec une adresse IP publique, car il n'y a aucune raison qu'elles soient exposées à Internet et que cela crée simplement des problèmes de sécurité. Pour éviter d'utiliser l'adresse IP publique, vous pouvez exécuter Packer à partir d'OCI ou utiliser le service OCI Bastion. Vous pouvez également utiliser FastConnect ou un autre VPN pour accéder au sous-réseau OCI sur site sans avoir à passer par Internet.

Tâche 2 : initialiser Packer

  1. Exécuter l'initialisation du packer.

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

    Exemple :

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

Tâche 3 : créer l'image

  1. A ce stade, vous disposez d'une image personnalisée qui contiendra image_launch_mode = "NATIVE" et nic_attachment_type = "VFIO". Il existe d'autres attributs que vous pouvez modifier. Tous sont décrits dans le document officiel.

  2. Vous pouvez exécuter des commandes ou des scripts personnalisés (des exemples sont joints).

    <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..........'
    

    Exemple d'utilisation de l'approvisionnement :

    • Cet exemple utilise provisioner (shell et fichier).

    • Il créerait 2 images (spécifiées dans la source).

      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}"]
        }
      }
      
      
    • Il utilise des variables (comme dans Terraform).

      image_compartment_ocid = var.deploy_in_comp
      
    • la méthode d'authentification est avec le fichier .oci/config (valeur par défaut), mais elle utilise un attribut pour spécifier le profil à utiliser dans le fichier.

      access_cfg_file_account = var.OCI_PROFILE
      
    • Dans ce cas, nous utilisons provisionneur "shell" et provisionneur"file" et provisionneur"shell-local".

    • Le provisionneur Shell Packer provisionne les machines créées par Packer à l'aide de scripts shell. Le provisionnement de shell est le moyen le plus simple d'installer et de configurer des logiciels sur une machine.

    • Vous pouvez exécuter la commande shell sur la machine (utiliser inline) ou exécuter le script e (utiliser script).

    • Nous avons également utilisé le programme de provisionnement file. Le programme de provisionnement File Packer télécharge des fichiers vers les machines créées par Packer.

    • Vous pouvez voir plus d'exemples dans le fichier hcl que vous pouvez télécharger prov-example.pkr.hcl.

    Exemple d'utilisation de fichiers variables et de provisionneurs Ansible :

    • Nous utilisons :

      • Fichiers de variables.
      • méthode d'authentification différente : utilisation de variables.
    • Au lieu d'utiliser shell pour installer des packages, nous utilisons ansible pour exécuter des livres de jeux stockés dans un dossier séparé.

    • Cette méthode est destinée à une situation plus complexe qui peut être mieux gérée par Ansible.

    • Le provisionnement est deux ans :

      • ansible-local : doit être installé sur l'hôte que Packer va construire (vous pouvez utiliser le shell de provisionnement pour installer Ansible).
      • ansible : il s'exécutera à partir de l'hôte qui exécute Packer. Il n'est donc pas nécessaire d'être présent sur l'instance que vous créez.
    • plusieurs fichiers de configuration sont impliqués. Vous devez donc indiquer le nom du répertoire lors de la création.

      packer build <directory name>
      
    • Ici, le fichier exemple ansible-example.pkr.hcl. Voici l'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" ]
      #}
      }
      
      
    • Voici le fichier vars.pkr.hcl. Dans ce fichier, nous les déclarons et les initialisons.

      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......"
      }
      
    • Voici l'authentification-vars.pkr.hcl, nous utilisons ce fichier pour configurer l'authentification.

      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 = "...."
      }
      

Remerciements

Auteur - Francisc Vass (architecte cloud principal)

Ressources de formation supplémentaires

Explorez d'autres ateliers sur docs.oracle.com/learn ou accédez à davantage de contenu de formation gratuit sur le canal Oracle Learning YouTube. En outre, accédez à education.oracle.com/learning-explorer pour devenir un explorateur Oracle Learning.

Pour consulter la documentation produit, consultez Oracle Help Center.