# puppet-sysctl模块

1. [先睹为快](https://newptone.gitbook.io/deployopenstackwithpuppet/base_modules/pages/-LeYyoPfVn6lANNBd6ey#先睹为快)
2. [代码讲解](https://newptone.gitbook.io/deployopenstackwithpuppet/base_modules/pages/-LeYyoPfVn6lANNBd6ey#代码讲解)
3. [扩展阅读](https://newptone.gitbook.io/deployopenstackwithpuppet/base_modules/pages/-LeYyoPfVn6lANNBd6ey#扩展阅读)&#x20;
4. [动手练习](https://newptone.gitbook.io/deployopenstackwithpuppet/base_modules/pages/-LeYyoPfVn6lANNBd6ey#动手练习)

`sysctl`命令被用于在内核运行时动态地修改内核的运行参数，系统可用的内核参数可在目录/proc/sys中查询。它包含了一些TCP/IP堆栈和虚拟内存系统的高级选项， 这可以让系统管理员提高对操作系统的性能进行调优。

本节要谈的`puppet-sysctl`模块是由个人维护的项目，其目的是在Puppet中提供管理sysctl的接口。

`puppet-sysctl`项目地址：<https://github.com/duritong/puppet-sysctl>

## 1.先睹为快

不想看下面大段的代码解析，已经跃跃欲试了？

OK，我们开始吧！

打开虚拟机终端并输入以下命令：

```
$ puppet apply -e 'sysctl::value { "net.ipv4.tcp_syncookies": value => "1"}'
```

这将开启内核中的`tcp_syscookieds`参数，常用于抵御`synflood`攻击。

我们打开`puppet-sysctl`模块下`manifests/base.pp`文件来一探究竟吧。

## 2.代码解析

### 2.1 `class sysctl::base`

`sysctl::base`是该模块仅有的一个类，其中的代码逻辑也非常简单，仅对`/etc/sysctl.conf`文件的所有者和权限进行了管理。

```
class sysctl::base {
  file { '/etc/sysctl.conf':
    ensure => 'present',
    owner  => 'root',
    group  => '0',
    mode   => '0644',
  }
}
```

### 2.2 `define sysctl::value`

`define sysctl::value`用于管理`/etc/sysctl.conf`文件中的配置项。这里，有三处值得展开解析。

```
define sysctl::value (
  $value,
  $key    = $name,
  $target = undef,
) {
  require sysctl::base
  $val1 = inline_template("<%= String(@value).split(/[\s\t]/).reject(&:empty?).flatten.join(\"\t\") %>")

  sysctl { $key :
    val    => $val1,
    target => $target,
    before => Sysctl_runtime[$key],
  }
  sysctl_runtime { $key:
    val => $val1,
  }
}
```

### 2.2.1 `require`函数

在`define sysctl::value`出现了`require`函数 (注意：与`require`元参数不同)，该函数可以声明一个或多个类，并与含有此函数的容器形成依赖关系。

```
require sysctl::base
```

在该例中，Puppet在执行`sysctl::value`实例前，确保`class sysctl::base`的所有资源已被应用。

### 2.2.2 `inline_template`函数

在`define sysctl::value`中出现了以下一段代码：

```
$val1 = inline_template("<%= String(@value).split(/[\s\t]/).reject(&:empty?).flatten.join(\"\t\") %>")
```

`inline_template`函数和`template`函数类似，可以简单地认为是只有一个字符串的模板。`inline_template`对模板求值后，生成字符串，常用于复杂的字符串拼接。

在前文中，已经提到标签`<%= %>`是插入值表达式，在该表达式中：首先对`$value`做字符串格式转换，然后以正则表达式`\s`和`\t`匹配进行字符串切割，去除空数组，对数组flatten操作，再做字符串连接。

#### 2.2.3 自定义资源类型

Puppet中有大量内置的资源类型，如`user`,`package`等等，同时用户也可以通过规范进行扩展，上述代码中的`sysctl`和`syscyl_runtime`是`puppet-sysctl`模块中自定义的资源类型，我们会在后文中详细讲解其代码结构和实现等细节。

### 2.3 `class sysctl::values`

`sysctl::values`的代码同样也非常简洁，主要是对`sysctl::value`进行了封装：

```
class sysctl::values($args, $defaults = {}) {
  create_resources(sysctl::value, $args, $defaults)
}
```

### 2.3.1 `create_resources`函数

`create_resources`函数接受一个hash类型的参数，将其转换为一个资源集合并添加到catalog中。这么讲比较抽象，我们可以来看一个实际的例子。

假设，接到其他部门的需求，需要在线上开启Linux内核的IP转发功能，要在开启该功能的节点上声明两个`sysctl::value`实例。

```
sysctl::value { 'net.ipv4.ip_forward':
  value => 1
}
sysctl::value { 'net.ipv6.conf.all.forwarding':
  value => 1
}
```

然而，在事前运维工程师是无法知道服务器需要开启哪些内核参数，按照第一章的`理解Hiera`一节中提到的节点数据不应该和节点数据放在一起，下面看如何借助`create_resources`函数来解决这个问题。 在节点定义文件中预先加入:

```
include ::sysctl::values
```

接着在`common.yaml`Hiera文件中加入：

```yaml
---
sysctl::values:args:
 net.ipv4.ip_forward:
   value: 1
 net.ipv6.conf.all.forwarding:
   value: 1
```

现在只需要对`sysctl::values:args`参数进行改动就能实现动态地管理服务器上的所有内核参数了！

## 3.扩展阅读

* <https://docs.puppet.com/puppet/latest/function.html#createresources>
* <https://docs.puppet.com/puppet/4.10/lang_template.html#with-a-template-string-inlinetemplate-and-inlineepp>
* <https://docs.puppet.com/puppet/4.10/lang_classes.html#using-require>

## 4.动手练习

1. 设置`net.ipv4.tcp_timestamps`参数为0
2. 设置`net.ipv4.tcp_rmem`参数为`4096` `131072` `131072`(多个值)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://newptone.gitbook.io/deployopenstackwithpuppet/base_modules/puppet-sysctl.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
