Capítulo 18. Contenedores OCI

This translation may be out of date. To help with the translations please access the FreeBSD translations instance.

18.1. Sinopsis

La Open Container Initiative, comúnmente denominada OCI, proporciona una forma independiente del proveedor y del sistema operativo de describir, distribuir y ejecutar contenedores. Las especificaciones de OCI proporcionan estas capacidades de forma que se pueden usar en muchos sistemas operativos diferentes, incluido FreeBSD. La tecnología de virtualización subyacente sigue siendo las jails de FreeBSD, con el mismo conjunto de funcionalidades, pero las herramientas OCI habilitan formas adicionales de trabajar y de construir cargas de trabajo basadas en contenedores. 14.3-RELEASE y posteriores, incluidas las instantáneas, ahora incluyen imágenes compatibles con OCI, y el conjunto de herramientas Podman en FreeBSD está listo para usarlas, tanto en las arquitecturas amd64 como arm64.

Para los usuarios de FreeBSD familiarizados con las jails, existe una analogía aproximada:

  • El tarball base.txz de FreeBSD es un ejemplo de imagen de contenedor.

  • el fichero jail.conf describe las propiedades deseadas del contenedor, o Containerfile.

  • usar la orden jail .. para ejecutar un contenedor, dada una ruta de sistema de ficheros, con el conjunto de herramientas podman.

Al importar esta pila de contenedores, los usuarios de FreeBSD no solo se benefician de herramientas comunes, sino que también disponen de amplia compatibilidad con registros de contenedores públicos y privados, así como con herramientas y servicios específicos para contenedores. En los directorios de descarga aarch64 y amd64, se pueden ver imágenes oficiales en formato OCI. La nomenclatura puede resultar algo confusa al principio, pero debería tener sentido una vez que se empiecen a usar.

Las mismas imágenes también están disponibles a través de registros públicos de contenedores habituales, incluidos Docker Hub y Github Container Registry, pero para lograr la cadena de confianza más sólida, se debería obtener la imagen directamente de Releases oficiales de FreeBSD e importarla al sistema local.

Cada imagen consta de un subconjunto de un tarball de release estándar base.txz de FreeBSD, para diversos casos de uso, y de los ficheros habituales CHECKSUM.* de FreeBSD, que se pueden verificar frente al anuncio de release firmado con PGP. Esto proporciona una cadena de procedencia muy sólida, verificable directamente por el equipo de releases de FreeBSD.

CHECKSUM.SHA256
CHECKSUM.SHA512
FreeBSD-15.1-RELEASE-amd64-container-image-static.txz
FreeBSD-15.1-RELEASE-amd64-container-image-dynamic.txz
FreeBSD-15.1-RELEASE-amd64-container-image-runtime.txz
FreeBSD-15.1-RELEASE-amd64-container-image-notoolchain.txz
FreeBSD-15.1-RELEASE-amd64-container-image-toolchain.txz

18.2. Nomenclatura y etiquetado de las imágenes de contenedor

18.2.1. Introducción

Las imágenes oficiales de contenedor de FreeBSD se construyen a partir de paquetes del sistema base, que a su vez se compilan durante el proceso de release de FreeBSD y se publican en registros públicos. Esta guía explica cómo se nombran y etiquetan las imágenes, ayudando a elegir la imagen adecuada para cada necesidad y a comprender las implicaciones de cada elección a medida que se publican nuevas imágenes y, en algunos casos, se modifican etiquetas mutables. Esta convención de nomenclatura se alinea con el nuevo esquema de nombres de paquetes del sistema base, proporcionando una procedencia clara entre las imágenes de contenedor y las releases de FreeBSD correspondientes.

18.2.2. Tipos de imágenes disponibles

Hay disponibles cinco tipos de imágenes de contenedor de FreeBSD, para las arquitecturas amd64 y aarch64.

18.2.2.1. freebsd-static

La imagen estática se concibe como una imagen base para una carga de trabajo que esté completamente enlazada de forma estática. No contiene bibliotecas ni binarios, solo los ficheros de apoyo que requieren la mayoría de las aplicaciones de esta naturaleza.

  • certificados TLS públicos

  • fichero de contraseñas mínimo

  • termcap mínimo

  • base de datos de zonas horarias

Téngase en cuenta que, por diseño, ocupa poco espacio, para que comprometer la seguridad del contenedor resulte menos útil a un atacante. No hay shell UNIX, herramientas de línea de órdenes, bibliotecas dinámicas ni gestor de paquetes. Es la imagen más pequeña proporcionada por el proyecto FreeBSD.

18.2.2.2. freebsd-dynamic

La imagen dinámica usa la imagen estática como capa padre y permite usar bibliotecas compartidas, incluida libc. La mayor parte del software de FreeBSD debería ejecutarse sin problemas con esta imagen, con cambios menores. No tiene shell, sistema rc ni gestor de paquetes. Estas limitaciones proporcionan seguridad adicional, dificultando a los atacantes de un contenedor comprometido desplazarse lateralmente o usar herramientas que nunca se instalaron.

18.2.2.3. freebsd-runtime

