Running Ansible Playbooks on Edge Devices
There may be cases in which you would like to be able to execute a scripts or commands in a device or on a group of devices. For example, in...
Read MorePublished on May 23, 2022 by Cosmin Tupangiu on guide flotta fcos flotta-agent
During development, the user may need to spin off a large number of Edge Devices. Fedora CoreOS provides an easy way to create a virtual machine to deploy Edge Device on it. Moreover, the relatively low footprint of CoreOS VM allows you to have a large number of Edge Devices on the same host.
flotta-agent installationFlotta-agent can be installed on any machine using the rpm provided by the fedora copr.
To install flotta-agent:
sudo dnf copr enable project-flotta/flotta
sudo dnf install -y flotta-agent
Now, that flotta-agent has been installed on the OS, we need to configure yggdrasil to know how to connect to Flotta Edge API.
By default, the configuration file can be found under /etc/yggdrasil/config.toml.
An example of yggdrasil configuration file is provided below:
log-level = "debug"
cert-file = "/etc/pki/consumer/cert.pem"
key-file = "/etc/pki/consumer/key.pem"
ca-root = ["/etc/pki/consumer/ca.pem"]
path-prefix = "api/flotta-management/v1"
protocol = "http"
client-id = "<some-id>"
server = "flotta.io:8043"
Let’s explain line by line the configuration:
log-level: sets the log level for yggdrasil. The options are: debug, info, warn, error.cert-file, key-file: path to client certification and private key.ca-root: CA root certification file.path-prefix: this is set to api/flotta-management/v1. All the request from the Edge Device will start with prefix followed by the id of the device (e.g. /api/flotta-management/v1/data/<device-id>/in).protocol: set to http.server: address of the Flotta Edge API. The domain name has to be the same as the domain set in the cluster because the certificates are valid only for that domain. The domain can be set in the cluster by modifying the configmap flotta-operator-manager-config and set DOMAIN to you desired value.client-id: the id of the client. Generally, we set this id to /etc/machine-id but you can use any value as long it is unique.The certificates can be obtained by running make get-certs in Flotta Operator cluster.
CoreOS configures the system using an ignition file. The ignition file is produced from a butane file.
You can find the specification of the butane file on coreos/butane. Basically, the butane file is a yaml file which specify
how the system will be configured after startup.
All the system configuration is done via systemd so to install and setup flotta-agent we need to create two services. These services run only one time when we are provisioning the system.
flotta-agentInstalling the flotta-agent through systemd requires adding flotta-agent copr and run rpm-ostree.
Remark: CoreOS is an ostree OS hence it is using rpm-ostree instead of dnf.
The service could look like this:
[Unit]
Description=Flotta setup service
Wants=network-online.target
After=network-online.target
ConditionPathExists=!/usr/lib/systemd/system/yggdrasild.service
[Service]
Type=oneshot
ExecStartPre=curl https://copr.fedorainfracloud.org/coprs/project-flotta/flotta/repo/fedora-35/project-flotta-flotta-fedora-35.repo -o /etc/yum.repos.d/project-flotta.repo
ExecStart=rpm-ostree install flotta-agent
ExecStart=/bin/bash -c "echo \"client-id = ##`cat /etc/machine-id`##\" >> /etc/yggdrasil/config.toml"
ExecStart=sed -i -s "s/##/\"/g" /etc/yggdrasil/config.toml
ExecStopPost=systemctl reboot
[Install]
WantedBy=multi-user.target
For those not familiar with systemd, here are some explications:
network-online.target meaning we need to have an internet connection.ConditionPathExists must be true for this service to start. This condition allows us to start this service only if yggdrasild.service has not been install yet.flotta-agent, we need to setup the copr. This is done with the target ExecStartPreExecStart installs what we need. The next ExecStart targets are set the client-id. Basically, what we what is to modify the provided yggdrasil configuration file to set the client-id to the machine-id.
This id is unique for each vm and it is available after the first run so we need to capture this id and added to yggdrasil configuration file.ExecStopPostflotta-agent servicesNormally, after you install a new service you need to run systemctl enable --now <service>. In CoreOS, to do this, we need another service:
[Unit]
Description=Flotta start service
Wants=network-online.target
After=network-online.target
ConditionPathExists=/usr/lib/systemd/system/yggdrasild.service
ConditionPathExists=!/etc/systemd/system/multi-user.target.wants/yggdrasild.service
[Service]
Type=oneshot
ExecStart=systemctl enable --now yggdrasild.service
ExecStart=systemctl enable --now node_exporter.service
[Install]
WantedBy=multi-user.target
Here we have the same problem as before: we need to run this service only once at provisioning time.
For that, we use two ConditionPathExists. The first one is checking if yggdrasild.service has been installed and the second is checking that yggdrasild.service hasn’t been yet enabled.
Now, that we have the install and setup services, let’s create our butane file step by step.
variant: fcos
version: 1.3.0
passwd:
users:
- name: core
uid: 1000
ssh_authorized_keys:
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICsx5m3Pu9nxayhj6FIdNfzE2ppSlKqbJ9OJgG74jV9Q cosmin@fedora
First we add a user and a ssh key. SSH key can be generated with ssh-key-gen. Here we put our public key.
Next, we specify the systemd services:
systemd:
units:
# Enable auto-login for 'core' user.
- name: serial-getty@ttyS0.service
dropins:
- name: autologin-core.conf
contents: |
[Service]
ExecStart=
ExecStart=-/usr/sbin/agetty --autologin core --noclear %I $TERM
TTYVTDisallocate=no
- name: zincati.service
mask: true
- name: podman.service
enabled: true
- name: podman.socket
enabled: true
- name: nftables.service
enabled: true
- name: flotta-setup.service
enabled: true
- name: flotta-start.service
enabled: true
Flotta-agent needs podman and nftables services to run. Also, we are adding our two custom services flotta-setup and flotta-start to install and setup flotta.
The first service is not mandatory but it is providing auto-login which is can be very useful. If you don’t use noautoconsole option in virt-install, the service auto-login will automatically log the user when the boot finished.
The next section is the storage:
storage:
trees:
- path: /etc/systemd/system
local: systemd/
directories:
- path: /etc/pki/consumer
mode: 0700
files:
# Hostname for virtual host.
- path: /etc/hostname
mode: 0644
contents:
inline: edgedevice
# Certificates
- path: /etc/pki/consumer/key.pem
mode: 0666
contents:
local: files/key.pem
user:
id: 1000
- path: /etc/pki/consumer/cert.pem
mode: 0666
contents:
local: files/cert.pem
user:
id: 1000
- path: /etc/pki/consumer/ca.pem
mode: 0666
contents:
local: files/ca.pem
user:
id: 1000
- path: /etc/yggdrasil/config.toml
mode: 0666
contents:
local: files/config.toml
# Dont log audit messages
- path: /etc/sysctl.d/20-silence-audit.conf
mode: 0644
contents:
inline: |
# Raise console message logging level from DEBUG (7) to WARNING (4)
# to hide audit messages from the interactive console.
kernel.printk=4
# Set operator hostname
- path: /etc/hosts
overwrite: true
contents:
inline: |
IPADDRESS DOMAIN
# linger root
- path: /etc/systemd/logind.conf
overwrite: true
contents:
inline: |
KillExcludeUsers=root
# disable selinux
- path: /etc/selinux/config
overwrite: true
contents:
inline: |
SELINUX=disabled
SELINUXTYPE=targeted
First, we need to copy our custom services to systemd folder. This is done under trees section.
The section directories creates the /etc/pki/customer folder where we will copy the certificates. Next, we copy the certificates and the configuration file from the host to vm.
The modification of 20-silence-audit.conf is not mandatory but it will be useful not to have those debug messages in the log.
A couple more files and we are done. First we need to setup Flotta API address and domain in the /etc/hosts file.
Next, we are enabling linger for root and disabling SELINUX.
Voilà! We are done with the butane file.
All that is rest is arrange all these file like this:
.
├── files
│ ├── ca.pem
│ ├── cert.pem
│ ├── config.toml
│ └── key.pem
├── spec.bu
└── systemd
├── flotta-setup.service
└── flotta-start.service
The folder files contains the files to be copied to OS and system folder contains our custom services.
The ignition file can be generate either with podman or directly by installing butane:
podman run --interactive --rm quay.io/coreos/butane:release \
--pretty --strict spec.bu spec.ign
Butane is available as Fedora package:
sudo dnf install -y butane
Run butane on the Butane file:
butane --pretty --strict spec.bu > spec.ign
For this blog, I use libvirt but you have lots of other solutions to create your instance. Please take a look at CoreOS doc.
After we fetch the latest image for qemu, the instance can be lunched using:
IGNITION_CONFIG="spec.ign"
IMAGE="/path/to/image.qcow2"
VM_NAME="fcos-test-01"
VCPUS="2"
RAM_MB="2048"
STREAM="stable"
DISK_GB="10"
virt-install --connect="qemu:///system" --name="${VM_NAME}" --vcpus="${VCPUS}" --memory="${RAM_MB}" \
--os-variant="fedora-coreos-$STREAM" --import --graphics=none \
--disk="size=${DISK_GB},backing_store=${IMAGE}" \
--network bridge=virbr0 \
--qemu-commandline="-fw_cfg name=opt/com.coreos/config,file=${IGNITION_CONFIG}"
If you don’t want to see the console, you can add --noautoconsole to virt-install command.
Everything that we did here, you can find it on Github.
There may be cases in which you would like to be able to execute a scripts or commands in a device or on a group of devices. For example, in...
Read MoreEdge Example App is an app for Flotta Edge devices, with a workload that will be deployed on the device that has two main features: Sensing the Internet (which helps...
Read MoreEdge Example App is an app for Flotta Edge devices, with a workload that will be deployed on the device that has two main features:
Read More