ノート:

Packerを使用したOracle Cloud Infrastructureカスタム・イメージの作成

イントロダクション

このチュートリアルでは、OCIベース・イメージ、またはOCIにすでに存在するコンピュート・イメージを取得し、顧客のニーズに応じて変更します。

たとえば、イメージの起動モードをネイティブから準仮想化に変更したり、仮想ネットワーク・インタフェース・カード(VNIC)アタッチメントを変更する必要がある場合があります。たとえば、OKEワーカー・ノードにはこれが必要です。同様に、追加のOSパッケージをインストールしたり、Packerprovisionerを使用してインスタンス・カーネル・パラメータを変更できます(Terraformなど)。

たとえば、PostgreSQLデータベースをインストールするイメージと、他の値を持つulimitパラメータが必要なとします。これらすべてを実行するには、イメージからコンピュートを起動し、必要なものをすべて変更し、プログラム、アプリケーション、必要なパッケージをインストールしてから、インスタンスを新しいカスタム・イメージとして保存します。

複数のカスタム・イメージを作成する必要があるとします。複数のアーキテクチャに対して、カスタム・イメージに追加されたプログラムやパッケージを追加/変更する必要があります。そのためには、HashiCorpPackerを使用できます。

パッカー

Packerは、HashiCorpのオープンソース・ツールで、ソース構成からマシン・イメージを作成するために使用されます。軽量で、すべての主要なオペレーティング・システムで実行され、高パフォーマンスです。ChefやPuppetなどの構成管理は置き換えられません。実際、イメージを構築する場合、PackerはChefやPuppetなどのツールを使用してソフトウェアをイメージにインストールできます。次のような機能があります。

パッカーを使用する利点

パッカー認証

次のオプションを使用して、パッカーを認証できます。

ノート: パッカー認証についてさらに学習しますが、.oci/configファイルまたはインスタンス・プリンシパルのいずれかを使用することをお薦めします。

Packerの動作

タスクでは、Packerはbase_image_ocidパラメータで指定されたイメージを取得し、必要な構成パラメータ(可用性*ドメイン、シェイプなど)でユーザーが指定した属性を持つコンピュート・インスタンスをデプロイします。

その後に、Packerは、起動後にベース・イメージのbuildブロックで指定したプロビジョナ(_provisioner "shell"*)を実行するために、インスタンスにSSHで試行します。このタスクでは、インスタンスのデプロイ場所(subnet_ocid属性)を考慮する必要があるため、Packerを実行するマシンからインスタンスにSSHを実行できます。末尾のPackerスナップショットでは、再利用可能なカスタム・イメージが作成されます。

パッカー・プロビジョナ

プロビジョニング・プロバイダは、稼働中のマシン内でソフトウェアをインストールおよび構成し、そのマシンを静的イメージに変換する重要なコンポーネントの1つです。イメージに有用なソフトウェアを含めるための主要な作業を実行します。

プロビジョナの例を次に示します。

目的

前提条件

タスク1: Packer構成ファイルの作成

PackerはHCLまたは JSON形式をサポートしています。次のタスクでは、HCL形式です。

  1. 必要に応じてファイル名を指定しますが、最後に .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は、カスタム・イメージが構築されるまでインスタンスがプロビジョニングされるサブネットです。これは、Packerを実行しているホストから到達できる必要があるサブネットです。通常、開発インスタンスがインターネットに公開される理由がないため、パブリックIPを使用して開発インスタンスを作成することは望ましくありません。作成すると、セキュリティ上の懸念が生じます。パブリックIPの使用を回避する1つの方法は、OCI内からPackerを実行するか、OCI Bastionサービスを使用することです。FastConnectまたはその他のVPNを使用して、インターネットを経由せずに、オンプレミスからOCIサブネットにアクセスすることもできます。

タスク2: Packerの初期化

  1. Packer initを実行します。

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

    次に例を示します:

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

タスク3: イメージの構築

  1. この時点で、image_launch_mode = "NATIVE"およびnic_attachment_type = "VFIO"を持つカスタム・イメージがあります。変更できるその他の属性があります。これらはすべて公式文書に記載されています。

  2. カスタム・コマンドまたはスクリプトを実行できます(例が添付されています)。

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

    プロビジョナを使用する例:

    • この例では、provisioner (シェルとファイル)を使用します。

    • 2つのイメージが作成されます(ソースで指定)。

      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}"]
        }
      }
      
      
    • 変数を使用します(Terraformなど)。

      image_compartment_ocid = var.deploy_in_comp
      
    • Authメソッドは.oci/configファイル(デフォルト)ですが、属性を使用して、使用するファイル内でwichプロファイルを指定します。

      access_cfg_file_account = var.OCI_PROFILE
      
    • ここでは、provisioner "shell"provisioner "file"provisioner "shell-local"を使用します。

    • shell Packer Provisionerは、シェル・スクリプトを使用してPackerによって構築されるマシンをプロビジョニングします。シェル・プロビジョニングは、マシンにソフトウェアをインストールして構成する最も簡単な方法です。

    • マシン上でシェルコマンドを実行(inlineを使用)するか、またはeスクリプトを実行(scriptを使用)できます。

    • fileプロセッサも使用しました。ファイルPackerプロビジョナは、Packerによって作成されたマシンにファイルをアップロードします。

    • hclファイルに、prov-example.pkr.hclをダウンロードできるその他の例が表示されることがあります。

    変数ファイルおよびAnsibleプロビジョナを使用する例:

    • 次を使用します。

      • 変数ファイル。
      • 別のAuthメソッド- 変数を使用します。
    • パッケージのインストールにシェルを使用する代わりに、別のフォルダに保存されているプレイブックを実行するためにansibleを使用します。

    • この方法は、Ansibleでより適切に処理できる、より複雑な状況を対象としています。

    • 次の2つの実行可能なプロビジョナがあります。

      • ansible-local : Packerが構築するホストにansibleをインストールする必要があります(プロビジョナシェルを使用して Ansibleをインストールできます)。
      • ansible: Packerを実行するホストから実行できるため、ビルドするインスタンスに存在する必要はありません。
    • 複数の構成ファイルが含まれているため、構築時にディレクトリ名を指定する必要があります。

      packer build <directory name>
      
    • この例のファイル ansible-example.pkr.hcl。次に、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" ]
      #}
      }
      
      
    • vars.pkr.hclを次に示します。このファイルでは、それらを宣言および初期化します。

      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......"
      }
      
    • 次にauth-vars.pkr.hclを示します。このファイルを使用して認証を設定します。

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

承認

作成者 - Francisc Vass(プリンシパル・クラウド・アーキテクト)

その他の学習リソース

docs.oracle.com/learnで他のラボをご覧いただくか、Oracle Learning YouTubeチャネルでより無料のラーニング・コンテンツにアクセスしてください。また、education.oracle.com/learning-explorerにアクセスして、Oracle Learning Explorerになります。

製品ドキュメントについては、Oracle Help Centerを参照してください。