前些时间有个前同事问我,为什么我的容器启动的Tomcat无法访问?他绝对是运维新秀,善于思考。不过以现在的互联网企业缩减速度,不知道现在学运维还有用吗?这个问题我也想过。既然选择了走这条路,这个方向。有一技再身,总比没有强吧,没背景,不学一些技术还能做什么?而且换个思路,文明离不开科技,未来科技总是会被需要的。接下去我们回过头来说一下关于容器启动的Tomcat无法访问的一些排查思路和技巧。
问题描述
docker run -it -p 3355:8088 tomcat /bin/bash #可以访问
docker run -it -p 3355:8080 tomcat /bin/bash #无法访问
# 制作镜像时候如果没有做HEALTHCHECK,那就算启动失败,容器也不会自动停止。所以不管能否访问,宿主机3355端口都会存在。
从上面的问题点可以看出来,映射到宿主机的端口都为3355,宿主机防火墙的可能性排除。其次为什么8088可以8080不行,很明显是镜像问题。但是docker官方镜像肯定是标准的8080。不过算了,不管是不是官方镜像进容器看看吧。
<img src="https://storage.bbcking5.com/文章内部图/自动/image-20240714224554206.png" alt="image-20240714224554206" style="zoom:50%;" />
查看端口号
最常见的办法
既然8080不行,那我们启动容器后,执行 docker exec -it tomcat /bin/bash
进入容器一看究竟。先是使用ss -nutlp
命令查看一下当前端口,直接报错没这个命令。好吧那就换成netstat -antlp
看下吧,毕竟ss命令是iproute包中的,netstat是net-tool包中的,net-tool在所有Linux发行版中大多都会默认自带,甚至BSD一般默认也会带有这个包。但不幸的是,还是报错没这个命令。新人对Linux不熟,通常这两条命令就是全部,别无他法。
对Linux深入理解后
我么知道Linux是一个一切皆文件的操作系统。文件中难道没有端口信息吗?答案肯定是有的嘛!我暂且就用一台有ss命令的Linux去做讲解的演示。演示以及理解后,相信自己也能够在没有命令协助下找到想要的端口。
# ps 或者 top 等命令都能查看进程号PID 为828
[root@test ~]# ps aux |grep ssh |grep -v grep
root 828 0.0 0.4 112984 4356 ? Ss Jun20 0:00 /usr/sbin/sshd -D
root 66427 0.0 0.5 158988 5640 ? Ss 07:16 0:00 sshd: root@pts/0,pts/1
# 查看828进程下句柄文件,有3个socket号。做网络编程的同学可能会比较熟悉socket是什么。
[root@test ~]# ll /proc/828/fd/
total 0
lr-x------. 1 root root 64 Jun 20 00:54 0 -> /dev/null
lrwx------. 1 root root 64 Jun 20 00:54 1 -> socket:[18824]
lrwx------. 1 root root 64 Jun 20 00:54 2 -> socket:[18824]
lrwx------. 1 root root 64 Jun 20 00:54 3 -> socket:[18840]
lrwx------. 1 root root 64 Jun 20 00:54 4 -> socket:[18849]
# 查看tcp或者udp的状态文件(得看进程具体监听是哪个协议)
[root@test ~]# cat /proc/828/net/tcp # 输出字段已缩减
sl local_address rem_address uid timeout inode
0: 00000000:14EB 00000000:0000 193 0 18956 1 ffff8d362f8c87c0 100 0 0 10 0
1: 00000000:0016 00000000:0000 0 0 18840 1 ffff8d362f8c8000 100 0 0 10 0
2: 0100007F:0019 00000000:0000 0 0 19478 1 ffff8d362f8c8f80 100 0 0 10 0
3: 3705A8C0:0016 02FAA8C0:FDB9 0 0 243038 4 ffff8d362d041740 20 4 27 10 -1
得到上述输出后,找到对应的socket号对应的是如下inode号。里面只有18840是对应的。注意力锁定到那一行,找到其中的 local_address 为 00000000:0016
。这其实就是以16进制表示的 ip:port
。把0016转成十进制 就等于 22。
最终验证
使用ss命令把端口和进程号一起打印出来,发现的确ssh的pid为828,且端口号是tcp的22端口,监听的ip也是0.0.0.0所有ip,完全正确。
[root@test ~]# ss -nutlp |grep ssh
tcp LISTEN 0 128 *:22 *:* users:(("sshd",pid=828,fd=3))
tcp LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=828,fd=4))
好像漏了啥
啊,前面说的容器的事情最后原因就是镜像问题镜像用的就是8088端口,绝对不是docker官方镜像,用8080端口后连进程都没起来。所以没有端口号,哈哈哈!
本文由mdnice多平台发布
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。