Graduate Program KB

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 using docker 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.
  • 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
  • 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>

Return