Докерное число строк в терминале, изменяющееся внутри докера
Я хотел бы знать, как изменить следующее поведение. Скажем, мой терминал имеет 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
[email protected]:/# 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 presentation, который учитывает строки в вашем терминале. Когда моя реализация завершилась неудачно, я попробовал другую команду docker implementation, но я столкнулся с той же ошибкой.
Здесь моя ошибка в изображении:
![Докерное число строк в терминале, меняющемся внутри докера]()
Кто-нибудь знает, что это может быть и как это можно решить?
Ответы
Ответ 1
Обновление, сентябрь 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" ]
С:
[email protected]:/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
ОП силгон предлагает в комментариях:
docker run --rm -it --entrypoint /bin/bash ubuntu:16.04 -c "sleep 0.1 && tput lines"
Как комментирует BMitch ниже:
Учитывая успех сна, я подозреваю, что докер раскручивает контейнер с запущенной командой, и когда клиент работает, он подключается к работающему контейнеру. Обычно это то, что занимает миллисекунды.
Это дало мне другую идею:
[email protected]:/c/Users/vonc/prog/testsu$
docker run --entrypoint='/bin/bash' --name ub -d -it ubuntu:16.04
0d9b8783afbb5e3ff4232da071d3f357985351ea1ce4d142bf6617ac456fb76b
[email protected]:/c/Users/vonc/prog/testsu$
d attach ub
[email protected]:/# tput lines
48
[email protected]:/# exit
exit
[email protected]:/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):
Это снова всплыло в спецификации времени выполнения (opencontainers/runtime-spec PR 563).
По сути, поскольку Windows требуется возможность установки размера консоли при первом запуске, мы можем добавить ее для всех платформ.
Силикон OP указывает на код в 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 и установить начальный размер консоли, используя это значение?
На нем есть Kenfe-Mickaël Laventure (mlaventure
), и новый патч может сделать это для Docker 1.13.
Ответ 2
ОБНОВИТЬ
теперь вы можете установить goinside
командной строки 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
теперь вы можете попасть внутрь контейнера докеров без проблем с размером терминала:
$ goinside containername
запомните source ~/.profile
goinside
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;
Ответ 3
Комментарии о sh
в сравнении с terminfo в значительной степени неактуальны. Соответствующая часть (непонятная в данном ответе) - это способ выполнения команды. tput
проверяет три функции в следующем порядке (используя setupterm
):
- размер терминала из базы данных terminfo (многие описания не дают этой информации, но с
TERM=xterm
она 24 80),
- фактическое количество строк, если оно может получить эту информацию из операционной системы (то есть текущий размер окна) и
- переменные окружения
LINES
и COLUMNS
.
Команда, которая запускается без интерактивной оболочки, может быть выполнена таким образом, чтобы исключить получение текущего размера окна. Например, это функция ssh
(опция -t
). Кроме того, было бы (хотя и бессмысленно) для Docker устанавливать переменные LINES
и COLUMNS
.
Для объяснения поведения достаточно одного (1) или (3); введение временных задержек и рас не делает этого.
Ответ 4
Это было исправлено в докере 18.06: https://github.com/moby/moby/issues/33794#issuecomment-406814439
Ответ 5
Я только что протестировал с версией 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
Ответ 6
Хороший способ запустить bash внутри контейнера без проблем со строкой (а не запускать exec дважды):
docker exec -e COLUMNS="'tput cols'" -e LINES="'tput lines'" -ti container bash