Antes de que la contenedorización facilitara tanto la preparación de imágenes para la virtualización, era todo un arte preparar imágenes ISO personalizadas para arrancar desde CD. Más tarde, estas imágenes se utilizaron para arrancar máquinas virtuales. En otras palabras, las imágenes ISO fueron precursoras de las imágenes de contenedor.
Es así que tuve un par de desafortunados encontronazos con el cliente Docker de Windows. Incluso cuando no estaba ejecutando ningún contenedor, el gestor de memoria de Windows le entregaba toda la memoria posible ralentizando cualquier cosa en la que estuviera ocupado. Por lo tanto, prohibí el cliente de Windows Docker de mi máquina.
Por favor, no me malinterpreten. No odio Docker – sólo su cliente Windows.
Este paso me obligó a retroceder en el tiempo. Empecé a ejecutar máquinas virtuales directamente sobre Hyper-V, el hipervisor de Windows. Formar clusters Kubernetes en Windows se convirtió entonces en un feliz pasatiempo para mí como se puede ver en mis anteriores posts publicados aquí en DZone.
Zapatero, ¿por qué vas descalzo?
Después de seguir durante muchas horas los mismos clics de ratón para crear máquinas virtuales en Hyper-V Manager, me di cuenta de que soy como un zapatero que va descalzo: Yo construyo una tubería DevOps por una tarifa por hora, pero ¿pierdo el tiempo en clics de ratón?
Reto aceptado. Hice un duckduckgo y leí que es posible crear máquinas virtuales usando PowerShell. No tardé ni una semana en tener un script que crea una nueva máquina virtual como se puede ver aquí. Un script hermano puede arrancar una máquina virtual que esté apagada.
Un viejo arte redescubierto
Esto era genial, pero me di cuenta de que seguía haciendo clicks con el ratón al instalar Ubuntu. Automatizar esto parecía un hueso más duro de roer. Uno tiene que desempaquetar una imagen ISO, manipularla de una forma u otra, y luego empaquetarla de nuevo teniendo cuidado de dejar intacto todo lo que instruye a un ordenador sobre cómo arrancar.
Afortunadamente, encontré una excelente guía sobre cómo hacer precisamente esto. El proceso consta de tres pasos:
- Descomprimir la imagen de arranque ISO de Ubuntu.
- Manipula el contenido:
- Mover el registro de arranque maestro (MBR) fuera.
- Especificar lo que los usuarios hacen normalmente en la GUI y personalizar lo que se instala y ejecuta durante la instalación. Esto se hace usando un subconjunto del lenguaje Cloud-init de Ubuntu. Ver aquí para las instrucciones que he creado.
- Instruye al gestor de arranque (Grub, en este caso) dónde encontrar las instrucciones de arranque personalizadas y que no espere a la entrada del usuario. Aquí está el Grub config me decidí por.
- Package todo usando una aplicación llamada Xorriso.
Para los magos de este antiguo oficio, Xorriso es su varita mágica. Tiene páginas de documentación en algo que se parece a un libro de hechizos. Tendré que ensuciarme las manos para entenderlo completamente, pero mi actual (y muy probablemente defectuosa) comprensión es que crea particiones de arranque, carga el MBR copiado, y hace algo con las instrucciones similares a Cloud-init para crear una imagen ISO modificada.
Ansible for the Finishing Touches
Aunque fue con gran satisfacción que logré arrancar Ubuntu22 desde PowerShell sin ninguna otra entrada de mi parte, ¿qué pasará la próxima vez que Ubuntu saque una nueva versión? El verdadero DevOps obliga a documentar el proceso no en ASCII, sino en algún script listo para ejecutarse cuando sea necesario. Ansible muestra su versatilidad en que me las arreglé para hacer precisamente esto en una tarde. El secreto está en indicarle a Ansible que se trata de una acción local. Es decir, no usar SSH para apuntar a una máquina para recibir instrucciones, sino que el controlador de Ansible sea también el alumno:
- hosts: localhost
connection: local
La jugada completa se da a continuación y proporciona otra visión de lo explicado anteriormente:
# stamp_images.yml
- hosts: localhost
connection: local
become: true
vars_prompt:
- name: "base_iso_location"
prompt: "Enter the path to the base image"
private: no
default: /tmp/ubuntu-22.04.4-live-server-amd64.iso
tasks:
- name: Install 7Zip
ansible.builtin.apt:
name: p7zip-full
state: present
- name: Install Xorriso
ansible.builtin.apt:
name: xorriso
state: present
- name: Unpack ISO
ansible.builtin.command:
cmd: "7z -y x {{ base_iso_location }} -o/tmp/source-files"
- name: Copy boot partitions
ansible.builtin.copy:
src: /tmp/source-files/[BOOT]/
dest: /tmp/BOOT
- name: Delete working boot partitions
ansible.builtin.file:
path: /tmp/source-files/[BOOT]
state: absent
- name: Copy files for Ubuntu Bare
ansible.builtin.copy:
src: bare/source-files/bare_ubuntu
dest: /tmp/source-files/
- name: Copy boot config for Ubuntu bare
ansible.builtin.copy:
src: bare/source-files/boot/grub/grub.cfg
dest: /tmp/source-files/boot/grub/grub.cfg
- name: Stamp bare image
ansible.builtin.command:
cmd: xorriso -as mkisofs -r -V 'Ubuntu 22.04 LTS AUTO (EFIBIOS)' -o ../ubuntu-22.04-wormhole-autoinstall-bare_V5_1.iso --grub2-mbr ../BOOT/1-Boot-NoEmul.img -partition_offset 16 --mbr-force-bootable -append_partition 2 28732ac11ff8d211ba4b00a0c93ec93b ../BOOT/2-Boot-NoEmul.img -appended_part_as_gpt -iso_mbr_part_type a2a0d0ebe5b9334487c068b6b72699c7 -c '/boot.catalog' -b '/boot/grub/i386-pc/eltorito.img' -no-emul-boot -boot-load-size 4 -boot-info-table --grub2-boot-info -eltorito-alt-boot -e '--interval:appended_partition_2:::' -no-emul-boot .
chdir: /tmp/source-files
- name: Copy files for Ubuntu Atomika
ansible.builtin.copy:
src: atomika/source-files/atomika_ubuntu
dest: /tmp/source-files/
- name: Copy boot config for Ubuntu Atomika
ansible.builtin.copy:
src: atomika/source-files/boot/grub/grub.cfg
dest: /tmp/source-files/boot/grub/grub.cfg
- name: Stamp Atomika image
ansible.builtin.command:
cmd: xorriso -as mkisofs -r -V 'Ubuntu 22.04 LTS AUTO (EFIBIOS)' -o ../ubuntu-22.04-wormhole-autoinstall-atomika_V5_1.iso --grub2-mbr ../BOOT/1-Boot-NoEmul.img -partition_offset 16 --mbr-force-bootable -append_partition 2 28732ac11ff8d211ba4b00a0c93ec93b ../BOOT/2-Boot-NoEmul.img -appended_part_as_gpt -iso_mbr_part_type a2a0d0ebe5b9334487c068b6b72699c7 -c '/boot.catalog' -b '/boot/grub/i386-pc/eltorito.img' -no-emul-boot -boot-load-size 4 -boot-info-table --grub2-boot-info -eltorito-alt-boot -e '--interval:appended_partition_2:::' -no-emul-boot .
chdir: /tmp/source-files
Nótese la magia del comando Xorriso utilizado aquí para preparar dos imágenes: una con soporte y otra sin soporte para Kubernetes.
La única advertencia es tener una máquina instalada con Ansible desde la que ejecutar esta play. La salida de la obra anterior se puede descargar desde aquí y preinstalar una versión muy reciente de Ansible.
Conclusión
Este post se volvió retro, pero es importante revisar dónde empezaron las cosas para comprender por qué las cosas son como son. Windows y los contenedores, además, no se mezclan tan bien y cualquier investigación sobre formas de mejorar los días de los desarrolladores debe ser bienvenida.
Me he referido a parte del código, pero el proyecto completo puede verse en GitHub.
Source:
https://dzone.com/articles/ansible-and-the-pre-container-arts