Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >jmxterm:在Docker容器中“无法创建系统终端”

jmxterm:在Docker容器中“无法创建系统终端”
EN

Stack Overflow用户
提问于 2021-06-03 15:38:24
回答 2查看 982关注 0票数 0

我有一个Docker映像,其中包含JRE、一些Java应用程序和jmxterm。后者用于运行一些特殊的管理任务。这个映像被使用在带有Docker1.13的CentOS 7服务器上(这个版本非常旧,但它是通过发行版的存储库提供的最新版本)来运行web应用程序本身。

所有操作都很好,但是在将jmxterm从1.0.0更新到最新版本(1.0.2)之后,当我进入正在运行的容器并启动jmxterm时,我会收到以下警告

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
WARNING: Unable to create a system terminal, creating a dumb terminal (enable debug logging for more information)

在此之后,jmxterm不会对箭头键作出反应(在尝试浏览命令历史记录时),也不会提供自动完成功能。

一些快速调查表明,这个问题可能会在CentOS 7的干净环境中重现。比如说,我可以用我需要的所有东西引导系统和容器:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ vagrant init centos/7
$ vagrant up
$ vagrant ssh
[vagrant@localhost ~]$ sudo yum install docker
[vagrant@localhost ~]$ sudo systemctl start docker
[vagrant@localhost ~]$ sudo docker run -it --entrypoint bash openjdk:11
root@0c4c614de0ee:/# wget https://github.com/jiaqi/jmxterm/releases/download/v1.0.2/jmxterm-1.0.2-uber.jar

这就是我进入容器并运行jmxterm的方式

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[vagrant@localhost ~]$ sudo docker exec -it 0c4c614de0ee sh
root@0c4c614de0ee:/# java -jar jmxterm-1.0.2-uber.jar
WARNING: Unable to create a system terminal, creating a dumb terminal (enable debug logging for more information)
root@0c4c614de0ee:/# bea<TAB>
<Nothing happens, but autocompletion had to appear>

很少有意见:

  • 无论使用哪个映像,旧的jmxterm都不会出现问题;无论使用哪种图像,新的jmxterm都会出现问题;
  • ,问题在我的笔记本电脑(内核和Docker较新的)上不可重现;

H 117jmxterm>如果我在CentOS 7服务器上使用最新的Docker(来自外部回购)而不是CentOS 7‘的本机版本1.13,则问题是不可复制的。H 218F 219

会发生什么,以及为什么错误只能在特定的环境中被复制?有什么解决办法吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-06-03 15:38:24

TLDR:以java -jar jmxterm-1.0.2-uber.jar < /dev/tty的形式运行新的jmxterm版本是一个快速、肮脏和麻烦的解决方案,可以在交互式容器会话中完成自动完成和其他工作。

快速检查显示,jmxterm试图通过运行tty实用程序来确定进程使用的终端设备--可能是以后获得终端功能的终端设备:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
root@0c4c614de0ee:/# strace -f -e 'trace=execve,wait4' java -jar jmxterm-1.0.2-uber.jar
execve("/opt/java/openjdk/bin/java", ["java", "-jar", "jmxterm-1.0.2-uber.jar"], 0x7ffed3a53210 /* 36 vars */) = 0
...
[pid   432] execve("/usr/bin/tty", ["tty"], 0x7fff8ea39608 /* 36 vars */) = 0
[pid   433] wait4(432, [{WIFEXITED(s) && WEXITSTATUS(s) == 1}], 0, NULL) = 432
WARNING: Unable to create a system terminal, creating a dumb terminal (enable debug logging for more information)

当状态为1时,该实用程序将失败,这可能是错误消息的原因。为什么?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
root@0c4c614de0ee:/# strace -y tty
...
readlink("/proc/self/fd/0", "/dev/pts/3", 4095) = 10
stat("/dev/pts/3", 0x7ffe966f2160)      = -1 ENOENT (No such file or directory)
...
write(1</dev/pts/3>, "not a tty\n", 10not a tty
) = 10

公用事业公司说“不提”,而我们肯定有一个。快速检查显示..。容器中确实没有PTY设备,尽管shell的标准流连接到一个!

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
root@0c4c614de0ee:/# ls -l /proc/self/fd
total 0
lrwx------. 1 root root 64 Jun  3 21:26 0 -> /dev/pts/3
lrwx------. 1 root root 64 Jun  3 21:26 1 -> /dev/pts/3
lrwx------. 1 root root 64 Jun  3 21:26 2 -> /dev/pts/3
lr-x------. 1 root root 64 Jun  3 21:26 3 -> /proc/61/fd

