Как автоматически обновить контейнеры docker, если обновляются базовые изображения


скажем, у меня есть тривиальный контейнер, основанный на ubuntu:latest. Теперь есть обновление для системы безопасности и ubuntu:latest обновляется в репо docker .

  1. Как я узнаю, что мой локальный образ и его контейнеры работают позади?

  2. есть ли какая-то лучшая практика для автоматического обновления локальных образов и контейнеров, чтобы следовать обновлениям Docker repo, которые на практике дадут вам те же тонкости автоматического обновления, запущенного на a обычная ubuntu-машина

12 137

12 ответов:

один из способов сделать это-проехать через ваши системы CI/CD. После того, как ваш родительский образ построен, есть что-то, что сканирует ваши репозитории git для изображений с использованием этого родителя. Если он будет найден, вы отправите запрос на вытягивание, чтобы перейти к новым версиям изображения. Запрос на вытягивание, если все тесты пройдут, будет объединен, и у вас будет новый дочерний образ на основе обновленного родителя. Пример инструмента, который использует этот подход можно найти здесь: https://engineering.salesforce.com/open-sourcing-dockerfile-image-update-6400121c1a75 .

Если вы не контролируете свой родительский образ, как это было бы в случае, если вы зависите от официального ubuntu image, вы можете написать некоторые инструменты, которые обнаруживают изменения в теге родительского изображения и вызывают дочерние сборки изображений соответственно.

мы используем скрипт, который проверяет, запущен ли запущенный контейнер с последним изображением. Мы также используем сценарии инициализации upstart для запуска образа docker.

#!/usr/bin/env bash
set -e
BASE_IMAGE="registry"
REGISTRY="registry.hub.docker.com"
IMAGE="$REGISTRY/$BASE_IMAGE"
CID=$(docker ps | grep $IMAGE | awk '{print }')
docker pull $IMAGE

for im in $CID
do
    LATEST=`docker inspect --format "{{.Id}}" $IMAGE`
    RUNNING=`docker inspect --format "{{.Image}}" $im`
    NAME=`docker inspect --format '{{.Name}}' $im | sed "s/\///g"`
    echo "Latest:" $LATEST
    echo "Running:" $RUNNING
    if [ "$RUNNING" != "$LATEST" ];then
        echo "upgrading $NAME"
        stop docker-$NAME
        docker rm -f $NAME
        start docker-$NAME
    else
        echo "$NAME up to date"
    fi
done

и инициализации выглядит так:

docker run -t -i --name $NAME $im /bin/bash

"докер путь" будет использовать докер-концентраторавтоматизированное построение. Элемент Ссылки На Репозиторий функция перестроит ваш контейнер, когда восходящий контейнер будет перестроен, и веб-перехватчиков функция отправит вам уведомление.

похоже, что веб-крючки ограничены вызовами HTTP POST. Вам нужно будет настроить службу, чтобы поймать их, или, возможно, использовать один из сообщений для почтовых служб там.

У меня нет заглянул в него, но новый Докер Универсальный Самолет Управления может иметь функцию для обнаружения обновленных контейнеров и повторного развертывания.

у меня была такая же проблема, и я думал, что ее можно просто решить с помощью вызова cronunattended-upgrade ежедневно.

Я намерен использовать это как автоматическое и быстрое решение для обеспечения безопасности и обновления производственного контейнера, поскольку мне может потребоваться некоторое время для обновления моих образов и развертывания нового образа docker с последними обновлениями безопасности.

также можно автоматизировать построение и развертывание образа с помощью Github крючки

Я создал Docker-образ С этим автоматически проверяет и устанавливает обновления безопасности ежедневно (может работать непосредственно по docker run itech/docker-unattended-upgrade).

Я также наткнулся на другой другой подход чтобы проверить, нуждается ли контейнер в обновлении.

Моя полная реализация:

Dockerfile

FROM ubuntu:14.04   

