Networking
- Container networking is the ability for containers to connect to and communicate with each other, or to non-docker workloads.
- Networking is enabled by default on containers.
- A container only sees networking details (IP, gateway, route table, DNS) when it connects, it doesn't really know what it is connected to.
User-defined Network
- Connect multiple containers to it.
- Containers communicate with each other over network.
- Create a network using the bridge network driver:
docker network create -d bridge my-net
. - You can then run the container with
docker run --network=my-net -itd -name=container3 busybox
.
Drivers
- IPvlan: provides full control over both IPv4 & IPv6 addressing.
- Bridge: default driver.
- Overlay: Can connect multiple docker daemons (A daemon is a program that runs in the background performing tasks without user interaction) together.
- Macvlan: Assign a MAC address to a container.
- Host: Remove network isolation between the container & docker host.
- None: Completely isolate a container from the host & other containers.
Container Networks
- We can attach a container to another container's network stack.
- We do it by using
--network container:<name|id>
. - The following flags are not supported for containers using the container networking mode: --add-host, --hostname, --dns-search, --dns-option, --mac-address, --publish, --publish-all , --expose.
- e.g. running a redis container, with redis binding to localhost, then running redis-cli command and connecting to the redis container over the localhost interface.
docker run -d --name redis example/redis --bind 127.0.0.1
docker run --rm -it --network container:redis example/redis-cli -h 127.0.0.1
Published Ports
- Ports aren't available default.
- You establish them with
-p
or--publish
. - This creates a firewall rule on the host.
- Examples:
-p 8080:80
: Maps port 8080 on docker host to TCP port 80 in the container.-p 192.168.1.100:8080:80
: Map port 8080 on docker host IP 192.168.1.100 to TCP port 80 in container.-p 80880:80/udp
: Maps port 8080 on docker host to UDP port 80 in container.-p 8080:80/tcp -p 8080:80/udp
: Maps TCP port 8080 on docker host to TCP port 80 in container, and maps UDP port 8080 on docker host to UDP port 80 in container.
- Publishing container ports is INSECURE by default.
- When you publish a container's ports its not only available to docker host but also to the outside world.
- Including localhost IP address (127.0.0.1 or ::1) with the publish flag, only docker host and its containers can access the published ports.
docker run -p 127.0.0.1:8080:80 -p '[::1]:8080:80' nginx
- Ports on the host's IPv6 addresses will map to the container's IPv4 if no host IP is given in a port mapping.
IP Address & Hostname
- Container gets an IP for every docker network it attaches to.
- Docker daemon performs dynamic sub-netting and IP address allocation for containers.
- Connect a running container to a network either with
--network
flag or usingdocker network connect
. - You can use
--ip
or--ipb
to specify containers IP addresses on particular networks. - Container's hostname defaults to the container's ID in docker.
- We can set our own with
--hostname
.
DNS Services
- Containers use the same DNS servers as the host by default (inherited from
/etc/resolv.conf
)- Override this with
--dns
.
- Override this with
- Containers that attach to the default bridge network get a copy of
resolv.conf
. - Containers that attach to a custom network inherit from host.
- You can configure DNS on a per-container basis. (docker run | docker create)
--dns
: IP address of a dns server, can be used multiple times in a command.
--dns-search
: search non-fully qualified hostnames.
--dns-opt
: Key-value pair representing a DNS option and its value. (OS's resolv.conf docs).
--hostname
: Hostname a container uses for itself (defaults to container's ID).
Volumes
- Completely managed by docker.
- Mechanism for persisting data generated by and used by docker containers.
- Advantages of Volumes over Bind Mounts:
- Easier to backup/migrate.
- Work on linux & windows containers.
- Manageable with docker cli or docker api.
- Volume drivers let you store volumes on remote hosts or cloud providers, encrypt the contents of volumes or add other functionality.
- New volumes can have their content pre-populated by a container.
- More safely shared among containers.
- If a container generates non-persistent data, opt for a tmpfs mount, to avoid storing the data anywhere permanently.
--v
flag consists of 3 fields separated by:
.- First field: Name of the volume.
- Second field: Path where the file or directory are mounted in the container.
- Third field: A comma separated list of options (wrap the this list in
""
). - e.g. read only volume: -v nginx-vol:/usr/share/nginx/html:ro
- Creating volumes:
- Create a volume:
docker volume create volume-name
- Remove a volume:
docker volume rm volume-name
- Inspect a volume:
docker volume inspect volume-name
- List volumes:
docker volume ls
- Create a volume:
- If you start a volume that doesn't exist, it will get made for you.
Example: nginx container that creates and populates a nginx volume with its default HTML content.
Mount:
docker run -d \
--name=nginx-test \
--mount source=nginx-vol,destination=/usr/share/nginx/html \
nginx:latest
Volume:
docker run -d \
--name=nginx-test \
-v nginx-vol:/usr/share/nginx/html \
nginx:latest
Sharing Data Between Machines
- Store in some object cloud storage like Amazon S3.
- Create volumes with a driver that supports writing files to an external storage system like NFS or S3.
- Volume drivers allow you to abstract the underlying storage system from the application logic.
Drivers with Volumes
- When creating a volume you can specify a driver:
docker volume create --driver
- If a driver requires you to pass options, you have to use
--mount
not-v
. - Adding a volume driver to a volume that doesn't exist yet involves just adding
volume-driver=
to the comma separated list.
Backup
- You can backup an existing volume by creating a new one with contents of the other one in it.
- First container:
docker run -v /dbdata --name dbstore ubunutu /bin/bash
. - Backup container:
docker run --rm --volumes-from dbstore -v $(pwd):/backup ubunutu tar cuf /backup/backup.tar /dbdata
Removing Volumes
--rm
will remove anonymous volumes when the container is deleted.docker volume prune
will remove all unused volumes.
Working Example
Create a Network
docker network create todo-app
Start a MySQL Container
docker run -d \
# network we made and an alias which can be used as a reference later
--network todo-app --network-alias mysql \
# volume that will be made for us, the path is the location on the host
-v todo-mysql:/var/lib/mysql \
# Environment variables
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=todos \
# image
mysql:8.0
To Connect to the Database
- To check if it works.
docker exec -it <mysql-container-id> mysql -p
- sql command to see if it is working:
SHOW_DATABASES;
.
Starting the Dev Container
- Start a separate container with
nicolaka/netshoot
, a useful tool for debugging network issues:docker run -it --network todo-app nicolaka/netshoot
- Use
dig mysql
to get the IP address for the hostname mysql (this is our alias we made.)
docker run -dp 3000:3000 \
-w /app -v "$(pwd):/app" \
--network todo-app \
-e MYSQL_HOST=mysql \
-e MYSQL_USER=root \
-e MYSQL_PASSWORD=secret \
-e MYSQL_DB=todos \
node:18-alpine \
sh -C "yarn install && yarn run dev"
- To view the logs for debugging:
docker logs -f <container-id>