DevOps - 基础设施配置测试工具Serverspec
阅读原文时间:2023年07月09日阅读:2

1 - Serverspec

Serverspec是可以测试基础设施配置的工具,能够验证配置管理工具(Ansible、Puppet、Chef等)的配置结果,可以实现基础设施测试代码化自动化。

  • 测试代码即测试设计文档
  • 测试代码可以复用
  • 可以通过代码对测试用例进行评审
  • 使用类似YAML的固定格式编写测试用例
  • 可以通过安装gem软件包coderay将测试结果输出为HTML格式
  • 可以在安装了Serverspec的本地主机上进行测试,也可以通过ssh远程进行测试
  • 提供了配置文件和交互式两种使用方式

官网信息

2 - 安装

注意:必须事先安装有ruby,并且版本不能过低,负责安装会失败。

[root@localhost ~]# gem install serverspec
Fetching rspec-support-3.9.0.gem
Fetching diff-lcs-1.3.gem
Fetching sfl-2.3.gem
Fetching multi_json-1.14.1.gem
Fetching rspec-expectations-3.9.0.gem
Fetching specinfra-2.82.4.gem
Fetching net-ssh-5.2.0.gem
Fetching net-scp-2.0.0.gem
Fetching rspec-core-3.9.0.gem
Fetching rspec-its-1.3.0.gem
Fetching rspec-mocks-3.9.0.gem
Fetching rspec-3.9.0.gem
Fetching serverspec-2.41.5.gem
Successfully installed sfl-2.3
Successfully installed net-ssh-5.2.0
Successfully installed net-scp-2.0.0
Successfully installed specinfra-2.82.4
Successfully installed multi_json-1.14.1
Successfully installed diff-lcs-1.3
Successfully installed rspec-support-3.9.0
Successfully installed rspec-expectations-3.9.0
Successfully installed rspec-core-3.9.0
Successfully installed rspec-its-1.3.0
Successfully installed rspec-mocks-3.9.0
Successfully installed rspec-3.9.0
Successfully installed serverspec-2.41.5
Parsing documentation for sfl-2.3
Installing ri documentation for sfl-2.3
Parsing documentation for net-ssh-5.2.0
Installing ri documentation for net-ssh-5.2.0
Parsing documentation for net-scp-2.0.0
Installing ri documentation for net-scp-2.0.0
Parsing documentation for specinfra-2.82.4
Installing ri documentation for specinfra-2.82.4
Parsing documentation for multi_json-1.14.1
Installing ri documentation for multi_json-1.14.1
Parsing documentation for diff-lcs-1.3
Couldn't find file to include 'Contributing.rdoc' from README.rdoc
Couldn't find file to include 'License.rdoc' from README.rdoc
Installing ri documentation for diff-lcs-1.3
Parsing documentation for rspec-support-3.9.0
Installing ri documentation for rspec-support-3.9.0
Parsing documentation for rspec-expectations-3.9.0
Installing ri documentation for rspec-expectations-3.9.0
Parsing documentation for rspec-core-3.9.0
Installing ri documentation for rspec-core-3.9.0
Parsing documentation for rspec-its-1.3.0
Installing ri documentation for rspec-its-1.3.0
Parsing documentation for rspec-mocks-3.9.0
Installing ri documentation for rspec-mocks-3.9.0
Parsing documentation for rspec-3.9.0
Installing ri documentation for rspec-3.9.0
Parsing documentation for serverspec-2.41.5
Installing ri documentation for serverspec-2.41.5
Done installing documentation for sfl, net-ssh, net-scp, specinfra, multi_json, diff-lcs, rspec-support, rspec-expectations, rspec-core, rspec-its, rspec-mocks, rspec, serverspec after 15 seconds
13 gems installed
[root@localhost ~]#

3 - Serverspec设置

