Cleaning up Docker volumes created by Testcontainers
I like to use Testcontainers to provide databases for tests in my Ruby projects. It is fast, and the test data is ephemeral. Or at least, that is what I thought.
I recently noticed that when I run my tests, my project creates and deletes a container as expected, but it also creates a volume that is not cleaned up. I run my tests frequently, so I had dozens of volumes taking up gigabytes of storage. I decided to investigate.
I found a comment on an issue in the Testcontainers NodeJS library that told me that some of the libraries have a
method .withRemoveVolumes that instructs the implementation to clean up anonymous volumes after removing the container. However, this option is not available in the Ruby library. Instead, I found that when you call remove on a container, you have the opportunity to pass options that will ultimately be passed to the Docker engine.
Setting the v option to true instructs the Docker engine to remove anonymous volumes associated with the container. This was exactly what I needed!
There is another option force which tells the Docker engine to stop the container if it is running before removing it. I have adopted it as well so I can stop and remove the container in one call to the Docker engine.
Following is an excerpt of code from my test_helper.rb file. It sets up the container, removes it and exits if initialization fails, and removes it after all tests have run.
begin
pg = Testcontainers::PostgresContainer.new("postgres:18").start
# other initialization...
rescue => e
warn("failed to initialize container: #{e}")
pg&.remove(force: true, v: true)
exit(1)
end
Minitest.after_run do
pg&.remove(force: true, v: true)
end