¿Cómo crear un intercambio para Azure Ubuntu VM?

9

He leído bastantes publicaciones sobre esto, pero todavía no estoy seguro sobre el enfoque correcto, suponiendo:

  1. Tengo una máquina virtual Ubuntu 14.04 LTS predeterminada creada y ejecutada en Azure, que no viene con un intercambio

  2. Me gustaría crear un intercambio utilizando el almacenamiento de VM existente, en lugar de crear un nuevo disco con almacenamiento adicional

Publicaciones que he leído:

Se discutieron muchas soluciones, pero parece que no puedo encontrar una que persista durante los reinicios del servidor (probablemente debido a que cloud-init tiene su propia idea sobre la partición de imágenes), ¿alguien puede aconsejarme sobre las mejores prácticas?

bitinn
fuente

Respuestas:

8

Asumiendo que tiene instalado el Agente Linux. Todo lo que tiene que hacer es habilitar el intercambio en /etc/waagent.conf. Estas son las líneas relevantes:

ResourceDisk.Format=y                   # Format if unformatted. If 'n', resour$
ResourceDisk.Filesystem=ext4            # Typically ext3 or ext4. FreeBSD image$
ResourceDisk.MountPoint=/mnt/resource   #
ResourceDisk.EnableSwap=y               # Create and use swapfile on resource d$
ResourceDisk.SwapSizeMB=2048            # Size of the swapfile.

Automáticamente usará el disco de recursos (que viene con cada VM) para crear el intercambio. No hay necesidad de crear un disco para ello.

Actualización : También debe ejecutar los pasos a continuación para crear el archivo de intercambio:

umount /mnt
service walinuxagent restart
Bruno Faria
fuente
La provisión de disco está controlada por Cloud Init en Ubuntu, a diferencia de otras distribuciones. Entonces no, esto no debería funcionar, y tanto doc como mi prueba lo confirman.
bitinn
2
I contacto con la ayuda MS y se encontró que la solución es conjunto ResourceDisk.Format, ResourceDisk.EnableSwapy ResourceDisk.SwapSizeMB. PERO el paso importante es hacer un manual sudo service walinuxagent restartpara crear el archivo de intercambio, ya que simplemente reiniciar el servidor no funciona para mí.
bitinn 01 de
Todavía estoy preguntando cómo Cloud Init figura en todo esto, porque sus comentarios de doc y waagent.conf son engañosos.
bitinn
Sip. Lo siento. olvidé incluir el reinicio del agente. Probé en mi ubuntu vm y trabajé sin problemas. He actualizado la respuesta. Con respecto a cloud-init, no creo que tenga nada que ver con la creación del archivo de intercambio, ya que el agente crea el archivo dentro de una partición ext4 (/ mnt). No crea una partición de intercambio.
Bruno Faria
2
No funcionó en Ubuntu 14.04 LTS VM, creado a partir de la imagen de Azure Gallery. Después de realizar todos los pasos, swapon -saún se muestra una lista vacía de archivos de intercambio.
JustAMartin
2

La respuesta de Bruno es un excelente punto de partida, pero solo funcionó después de reiniciar y le di otro minuto después de arrancar.

a. Habilitar intercambio /etc/waagent.conf, líneas relevantes:

ResourceDisk.Format=y                   # Format if unformatted. If 'n', resour$
ResourceDisk.Filesystem=ext4            # Typically ext3 or ext4. FreeBSD image$
ResourceDisk.MountPoint=/mnt/resource   #
ResourceDisk.EnableSwap=y               # Create and use swapfile on resource d$
ResourceDisk.SwapSizeMB=2048            # Size of the swapfile.

si. Haga lo siguiente como root, que incluye reiniciar su máquina:

umount /mnt
service walinuxagent restart
reboot

C. Después de arrancar, todavía llevará algún tiempo antes de que el intercambio esté realmente habilitado. Puedes consultarlo con swapon -s.

kqw
fuente
1

Creo que la manera correcta de hacer esto para que tanto cloud-init como waagent jueguen 'bien' juntos (de los documentos de Cloud-Init Azure ) es mantener estos valores establecidos en este

# disabling provisioning turns off all 'Provisioning.*' function
Provisioning.Enabled=n
# this is currently not handled by cloud-init, so let walinuxagent do it.
ResourceDisk.Format=y
ResourceDisk.MountPoint=/mnt

