1. Как мисля за Docker Networking
Docker не стартира контейнерите просто като процеси, които случайно са се оказали на една машина. Всеки container има собствен network namespace и собствена мрежова конфигурация. Docker Engine изгражда необходимата свързаност чрез network drivers, virtual interfaces и правила на host системата.
На практика това означава, че мога да имам nginx, application и database на един host, без да отварям database към локалната мрежа. Web контейнерът говори с database контейнера през Docker network, докато само nginx има публикуван port към host-а.
HTTP/HTTPS
Published port
Docker network
Достъпна само през вътрешната Docker network
2. Основните Docker Network Drivers
Docker поддържа няколко network drivers. Не е необходимо да използвам всички, но трябва да разбирам разликата между тях, защото изборът влияе директно върху изолацията и начина, по който контейнерите комуникират.
| Driver | Предназначение | Практическа употреба |
|---|---|---|
| bridge | Изолирана мрежа за containers на един Docker host | Най-често срещаният избор |
| host | Container използва network stack-а на host-а | Специализирани случаи |
| none | Без нормална мрежова свързаност | Силно изолирани containers |
| overlay | Мрежа между Docker hosts | Docker Swarm и разпределени среди |
| macvlan | Container получава собствен MAC адрес | Специализирани L2 сценарии |
3. Bridge Network — работният кон
За обикновена инфраструктура с няколко containers на един host bridge network е основният инструмент. Docker създава виртуална мрежа и включва контейнерите в нея чрез виртуални Ethernet интерфейси.
Има важна разлика между автоматично създадената default bridge network и собствена user-defined bridge network. За реални приложения предпочитам втория вариант.
docker network create app_net
docker network ls
docker network inspect app_net4. Комуникация между Containers
Нека създам два containers в една network. Няма нужда да знам IP адреса на първия container, за да го достигна от втория.
docker network create backend
docker run -d \
--name database \
--network backend \
postgres:16-alpine
docker run -it --rm \
--network backend \
alpine shОт временния Alpine container мога да проверя резолюцията на името database. Docker DNS ще разреши това име към адреса на съответния container в network-а.
getent hosts database
ping database5. Published Ports ≠ Container-to-Container Networking
Това е едно от най-важните разграничения в Docker.
docker run -d \
--name web \
-p 8080:80 \
nginx:alpine8080:80 означава: port 8080 на host-а се публикува към port 80 в container-а. Това е необходимо, ако клиент извън Docker network-а трябва да достигне nginx.
Ако два containers са в една Docker network, вторият не трябва да използва host port-а, за да достигне първия.
http://web:806. Network Inspect — когато нещо не работи
Когато контейнерите „трябва“ да се виждат, но не се виждат, не започвам да гадая. Първата ми работа е да проверя network configuration.
docker network ls
docker network inspect backend
docker inspect database
docker exec -it database shВ изхода на docker network inspect особено ме интересува секцията Containers. Там мога веднага да видя кои containers са включени в network-а и какви адреси са получили.
6.1. Типичен диагностичен ред
- Проверявам дали и двата containers са running;
- проверявам дали са в една и съща user-defined network;
- проверявам DNS резолюцията по име;
- проверявам дали приложението слуша на правилния port;
- проверявам firewall и други мрежови политики;
- чак тогава търся проблем в самото приложение.
7. Един Container в Няколко Networks
Docker позволява един container да бъде включен едновременно в няколко мрежи. Това е полезно за разделяне на frontend и backend комуникацията.
Reverse proxy ↔ application
Участва и в двете networks
application ↔ database
Така database container-ът може да бъде извън frontend network-а. Той приема връзки само от containers, които имат достъп до db_net.
docker network create proxy_net
docker network create db_net
docker run -d --name database --network db_net postgres:16-alpine
docker run -d --name app --network db_net myapp:latest
docker network connect proxy_net app8. Docker Compose Networking
При Docker Compose ситуацията става още по-интересна, защото Compose автоматично създава network за проекта. Services, които са част от един Compose project, могат да комуникират помежду си по service name.
services:
web:
image: nginx:alpine
depends_on:
- app
app:
image: myapp:latest
depends_on:
- db
db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: secretApplication container-ът не трябва да използва localhost, за да се свърже с PostgreSQL. localhost означава текущия container.
DB_HOST=db
DB_PORT=5432При Compose service name е hostname в рамките на Compose network-а.
9. Когато Compose Network-ът трябва да е изричен
При по-голяма инфраструктура често искам да определя topology-то изрично.
services:
proxy:
image: nginx:alpine
networks:
- frontend
app:
image: myapp:latest
networks:
- frontend
- backend
db:
image: postgres:16-alpine
networks:
- backend
networks:
frontend:
driver: bridge
backend:
driver: bridgeТук proxy няма директна връзка с database. Application container-ът е единственият, който участва и в двете мрежи.
10. Най-опасната дума: localhost
Един от най-честите проблеми при Docker Networking е configuration, която изглежда напълно логична:
DB_HOST=localhostАко application и database са в различни containers, това няма да работи. localhost сочи към network namespace-а на application container-а, а не към Docker host-а и не към database container-а.
DB_HOST=db11. Networking и Security
Docker Networking не е само въпрос на това „да тръгне“. Мрежовата архитектура е част от security модела на приложението.
- Не публикувам database ports без реална необходимост;
- разделям frontend и backend traffic, когато архитектурата го изисква;
- не приемам, че container network автоматично решава всички security проблеми;
- проверявам реалната network topology, вместо да разчитам на предположения.
-p 5432:5432, трябва да имам конкретна причина. Ако application и PostgreSQL са в една Docker network, обикновено такъв publish не е необходим.12. Когато Networking не работи
При проблем с комуникацията между containers не променям на случаен принцип IP адреси, ports и configuration файлове. Работя последователно.
docker ps
docker network ls
docker network inspect app_net
docker inspect app
docker exec -it app sh
# Вътре в container-а:
getent hosts dbАко getent hosts db не върне адрес, проблемът е много вероятно в network membership или DNS. Ако името се резолвира, но връзката към port-а не работи, проверявам дали приложението слуша на правилния interface и port.
13. Практически правила, които следвам
- Използвам user-defined bridge networks за приложения на един host.
- Използвам service names, а не IP адреси между Compose services.
- Не използвам localhost за комуникация с друг container.
- Публикувам само необходимите ports.
- Разделям frontend и backend networks, когато архитектурата го оправдава.
- Проверявам network topology с docker network inspect, преди да започна да гадая.
- Не бъркам published port с вътрешна container комуникация.
Заключение
Docker Networking изглежда просто, докато не започнеш да изграждаш реална инфраструктура. Тогава разликата между host port, container port, service name, network namespace и Docker network става критична.
За мен правилният подход е да мисля първо за комуникационните зависимости, а след това за командите. Кой трябва да вижда кого? Кой port трябва да бъде достъпен отвън? Кои containers трябва да останат изолирани?
Когато тези въпроси са ясни, Docker Networking престава да бъде магия. Получава се нормална мрежова архитектура — само че реализирана върху containers.