docker-compose で Goss 試してみた


はじめに

これまで業務でサーバ構築後のテストツールとして、Serverspec を使用していました。

Ansible と組み合わせて、Serverspec のテストケースの生成、実行などの自動化を行いましたが、手動でやるよりは確実に速いものの 実行にそこそこ時間がかかってしまう という欠点を感じていました。

人間、どんどん欲深くなるものですね、恐ろしや恐ろしや

そんなある日、Goss というテストツールがあることを知ったので試してみました。

Serverspec と比較した Goss の特徴

Serverspec Goss
環境構築 そこそこ簡単、テスト対象に接続可能な 1 ホストにあればいい テスト対象全てにシングルバイナリ配布
実行速度* 速い (100テストケース:10秒くらい) 爆速(500テストケース:1秒くらい)
テストケース形式 Ruby 形式 YAML 形式
テストケース生成 手動 一部自動生成可能

実行速度に関しては、テスト対象が物理マシンか VM か、などで変わると思うがあくまで参考

環境構築

テストの趣旨として、Serverspec をそのまま Goss に置き換え、これまで通り Ansible と組み合わせてテストの自動実行を行います。

環境

docker-compose で ansible-servertest-target の2つのコンテナを立ち上げ、テストを行います。

ansible-server に Goss をインストールして、そのバイナリをテスト対象に Ansible でばら撒いてテストを行うといった流れです。

┌────────────────┐          ┌─────────────┐ 
│ ansible-server │ =[SSH]=> │ test-target │
└────────────────┘          └─────────────┘

ディレクトリ構成

.
├── ansible-server
│   ├── Dockerfile
│   ├── config
│   └── test-target-key
├── docker-compose.yml
├── test-target
│   ├── Dockerfile
│   └── test-target-key.pub
└── work
    ├── inventory.yml
    ├── roles
    │   └── goss
    │       ├── files
    │       │   ├── goss
    │       │   └── goss.yaml
    │       ├── tasks
    │       │   └── main.yml
    │       ├── templates
    │       └── vars
    │           └── main.yml
    └── site.yml

Dockerfile [ansible-server]

FROM ubuntu:18.04

WORKDIR /root

# SSH Settings
COPY ./test-target-key /root/.ssh/
COPY ./config /root/.ssh/
# Install common tools
RUN apt update && apt install --yes curl vim
# Install ansible
RUN apt install --yes software-properties-common && \
    apt-add-repository --yes --update ppa:ansible/ansible && \
    apt install --yes ansible
# Install Goss
RUN curl -L https://github.com/aelsabbahy/goss/releases/latest/download/goss-linux-amd64 -o /usr/local/bin/goss && \
    chmod +rx /usr/local/bin/goss && \
    cp -i $(which goss) .

CMD ["tail", "-f", "/dev/null"]

Dockerfile [test-target]

FROM ubuntu:18.04

WORKDIR /root

RUN apt update && apt install --yes openssh-server
RUN mkdir /var/run/sshd
RUN echo 'root:P@ssw0rd' | chpasswd
COPY ./test-target-key.pub /root/.ssh/authorized_keys
EXPOSE 22

# For Test.
RUN echo "this is test." > test.txt
RUN apt install --yes nginx
EXPOSE 80

CMD ["/usr/sbin/sshd", "-D"]

docker-compose.yml

---
  version: "2"
  services:
    ansible-server:
      build: ./ansible-server
      volumes:
        - ./work:/root/work

    test-target:
      build: ./test-target
      ports:
        - 8080:80

起動

$ docker-compose build
$ docker-compose up -d

テスト

test-target の Dockerfile 内の記述、 # For Test. 以下のテストを行います。

  • test.txtthis is test. と記述されていること
  • Nginx がインストールされていること
  • Nginx が起動していること
  • 80 ポートで Listen していること

テストケースは、YAML 形式で記述します。

goss.yaml

file:
  /root/test.txt:
    exists: true
    contains: ["this is test."]

port:
  tcp:80:
    listening: true
    ip:
    - 0.0.0.0
  tcp6:80:
    listening: true
    ip:
    - '::'
service:
  nginx:
    enabled: true
    running: false
process:
  nginx:
    running: true

Ansible のプレイブックは割愛

テスト実行

$ docker-compose exec ansible-server /bin/bash
root@38b380ec3969:~# cd work/
root@38b380ec3969:~/work# ansible-playbook -i inventory.yml site.yml
ok: [test-target] => {
    "msg": {
        "changed": true,
        "cmd": [
            "./goss",
            "validate",
            "--format",
            "documentation"
---
        "stdout_lines": [
            "File: /root/test.txt: exists: matches expectation: [true]",
            "File: /root/test.txt: contains: matches expectation: [this is test.]",
            "Port: tcp:80: listening: matches expectation: [true]",
            "Port: tcp:80: ip: matches expectation: [[\"0.0.0.0\"]]",
            "Port: tcp6:80: listening: matches expectation: [true]",
            "Port: tcp6:80: ip: matches expectation: [[\"::\"]]",
            "Process: nginx: running: matches expectation: [true]",
            "Service: nginx: enabled: matches expectation: [true]",
            "Service: nginx: running: matches expectation: [false]",
            "",
            "",
            "Total Duration: 0.006s",
            "Count: 9, Failed: 0, Skipped: 0"
        ]
    }
}

9 のテストケースを 0.006 秒でクリア してますね、爆速。

まとめ

  • Goss はやはり爆速
  • Ansible との相性も良さそう
  • テストケース作るのも簡単 (紹介してないが、今回のテストケースはほとんど自動生成した)

他にも、環境に合わせてテストケースを切り替えたりする機能や、for ループでテストを回す機能などもある

さいごに

今回作成したソースコードは GItHub で公開しています。

Goss で凝ったテストを作ろうとすると、やはり Golang の知識が必要そう、時代はやはり Golang か