Logo docker

En este apunte describo como instalar Alpine Linux en una máquina virtual en mi servidor QEMU/KVM y cómo instalar Docker en ella, para pruebas de concepto, laboratorios, etc. ¿Se puede instalar un Host Docker encima de una Máquina Virtual?. La respuesta es un sí rotundo, de hecho es un lugar excelente para hacerlo, sobre todo en entornos de laboratorio, caseros, pequeños despliegues.


Introducción

En mi laboratorio tengo un pequeño y a la vez potente servidor Meerkat de System76 para hospedar mis máquinas virtuales. Recientemente he decidido probar y desplegar algunos servicios a través de Docker. Por cierto, hacía mucho tiempo que no (jugaba con Docker).

Necesito poder ejecutar máquinas virtuales y contenedores Docker. Mi duda es si hacerlo en paralelo en mi servidor Ubuntu LTS. Decidí optar por un enfoque distinto: montar máquinas virtuales dedicadas a contenedores Docker. El motivo principal ha sido evitar follones con el networking (openvswitch + docker switches + iptables) y por otro aislar y contener problemas/troubleshooting. En mi servidor queda la cosa como sigue:

  • Hardware: Meerkat de System76
  • Software: Pop!_OS, Ubuntu Server LTS.
  • Networking: Open vSwtich
  • QEMU/KVM con Hypervisor
  • Varios Guest’s con máquinas virtuales corriendo Ubuntu Server LTS y servicios.
  • Varios Guest’s, con appliance como Umbrella o vWLC de Cisco.
  • Varios Guest’s con máquinas virtuales corriendo Alpine Linux con Docker y contenedores.


¿Donde ejecutar Docker?

Lo primero que necesitaba decidir es sobre qué SO iba a montar Docker, teniendo en cuenta que:

  • Voy a correr Docker dentro de una Máquina Virtual en mi Servidor QEMU/KVM.
  • El Sistema Operativo Guest solo va a tener Docker, no necesito una distribución enorme.
  • Busco algo pequeño, fácil de mantener y robusto

Entre las diferentes opciones que he visto por ahí he optado por Alpine Linux


Máquina virtual con Alpine Linux

  • Creo una VM llamada docker.parchis.org. Descargo Alpine Linux desde Downloads > VIRTUAL > Slimmed down kernel. Optimized for virtual systems, x86_64 (solo 52MB), es la versión más compacta posible.
    luis@sol:~/kvm/base$ wget https://dl-cdn.alpinelinux.org/alpine/v3.15/releases/x86_64/alpine-virt-3.15.3-x86_64.iso
    luis@sol:~/kvm/base$ wget https://dl-cdn.alpinelinux.org/alpine/v3.15/releases/x86_64/alpine-virt-3.15.3-x86_64.iso.sha256
    luis@sol:~/kvm/base$ sha256sum -c alpine-virt-3.15.3-x86_64.iso.sha256
    alpine-virt-3.15.3-x86_64.iso: La suma coincide
    
  • Creo un puerto estático en mi switch virtual (más info aquí: Open vSwitch y KVM).
    luis@sol:~$ sudo ovs-vsctl add-port solbr v100vnet13 tag=100 -- set Interface v100vnet13 type=internal
    
  • Creo una máquina virtual desde virt-manager con 1GB de RAM, 1 CPU, disco de 4GB y una NIC virtio, usando la imagen: alpine-virt-3.15.3-x86_64.iso, la llamo docker.parchis.org y en la configuración de red uso el interfaz que acabo de crear v100vnet13.
    luis@sol:~$ virt-manager
    
Creo VM desde virt-manager
  • Arranco la VM y entro en el setup de Alpine (más info en esta guía).
    luis@sol:~/kvm/gitea-traefik-docker$ virsh console docker.parchis.org
    localhost login: root
    Welcome to Alpine!
    :
    localhost:~#
    :
    # export SWAP_SIZE=0
    # setup-alpine
    Select keyboard layout: [none] es
    Select variant (or 'abort'): es
    Enter system hostname (fully qualified form, e.g. 'foo.example.org') [localhost] docker
    Available interfaces are: eth0.
    Which one do you want to initialize? (or '?' or 'done') [eth0]
    Ip address for eth0? (or 'dhcp', 'none', '?') [dhcp] 192.168.100.225/24
    Gateway? (or 'none') [none] 192.168.100.1
    Do you want to do any manual network configuration? (y/n) [n] n
    DNS domain name? (e.g 'bar.com') parchis.org
    DNS nameserver(s)? 192.168.100.224
    Changing password for root
    Which timezone are you in? ('?' for list) [UTC] Europe/Madrid
    HTTP/FTP proxy URL? (e.g. 'http://proxy:8080', or 'none') [none]
    Enter mirror number (1-71) or URL to add (or r/f/e/done) [1]
    Which SSH server? ('openssh', 'dropbear' or 'none') [openssh]
    Which disk(s) would you like to use? (or '?' for help or 'none') [none] vda
    How would you like to use it? ('sys', 'data', 'crypt', 'lvm' or '?' for help) [?] sys
    WARNING: Erase the above disk(s) and continue? (y/n) [n] y
    Installation is complete. Please reboot.
    docker:~# reboot
    
  • Hago login como root e instalo unas cuantas herramientas útiles.
    docker:~# apk add iproute2 nano sudo tzdata
    docker:~# cp /usr/share/zoneinfo/Europe/Madrid /etc/localtime
    docker:~# echo "Europe/Madrid" >  /etc/timezone
    docker:~# apk del tzdata
    
  • Creo mi usuario luis y configuro ssh
    docker:~# addgroup -g 1000 luis
    docker:~# adduser -h /home/luis -s /bin/ash -G luis --u 1000 luis
    docker:~# adduser luis wheel
    docker:~# su - luis
    docker:~$ 
    docker:~$ ssh-keygen -t rsa -b 2048 -C "luis@docker.parchis.org"
    :
    docker:~$ exit
    
  • Creo authorized_keys (apunte sobre SSH en linux)
  • Modifico SSH para que trabaje solo con clave pública/privada
    docker:~$ su -
    Password:
    docker:~# cat /etc/ssh/sshd_config
    # Config LuisPa
    Port 22
    PubkeyAuthentication yes
    PasswordAuthentication no
    AuthenticationMethods publickey
    AllowAgentForwarding yes
    AllowTcpForwarding yes
    GatewayPorts yes
    AddressFamily inet
    PrintMotd no
    Subsystem sftp /usr/lib64/misc/sftp-server
    AcceptEnv LANG LC_*
    docker:~# service sshd restart
    
  • Creo el fichero /etc/nanorc (fuente aquí) para el editor nano
  • Acelero el tiempo de boot a unos 5 segundos
    docker:~# cat /boot/extlinux.conf
    # Generated by update-extlinux 6.04_pre1-r9
    #DEFAULT menu.c32                        # Comento esta línea
    DEFAULT virt                             # Añadida, virt = nombre más abajo
    PROMPT 0
    MENU TITLE Alpine/Linux Boot Menu
    MENU HIDDEN
    MENU AUTOBOOT Alpine will be booted automatically in # seconds.
    TIMEOUT 30
    LABEL virt
    MENU LABEL Linux virt
    LINUX vmlinuz-virt
    INITRD initramfs-virt
    APPEND root=UUID=bff03f67-29ee-4525-96d9-3096a1799fc7 modules=sd-mod,usb-storage,ext4 quiet rootfstype=ext4
    MENU SEPARATOR
    


Instalación de Docker y Docker Compose

  • Habilito el Community repository
    git:~# cat /etc/apk/repositories
    #/media/cdrom/apks
    http://dl-cdn.alpinelinux.org/alpine/v3.15/main
    http://dl-cdn.alpinelinux.org/alpine/v3.15/community   <== Descomento esta línea
    
  • Actualizo el sistema e instalo herramientas muy útiles además de docker y docker-compose
    docker:~# apk update
    docker:~# apk upgrade --available
    docker:~# apk add bash-completion procps util-linux 
    docker:~# apk readline findutils sed coreutils sudo
    docker:~# apk add docker docker-bash-completion docker-compose docker-compose-bash-completion docker-cli-compose
    docker:~# rc-update add docker boot
    docker:~# service docker start
    
  • Añado mi usuario al grupo docker y hago un reboot…
    git:~# addgroup luis docker
    git:~# reboot -f
    
  • Pruebo Docker (con la última imagen de alpine, que ocupa poquísimo…)
    docker:~$ docker pull alpine:latest
    docker:~$ docker images
    REPOSITORY   TAG       IMAGE ID       CREATED      SIZE
    alpine       latest    76c8fb57b6fc   3 days ago   5.57MB
    docker:~$ docker create -t -i  --name myalpine alpine:latest
    5f1fefa539848f9e0fe995bf2e9c426def69ca48bfacc51bdb509197939c041e
    docker:~$ docker start myalpine
    docker:~$ docker exec -it myalpine /bin/ash
    docker:~$ docker stop myalpine
    docker:~$ docker rm myalpine
    myalpine
    
  • Que no te sorprenda que docker stop myalpinetarde un rato en pararse, aquí tienes la explicacion.