|
| 1 | +--- |
| 2 | +title: Run Image Factory On-prem |
| 3 | +--- |
| 4 | + |
| 5 | +The [Image Factory](https://github.com/siderolabs/image-factory) is a way for you to dynamically create Talos Linux images. There is a public, hosted version of the Image Factory at [factory.talos.dev](https://factory.talos.dev) and it can also be run in your environment. |
| 6 | + |
| 7 | +The Image Factory is a critical component of [Omni](../overview/what-is-omni) to generate installation media and update Talos nodes, but it is not required to use Omni to use the Image Factory. It is a web interface and API for the `imager` command which is used to customize Talos from the command line. |
| 8 | + |
| 9 | +### Prerequisites |
| 10 | + |
| 11 | +* Container registry (with Talos images) |
| 12 | +* Machine to run Image Factory |
| 13 | +* Image cache signing key |
| 14 | +* Image cache storage (optional) |
| 15 | + |
| 16 | +Image factory can be run in a connected and disconnected or airgapped mode. The default, connected mode will pull images from the upstream Sidero Labs official container registry. |
| 17 | + |
| 18 | +The upstream Sidero Labs registry has all of the required Talos installation containers, extensions, and tools. |
| 19 | + |
| 20 | +If you are running the Image Factory in an airgapped environment you will need to provide a container registry and populate it with the required Talos images. |
| 21 | + |
| 22 | +### Run in Connected Mode |
| 23 | + |
| 24 | +To run the Image Factory connected to the Sidero Labs registry you can run the following commands. |
| 25 | + |
| 26 | +Create image cache private signing key |
| 27 | + |
| 28 | +```shell |
| 29 | +openssl ecparam -name prime256v1 -genkey -noout -out cache-signing-key.key |
| 30 | +``` |
| 31 | + |
| 32 | +Run image factory |
| 33 | + |
| 34 | +```shell |
| 35 | +docker run -p 8080:8080 -d \ |
| 36 | + -v $PWD/cache-signing-key.key:/cache-signing-key.key:ro \ |
| 37 | + ghcr.io/siderolabs/image-factory \ |
| 38 | + -cache-signing-key-path /cache-signing-key.key |
| 39 | +``` |
| 40 | + |
| 41 | +This will publish the image factory on your machine on port 8080 and pull container images from Sidero Labs ghcr.io registry. It will also validate image signatures using [`cosign`](https://edu.chainguard.dev/open-source/sigstore/cosign/an-introduction-to-cosign/) to validate pulled images. |
| 42 | + |
| 43 | +#### Image Cache |
| 44 | + |
| 45 | +There are a variety of image cache locations to store built images. Without an image cache each asset will be built when requested which can consume a high amount of CPU on the image factory machine. |
| 46 | + |
| 47 | +Some supported cache storage options include: |
| 48 | + |
| 49 | +* CDN |
| 50 | +* s3 bucket (or compatable API) |
| 51 | + |
| 52 | +Please view the `--help` output for cache options. |
| 53 | + |
| 54 | +### Run in Disconnected or Airgapped Mode |
| 55 | + |
| 56 | +Running the image factory in an air airgapped environment has more requirements than running in a connected mode. In addition to the requirements above you will also need. |
| 57 | + |
| 58 | +* Certificates for web frontend and registry |
| 59 | +* Cosign image signing key |
| 60 | + |
| 61 | +First you will need to run a container registry in your environment. Any OCI compatable registry should work. |
| 62 | + |
| 63 | +Note: This is just an example and should not be used in a production environment. If you want to test locally on your mahcine you can also see the [developer documentation](https://github.com/siderolabs/image-factory#air-gapped-mode) in the repository. |
| 64 | + |
| 65 | +```bash |
| 66 | +docker run -d -p 5000:5000 --name zot \ |
| 67 | + ghcr.io/project-zot/zot:latest |
| 68 | +``` |
| 69 | + |
| 70 | +Populate the registry with required images. This example uses [`skopeo`](https://github.com/containers/skopeo) because it has an easy `sync` command. Other options to copy container images such as `crane` or `docker` are also possible. |
| 71 | + |
| 72 | +Each image in the upstream registry has a lot of image tags and it is recommended that you only copy the tags for versions you need. |
| 73 | + |
| 74 | +The images you would need to copy would include the following. |
| 75 | + |
| 76 | +* siderolabs/imager |
| 77 | +* siderolabs/installer-base |
| 78 | +* siderolabs/talosctl-all |
| 79 | +* siderolabs/overlays (optional for SBC builds) |
| 80 | +* siderolabs/extensions (optional for system extensions) |
| 81 | + |
| 82 | +You can also create a config file for `skopeo` to pull specific images and tags. This example configuration pulls the required talos images and all of the core system extensions. |
| 83 | + |
| 84 | +``` |
| 85 | +ghcr.io: |
| 86 | + images: |
| 87 | + siderolabs/imager: ["v1.11.0", "v1.10.0"] |
| 88 | + siderolabs/installer-base: ["v1.11.0", "v1.10.0"] |
| 89 | + siderolabs/talosctl-all: ["v1.11.0", "v1.10.0"] |
| 90 | + siderolabs/gvisor: ["20250707.0"] |
| 91 | + siderolabs/stargz-snapshotter: ["v0.17.0"] |
| 92 | + siderolabs/amd-ucode: ["20250808"] |
| 93 | + siderolabs/bnx2-bnx2x: ["20250808"] |
| 94 | + siderolabs/intel-ice-firmware: ["20250808"] |
| 95 | + siderolabs/intel-ucode: ["20250812"] |
| 96 | + siderolabs/qlogic-firmware: ["20250808"] |
| 97 | + siderolabs/realtek-firmware: ["20250808"] |
| 98 | + siderolabs/amdgpu: ["20250808-v1.11.0"] |
| 99 | + siderolabs/i915: ["20250808-v1.11.0"] |
| 100 | + siderolabs/amazon-ena: ["2.15.0-v1.11.0"] |
| 101 | + siderolabs/mei: ["v1.11.0", "v1.10.0"] |
| 102 | + siderolabs/glibc: ["2.41"] |
| 103 | + siderolabs/fuse3: ["3.17.4"] |
| 104 | + siderolabs/iscsi-tools: ["v0.2.0"] |
| 105 | + siderolabs/metal-agent: ["v0.1.3"] |
| 106 | + siderolabs/nonfree-kmod-nvidia-lts: |
| 107 | + ["535.247.01-v1.11.0", "535.230.02-v1.10.0"] |
| 108 | + siderolabs/nonfree-kmod-nvidia-production: |
| 109 | + ["570.172.08-v1.11.0", "570.124.06-v1.10.0"] |
| 110 | + siderolabs/nvidia-container-toolkit-lts: |
| 111 | + ["535.247.01-v1.17.8", "535.230.02-v1.17.5"] |
| 112 | + siderolabs/nvidia-container-toolkit-production: |
| 113 | + ["570.172.08-v1.17.8", "570.124.06-v1.17.5"] |
| 114 | + siderolabs/nvidia-fabricmanager-lts: ["535.247.01", "580.82.07"] |
| 115 | + siderolabs/nvidia-fabricmanager-production: ["570.158.01", "570.172.08"] |
| 116 | + siderolabs/nvidia-open-gpu-kernel-modules-lts: |
| 117 | + ["535.230.02-v1.10.0", "535.247.01-v1.11.1"] |
| 118 | + siderolabs/nvidia-open-gpu-kernel-modules-production: |
| 119 | + ["570.124.06-v1.10.0", "570.172.08-v1.11.1"] |
| 120 | + siderolabs/ctr: ["v2.1.4"] |
| 121 | +``` |
| 122 | + |
| 123 | +You can sync these files and images with |
| 124 | + |
| 125 | +Note: If your internal registry has authentication and valid TLS it is recommended to remove the options `--dest-no-creds` and `--dest-tls-verify=false` |
| 126 | + |
| 127 | +``` |
| 128 | +skopeo sync --src yaml --dest docker \ |
| 129 | + --all \ |
| 130 | + --dest-no-creds \ |
| 131 | + --dest-tls-verify=false \ |
| 132 | + --preserve-digests \ |
| 133 | + sidero-images.yaml \ |
| 134 | + localhost:5000/siderolabs |
| 135 | +``` |
| 136 | + |
| 137 | +### Sign Container Images |
| 138 | + |
| 139 | +The Image Factory verifies container image signatures when being used. You will need to generate a cosign singing key and sign each container we just pushed to the registry. |
| 140 | + |
| 141 | +First generate a cosign key |
| 142 | +```bash |
| 143 | +cosign generate-key-pair |
| 144 | +``` |
| 145 | + |
| 146 | +Now sign each image and tag in your internal registry. This will allow the registry to validate images without reaching out to any external services for key validation. |
| 147 | + |
| 148 | +```bash |
| 149 | +#!/bin/bash |
| 150 | +REGISTRY="localhost:5000" |
| 151 | +KEY_FILE="cosign.key" |
| 152 | + |
| 153 | +curl -k -s "http://$REGISTRY/v2/_catalog" | |
| 154 | + jq -r '.repositories[]' | |
| 155 | + while read repo; do |
| 156 | + echo "Processing repository: $repo" |
| 157 | + curl -k -s "http://$REGISTRY/v2/$repo/tags/list" | |
| 158 | + jq -r '.tags[]' | |
| 159 | + while read tag; do |
| 160 | + image="$REGISTRY/$repo:$tag" |
| 161 | + digest=$(skopeo inspect --no-creds --tls-verify=false "docker://$image" 2>/dev/null | jq -r '.Digest') |
| 162 | + |
| 163 | + if [ "$digest" != "null" ] && [ -n "$digest" ]; then |
| 164 | + digest_image="$REGISTRY/$repo@$digest" |
| 165 | + echo "Signing by digest: $digest_image" |
| 166 | + cosign sign --key "$KEY_FILE" --allow-insecure-registry=true "$digest_image" < /dev/tty |
| 167 | + else |
| 168 | + echo "Could not get digest for $image" |
| 169 | + echo "Signing: $image" |
| 170 | + cosign sign --key "$KEY_FILE" --allow-insecure-registry=true "$image" < /dev/tty |
| 171 | + fi |
| 172 | + done |
| 173 | + done |
| 174 | +``` |
| 175 | + |
| 176 | +### Run Image Factory |
| 177 | + |
| 178 | +With a populated container registry and signed images you are ready to run the Image Factory. |
| 179 | + |
| 180 | +Note: If the container registry and image factory are run on the same machine `localhost` won't be reachable unless you run each container with `--net=host` which is not recommended. An alternative approach would be to use [private Docker networking](https://docs.docker.com/engine/network/) to bridge the containers. |
| 181 | + |
| 182 | +```bash |
| 183 | +docker run -p 8080:8080 -d \ |
| 184 | + -v $PWD/cache-signing-key.key:/cache-signing-key.key:ro \ |
| 185 | + -v $PWD/cosign.key:/cosign.key:ro \ |
| 186 | + ghcr.io/siderolabs/image-factory \ |
| 187 | + -image-registry $REGISTRY_HOST \ |
| 188 | + -installer-internal-repository $REGISTRY_HOST/siderolabs \ |
| 189 | + -installer-internal-repository $REGISTRY_HOST/siderolabs \ |
| 190 | + -schematic-service-repository $REGISTRY/siderolabs/image-factory/schematic \ |
| 191 | + -cache-repository $REGISTRY/siderolabs/cache \ |
| 192 | + -cache-signing-key-path /cache-signing-key.key \ |
| 193 | + -insecure-image-registry \ |
| 194 | + -insecure-installer-internal-repository \ |
| 195 | + -insecure-schematic-service-repository \ |
| 196 | + -cache-cdn-enabled=false \ |
| 197 | + -cache-s3-enabled=false |
| 198 | +``` |
| 199 | + |
| 200 | +If you are running on a server with SELinux enabled and enforcing then volumes mounted into the container will not be available unless you append `:Z` to the volume mounts. |
| 201 | + |
| 202 | +If you have an internal, private certificate authority you will need to mount that into the Image Factory image so it can trust the registry certificate. Mount it into the container by adding `-v /etc/pki/ca-trust/source/anchors:/etc/ssl/certs:ro` to the Image Factory commands. |
| 203 | + |
| 204 | +After the image factory is running you can continue to the [Omni documentation for a self-hosted installation](./self-hosted/deploy-omni-on-prem). |
0 commit comments