Google Container Structure Testsと、Inspec/Serverspecの違いを確認する

# 1. Google Container Structure Testsとは
出遅れましたが、Google社からコンテナ環境をテストするフレームワークが公開されました。
[Container Structure Tests: Unit Tests for Docker Images | Google Open Source Blog] (https://opensource.googleblog.com/2018/01/container-structure-tests-unit-tests.html)

コンテナ内部でコマンドを実行し、正しい出力やエラーが帰ってくるかどうかや、コンテナ内部のファイルが正しく格納されているか等をテストできるフレームワークです。注目されていて、検証された方もいらっしゃいます。
[GoogleのContainer Structure TestsをMacOSで実行してみる](https://qiita.com/sawanoboly/items/a62fc83aff346c9f8bac)


# 2. Google Container Structure Testsに対して思った疑問
ただ、既にInspecやServerspecなどのテスト自動化フレームワークが世の中にあります。例えばInspecの場合、Resourceとして、[docker](https://www.inspec.io/docs/reference/resources/docker/)、[docker_container](https://www.inspec.io/docs/reference/resources/docker_container/)、[docker_image](https://www.inspec.io/docs/reference/resources/docker_image/)が提供されており、コンテナ環境のテストを容易に実現できます。下記のように、docker idを指定すれば、コンテナ内部でコマンドを実行するテストを実現できます。
Google Container Structure Testsと、Inspec/Serverspecの違いは何だろう?! Google Container Structure Testsの使用用途は何だろう?! と疑問に思ってしまいました。
・テストスクリプト
-
```
$ cat test.rb
describe command('env | grep HOME') do
  its('stdout') { should eq "HOME=/root\n" }
end
describe directory('/var/local') do
    it { should be_directory }
end
```
・テスト実行ログ
-
```
# mkdir gcst_test
# cd .\gcst_test
# git clone https://github.com/coreos/coreos-vagrant/
# vagrant up
# vagrant plugin install vagrant-teraterm
# vagrant teraterm core-01

$ git clone https://github.com/chef/inspec.git
Cloning into 'inspec'...
remote: Counting objects: 28404, done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 28404 (delta 3), reused 1 (delta 1), pack-reused 28395
Receiving objects: 100% (28404/28404), 9.66 MiB | 1.17 MiB/s, done.
Resolving deltas: 100% (19135/19135), done.

# docker run -it --rm -v $(pwd):/share chef/inspec version
1.50.1

$ docker run -dti ubuntu /bin/bash
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
45217c8cb144        ubuntu              "/bin/bash"         26 seconds ago      Up 25 seconds                           lucid_cray

$ docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock -v $(pwd):/share chef/inspec exec test1.rb -t docker://45217c8cb144
Profile: tests from test.rb (tests from test.rb)
Version: (not specified)
Target:  docker://45217c8cb1441cf9f915c1bb15cbea6d905196a42e11b6614f7b51ea4c2bccd8

  Command env
     ?  | grep HOME stdout should eq "HOME=/root\n"
  Directory /var/local
     ?  should be directory

Test Summary: 2 successful, 0 failures, 0 skipped
```

# 3. Google Container Structure Testsと、Inspec/Serverspecの違い
疑問を解決すべく、Google Container Structure Testsを検証してみました。
先に結論をお伝えすると、Google Container Structure Testsは「コンテナ作成前のテスト& Dockerless」で、Inspec/Serverspecは「コンテナ作成後のテスト」に主眼を置いていると思いました。Google Container Structure Testsは、実際にコンテナを作成することなく、テスト出来ます。
ブログに書いてある通り(=before shipping)ですね... 製品名も「Structure Tests」でした...
```
What if we want to ensure a set of commands runs successfully inside of our container, or check that certain files are in the correct place with the correct contents, before shipping?
```
・テストスクリプト1
-
```
$ cat ubuntu_test1.yaml
schemaVersion: '2.0.0' # Make sure to test the latest schema version
commandTests:
- name: 'test1'
  command: 'sh'
  args: ['-c', 'env | grep HOME']
  expectedOutput: ['HOME=/root']
fileContentTests:
- name: 'test2'
  expectedContents: ['sudo']
  path: '/etc/group'
```

・テスト実行ログ1
-
```
$ docker pull gcr.io/gcp-runtimes/container-structure-test:v0.1.3
v0.1.3: Pulling from gcp-runtimes/container-structure-test
cd2f5b7886e9: Pull complete
9be56f236f9a: Pull complete
Digest: sha256:15ae6f3996ebc05b657a042bd5dd8f4d4d66b015effea5fd024c70b8a1f9c42a
Status: Downloaded newer image for gcr.io/gcp-runtimes/container-structure-test:v0.1.3

$ docker images
REPOSITORY                                     TAG                 IMAGE ID            CREATED             SIZE
gcr.io/gcp-runtimes/container-structure-test   v0.1.3              88080a73495e        48 years ago        25.7MB

$ docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v `pwd`/ubuntu_test1.yaml:/ubuntu_test1.yaml   gcr.io/gcp-runtimes/container-structure-test:v0.1.3 -pull -test.v --image ubuntu:latest ubuntu_test1.yaml
latest: Pulling from library/ubuntu
Digest: sha256:d3fdf5b1f8e8a155c17d5786280af1f5a04c10e95145a515279cf17abdf0191f
Status: Image is up to date for ubuntu:latest
Using driver docker
=== RUN   TestAll
=== RUN   TestAll/Command_Test:_test1
2018/01/19 16:20:46 Running tests for file ubuntu_test1.yaml
=== RUN   TestAll/File_Content_Test:_test2
=== RUN   TestAll/Metadata_Test
--- PASS: TestAll (0.49s)
    --- PASS: TestAll/Command_Test:_test1 (0.43s)
        docker_driver.go:74: stdout: HOME=/root
    --- PASS: TestAll/File_Content_Test:_test2 (0.06s)
    --- PASS: TestAll/Metadata_Test (0.00s)
        structure_test.go:47: Total tests run: 3
PASS
```

テスト時、docker psコマンドを実行したところ、ubuntuのコンテナリストは取得できませんでした。ただ、docker ps -aコマンドでは、ubuntuのコンテナリストが表示されました。あれ？ Dockerlessではないぞ。そもそも、/var/run/docker.sockをマウントさせているし...

```
# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS                   PORTS               NAMES
d6ced0191f56        ubuntu:latest       "NOOP_COMMAND_DO_NOT…"   About a minute ago   Created                                      nostalgic_brattain
```

調べたところ、下記の通り、commandTestsは、Dockerless Test Runsがnot supportでした。
気を取り直して、commandTestsを外してdriverにtarを指定して実行してみたところ、docker ps -aコマンドでも、ubuntuのコンテナリストが表示されませんでした。本当にDockerlessでした！ ただ、実行時間がかかりました。テスト1は49sで、テスト2は238.54sです。
```
we created a tar-based test driver, which can handle the execution of all file-related tests through simple tar manipulation. Command tests are currently not supported in this mode, since running commands in a container requires a container runtime.
```

・テストスクリプト2
-
```
$ cat ubuntu_test2.yaml
schemaVersion: '2.0.0' # Make sure to test the latest schema version
fileContentTests:
- name: 'test2'
  expectedContents: ['sudo']
  path: '/etc/group'
```

・テスト実行ログ2
-
```
$ docker run --rm -v `pwd`/ubuntu_test2.yaml:/ubuntu_test2.yaml gcr.io/gcp-runtimes/container-structure-test:v0.1.3 -test.v -driver tar --image ubuntu:latest ubuntu_test2.yaml
Using driver tar
=== RUN   TestAll
=== RUN   TestAll/File_Content_Test:_test2
2018/01/20 11:50:40 Running tests for file ubuntu_test2.yaml
(省略)
--- PASS: TestAll (238.54s)
    --- PASS: TestAll/File_Content_Test:_test2 (89.47s)
    --- PASS: TestAll/Metadata_Test (149.05s)
        structure_test.go:47: Total tests run: 2
PASS
```

「コンテナ作成前のテスト& Dockerless」は、Chefのwhy-runみたいな使い方になるのかな?! 
興味深いので、もっと探ってみます。