De nuevo, runtime se basa en la capa dinámica anterior y finalmente añade el mínimo que esperaría un usuario: una shell UNIX, un sistema rc y el gestor de paquetes. Es la imagen base ideal para portar aplicaciones existentes con un mínimo de cambios. Los usuarios tendrán que incluir bibliotecas adicionales del sistema base de FreeBSD, así como paquetes adicionales del árbol de ports. Es lo más parecido a un sistema FreeBSD típico e incluye la herramienta pkg(8), lo que permite a los usuarios instalar o hacer casi cualquier cosa, de manera similar a un sistema no contenedorizado.

18.2.2.4. freebsd-notoolchain

Esta imagen base contiene casi todas las herramientas que se esperarían en un sistema FreeBSD típico, excepto las relacionadas directamente con el hardware, que por lo general no son útiles dentro de un contenedor, y el compilador y la cadena de herramientas relacionados, ya que ocupan bastante espacio.

18.2.2.5. freebsd-toolchain

La imagen base Toolchain es la suma de todas las imágenes anteriores e incluye un compilador y una cadena de herramientas completos. Por lo general, es posible compilar casi cualquier software para FreeBSD del mismo modo que en un sistema FreeBSD normal que no sea una jail. Todas las imágenes siguen un patrón de nomenclatura coherente, derivado de la release de FreeBSD en la que se basan.

18.2.3. Estructura de las etiquetas de imagen

18.2.3.1. Etiquetas inmutables

Las etiquetas inmutables nunca cambian y son ideales para sistemas de producción en los que se necesita estabilidad y previsibilidad. Son las etiquetas más habituales utilizadas por el proceso de release. No cambiarán, ni siquiera tras parches de seguridad o avisos de erratas de FreeBSD. Son ideales como imágenes base para despliegues de software donde se espera un alto grado de reproducibilidad, incluso a cambio de aplicar parches de seguridad de manera menos proactiva.

  • major.minor (p. ej., 14.4): apunta a una versión RELEASE específica de FreeBSD

  • major.minor.pX (p. ej., 14.4p1): apunta a un nivel de parche específico de una RELEASE

  • major.snapYYYYMMDDHHMMSS (p. ej., 16.snap20260325035941): una compilación de instantánea con marca de tiempo

18.2.3.2. Etiquetas mutables

Las etiquetas mutables se actualizan con el tiempo y son ideales para sistemas de producción o CI/CD que siempre quieren las actualizaciones más recientes, pero que aún desean mantener la compatibilidad ABI de FreeBSD.

  • major (p. ej., 15) será siempre la versión RELEASE compatible más reciente dentro de la ABI estable 15.x

  • major.snap (p. ej., 15.snap) sigue la instantánea de desarrollo más reciente dentro de la rama ABI estable 15.x, a menudo estará por delante de las releases oficiales y conlleva riesgo de fallos, incompatibilidades u otros problemas imprevistos. Esta es la etiqueta más mutable y debe usarse con precaución. Son exactamente iguales que usar las instantáneas STABLE o CURRENT de FreeBSD, ya que usan esas imágenes como origen.

18.2.4. Cuándo usar cada tipo de etiqueta

18.2.4.1. Para producción

Use etiquetas inmutables para garantizar que el entorno se mantenga coherente:

  • freebsd-runtime:15.0 - fijada a FreeBSD 15.0-RELEASE

Cuando se publiquen parches de seguridad, se debe reconstruir o actualizar explícitamente con una nueva etiqueta de imagen.

18.2.4.2. Para integración continua y desarrollo

Use etiquetas mutables para obtener automáticamente las actualizaciones más recientes:

  • freebsd-runtime:15 - siempre la RELEASE oficial más reciente de la serie 15.x

Estas etiquetas mutables adicionales seguirán las instantáneas publicadas periódicamente de FreeBSD STABLE y CURRENT. Úselas si desea realizar pruebas con lo que puedan contener las futuras releases posteriores de FreeBSD y acepta fallos ocasionales o cambios imprevistos.

  • freebsd-runtime:14.snap - siempre la compilación más reciente de la rama 14-STABLE

  • freebsd-runtime:15.snap - siempre la compilación más reciente de la rama 15-STABLE

  • freebsd-runtime:16.snap - siempre la compilación más reciente de la rama 16-CURRENT

18.3. Ubicaciones de los registros oficiales

Las imágenes independientes de la arquitectura se pueden descargar e importar directamente en un registro propio desde el sitio Releases oficiales de FreeBSD o, como alternativa, extraerlas del Docker Hub del proyecto FreeBSD o de GitHub Container Registry.

Tanto Alpine Linux como el proyecto Debian publican imágenes etiquetadas y mutables mediante enfoques similares.

18.4. Introducción a Podman

El conjunto de herramientas Podman consta de tres herramientas principales y varias de apoyo:

  • podman es un motor de contenedores sin daemon que usa órdenes compatibles con docker

  • buildah genera imágenes de contenedor en formato OCI

  • skopeo funciona con registros remotos de imágenes OCI

18.5. Preparación del sistema para los contenedores Podman

Si se ejecutan órdenes mediante SSH, o en una sesión remota similar, use screen(1), tmux(1) o una herramienta similar para evitar perder la conexión mientras se reinicia el firewall.

Si ZFS no está disponible, cambie al almacenamiento UFS y omita las órdenes de ZFS siguientes:

# sed -I .bak -e 's/driver = "zfs"/driver = "vfs"/' \
    /usr/local/etc/containers/storage.conf

En caso contrario, cree el dataset de almacenamiento de contenedores:

