GithubHelp home page GithubHelp logo

flaktack / systemd-resolved-docker Goto Github PK

View Code? Open in Web Editor NEW
16.0 2.0 4.0 41 KB

systemd-resolved and docker DNS integration

Home Page: https://copr.fedorainfracloud.org/coprs/flaktack/systemd-resolved-docker/

License: Other

Python 73.98% Shell 26.02%
systemd-resolved docker dns

systemd-resolved-docker's Introduction

systemd-resolved-docker

Provides systemd-resolved and docker DNS integration.

  1. A DNS server is configured to listen on the docker interface's IP address. This is used to expose the systemd-resolved DNS service (127.0.0.53) to docker containers by proxying DNS requests, which doesn't work by default due to the differing network namespaces.

  2. Allows containers to be referenced by hostname by adding a DNS servers to a dummy interface using the systemd-resolved D-Bus API.

Features

Container domain addresses

Based on the container's properties multiple domain names may be generated. For this the default_domain (DEFAULT_DOMAIN) and allowed domains (ALLOWED_DOMAINS) options are used. The list of allowed domains specifies which domains may be handled. An entry starting with . (example: .docker) allows all matching subdomains, otherwise an exact match is required. If a generated domain address doesn't match the list of allowed domains, then the default_domain is appended.

  1. <container_id>.<default_domain>

    All containers will be reachable by their container_id:

    docker run --rm -it alpine                                        #  d6d51528ac46.docker
    docker ps
    CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS              PORTS                    NAMES
    d6d51528ac46        alpine                    "/bin/sh"                8 seconds ago       Up 6 seconds                                 relaxed_cartwright
  2. <container_hostname>.<default_domain>, <container_hostname>.<container_domain>.<default_domain>, <container_hostname>.<container_domain>

    If an explicit --hostname is provided then that may also be used:

    docker run --rm -it --hostname test      alpine                   # test.docker

    Glob matching is supported in the --hostname, with which wildcard domains are supported:

    docker run --hostname '*.test' --rm -it alpine                    # anything.test

    If an explicit --domainname is provided then that may also be used:

    docker run --rm -it --hostname test --domainname mydomain alpine  # test.mydomain.docker

    When the domain name is in the list of allowed domains (ALLOWED_DOMAINS=.docker,.local), then the default_domain will not be appended:

    docker run --rm -it --hostname test --domainname local    alpine  # test.local
  3. <container_name>.<container_network>.<default_domain>, <container_name>.<container_network>

    If a non-default network is used (not bridge or host) then a name will be generated based on the network's name:

    docker run --rm -it           --network testnet alpine            # zealous_jones.testnet.docker
    docker run --rm -it --name db --network testnet alpine            # db.testnet.docker

    When the network's name is in the list of allowed domains (ALLOWED_DOMAINS=.docker,.somenet), then the default_domain will not be appended:

    docker run --rm -it           --network somenet alpine            # zealous_jones.somenet
    docker run --rm -it --name db --network somenet alpine            # db.somenet.docker
  4. <service>.<project>.<default_domain>, <service>.<project>, <container_number>.<service>.<project>.<default_domain>, <container_number>.<service>.<project>

    If docker-compose is used then names will be generated based on the service and project names. If a service has multiple containers then the reply will contain all instances:

    host   webserver.someproject.docker                        #   webserver.someproject.docker has address 172.16.238.3
                                                               #   webserver.someproject.docker has address 172.16.238.4
    host 1.webserver.someproject.docker                        # 1.webserver.someproject.docker has address 172.16.238.3

    When the project's name is in the list of allowed domains (ALLOWED_DOMAINS=.docker,.someproject), then the default_domain will not be appended.

    If a <service> name is unique, then it is available also as <service>.<default_domain>.

    host   webserver.docker                                    #   webserver.docker has address 172.16.238.3
    

If configured correctly then resolvectl status should show the configured link-specific DNS server:

$ resolvectl status
...
Link 7 (srd-dummy)
Current Scopes: DNS LLMNR/IPv4 LLMNR/IPv6
     Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
   DNS Servers: 127.0.0.153
    DNS Domain: ~docker
... 

A dummy interface (srd-dummy by default) is created to add the custom DNS server to systemd-resolved. This is required because the lifecycle of the docker0 depends on there being running containers on the default network, even if there are running containers on other networks.

