Docker и git clone: как бороться с using cache?
Уважаемые господа,
я делаю вот что:
у меня есть исходный код (мой) моего простенького приложения, написанного на C# / NET Core 6.0, лежащий в репозитории на гитхабе.
Я пишу Dockerfile, который должен взять этот код, и собрать приложение.
Это - довольно распространненная практика, как я понял - отдельный контейнер, который собирает приложение.
вот этот докерфайл, в нём нет ничего особенно оригинального (ия его нарочно не оптимизировал):
FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -y wget
RUN wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
RUN dpkg -i packages-microsoft-prod.deb
RUN rm packages-microsoft-prod.deb
RUN apt-get update
RUN apt-get install -y apt-transport-https
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
RUN apt-get install -y dotnet-sdk-6.0
# dotnet sdk is installed!
RUN apt-get install -y git
ARG ssh_prv_key
ARG ssh_pub_key
# Authorize SSH Host
RUN mkdir -p /root/.ssh
RUN chmod 0700 /root/.ssh
RUN ssh-keyscan github.com > /root/.ssh/known_hosts
# Add the keys and set permissions
RUN echo "$ssh_prv_key" > /root/.ssh/id_rsa
RUN echo "$ssh_pub_key" > /root/.ssh/id_rsa.pub
RUN chmod 600 /root/.ssh/id_rsa
RUN chmod 600 /root/.ssh/id_rsa.pub
WORKDIR /App
RUN git clone [email protected]:junecat/InternalProject.git
WORKDIR /App/InternalProject
RUN dotnet publish -c release
CMD mkdir /App/publish-output/
WORKDIR /App/publish-output
CMD cp -r /App/InternalProject/bin/Release/net6.0/* /App/publish-output
Из этого докерфайла я строю образ контейнера, котрый должен собрать придожение, командой
docker build -t internal_project_build-image --build-arg ssh_prv_key="$(cat ~/.ssh/ro1_key)" --build-arg ssh_pub_key="$(cat ~/.ssh/ro1_key.pub)" -f Dockerfile .
Как видите, на этом этапе мои readonly-ключи для доступа к github попадают с хоста в контейнер.
Затем я запускаю контейнер командой
docker run -it --name internal_project_build-cont -v /home/konst/BuildingContainer/publish-output:/App/publish-output -d internal_project_build-image
И у меня мой Dockerfile уже работал так, что я просто чувствовал себя властелином мира. Всё было классно.
До того момнета, как я внёс небольшие изменения в исходный код, а потом поопробовал пересобрать приложение.
Приложение собралось из старого исходного кода. я это видел по ошибкам, которые оно выдаёт. Именно на исправление этих ошибок были направлены мои "небольшим изменения".
И тогда я заметил, что при сборке образа контейнера в ответ на команду
RUN git clone [email protected]:junecat/InternalProject.git
я вижу в консоли команды docker build сообщение
Step 22/24 : RUN git clone [email protected]:junecat/InternalProject.git
---> Using cache
---> 3c5778dd3426
"Э! — сказали мы с Петром Ивановичем"
Похоже, по какой то неизвестной мне причине умный докер вместо того, чтобы сходить на гитхаб на свежими исходниками рещил, что "и так сойдёт!"
Как бы мне его от этого отучить?
Кстати, поверхностым поиском я вижу, что я не один мучаюсь. Но что то ни один из приведенны в том вопросе - ответе способов не кажется мне подходящим...
Также, спасибо Вам, если Вы дадите мне советы по оптимизации того процесса, которым я занимаюсь (построение приложения в контейнере)
Заранее большое спасибо за советы!
Небольшое дополнение
Во первых, спасибо большое tym32167 за совет использовать git pull после git clone. Это помогло, но, как и предсказывали в комментариях, ровно на один раз. Потом, видимо, "все закешировалось" опять. Конечно, я попробую еще раз проверить, может, я невнимательный был, но, кажется, это все таки не решает проблему.
Пока для меня проблему "решило" использование команды docker builder prune. Но я не зря взял слово "решило" в кавычки: эта команда сбрасывает весь кеш билдера. То есть, в следующий раз он ВСЁ, вот ВСЁ будет качать заново. По эффекту это похоже на то, что есть Вам не понравилась конкретная божья коровка на былинке - нужно выжечь весь луг напалмом и вырастить его заново.
Ответы (1 шт):
Благодаря комметариям к моему вопросу, я понял, что я "копал глубоко, но не в том месте"
Нет смысла для моего "простого, как рельсы" проекта связываться с тем, чтобы внутри контейнера забирать исходники из репозитория и что то из них собирать.
То есть, это, конечно, круто - когда контейнер всё это может делать, и мы для этого в него передаём снаружи ключи и т.п. - но, видимо, эту технику надо использовать для более сложных целей, например, в случае, когда какая то часть проекта обязана собираться из исходников...
Если же у нас есть "просто проект" - то лучшим способом его сборки будет такой:
делаем docker clone
в результате мы получаем каталог с исходником проекта. Из него запускаем сборку контейнера и потом запуск контейнера.
Дальше - только одно "косметическое" исправление: на верхнем уровне в этом каталоге лежат всего 2 вещи: Dockerfile и еще один каталог, в котором уже лежит проект в исходниках.
Какую проблему это решает?
Если у нас вдруг появится еще один проект, то это приведет просто к тому, что рядом с докерфайлом будет 2 каталога.
А это может произойти, либо потому, что мы решили, что просто в один репозиторий попадает несколько проектов (очень распространенная практика для небольщих проектов), либо потому, что рядом спроектом как то обычно сами собой появляются тесты, сетап и т.п. сопутствующие проекты.
В общем, я - как примерный мальчик - даже сделал демо-проект, который поясняет мою мысль.
Прект называется BuildDemo, соответственно, после
git clone [email protected]:junecat/BuildDemo.git
у Вас появится папочка ~/BuildDemo (буду считать, что всё происходит в домашней директории. Если нет - подправьте пути в тех местах, где это важно)
затем мы заходим в эту папку, и делаем
docker build -t build_demo-image -f Dockerfile .
docker run -it --name build_demo-cont -v ~/BuildDemo/publish-output:/App/publish-output -d build_demo-image
Теоретически, можно "воткнуть" в докерфайл последней строчкой STOPSIGNAL SIGQUIT и тогда можно будет уже после завершения работы контейнера попасть в него командой
docker exec -it build_demo-cont /bin/bash
и посмотреть, как там и что.
А еще - там в проекте лежит второй докерфайл (я, не мудрствуя лукаво, назвал его Dockerfile2).
Он собирает из результатов работы первого контейнера - второй контейнер, уже "рабочий":
docker build -t csharp_run_demo-image -f Dockerfile2 .
и запускает его командой
docker run -it --name csharp_run_demo-cont -v ~/BuildDemo/Logs/:/App/Logs/ -d csharp_run_demo-image
(также, эти команды лежат в )
Затем - вы можете в папке Logs, которая будет создана в ~/BuildDemo, и убедиться, что контейнер отработал и записал своё "hello world" в лог.
Большое спасибо всем, кто помог мне разобраться!