root@0c4c614de0ee:/# ls -l /dev/pts
total 0
crw-rw-rw-. 1 root root 5, 2 Jun  3 21:26 ptmx

如果我们对最新的码头工人进行同样的检查呢?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
root@c0ebd608f79a:/# ls -l /proc/self/fd
total 0
lrwx------ 1 root root 64 Jun  3 21:45 0 -> /dev/pts/1
lrwx------ 1 root root 64 Jun  3 21:45 1 -> /dev/pts/1
lrwx------ 1 root root 64 Jun  3 21:45 2 -> /dev/pts/1
lr-x------ 1 root root 64 Jun  3 21:45 3 -> /proc/16/fd

root@c0ebd608f79a:/# ls -l /dev/pts
total 0
crw--w---- 1 root tty  136, 0 Jun  3 21:44 0
crw--w---- 1 root tty  136, 1 Jun  3 21:45 1
crw-rw-rw- 1 root root   5, 2 Jun  3 21:45 ptmx

对啰!现在,我们的PTY应该在哪里,所以jmxterm与最新的码头很好的工作。

对于较老的Docker来说,进程连接到一些PTY,而在/dev/pts中没有它们的设备,这似乎很奇怪,但是跟踪Docker进程可以解释为什么会发生这种情况。较老的Docker在设置其他内容之前为容器分配PTY (包括输入新的挂载命名空间并将devpts挂载到容器中,或者只在docker exec -it情况下输入挂载名称空间):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[vagrant@localhost ~]$ sudo strace -p $(pidof docker-containerd-current) -f -e trace='execve,mount,unshare,openat,ioctl'
...
[pid  3885] openat(AT_FDCWD, "/dev/ptmx", O_RDWR|O_NOCTTY|O_CLOEXEC) = 9
[pid  3885] ioctl(9, TIOCGPTN, [1])     = 0
[pid  3885] ioctl(9, TIOCSPTLCK, [0])   = 0
...
[pid  3898] unshare(CLONE_NEWNS|CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET|CLONE_NEWPID) = 0
...
[pid  3899] mount("devpts", "/var/lib/docker/overlay2/3af250a9f118d637bfba5701f5b0dfc09ed154c6f9d0240ae12523bf252e350c/merged/dev/pts", "devpts", MS_NOSUID|MS_NOEXEC, "newinstance,ptmxmode=0666,mode=0"...) = 0
...
[pid  3899] execve("/bin/bash", ["bash"], 0xc4201626c0 /* 7 vars */ <unfinished ...>

注意,newinstance挂载选项确保devpts挂载只拥有它的PTY,而不与其他挂载共享它们。这就产生了有趣的效果:容器的PTY设备停留在主机上,属于主机的devpts挂载,而容器化过程仍然可以访问它,因为它在生命刚开始时就获得了已经打开的文件描述符!

最新的Docker首先为容器挂载devpts,然后分配PTY,因此PTY属于容器的devpts挂载,并且在容器的文件系统中可见:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ sudo strace -p $(pidof containerd) -f -e trace='execve,mount,unshare,openat,ioctl'
...
[pid 14043] unshare(CLONE_NEWNS|CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWNET) = 0
...
[pid 14044] mount("devpts", "/var/lib/docker/overlay2/b743cf16ab954b9a4b4005bca0aeaa019c4836c7d58d6073044e5b48446c3d62/merged/dev/pts", "devpts", 
MS_NOSUID|MS_NOEXEC, "newinstance,ptmxmode=0666,mode=0"...) = 0
...
[pid 14044] openat(AT_FDCWD, "/dev/ptmx", O_RDWR|O_NOCTTY|O_CLOEXEC) = 7
[pid 14044] ioctl(7, TIOCGPTN, [0])     = 0
[pid 14044] ioctl(7, TIOCSPTLCK, [0])   = 0
...
[pid 14044] execve("/bin/bash", ["/bin/bash"], 0xc000203530 /* 4 vars */ <unfinished ...>

这个问题是由不适当的码头工人行为引起的,但是为什么老的jmxterm在相同的环境中工作得很好呢?让我们检查一下(注意,这里使用的是Java8映像,因为旧的jmxterm不能很好地处理Java 11):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
root@504a7757e310:/# wget https://github.com/jiaqi/jmxterm/releases/download/v1.0.0/jmxterm-1.0.0-uber.jar
root@504a7757e310:/# strace -f -e 'trace=execve,wait4' java -jar jmxterm-1.0.0-uber.jar
execve("/usr/local/openjdk-8/bin/java", ["java", "-jar", "jmxterm-1.0.0-uber.jar"], 0x7fffdcaebdd0 /* 10 vars */) = 0
...
[pid   310] execve("/bin/sh", ["sh", "-c", "stty -a < /dev/tty"], 0x7fff1f2a1cc8 /* 10 vars */) = 0

因此,旧的jmxterm只使用/dev/tty,而不是向tty询问设备名称,这是可行的,因为这个设备存在于容器中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
root@504a7757e310:/# ls -l /dev/tty
crw-rw-rw-. 1 root root 5, 0 Jun  3 21:36 /dev/tty

这些版本的jmxterm之间的巨大区别在于,较新的工具版本使用了更高的主要版本的jline,后者是负责与终端交互的库(类似于C世界中的readline )。主要jline版本之间的差异导致了jmxterm行为与当前版本just rely on tty的差异。

这个观察给我们带来了快速而又肮脏的解决方法,它既不需要更新Docker,也不需要修补jline/jmxterm串联:我们可以强制将jmxterm的stdin附加到/dev/tty,从而使jline使用此设备(现在由/proc/self/fd/0引用),而不是/dev/pts条目(在形式上,/dev/pts条目并不总是正确的,但仍然足以供临时使用):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
root@0c4c614de0ee:/# java -jar jmxterm-1.0.2-uber.jar < /dev/tty
Welcome to JMX terminal. Type "help" for available commands.
$>bea<TAB>
bean    beans

现在我们有了自动完成,历史和其他我们需要的酷的东西。

票数 0
EN

Stack Overflow用户

发布于 2022-02-04 00:19:57

如果您试图在一个码头容器或kubernetes中的一个吊舱中运行一个交互式应用程序(需要tty),那么下面的内容应该可以工作。

船坞-合成用途:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
image: image-name:2.0
container_name: container-name
restart: always

stdin_open: true
tty: true

对于kubernetes使用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
spec:
      containers:
      - name: web
        image: web:latest

        tty: true
        stdin: true
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67829844

复制
相关文章
python类中初始化形式:def __init__(self)和def __init__(self, 参数1,参数2,,,参数n)区别
这种形式在init方法中,只有一个self,指的是实例的本身,但是在方法的类部,包含两个属性,name, grade。
Python学习者
2023/06/07
5730
32-位置参数
注意:位置参数中的数字是字符形式的 import sys print(sys.argv) # sys.argv是sys模块里的argv列表 # python3 position_args.py # python3 position_args.py 10 # python3 position_args.py 10 bob
凯茜的老爸
2018/09/11
4420
python之函数的位置参数
  实际开发过程中,经常会遇到很多完全相同或者非常相似的操作,这时,可以将实现类似操作的代码封装为函数,然后在需要的地方调用该函数。这样不仅可以实现代码的复用,还可以使代码更有条理性,增加代码的可靠性。下面我们来介绍一下python的函数位置参数相关内容。
jiankang666
2022/12/05
5510
python之函数的位置参数
解决WebService中System.InvalidOperationException:缺少参数的问题
此问题在.Net 4.0 IIS7 Windows Server 2008下可能会出现。 现象是第一次正常调用,第二次接口报错。 删除CacheDuration即可。
从今若
2019/09/18
2.7K1
django_filters TypeError: __init__() got an unexpected keyword argument 'name'
django-filter 参数名字已经由 name 更改为 field_name
卓越笔记
2023/02/18
5240
(23)Bash位置参数变量
位置参数变量主要是用来向脚本当中传递参数或数据的,变量名不能自定义,变量作用是固定的。
生信real
2020/08/26
8990
[周末往期回顾]Oracle Data Guard 参数介绍
Data Guard作为Oracle提供的一个高可用及灾备解决方案,理解并可以实施它对于DBA来说是非常重要套的技能
bsbforever
2020/08/19
4840
[周末往期回顾]Oracle Data Guard 参数介绍
Django 获取请求参数
  我们在使用python做接口测试的时候,通常使用的是requests库。而大家都知道还有一个request东西,很多人对requests与request两个东西傻傻分不清。下面我简单来介绍一下。
全栈测试开发日记
2023/02/02
2.7K0
Django 获取请求参数
【说站】python位置参数的使用注意
2、调用函数中指定的实际参数的数量必须与形式参数的数量一致(不能传输多传输少),否则Python解释器会抛出TypeError异常,并提示缺乏必要的位置参数。
很酷的站长
2022/11/23
5940
【说站】python位置参数的使用注意
Linux之Shell位置参数变量
文章目录 位置参数变量 1. 介绍 2. 基本语法 3. 位置参数变量 位置参数变量 1. 介绍 当我们执行一个 shell 脚本时,如果希望获取到命令行的参数信息,就可以使用到位置参数变量 比如 : ./myshell.sh 100 200 , 这个就是一个执行 shell 的命令行,可以在 myshell 脚本中获取到参数信息 2. 基本语法 n (功能描述:n 为数字,0 代表命令本身,1-9 代表第一到第九个参数。十以上的参数,十以上的参数需要用大括号包含,如 * (功能描述:这个变量代表命令
兮动人
2021/07/21
5.3K0
Linux之Shell位置参数变量
Django连接MySQL缺少mysqlclient包,Python3.8安装mysqlclient
在https://www.lfd.uci.edu/~gohlke/pythonlibs/#mysqlclient找到适合自己版本的mysqlclient
SingYi
2022/07/14
8840
Django连接MySQL缺少mysqlclient包,Python3.8安装mysqlclient
View的位置参数及其Scroller类的理解
x和y是View左上角的坐标,translationX和translationY是View左上角相对于容器的偏移量。这几个参数都是相对于父容器的坐标。
1025645
2018/08/23
6170
多说单点登录(SSO)介绍(解决缺少client_id参数)
多说是目前用的最广泛的一个社会化插件,同时也支持各主流网站的单点登录。官方有详细的开发文档: http://dev.duoshuo.com/docs/5023323ce9b7bde608000012
飞奔去旅行
2019/06/13
1.5K0
多说单点登录(SSO)介绍(解决缺少client_id参数)
【JMeter】参数Parameters和Body Data
在做接口并发测试的时候,才发现Jmeter中的Parameters和Body Data两种参数格式并不是简单的一个是xx=xx,另外一个是json格式的参数
全栈程序员站长
2022/09/12
1.3K0
【JMeter】参数Parameters和Body Data
PYTHON 中的__init__()方
在类定义时,self和__init__会时常用到。 self 参数,它在所有的方法声明中都存在。它代表实例对象本身,当你用实例调用方法时,由解释器悄悄地传递给方法的,所以,你不需要自己传递self 进来,因为它是自动传入的。
py3study
2020/01/07
5580
dh参数建模_data vault 建模
DH法一般用一次就丢,然后后面再需要用的时候就会忘,所以本文整理了DH建模法,方便需要使用的时候进行参考。这里不讲原理,只讲结论和方法
全栈程序员站长
2022/09/29
5340
dh参数建模_data vault 建模
Oracle Data Guard 重要配置参数
    Oracle Data Guard主要是通过为生产数据库提供一个或多个备用数据库(是产生数据库的一个副本),以保证在主库不可用或异常时数据不丢失并通过备用数据库继续提供服务。对于Oracle DG的配置,我们可以通过Grid Control来完成,也可以通过Data Guard Broker以及SQL*Plus来完成。对于前两者方式可以在图形界面上完成,操作简单。而对于使用SQL*Plus命令行方式,我们需要进行大量的配置,尤其是这其中的一些参数。本文主要描述配置Oracle Data Guard 的重要参数。下面关于Data Guard简称为DG。
Leshami
2018/08/13
1K0
python 函数编程的位置参数、默认参数、关键字参数以及函数的递归
首先对于函数调用: !usr/bin/env python _*_ coding:utf-8 _*_ def AQA(INPUT): if INPUT=='hello world': #在输入正确的情况下,不想让其调用hello_again()函数, #法一: 可利用返回值(return)进行判断 #法二:可将函数放在else下执行 print('你好,世界') return 'right' else:
学到老
2018/03/19
1.2K0
python  函数编程的位置参数、默认参数、关键字参数以及函数的递归
三维世界中相机的位置参数
上篇文章带读者完成了一个3d弹弹球的加强版,读者顺便了解了下灯光和阴影的基本用法,关于相机的位置参数问题,我们在前文只是简单提过,本篇文章,想和读者分享下相机的位置参数问题。
江南一点雨
2019/03/07
1.4K0
mysql性能优化(四) mysql修改data存放位置
mysql性能优化(四) mysql修改data存放位置
Java架构师必看
2021/05/27
2.4K0
mysql性能优化(四) mysql修改data存放位置

相似问题

TypeError:__init__()缺少一个必需的位置参数:'data‘

110

Django - __init__()缺少一个必需的位置参数:'request‘

16

__init__()缺少一个必需的位置参数

60

__init__()缺少一个必需的位置参数:'self‘

41

TypeError:__init__()缺少一个必需的位置参数

11
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文