This is a container to be used as a Tinkerbell Action. It has the following purposes:
- Run any arbitrary container image with its accompanying envs, command, volumes, etc.
- Wait an arbitrary amount of time before running your specified container image.
- Immediately report back to the Tink server that the Action has completed successfully.
waitdaemon supports Docker and nerdctl. By default it auto-detects which runtime is available (preferring Docker, then probing for nerdctl). You can override this with the CONTAINER_RUNTIME environment variable.
waitdaemon's main use cases are kexec-ing and rebooting a machine. Currently, in Tinkerbell, these Actions generally cause the STATE to never transition to SUCCESS.
This has a few consequences.
- If/when the machine runs Tink worker again (via a network boot, for example), this Action will be run again. The same issue with
STATEnot transitioning will continue to occur. - Any entity watching and expecting the
SUCCESSstate of the Action and Workflow will be unable to determine if the kexec or reboot occurred or not. CAPT, for example. - Poor user experience. A machine might have successfully kexec'd or rebooted but the
STATEis not accurate. (This one is actually not solved by waitdaemon. ASUCCESSstate does not guarantee the Action was successful.)
NOTE: waitdaemon does not guarantee your container ran successfully! Using waitdaemon means that failures in running your container are not surfaced to Tink server and your Workflow. You will need to check the Smee logs for any errors.
The following Tinkerbell Action fields require specific values for waitdaemon to work properly:
| Field | Description | Required |
|---|---|---|
image |
The image must be set to ghcr.io/jacobweinstock/waitdaemon:latest or a specific tag version, ghcr.io/jacobweinstock/waitdaemon:<tag>. |
Yes |
pid |
This will almost always need to be set to host because reboot and kexec require it and nerdctl may also require it. |
Yes |
command |
The command should be set to what you want run inside the image defined in the environment variable: IMAGE. |
Yes |
environment |
The environment variables are detailed below. | Yes |
volumes |
The volumes settings are detailed below. | Yes |
The following are the configurable waitdaemon environment variables:
| Variable | Description | Required | Default |
|---|---|---|---|
IMAGE |
The container image to run after waiting. | Yes | N/A |
WAIT_SECONDS |
The number of seconds to wait before running the container. | No | 10 |
CONTAINER_RUNTIME |
The container runtime to use. Valid values are: docker, nerdctl, auto. |
No | auto |
NERDCTL_NAMESPACE |
The namespace in which nerdctl should operate. | No | tinkerbell |
NERDCTL_HOST |
When set to true or 1, nerdctl from the host will be used. |
No | true |
The required volume mounts depend on the container runtime you are using.
When using the Docker (which is the only runtime available in HookOS), the Docker socket must be mounted:
volumes:
- /var/run/docker.sock:/var/run/docker.sockWhen using nerdctl (which is the only runtime available in CaptainOS), volume mounts are only required if NERDCTL_HOST is false or when set to true and it does not work for your setup.
volumes:
- /run/containerd/containerd.sock:/run/containerd/containerd.sock
- /var/lib/containerd:/var/lib/containerd
- /var/lib/nerdctl:/var/lib/nerdctl
- /opt/cni/bin:/opt/cni/bin
- /etc/cni/net.d:/etc/cni/net.dwaitdaemon is compatible with both HookOS and CaptainOS.
Here are two example Actions that will work with both HookOS and CaptainOS:
-
Reboot a machine:
- name: "reboot" image: ghcr.io/jacobweinstock/waitdaemon:latest timeout: 90 pid: host command: ["reboot"] environment: IMAGE: alpine volumes: - /var/run/docker.sock:/var/run/docker.sock
-
kexec into a new kernel:
- name: "kexec" image: ghcr.io/jacobweinstock/waitdaemon:latest timeout: 90 pid: host environment: BLOCK_DEVICE: {{ formatPartition ( index .Hardware.Disks 0 ) 1 }} FS_TYPE: ext4 IMAGE: quay.io/tinkerbell-actions/kexec:v1.0.0 volumes: - /var/run/docker.sock:/var/run/docker.sock
-
When
NERDCTL_HOSTisfalse:- name: "reboot" image: ghcr.io/jacobweinstock/waitdaemon:latest timeout: 90 pid: host command: ["reboot"] environment: IMAGE: alpine volumes: - /run/containerd/containerd.sock:/run/containerd/containerd.sock - /var/lib/containerd:/var/lib/containerd - /var/lib/nerdctl:/var/lib/nerdctl - /opt/cni/bin:/opt/cni/bin - /etc/cni/net.d:/etc/cni/net.d
-
When you want to explicitly use Docker:
- name: "reboot" image: ghcr.io/jacobweinstock/waitdaemon:latest timeout: 90 pid: host command: ["reboot"] environment: IMAGE: alpine CONTAINER_RUNTIME: docker volumes: - /var/run/docker.sock:/var/run/docker.sock
-
When you want to explicitly use nerdctl:
- name: "reboot" image: ghcr.io/jacobweinstock/waitdaemon:latest timeout: 90 pid: host command: ["reboot"] environment: IMAGE: alpine CONTAINER_RUNTIME: nerdctl
-
When you want to customize the wait time:
- name: "reboot" image: ghcr.io/jacobweinstock/waitdaemon:latest timeout: 90 pid: host command: ["reboot"] environment: IMAGE: alpine WAIT_SECONDS: 30 volumes: - /var/run/docker.sock:/var/run/docker.sock
Under the hood, the waitdaemon is doing something akin to daemonizing or double forking a Linux process but for containers and a Tinkerbell action.
All values you specify in your action. command, volumes, pid, environment, etc are propogated to your container image when it's run.
┌──────────────Action Container───────────────┐
│ │
│ image: ghcr.io/jacobweinstock/waitdaemon │
│ │
│ ┌────process─────┐ │
│ │ waitdaemon │ │
│ └────────┬───────┘ │
└──────────────────────┼──────────────────────┘
│
create, exit
│
▼
┌──────────────────Container──────────────────┐
│ │
│ image: ghcr.io/jacobweinstock/waitdaemon │
│ │
│ ┌────process─────┐ │
│ │ waitdaemon │ │
│ └────────┬───────┘ │
└──────────────────────┼──────────────────────┘
│
wait, create, exit
│
▼
┌──────────────────Container──────────────────┐
│ │
│ image: your image │
│ │
│ │
│ │
│ │
└─────────────────────────────────────────────┘