Set Hostname Using CloudInit for DHCP Server – Systemd Overrides

cloud-initdhcpdomain-name-systemsystemdUbuntu

For a testing environment, I want to connect multiple VMs using DHCP with their hostnames as DNS entrys. The troubleshooting shows that my DNS/DHCP works. But the VM got registered using ubuntu as hostname instead of my own (k8sm in this example):

root@k8sm:~# ping k8sm -c1
PING k8sm (192.168.2.89) 56(84) bytes of data.
64 bytes from ubuntu.k8s.home (192.168.2.89): icmp_seq=1 ttl=64 time=0.019 ms

Using my k8sm hostname, I didn't get an IP when trying dig +short k8sm.k8s.home @192.168.2.2 (where .2.2 is my DNS server).

Cloudinit user-data

hostname: ${hostname}
fqdn: ${hostname}.k8s.home

Which is called from my Terraform config file here:

data "template_file" "k8sm-cloudinit-data" {
  template = "${file("${path.module}/cloudinit/user-data.cfg")}"
  vars = {
    hostname = "k8sm"
  }
}

According to the logs

root@k8sm:~# grep hostname /var/log/syslog
Jun  6 19:17:09 k8sm systemd-resolved[604]: Using system hostname 'ubuntu'.
Jun  6 19:17:09 k8sm systemd-networkd[581]: Not connected to system bus, not setting hostname.
Jun  6 19:17:09 k8sm systemd-resolved[604]: System hostname changed to 'k8sm'.
Jun  6 19:17:09 k8sm kernel: [    3.526063] systemd[1]: Set hostname to <ubuntu>.
Jun  6 19:17:09 k8sm dbus-daemon[781]: [system] Activating via systemd: service name='org.freedesktop.hostname1' unit='dbus-org.freedesktop.hostname1.service' requested by ':1.0' (uid=100 pid=581 comm="/lib/systemd/systemd-networkd " label="unconfined")
Jun  6 19:17:09 k8sm dbus-daemon[781]: [system] Successfully activated service 'org.freedesktop.hostname1'
Jun  6 19:17:09 k8sm systemd-hostnamed[844]: Changed host name to 'ubuntu'

it seems that my k8sm hostname is applyed, but got overriden by systemd. Why is this happen and what need to be done to set the hostname correctly for DHCP? The target is to reach the machine using k8sm.k8s.home in this example.

hostnamectl shows me the correct hostname in the VM

root@k8sm:~# hostnamectl status
   Static hostname: k8sm.k8s.home
         Icon name: computer-vm
           Chassis: vm
        Machine ID: 001637a6a5e0410f923cb082af1953d2
           Boot ID: 853577fa58844d8e900c107cfb0c1dde
    Virtualization: kvm
  Operating System: Ubuntu 18.04.2 LTS
            Kernel: Linux 4.15.0-50-generic
      Architecture: x86-64

Both host and VM runs 18.04 LTS with KVM 2.11.1.

Another approach I tried

preserve_hostname: true
runcmd:
  - hostnamectl set-hostname k8sm
  - hostnamectl set-hostname k8sm --static

The idea was to skip cloudinits hostname setting with preserve_hostname and set it manually (later), but the result is the same: VM got registered as ubuntu instead of its new hostname.

Best Answer

After some headaches, I realized that the problem got fixed by rebooting the VM:

power_state:
  delay: now
  mode: reboot
  message: Reboot to apply new hostname
  timeout: 10

This is working, but conflicts with my Ansible provisioning executing after the machine is created. And it also delays everything. Furthermore, I want to understand why this behaviour occurs. Since the reboot works, I assumed a timing problem instead of systemd: DHCP got the default ubuntu hostname, before cloudinit could apply it. Then it won't get updated automatically. Maybe on the next lease, but I want an instant solution.

Found an article that explains how to force a release and this worked manually. So I replaced the reboot using power_state above by those shell-commands:

runcmd: 
  - dhclient -r
  - dhclient

Now DNS works as expected without having to reboot the entire machine:

root@k8sm:~# ping k8sm
PING k8sm.k8s.home (192.168.2.48) 56(84) bytes of data.
Related Topic