Remove docker containers and network only if they exists - docker

In Jenkins I am trying to remove all my running containers and remove my network (called my-net), but only if they exists.
In one of the steps I have:
stage('test1') {
steps {
sh 'docker network create my-net'
sh 'docker build -t myimage1 .'
sh 'docker create --name mybackend--network my-net myimage1'
sh 'docker start mybackend'
}
}
Before all stages I put this:
stage('Remove containers and network') {
steps {
sh 'docker stop $(docker ps -a -q)'
sh 'docker rm $(docker ps -a -q)'
sh 'docker network rm my-net'
}
}
This should remove all the running containers (as I don't have only one container running) and my-net network.
I used this to remove all running containers, because I don't know how to remove just the container with name mybackend, but only if it is running.
The problem is also with the network, if it is not running, it fails on this line:
sh 'docker network rm my-net'
I also tried to put this removal step at the very end of all my steps, but in that case if the script fails somewhere, it doesn't reach the removal steps at the end.
So the question is, if I want to keep the removal as the first step, is there a way to:
stop and remove container with name mybackend ONLY if it is running (and also remove the other one same way called e.g. mybackend2)
remove my-net network, but ONLY if it exists
What I found when I investigated:
docker system prune
This should clean up all unused containers, networks, images. But in my case the network or container might be running, so it is not unused, so the only thing I want, is to remove my containers and network, if they are running.

ok, I've found a solution, I put all the stuff in the post -> always step, which will run even if something fails.
post {
always {
sh 'docker stop $(docker ps -a -q)'
sh 'docker rm $(docker ps -a -q)'
sh 'docker network rm my-net'
}
}

Related

Jenkinsfile error when using $() with sh or /bin/bash

I have a step in my Jenkinsfile, that look like this:
steps {
sh '''#!/bin/bash
docker kill $(docker ps -q --filter ancestor=nginx-example )'''
sh '''docker build -t nginx-example .
docker run -d -p 8081:80 nginx-example'''
}
And it errors like this
"docker kill" requires at least 1 argument.
See 'docker kill --help'.
Usage: docker kill [OPTIONS] CONTAINER [CONTAINER...]
Kill one or more running containers
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
ERROR: script returned exit code 1
Finished: FAILURE
How can I run docker kill with $()? It only does not work in Jenkinsfile, while in Jenkins Pipeline it was working totally fine.
Is there a docker running with the name nginx-example? If the docker is not running, then I'm getting the same error in bash as well:
# docker kill $(docker ps -q --filter ancestor=nginx-example )
"docker kill" requires at least 1 argument.
See 'docker kill --help'.
Usage: docker kill [OPTIONS] CONTAINER [CONTAINER...]
Kill one or more running containers
If it's in stopped state, I would suggest you to use docker ps -a

What is the difference between "docker container prune" vs "docker rm $(docker container ls -aq)"

I'm reading through the Docker documentation and I don't understand the difference between:
docker container prune
and
docker rm $(docker container ls -aq)
Note that in the link, the second command I've listed is docker rm $(docker ps -a -q), but there is no difference between that and what I've written. container ls is just the newer version of the ps command.
It seems that both of these commands remove all stopped containers. Is there more to it than that, or are these just synonyms?
I don't think there is substantial difference. This -a though means list all containers and as a result docker rm ... will also try to remove running containers. This gives the error that you see below:
Error response from daemon: You cannot remove a running container [...] Stop the container before attempting removal or force remove
example:
$ docker container run --rm -itd alpine:latest
0ec4d7459d35749ecc24cc5c6fd748f4254b0782f73f1ede76cf49b1fc53b2d4
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0ec4d7459d35 alpine:latest "/bin/sh" 4 seconds ago Up 1 second jovial_ritchie
$ docker rm $(docker container ls -aq)
Error response from daemon: You cannot remove a running container 0ec4d7459d35749ecc24cc5c6fd748f4254b0782f73f1ede76cf49b1fc53b2d4. Stop the container before attempting removal or force remove
$ docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Total reclaimed space: 0B
But... difference when --force, -f is used:
In this case, the commands do 2 different things:
docker rm -f ... Forces the removal of a running container (uses SIGKILL) which means that it will remove running containers.
$ docker rm -f $(docker container ls -aq)
0ec4d7459d35
docker container prune -f will remove all stopped containers without asking for confirmation (no [y/N] prompt will be printed).
$ docker container prune -f
Total reclaimed space: 0B
The effects of the two commands are indeed similar, but there are some nuances to consider:
docker container prune can be used with the --filter option.
docker container prune has a synchronous protection that blocks concurrent prune executions on the daemon.
docker container prune attempts to remove only the containers that are not running, instead of trying to delete all containers and relying on the daemon to throw an exception for those that are not stopped, therefore is quicker and does not generate unnecessary error logs in case someone is tracking the daemon logs.
docker container prune builds a report at the end of its execution, providing the reclaimed space. The report is added in daemon.EventsService and implicitly displayed on the screen.
docker container prune is shorter
In the end of this answer I have a question: Why would someone type 15 additional characters to get the same result or worse?
docker system prune -f : to remove all the stopped containers (docker do not touch the running containers)
docker system prune -a : to remove all the stopped containers (docker do not touch the running containers) + unused images
docker rm <container_id> : remove a specific container, it should be stopped before (docker stop <container_id>)

How to correct docker in makefile which requires at least 1 argument for remove all containers command

The docker command "docker container rm $(docker ps -aq) -f" works fine from the command line. However, when I try to run it from a makefile using the following target ("remove_all_containers")...
remove_all_containers:
docker container rm $(docker ps -aq) -f
I get the error message:
host_name$ make remove_all_containers
docker container rm -f
"docker container rm" requires at least 1 argument.
See 'docker container rm --help'.
Usage: docker container rm [OPTIONS] CONTAINER [CONTAINER...]
Remove one or more containers
make: *** [remove_all_containers] Error 1
Clearly, when executed from within the makefile, the "docker ps" command is not being properly being properly executed in a way where its results can be collected and passed into the "container rm" command.
My Question: How do I get the "docker ps" command to run correctly from within the makefile and pass its results correctly into the "docker rm" command, also within the makefile?
Thanks, in advance, for any assistance you can offer.
You need a second $ in your recipe:
remove_all_containers:
docker container rm $$(docker ps -aq) -f
# ^
The single $ is expanded as a makefile variable when the makefile is parsed. It expands to blank. Make therefore passes docker container rm -f to your shell. The second $ sign causes make to expand $$ to $, and it will pass docker container rm $(docker ps -aq) -f to bash, which I'm guessing is what you want.
Notice, if you put the shell in there as #EricMd proposed, it will run a shell command, but that command will be run at Makefile read time, as opposed to the time that the recipe is executed. If the docker ps -aq command is dependent on any other artifacts of your build it would not work.
Sounds like you don't have any containers in docker to remove. I sometimes use a different syntax for this scenario:
remove_all_containers:
docker container ls -aq | xargs --no-run-if-empty docker container rm -f
The xargs syntax will not run docker container rm if there are no containers to delete.
According to the documentation, docker ps -a should list all containers.
You obtained this message "docker container rm" requires at least 1 argument certainly because you forgot to prepend the command at stake with Make's shell builtin:
remove_all_containers:
docker container rm $(shell docker ps -aq) -f
Note also that the docker ps admits a filtering feature: the online doc describes the various flavors of the corresponding -f flag.
For example, below are three Bash alias examples that can be useful to (i) stop all containers, (ii) remove all stopped containers; and (iii) remove dangling images−that would be tagged as <none> when doing docker images ls:
alias docker-stop='docker stop $(docker ps -a -q)'
alias docker-clean='docker rm $(docker ps -a -q -f status=exited)'
alias docker-purge='docker rmi $(docker images -q -f dangling=true)'
I tested for 2 way follow bellow answer:
remove_all_containers:
docker container rm $$(docker ps -aq) -f
remove_all_containers:
docker container rm $(shell docker ps -aq) -f

single command to stop and remove docker container

Is there any command which can combine the docker stop and docker rm command together ? Each time I want to delete a running container, I need to execute 2 commands sequentially, I wonder if there is a combined command can simplify this process.
docker stop CONTAINER_ID
docker rm CONTATINER_ID
You can use :
docker rm -f CONTAINER_ID
It will remove the container even if it is still running.
https://docs.docker.com/engine/reference/commandline/rm/
You can also run your containers with --rm option (e.g. docker run --rm -it alpine), it will be automatically removed when stopped.
https://docs.docker.com/engine/reference/run/#clean-up---rm
Edit: The rm -f might be dangerous for your data and is best suited for test or development containers. #Bernard's comment on this subject is worth reading.
docker stop CONTAINER_ID | xargs docker rm
You can stop and remove the container with a single command the $_ gives you the last echo
docker stop CONTAINER && docker rm $_
In my case, to remove the running containers I used
docker rm -f $(docker ps -a -q)
In case you also need to remove the images, then run
docker rmi $(docker images -q) afterwards.
Only run docker rmi $(docker images -q) if you want to remove the images.
https://www.ctl.io/developers/blog/post/gracefully-stopping-docker-containers/
You can use kill, and also by using rm and the force flag it will also use kill.
Remove all containers: docker ps -aq | xargs docker rm -f
This will stop and remove all images including running containers as we are using -f
docker rmi -f $(docker images -a -q)
Use the docker ps command with the -a flag to locate the name or ID of the containers you want to remove
docker ps -a
To remove: $ docker rm ID_or_Name ID_or_Name
Remove a container upon exit:
If you know when you’re creating a container that you won’t want to keep it around once you’re done, you can run docker run --rm to automatically delete it when it exits.
Run and Remove : docker run --rm image_name
Remove all exited containers:
You can locate containers using docker ps -a and filter them by their status: created, restarting, running, paused, or exited. To review the list of exited containers, use the -f flag to filter based on status. When you've verified you want to remove those containers, using -q to pass the IDs to the docker rm command.
List:
docker ps -a -f status=exited
docker rm $(docker ps -a -f status=exited -q)
Remove containers using more than one filter:
Docker filters can be combined by repeating the filter flag with an additional value. This results in a list of containers that meet either condition. For example, if you want to delete all containers marked as either Created (a state which can result when you run a container with an invalid command) or Exited, you can use two filters:
docker ps -a -f status=exited -f status=created
Stop and Remove all the containers:
docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)
For removing a single container
docker rm -f CONTAINER_ID
For removing all containers
docker rm -f `docker container ps -qa`
To remove all stopped containers docker system prune
To stop live container, docker stop CONTAINER_ID waits 10 sec and it calls docker kill CONTAINER_ID
Or with docker kill CONTAINER_ID, you can immediately stop the container
remove all container with xargs
docker ps -a -q | xargs docker rm
for stop all
sudo docker ps -a -q |sudo xargs docker stop
remove single container
docker rm -f <container_id>

