Why won't InSpec admit that port 5432 is listening inside a PostgreSQL container? Background

I'm trying to test a PostgreSQL container with InSpec 2.1.10, but I cannot get a simple port check to return true, even though Docker, netstat, and psql all report that the port is properly mapped. While it's possible this is a bug in InSpec, it seems more likely that the problem exists between the keyboard and the chair. What have I missed?

Repeatable Tests

My Spec

# port_test.rb
describe port(5432) do
  it { should be_listening }
end


My Testing Commands

container=$(docker run -d -P --rm postgres:alpine)
inspec exec port_test.rb -t docker://$container


My Output


Profile: tests from test.rb (tests from test.rb)
Version: (not specified)
Target:  docker://8caceaa7e2eefa4a2bf50a58ea1ddf9c927c08d3397e3d9ad5b60d3519971380

  Port 5432
     ×  should be listening
     expected `Port 5432.listening?` to return true, got false

Test Summary: 0 successful, 1 failure, 0 skipped



But It Should Work!

Everything but InSpec reports that things are working as expected.

$ docker port $container
5432/tcp -&gt; 0.0.0.0:32770

# from inside container using netstat
$ docker exec $container netstat -lntp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:5432            0.0.0.0:*               LISTEN      -
tcp        0      0 :::5432                 :::*                    LISTEN      -

# on macOS Docker host; flags are the macOS equivalent to `-lntp`
$ netstat -anv | fgrep $(docker port $container | cut -d: -f2)
tcp6       0      0  ::1.32770              *.*                    LISTEN      131072 131072    709      0
tcp4       0      0  *.32770                *.*                    LISTEN      131072 131072    709      0

# connecting to database in container from host
$ psql -V \
       -h localhost \
       -p $(docker port $container | cut -d: -f2)
psql (PostgreSQL) 10.3
You did everything right, it is the correct InSpec test and use with Docker!

You encountered a bug in InSpec that is related to InSpec's netstat output parsing combination with Alpine's netstat output. 

See InSpec's output for postgres container instead of postgres:alpine:

$ inspec exec docker_test.rb -t docker://1c8162517c22                                                               1d15h master[a5ff79d3]

Profile: tests from docker_test.rb (tests from docker_test.rb)
Version: (not specified)
Target:  docker://1c8162517c229ff8c87ab3e8c909f46b4370d7c63a65c0f973a5c10fdebda800

  Port 5432
     ✔  should be listening

Test Summary: 1 successful, 0 failures, 0 skipped


In your case, the problem is that Apline's netstat reports a different output then other Linux eg. Ubuntu, CentOS:

# netstat -tulpen
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       User       Inode      PID/Program name    
tcp        0      0 0.0.0.0:5432            0.0.0.0:*               LISTEN      999        108791     -                   
tcp6       0      0 :::5432                 :::*                    LISTEN      999        108792     -  


On Alpine, the inode output is missing:

netstat -tulpen
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:5432            0.0.0.0:*               LISTEN      -
tcp        0      0 :::5432                 :::*                    LISTEN      -


That is why InSpec is not able to parse the netstat output. It is clearly a bug in InSpec. As a mitigation, I recommend to install the iproute2 package for alpine containers via apk add iproute2. InSpec prefers ss over netstat. Please report this bug to InSpec team.