RUN apt-get update \
&& apt-get install -y supervisor unattended-upgrades \
&& rm -rf /var/lib/apt/lists/*

COPY install /install
RUN chmod 755 install
RUN /install

COPY start /start
RUN chmod 755 /start

помощник скрипты

установить

#!/bin/bash
set -e

cat > /etc/supervisor/conf.d/cron.conf <<EOF
[program:cron]
priority=20
directory=/tmp
command=/usr/sbin/cron -f
user=root
autostart=true
autorestart=true
stdout_logfile=/var/log/supervisor/%(program_name)s.log
stderr_logfile=/var/log/supervisor/%(program_name)s.log
EOF

rm -rf /var/lib/apt/lists/*

ENTRYPOINT ["/start"]

старт

#!/bin/bash

set -e

echo "Adding crontab for unattended-upgrade ..."
echo "0 0 * * * root /usr/bin/unattended-upgrade" >> /etc/crontab

# can also use @daily syntax or use /etc/cron.daily

echo "Starting supervisord ..."
exec /usr/bin/supervisord -n -c /etc/supervisor/supervisord.conf

Edit

Я разработал небольшой инструмент docker-run который работает как контейнер docker и может использоваться для обновления пакетов внутри всех или выбранных запущенных контейнеров, он также может использоваться для запуска любых произвольных команд.

смогите легко быть испытано с следующим команда:

docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run exec

, который по умолчанию будет выполнять date команда во всех запущенных контейнерах и отображение результатов. Если вы пройдете update вместо exec он будет выполнять apt-get update следовал по apt-get upgrade -y во всех запущенных контейнеров

можно использовать башня чтобы следить за обновлениями образа, из которого создается экземпляр контейнера, автоматически извлеките обновление и перезапустите контейнер с помощью обновленного образа. Однако это не решает проблему восстановления ваших собственных пользовательских изображений, когда есть изменение в исходном изображении, на котором оно основано. Вы можете рассматривать это как проблему из двух частей: (1) зная, когда восходящее изображение было обновлено, и (2) делая фактическое перестроение изображения. (1) может быть решена достаточно легко, но (2) во многом зависит от вашей локальной среды сборки/практики, поэтому, вероятно, гораздо сложнее создать обобщенное решение для этого.

Если вы можете использовать Docker Hub в автоматизированное построение, вся проблема может быть решена относительно чисто с помощью ссылки на репозиторий функция, которая позволяет автоматически запускать перестройку при обновлении связанного репозитория (возможно, вышестоящего). Вы также можете настроить webhook to уведомляет вас, когда происходит автоматическая сборка. Если вы хотите уведомление по электронной почте или SMS, вы можете подключить webhook к IFTTT Maker. Я нашел частичное будильника пользовательского интерфейса, чтобы быть немного запутанным, но вы настроить настройки веб-перехватчик на должность https://maker.ifttt.com/trigger/docker_xyz_image_built/С/ключ/your_key.

Если вам нужно построить локально, вы можете по крайней мере решить проблему получения уведомлений при обновлении восходящего изображения, создав манекен РЕПО в Docker Hub связано с интересующими вас РЕПО. Единственной целью фиктивного РЕПО было бы вызвать webhook, когда он будет перестроен (что подразумевает, что один из его связанных РЕПО был обновлен). Если вы можете получить этот веб-крючок, вы можете даже использовать его, чтобы вызвать перестройку на вашей стороне.

вы не знаете ваш контейнер не работает докер тянуть. Тогда вам нужно будет восстановить или композицию ваш образ.

docker pull image:tag
docker-compose -f docker-compose.yml -f production.yml up -d --build

команды могут быть помещены в сценарий вместе с чем-либо еще, необходимым для завершения обновления, хотя надлежащий контейнер не будет нуждаться в чем-либо дополнительном.

Я не буду вдаваться в весь вопрос о том, хотите ли вы автоматические обновления в производстве (я думаю, что нет). Я просто оставляю это здесь для справки, если кто-нибудь сочтет это полезным. Обновите все изображения docker до последней версии с помощью следующей команды в терминале:

# docker images | awk '(NR>1) && (!~/none/) {print ":"}' | xargs -L1 docker pull

другой подход может заключаться в том, чтобы предположить, что ваш базовый образ довольно быстро отстает (и это очень вероятно), и периодически принудительно создавать другой образ вашего приложения (например, каждую неделю), а затем повторно развертывать его, если он изменился.

насколько я могу судить, популярные базовые образы, такие как официальный Debian или Java, обновляют свои теги для удовлетворения исправлений безопасности, поэтому теги не являются неизменяемыми (если вы хотите более сильную гарантию того, что вам нужно использовать ссылку [image:@digest], доступно в более поздних версиях Docker). Поэтому, если вы должны были построить свой образ с docker build --pull, то ваше приложение должно получить последнюю и самую большую из базового тега изображения, на который вы ссылаетесь.

поскольку изменяемые теги могут сбивать с толку, лучше каждый раз увеличивать номер версии вашего приложения, чтобы по крайней мере на вашей стороне все было чище.

поэтому я не уверен, что сценарий, предложенный в одной из предыдущих ответов выполняет задание, так как он не перестраивает образ приложения - он просто обновляет тег базового образа, а затем перезапускает контейнер, но новый контейнер по-прежнему ссылается на старый хэш базового образа.

Я бы не выступал за запуск заданий типа cron в контейнерах (или любых других процессах, если это действительно необходимо), поскольку это противоречит мантре запуска только одного процесса на контейнер (есть различные аргументы о том, почему это лучше, поэтому я не буду вдаваться в это здесь.)

предпосылка к моему ответу:

  1. контейнеры запускаются с тегами.
  2. тот же тег можно указать на другой UUID изображения, как нам нравится/ чувствовать себя уместно.
  3. обновления, выполненные для изображения, могут быть зафиксированы в новом слое изображения

подход

  1. построить все контейнеры в первую очередь с помощью сценария обновления security-patch
  2. построить автоматизированный процесс для следующий
    • запустите существующий образ в новый контейнер с помощью сценария исправления безопасности в качестве команды
    • зафиксировать изменения в изображении как
      • существующий тег - > с последующим перезапуском контейнеров один за другим
      • новая версия тега - > заменить несколько контейнеров с новым тегом - > проверить - > переместить все контейнеры в новый тег

дополнительно, низкопробное изображение можно модернизировать / контейнер с полным новое базовое изображение может быть построено через регулярные промежутки времени, так как сопровождающий чувствует себя необходимым

преимущества

  1. мы сохраняем старую версию образа при создании нового исправленного образа безопасности, поэтому при необходимости мы можем откатиться к предыдущему запущенному образу
  2. мы сохраняем кэш docker, следовательно, меньше сетевой передачи (только измененный слой попадает на провод)
  3. процесс обновления можно проверить в промежуточном прежде чем перейти к прод
  4. Это может быть контролируемый процесс, поэтому патчи безопасности только тогда, когда это необходимо/ считается важным, могут быть выдвинуты.

управление зависимостями для докеров изображений является реальной проблемой. Я часть команды, которая построила инструмент, MicroBadger, чтобы помочь с этим путем мониторинга изображений контейнеров и проверки метаданных. Одна из его особенностей заключается в том, чтобы вы могли настроить уведомление webhook, которое вызывается при изменении интересующего вас изображения (например, базового изображения).

есть много ответов, но ни один из них не отвечал моим потребностям. Я хотел получить реальный ответ на вопрос № 1 спрашивающего. Как узнать, когда изображение обновляется hub.docker.com?

ниже скрипт может быть запущен ежедневно. При первом запуске он получает базовую версию тегов и даты обновления из реестра концентратора и сохраняет их локально. С тех пор, каждый раз, когда он запускается, он проверяет реестр на наличие новых тегов и обновление даты. Поскольку это изменяется каждый раз, когда существует новое изображение, оно сообщает мы, если базовый образ изменился. Вот этот скрипт:

#!/bin/bash

DATAPATH='/data/docker/updater/data'

if [ ! -d "${DATAPATH}" ]; then
        mkdir "${DATAPATH}";
fi
IMAGES=$(docker ps --format "{{.Image}}")
for IMAGE in $IMAGES; do
        ORIGIMAGE=${IMAGE}
        if [[ "$IMAGE" != *\/* ]]; then
                IMAGE=library/${IMAGE}
        fi
        IMAGE=${IMAGE%%:*}
        echo "Checking ${IMAGE}"
        PARSED=${IMAGE//\//.}
        if [ ! -f "${DATAPATH}/${PARSED}" ]; then
                # File doesn't exist yet, make baseline
                echo "Setting baseline for ${IMAGE}"
                curl -s "https://registry.hub.docker.com/v2/repositories/${IMAGE}/tags/" > "${DATAPATH}/${PARSED}"
        else
                # File does exist, do a compare
                NEW=$(curl -s "https://registry.hub.docker.com/v2/repositories/${IMAGE}/tags/")
                OLD=$(cat "${DATAPATH}/${PARSED}")
                if [[ "${VAR1}" == "${VAR2}" ]]; then
                        echo "Image ${IMAGE} is up to date";
                else
                        echo ${NEW} > "${DATAPATH}/${PARSED}"
                        echo "Image ${IMAGE} needs to be updated";
                        H=`hostname`
                        ssh -i /data/keys/<KEYFILE> <USER>@<REMOTEHOST>.com "{ echo \"MAIL FROM: root@${H}\"; echo \"RCPT TO: <USER>@<EMAILHOST>.com\"; echo \"DATA\"; echo \"Subject: ${H} - ${IMAGE} needs update\"; echo \"\"; echo -e \"\n${IMAGE} needs update.\n\ndocker pull ${ORIGIMAGE}\"; echo \"\"; echo \".\"; echo \"quit\"; sleep 1; } | telnet <SMTPHOST> 25"
                fi

        fi
done;

вы хотите изменить DATAPATH переменной в верхней части, и изменить команду уведомлений по электронной почте в конце, чтобы удовлетворить ваши потребности. Для меня у меня есть SSH на сервере в другой сети, где находится мой SMTP. Но вы можете легко использовать тоже.

теперь, вы также хотите, чтобы проверить наличие обновленных пакетов внутри самих контейнеров. Это на самом деле, вероятно, более эффективно, чем делать "потяните", как только ваши контейнеры работают. Вот сценарий, чтобы снять это:

#!/bin/bash


function needsUpdates() {
        RESULT=$(docker exec  bash -c ' \
                if [[ -f /etc/apt/sources.list ]]; then \
                grep security /etc/apt/sources.list > /tmp/security.list; \
                apt-get update > /dev/null; \
                apt-get upgrade -oDir::Etc::Sourcelist=/tmp/security.list -s; \
                fi; \
                ')
        RESULT=$(echo $RESULT)
        GOODRESULT="Reading package lists... Building dependency tree... Reading state information... Calculating upgrade... 0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded."
        if [[ "${RESULT}" != "" ]] && [[ "${RESULT}" != "${GOODRESULT}" ]]; then
                return 0
        else
                return 1
        fi
}

function sendEmail() {
        echo "Container  needs security updates";
        H=`hostname`
        ssh -i /data/keys/<KEYFILE> <USRER>@<REMOTEHOST>.com "{ echo \"MAIL FROM: root@${H}\"; echo \"RCPT TO: <USER>@<EMAILHOST>.com\"; echo \"DATA\"; echo \"Subject: ${H} -  container needs security update\"; echo \"\"; echo -e \"\n container needs update.\n\n\"; echo -e \"docker exec  bash -c 'grep security /etc/apt/sources.list > /tmp/security.list; apt-get update > /dev/null; apt-get upgrade -oDir::Etc::Sourcelist=/tmp/security.list -s'\n\n\"; echo \"Remove the -s to run the update\"; echo \"\"; echo \".\"; echo \"quit\"; sleep 1; } | telnet <SMTPHOST> 25"
}

CONTAINERS=$(docker ps --format "{{.Names}}")
for CONTAINER in $CONTAINERS; do
        echo "Checking ${CONTAINER}"
        if needsUpdates $CONTAINER; then
                sendEmail $CONTAINER
        fi
done

выше ответы также правильные

есть два подхода

  1. использовать webhooks
  2. запустить скрипт для каждой конкретной минуты, чтобы получить свежий тянуть докер изображений

Я просто разделяю скрипт может быть это будет полезно для вас! Вы можете использовать его с cronjob, я пытался успешно на OSX

#!/bin/bash
##You can use below commented line for setting cron tab for running cron job and to store its O/P in one .txt file  
#* * * * * /usr/bin/sudo -u admin -i bash -c /Users/Swapnil/Documents/checkimg.sh > /Users/Swapnil/Documents/cron_output.log 2>&1
# Example for the Docker Hub V2 API
# Returns all images and tags associated with a Docker Hub organization account.
# Requires 'jq': https://stedolan.github.io/jq/

# set username, password, and organization
# Filepath where your docker-compose file is present
FILEPATH="/Users/Swapnil/Documents/lamp-alpine"
# Your Docker hub user name
UNAME="ur username"
# Your Docker hub user password
UPASS="ur pwd"
# e.g organisation_name/image_name:image_tag
ORG="ur org name"
IMGNAME="ur img name"
IMGTAG="ur img tag"
# Container name
CONTNAME="ur container name"
# Expected built mins
BUILDMINS="5"
#Generally cronjob frequency
CHECKTIME="5"
NETWORKNAME="${IMGNAME}_private-network"
#After Image pulling, need to bring up all docker services?
DO_DOCKER_COMPOSE_UP=true
# -------
echo "Eecuting Script @ date and time in YmdHMS: $(date +%Y%m%d%H%M%S)"
set -e
PIDFILE=/Users/Swapnil/Documents/$IMGNAME/forever.pid
if [ -f $PIDFILE ]
then
  PID=$(cat $PIDFILE)
  ps -p $PID > /dev/null 2>&1
  if [ $? -eq 0 ]
  then
    echo "Process already running"
    exit 1
  else
    ## Process not found assume not running
    echo $$
    echo $$ > $PIDFILE
    if [ $? -ne 0 ]
    then
      echo "Could not create PID file"
      exit 1
    fi
  fi
else
  echo $$ > $PIDFILE
  if [ $? -ne 0 ]
  then
    echo "Could not create PID file"
    exit 1
  fi
fi

# Check Docker is running or not; If not runing then exit
if docker info|grep Containers ; then
    echo "Docker is running"
else
    echo "Docker is not running"
    rm $PIDFILE
    exit 1
fi

# Check Container is running or not; and set variable
CONT_INFO=$(docker ps -f "name=$CONTNAME" --format "{{.Names}}")
if [ "$CONT_INFO" = "$CONTNAME" ]; then
    echo "Container is running"
    IS_CONTAINER_RUNNING=true
else
    echo "Container is not running"
    IS_CONTAINER_RUNNING=false
fi


# get token
echo "Retrieving token ..."
TOKEN=$(curl -s -H "Content-Type: application/json" -X POST -d '{"username": "'${UNAME}'", "password": "'${UPASS}'"}' https://hub.docker.com/v2/users/login/ | jq -r .token)

# get list of repositories
echo "Retrieving repository list ..."
REPO_LIST=$(curl -s -H "Authorization: JWT ${TOKEN}" https://hub.docker.com/v2/repositories/${ORG}/?page_size=100 | jq -r '.results|.[]|.name')

# output images & tags
echo "Images and tags for organization: ${ORG}"
echo
for i in ${REPO_LIST}
do
  echo "${i}:"
  # tags
  IMAGE_TAGS=$(curl -s -H "Authorization: JWT ${TOKEN}" https://hub.docker.com/v2/repositories/${ORG}/${i}/tags/?page_size=100 | jq -r '.results|.[]|.name')
  for j in ${IMAGE_TAGS}
  do
    echo "  - ${j}"
  done
  #echo
done

# Check Perticular image is the latest or not
#imm=$(curl -s -H "Authorization: JWT ${TOKEN}" https://hub.docker.com/v2/repositories/${ORG}/${IMGNAME}/tags/?page_size=100)
echo "-----------------"
echo "Last built date details about Image ${IMGNAME} : ${IMGTAG} for organization: ${ORG}"
IMAGE_UPDATED_DATE=$(curl -s -H "Authorization: JWT ${TOKEN}" https://hub.docker.com/v2/repositories/${ORG}/${IMGNAME}/tags/?page_size=100 | jq -r '.results|.[]|select(.name | contains("'${IMGTAG}'")).last_updated')
echo "On Docker Hub IMAGE_UPDATED_DATE---$IMAGE_UPDATED_DATE"
echo "-----------------"

IMAGE_CREATED_DATE=$(docker image inspect ${ORG}/${IMGNAME}:${IMGTAG} | jq -r '.[]|.Created')
echo "Locally IMAGE_CREATED_DATE---$IMAGE_CREATED_DATE"

updatedDate=$(date -jf '%Y-%m-%dT%H:%M' "${IMAGE_UPDATED_DATE:0:16}" +%Y%m%d%H%M%S) 
createdDate=$(date -jf '%Y-%m-%dT%H:%M' "${IMAGE_CREATED_DATE:0:16}" +%Y%m%d%H%M%S)
currentDate=$(date +%Y%m%d%H%M%S)

start_date=$(date -jf "%Y%m%d%H%M%S" "$currentDate" "+%s")
end_date=$(date -jf "%Y%m%d%H%M%S" "$updatedDate" "+%s")
updiffMins=$(( ($start_date - $end_date) / (60) ))
if [[ "$updiffMins" -lt $(($CHECKTIME+1)) ]]; then
        if [ ! -d "${FILEPATH}" ]; then
            mkdir "${FILEPATH}";
        fi
        cd "${FILEPATH}"
        pwd
        echo "updatedDate---$updatedDate" > "ScriptOutput_${currentDate}.txt"
        echo "createdDate---$createdDate" >> "ScriptOutput_${currentDate}.txt"
        echo "currentDate---$currentDate" >> "ScriptOutput_${currentDate}.txt"
        echo "Found after regular checking time -> Docker hub's latest updated image is new; Diff ${updiffMins} mins" >> "ScriptOutput_${currentDate}.txt"
        echo "Script is checking for latest updates after every ${CHECKTIME} mins" >> "ScriptOutput_${currentDate}.txt"
        echo "Fetching all new"
        echo "---------------------------"
        if $IS_CONTAINER_RUNNING ; then
            echo "Container is running"         
        else
            docker-compose down
            echo "Container stopped and removed; Network removed" >> "ScriptOutput_${currentDate}.txt"
        fi
        echo "Image_Created_Date=$currentDate" > ".env"
        echo "ORG=$ORG" >> ".env"
        echo "IMGNAME=$IMGNAME" >> ".env"
        echo "IMGTAG=$IMGTAG" >> ".env"
        echo "CONTNAME=$CONTNAME" >> ".env"
        echo "NETWORKNAME=$NETWORKNAME" >> ".env"
        docker-compose build --no-cache
        echo "Docker Compose built" >> "ScriptOutput_${currentDate}.txt"
        if $DO_DOCKER_COMPOSE_UP ; then
            docker-compose up -d
            echo "Docker services are up now, checked in" >> "ScriptOutput_${currentDate}.txt"  
        else
            echo "Docker services are down, checked in" >> "ScriptOutput_${currentDate}.txt"
        fi
elif [[ "$updatedDate" -gt "$createdDate" ]]; then 
    echo "Updated is latest"
    start_date=$(date -jf "%Y%m%d%H%M%S" "$updatedDate" "+%s")
    end_date=$(date -jf "%Y%m%d%H%M%S" "$createdDate" "+%s")
    diffMins=$(( ($start_date - $end_date) / (60) ))
    if [[ "$BUILDMINS" -lt "$diffMins" ]]; then
        if [ ! -d "${FILEPATH}" ]; then
            mkdir "${FILEPATH}";
        fi
        cd "${FILEPATH}"
        pwd
        echo "updatedDate---$updatedDate" > "ScriptOutput_${currentDate}.txt"
        echo "createdDate---$createdDate" >> "ScriptOutput_${currentDate}.txt"
        echo "currentDate---$currentDate" >> "ScriptOutput_${currentDate}.txt"
        echo "Found after comparing times -> Docker hub's latest updated image is new; Diff ${diffMins} mins" >> "ScriptOutput_${currentDate}.txt"
        echo "Actual image built time is less i.e. ${diffMins} mins than MAX expexted BUILD TIME i.e. ${BUILDMINS} mins" >> "ScriptOutput_${currentDate}.txt"
        echo "Fetching all new" >> "ScriptOutput_${currentDate}.txt"
        echo "-----------------------------"
        if $IS_CONTAINER_RUNNING ; then
            echo "Container is running"         
        else
            docker-compose down
            echo "Container stopped and removed; Network removed" >> "ScriptOutput_${currentDate}.txt"
        fi
        echo "Image_Created_Date=$currentDate" > ".env"
        echo "ORG=$ORG" >> ".env"
        echo "IMGNAME=$IMGNAME" >> ".env"
        echo "IMGTAG=$IMGTAG" >> ".env"
        echo "CONTNAME=$CONTNAME" >> ".env"
        echo "NETWORKNAME=$NETWORKNAME" >> ".env"
        docker-compose build --no-cache
        echo "Docker Compose built" >> "ScriptOutput_${currentDate}.txt"
        if $DO_DOCKER_COMPOSE_UP ; then
            docker-compose up -d
            echo "Docker services are up now" >> "ScriptOutput_${currentDate}.txt"  
        else
            echo "Docker services are down" >> "ScriptOutput_${currentDate}.txt"
        fi
    elif [[ "$BUILDMINS" -gt "$diffMins" ]]; then
        echo "Docker hub's latest updated image is NOT new; Diff ${diffMins} mins"
        echo "Docker images not fetched"
    else
        echo "Docker hub's latest updated image is NOT new; Diff ${diffMins} mins"
        echo "Docker images not fetched"
    fi
elif [[ "$createdDate" -gt "$updatedDate" ]]; then 
    echo "Created is latest"
    start_date=$(date -jf "%Y%m%d%H%M%S" "$createdDate" "+%s")
    end_date=$(date -jf "%Y%m%d%H%M%S" "$updatedDate" "+%s")
    echo "Docker hub has older docker image than local; Older than $(( ($start_date - $end_date) / (60) ))mins"
fi
echo 
echo "------------end---------------"
rm $PIDFILE

вот мой docker-compose file

version:  "3.2"
services:
  lamp-alpine:
    build:
      context: .
    container_name: "${CONTNAME}"
    image: "${ORG}/${IMGNAME}:${IMGTAG}"
    ports:
      - "127.0.0.1:80:80"
    networks:
      - private-network 

networks:
  private-network:
    driver: bridge