如何为Azure Ubuntu VM创建交换?


9

我已经阅读了很多关于此的文章,但是我仍然不确定正确的方法,假设:

  1. 我有一个默认的Ubuntu 14.04 LTS VM,它由Azure创建并在Azure上运行,并且没有交换

  2. 我想使用现有的VM存储创建交换,而不是使用其他存储创建新磁盘

我读过的帖子:

讨论了许多解决方案,但我似乎找不到能在服务器重新启动后持续存在的解决方案(可能是由于cloud-init对映像分区具有自己的想法),有人可以建议我这样做吗?

Answers:


8

假设您已安装Linux代理。您要做的就是在/etc/waagent.conf下启用交换。这些是相关的行:

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.

它将自动使用资源磁盘(每个VM随附)来创建交换。无需为其创建磁盘。

更新:您还需要执行以下步骤以创建交换文件:

umount /mnt
service walinuxagent restart

与其他发行版不同,磁盘置备由Ubuntu上的Cloud Init控制。因此,不行,这行不通,文档和我的测试都对此进行了确认。
2015年

2
我接触MS支持,发现该溶液是设置ResourceDisk.FormatResourceDisk.EnableSwapResourceDisk.SwapSizeMB。但是重要的一步是手动sudo service walinuxagent restart创建交换文件,因为重启服务器对我不起作用。
bitinn

我仍在询问Cloud Init如何将所有这些因素考虑在内,因为他们的doc和waagent.conf注释具有误导性。
bitinn 2015年

对。对不起。忘记包括代理重新启动。我在ubuntu vm上进行了测试,并且工作正常。我已经更新了答案。关于cloud-init,我认为它与交换文件的创建完全没有关系,因为代理在ext4分区(/ mnt)内创建文件。它不会创建交换分区。
Bruno Faria 2015年

2
在从Azure Gallery映像创建的Ubuntu 14.04 LTS VM上不起作用。执行完所有步骤后,swapon -s仍然显示空白列表的交换文件。
JustAMartin

2

Bruno的答案是一个很好的起点,但是它只有在我重新启动并在启动后再等待一分钟后才起作用。

一个。在/etc/waagent.conf相关行中启用交换:

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。以root用户身份执行以下操作,其中包括重新引导计算机:

umount /mnt
service walinuxagent restart
reboot

C。引导后,仍然需要一些时间才能真正启用交换。您可以使用进行检查swapon -s


1

我相信这样做的正确方法是使cloud-init和waagent一起发挥“不错”的作用(来自Cloud-Init Azure文档)是将这些值设置为此

# 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

我尝试更改安装点,但是它似乎无法正常工作,因此文档可能对值很准确

然后您可以根据需要自定义交换选项

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

# Size of the swapfile.
ResourceDisk.SwapSizeMB=8192

基本重新启动会收取新的掉期罚款

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

0

我已经阅读了很多相关文章,但是我仍然不确定正确的方法,并假设:1.我有一个默认的Ubuntu 14.04 LTS VM,由Azure创建并在Azure上运行,并且没有交换2。想要使用现有VM存储创建交换,而不是使用其他存储创建新磁盘

我也需要这个(实际上是16.04而不是14.04,但我的答案将适用于我认为的两者)。

我读过的帖子:

但是,当我看到我不得不阅读冗长的文章以致您指出时,我将放弃……但是突然间,我想起了DigitalOcean博客中一篇非常简单的文章:

如何在Ubuntu 14.04上添加交换

非常简单,我什至为此写了一个脚本(至少在最好的情况下还没有交换设置和其他高级内容):

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

为了使以上功能sudo apt install fsharp生效,您需要首先(至少Ubuntu 16.04在存储库中具有fsharp,不确定14.04左右)。

您还需要此InfraTools.fs文件:

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

讨论了许多解决方案,但我似乎找不到能在服务器重新启动后持续存在的解决方案

通过服务器重新引导使我的答案起作用的部分是写入/ etc / fstab文件。

此解决方案的优点是,它应该可以在Azure,DigitalOcean,YouNameIt等环境中运行。

请享用!


2
“很简单”,后面紧跟着50行代码,这似乎有点矛盾!
kqw

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.