# zfs create -o mountpoint=/var/db/containers zroot/containers
# zfs snapshot zroot/containers@empty

Se requiere el sistema de ficheros de descriptores de fichero:

# mount -t fdescfs fdesc /dev/fd

Esto se debería añadir a /etc/fstab para que persista tras los reinicios:

fdescfs  /dev/fd  fdescfs  rw  0  0

18.6. Instalación de Podman

Solo se requiere el metapaquete sysutils/podman-suite, pero si se instala el paquete adicional emulators/qemu-user-static, será posible compilar o probar imágenes para otras arquitecturas, como arm64, en un host amd64.

# pkg install -r FreeBSD -y podman-suite emulators/qemu-user-static

18.7. Configuración de la red

La red de contenedores usa la traducción de direcciones de red (NAT) para permitir que las jails VNET accedan a la red del host. Esto se realiza mediante pf(4), por lo que se debe cargar el módulo del kernel del filtro de paquetes.

Integre los cambios de /usr/local/etc/containers/pf.conf.sample en /etc/pf.conf y configure las macros de interfaz de salida para que coincidan con la interfaz de red predeterminada.

# Change these to your interface(s) with the default route
v4egress_if = "vtnet0"
v6egress_if = "vtnet0"

nat on $v4egress_if inet from <cni-nat> to any -> ($v4egress_if)
nat on $v6egress_if inet6 from <cni-nat> to !ff00::/8 -> ($v6egress_if)

rdr-anchor "cni-rdr/*"
nat-anchor "cni-rdr/*"
table <cni-nat>

Las líneas rdr-anchor y nat-anchor "cni-rdr/*" implementan redirecciones de puertos como anclas anidadas bajo cni-rdr. En particular, la línea nat-anchor "cni-rdr/*" es necesaria para redirigir conexiones desde el host de contenedores a servicios que se ejecutan dentro de un contenedor, incluso cuando el destino es localhost (127.0.0.1 o ::1).

Habilite e inicie el firewall:

# service pf enable
# service pf start

La redirección de conexiones desde el propio host de contenedores a servicios que se ejecutan dentro de un contenedor también requiere habilitar la compatibilidad con redirecciones locales:

# sysctl net.pf.filter_local=1

Modifique /etc/sysctl.conf para hacer permanente este cambio:

net.pf.filter_local=1

18.8. Ficheros de configuración adicionales

Los paquetes instalan varios ficheros de configuración de plantilla, ninguno de los cuales es necesario editar de inmediato. Revise y modifique estos según sea necesario:

# pkg list | grep /etc/containers/
/usr/local/etc/containers/containers.conf.sample
/usr/local/etc/containers/policy.json.sample
/usr/local/etc/containers/registries.conf.sample
/usr/local/etc/containers/storage.conf.sample
/usr/local/etc/containers/pf.conf.sample

18.9. Ejecución del primer contenedor

Las distintas opciones se describen en podman-run(1). Esta invocación crea un contenedor nuevo, conecta un terminal interactivo y eliminará el contenedor al salir:

# podman run -it --rm ghcr.io/freebsd/freebsd-notoolchain:{rel-latest}
# top -b
last pid: 24414;  load averages:    0.47,    0.51,    0.53; battery: 23%  up 0+18:48:46    23:30:12
2 processes:   1 running, 1 sleeping
CPU:  6.9% user,  0.0% nice,  2.2% system,  0.7% interrupt, 90.2% idle
Mem: 2619M Active, 6587M Inact, 1813M Laundry, 4552M Wired, 56K Buf, 334M Free
ARC: 2526M Total, 802M MFU, 1219M MRU, 3586K Anon, 29M Header, 467M Other
     1625M Compressed, 4234M Uncompressed, 2.61:1 Ratio
Swap: 10G Total, 219M Used, 10G Free, 2% Inuse

  PID USERNAME    THR PRI NICE   SIZE    RES STATE    C   TIME    WCPU COMMAND
17963 root          1   1    0    14M  3120K wait     1   0:00   0.44% sh
24414 root          1   3    0    15M  2992K CPU0     0   0:00   0.00% top
# exit

18.10. Importación y ejecución de contenedores

Actualmente, todos los contenedores Podman en FreeBSD deben ejecutarse como root, ya que las jails de FreeBSD lo requieren.

Con las herramientas y reglas de firewall necesarias en su lugar, las imágenes publicadas oficialmente se pueden obtener de Releases de FreeBSD, para aarch64 o amd64, según corresponda.

18.10.1. Importación de imágenes OCI de FreeBSD

Como se indicó anteriormente, aunque resulta más cómodo extraer las imágenes directamente de un registro público de contenedores, para lograr la cadena de confianza más sólida, descárguelas directamente de FreeBSD.org y verifique las sumas de comprobación frente al anuncio de release firmado con PGP.

# export OCIBASE=https://download.freebsd.org/releases/OCI-IMAGES/15.1-RELEASE/amd64/Latest
# podman load -i=$OCIBASE/FreeBSD-15.1-RELEASE-amd64-container-image-static.txz
Getting image source signatures
Copying blob 44defc6cee2e done   |
Copying config 5921c62e76 done   |
Writing manifest to image destination
Loaded image: localhost/freebsd-static:15.1-RELEASE-amd64

# podman load -i=$OCIBASE/FreeBSD-15.1-RELEASE-amd64-container-image-dynamic.txz
Getting image source signatures
Copying blob 6054dffc3887 done   |
Copying config 33427d59f9 done   |
Writing manifest to image destination
Loaded image: localhost/freebsd-dynamic:15.1-RELEASE-amd64

# podman load -i=$OCIBASE/FreeBSD-15.1-RELEASE-amd64-container-image-runtime.txz
Getting image source signatures
Copying blob dcbbfcb598fe done   |
Copying config 90c4936754 done   |
Writing manifest to image destination
Loaded image: localhost/freebsd-runtime:15.1-RELEASE-amd64

# podman load -i=$OCIBASE/FreeBSD-15.1-RELEASE-amd64-container-image-notoolchain.txz
Getting image source signatures
Copying blob a16c94176cc3 done   |
Copying config 086572f35c done   |
Writing manifest to image destination
Loaded image: localhost/freebsd-notoolchain:15.1-RELEASE-amd64

# podman load -i=$OCIBASE/FreeBSD-15.1-RELEASE-amd64-container-image-toolchain.txz
Getting image source signatures
Copying blob b04531b7d93d done   |
Copying config b927c11b2e done   |
Writing manifest to image destination
Loaded image: localhost/freebsd-toolchain:15.1-RELEASE-amd64

18.10.2. Listado de imágenes

# podman images
REPOSITORY                    TAG                   IMAGE ID      CREATED       SIZE
localhost/freebsd-toolchain   15.1-RELEASE-amd64  b927c11b2e8d  13 days ago   660 MB
localhost/freebsd-notoolchain 15.1-RELEASE-amd64  086572f35cc9  13 days ago   152 MB
localhost/freebsd-runtime     15.1-RELEASE-amd64  90c493675429  13 days ago   34.1 MB
localhost/freebsd-dynamic     15.1-RELEASE-amd64  33427d59f990  13 days ago   14.5 MB
localhost/freebsd-static      15.1-RELEASE-amd64  5921c62e76c1  13 days ago   2.92 MB

Téngase en cuenta que los ID de imagen son reproducibles cada vez y que la columna IMAGE_ID coincide con los hashes indicados al importar las imágenes.

18.10.3. Listado de capas

Es posible mostrar las capas que componen una imagen, demostrando cómo la imagen runtime tiene tres componentes, cada uno de los cuales es una capa por derecho propio:

# podman image tree ghcr.io/freebsd/freebsd-runtime:14.2
Image ID: c5f3e77557a9
Tags:     [ghcr.io/freebsd/freebsd-runtime:14.2]
Size:     35.07MB
Image Layers
├── ID: cd53fb07fb66 Size: 5.449MB Top Layer of: [ghcr.io/freebsd/freebsd-static:14.2]
├── ID: a01d37f7777b Size:  10.4MB Top Layer of: [ghcr.io/freebsd/freebsd-dynamic:14.2]
└── ID: 36b0c80ca1f7 Size: 19.21MB Top Layer of: [ghcr.io/freebsd/freebsd-runtime:14.2]

18.10.4. Uso de registros públicos

Aunque la procedencia más segura se obtiene descargando desde Releases oficiales de FreeBSD, hay dos registros públicos de contenedores gestionados por los equipos de Release y de administración del clúster de FreeBSD. Las imágenes de ambos registros son idénticas, pero proporcionan un flujo de trabajo más sencillo y adecuado para contenedores.

18.10.5. Obtención de contenedores

Las imágenes se pueden obtener de un registro público mediante podman pull:

# podman pull ghcr.io/freebsd/freebsd-notoolchain:15.1
Trying to pull ghcr.io/freebsd/freebsd-notoolchain:15.1...
Getting image source signatures
Copying blob 711cf0d3c0ef done   |
Copying config 086572f35c done   |
Writing manifest to image destination
086572f35cc90b1a1d2b7904b63e8a849071b4ba89b15492f6da47a802372aa2

18.10.6. Ejecución de un contenedor

Use podman run para iniciar un contenedor. Las opciones -it asignan un terminal interactivo y --rm elimina el contenedor cuando sale. Si no se especifica ninguna orden, se usa el punto de entrada predeterminado de la imagen:

# podman run -it --rm ghcr.io/freebsd/freebsd-notoolchain:15.1
# exit

También se puede proporcionar una orden específica:

# podman run -it --rm ghcr.io/freebsd/freebsd-notoolchain:15.1 uname -a
FreeBSD c0038de70651 15.1-RELEASE FreeBSD 15.1-RELEASE releng/15.1-n283562-96841ea08dcf GENERIC amd64

Como la imagen de contenedor no incluye el kernel, freebsd-version(1) muestra resultados diferentes para el kernel en ejecución y para el espacio de usuario instalado. En este ejemplo, un contenedor 15.0-RELEASE se ejecuta en un host 15.1-RELEASE:

# podman run -it --rm ghcr.io/freebsd/freebsd-notoolchain:15.0 /bin/sh
# freebsd-version -ru
15.1-RELEASE
15.0-RELEASE
# exit

18.11. Variaciones y consejos útiles

Casi todos los parámetros de podman run ... también se aplican a podman build. Consulte las páginas de manual podman-run(1) y podman-build(1) para obtener más información.

Use la opción --rm para que los contenedores efímeros se limpien automáticamente después.

Use podman images -a para mostrar todas las imágenes descargadas:

