Docker номер строки в терминале меняется внутри докера
Я хотел бы знать, как изменить следующее поведение. Допустим, у моего терминала 28 линий. Затем я использую следующие команды:
$ tput lines # my terminal
28
$ docker run --rm -it ubuntu:16.04 tput lines # docker container
24 ## WHY??
$ docker run --rm -it ubuntu:16.04 bash # docker container inside command
root@810effa2777c:/# tput lines
28
Как видите, даже когда все результаты должны быть 28, когда я вызываю контейнер как docker run --rm -it ubuntu:16.04 tput lines
это всегда дает мне 24 несмотря на размер моего терминала. Это не только с контейнером Ubuntu, я также пытался с Debian (docker run --rm -it debian tput lines
) и у меня тот же результат 24.
Цель этого состоит в том, чтобы использовать инструмент представления mdp, который учитывает линии в вашем терминале. Когда моя реализация не удалась, я попробовал реализацию докера другого человека, но столкнулся с той же ошибкой.
Вот моя ошибка в изображении:
Кто-нибудь знает, что это может быть и как это можно решить?
5 ответов
Обновление, сентябрь 2018 года: проверьте, имеет ли Docker 18.06 ту же проблему ( не должно быть после moby/moby
выпуск 33794, а также moby/moby
выпуск 35407 и PR 37172, часть примечаний к выпуску от 18.06).
2016:
Ubuntu Dockerfile включает в себя:
CMD ["/bin/bash"]
Это означает, что по умолчанию ENTRYPOINT
является sh -c
(и я сомневаюсь tput line
хорошо работает в sh
сеанс, так как tput использует terminfo
база данных, которая может быть установлена только для bash в этом образе)
Вы можете попробовать перезаписать ENTRYPOINT
с bash -c
и проверьте, работает ли это лучше.
Это не работает из командной строки, хотя:
docker run --entrypoint /bin/bash --rm -it ubuntu:16.04 -i -c 'tput lines'
24
Я проверю опцию определения пользовательского изображения.
FROM ubuntu:16.04
ENTRYPOINT ["/bin/bash", "-c"]
Результат тот же, хотя:
docker run --rm -it u 'tput lines'
24
Это однако "работает":
FROM ubuntu:16.04
ENTRYPOINT [ "/bin/bash" ]
С:
docker@default:/c/Users/vonc/prog/testsu$ docker run --rm -it u -i -c 'ls; tput lines'
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
48
Может быть проблема с синхронизацией, поскольку одна и та же команда время от времени возвращает 24.
На самом деле, следующие всегда возвращают "не 24" с:
FROM ubuntu:16.04
ENTRYPOINT [ "/bin/bash", "-l", "-i", "-c" ]
docker run --rm -it u -c 'sleep 0.1; ls; tput lines'
48
silgon предлагает в комментариях:
docker run --rm -it --entrypoint /bin/bash ubuntu:16.04 -c "sleep 0.1 && tput lines"
Учитывая успех сна, я подозреваю, что докер раскручивает контейнер с запущенной командой, и когда клиент работает, он подключается к работающему контейнеру. Обычно это то, что занимает миллисекунды.
Это дало мне другую идею:
docker@default:/c/Users/vonc/prog/testsu$
docker run --entrypoint='/bin/bash' --name ub -d -it ubuntu:16.04
0d9b8783afbb5e3ff4232da071d3f357985351ea1ce4d142bf6617ac456fb76b
docker@default:/c/Users/vonc/prog/testsu$
d attach ub
root@0d9b8783afbb:/# tput lines
48
root@0d9b8783afbb:/# exit
exit
docker@default:/c/Users/vonc/prog/testsu$ drmae
0d9b8783afbb5e3ff4232da071d3f357985351ea1ce4d142bf6617ac456fb76b
tput lines
в прикрепленном сеансе работает просто отлично.
(На drmae
см. " Как удалить старые и неиспользуемые образы Docker ")
thaJeztah добавляет в комментариях:
контейнер создан, затем запущен со значениями по умолчанию (
80x24
) и после этого (когда-it
), сессия прилагается.
Сеанс определяет размер терминала;
См. API " Изменение размера TTY контейнера ".
DEBU[0244] Calling POST /v1.25/containers/c42fd5c4eb79c06fd7f9912b8359022f7d93887afbb33b57a67ed8bb7bfee43a/resize?h=46&w=221
Для получения дополнительной информации см. Выпуск докера 25450.
Это связано с проблемой 10341 "Создание или запуск контейнера должны принимать параметры высоты / ширины". Алекса Сарай (cyphar) добавляет (сентябрь 2016):
Это снова всплыло в спецификации времени выполнения ( https://github.com/opencontainers/runtime-spec/pull/563).
По сути, поскольку Windows требуется возможность установки размера консоли при первом запуске, мы можем добавить ее для всех платформ.
silgon указывает на код в api/client/container/run.go
:
// Telling the Windows daemon the initial size of the tty during start makes
// a far better user experience rather than relying on subsequent resizes
// to cause things to catch up.
if runtime.GOOS == "windows" {
hostConfig.ConsoleSize[0], hostConfig.ConsoleSize[1] = dockerCli.GetTtySize()
}
С логическим вопросом:
имеет ли смысл также использовать это свойство в Linux и установить начальный размер консоли, используя это значение?
Кенфе-Микаэль Лавентур ( mlaventure
), и новый патч может сделать это в Docker 1.13.
ОБНОВИТЬ
Теперь вы можете установить goinside
инструмент командной строки с:
sudo npm install -g goinside
и войдите в докер-контейнер с правильным размером терминала:
goinside docker_container_name
Логика позади Goinside
благодаря ответу @VonC у нас есть решение этой проблемы с простым фрагментом bash, который мы вставляем ~/.profile
:
goinside(){
docker exec -it $1 bash -c "stty cols $COLUMNS rows $LINES && bash";
}
export -f goinside
Теперь вы можете получить доступ к Docker-контейнеру без проблем с размером терминала:
$ goinside containername
не забудьте source ~/.profile
перед использованием goinside
функция.
включение автозаполнения в bash
(как это указано в одном из комментариев ниже), если вы хотите включить автозаполнение для goinside
Вы можете использовать этот фрагмент в .profile
:
goinside(){
docker exec -it $1 bash -c "stty cols $COLUMNS rows $LINES && bash";
}
_goinside(){
COMPREPLY=( $(docker ps --format "{{.Names}}" -f name=$2) );
}
complete -F _goinside goinside;
export -f goinside;
Включение автозаполнения в Zsh
если вы используете zsh
в качестве терминала по умолчанию вы можете использовать этот фрагмент внутри вашего ~/.zshrc
файл:
autoload bashcompinit
bashcompinit
goinside(){
docker exec -it $1 bash -c "stty cols $COLUMNS rows $LINES && bash";
}
_goinside(){
COMPREPLY=( $(docker ps --format "{{.Names}}" -f name=$2) );
}
complete -F _goinside goinside;
export goinside;
Хороший способ запустить bash внутри контейнера без проблем со строкой здесь:
docker exec -e COLUMNS="`tput cols`" -e LINES="`tput lines`" -ti container bash
Это было исправлено в докере 18.06: https://github.com/moby/moby/issues/33794
Я только что проверил с версией Docker version 18.06.1-ce, build e68fc7a
, Кажется, есть та же проблема. Тем не менее, один из парней в выпуске github дал практический обходной путь:
docker run --rm -it -e COLUMNS=$COLUMNS -e LINES=$LINES -e TERM=$TERM -it ubuntu:16.04 tput lines
Комментарии о sh
по сравнению с terminfo в значительной степени не имеют значения. Соответствующая часть (непонятная в данном ответе) - это способ выполнения команды. tput
проверяет три функции в следующем порядке (используя setupterm
):
- размер терминала из базы данных terminfo (многие описания не дают эту информацию, но с
TERM=xterm
это 24 на 80), - фактическое количество строк, если оно может получить эту информацию из операционной системы (т. е. текущий размер окна), и
-
LINES
а такжеCOLUMNS
переменные среды
Команда, которая запускается без интерактивной оболочки, может быть выполнена способом, который исключает получение текущего размера окна. Например, это особенность ssh
(-t
опция). Кроме того, было бы возможно (хотя и бессмысленно) для Docker установить LINES
а также COLUMNS
переменные.
Любой случай (1) или (3) достаточно, чтобы объяснить поведение; введение задержек и гонок не делает этого.