vHoge

VMwareのアレコレ備忘録。CLIでがんばるネタ多め。

Salt でサーバに味付けを

こちらの投稿は vExperts Advent Calendar 2021 の 13 日目になります。
今回は大変長くなっております(`・ω・´)
adventar.org

Salt とは?

SaltStack 社により開発が行われていた Python 製のオープンソースな構成管理ツール。
構成管理ツールというと Chef や Puppet、Ansible が有名。
後発だが、初版リリースは Ansible より早いらしい。

2020 年に VMware 社が SaltStack 社を買収したことにより、VMware ファミリーの一員となり、vRealize Automation 8.3 から「vRealize Automation SaltStack Config」、「vRealize Automation SaltStack SecOps」として組み込まれています。
blogs.vmware.com www.vmware.com
なお、Salt のコア部分については VMware 社支援のもと、今まで通りオープンソースプロジェクトとして開発が進んでいます。 github.com
なので…
Salt は VMwareポートフォリオの 1つです
Salt は VMwareポートフォリオの 1つです
大事なことなので(ry

アーキテクチャ

Salt はクライアント/サーバモデルとなっており、Master と呼ばれるコントローラサーバと Minion と呼ばれる各クライアント環境で動くエージェントで構成されます。
Master-Minion 間は SSH は使わず、4505/TCP、4506/TCP で ZeroMQ によるメッセージングライブラリを介して通信を行います。
f:id:masahiroirie:20211212000609j:plain

エージェントとなると各 OS にインストールとなるので、LinuxWindows 等の PC 用の汎用的な OS になってしまうのですが、Salt Proxy Minion を利用することで、Proxy Minion から制御対象に対し APISSH 経由で構成管理を行うことができます。
f:id:masahiroirie:20211212000646j:plain
基本は Minion インストールによるエージェント型なのですが、Salt SSH という方式を使うことで、対象に Minion をインストールすることなく、Master から SSH 経由で管理を行うことも可能。
ただし、Minion に比べると遅いので、初回の Minion インストールや事情により Minion が利用できないケースに使うことが推奨なようです。

インストール

今回は Ubuntu 20.04 の VM に公式リポジトリからapt でインストール。
repo.saltproject.io

Master

mirie@salttest01:~$ sudo curl -fsSL -o /usr/share/keyrings/salt-archive-keyring.gpg https://repo.saltproject.io/py3/ubuntu/20.04/amd64/latest/salt-archive-keyring.gpg
mirie@salttest01:~$ echo "deb [signed-by=/usr/share/keyrings/salt-archive-keyring.gpg arch=amd64] https://repo.saltproject.io/py3/ubuntu/20.04/amd64/latest focal main" | sudo tee /etc/apt/sources.list.d/salt.list
mirie@salttest01:~$ sudo apt update
mirie@salttest01:~$ sudo apt install salt-master

salt-master はとりあえずであれば設定不要。
コレで salt-master のプロセスが起動し、4505/TCP、4506/TCP が LISTEN になっていればおけ。

Minion

リポジトリは同じで、インストール対象が salt-minion に。

mirie@minion01:~$ sudo apt install salt-minion

salt-minion の設定として、salt-master の指定を conf に行う。

mirie@minion01:~$ echo "master: 192.168.100.153" | sudo tee -a /etc/salt/minion
mirie@minion01:~$ sudo systemctl restart salt-minion

こちらは salt-minion のプロセスが起動すれば一旦おけ。

ちなみに Windowsインストーラで Minion をインストールできます。(Master は無さげ)

インストーラでのインストール

インストーラのダウンロードはこちらから。 docs.saltproject.io f:id:masahiroirie:20211208180741j:plain f:id:masahiroirie:20211208180751j:plain f:id:masahiroirie:20211208180803j:plain インストーラの中で Master 指定/識別名指定。 f:id:masahiroirie:20211208180817j:plain f:id:masahiroirie:20211208180917j:plain f:id:masahiroirie:20211208180932j:plain

Minion の認証

Master 指定があっていれば、salt-master で Minion の Key が見えるように。

mirie@salttest01:~$ sudo salt-key -L
Accepted Keys:
Denied Keys:
Unaccepted Keys:
minion01
Rejected Keys:

心当たりがあれば Accept してやる。

mirie@salttest01:~$ sudo salt-key -A
The following keys are going to be accepted:
Unaccepted Keys:
minion01
Proceed? [n/Y] Y
Key for minion minion01 accepted.

これで Master と各 Minion がやりとりするように。

機能

結構多機能なようで触り切れてないのですが、ひとまず自動化・構成管理まわりのトピックとして "Grains""Remote Execution""State" を紹介。
他にも beacon とか reactor とか salt-runner とか色々あるらしいのですが、また機会があれば(←まだ触れてない)

Grains

Salt において、 管理対象のハード情報や OS 情報、ネットワーク情報などあまり変更されない静的に近いシステム情報のことを Grains と言います。
Master から対象 Minion の Grains を取得し参照が可能です。

grains.items の結果(長い)

mirie@salttest01:~$ sudo salt 'minion01' grains.items
minion01:
    ----------
    biosreleasedate:
        11/12/2020
    biosversion:
        6.00
    cpu_flags:
        - fpu
        - vme
        - de
        - pse
        - tsc
        - msr
        - pae
        - mce
        - cx8
        - apic
        - sep
        - mtrr
        - pge
        - mca
        - cmov
        - pat
        - pse36
        - clflush
        - mmx
        - fxsr
        - sse
        - sse2
        - syscall
        - nx
        - mmxext
        - fxsr_opt
        - pdpe1gb
        - rdtscp
        - lm
        - constant_tsc
        - rep_good
        - nopl
        - tsc_reliable
        - nonstop_tsc
        - cpuid
        - extd_apicid
        - pni
        - pclmulqdq
        - ssse3
        - fma
        - cx16
        - sse4_1
        - sse4_2
        - x2apic
        - movbe
        - popcnt
        - aes
        - xsave
        - avx
        - f16c
        - rdrand
        - hypervisor
        - lahf_lm
        - extapic
        - cr8_legacy
        - abm
        - sse4a
        - misalignsse
        - 3dnowprefetch
        - osvw
        - topoext
        - ssbd
        - ibpb
        - vmmcall
        - fsgsbase
        - bmi1
        - avx2
        - smep
        - bmi2
        - rdseed
        - adx
        - smap
        - clflushopt
        - clwb
        - sha_ni
        - xsaveopt
        - xsavec
        - xgetbv1
        - xsaves
        - clzero
        - wbnoinvd
        - arat
        - umip
        - rdpid
        - overflow_recov
        - succor
    cpu_model:
        AMD Ryzen 7 4800U with Radeon Graphics
    cpuarch:
        x86_64
    cwd:
        /
    disks:
        - sr0
    dns:
        ----------
        domain:
        ip4_nameservers:
            - 192.168.100.2
        ip6_nameservers:
        nameservers:
            - 192.168.100.2
        options:
        search:
            - home.lab
        sortlist:
    domain:
    efi:
        False
    efi-secure-boot:
        False
    fqdn:
        minion01
    fqdn_ip4:
        - 127.0.1.1
    fqdn_ip6:
    fqdns:
        - minion01
    gid:
        0
    gpus:
        |_
          ----------
          model:
              SVGA II Adapter
          vendor:
              vmware
    groupname:
        root
    host:
        minion01
    hwaddr_interfaces:
        ----------
        ens192:
            00:50:56:8d:87:a3
        lo:
            00:00:00:00:00:00
    id:
        minion01
    init:
        systemd
    ip4_gw:
        192.168.100.1
    ip4_interfaces:
        ----------
        ens192:
            - 192.168.100.154
        lo:
            - 127.0.0.1
    ip6_gw:
        False
    ip6_interfaces:
        ----------
        ens192:
            - fe80::250:56ff:fe8d:87a3
        lo:
            - ::1
    ip_gw:
        True
    ip_interfaces:
        ----------
        ens192:
            - 192.168.100.154
            - fe80::250:56ff:fe8d:87a3
        lo:
            - 127.0.0.1
            - ::1
    ipv4:
        - 127.0.0.1
        - 192.168.100.154
    ipv6:
        - ::1
        - fe80::250:56ff:fe8d:87a3
    kernel:
        Linux
    kernelparams:
        |_
          - BOOT_IMAGE
          - /boot/vmlinuz-5.4.0-91-generic
        |_
          - root
          - None
        |_
          - ro
          - None
        |_
          - maybe-ubiquity
          - None
    kernelrelease:
        5.4.0-91-generic
    kernelversion:
        #102-Ubuntu SMP Fri Nov 5 16:31:28 UTC 2021
    locale_info:
        ----------
        defaultencoding:
            UTF-8
        defaultlanguage:
            en_US
        detectedencoding:
            utf-8
        timezone:
            UTC
    localhost:
        minion01
    lsb_distrib_codename:
        focal
    lsb_distrib_description:
        Ubuntu 20.04.2 LTS
    lsb_distrib_id:
        Ubuntu
    lsb_distrib_release:
        20.04
    lvm:
        ----------
    machine_id:
        23480b5e791e447eb52bd5e85909d52f
    manufacturer:
        VMware, Inc.
    master:
        192.168.100.153
    mdadm:
    mem_total:
        7962
    nodename:
        minion01
    num_cpus:
        2
    num_gpus:
        1
    os:
        Ubuntu
    os_family:
        Debian
    osarch:
        amd64
    oscodename:
        focal
    osfinger:
        Ubuntu-20.04
    osfullname:
        Ubuntu
    osmajorrelease:
        20
    osrelease:
        20.04
    osrelease_info:
        - 20
        - 4
    path:
        /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
    pid:
        227322
    productname:
        VMware Virtual Platform
    ps:
        ps -efHww
    pythonexecutable:
        /usr/bin/python3
    pythonpath:
        - /usr/bin
        - /usr/lib/python38.zip
        - /usr/lib/python3.8
        - /usr/lib/python3.8/lib-dynload
        - /usr/local/lib/python3.8/dist-packages
        - /usr/lib/python3/dist-packages
    pythonversion:
        - 3
        - 8
        - 10
        - final
        - 0
    saltpath:
        /usr/lib/python3/dist-packages/salt
    saltversion:
        3004
    saltversioninfo:
        - 3004
    serialnumber:
        VMware-42 0d f1 47 3e f6 10 7b-57 b0 71 dc af 55 22 6c
    server_id:
        1293882994
    shell:
        /bin/sh
    ssds:
        - sda
    swap_total:
        4095
    systemd:
        ----------
        features:
            +PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN2 -IDN +PCRE2 default-hierarchy=hybrid
        version:
            245
    systempath:
        - /usr/local/sbin
        - /usr/local/bin
        - /usr/sbin
        - /usr/bin
        - /sbin
        - /bin
        - /snap/bin
    transactional:
        False
    uid:
        0
    username:
        root
    uuid:
        47f10d42-f63e-7b10-57b0-71dcaf55226c
    virtual:
        VMware
    zfs_feature_flags:
        False
    zfs_support:
        False
    zmqversion:
        4.3.2

システム情報以外にも、/etc/salt/grainYAML 形式でユーザ定義することが可能です。
これを使うことで、例えばサーバグルーピングやメタ情報付与といったことが可能になり、また、それらを利用した対象指定の条件ができます。

# Grains より OS が Ubuntu のものに test.ping を実行
# (1台しかないので分かり難いけど…)
mirie@salttest01:~$ sudo salt -G 'os:Ubuntu' test.ping
minion01:
    True

Remote Execution

端的に言うと psshfabric みたいなもので、Minion としてぶら下がっている対象に対して一斉にコマンドを発行することができます。

mirie@salttest01:~$ sudo salt '*' cmd.run 'uname -a'
minion01:
    Linux minion01 5.4.0-91-generic #102-Ubuntu SMP Fri Nov 5 16:31:28 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

コマンド実行ができればどうにでもなりますが、汎用的なものや API を叩くようなものは Execition Module として用意されています。
また、それでも足りないものは自分で独自に拡張することも可能です。

# nginx インストール
mirie@salttest01:~$ sudo salt '*' pkg.install nginx
minion01:
    ----------
    fontconfig-config:
        ----------
        new:
            2.13.1-2ubuntu3
        old:
【中略】
    nginx:
        ----------
        new:
            1.18.0-0ubuntu1.2
        old:
    nginx-common:
        ----------
        new:
            1.18.0-0ubuntu1.2
        old:
    nginx-core:
        ----------
        new:
            1.18.0-0ubuntu1.2
        old:

# nginx の configtest
mirie@salttest01:~$ sudo salt '*' nginx.configtest
minion01:
    ----------
    comment:
        Syntax OK
    result:
        True
    stdout:
        nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
        nginx: configuration file /etc/nginx/nginx.conf test is successful

# systemctl からの nginx restart
mirie@salttest01:~$ sudo salt '*' service.restart nginx
minion01:
    True

Execution Module として準備されてるものは以下のページに。
docs.saltproject.io

State

基本的な実行

IaC 的に構成をファイルに記述し、ツールがそれに従って一連のコマンドを実行し、構成や設定を投入するやり方。
Salt だとそのファイルは State と呼ばれ、YAML 形式の sls ファイルで構成を記述します。
↑ と同じように nginx インストール → configtest → restart を構成すると以下。

# デフォルトだと /srv/salt の下を見に行く。
mirie@salttest01:~$ cat /srv/salt/nginx_install.sls
nginx_test:
  pkg.installed:
    - pkgs:
       - nginx

configtest:
  cmd.run:
    - name: /usr/sbin/nginx -t
    - require:
      - nginx_test

nginx_restart:
  cmd.run:
    - name: 'salt-call service.restart nginx'
    - require:
      - nginx_test

これで、salt コマンドで state.apply にて、対象ホストと state を指定すると定義した内容に従ってインストールやコマンドが実行されます。

mirie@salttest01:~$ sudo salt '*' state.apply nginx_install
minion01:
----------
          ID: nginx_test
    Function: pkg.installed
      Result: True
     Comment: The following packages were installed/updated: nginx
     Started: 14:00:22.884601
    Duration: 5405.443 ms
     Changes:
              ----------
              nginx:
                  ----------
                  new:
                      1.18.0-0ubuntu1.2
                  old:
----------
          ID: configtest
    Function: cmd.run
        Name: /usr/sbin/nginx -t
      Result: True
     Comment: Command "/usr/sbin/nginx -t" run
     Started: 14:00:28.291968
    Duration: 11.563 ms
     Changes:
              ----------
              pid:
                  352955
              retcode:
                  0
              stderr:
                  nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
                  nginx: configuration file /etc/nginx/nginx.conf test is successful
              stdout:
----------
          ID: nginx_restart
    Function: cmd.run
        Name: salt-call service.restart nginx
      Result: True
     Comment: Command "salt-call service.restart nginx" run
     Started: 14:00:28.303740
    Duration: 875.27 ms
     Changes:
              ----------
              pid:
                  352957
              retcode:
                  0
              stderr:
              stdout:
                  local:
                      True

Summary for minion01
------------
Succeeded: 3 (changed=3)
Failed:    0
------------
Total states run:     3
Total run time:   6.292 s

State でのホスト指定

数台規模であれば CLI からのホスト指定/ state 指定でもどうにかなりますが、多数のホストに多数の state を管理となってくるとどのホストにどの state かをイチイチ指定していくのはシンドい…
top.sls というファイルに対象ホストや state を指定することで対象と state の管理が可能。

mirie@salttest01:~$ cat /srv/salt/top.sls
base:
  '*':
    - init_server
  'minion01':
    - nginx_install
  'minion02':
    - mysql_install

saltstate.apply にて state 指定なしで top.sls の定義に従って実行されます。

# top.sls に従って全 Minion を実行
mirie@salttest01:~$ sudo salt '*' state.apply

# 特定の対象だけも指定可能
mirie@salttest01:~$ sudo salt 'minion01' state.apply

補:State ファイルの話

State は YAML ファイルと言ったな
あれは嘘だ

State ファイルは YAML 形式のファイルと書きましたが、実は Jinja2 テンプレートなので、ちょっとしたロジックを仕込むことも可能です。
例えば Grains の OS 種類から apache のパッケージ指定するとこんな感じに。

apache:
  pkg.installed:
    {% if grains['os'] == 'RedHat' %}
    - name: httpd
    {% elif grains['os'] == 'Ubuntu' %}
    - name: apache2
    {% endif %}

docs.saltproject.io ちなみに State ファイルにはパスワードとか暗号化キー、可変的な Value を直書きするのはよろしくなく、その辺は pillar という別の機構に格納し、State からは {{ pillar['hoge] }} みたいな形で参照するのがお作法的には正しいようです。

所感

エージェント型となると導入が面倒ではありますが、その分できることは豊富。
Remote Execution だったり、今回は試してないですが、beacon とか salt-runner 辺りが使いこなせればさらに構成管理や日常運用が楽になりそう?
また、エージェント導入も Salt SSH でカバーできたりで大きなマイナスではないかも。

ネックはとにかく情報量の少なさ…
利用が増え、情報量が増えたりモジュール開発がより活発になれば、他の構成管理ツールより強力なツールになり得るポテンシャルは十分に秘めていそうです。

ところで vRealize Automation SaltStack Config は何するの?

そんな Salt の GUIダッシュボード、統合管理、認証、監査ログなどなど、エンタープライズ向け機能が追加されているものが旧 SaltStack Enterprise で、現在で言うところの vRealize Automation SaltStack Config になります。
(Ansible における Ansible Tower みたいな感じ?)

で、試してみようと思うわけですが…MyVMware を見てみると
f:id:masahiroirie:20211208200632p:plain
Download できず。試用不可。

vExpert Portal 上にも何もなく、入手すら不可という状態…orz
(ライセンスは vRealize Suite でいける?)
そのうち検証版出たりするかなぁ。

Appendix

2021/12/15 に開催される VMware DevOps Meetup #11 にて Salt で話をします! vmware.connpass.com ブログ内容ベースにこぼれたネタ + デモを入れる予定ですが、話のボリュームが…

参考サイト

saltproject.io

docs.saltproject.io

docs.vmware.com

www.ipswitch.com

toe.bbtower.co.jp