No possibility to delete named volumes
Hello,
First of all, thank you for the plugin. It gets the job done!
Currently there is no way to delete named volumes. This is implemented by the docker-compose down --volumes command, but there is no equivalent in your plugin.
Regards Piotr Minkina
Hello,
thank you! There is actually removeVolumes option that should add --volumes to the down command: https://github.com/avast/gradle-docker-compose-plugin/blob/main/src/main/groovy/com/avast/gradle/dockercompose/tasks/ComposeDownForced.groovy#L78
Is this what you are actually looking for? 🙏
Hello,
I did not notice this in the implementation, but unfortunately it does not solve my problem, i.e. named volumes are not deleted. In my case, the Plugin executes most likely the block https://github.com/avast/gradle-docker-compose-plugin/blob/8155c72073039e293b9bd43cfbe6e6f068a31662/src/main/groovy/com/avast/gradle/dockercompose/tasks/ComposeDownForced.groovy#L61-L66. The -v parameter used there is only responsible for deleting anonymous volumes. My configuration of this Plugin is as follows.
task appUp() { /** ... */ }
task appDown() { /** ... */ }
task logsUp() { /** ... */ }
task logsDown() { /** ... */ }
task docsUp() { /** ... */ }
task docsDown() { /** ... */ }
clean {
dependsOn appDown, logsDown, docsDown
}
dockerCompose {
isRequiredBy(tasks.appUp)
isRequiredBy(tasks.test)
projectName = env.COMPOSE_PROJECT_NAME.value
useComposeFiles = env.COMPOSE_FILE.value.tokenize(env.COMPOSE_PATH_SEPARATOR.value)
// Profiles aren't supported by this plugin
composeAdditionalArgs = ['--profile=app']
// It should be detected automatically on the basis of the profile, but is not supported
startedServices = ['nginx', 'artifactory', 'mountebank', 'squid']
waitForHealthyStateTimeout = Duration.ofMinutes(3)
includeDependencies = true
stopContainers = false
docs {
isRequiredBy(tasks.docsUp)
projectName = env.COMPOSE_PROJECT_NAME.value
// Profiles aren't supported by this plugin
composeAdditionalArgs = ['--profile=docs']
// It should be detected automatically on the basis of the profile, but is not supported
startedServices = ['mkdocs', 'kroki']
}
logs {
isRequiredBy(tasks.logsUp)
// Currently no implementation for logs testing
//isRequiredBy(tasks.test)
projectName = env.COMPOSE_PROJECT_NAME.value
// Profiles aren't supported by this plugin
composeAdditionalArgs = ['--profile=logs']
// It should be detected automatically on the basis of the profile, but is not supported
startedServices = ['filebeat']
}
}
Executing one of the three configured stacks looks like the following:
$ ./gradlew appUp
> Task :composeBuild
[...]
> Task :composeUp
Creating artifactory_squid ...
Creating artifactory_mountebank ...
Creating artifactory_mountebank ... done
Creating artifactory_squid ... done
Creating artifactory_artifactory ...
Creating artifactory_artifactory ... done
Creating artifactory_nginx ...
Creating artifactory_nginx ... done
[...]
> Task :composeDown
You're trying to stop the containers, but stopContainers is set to false. Please use composeDownForced task instead.
[...]
This will also automatically create named volumes.
$ docker volume ls --filter=label=com.docker.compose.project=artifactory
DRIVER VOLUME NAME
local artifactory_artifactory_var
local artifactory_nginx_cache_proxy
When I want to delete the whole stack, I do it with the command as below, but unfortunately the named volumes are not deleted.
$ ./gradlew clean
> Task :composeDownForced
Stopping artifactory_nginx ...
Stopping artifactory_artifactory ...
Stopping artifactory_mountebank ...
Stopping artifactory_squid ...
Stopping artifactory_nginx ... done
Stopping artifactory_artifactory ... done
Stopping artifactory_mountebank ... done
Stopping artifactory_squid ... done
Removing artifactory_nginx ...
Removing artifactory_artifactory ...
Removing artifactory_mountebank ...
Removing artifactory_squid ...
Removing artifactory_squid ... done
Removing artifactory_nginx ... done
Removing artifactory_mountebank ... done
Removing artifactory_artifactory ... done
Going to remove artifactory_nginx, artifactory_artifactory, artifactory_mountebank, artifactory_squid
> Task :docsComposeDownForced
No stopped containers
> Task :logsComposeDownForced
No stopped containers
[...]
The way I currently deal with this problem is to define an additional task volumesDown, which takes care of deleting the named volumes, at the appropriate time.
task volumesDown() {
dependsOn appDown, logsDown, docsDown
/** ... */
doLast {
def projectName = dockerCompose.projectName.get()
def executor = dockerCompose.dockerExecutor
executor
.execute(
'volume',
'ls',
'--filter=label=com.docker.compose.project=' + projectName,
'--format={{ .Name }}'
)
.eachLine({
executor.execute('volume', 'rm', it)
})
}
}
clean {
dependsOn appDown, logsDown, docsDown, volumesDown
}
To cover my case in your Plugin, I think somewhere in the block https://github.com/avast/gradle-docker-compose-plugin/blob/8155c72073039e293b9bd43cfbe6e6f068a31662/src/main/groovy/com/avast/gradle/dockercompose/tasks/ComposeDownForced.groovy#L61 there should be an implementation that additionally removes named volumes from the project that are no longer used by other containers.
Example code implementing this case:
def projectName = dockerCompose.projectName.get()
def executor = dockerCompose.dockerExecutor
executor
.execute(
'volume',
'ls',
'--filter=label=com.docker.compose.project=' + projectName,
'--format={{ .Name }}'
)
.eachLine({ volumeName ->
def containersNames = executor
.execute(
'ps',
'--all',
"--filter=volume=${volumeName}",
'--format={{ .Names }}'
)
.tokenize('\n')
if (containersNames) {
logger.lifecycle('Volume {} is used by: {}', volumeName, containersNames.join(', '))
} else {
executor.execute(
'volume',
'rm',
volumeName
)
logger.lifecycle('Removed volume {}', volumeName)
}
})
The above code can produce this output:
Removed volume artifactory_artifactory_var
Volume artifactory_nginx_cache_proxy is used by: another_container, artifactory_nginx
Greetings Piotr Minkina