5

I have a starting docker script here:

#!/usr/bin/env bash
set -e

echo '>>> Get old container id'
CID=$(sudo docker ps --all | grep "web-client" | awk '{print $1}')
echo $CID


echo '>>> Stopping and deleting old container'
if [ "$CID" != "" ];
then
  sudo docker stop $CID
  sudo docker rm $CID
fi


echo '>>> Starting new container'
sudo docker pull my-example-registry.com:5050/web-client:latest
sudo docker run --name=web-client -p 8080:80 -d my-example-registry.com:5050/web-client:latest

The fact is this script has umproper result. It deletes the old container everytime the script is run.

The "starting new container" section will pull the most recent image. Here is an example output of docker pull if the image locally is up to date:

Status: Image is up to date for my-example-registry:5050/web-client:latest

Is there any way to improve my script by adding a condition:

Before anything, check via docker pull the local image is the most recent version available on registry. Then if it's the most recent version, proceed the stop and delete old container action and docker run the new pulled image.

In this script, how to parse the status to check the local image corresponds to the most up to date available on registry?

Maybe a docker command can do the trick, but I didn't manage to find a useful one.

Scott Stensland
  • 26,870
  • 12
  • 93
  • 104
BlackHoleGalaxy
  • 9,160
  • 17
  • 59
  • 103

3 Answers3

7

Check the string "Image is up to date" to know whether the local image was updated:

sudo docker pull my-example-registry.com:5050/web-client:latest | 
   grep "Image is up to date" ||
   (echo Already up to date. Exiting... && exit 0)

So change your script to:

#!/usr/bin/env bash
set -e

sudo docker pull my-example-registry.com:5050/web-client:latest | 
   grep "Image is up to date" ||
   (echo Already up to date. Exiting... && exit 0)


echo '>>> Get old container id'
CID=$(sudo docker ps --all | grep "web-client" | awk '{print $1}')
echo $CID


echo '>>> Stopping and deleting old container'
if [ "$CID" != "" ];
then
  sudo docker stop $CID
  sudo docker rm $CID
fi


echo '>>> Starting new container'
sudo docker run --name=web-client -p 8080:80 -d my-example-registry.com:5050/web-client:latest
Robert
  • 33,429
  • 8
  • 90
  • 94
  • That exit 0 won't work as it's wrapped in a command grouping – Shardj Jul 06 '22 at 15:16
  • Comment is gonna screw up this formatting but: `pullContents=$(docker pull imagename); pullCode=$?; if (( $pullCode > 0 )) ; then echo 'Failed to pull image'; exit 1; fi; if echo $pullContents | grep "Image is up to date" ; then echo 'Image already up to date'; exit 0; fi` – Shardj Jul 06 '22 at 15:26
4

Simple use docker-compose and you can remove all the above.

docker-compose pull && docker-compose up

This will pull the image, if it exists, and up will only recreate the container, if it actually has a newer image, otherwise it will do nothing

Eugen Mayer
  • 8,942
  • 4
  • 33
  • 57
1

If you're using docker compose, here's my solution where I keep put my latest docker-compose.yml into an image right after I've pushed all of the needed images that are in docker-compose.yml

The server runs this as a cron job:

#!/usr/bin/env bash
docker login --username username --password password
if (( $? > 0 )) ; then
  echo 'Failed to login'
  exit 1
fi
# Grab latest config, if the image is different then we have a new update to make
pullContents=$(docker pull my/registry:config-holder)
if (( $? > 0 )) ; then
  echo 'Failed to pull image'
  exit 1
fi
if echo $pullContents | grep "Image is up to date" ; then
  echo 'Image already up to date'
  exit 0
fi

cd /srv/www/

# Grab latest docker-compose.yml that we'll be needing
docker run -d --name config-holder my/registry:config-holder
docker cp config-holder:/home/docker-compose.yml docker-compose-new.yml
docker stop config-holder
docker rm config-holder

# Use new yml to pull latest images
docker-compose -f docker-compose-new.yml pull

# Stop server
docker-compose down

# Replace old yml file with our new one, and spin back up
mv docker-compose-new.yml docker-compose.yml
docker-compose up -d

Config holder dockerfile:

FROM bash
# This image exists just to hold the docker-compose.yml. So when remote updating the server can pull this, get the latest docker-compose file, then pull those
COPY docker-compose.yml /home/docker-compose.yml
# Ensures that the image is subtly different every time we deploy. This is required we want the server to find this image has changed to trigger a new deployment
RUN bash -c "touch random.txt; echo $(echo $RANDOM | md5sum | head -c 20) >> random.txt"
# Wait forever
CMD exec bash -c "trap : TERM INT; sleep infinity & wait"
Shardj
  • 1,800
  • 2
  • 17
  • 43