How to Expose Docker Containers to External Users
We know that an application runs inside a Docker container or Kubernetes Pod. But how can a user outside the container or cluster access that application?
For example: User │ │ http://20.10.10.5:8080 ▼ ??? │ ▼ Application running inside container
docker run -p 8080:80 nginx
-p HOST_PORT:CONTAINER_PORT
8080 : 80
│ │
│ └── Container port
│
└──────── Host port
Traffic:
External User │ │ http://HOST\_IP:8080 ▼ Docker Host :8080 │ │ Docker port mapping ▼ Container :80 │ ▼ Nginx
Container Port vs Host Port:
docker run -p 8080:80 nginx
Port Meaning 8080 Host port 80 Container port
What happens without -p?
This is an important comparison.
docker run nginx
versus:
docker run -p 8080:80 nginx Without publishing User X │ Docker Host │ Container :80 With publishing User │ ▼ Host :8080 │ ▼ Container :80 │ ▼ Nginx
Explain:
The -p option publishes a container port on the Docker host, allowing traffic to reach the container through the host's network interface.
- Docker Port Publishing with Different Ports
Use:
docker run -p 9090:80 nginx
Then:
User │ │ :9090 ▼ Docker Host │ │ mapping ▼ Container :80 │ ▼ Nginx
The user connects to:
while Nginx remains on:
:80
This is a great example because it reinforces the concept from your previous article.
- Now introduce Kubernetes
This is where the article becomes very useful for DevOps.
Start with:
Docker Container ↓ -p 8080:80 ↓ External User
But Kubernetes is different.
A Pod has an IP address, but you generally should not expose applications directly through Pod IPs.
Why?
Because Pods are:
Temporary Recreated Scaled Replaced Assigned changing IP addresses
Therefore Kubernetes provides Services.
- Kubernetes Pod
Example:
apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80
Visual:
Kubernetes Cluster
┌─────────────────────────┐ │ Node │ │ │ │ ┌─────────────────┐ │ │ │ Pod │ │ │ │ │ │ │ │ Nginx :80 │ │ │ └─────────────────┘ │ │ │ └─────────────────────────┘
Then explain:
containerPort: 80 documents the port the container is expected to listen on. By itself, it does not make the Pod externally accessible.
This is a very important point.
- Kubernetes Service
Now introduce:
Pod ↓ Service ↓ External access
A Service provides a stable endpoint for Pods.
Example:
apiVersion: v1 kind: Service metadata: name: nginx-service spec: selector: app: nginx ports: - port: 80 targetPort: 80
Visual:
Kubernetes Cluster
┌─────────────────────────────┐
│ │
│ Service :80 │
│ │ │
│ ┌─────┴─────┐ │
│ ↓ ↓ │
│ Pod :80 Pod :80 │
│ │
└─────────────────────────────┘
Explain:
Service port → 80 Target port → 80
The Service forwards traffic to matching Pods.
- How does an external user access Kubernetes?
This is where you introduce Service types.
The main ones you should cover are:
ClusterIP NodePort LoadBalancer
And later:
Ingress 10. ClusterIP
Default Service type:
type: ClusterIP
Traffic:
Pod ↑ │ Service :80 ↑ │ Internal clients
ClusterIP is generally internal to the cluster.
So:
External Internet X │ ▼ ClusterIP Service │ ▼ Pod
Use it for communication between applications inside Kubernetes.
Example:
frontend │ ▼ backend-service │ ▼ backend Pod 11. NodePort
Now expose it externally.
type: NodePort
Example:
Service Port: 80 NodePort: 30080
Traffic:
External User │ │ :30080 ▼ Kubernetes Node │ │ ▼ Service :80 │ ▼ Pod :80
User accesses:
This is very important to understand.
- LoadBalancer
For cloud Kubernetes such as AKS, this is one of the most important concepts.
Example:
type: LoadBalancer
Traffic:
Internet
│
▼
Public IP Address
│
▼
Cloud Load Balancer
│
▼
Kubernetes Service
│
▼
Pod :80
For Azure AKS, the external user can ultimately access something like:
The exact public IP is assigned by the cloud infrastructure.
- Compare Docker vs Kubernetes
This should be one of the strongest sections of the article.
Docker Kubernetes Container Pod Container port Container port -p Service Host port NodePort / LoadBalancer Docker host IP Node/external endpoint Docker port publishing Kubernetes Service exposure
Conceptually:
DOCKER
User ↓ Host :8080 ↓ Container :80 ↓ Application
versus:
KUBERNETES
User ↓ LoadBalancer :80 ↓ Service :80 ↓ Pod :80 ↓ Application 14. The most important Kubernetes port concepts
I strongly recommend having a dedicated section for this because these names confuse almost everyone initially.
containerPort ↓ targetPort ↓ port ↓ nodePort
But don't imply these always form one direct sequential chain.
Explain each separately:
containerPort
Port on which the application inside the container listens.
Pod └── Container :8080 targetPort
Port on the Pod/container that the Service forwards traffic to.
Service │ │ targetPort: 8080 ▼ Pod :8080 port
Port exposed by the Kubernetes Service.
Service :80 │ ▼ Pod :8080
Example:
ports:
- port: 80 targetPort: 8080
Traffic:
Client ↓ Service :80 ↓ Pod :8080 ↓ Application nodePort
Port exposed on Kubernetes nodes.
Node :30080 ↓ Service :80 ↓ Pod :8080 15. Complete Kubernetes example
This would be an excellent practical exercise.
Deployment apiVersion: apps/v1 kind: Deployment metadata: name: nginx spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 Service apiVersion: v1 kind: Service metadata: name: nginx-service spec: type: LoadBalancer selector: app: nginx ports: - port: 80 targetPort: 80
Then:
External User
│
│ HTTP :80
▼
┌──────────────────┐
│ Public IP │
│ Load Balancer │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Service :80 │
└────────┬─────────┘
│
┌──────┴──────┐
▼ ▼
Pod :80 Pod :80
Nginx Nginx
This also demonstrates why a Service is useful when you have multiple replicas.
- Troubleshooting section
Definitely add this.
Docker
If:
docker run nginx
doesn't work externally, check:
Is container running? ↓ Is application listening? ↓ Was the port published? ↓ Is Docker mapping correct? ↓ Is host firewall allowing the port? ↓ Is cloud NSG/security rule allowing it?
Commands:
docker ps docker port Kubernetes
If your Pod is running but you can't access it:
Pod running? ↓ Application listening? ↓ Service exists? ↓ Service selector matches Pod labels? ↓ Correct targetPort? ↓ Correct Service type? ↓ NodePort / LoadBalancer configured? ↓ Cloud firewall / NSG?
Useful commands:
kubectl get pods kubectl get svc kubectl describe svc nginx-service kubectl get endpoints
And:
kubectl logs 17. Final mental model
End the article with one diagram readers can remember:
EXTERNAL USER
│
▼
┌─────────────────┐
│ External Access │
│ │
│ Docker → Host │
│ K8s → LB/Ingress│
└────────┬────────┘
│
▼
SERVICE/PORT
│
▼
CONTAINER/POD
│
▼
APPLICATION
Then summarize:
Docker uses port publishing (-p) to expose a container through the Docker host. Kubernetes uses Services to provide stable access to Pods, with NodePort and LoadBalancer commonly used for external access.
Recommended article title
I would use:
How to Expose Docker Containers and Kubernetes Pods to External Users
And your article series becomes:
What is a Port? ↓
How to Expose Docker Containers and Kubernetes Pods ↓
Docker Networking Explained ↓
Docker Bridge vs Host vs None Networks ↓
Kubernetes Networking Explained ↓
Kubernetes Services: ClusterIP, NodePort & LoadBalancer ↓
Kubernetes Ingress Explained ↓
Azure AKS Networking
This is a very good progression for your DevOps blog, because each article builds on the previous one instead of teaching isolated concepts.