SaltStack基础(3) – 执行命令

安装saltstack后,已经可以执行shell命令,更新软件包和同时分发文件到所有minions。minions执行命令后会以一致地和可配置的格式返回结果,这样你就可以很容易地查看执行了什么和工作正不正常。

执行shell命令

你可以使用cmd.run在salt master上向所有的minion发送一个shell命令来执行:

  1. salt ‘*’ cmd.run ‘ls -l /etc’

所有的minion将同时执行这个命令并立即返回结果给salt master。
运维自动化

salt执行函数

使用cmd.run执行shell命令当然是有用的,不过saltstack强大的功能是使用salt执行函数。salt社区已经投入很多努力创建数百个函数来简单大部分的管理任务。甚至同一个函数能在所有支持的系统上使用。

显示硬盘使用

  1. salt ‘*’ disk.usage

运维自动化

安装一个包

  1. salt ‘*’ pkg.install cowsay

运维自动化

列出网络接口

  1. salt ‘*’ network.interfaces

运维自动化

SaltStack基础(2) – 安装saltstack

你可以从包管理器,pip,源码编译或使用bootstrap脚本安装saltstack。saltstack也提供独立的工具来创建机器和在公有和私有云安装saltstack(salt-cloud和salt-virt)。我们这里没有涉及到这些工具,不过只要你有一个系统需要管理,慢慢就会了解这些,saltstack在物理的,云和虚拟资源中使用都相同。

安装

如果你使用的是上一篇文章介绍的Vagrant工程,那么saltstack已经安装了并且已经接受每一个minion的连接。你可以根据下面段落中“接受连接”的方法来验证你的minions是否已经连接。
如果你使用的是不同的环境,安装saltstack最简单的方法是使用bootstrap脚本。执行这个脚本的两个命令就可以在大多数操作系统上安装saltstack。

接受连接

salt master和salt minion之间的每一个连接都使用加密密钥进行管理和保护。安装完成后,每一个salt minion发送它的公钥到salt master,等待连接被接受。salt minion密钥必须先被接受才能在系统上执行来自salt master的命令。
在命令行提示符,cd进入vagrant-demo-master目录,执行如下命令进入salt master:

  1. vagrant ssh master

连接后,执行如下命令来切换到root用户:

  1. sudo su

运维自动化

查看所有密钥

在salt master,你可以快速查看所有的salt minion连接和查看连接是否被接受,拒绝或待定。

  1. salt-key –list-all

接受指定密钥

你必须接受minion的密钥,它才能连接。

  1. salt-key –accept=<key>

接受所有密钥

  1. salt-key –accept-all

运维自动化

发送命令

你接受每一个密钥后,从salt master发送一个命令来验证salt minions是否在监听。

  1. salt ‘*’ test.ping

运维自动化

SaltStack基础(1) – demo环境搭建

salt基础系统将涉及如下几个方面:

  • 安装saltstack
  • 在受管系统运行命令
  • 定义可重复使用的配置
  • 将命令和配置应用于特定系统
  • 学习SaltStack最好的方法是做各种试验。你可以通过阅读本系列文章对saltstack有一个初步了解,saltstack非常容易配置,这里我们提供几个示例来帮助你学习。另外你可以保留你的demo环境继续做其它试验。

    demo环境

    完成如下步骤来配置一个简单的saltstack环境。

  • 1.安装VirtualBox
  • 2.安装Vagrant
  • 3.下载https://github.com/UtahDave/salt-vagrant-demo。你可以使用git或直接从GitHub下载zip包
  • 4.解压下载的zip文件,然后把目录切换到解压出来的目录
  • windows:

    1. cd %homepath%Downloadssalt-vagrant-demo-master

    Mac:

    1. cd ~Downloadssalt-vagrant-demo-master
  • 5.运行vagrant up来启动demo环境
    1. vagrant up

    大约等待10分钟后,demo环境就搭建好了。

    Docker实践(19) – 保留容器的bash历史记录

    我们知道在容器内做试验完成时,容器可以设置自动清除,这就省了好多事。不过仍然有一些不方便的地方。其中一个是我们可能需要在容器中多次执行一个相同的命令,而bash历史又没有了,只能手打。

    问题

    你想与容器共享你的主机bash历史记录。

    解决方法

    为docker run命令设置一个别名来与主机共享bash历史记录。

    讨论

    要理解这个问题,我们来展示一个场景。
    假设你在Docker容器做试验,比如做一些有趣的和可重复使用的东西。这里我们使用echo命令,但这可能是一个长且复杂的一连串程序:

    1. $ docker run -ti –rm ubuntu /bin/bash
    2. $ echo my amazing command
    3. $ exit

    过了一些时间,你想重新执行之间执行过的复杂的echo命令。不过,你不记得命令了,而且终端会话也找不到这个命令,你尝试找bash历史记录,但没有任何输出:

    1. $ history | grep amazing

    为了解决这个问题,我们可以在你运行docker镜像时挂载一个volume,如下:

    1. $ docker run -e HIST_FILE=/root/.bash_history
    2.  -v=$HOME/.bash_history:/root/.bash_history
    3.  -ti ubuntu /bin/bash

    命令太长太难记了,我们把它设置为一个别名吧,在~/.bashrc文件中添加:

    1. $ alias dockbash=’docker run -e HIST_FILE=/root/.bash_history
    2.  -v=$HOME/.bash_history:/root/.bash_history

    这个体验仍然不好,因为当你要执行docker run命令时都要记住执行dockerbash命令。要获得更加无缝的体验,你您可以将这些添加到〜/ .bashrc文件:

    1. function basher() {
    2.   if [[ $1 = ‘run’ ]]
    3.   then
    4. shift
    5. /usr/bin/docker run
    6.   -e HIST_FILE=/root/.bash_history
    7.   -v $HOME/.bash_history:/root/.bash_history "$@"
    8.    else
    9.     /usr/bin/docker "$@"
    10. fi
    11. }alias docker=basher

    现在当你打开bash shel并执行任意的docker run命令时都会自动把bash历史记录的设置添加到命令中去。

    Docker实践(18) – 使用BitTorrent Sync分发volumes

    在团队中试用Docker时,你可能希望能够在团队成员之间共享大量数据,不过你可能没有足够的空间来搭建一台共享服务器。最简单的方法是当你需要时再从其它团队成员复制最新的文件 – 不过在一个更大的团队中这个方法就不太可行了。
    解决方案是使用BitTorrent Sync工具来共享文件 – 不需要专门的资源。

    问题

    你想通过internet在主机之间共享volumes。

    解决方法

    使用BitTorrent Sync镜像来共享volume。

    讨论

    下图说明了这个方法是如何运作的。
    虚拟化技术
    最终结果是通过因特网方便地同步的卷(/data),不需要任何复杂的设置。
    执行如下命令在第一台主机上设置容器:

    1. [host1]$ docker run -d -p 8888:8888 -p 55555:55555 –name btsync ctlc/btsync
    2. $ docker logs btsync
    3. Starting btsync with secret: ALSVEUABQQ5ILRS2OQJKAOKCU5SIIP6A3
    4. By using this application, you agree to our Privacy Policy and Terms.
    5. http://www.bittorrent.com/legal/privacy
    6. http://www.bittorrent.com/legal/terms-of-use
    7. total physical memory 536870912 max disk cache 2097152
    8. Using IP address 172.17.4.121
    1. [host1]$ docker run -i -t –volumes-from btsync ubuntu /bin/bash
    2. $ touch /data/shared_from_server_one
    3. $ ls /data
    4. shared_from_server_one

    在第二个服务器,打开一个终端运行这些命令来同步volume:

    1. [host2]$ docker run -d –name btsync-client -p 8888:8888 -p 55555:55555 ctlc/btsync ALSVEUABQQ5ILRS2OQJKAOKCU5SIIP6A3
    1. [host2]$ docker run -i -t –volumes-from btsync-client ubuntu bash
    2. $ ls /data
    3. shared_from_server_one
    4. $ touch /data/shared_from_server_two
    5. $ ls /data
    6. shared_from_server_one  shared_from_server_two

    回到第一台主机运行的容器,你应该能看到第二台主机的创建的文件了:

    1. [host1]$ ls /data
    2. shared_from_server_one  shared_from_server_two

    理解SaltStack(8) – Python

    我知道我们之前有说过使用Salt不需要会写Python和其它代码,这当然是真的。不过会读Python代码在许多情况下会有所帮助,或者至少会读Python函数文档。
    本文介绍Python基础知识,帮助你更好地了解salt的工作原理。

    模块

    Salt中,每个子系统插件是一个Python模块。你可以认为salt模块是一组函数(又称命令)组成,用来管理应用(mysql.docker),系统组件(硬盘,文件)或与外部系统(gitfs)交互。
    你需要了解几点:

  • 所有的模块都在源文件夹的salt目录。每个子系统是一个单独的目录,每个模块是一个单独的python文件
  • 模块以salt.subsystem.module格式命名。此命令空间在文档中可找到,所以你可以快速识别目前在看哪个子系统模块。唯一一个令人困惑的是:执行模块以salt.module开头,是由于这个模块是初始版本中的第一个模块并且只有这个模块可用。
  • 模块包含了我们需要的多个或少量的函数。由于文件管理需要做的事情非常多,所以文件执行模块(salt.modules.file)包含了非常多的函数。而uwsgi统计服务器执行模块(salt.modules.uwsgi)只有一个函数。
  • 函数

    所以你理解了以上的模块,函数应该就更简单了。你可以认为函数是在模块中指定的命令,能调用来管理和配置文件。例如,salt.modules.pkg.install, salt.modules.network.interfaces和salt.modules.user.add都是常见的执行模块函数。函数相当于salt的动词,你通常可以打开模块文档并查看函数名称来决定使用哪个函数。

    参数

    参数有一点复杂,特别是如果是对关键词参数不是很熟悉,参数很可能是你准备入门salt遇到问题的地方。
    远程执行和状态之间的参数不太一样,我们来分别讨论。

    执行函数参数

    当在命令行调用salt时,执行参数作为附加值传递过去,或者作为一个值,或者作为argument = value。必需值通常以空格分隔并以指定顺序传递,带默认值的可选参数以argument=value格式传递。
    例如,我们来看下salt.modules.useradd.add函数:

    1. salt.modules.useradd.add(name, uid=None, gid=None, groups=None, home=None,
    2. shell=None, unique=True, system=False, fullname=”, roomnumber=”,
    3. workphone=”, homephone=”, createhome=True, loginclass=None)

    当调用这个模块,参数name是必需的,你可以看到它没有默认值。其余的参数会使用列出的值,除非你传一个不同的值来覆盖。下面的例子是创建一个用户名为Fred并设置一个不同的默认shell:

    1. salt ‘*’ user.add fred shell=/bin/zsh

    更多的例子
    常规参数和关键字参数(通常缩写为args和kwargs)是你将遇到的最常见的类型。下面的例子传递一个arg和3个kwargs:

    1. salt ‘*’ network.connect google-public-dns-a.google.com port=53 proto=udp timeout=3

    传递两个args和一个kwarg:

    1. salt ‘*’ cp.get_file salt://vimrc /etc/vimrc gzip=5

    一些执行模块接收列表值:

    1. `salt ns1 pkg.install pkgs=[‘bind9′,’bind9-docs’,’bind-utils’]`

    一些甚至可以传字典类型:

    1. `salt ‘*’ pkg.install sources='[{"foo": "salt://foo.deb"},{"bar": "salt://bar.deb"}]’`

    state函数参数

    State函数在state文件中使用YAML语法调用。YAML语法非常适合表示数据类型,所以你会发现调用具有复杂数据类型的函数在state中更容易。为了弄清楚在state中如何添加用户,我们来看下salt.states.user.present函数:

    1. salt.states.user.present(name, uid=None, gid=None, gid_from_name=False,
    2. groups=None, optional_groups=None, remove_groups=True, home=None,
    3. createhome=True, password=None, hash_password=False, enforce_password=True,
    4. empty_password=False, shell=None, unique=True, system=False, fullname=None,
    5. roomnumber=None, workphone=None, homephone=None, loginclass=None, date=None,
    6. mindays=None, maxdays=None, inactdays=None, warndays=None, expire=None,
    7. win_homedrive=None, win_profile=None, win_logonscript=None,
    8. win_description=None)

    即使这个函数有许多参数,在YAML中调用带关键词参数的函数很容易:

    1. a state example that calls user.present:
    2. user.present:
    3.     – name: fred
    4.     – shell: /bin/zsh

    list类型在YAML中也很容易定义:

    1. install bind packages:
    2.   pkg.installed:
    3.     – pkgs:
    4.       – bind9
    5.       – bind9-docs
    6.       – bind-utils

    定义字典也比在命令行中容易:

    1. Install some packages using other sources:
    2.   pkg.installed:
    3.     – name: mypkgs
    4.     – sources:
    5.       – foo: salt://foo.deb
    6.       – bar: http://somesite.org/bar.deb

    理解SaltStack(7) – 系统数据

    本文讨论系统数据的两个主要方面:获取你系统的有关数据和为你的系统设置数据。salt为这两个任务分别提供了两个不同的子系统来完成:salt grains和salt pillar。
    本文还介绍了第三个组件,称为salt mine,用来从minion推送数据到master的共享数据存储上以便所有的minions能访问这些数据。

    GRAINS

    Grains用来获取你系统的数据。Grains是关于底层操作系统静态信息,如内存,硬盘和许多其它系统属性。
    当minion启动时,Grains自动收集信息,然后定期刷新或者使用远程执行命令。
    所以你用grains能做什么?你可以使用grain执行模块收集清单,可以列出所有grains,找到具有特定grain值的系统等。
    Grains也是minion系统的组成部分,也用来定位salt state和salt pillar数据。

    GRAINS如何收集数据?
    在之前的章节中你已经对插件有所了解,已经知道grains如何工作了。grains子系统有几个salt grains模块(又名插件)运行在minion来填充grains目录。grains与远程执行模块类似,每一个grain模块包含在各种OS的收集grain数据的逻辑(不是使用多个模块和__virtualname__)

    SALT PILLAR

    salt pillar用来传送数据到你的系统。想象一个当配置甚至是一个简单的系统时不同的自定义数据:用户名称,服务URL,首选安装路径,端口,非默认应用程序设置和许多其它的设置。通常这些值在每个系统或系统角色(web,数据库等)都不一样。
    salt pillar让你定义这些数据值,然后使用targets将它们分配给一个或多个minions。然后这些值可以作为变量在salt sates中使用。
    salt pilllar使用目标minions的公钥来加密数据和通过安全通道来发送,因此salt pillar也非常适合分发安全数据,如密码和ssh密钥,因为它只能由目标minon来解密。
    默认下salt pillar模块使用YAML文件来定义pillar,超过30个salt pillar模块用来支持各种后端。热门选项包括Mongo和Redis,都是非常适合存储结构数据的。许多用户坚持使用YAML文件,但使用一个私有git repo来管理和分发pillar数据。

    SALT MINE

    salt mine用来在salt minions之间共享数据值。例如如果你设置一个共享的数据库,你可以在数据库服务器上配置salt minion来自动推送它的IP到salt mine。这个方法比手动更新salt state或salt pillar的数据要好。
    当你需要这些值来配置系统时,你可以直接通过salt state文件来访问salt mine的数据。
    salt mine使用简单,最大的问题是许多用户不记得使用它。

    理解SaltStack(6) – salt runners

    runner子系统提供在salt master运行的salt模块(还记得执行和状态模块在目标服务器minion异步执行吗,不是在salt master)。
    Runners可用功能为列出作业状态,实时查看事件,管理salt文件服务器,查看salt mine数据,发送wake-on-lan到minions,调用webhooks和发送其它http请求等。

  • Runners由salt-run命令行接口调用。不需要指定目标因为目标是salt master。
  • salt runners的参数语法与salt执行模块的参数语法一样。
  • ORCHESTRATE RUNNER

    The orchestrate runner提供了salt的核心功能之一:以指定顺序在多个minions之间运行命令和应用配置的能力。例如,使用orchestrate runner你可以使用状态系统的全部功能来配置多个系统(包括必需条件,失败分支,依赖性,有序执行等)。

    Docker实践(17) – 容器挂载主机目录

    容器最强大的功能是它在迁移时能保持系统环境一致性。
    不过有时候你不想把所有的文件放进容器中。你可能想在容器之间共享一些大的文件,或者单独管理这些文件。典型的例子是你希望容器访问大型集中式数据库,但是还希望其它客户端也能与容器一起访问。
    解决方法是volumes,在容器生命周期外管理文件的Docker机制。虽然这违背了容器“部署在任何地方”的理念(例如,你将无法在没有挂载数据库的系统中部署容器),不过有时候在实际环境中不得不用。

    问题

    你想在容器内部访问主机的文件。

    解决方法

    使用Docker的volume参数来设置容器访问主机文件。

    讨论

    下面的命令显示主机的/var/db/tables目录被挂载到容器的/var/data1上。

    1. $ docker run -v /var/db/tables:/var/data1 -it debian bash

    -v参数(–volume)表明需要为容器设置一个外部的volume。随后的参数值是由两个以冒号分隔的目录组成,冒号之前的目录是主机目录,之后是容器目录,如果这两个目录不存在则会自动创建。
    下图说明容器访问主机目录是如何交互的:
    虚拟化技术

    Docker实践(16) – 引用特定镜像构建镜像

    在你构建镜像大多数时候会引用镜像名称,如“node”或”ubuntu”,这个没有任何问题。
    如果你引用镜像名称,它有可能tag名称保持一样而镜像被更改了。看起来这自相矛盾,不过它真实发生了!repository名称仅仅是个引用,它有可能被更改指向一个不同的镜像。指定一个带冒号的tag名称也不会消除这种风险,因为安全更新会使用相同的tag来自动重新构建有漏洞的镜像。
    大多数时候你会想让它这样做 – 镜像维护者对镜像有所改进,并修补了安全漏洞是一件好事。不过有时候可能会给你带来痛苦。这不仅仅是一个理论上的风险:这已经出现过很多次了,中断了持续交付且很难调试。在Docker早期,镜像会添加和删除软件包(包括,记忆中消失了的passwd命令),使构建镜像突然地中断。

    问题

    你想确保镜像的构建始终从一个指定的不会被更改的镜像。

    解决方法

    从一个指定的镜像ID构建。

    讨论

    对于你想决定确认从一个指定的镜像构建镜像时,可以在Dockerfile中指定镜像ID.
    下面是示例:

    1. FROM 8eaa4ff06b53
    2. RUN echo "Built from image id:" > /etc/buildinfo
    3. RUN echo "8eaa4ff06b53" >> /etc/buildinfo
    4. RUN echo "an ubuntu 14.4.01 image" >> /etc/buildinfo
    5. CMD ["echo","/etc/buildinfo"]

    像这样从一个指定的镜像ID构建镜像,这个镜像必须已经保存在了本地。Docker registry不会在Docker Hub搜索这个镜像ID的。
    注意你引用的镜像不需要tag。你可以从任意层来构建镜像。