diff --git a/docs/reference/config.md b/docs/reference/config.md index ecd89b5d09..ac75bd2516 100644 --- a/docs/reference/config.md +++ b/docs/reference/config.md @@ -592,7 +592,30 @@ The following settings are available: : Add the specified flags to the volume mounts e.g. `mountFlags = 'ro,Z'`. `docker.registry` -: The registry from where Docker images are pulled. It should be only used to specify a private registry server. It should NOT include the protocol prefix i.e. `http://`. +: Specify a custom registry from which to pull Docker images. It should be only used to specify a private registry server. It should NOT include the protocol prefix i.e. `http://`. +: The custom registry is only applied to container images that don't specify a registry. Use `docker.registryOverrides` to also override fully-qualified container images. + +`docker.registryOverrides` +: :::{versionadded} 25.06.0-edge + ::: +: A list of registries to override when specifying a custom registry with `docker.registry`. For example: + + ```groovy + docker.registryOverrides = [ + 'community.wave.seqera.io', + 'quay.io' + ] + ``` + +: Nextflow will use this list to modify fully-qualified container images to use the registry specified by `docker.registry`. + +: :::{tip} + Use `nextflow inspect` to obtain the list of all containers used by a pipeline, from which you can determine the set of registries that need to be overridden. + ::: + +: :::{warning} + The pipeline will fail if a container image cannot be overridden when using this setting, in order to prevent Nextflow from pulling containers from outside the custom registry. + ::: `docker.remove` : Clean-up the container after the execution (default: `true`). See the [Docker documentation](https://docs.docker.com/engine/reference/run/#clean-up---rm) for details. diff --git a/modules/nextflow/src/main/groovy/nextflow/container/ContainerHandler.groovy b/modules/nextflow/src/main/groovy/nextflow/container/ContainerHandler.groovy index 2dae5abbc5..00738931d7 100644 --- a/modules/nextflow/src/main/groovy/nextflow/container/ContainerHandler.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/container/ContainerHandler.groovy @@ -157,17 +157,36 @@ class ContainerHandler { if( !imageName ) return null - String reg = this.config?.registry - if( !reg ) + final registry = normalizeRegistry(this.config?.registry as String) + final registryOverrides = (this.config?.registryOverrides as List)?.collect((r) -> normalizeRegistry(r)) + if( !registry ) return imageName - if( isAbsoluteDockerName(imageName) ) + // apply the registry only to relative container images + // when registry overrides are not specified + if( !isAbsoluteDockerName(imageName) ) + return registry + imageName + + if( !registryOverrides ) return imageName - if( !reg.endsWith('/') ) - reg += '/' + // when registry overrides are specified, apply the custom registry also + // to fully-qualified container images + final newImageName = overrideRegistry(imageName, registry, registryOverrides) + if( newImageName ) + return newImageName + + // otherwise, raise an error to prevent Nextflow from pulling container images + // from outside of the custom registry + throw new IllegalArgumentException("Registry for container image '$imageName' not found in overrides") + } - return reg + imageName + static String normalizeRegistry(String registry) { + if( !registry ) + return null + return registry.endsWith('/') + ? registry + : registry + '/' } static boolean isAbsoluteDockerName(String image) { @@ -179,6 +198,14 @@ class ContainerHandler { image.contains('.') || image.contains(':') } + static String overrideRegistry(String imageName, String toRegistry, List registryOverrides) { + for( final fromRegistry : registryOverrides ) { + if( imageName.startsWith(fromRegistry) ) + return toRegistry + imageName.substring(fromRegistry.length()) + } + return null + } + /** * Normalize Udocker image name adding `:latest` * when required diff --git a/modules/nextflow/src/test/groovy/nextflow/container/ContainerHandlerTest.groovy b/modules/nextflow/src/test/groovy/nextflow/container/ContainerHandlerTest.groovy index 658bc51e10..cebc23bd2a 100644 --- a/modules/nextflow/src/test/groovy/nextflow/container/ContainerHandlerTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/container/ContainerHandlerTest.groovy @@ -64,6 +64,26 @@ class ContainerHandlerTest extends Specification { } + def 'should override absolute docker image name when enabled' () { + + given: + def registry = 'd.reg' + def registryOverrides = [ 'registry:5000' ] + def handler = new ContainerHandler([registry: registry, registryOverrides: registryOverrides]) + + when: + def result = handler.normalizeDockerImageName('registry:5000/cbcrg/hello') + then: + result == 'd.reg/cbcrg/hello' + + when: + handler.normalizeDockerImageName('registry:8000/cbcrg/hello') + then: + def e = thrown(IllegalArgumentException) + e.message == "Registry for container image 'registry:8000/cbcrg/hello' not found in overrides" + + } + def 'test normalize shifter image name' () { given: