Search code examples
dockercicdazure-devops-self-hosted-agentbuild-agent

How to automatically restart a Docker container with/from a clean image?


I'm working on introducing build agents in docker container and starting them currently with the following command:

docker run -d --restart=unless-stopped --cpus="4" -m="8g" --name "${AZP_AGENT_NAME}${i}" -e AZP_URL="$AZP_URL" -e AZP_TOKEN="$AZP_TOKEN" -e AZP_AGENT_NAME="${AZP_AGENT_NAME}${i}" -e AZP_POOL="$AZP_POOL" -v /var/run/docker.sock:/var/run/docker.sock -ti dockeragent:latest --once

This allows us to run our build pipeline in docker containers which will restart as soon as the build tasks are complete (container is being shutdown after finishing last task with argument --once.

As --restart=unless-stopped will keep the same container (and underlying file system) when restarting, I have the same state of the container as before (which is probably the intended strategy for most use cases). But as we expect a clean container for each build, this is not the right way.

Is there a way to always restart the container from a fresh image in an initial state?

I tried with the combination of --restart=unless-stopped --rm but this makes docker not happy and replies with docker: Conflicting options: --restart and --rm.. I excepted the container to be removed and be running fresh from the image again. But it probably makes sense this isn't going to work as the intended goal would be to bring up the same container again.




Thanks to @jcragun, I ended up with the following systemd unit configuration:
[Unit]
Description=Dockeragent <Agent-Hostname>-<Agent-Instance>
After=docker.service
Requires=docker.service

[Service]
EnvironmentFile=/etc/systemd/system/<Agent-Hostname>-<Agent-Instance>.service.d/env.conf
TimeoutStartSec=0
Restart=always
ExecStartPre=-/usr/bin/docker stop %n 
ExecStartPre=-/usr/bin/docker rm %n
ExecStart=/usr/bin/docker run --rm --cpus="4" -m="8g" --name %n \
        -e AZP_URL=${AZP_URL} -e AZP_TOKEN=${AZP_TOKEN} -e AZP_AGENT_NAME=${AZP_AGENT_HOSTNAME}-<Agent-Instance> -e AZP_POOL=${AZP_POOL} \
        -v /var/run/docker.sock:/var/run/docker.sock \
        dockeragent:latest --once

[Install]
WantedBy=default.target

Solution

  • Consider using a process manager like systemd to do this work outside of the container lifecycle as managed by Docker. See Docker docs for more info. For example:

    [Unit]
    Description=My Service
    After=docker.service
    Requires=docker.service
    
    [Service]
    TimeoutStartSec=0
    Restart=always
    ExecStartPre=-/usr/bin/docker exec %n stop
    ExecStartPre=-/usr/bin/docker rm %n
    ExecStartPre=/usr/bin/docker pull dockeragent:latest
    ExecStart=/usr/bin/docker run --rm --name %n \
        -v /var/run/docker.sock:/var/run/docker.sock \
        dockeragent:latest
    
    [Install]
    WantedBy=default.target