Implementación de mydocker logs para visualizar registros de contenedores

Para habilitar la visualización de registros de contenedores similar a docker logs, se implementa un mecanismo que redirige la salida estándar de los procesos en contenedores a archivos de log. Esto permite consultar los registros cuando sea necesario, siguiendo un diseño donde los contenedores en segundo plano almacenan su salida, mientras que los contenedores en primer plano mantienen la salida en la consola.

Decsripción técnica

El objetivo es agregar un comando mydocker logs que permita inspeccionar los registros de contenedores. La estrategia consiste en, al iniciar un contenedor en modo no interactivo, redirigir stdout y stderr a un archivo de log específico dentro del directorio del contenedor. Posteriormente, el comando de logs lee este archivo y muestra su contenido.

Cambios en la creación de procesos

Se modifica la función encargada de configurar el proceso principal del contenedor. Para contenedores que no requieren terminal, se crea un archivo de log y se asigna como destino para la salida estándar y los errores.


func ConfigurarProcesoHijo(usarTerminal bool, volumen, identificador string) (*exec.Cmd, *os.File) {
    // Otras inicializaciones omitidas
    if usarTerminal {
        cmd.Stdin = os.Stdin
        cmd.Stdout = os.Stdout
        cmd.Stderr = os.Stderr
    } else {
        rutaDirectorio := fmt.Sprintf(RutaDatosContenedor, identificador)
        if err := os.MkdirAll(rutaDirectorio, permisos.Directorio); err != nil {
            log.Errorf("Error al crear directorio %s: %v", rutaDirectorio, err)
            return nil, nil
        }
        rutaArchivo := rutaDirectorio + NombreArchivoLog
        archivo, err := os.Create(rutaArchivo)
        if err != nil {
            log.Errorf("Error al crear archivo %s: %v", rutaArchivo, err)
            return nil, nil
        }
        cmd.Stdout = archivo
        cmd.Stderr = archivo
    }
    // Resto de la configuración
}

Añadir el comando de logs

Se integra un nuevo comando en la interfaz de línea de comandos. Este comando extrae el nombre del contenedor de los argumentos y llama a la función para mostrar los registros.


var cmdLogs = cli.Command{
    Name:  "logs",
    Usage: "Muestra los registros de un contenedor",
    Action: func(ctx *cli.Context) error {
        if ctx.NArg() < 1 {
            return fmt.Errorf("Se requiere el nombre del contenedor")
        }
        nombreCont := ctx.Args().First()
        ObtenerRegistros(nombreCont)
        return nil
    },
}

Este comando se registra en la aplicación principal junto con los otros comandos existentes.

Función para obtener registros

La lógica para leer y presentar los registros se ecnapsula en una función que localiza el archivo de log basado en el identificador del contenedor.


func ObtenerRegistros(nombreContenedor string) {
    ubicacionLog := fmt.Sprintf(RutaDatosContenedor, nombreContenedor) + NombreArchivoLog
    archivo, err := os.Open(ubicacionLog)
    if err != nil {
        log.Errorf("No se pudo abrir el archivo %s: %v", ubicacionLog, err)
        return
    }
    defer archivo.Close()
    datos, err := ioutil.ReadAll(archivo)
    if err != nil {
        log.Errorf("Error al leer el archivo %s: %v", ubicacionLog, err)
        return
    }
    fmt.Fprint(os.Stdout, string(datos))
}

Verificación funcional

Para probar, se inicia un contenedor en segundo plano y se comprueba la generación del archivo de log.


$ ./mydocker run -d -name testcontainer top
$ ./mydocker ps
ID            NAME          PID     STATUS    COMMAND   CREATED
xyz987654     testcontainer 54321   running   top       2024-01-26 10:30:00

Se inspecciona el directorio del contenedor para confirmar la existencia del archivo de log.


$ ls /var/lib/mydocker/containers/xyz987654/
xyz987654-json.log config.json

El contenido del archivo de log refleja la salida del proceso top.


$ cat /var/lib/mydocker/containers/xyz987654/xyz987654-json.log
Mem: 1785600K used, 249776K free, 1080K shrd, 92000K buff, 1360000K cached
CPU:  0.2% usr  0.1% sys  0.0% nic 99.5% idle  0.0% io  0.0% irq  0.2% sirq
Load average: 0.02 0.01 0.00 1/140 3
  PID  PPID USER     STAT   VSZ %VSZ CPU %CPU COMMAND

Finalmente, se ejecuta el comando de logs para visualizar los registros almacenados.


$ ./mydocker logs xyz987654
Mem: 1785600K used, 249776K free, 1080K shrd, 92000K buff, 1360000K cached
CPU:  0.2% usr  0.1% sys  0.0% nic 99.5% idle  0.0% io  0.0% irq  0.2% sirq
Load average: 0.02 0.01 0.00 1/140 3
  PID  PPID USER     STAT   VSZ %VSZ CPU %CPU COMMAND

Etiquetas: Docker linux golang containers logging

Publicado el 6-2 00:29