Делаются локальные копии основных репозиториев (reposync, debmirror и другие подобные инструменты), это может касаться и самих дистрибов с пакетами, и всяких менеджеров пакетов для языков типа pip, maven, npm. Либо, как вариант, доступ к ним прописывается через прокси с хорошо контролируемым списком хостов, куда разрешено ходить. Отдельные приложения (вне репозиториев или собственные разработки или свои кастомные сборки) можно класть в свои репозитории либо иногда норм даже просто положить архивом на http, который скрипт раскатки (ansible?) скачает и положит куда надо. Например, именно так у нас по хостам расползается jdk всех нужных версий (в тех проектах, где до контейнеризации нужно ещё космическое количество рефакторинга провести).
В современном мире крупные компании с большим серверным парком нередко систему вообще не обновляют, а полностью перезаливают новый сервер и на него мигрируют. Кроме того, сейчас тренд всё запускать в контейнерах, в которых количество софта невелико, а в случае необходимости собирается новый образ и раскатывается в прод как и любое рядовое обновление.
Это вообще часть подхода, при котором инфраструктура имеет свой жизненный цикл, свои практики и инструменты, которые отделены от жизненного цикла конечных бизнес-приложений с их совсем другими методами раскатки, обновления, контроля работоспособности.