Intenté cambiar el punto de montaje pero no parecía funcionar correctamente, por lo que los documentos probablemente sean precisos sobre los valores

Y luego puede personalizar las opciones de intercambio como desee

# Create and use swapfile on resource disk.
ResourceDisk.EnableSwap=y

# Size of the swapfile.
ResourceDisk.SwapSizeMB=8192

Un reinicio básico recoge el nuevo intercambio bien

sudo service walinuxagent restart

free -m
             total       used       free     shared    buffers     cached
Mem:          3944        882       3061         44         29        163
-/+ buffers/cache:        689       3255
Swap:         8192          0       8192
Hiena sin miedo
fuente
0

He leído bastantes publicaciones sobre esto, pero todavía no estoy seguro sobre el enfoque correcto, suponiendo: 1. Tengo una máquina virtual Ubuntu 14.04 LTS predeterminada creada y ejecutada en Azure, que no viene con un intercambio 2. I quisiera crear un intercambio utilizando el almacenamiento de VM existente, en lugar de crear un nuevo disco con almacenamiento adicional

También necesitaba esto (en realidad, 16.04 en lugar de 14.04, pero mi respuesta se aplicará a ambos, creo).

Publicaciones que he leído:

Pero cuando vi que tenía que leer ensayos tan largos que usted señala, me iba a rendir ... Pero de repente recordé un artículo muy sencillo en el blog de DigitalOcean:

Cómo agregar intercambio en Ubuntu 14.04

Es tan simple que incluso he escrito un script para él (al menos en su mayor parte, aún no la configuración de intercambio y otras cosas avanzadas):

#!/usr/bin/env fsharpi

open System
open System.IO
open System.Net
open System.Diagnostics

#load "InfraTools.fs"
open Gatecoin.Infrastructure

// automation of https://www.digitalocean.com/community/tutorials/how-to-add-swap-on-ubuntu-14-04

let NUMBER_OF_GB_FOR_SWAP = 1

let isThereSwapMemoryInTheSystem (): bool =
    let _,output,_ = Tools.SafeHiddenExec("swapon", "-s")
    (output.Trim().Length > 0)

if (isThereSwapMemoryInTheSystem()) then
    Console.WriteLine("Swap already setup")
    Environment.Exit(0)

let swapFile = new FileInfo(Path.Combine("/", "swapfile"))
if not (swapFile.Exists) then
    Tools.BailIfNotSudoer("Need to use 'fallocate' to create swap file")
    Console.WriteLine("Creating swap file...")
    Tools.SafeExec("fallocate", String.Format("-l {0}G {1}", NUMBER_OF_GB_FOR_SWAP, swapFile.FullName), true)

let permissionsForSwapFile = 600
if not (Tools.OctalPermissions(swapFile) = permissionsForSwapFile) then
    Tools.BailIfNotSudoer("Need to adjust permissions of the swap file")
    Tools.SafeExec("chmod", String.Format("{0} {1}", permissionsForSwapFile, swapFile.FullName), true)

Tools.BailIfNotSudoer("Enable swap memory")
Tools.SafeExec("mkswap", swapFile.FullName, true)
Tools.SafeExec("swapon", swapFile.FullName, true)
if not (isThereSwapMemoryInTheSystem()) then
    Console.WriteLine("Something went wrong while enabling the swap file")
    Environment.Exit(1)

Tools.BailIfNotSudoer("Writing into /etc/fstab")
Tools.SafeHiddenExecBashCommand(String.Format("echo \"{0}   none    swap    sw    0   0\" >> /etc/fstab", swapFile.FullName))

Para que lo anterior funcione, sudo apt install fsharpprimero debe hacerlo (al menos Ubuntu 16.04 tiene fsharp en los repositorios, no estoy seguro acerca de 14.04).

También necesitas este InfraTools.fsarchivo:

open System
open System.IO
open System.Net

namespace Gatecoin.Infrastructure

