Mit diesem Post wollen wir 2 Schritte abarbeiten.
- Erstellen einer CentOs8 ESXi VM
- Export in eine OVA Vorlage
Das OpenSource Tool Packer kann dazu benutzt werden einen VMware ESXi Gast in einer unbeaufsichtigten Installation zu erzeugen. Das ganze heisst neumodern Infrastructure as code. Ist der Build erstmal gelungen hat man die Möglichkeit mit weiteren Export Schnittstellen wie in unserem Fall OVA und z. B. Vagrant Base Boxen zu arbeiten. Die Vielzahl der Export Schnittstellen ist sehr groß, so dass man vom AWS EC2 Image bis Azure / Docker etc… alles bauen kann was man heute für die Cloud benötigt.
Das ESXi System für Packer vorbereiten.
Wichtig hierbei ist, dass die Kommunikation vom Packer Host zum ESXi Server mit den Ports für ssh und vnc für unsere Workstation offen sein muss
Das folgende Skript welches auf dem ESXi Host ausgeführt werden muss bereitet den ESXi 6.7 Host für die Packer Kommunikation vor:
#!/bin/sh # local configuration options # Note: modify at your own risk! If you do/use anything in this # script that is not part of a stable API (relying on files to be in # specific places, specific tools, specific output, etc) there is a # possibility you will end up with a broken system after patching or # upgrading. Changes are not supported unless under direction of # VMware support. # configuration firewallConfigFile="/etc/vmware/firewall/service.xml" # enable guest ip hack esxcli system settings advanced set -o /Net/GuestIPHack -i 1 # change permissions on firewall config file chmod 644 "$firewallConfigFile" chmod +t "$firewallConfigFile" # remove config root end tag from firewall config file sed -i -e 's|</ConfigRoot>||g' "$firewallConfigFile" # add xml block for vnc ports to the end of the firewall config file cat <<EOT >> "$firewallConfigFile" <!– Ports opened for Packer VNC commands –> <service id="1000"> <id>packer-vnc</id> <rule id="0000"> <direction>inbound</direction> <protocol>tcp</protocol> <porttype>dst</porttype> <port> <begin>5900</begin> <end>6000</end> </port> </rule> <enabled>true</enabled> <required>true</required> </service> </ConfigRoot> EOT # restore permissions on firewall config file chmod 444 "$firewallConfigFile" # restart firewall service esxcli network firewall refresh exit 0 |
Packer installieren
Wir haben packer in einem Centos7 OS installiert.
sudo yum install -y yum-utils sudo yum-config-manager –add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo sudo yum -y install packer Collision mit einen binary namens packer Deswegen umbenamung von packer in packer_io mv /usr/bin/packer /usr/bin/packer_io packer wird nun stattdessen mit packer_io aufgerufen |
Ovftool installieren
Wir besorgen uns das Linux Paket VMware-ovftool-4.4.1-16812187-lin.x86_64.bundle von der VMware Seite.
scp VMware-ovftool-4.4.1-16812187-lin.x86_64.bundle /tmp chmod +x VMware-ovftool-4.4.1-16812187-lin.x86_64.bundle cd /tmp ./ VMware-ovftool-4.4.1-16812187-lin.x86_64.bundle |
Dieses Packer json file erstellt eine VM, und exportiert diese als OVA Vorlage.
Datei: centos8.json
{ "builders" : [ { "boot_command" : [ "<tab><bs><bs><bs><bs><bs>text ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks7.cfg<enter><wait>" ], "boot_wait" : "{{ user `boot_wait` }}", "disk_size" : "{{ user `disk_size` }}", "guest_os_type" : "centos7-64", "headless" : false, "http_directory" : "http", "iso_checksum" : "{{ user `iso_checksum` }}", "iso_url" : "{{ user `iso_url` }}", "network_name" : "Management", "shutdown_command" : "echo 'packer'|sudo -S /sbin/halt -h -p", "ssh_password" : "{{ user `ssh_password` }}", "ssh_port" : 22, "ssh_timeout" : "30m", "ssh_username" : "{{ user `ssh_username` }}", "type" : "vmware-iso", "vm_name" : "{{ user `vm_name` }}", "keep_registered" : true, "remote_datastore" : "{{user `esxi_datastore`}}", "remote_host" : "{{user `esxi_host`}}", "remote_password" : "{{user `esxi_password`}}", "remote_type" : "esx5", "remote_username" : "{{user `esxi_username`}}", "skip_export" : false, "vnc_disable_password" : true, "vmx_data" : { "format" : "vmx", "memsize" : "{{ user `memsize` }}", "numvcpus" : "{{ user `numvcpus` }}", "virtualHW.version" : "14" } } ], "variables" : { "boot_wait" : "5s", "disk_size" : "40960", "esxi_datastore" : "datastore3", "esxi_host" : "192.168.17.15", "esxi_password" : "MyPassword", "esxi_username" : "root", "iso_checksum" : "e33d7b1ea7a9e2f38c8f693215dd85254c3a4fe446f93f563279715b68d07987", "iso_url" : "iso/CentOS-7-x86_64-DVD-2009.iso", "memsize" : "1024", "numvcpus" : "1", "ssh_password" : "packer", "ssh_username" : "packer", "ip_addr" : "192.168.17.100", "vm_name" : "CentOS-7-x86_64" }, "provisioners" : [ { "type" : "file", "source" : "scripts/provision.sh", "destination" : "/tmp/provision.sh" }, { "type" : "shell", "inline" : [ "chmod u+x /tmp/provision.sh", "/tmp/provision.sh {{user `ip_addr`}}" ] } ] } |
Als erstes müssen wir einen ESXi-Host für unsere Builds festlegen. Der Grund, warum wir einen Host und kein vCenter benötigen, ist, dass Packer über SSH eine Verbindung zum Host herstellt und verschiedene vim-cmd-Befehle verwendet (vmware-iso Schnittstelle), um die Arbeit zu erledigen.
Hier müssen die folgenden Variablen im Skript oben angepasst werden:
Item |
Value |
"network_name" |
"Management" |
"esxi_datastore" |
"datastore3" |
"esxi_host" |
"192.168.17.15" |
"esxi_password" |
"MyPassword" |
"esxi_username" |
"root" |
|
|
Installation tree
Unser Installations-Verzeichnis sieht folgendermaßen aus:
templates/ ├── centos8.json ├── http │ └── ks.cfg ├── iso │ ├── CentOS-8.3.2011-x86_64-boot.isoo ├── output-vmware-iso │ ├── CentOS-8-x86_64-disk1.vmdk │ ├── CentOS-8-x86_64-file1.nvram │ ├── CentOS-8-x86_64.mf │ └── CentOS-8-x86_64.ovf ├── packer_centos8_build.sh ├── scripts │ ├── ipstatic.sh |
Es enthält under anderem unsere kickstart Datei in einem Verzeichniss in dem packer von sich aus einen http Server aufmacht, um es der CentOS Installation anzubieten.
Der Konfig Eintrag ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg macht den http Server auf.
Die kickstart Datei
Datei: ks.cfg
# https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/performing_an_advanced_rhel_installation/kickstart-commands-and-options-reference_installing-rhel-as-an-experienced-user # Set the authentication options for the system auth –passalgo=sha512 –useshadow # Install OS instead of upgrade install # License agreement eula –agreed # Use text mode install text # Disable Initial Setup on first boot firstboot –disable # Keyboard layout keyboard –vckeymap=de –xlayouts='de' # System language lang de_DE.UTF-8 # Network information network –bootproto=static –device=ens33 –gateway=192.168.17.1 –ip=192.168.17.100 –nameserver=192.168.17.1 –netmask=255.255.255.0 –noipv6 –activate network –hostname=centos7.localdomain # Root password rootpw $1$+xLTvuVv$vAMwt4RuJqO3qp9nLQj1U0 –iscrypted # SELinux configuration selinux –enforcing # Do not configure the X Window System skipx # System timezone timezone Europe/Paris –isUtc # Add a user named packer user –groups=wheel –name=packer –password=$6$Jaa5U0EwAPMMp3.5$m29yTwr0q9ZJVJGMXvOnm9q2z13ldUFTjB1sxPHvaiW4upMSwQ50181wl7SjHjh.BTH7FGHx37wrX..SM0Bqq. –iscrypted –gecos="packer" user –groups=wheel –name=vagrant –password=$6$dpIioZs4JBTf6l1n$6nySAWfwHTuo2TnszX6nAzrvGixLpgq/zvkLN5G4QULXIplUSR71BTHtFQNGkNEHYYLu6MZFBPfIhTY6fNRwp/ –iscrypted –gecos="vagrant" # System bootloader configuration bootloader –location=mbr –append="crashkernel=auto" # Clear the Master Boot Record zerombr # Remove partitions clearpart –all –initlabel # Automatically create partitions using LVM autopart –type=lvm # Reboot after successful installation reboot %packages –ignoremissing # dnf group info minimal-environment @^minimal-environment @development @guest-agents @headless-management @legacy-unix @rpm-development-tools @scientific @standard @system-tools kexec-tools # Exclude unnecessary firmwares -iwl*firmware %end %post –nochroot –logfile=/mnt/sysimage/root/ks-post.log # Disable quiet boot and splash screen sed –follow-symlinks -i "s/ rhgb quiet//" /mnt/sysimage/etc/default/grub sed –follow-symlinks -i "s/ rhgb quiet//" /mnt/sysimage/boot/grub2/grubenv # Passwordless sudo for the user 'packer' echo "packer ALL=(ALL) NOPASSWD: ALL" >> /mnt/sysimage/etc/sudoers.d/packer echo "vagrant ALL=(ALL) NOPASSWD: ALL" >> /mnt/sysimage/etc/sudoers.d/vagrant %end |
Die im ks.cfg File hinterlegten User mit Passwort sind somit:
packer | packer
root | packer
vagrant | vagrant
Das iscypted Password kann mit dem folgenden Aufruf erstellt werden:
python -c 'import crypt,getpass;pw=getpass.getpass();print(crypt.crypt(pw) if (pw==getpass.getpass("Confirm: ")) else exit())' |
Start des packer build Vorgangs per shellscript Aufruf
Wir befüllen und starten das folgende Shellscript: packer_centos8_build.sh
#!/bin/bash packer_io build -var "esxi_host=192.168.17.15" -var "esxi_datastore=datastore3" -var "esxi_username=root" -var "esxi_password=MyPassword" centos8.json |
Der Build Vorgang läuft nun wie folgt ab:
[root@pentaho templates]# ./packer_centos8_build.sh Warning: Warning when preparing build: "vmware-iso" Your vmx data contains the following variable(s), which Packer normally sets when it generates its own default vmx template. This may cause your build to fail or behave unpredictably: numvcpus, memsize, virtualHW.version vmware-iso: output will be in this color. ==> vmware-iso: Retrieving ISO ==> vmware-iso: Trying iso/CentOS-8.3.2011-x86_64-boot.iso ==> vmware-iso: Trying iso/CentOS-8.3.2011-x86_64-boot.iso?checksum=sha256%3A2b801bc5801816d0cf27fc74552cf058951c42c7b72b1fe313429b1070c3876c ==> vmware-iso: iso/CentOS-8.3.2011-x86_64-boot.iso?checksum=sha256%3A2b801bc5801816d0cf27fc74552cf058951c42c7b72b1fe313429b1070c3876c => /pentaho/apps/packer/templates/iso/CentOS-8.3.2011-x86_64-boot.iso ==> vmware-iso: Configuring output and export directories… ==> vmware-iso: Remote cache was verified skipping remote upload… ==> vmware-iso: Creating required virtual machine disks ==> vmware-iso: Building and writing VMX file ==> vmware-iso: Starting HTTP server on port 8787 ==> vmware-iso: Registering remote VM… ==> vmware-iso: Starting virtual machine… ==> vmware-iso: Connecting to VNC… ==> vmware-iso: Waiting 5s for boot… ==> vmware-iso: Typing the boot command over VNC… ==> vmware-iso: Waiting for SSH to become available… ==> vmware-iso: Connected to SSH! ==> vmware-iso: Gracefully halting virtual machine… vmware-iso: Waiting for VMware to clean up after itself… ==> vmware-iso: Deleting unnecessary VMware files… vmware-iso: Deleting: /vmfs/volumes/datastore3/CentOS-8-x86_64-2004/vmware.log ==> vmware-iso: Cleaning VMX prior to finishing up… vmware-iso: Detaching ISO from CD-ROM device ide0:0… vmware-iso: Disabling VNC server… ==> vmware-iso: Exporting virtual machine… vmware-iso: Executing: ovftool –noSSLVerify=true –skipManifestCheck -tt=ovf vi://root:%3Cpassword%3E@192.168.17.15/CentOS-8-x86_64-2004 output-vmware-iso/CentOS-8-x86_64-2004.ovf ==> vmware-iso: Keeping virtual machine registered with ESX host (keep_registered = true) Build 'vmware-iso' finished after 14 minutes 39 seconds. ==> Wait completed after 14 minutes 39 seconds ==> Builds finished. The artifacts of successful builds are: –> vmware-iso: VM files in directory: output-vmware-iso –> vmware-iso: 'vmware' provider box: CentOS-8-x86_64-2004.box |
Das Beispiel ließe sich noch mit den verschiedenen Provisioning Möglichkeiten ergänzen.
Vom Shellskript bis Ansible ist alles möglich was das Herz begeht, um zu einem Individuellen System zu kommen.
Hier nur ein Beispiel:
Die Variable ip_addr wird über die Datei centos7.json passend befüllt.
"provisioners" : [ { "type" : "file", "source" : "scripts/provision.sh", "destination" : "/tmp/provision.sh" }, { "type" : "shell", "inline" : [ "chmod u+x /tmp/provision.sh", "/tmp/provision.sh {{user `ip_addr`}}" ] } |
Das passende Skript dazu:
#!/bin/bash #– —————————————————————————– #– Script : provision.sh #– Task : we are setting the ip address from a packer variable #– Do : ./provision.sh 192.168.17.101 /24 192.168.17.1 #– Author : Stefan M. Dohn, 18.05.2021 #– 18.05.2021 SDohn Creation from scrap #– Last updates: #– —————————————————————————– #set -x # declare variables # Static settings ip_addr="$1" #we are get our ip address via $1 argument# ip_cidr="$2" #we are get our ip netmask via $2 argument# ip_gw="$3" #we are get our gateway via $3 argument# mgmt_ip='192.168.17.101' mgmt_cidr='/24' mgmt_gw='192.168.17.1' [ -z $ip_addr ] && echo "no ip given, we exit here…" && exit 0 [ -z $ip_cidr ] && ip_cidr=$mgmt_cidr [ -z $ip_gw ] && ip_gw=$mgmt_gw # Inline provisioning script INTERFACE=$(nmcli -t -f DEVICE device | grep e | head -n 1 |xargs) VVAL=$(nmcli con show | grep $INTERFACE | awk -F " " '{ print $1}') echo "Change IP for interfacename $VVAL" sudo /usr/bin/nmcli con mod "$VVAL" ipv4.addresses ${ip_addr}${ip_cidr} sudo /usr/bin/nmcli con mod "$VVAL" ipv4.gateway ${ip_gw} sudo /usr/bin/nmcli con mod "$VVAL" ipv4.method manual sudo /usr/bin/nmcli con mod "$VVAL" connection.autoconnect on exit 0 |