Air-Gapped Installation of Talos Linux Cluster

Bootstrap a Talos Linux cluster for Cozystack with an air-gapped environment

Introduction

This guide outlines the steps to bootstrap a Cozystack cluster in an air-gapped environment.

Air-gapped installation means that the cluster has no direct access to the Internet. All necessary resources, such as images and metadata, must be available on the private network.

Configure Talos nodes

1. Configure NTP Servers

Accurate time synchronization is critical for the cluster. In your Talos machine configuration, set local NTP servers that are accessible inside your private network:

machine:
  time:
    servers:
      # example values
      - 192.168.0.4
      - 10.10.0.5

Ensure that these NTP servers are reachable from the first Talos node.

2. Configure Container Registry Mirrors

Since the cluster cannot access public container registries, it needs to use their local mirrors. Creating such mirrors is out of the scope of this guide.

Update your machine configuration in the following way, providing the IP addresses and ports of your local mirrors for each registry:

machine:
  registries:
    mirrors:
      docker.io:
        endpoints:
          - http://10.0.0.1:8082
      ghcr.io:
        endpoints:
          - http://10.0.0.1:8083
      gcr.io:
        endpoints:
          - http://10.0.0.1:8084
      registry.k8s.io:
        endpoints:
          - http://10.0.0.1:8085
      quay.io:
        endpoints:
          - http://10.0.0.1:8086
      cr.fluentbit.io:
        endpoints:
          - http://10.0.0.1:8087
      docker-registry3.mariadb.com:
        endpoints:
          - http://10.0.0.1:8088
    config:
      "10.0.0.1:8082":
        insecure: true
        auth:
          username: myuser
          password: mypass

Of course, the values for config.[0].auth.* are given as examples, and you need to use real credentials. Make sure your local registry proxies mirror all required images for Talos and Kubernetes components.

3. Add CA Certificate

To use a private Certificate Authority, you need to add its certificate to the nodes.

# talm: nodes=["10.10.10.10"], endpoints=["10.10.10.10"], templates=["templates/controlplane.yaml"]
# THIS FILE IS AUTOGENERATED. PREFER TEMPLATE EDITS OVER MANUAL ONES.
machine:
# ...
# ...
  discovery:
    enabled: false
  etcd:
    advertisedSubnets:
      - 10.4.100.10/24
  allowSchedulingOnControlPlanes: true
---
apiVersion: v1alpha1
kind: TrustedRootsConfig
name: my-enterprise-ca
certificates: |
  -----BEGIN CERTIFICATE-----
  ...
  -----END CERTIFICATE-----  

4. Apply Changes

After you have made the changes above, you can apply the configuration and bootstrap a cluster:

Using Talm

Rebuild the node configuration files and apply them to each node:

talm template -e <ip> -n <ip> -t templates/controlplane.yaml -i > nodes/node1.yaml
talm apply -f nodes/node1.yaml
# repeat for each node

Finally, bootstrap the cluster as usual:

talm bootstrap -f nodes/node1.yaml

Read the Talm cluster configuration guide to learn more.

Using talosctl

Apply the configuration to each node:

talosctl apply -f controlplane.yaml -n <ip> -e <ip> -i

Finally, bootstrap the cluster using one of the nodes:

talosctl bootstrap -n <ip> -e <ip>

Read the Talm cluster configuration guide to learn more.

5. Configure Container Registry Mirrors for Tenant Kubernetes

To perform this configuration, you first need to complete Cozystack installation.

To use registry mirrors, tenant Kubernetes clusters need a separate config, similar to the one made for the Talos nodes.

Generate a secret using the following example:

apiVersion: v1
kind: Secret
metadata:
  name: patch-containerd
  namespace: cozy-system
type: Opaque
stringData:
  docker.io.toml: |
    server = "https://registry-1.docker.io"
    [host."http://10.0.0.1:8082"]
      capabilities = ["pull", "resolve"]
      skip_verify = true    
  ghcr.io.toml: |
    server = "https://ghcr.io"
    [host."http://10.0.0.1:8083"]
      capabilities = ["pull", "resolve"]
      skip_verify = true    
  gcr.io.toml: |
    server = "https://gcr.io"
    [host."http://10.0.0.1:8084"]
      capabilities = ["pull", "resolve"]
      skip_verify = true    
  registry.k8s.io.toml: |
    server = "https://registry.k8s.io"
    [host."http://10.0.0.1:8085"]
      capabilities = ["pull", "resolve"]
      skip_verify = true    
  quay.io.toml: |
    server = "https://quay.io"
    [host."http://10.0.0.1:8086"]
      capabilities = ["pull", "resolve"]
      skip_verify = true    
  cr.fluentbit.io.toml: |
    server = "https://cr.fluentbit.io"
    [host."http://10.0.0.1:8087"]
      capabilities = ["pull", "resolve"]
      skip_verify = true    
  docker-registry3.mariadb.com.toml: |
    server = "https://docker-registry3.mariadb.com"
    [host."http://10.0.0.1:8088"]
      capabilities = ["pull", "resolve"]
      skip_verify = true    

This secret will be copied for every tenant Kubernetes cluster deployed in your Cozystack. If you need to set a custom config for a particular tenant K8s cluster, set useCustomSecretForPatchContainerd: true in the values of Kubernetes app (since version 0.23.0) and create a Secret with name kubernetes-clustername before creating a cluster.

To learn more about registry configuration, read the CRI Plugin configuration guide