# podman images -a
REPOSITORY                       TAG            IMAGE ID      CREATED      SIZE
ghcr.io/freebsd/freebsd-runtime  15.1   90c493675429  2 weeks ago  34.1 MB

Use podman ps -a para ver los contenedores en ejecución:

# podman ps -a
CONTAINER ID  IMAGE                                          COMMAND  CREATED        STATUS        NAMES
3123623bef9b  ghcr.io/freebsd/freebsd-runtime:15.1   /bin/sh  4 minutes ago  Up 4 minutes  admiring_brattain

18.11.1. Variables de entorno

Podman establece varias variables de entorno predeterminadas en cada contenedor:

# podman run -it --rm ghcr.io/freebsd/freebsd-notoolchain:15.1 /usr/bin/env
container=podman
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOME=/root
HOSTNAME=60bae3343e6b

El HOSTNAME se establece de forma predeterminada en el ID del contenedor. Se puede sobrescribir con --hostname, lo cual resulta útil cuando la aplicación dentro del contenedor necesita un nombre de host estable o significativo.

Se pueden pasar variables de entorno arbitrarias con --env:

# podman run --env FOO=BAR -it --rm ghcr.io/freebsd/freebsd-runtime:15.1
# echo $FOO
BAR

18.11.2. Montaje de ficheros y volúmenes

Tanto los ficheros como los volúmenes se pueden pasar a los contenedores mediante --volume. Por ejemplo, la imagen runtime no contiene which(1):

# podman run -it --rm ghcr.io/freebsd/freebsd-runtime:15.1
# which
/bin/sh: which: not found

Se puede montar en el contenedor desde el host:

# podman run -it --rm --volume /usr/bin/which:/usr/bin/which \
    ghcr.io/freebsd/freebsd-runtime:15.1
# which which
/usr/bin/which

Para una imagen ligera como freebsd-static, monte el pkg-static(8) existente desde el host para inicializar pkg(8) dentro del contenedor. Compartir la caché de paquetes del host mediante --volume /var/cache/pkg evita volver a descargar paquetes que ya se han obtenido, lo que es especialmente útil al compilar varios contenedores. La opción --no-hosts impide montar /etc/hosts, que de otro modo interferiría con las actualizaciones de paquetes.

Compartir la caché de paquetes solo funciona cuando el host y el contenedor ejecutan la misma versión principal de FreeBSD, ya que los paquetes son específicos de cada versión.

# podman run -it --rm \
    --env ASSUME_ALWAYS_YES=true \
    --no-hosts \
    --volume /usr/local/sbin/pkg-static:/bin/pkg-static \
    --volume /var/cache/pkg \
    ghcr.io/freebsd/freebsd-static:15.1
# pkg-static bootstrap -r FreeBSD
Bootstrapping pkg from pkg+https://pkg.FreeBSD.org/FreeBSD:14:amd64/latest, please wait...
Verifying signature with trusted certificate pkg.freebsd.org.2013102301... done
[fd343e182fa5] Installing pkg-2.1.2...
[fd343e182fa5] Extracting pkg-2.1.2: 100%

Los ficheros y directorios del host también se pueden montar en los contenedores:

# podman run -it --rm \
    --volume /etc/fstab:/etc/fstab \
    --volume /tmp:/var/tmp \
    --volume /tmp \
    ghcr.io/freebsd/freebsd-runtime:15.1

18.11.3. Inspección del contenido de imágenes

Para listar todos los ficheros de cualquier imagen, incluidas las imágenes mínimas sin shell ni herramientas, exporte el sistema de ficheros del contenedor y liste su contenido:

# podman export $(podman create --rm ghcr.io/freebsd/freebsd-static:15.1 /) | tar tf -

Las imágenes de contenedor no incluyen pkg(8), pero se puede montar pkg-static(8) desde el host para consultar los paquetes instalados del sistema base. Use pkg info -q para listar los nombres de paquetes o pkg info -ql para mostrar todos los ficheros que pertenecen a los paquetes:

# podman run --rm \
    -v /usr/local/sbin/pkg-static:/pkg \
    ghcr.io/freebsd/freebsd-runtime:15.1 /pkg info -q
FreeBSD-audit-lib-15.1
FreeBSD-bzip2-lib-15.1
FreeBSD-certctl-15.1
FreeBSD-clibs-15.1
FreeBSD-fetch-15.1
FreeBSD-kerberos-lib-15.1
FreeBSD-libarchive-15.1
FreeBSD-libcasper-15.1
FreeBSD-libexecinfo-15.1
FreeBSD-libucl-15.1
FreeBSD-mtree-15.1
FreeBSD-ncurses-lib-15.1
FreeBSD-openssl-15.1
FreeBSD-openssl-lib-15.1
FreeBSD-pam-lib-15.1
FreeBSD-pkg-bootstrap-15.1
FreeBSD-rc-15.1
FreeBSD-runtime-15.1
FreeBSD-xz-lib-15.1
FreeBSD-zlib-15.1
FreeBSD-zoneinfo-15.1
FreeBSD-zstd-lib-15.1

Cuando el host y el contenedor ejecutan versiones principales diferentes de FreeBSD, pkg(8) detecta la ABI inspeccionando /bin/sh dentro del contenedor y advertirá sobre la discrepancia:

# podman run -it --rm \
    --env ASSUME_ALWAYS_YES=true \
    --no-hosts \
    --volume /usr/local/sbin/pkg-static:/usr/sbin/pkg \
    --volume /var/cache/pkg \
    ghcr.io/freebsd/freebsd-runtime:14.4 /bin/sh
# pkg bootstrap
pkg: Warning: Major OS version upgrade detected.  Running "pkg bootstrap -f" recommended

Para las imágenes sin /bin/sh, como freebsd-dynamic, pkg-static(8) no puede detectar en absoluto la ABI del sistema.

18.12. Redes y resolución de nombres

De forma predeterminada, el conjunto de herramientas Podman usará mount_nullfs(8) para montar /etc/resolv.conf y un /etc/hosts modificado desde el host de jail, además de un fichero .containerenv en /var/run.

Este fichero hosts entrará en conflicto con las actualizaciones de paquetes del sistema base, por lo que se aconseja omitirlo durante las ejecuciones de podman build, pero dejarlo habilitado durante el despliegue en producción:

# podman run --dns 1.2.3.4 ...
# podman build --no-hosts ...

La opción --dns especifica un servidor DNS personalizado en lugar de montar /etc/resolv.conf desde el host. La opción --no-hosts impide montar /etc/hosts desde el host.

18.13. Creación de imágenes personalizadas

Las imágenes personalizadas se pueden crear directamente a partir de tarballs (por ejemplo, los de poudriere(8) o tarballs de release oficiales), de imágenes etiquetadas existentes o inicializarlas a partir de pkg(8).

18.13.1. Creación a partir de tarballs

Se puede crear una imagen personalizada desde cualquier tarball de sistema de ficheros raíz de FreeBSD mediante podman-import(1). El tarball puede ser un base.txz de release oficial, uno producido por poudriere-image(8) o un tarball personalizado propio. La imagen final etiquetada puede enviarse a registros, modificarse y usarse para crear más imágenes.

# podman import --os freebsd \
    --arch amd64 \
    --message 'Import FreeBSD 15.1-RELEASE base.txz' \
    https://download.freebsd.org/releases/amd64/15.1-RELEASE/base.txz
Downloading from "https://download.freebsd.org/releases/amd64/15.1-RELEASE/base.txz"
Getting image source signatures
Copying blob 3768988b151c done   |
Copying config 332bec83a4 done   |
Writing manifest to image destination
sha256:332bec83a428efa6c9f7d1f8b3fbd589c5613d938dca7da5125240c89f4f3dcd

# podman image tag 332bec83a428 localhost/freebsd-base:15.1

# podman image ls
REPOSITORY              TAG   IMAGE ID      CREATED        SIZE
localhost/freebsd-base  15.1  332bec83a428  5 minutes ago  715 MB

18.13.2. Creación a partir de Containerfiles

Las imágenes se pueden crear mediante un Containerfile, de forma similar a un Dockerfile. En la mayoría de los casos, la imagen freebsd-notoolchain es la base más conveniente, ya que incluye casi todas las herramientas estándar del sistema. Para contenedores más ligeros, comience con freebsd-static, freebsd-dynamic o freebsd-runtime, según corresponda, y añada solo lo necesario:

# Containerfile
FROM ghcr.io/freebsd/freebsd-notoolchain:15.1
RUN env ASSUME_ALWAYS_YES=yes IGNORE_OS_VERSION=yes pkg bootstrap -r FreeBSD
RUN pkg update
RUN pkg upgrade -y
RUN pkg clean -y
ENTRYPOINT /bin/sh

Compile la imagen con podman-build(1):

# podman build --no-hosts --squash \
    -t localhost/freebsd-base:15.1 \
    -f ./Containerfile

Se pueden superponer imágenes adicionales:

# Containerfile.webserver
FROM localhost/freebsd-base:15.1
RUN pkg install -y lang/python3
RUN pkg clean -y
ENTRYPOINT /usr/local/bin/python3 -m http.server
# podman build --no-hosts \
    -t localhost/python-www:15.1 \
    -f ./Containerfile.webserver

Ejecute el servidor web en segundo plano con --detach y use -p para asignar un puerto del host al puerto del contenedor. En este ejemplo, el contenedor escucha en su puerto predeterminado 8000, que se asigna al puerto 8888 en el host:

# c=$(podman run --detach --rm -p 8888:8000 localhost/python-www:15.1)

La asignación de puertos utiliza reglas de redirección de pf(4). Estas reglas redirigen el tráfico que llega por la red, por lo que se debe acceder al puerto asignado desde otro host o a través de la dirección IP del host orientada a la red:

$ fetch -v http://172.16.2.10:8888/
resolving server address: 172.16.2.10:8888
requesting http://172.16.2.10:8888/
remote size / mtime: 784 / 0
fetch.out                                              784  B 3791 kBps    00s

Para acceder directamente al contenedor desde el host, use la propia IP del contenedor en su puerto de escucha:

# podman inspect -f '{{.NetworkSettings.IPAddress}}' $c
10.88.0.91
# fetch -v http://10.88.0.91:8000/
resolving server address: 10.88.0.91:8000
requesting http://10.88.0.91:8000/
remote size / mtime: 784 / 0
fetch.out                                              784  B   25 MBps    00s

Las asignaciones de puertos mediante -p se gestionan mediante reglas de redirección de pf(4) y solo se aplican al tráfico que llega por la red. El tráfico originado desde el propio host de jail hacia localhost o 127.0.0.1 no se redirigirá. Desde el host, use directamente la dirección IP del contenedor.

