#android #docker #shell
#Android #docker #оболочка
Вопрос:
Я запускаю эту команду в docker для установки некоторых компонентов android-sdk:
RUN mkdir ${ANDROID_HOME} amp;amp; wget --output-document=android-sdk.zip https://dl.google.com/android/repository/commandlinetools-linux-6609375_latest.zip
amp;amp; unzip android-sdk.zip -d ${ANDROID_HOME}
amp;amp; echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} --list
amp;amp; echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "build-tools;25.0.1"
amp;amp; echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "build-tools;28.0.3"
amp;amp; echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "build-tools;29.0.2"
amp;amp; echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "platform-tools"
amp;amp; echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "platforms;android-25"
amp;amp; echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "platforms;android-28"
amp;amp; echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "platforms;android-30"
amp;amp; echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "extras;android;m2repository"
amp;amp; echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "extras;google;google_play_services"
amp;amp; ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "ndk;${ANDROID_NDK_VERSION}"
amp;amp; ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "cmake;3.10.2.4988404"
amp;amp; yes | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} --update
поскольку это изображение docker, я должен запускать все в одной команде, иначе изображения будут иметь слишком много дополнительных слоев и занимать слишком много места.
Проблема в том, что из-за ненадежного интернета mu очень вероятно, что я получаю несоответствие тегов для одного из устанавливаемых компонентов, что заставляет меня снова запускать процесс. Мне приходится создавать свой образ docker более 30 раз, чтобы заставить его успешно выполнять все команды.
Есть ли способ повторить попытку при несоответствии тегов в android-sdk?
Я также подумал о попытке запустить каждую строку по отдельности, но все же внутри одной большой команды.
Может быть
while true; do
subcommand1
if [ $? -eq 0 ]; then
break
fi
sleep 1
done
while true; do
subcommand2
if [ $? -eq 0 ]; then
break
fi
sleep 1
done
Это было бы легко сделать с файлом .sh, создав функцию, которая выполняет while
цикл, но что, если я хочу сделать все в Dockerfile?
У кого-нибудь есть идея получше?
Ответ №1:
Отказ от ответственности: я понятия не имею, что делает ваша команда (помимо загрузки android-sdk), поэтому вам может потребоваться немного изменить мой код, чтобы заставить его работать.Кроме того, ваше изображение может не включать timeout
Во-первых, я бы начал с перемещения вашего скрипта в отдельный файл в том же каталоге, что и ваш Dockerfile
, а затем выполнил его следующим образом:
COPY ./build.sh .
RUN chmod x ./build.sh amp;amp; ./build.sh
Теперь в скрипте вы можете проверить вывод каждой строки, прежде чем продолжить:
#!/bin/bash
url="https://dl.google.com/android/repository/commandlinetools-linux-6609375_latest.zip"
mkdir ${ANDROID_HOME}
until (
wget --output-document=android-sdk.zip "$url" amp;amp;
unzip android-sdk.zip -d ${ANDROID_HOME}
); do
sleep 1
done
args=(
"--list"
"build-tools;25.0.1"
"build-tools;28.0.3"
"build-tools;29.0.2"
"platform-tools"
"platforms;android-25"
"platforms;android-28"
"platforms;android-30"
"extras;android;m2repository"
"extras;google;google_play_services"
)
# you may need to modify this slightly!
for arg in "${args[@]}";
do
until ( echo y | ${SDKMANAGER} --sdk_root=${ANDROID_HOME} "$arg" ); do
sleep 5
done
done
Было бы неплохо установить тайм-аут, чтобы ваша сборка не застряла в бесконечном цикле. Вместо добавления 2 отдельных проверок в скрипт, я бы просто добавил его в Dockerfile
:
# might need adjusting
ARG MAX_TIMEOUT=60
COPY ./build.sh .
RUN chmod x ./build.sh amp;amp; timeout -k $MAX_TIMEOUT ./build.sh
Я бы рекомендовал использовать это как Base Image
для вашего основного проекта, а не включать его в один и тот же Dockerfile
. Таким образом, если вам нужно переделать свой проект Dockerfile
и перестроить его, вам не придется каждый раз перестраивать android-sdk.