127.0.0.53 / systemd-resolved within containers

If docker is configured to use the provided DNS server then the container domain names may also be resolved within containers:

$ docker run --dns 1.1.1.1 --rm -it alpine
/ # apk add bind
/ # host test.docker
Host test.docker not found: 3(NXDOMAIN)
$ docker run --dns 172.17.0.1 --rm -it alpine
/ # apk add bind
/ # host test.docker
/ # host test.docker
test.docker has address 172.17.0.3
Host test.docker not found: 3(NXDOMAIN)
Host test.docker not found: 3(NXDOMAIN)

If there are link-local, VPN or other DNS servers configured then those will also work within containers.

Configuration

systemd-resolved-docker may be configured using environment variables. When installed using the RPM /etc/sysconfig/systemd-resolved-docker may also be modified to update the environment variables.

Name Description Default Value Example
DNS_SERVER DNS server to use when resolving queries from docker containers. 127.0.0.53 - systemd-resolved DNS server 127.0.0.53
SYSTEMD_RESOLVED_INTERFACE Dummy interface name which will be created to interface with systemd-resolved srd-dummy srd-dummy
SYSTEMD_RESOLVED_LISTEN_ADDRESS IPs (+port) to listen on for queries from systemd-resolved. 127.0.0.153 127.0.0.153:1053
DOCKER_LISTEN_ADDRESS IPs (+port) to listen on for queries from docker containers in the default network. ip of the default docker bridge, often 172.17.0.1 172.17.0.1 or 172.17.0.1:53
ALLOWED_DOMAINS Domain which will be handled by the DNS server. If a domain starts with . then all subdomains will also be allowed. .docker .docker,.local
DEFAULT_DOMAIN Domain to append to hostnames which are not allowed by ALLOWED_DOMAINS. docker docker
DEFAULT_HOST_IP IP address to use for containers on the host network if the container doesn't contain one. 127.0.0.1 127.0.0.1
--------------------------------- ----------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------- ---------------------------------

Install

Fedora / COPR

For Fedora and RPM based systems COPR contains pre-built packages.

  1. Enabled the COPR repository

    dnf copr enable flaktack/systemd-resolved-docker
    
  2. Install the package

    dnf install systemd-resolved-docker
    
  3. Start and optionally enable the service

    systemctl start  systemd-resolved-docker
    systemctl enable systemd-resolved-docker
    
  4. Docker should be updated to use the DNS server provided by systemd-docker-resolved. This may be done globally by editing the docker daemon's configuration (daemon.json) or per-container using the --dns flag.

    "dns": [
      "172.17.0.1" // docker0 interface's IP address
    ]
  5. NetworkManager may reset the docker interface's configuration for systemd-resolved. If that happens than the interface needs to be unmanaged. This may be done by creating a /etc/NetworkManager/conf.d/99-docker.conf:

    [main]
    plugins=keyfile
    
    [keyfile]
    unmanaged-devices=interface-name:docker0

Build

setup.py may be used to create a python package.

tito may be used to create RPMs.

Links

Portions are based on docker-auto-dnsmasq and dnslib.

systemd-resolved-docker's People

Contributors

flaktack avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

systemd-resolved-docker's Issues

Deb build attempt for bionic/18.04 fails with "The 'dbus-python' distribution was not found"

Would very much like to use this with Ubuntu bionic/18.04 (because reasons), so attempting to manual-build following the steps in the github/workflows/workflow.yml. Figuring the build process for 20.04 would be closest - that whole process works fine and a python-systemd-resolved-docker_1.0.0_all.deb is built and can be installed.

The problem shows up with the service not starting. Running manually with sudo /usr/bin/systemd-resolved-docker results in

ubuntu@bionic:~/systemd-resolved-docker$ sudo /usr/bin/systemd-resolved-docker
Traceback (most recent call last):
  File "/usr/bin/systemd-resolved-docker", line 6, in <module>
    from pkg_resources import load_entry_point
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 3088, in <module>
    @_call_aside
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 3072, in _call_aside
    f(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 3101, in _initialize_master_working_set
    working_set = WorkingSet._build_master()
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 574, in _build_master
    ws.require(__requires__)
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 892, in require
    needed = self.resolve(parse_requirements(requirements))
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 778, in resolve
    raise DistributionNotFound(req, requirers)
pkg_resources.DistributionNotFound: The 'dbus-python' distribution was not found and is required by systemd-resolved-docker

Does not work with IPv6?

systemd[1]: Starting systemd-resolved-docker.service - systemd-resolved and docker DNS integration...
systemd-resolved-docker[4018773]: Found gateway 172.17.0.1 for docker0
systemd-resolved-docker[4018773]: Found gateway fd00:ffff::1 for docker0 
systemd-resolved-docker[4018773]: Default domain: docker, allowed domains: .docker 
systemd-resolved-docker[4018773]: Traceback (most recent call last): 
systemd-resolved-docker[4018773]:   File "/usr/bin/systemd-resolved-docker", line 33, in <module>
systemd-resolved-docker[4018773]:     sys.exit(load_entry_point('systemd-resolved-docker==1.0.0', 'console_scripts', 'systemd-resolved-docker')())
systemd-resolved-docker[4018773]:   File "/usr/lib/python3.10/site-packages/systemd_resolved_docker/cli.py", line 60, in main
systemd-resolved-docker[4018773]:     docker_listen_addresses = parse_listen_address(docker_listen_address,
systemd-resolved-docker[4018773]:   File "/usr/lib/python3.10/site-packages/systemd_resolved_docker/utils.py", line 28, in parse_listen_address
systemd-resolved-docker[4018773]:     return default_value()   
systemd-resolved-docker[4018773]:   File "/usr/lib/python3.10/site-packages/systemd_resolved_docker/cli.py", line 61, in <lambda>
systemd-resolved-docker[4018773]:     lambda: [parse_ip_port(entry['gateway']) for entry in
systemd-resolved-docker[4018773]:   File "/usr/lib/python3.10/site-packages/systemd_resolved_docker/cli.py", line 61, in <listcomp>
systemd-resolved-docker[4018773]:     lambda: [parse_ip_port(entry['gateway']) for entry in
systemd-resolved-docker[4018773]:   File "/usr/lib/python3.10/site-packages/systemd_resolved_docker/utils.py", line 21, in parse_ip_port
systemd-resolved-docker[4018773]:     return IpAndPort(ip=ipaddress.ip_address(result.hostname), port=result.port or default_port)
systemd-resolved-docker[4018773]:   File "/usr/lib64/python3.10/ipaddress.py", line 54, in ip_address
systemd-resolved-docker[4018773]:     raise ValueError(f'{address!r} does not appear to be an IPv4 or IPv6 address')
systemd-resolved-docker[4018773]: ValueError: 'fd00' does not appear to be an IPv4 or IPv6 address

I had a quick look to try to find where the rest of the IPv6-address is stripped after it "found gateway", but did not see anything obvious.

Unexpected git history rewrite

๐Ÿ‘‹๐Ÿป I considered this project interesting and decided to mirror is to my infrastructure. Today the mirroring process warned me that a push failed due to a history rewrite.

A few minutes later, I figure out, that all commits after 6be3a30 have been rewritten including various tags.

Not this is a problem, I just want to check with you, that this was intended behaviour and not an accident.

For comparison:
My mirror: https://git.shivering-isles.com/github-mirror/flaktack/systemd-resolved-docker/-/commits/master
This repository: https://github.com/flaktack/systemd-resolved-docker/commits/master

Handle differing systemd dbus interface versions

Currently the dbus code works around having different methods in different systemd versions by catching exceptions, replace it with an actual version check.

try:
ips = [
[
AF_INET if isinstance(ip_port.ip, ipaddress.IPv4Address) else AF_INET6,
ip_port.ip.packed,
ip_port.port,
"",
]
for ip_port in self.listen_addresses
]
manager = self.if_manager()
manager.SetLinkDNSEx(self.ifindex, ips)
manager.SetLinkDNSSEC(self.ifindex, "no")
manager.SetLinkDomains(self.ifindex, domains)
except Exception as ex:
ips = [
[
AF_INET if isinstance(ip_port.ip, ipaddress.IPv4Address) else AF_INET6,
ip_port.ip.packed
]
for ip_port in self.listen_addresses
]
manager = self.if_manager()
manager.SetLinkDNS(self.ifindex, ips)
manager.SetLinkDNSSEC(self.ifindex, "no")
manager.SetLinkDomains(self.ifindex, domains)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.