Best way to stop Docker container in Jenkins

I have a CI-server (jenkins) which is building new Docker images.
Now I want to run a new Docker container when the build is succesful.
But therefor I have to stop the previous running container.
What's the best way to perform this?
localhost:5000/test/myapp:"${BUILD_ID} is the name of my new images. So I'm using the build-id as tag. First I thought to perform:
docker stop localhost:5000/dbm/my-php-app:${BUILD_ID-1}
But this isn't a right solution because when a build would fail, this would be wrong.
Build 1: succes -> run container 1
Build 2: failed -> run container 1
Build 3: succes -> stop container (3-1) =2 --> wrong (isn't running)
What could be a solution? Proposals where I have to change the tag-idea are also welcome
The docker stop command takes a docker container name as parameter, not a docker image ID.
You would have to name your container when you run it:
# build the new image
docker build -t localhost:5000/test/myapp:"${BUILD_ID}" .
# remove the existing container
docker rm -f myjob && echo "container myjob removed" || echo "container myjob does not exist"
# create and run a new container
docker run -d --name myjob localhost:5000/test/myapp:"${BUILD_ID}"
Just replace myjob with a better suited name in this example.
Thanks to #Thomasleveil I found the answer on my question:
# build the new image
docker build -t localhost:5000/test/myapp:"${BUILD_ID}" .
# remove old container
SUCCESS_BUILD=`wget -qO- http://jenkins_url:8080/job/jobname/lastSuccessfulBuild/buildNumber`
docker rm -f "${SUCCESS_BUILD}" && echo "container ${SUCCESS_BUILD} removed" || echo "container ${SUCCESS_BUILD} does not exist"
# run new container
docker run -d -p 80:80 --name "${BUILD_ID}" localhost:5000/test/myapp:${version}
If you are using Jenkins Pipeline and want to gracefully stop and remove containers then here is the solution.
First you have to check is any container is present, and if there is any then you will have to stop and remove it. Here is the code
def doc_containers = sh(returnStdout: true, script: 'docker container ps -aq').replaceAll("\n", " ")
if (doc_containers) {
sh "docker stop ${doc_containers}"
}
The variable doc_containers will store the container IDs, and you can perform the empty check. If container is not available then docker stop command should not be executed.
Here is the pipeline code
stage('Clean docker containers'){
steps{
script{
def doc_containers = sh(returnStdout: true, script: 'docker container ps -aq').replaceAll("\n", " ")
if (doc_containers) {
sh "docker stop ${doc_containers}"
}
}
}
}

Resources