18.14. Uso avanzado

18.14.1. Ejecución de Podman como daemon

La implementación de Podman de FreeBSD proporciona dos servicios rc(8):

  • El servicio podman se ejecuta durante el arranque y garantiza que se inicien todos los contenedores marcados con restart-policy=always.

  • El servicio podman_service ejecuta el servicio API de Podman, proporciona una API REST y escucha en /var/run/podman/podman.sock de forma predeterminada.

Habilítelos de la siguiente manera:

# sysrc podman_enable=YES
# sysrc podman_service_enable=YES
# sysrc podman_service_flags='--time 0'
# service podman start
# service podman_service start

Los contenedores que deban reiniciarse automáticamente tras reiniciar el host se deben ejecutar con la opción --restart=always:

# podman run --detach --restart=always my-image

18.14.2. Ejecución de contenedores Linux

Es posible ejecutar muchas imágenes de contenedor Linux mediante la emulación Linux de FreeBSD:

# service linux onestart
# podman run --rm --os=linux docker.io/alpine cat /etc/os-release | head -1
Trying to pull docker.io/library/alpine:latest...
Getting image source signatures
Copying blob 4abcf2066143 done   |
Copying config 05455a0888 done   |
Writing manifest to image destination
NAME="Alpine Linux"

Es posible que los contenedores Linux que dependan de systemd, esperen ser PID 1 o dependan de interfaces del kernel específicas de Linux no funcionen correctamente con la emulación Linux de FreeBSD.

18.14.3. Ejecución de un registro local

Un registro es un servidor web para almacenar y compartir imágenes OCI. El port sysutils/docker-registry proporciona un registro sencillo adecuado para el desarrollo local o una organización pequeña. Zot Registry es una alternativa moderna más completa.

# pkg install -r FreeBSD sysutils/docker-registry
# zfs create zroot/var/db/registry
# chown -R www:www /var/db/registry
# sysrc docker_registry_enable=YES
# sysrc docker_registry_user=www
# sed -i '' -E -e 's,rootdirectory:.+,rootdirectory: /var/db/registry,' \
    /usr/local/etc/docker-registry/config.yml
# touch /usr/local/etc/docker-registry/htpasswd
# chown -R root:www /usr/local/etc/docker-registry/config.yml \
    /usr/local/etc/docker-registry/htpasswd
# chmod 0640 /usr/local/etc/docker-registry/config.yml \
    /usr/local/etc/docker-registry/htpasswd

Una configuración de ejemplo para /usr/local/etc/docker-registry/config.yml:

version: 0.1
log:
  fields:
    service: registry
storage:
  cache:
    blobdescriptor: inmemory
  filesystem:
    rootdirectory: /var/db/registry
http:
  addr: :5000
  secret: <random-secret>
  headers:
    X-Content-Type-Options: [nosniff]
auth:
  htpasswd:
    realm: basic-realm
    path: /usr/local/etc/docker-registry/htpasswd
health:
  storagedriver:
    enabled: true
    interval: 10s
    threshold: 3

Inicie el registro y verifique que se esté ejecutando:

# service registry start
# curl -u admin:passwd http://localhost:5000/v2/

Se recomienda servir el registro mediante TLS, detrás de un proxy inverso como nginx o haproxy.

18.14.4. Sincronización de registros

Es posible sincronizar imágenes oficiales de FreeBSD en un registro local mediante skopeo. El siguiente ejemplo replica todas las imágenes relacionadas con FreeBSD desde Docker Hub en un registro local:

# sync.yml
docker.io:
  images:
    freebsd/freebsd-static: []
    freebsd/freebsd-dynamic: []
    freebsd/freebsd-runtime: []
$ skopeo sync --src yaml --dest docker --all sync.yml cr.example.net/freebsd
INFO[0000] Processing repo                               repo=freebsd/freebsd-static
INFO[0000] Querying registry for image tags              repo=freebsd/freebsd-static
...
INFO[0771] Synced 42 images from 3 sources

Siempre que las credenciales de /root/.config/containers/auth.json estén actualizadas, no se requiere acceso de root para sincronizar imágenes.

18.14.5. Trabajo con registros de contenedores

Por lo general, los registros requieren autenticación para las operaciones de envío y, opcionalmente, para la extracción. Las credenciales se guardan de forma predeterminada en /root/.config/containers/auth.json después de iniciar sesión:

# podman login ghcr.io -u username
Password:
Login Succeeded!

Las imágenes se pueden enviar a un registro:

# podman push localhost/freebsd-runtime:15.1 \
    docker://ghcr.io/example/freebsd-runtime:15.1
Getting image source signatures
Copying blob bbacfdfbe140 done   |
Copying config 786f2592a8 done   |
Writing manifest to image destination

Las imágenes públicas se pueden extraer sin autenticación:

# podman pull ghcr.io/freebsd/freebsd-runtime:15.1

18.15. Creación de imágenes de contenedor a partir de fuentes

Las herramientas de release de FreeBSD proporcionan un objetivo oci-release para compilar las imágenes necesarias que usará podman load. Primero se deben compilar world, kernel y los paquetes del sistema base, por lo que esto puede tardar un tiempo.

El siguiente ejemplo compila imágenes arm64:

# cd /usr/src \
    && make TARGET_ARCH=aarch64 TARGET=arm64 -s -j32 buildworld \
    && make TARGET_ARCH=aarch64 TARGET=arm64 KERNCONF=GENERIC -s -j32 buildkernel \
    && make TARGET_ARCH=aarch64 TARGET=arm64 KERNCONF=GENERIC -s -j32 packages \
    && cd ./release \
    && make TARGET_ARCH=aarch64 TARGET=arm64 -j32 -s clean \
    && make KERNCONF=GENERIC TARGET_ARCH=aarch64 TARGET=arm64 WITH_OCIIMAGES=yes \
      -s oci-release

Y de forma similar para amd64:

# cd /usr/src \
    && make TARGET_ARCH=amd64 TARGET=amd64 -s -j32 buildworld \
    && make TARGET_ARCH=amd64 TARGET=amd64 KERNCONF=GENERIC -s -j32 buildkernel \
    && make TARGET_ARCH=amd64 TARGET=amd64 KERNCONF=GENERIC -s -j32 packages \
    && cd ./release \
    && make TARGET_ARCH=amd64 TARGET=amd64 -s -j32 clean \
    && make KERNCONF=GENERIC TARGET_ARCH=amd64 TARGET=amd64 \
      WITH_OCIIMAGES=yes -s oci-release

18.16. Pruebas entre arquitecturas

El paquete emulators/qemu-user-static permite probar imágenes de contenedor compiladas para otras arquitecturas. Después de instalar el paquete, habilite e inicie el servicio para registrar activadores de imágenes para todas las arquitecturas emuladas:

# pkg install emulators/qemu-user-static
# service qemu_user_static enable
# service qemu_user_static start

A continuación, ejecute una imagen arm64 en un host amd64 montando el binario QEMU apropiado:

# podman run -it --rm --arch=arm64 \
    -v /usr/local/bin/qemu-aarch64-static:/usr/local/bin/qemu-aarch64-static \
    ghcr.io/freebsd/freebsd-runtime:14.snap uname -a
FreeBSD 73d4049d10b2 14.2-RELEASE-p1 FreeBSD 14.2-RELEASE-p1 GENERIC arm64

18.17. Resolución de problemas

18.17.1. Actualizaciones de paquetes y ficheros montados

Podman monta /etc/resolv.conf y /etc/hosts en los contenedores mediante mount_nullfs(8). Estos montajes pueden causar errores durante las operaciones de pkg(8) con mensajes como Cross-device link:

pkg: Fail to rename /etc/.pkgtemp.hosts.VeIDrHM0sKN5 -> /etc/hosts:Cross-device link

Para evitarlo, use las opciones --no-hosts y --dns:

# podman run --no-hosts --dns 1.1.1.1 -it --rm \
    ghcr.io/freebsd/freebsd-runtime:15.1 /bin/sh

18.17.2. Comprobación de la red

Comience con las reglas de firewall de /usr/local/etc/containers/pf.conf.sample. Pruebe la conectividad paso a paso desde dentro de un contenedor:

# podman run --no-hosts --dns 1.1.1.1 \
    --env ASSUME_ALWAYS_YES=1 \
    -it --rm \
    ghcr.io/freebsd/freebsd-runtime:15.1 \
    /bin/sh

# route show 1.1.1.1
   route to: 1.1.1.1
destination: default
    gateway: 10.88.0.1
  interface: eth0

# ping -c 3 10.88.0.1
PING 10.88.0.1 (10.88.0.1): 56 data bytes
64 bytes from 10.88.0.1: icmp_seq=0 ttl=64 time=0.083 ms
...

# ping -c 3 1.1.1.1
PING 1.1.1.1 (1.1.1.1): 56 data bytes
64 bytes from 1.1.1.1: icmp_seq=0 ttl=60 time=0.920 ms
...

# fetch -v http://1.1.1.1/
...

# pkg -dd bootstrap -r FreeBSD

Si ping(8) falla, compruebe las reglas de firewall en busca de ICMP bloqueado. Si fetch(1) falla, compruebe las reglas de firewall en busca de TCP bloqueado en los puertos 80 y 443. Si pkg(8) falla pero ICMP y TCP funcionan, podría tratarse de un problema de fragmentación o MTU. Añada set reassemble yes no-df a /etc/pf.conf y reinicie el firewall.

Para depurar paquetes bloqueados, habilite log en todas las reglas de bloqueo de /etc/pf.conf y use tcpdump(1) en el dispositivo pflog(4):

# service pflog onerestart
# tcpdump -vvveni pflog0 icmp or net 10.88.0.0/16

18.17.3. Coherencia de MTU

Asegúrese de que los valores de MTU sean coherentes en la interfaz de red principal, el puente de contenedores y el propio contenedor. Los valores de MTU no coincidentes pueden provocar fragmentación de paquetes y fallos de conectividad.

En el siguiente ejemplo, vtnet0 tiene una MTU de 9000, pero el puente y los contenedores tienen una MTU de 1500. En general, alinee el diseño interno con la red externa:

# ifconfig vtnet0 mtu 9000
# ifconfig cni-podman0 mtu 9000

Dentro del contenedor:

# ifconfig eth0 mtu 9000

Los puentes y epairs que usa Podman son efímeros y deberán configurarse para cada creación de puente y para cada contenedor. En algunos entornos de nube, también puede ser necesario añadir set reassemble yes no-df a /etc/pf.conf.