A common troubleshooting scenario involves applications, such as Tomcat running in a Docker container, failing to be accessible despite the host port appearing to be bound. This often leads to confusion, especially when one port mapping works while another fails for the same service.
Problem Scenario
Consider the following Docker commands:
docker run -it -p 3355:8088 tomcat /bin/bash # Accessible
docker run -it -p 3355:8080 tomcat /bin/bash # Inaccessible
In these examples, the host port 3355 is mapped to different container ports. If the container's service isn't running or listening on the expected port, the host port might still show as bound if the container started but the application failed. Host firewall rules are usually ruled out if other port mappings on the same host are functional. The discrepancy between port 8088 and 8080 suggests an issue within the container's application or its configuration, ptoentially even if an official Docker image is not being used.
Investigating Port Usage
Initial Approaches
When a containerized application is unresponsive on a specific port, the immediate step is to inspect network connections within the container. A common command to list listening ports and associated processes is ss -nutlp. However, this command might not be available in minimal container environments. The alternative, netstat -antlp, relies on the net-tools package, which is also not always present by default.
For users less familiar with Linux internals, these two commands often represent the extent of their options for port introspection.
Leveraging Linux's /proc Filesystem
A deeper understanding of Linux reveals that it treats many system resources as files. The /proc filesystem provides a window into kernel and process information, including network socket details.
First, identify the Process ID (PID) of the application. Commands like ps or top can be used:
# Example: Finding the PID for sshd
ps aux | grep ssh | grep -v grep
# Output might show PID 828 for sshd
Once the PID is known, you can examine the file descriptors associated with that process. These include network sockets:
# Examining file descriptors for process 828
ll /proc/828/fd/
The output will list entries, some of which might point to socket:[inode_number]. To find the actual port information, you can inspect the kernel's network status files. The location and format depend on the protocol (TCP or UDP).
# Example for TCP connections (output fields are truncated for brevity)
cat /proc/828/net/tcp
In the output of /proc/[PID]/net/tcp (or udp), look for a line corresponding to a socket inode number found in the file descriptor list. The local_address field displays the IP address and port in hexadecimal format. For example, 00000000:0016 indicates an IP address of 0.0.0.0 and a port number of 0x0016. Converting 0x16 to decimal yields 22.
Verification with ss
To confirm, you can use ss (if available) to correlate the identified process PID and port:
# Verifying sshd on port 22
ss -nutlp | grep ssh
# Expected output: tcp LISTEN 0 128 *:22 *: * users:(("sshd",pid=828,fd=3))
Root Cause Analysis
Returning to the initial Docker problem, the inability to access Tomcat on port 8080 while port 8088 worked suggests that the Tomcat process either failed to start within the container or was configured to listen on a different port entirely. If the application process never successfully bound to port 8080, it wouldn't appear in the network status, even if the container reported as running. This points towards an issue with the specfiic container image's application configuration rather than a general Docker or host networking problem.