在CentOS系统下以本地主机模式运行,测试内容保存在spec/localhost/*_spec.rb文件中。

参考示例文件sample_spec.rb可以编写指定的测试内容。

[root@localhost ~]# pwd
/root
[root@localhost ~]# mkdir serverspec
[root@localhost ~]# cd serverspec
[root@localhost serverspec]# pwd
/root/serverspec
[root@localhost serverspec]#
[root@localhost serverspec]# serverspec-init
Select OS type:
​
  1) UN*X
  2) Windows
​
Select number: 1
​
Select a backend type:
​
  1) SSH
  2) Exec (local)
​
Select number: 2
​
 + spec/
 + spec/localhost/
 + spec/localhost/sample_spec.rb
 + spec/spec_helper.rb
 + Rakefile
 + .rspec
[root@localhost serverspec]# ll
total 4
-rw-rw-r-- 1 root root 685 Nov 20 09:48 Rakefile
drwxrwxr-x 3 root root  45 Nov 20 09:48 spec
[root@localhost serverspec]# tree
.
├── Rakefile
└── spec
    ├── localhost
    │   └── sample_spec.rb
    └── spec_helper.rb
​
2 directories, 3 files
[root@localhost serverspec]#
[root@localhost serverspec]# cat spec/localhost/sample_spec.rb
require 'spec_helper'
​
describe package('httpd'), :if => os[:family] == 'redhat' do
  it { should be_installed }
end
​
describe package('apache2'), :if => os[:family] == 'ubuntu' do
  it { should be_installed }
end
​
describe service('httpd'), :if => os[:family] == 'redhat' do
  it { should be_enabled }
  it { should be_running }
end
​
describe service('apache2'), :if => os[:family] == 'ubuntu' do
  it { should be_enabled }
  it { should be_running }
end
​
describe service('org.apache.httpd'), :if => os[:family] == 'darwin' do
  it { should be_enabled }
  it { should be_running }
end
​
describe port(80) do
  it { should be_listening }
end
[root@localhost serverspec]#

4 - 使用示例

注意:必须在Rakefile文件所在目录执行rake命令

[root@localhost serverspec]# pwd
/root/serverspec
[root@localhost serverspec]# ll
total 4
-rw-rw-r-- 1 root root 685 Nov 20 09:48 Rakefile
drwxrwxr-x 3 root root  45 Nov 20 09:48 spec
[root@localhost serverspec]#
[root@localhost serverspec]# rake spec
/usr/local/rvm/rubies/ruby-2.5.5/bin/ruby -I/usr/local/rvm/gems/ruby-2.5.5/gems/rspec-support-3.9.0/lib:/usr/local/rvm/gems/ruby-2.5.5/gems/rspec-core-3.9.0/lib /usr/local/rvm/gems/ruby-2.5.5/gems/rspec-core-3.9.0/exe/rspec --pattern spec/localhost/\*_spec.rb
​
Package "httpd"
  is expected to be installed
​
Service "httpd"
  is expected to be enabled (FAILED - 1)
  is expected to be running (FAILED - 2)
​
Port "80"
  is expected to be listening
​
Failures:
​
  1) Service "httpd" is expected to be enabled
     On host `localhost'
     Failure/Error: it { should be_enabled }
       expected Service "httpd" to be enabled
       /bin/sh -c systemctl\ --quiet\ is-enabled\ httpd

     # ./spec/localhost/sample_spec.rb:12:in `block (2 levels) in <top (required)>'
​
  2) Service "httpd" is expected to be running
     On host `localhost'
     Failure/Error: it { should be_running }
       expected Service "httpd" to be running
       /bin/sh -c systemctl\ is-active\ httpd
       unknown
​
     # ./spec/localhost/sample_spec.rb:13:in `block (2 levels) in <top (required)>'
​
Finished in 0.14409 seconds (files took 0.65376 seconds to load)
4 examples, 2 failures
​
Failed examples:
​
rspec ./spec/localhost/sample_spec.rb:12 # Service "httpd" is expected to be enabled
rspec ./spec/localhost/sample_spec.rb:13 # Service "httpd" is expected to be running
​
/usr/local/rvm/rubies/ruby-2.5.5/bin/ruby -I/usr/local/rvm/gems/ruby-2.5.5/gems/rspec-support-3.9.0/lib:/usr/local/rvm/gems/ruby-2.5.5/gems/rspec-core-3.9.0/lib /usr/local/rvm/gems/ruby-2.5.5/gems/rspec-core-3.9.0/exe/rspec --pattern spec/localhost/\*_spec.rb failed
[root@localhost serverspec]#

以Nginx为例。

[root@localhost ansible-playbook-sample]# pwd
/root/zzz/ansible-playbook-sample
[root@localhost ansible-playbook-sample]#
[root@localhost ansible-playbook-sample]# cat site.yml
---
- hosts: webservers
  become: yes
  connection: local
  roles:
    - common
    - nginx
    - serverspec
    - serverspec_sample
#    - jenkins
[root@localhost ansible-playbook-sample]#
[root@localhost ansible-playbook-sample]# tree roles/serverspec_sample/
roles/serverspec_sample/
├── files
│   └── serverspec_sample
│       ├── Rakefile
│       └── spec
│           ├── localhost
│           └── spec_helper.rb
├── meta
│   └── main.yml
├── tasks
│   └── main.yml
├── templates
│   ├── nginx_spec.rb.j2
│   └── web_spec.rb.j2
└── vars
    └── main.yml
​
8 directories, 7 files
[root@localhost ansible-playbook-sample]#
[root@localhost ansible-playbook-sample]# ansible-playbook -i development site.yml
[DEPRECATION WARNING]: The TRANSFORM_INVALID_GROUP_CHARS settings is set to allow bad characters in group names by default, this will change, but still be user configurable on deprecation. This feature will be removed in version 2.10.
Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details
​
​
PLAY [webservers] **************************************************************************************************************************************************************************************************************************
​
TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************************
ok: [localhost]
​
TASK [common : install epel] ***************************************************************************************************************************************************************************************************************
ok: [localhost]
​
TASK [nginx : install nginx] ***************************************************************************************************************************************************************************************************************
ok: [localhost]
​
TASK [nginx : replace index.html] **********************************************************************************************************************************************************************************************************
ok: [localhost]
​
TASK [nginx : nginx start] *****************************************************************************************************************************************************************************************************************
ok: [localhost]
​
TASK [serverspec : install ruby] ***********************************************************************************************************************************************************************************************************
ok: [localhost]
​
TASK [serverspec : install serverspec] *****************************************************************************************************************************************************************************************************
ok: [localhost] => (item=rake)
ok: [localhost] => (item=serverspec)
​
TASK [serverspec_sample : distribute serverspec suite] *************************************************************************************************************************************************************************************
changed: [localhost]
​
TASK [serverspec_sample : distribute spec file] ********************************************************************************************************************************************************************************************
changed: [localhost]
​
PLAY RECAP *********************************************************************************************************************************************************************************************************************************
localhost                  : ok=9    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
​
[root@localhost ansible-playbook-sample]#
[root@localhost ansible-playbook-sample]# ll /tmp/serverspec_sample/
total 4
-rw-rw-r-- 1 root root 685 Nov 20 13:54 Rakefile
drwxrwxr-x 3 root root  45 Nov 20 13:54 spec
[root@localhost ansible-playbook-sample]#
[root@localhost ansible-playbook-sample]# tree /tmp/serverspec_sample/
/tmp/serverspec_sample/
├── Rakefile
└── spec
    ├── localhost
    │   └── web_spec.rb
    └── spec_helper.rb
​
2 directories, 3 files
[root@localhost ansible-playbook-sample]# cd /tmp/serverspec_sample/
[root@localhost serverspec_sample]# cat spec/localhost/web_spec.rb
require 'spec_helper'
​
describe package('nginx') do
  it { should be_installed }
end
​
describe service('nginx') do
  it { should be_enabled }
  it { should be_running }
end
​
describe port(80) do
  it { should be_listening }
end
​
describe file('/usr/share/nginx/html/index.html') do
  it { should be_file }
  it { should exist }
  its(:content) { should match /^Hello, development ansible!!$/ }
end
[root@localhost serverspec_sample]#
[root@localhost serverspec_sample]# rake spec
/usr/local/rvm/rubies/ruby-2.5.5/bin/ruby -I/usr/local/rvm/gems/ruby-2.5.5/gems/rspec-support-3.9.0/lib:/usr/local/rvm/gems/ruby-2.5.5/gems/rspec-core-3.9.0/lib /usr/local/rvm/gems/ruby-2.5.5/gems/rspec-core-3.9.0/exe/rspec --pattern spec/localhost/\*_spec.rb
​
Package "nginx"
  is expected to be installed
​
Service "nginx"
  is expected to be enabled
  is expected to be running
​
Port "80"
  is expected to be listening
​
File "/usr/share/nginx/html/index.html"
  is expected to be file
  is expected to exist
  content
    is expected to match /^Hello, development ansible!!$/ (FAILED - 1)
​
Failures:
​
  1) File "/usr/share/nginx/html/index.html" content is expected to match /^Hello, development ansible!!$/
     On host `localhost'
     Failure/Error: its(:content) { should match /^Hello, development ansible!!$/ }
       expected "hello, development ansible\n" to match /^Hello, development ansible!!$/
       Diff:
       @@ -1,2 +1,2 @@
       -/^Hello, development ansible!!$/
       +hello, development ansible

       /bin/sh -c cat\ /usr/share/nginx/html/index.html\ 2\>\ /dev/null\ \|\|\ echo\ -n
       hello, development ansible
​
     # ./spec/localhost/web_spec.rb:19:in `block (2 levels) in <top (required)>'
​
Finished in 0.23396 seconds (files took 0.64631 seconds to load)
7 examples, 1 failure
​
Failed examples:
​
rspec ./spec/localhost/web_spec.rb:19 # File "/usr/share/nginx/html/index.html" content is expected to match /^Hello, development ansible!!$/
​
/usr/local/rvm/rubies/ruby-2.5.5/bin/ruby -I/usr/local/rvm/gems/ruby-2.5.5/gems/rspec-support-3.9.0/lib:/usr/local/rvm/gems/ruby-2.5.5/gems/rspec-core-3.9.0/lib /usr/local/rvm/gems/ruby-2.5.5/gems/rspec-core-3.9.0/exe/rspec --pattern spec/localhost/\*_spec.rb failed
[root@localhost serverspec_sample]#

发现有一个失败的测试用例,根据报错信息分析并更改,然后重新执行。

[root@localhost templates]# pwd
/root/zzz/ansible-playbook-sample/roles/nginx/templates
[root@localhost templates]#
[root@localhost templates]# ll
total 4
-rw-r--r-- 1 root root 25 Nov 19 17:25 index.html.j2
[root@localhost templates]# cat index.html.j2
hello, {{ env }} ansible
[root@localhost templates]#
[root@localhost templates]# vim index.html.j2
[root@localhost templates]# cat index.html.j2
Hello, {{ env }} ansible!!
[root@localhost templates]#
[root@localhost serverspec_sample]# cd  ~/zzz/ansible-playbook-sample/
[root@localhost ansible-playbook-sample]# ansible-playbook -i development site.yml
[DEPRECATION WARNING]: The TRANSFORM_INVALID_GROUP_CHARS settings is set to allow bad characters in group names by default, this will change, but still be user configurable on deprecation. This feature will be removed in version 2.10.
Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details
​
​
PLAY [webservers] **************************************************************************************************************************************************************************************************************************
​
TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************************
ok: [localhost]
​
TASK [common : install epel] ***************************************************************************************************************************************************************************************************************
ok: [localhost]
​
TASK [nginx : install nginx] ***************************************************************************************************************************************************************************************************************
ok: [localhost]
​
TASK [nginx : replace index.html] **********************************************************************************************************************************************************************************************************
changed: [localhost]
​
TASK [nginx : nginx start] *****************************************************************************************************************************************************************************************************************
ok: [localhost]
​
TASK [serverspec : install ruby] ***********************************************************************************************************************************************************************************************************
ok: [localhost]
​
TASK [serverspec : install serverspec] *****************************************************************************************************************************************************************************************************
ok: [localhost] => (item=rake)
ok: [localhost] => (item=serverspec)
​
TASK [serverspec_sample : distribute serverspec suite] *************************************************************************************************************************************************************************************
ok: [localhost]
​
TASK [serverspec_sample : distribute spec file] ********************************************************************************************************************************************************************************************
ok: [localhost]
​
PLAY RECAP *********************************************************************************************************************************************************************************************************************************
localhost                  : ok=9    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
​
[root@localhost ansible-playbook-sample]#
[root@localhost ansible-playbook-sample]# cd /tmp/serverspec_sample/
[root@localhost serverspec_sample]# rake spec
/usr/local/rvm/rubies/ruby-2.5.5/bin/ruby -I/usr/local/rvm/gems/ruby-2.5.5/gems/rspec-support-3.9.0/lib:/usr/local/rvm/gems/ruby-2.5.5/gems/rspec-core-3.9.0/lib /usr/local/rvm/gems/ruby-2.5.5/gems/rspec-core-3.9.0/exe/rspec --pattern spec/localhost/\*_spec.rb
​
Package "nginx"
  is expected to be installed
​
Service "nginx"
  is expected to be enabled
  is expected to be running
​
Port "80"
  is expected to be listening
​
File "/usr/share/nginx/html/index.html"
  is expected to be file
  is expected to exist
  content
    is expected to match /^Hello, development ansible!!$/
​
Finished in 0.19861 seconds (files took 0.61345 seconds to load)
7 examples, 0 failures
​
[root@localhost serverspec_sample]#

5 - 问题处理

通过gem安装serverspec时,ruby版本过低导致安装失败,版本必须大于等于2.2.6。

# gem install serverspec
Fetching: rspec-support-3.9.0.gem (100%)
Successfully installed rspec-support-3.9.0
......
......
......
ERROR:  Error installing serverspec:
    net-ssh requires Ruby version >= 2.2.6.
#
# ruby -v
ruby 2.0.0p648 (2015-12-16) [x86_64-linux]
#

处理方法

通过yum方式在线安装ruby,其版本仍然为2.0.0。

只能通过更换ruby仓库和使用RAM的方式来完成版本升级。

参考信息:https://www.jianshu.com/p/7a625eb8cde0

[root@localhost ~]# gem sources -a http://mirrors.aliyun.com/rubygems/
http://mirrors.aliyun.com/rubygems/ added to sources
[root@localhost ~]#
[root@localhost ~]# gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3  7D2BAF1CF37B13E2069D6956105BD0E739499BDB
gpg: requesting key D39DC0E3 from hkp server keys.gnupg.net
gpg: requesting key 39499BDB from hkp server keys.gnupg.net
gpg: /root/.gnupg/trustdb.gpg: trustdb created
gpg: key D39DC0E3: public key "Michal Papis (RVM signing) <mpapis@gmail.com>" imported
gpg: key 39499BDB: public key "Piotr Kuczynski <piotr.kuczynski@gmail.com>" imported
gpg: no ultimately trusted keys found
gpg: Total number processed: 2
gpg:               imported: 2  (RSA: 2)
[root@localhost ~]#
[root@localhost ~]# curl -sSL https://get.rvm.io | bash -s stable
Downloading https://github.com/rvm/rvm/archive/1.29.9.tar.gz
Downloading https://github.com/rvm/rvm/releases/download/1.29.9/1.29.9.tar.gz.asc
gpg: Signature made Wed 10 Jul 2019 04:31:02 PM CST using RSA key ID 39499BDB
gpg: Good signature from "Piotr Kuczynski <piotr.kuczynski@gmail.com>"
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 7D2B AF1C F37B 13E2 069D  6956 105B D0E7 3949 9BDB
GPG verified '/usr/local/rvm/archives/rvm-1.29.9.tgz'
Creating group 'rvm'
Installing RVM to /usr/local/rvm/
Installation of RVM in /usr/local/rvm/ is almost complete:
​
  * First you need to add all users that will be using rvm to 'rvm' group,
    and logout - login again, anyone using rvm will be operating with `umask u=rwx,g=rwx,o=rx`.
​
  * To start using RVM you need to run `source /etc/profile.d/rvm.sh`
    in all your open shell windows, in rare cases you need to reopen all shell windows.
  * Please do NOT forget to add your users to the rvm group.
     The installer no longer auto-adds root or users to the rvm group. Admins must do this.
     Also, please note that group memberships are ONLY evaluated at login time.
     This means that users must log out then back in before group membership takes effect!
Thanks for installing RVM

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章