module Tools =

    let HiddenExec (command: string, arguments: string) =
        let startInfo = new System.Diagnostics.ProcessStartInfo(command)
        startInfo.Arguments <- arguments
        startInfo.UseShellExecute <- false

        // equivalent to `>/dev/null 2>&1` in unix
        startInfo.RedirectStandardError <- true
        startInfo.RedirectStandardOutput <- true

        use proc = System.Diagnostics.Process.Start(startInfo)
        proc.WaitForExit()
        (proc.ExitCode,proc.StandardOutput.ReadToEnd(),proc.StandardError.ReadToEnd())

    let HiddenExecBashCommand (commandWithArguments: string) =
        let args = String.Format("-c \"{0}\"", commandWithArguments.Replace("\"", "\\\""))
        HiddenExec("bash", args)

    let SafeHiddenExecBashCommand (commandWithArguments: string) =
        let exitCode,stdOut,stdErr = HiddenExecBashCommand commandWithArguments
        if not (exitCode = 0) then
            Console.Error.WriteLine(stdErr)
            Console.Error.WriteLine()
            Console.Error.WriteLine("Bash command '{0}' failed with exit code {1}.", commandWithArguments, exitCode.ToString())
            Environment.Exit(1)
        exitCode,stdOut,stdErr

    let Exec (command: string, arguments: string, echo: bool) =
        let psi = new System.Diagnostics.ProcessStartInfo(command)
        psi.Arguments <- arguments
        psi.UseShellExecute <- false
        if (echo) then
            Console.WriteLine("{0} {1}", command, arguments)
        let p = System.Diagnostics.Process.Start(psi)
        p.WaitForExit()
        p.ExitCode

    let ExecBashCommand (commandWithArguments: string, echo: bool) =
        let args = String.Format("-c \"{0}\"", commandWithArguments.Replace("\"", "\\\""))
        if (echo) then
            Console.WriteLine(commandWithArguments)
        Exec("bash", args, false)

    let SafeHiddenExec (command: string, arguments: string) =
        let exitCode,stdOut,stdErr = HiddenExec(command, arguments)
        if not (exitCode = 0) then
            Console.Error.WriteLine(stdErr)
            Console.Error.WriteLine()
            Console.Error.WriteLine("Command '{0}' failed with exit code {1}. Arguments supplied: '{2}'", command, exitCode.ToString(), arguments)
            Environment.Exit(1)
        exitCode,stdOut,stdErr

    let SafeExec (command: string, arguments: string, echo: bool) =
        let exitCode = Exec(command, arguments, echo)
        if not (exitCode = 0) then
            Console.Error.WriteLine("Command '{0}' failed with exit code {1}. Arguments supplied: '{2}'", command, exitCode.ToString(), arguments)
            Environment.Exit(1)
            failwith "unreached"
        ()

    let SafeExecBashCommand (commandWithArguments: string, echo: bool) =
        let args = String.Format("-c \"{0}\"", commandWithArguments.Replace("\"", "\\\""))
        if (echo) then
            Console.WriteLine(commandWithArguments)
        SafeExec("bash", args, false)

    let FirstElementOf3Tuple (a, _, _) = a
    let SecondElementOf3Tuple (_, b, _) = b

    let SimpleStringSplit (str: string, separator: string): string list =
        List.ofSeq(str.Split([|separator|], StringSplitOptions.RemoveEmptyEntries))

    let SplitStringInLines (str: string): string list =
        SimpleStringSplit(str,Environment.NewLine)

    let CommandWorksInShell (command: string): bool =
        let exitCode =
            try
                Some(FirstElementOf3Tuple(HiddenExec(command,String.Empty))
            with
                | :? System.ComponentModel.Win32Exception -> (); None
        if exitCode.IsNone then
            false
        else
            true

    let BailIfNotSudoer(reason: string): unit =   
        if not (CommandWorksInShell "id") then
            Console.WriteLine ("'id' unix command is needed for this script to work")
            Environment.Exit(2)
            ()

        let _,idOutput,_ = HiddenExec("id","-u")
        if not (idOutput.Trim() = "0") then
            Console.Error.WriteLine ("Error: needs sudo privilege. Reason: {0}", reason)
            Environment.Exit(3)
            ()
        ()

    let OctalPermissions (file: FileInfo): int =
        let output = SecondElementOf3Tuple(SafeHiddenExec("stat", String.Format("-c \"%a\" {0}", file.FullName)))
        Int32.Parse(output.Trim())

Se discutieron muchas soluciones, pero parece que no puedo encontrar una que persista en los reinicios del servidor

La parte que hace que mi respuesta funcione a través de reinicios del servidor es la escritura en el archivo / etc / fstab.

Lo bueno de esta solución es que debería funcionar en Azure, DigitalOcean, YouNameIt, ...

¡Disfrutar!

knocte
fuente
2
¡"Es tan simple" seguido de 50 líneas de código parece un poco un oxímoron!
kqw