Jak utworzyć wymianę dla maszyny Wirtualnej Ubuntu Azure?

9

Przeczytałem już sporo postów na ten temat, ale nadal nie jestem pewien co do prawidłowego podejścia, zakładając:

  1. Mam domyślną maszynę Wirtualną Ubuntu 14.04 LTS utworzoną przez i uruchomioną na platformie Azure, która nie jest dostarczana z wymianą

  2. Chciałbym utworzyć swap przy użyciu istniejącego magazynu VM, zamiast tworzyć nowy dysk przy użyciu dodatkowego magazynu

Posty, które przeczytałem:

Dyskutowano o wielu rozwiązaniach, ale nie mogę znaleźć takiego, który będzie się utrzymywał po ponownym uruchomieniu serwera (prawdopodobnie z powodu inicjacji w chmurze ma własny pomysł na partycjonowanie obrazów), czy ktoś może mi doradzić najlepszą praktykę?

bitinn
źródło

Odpowiedzi:

8

Zakładając, że masz zainstalowany Linux Agent. Wszystko, co musisz zrobić, to włączyć wymianę w /etc/waagent.conf. Oto odpowiednie linie:

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.

Automatycznie użyje dysku zasobów (dostarczanego z każdą maszyną wirtualną) do utworzenia wymiany. Nie ma potrzeby tworzenia dla niego dysku.

Aktualizacja : Musisz również wykonać poniższe czynności, aby utworzyć plik wymiany:

umount /mnt
service walinuxagent restart
Bruno Faria
źródło
Zapewnienie dysku jest kontrolowane przez Cloud Init na Ubuntu, w przeciwieństwie do innych dystrybucji. Więc nie, to nie powinno działać, a zarówno doc, jak i mój test to potwierdzają.
bitinn
2
I skontaktowany nośnik MS i okazało się, że rozwiązanie to ustawienie ResourceDisk.Format, ResourceDisk.EnableSwapi ResourceDisk.SwapSizeMB. ALE ważnym krokiem jest zrobienie instrukcji, sudo service walinuxagent restartaby utworzyć plik wymiany, ponieważ sam restart serwera nie działa dla mnie.
bitinn
Nadal pytam o to, jak Cloud Init bierze w tym udział, ponieważ ich komentarze doc i waagent.conf wprowadzają w błąd.
bitinn
Tak. Przepraszam. zapomniałem dołączyć restart agenta. Testowałem na moim Ubuntu VM i pracowałem bez problemów. Zaktualizowałem odpowiedź. Jeśli chodzi o inicjowanie w chmurze, nie sądzę, aby miało to w ogóle związek z tworzeniem pliku wymiany, ponieważ agent tworzy plik na partycji ext4 (/ mnt). Nie tworzy partycji wymiany.
Bruno Faria,
2
Nie działał na maszynie Wirtualnej Ubuntu 14.04 LTS, utworzonej z obrazu galerii Azure. Po wykonaniu wszystkich kroków swapon -snadal wyświetla pustą listę plików wymiany.
JustAMartin
2

Odpowiedź Bruno jest świetnym punktem wyjścia, ale zadziałała dopiero po ponownym uruchomieniu i dała mi kolejną minutę po uruchomieniu.

za. Włącz zamianę /etc/waagent.conf, odpowiednie linie:

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.

b. Wykonaj następujące czynności jako root, co obejmuje ponowne uruchomienie komputera:

umount /mnt
service walinuxagent restart
reboot

do. Po uruchomieniu nadal zajmie trochę czasu, zanim zamiana zostanie faktycznie włączona. Możesz to sprawdzić za pomocą swapon -s.

kqw
źródło
1

Uważam, że właściwym sposobem na zrobienie tego, aby zarówno inicjator chmury, jak i osoba obsługująca grę bawili się „dobrze” razem (z dokumentów Azure na platformie Azure-Init ), jest ustawienie tych wartości na tym

# 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

Próbowałem zmienić punkt montowania, ale wyglądało na to, że nie działa poprawnie, więc dokumenty prawdopodobnie są dokładne w kwestii wartości

Następnie możesz dostosować opcje zamiany, jak chcesz

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

# Size of the swapfile.
ResourceDisk.SwapSizeMB=8192

Podstawowe ponowne uruchomienie odbiera nową wymianę w porządku

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
FearlessHyena
źródło
0

Przeczytałem sporo postów na ten temat, ale nadal nie jestem pewien, jakie jest właściwe podejście, zakładając: 1. Mam domyślną maszynę wirtualną Ubuntu 14.04 LTS utworzoną przez platformę Azure i działającą na platformie Azure, która nie jest dostępna z wymianą 2. I chciałby utworzyć swap przy użyciu istniejącego magazynu VM, zamiast tworzyć nowy dysk przy użyciu dodatkowego magazynu

Potrzebowałem tego również (właściwie 16.04 zamiast 14.04, ale myślę, że moja odpowiedź będzie dotyczyła obu).

Posty, które przeczytałem:

Ale kiedy zobaczyłem, że muszę czytać tak długie eseje, że zwracacie uwagę, zamierzałem się poddać ... Ale nagle przypomniałem sobie bardzo prosty artykuł na blogu DigitalOcean:

Jak dodać Zamień na Ubuntu 14.04

To takie proste, że napisałem nawet dla niego skrypt (przynajmniej w najlepszym razie, jeszcze nie ustawienia swapiness i inne zaawansowane rzeczy):

#!/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))

Aby powyższe zadziałało, musisz sudo apt install fsharpnajpierw (przynajmniej Ubuntu 16.04 ma fsharp w repozytoriach, nie jestem pewien co do 14.04).

Potrzebujesz również tego InfraTools.fspliku:

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())

Omówiono wiele rozwiązań, ale nie mogę znaleźć takiego, który będzie się utrzymywał po ponownym uruchomieniu serwera

Część, która sprawia, że ​​moja odpowiedź działa poprzez restart serwera, to zapis do pliku / etc / fstab.

Zaletą tego rozwiązania jest to, że powinno ono działać na platformie Azure, DigitalOcean, YouNameIt, ...

Cieszyć się!

knocte
źródło
2
„To takie proste”, po którym następuje 50 linii kodu, wydaje się trochę oksymoronem!
kqw